github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/gc/walk.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "cmd/compile/internal/types" 9 "cmd/internal/objabi" 10 "cmd/internal/sys" 11 "encoding/binary" 12 "fmt" 13 "strings" 14 ) 15 16 // The constant is known to runtime. 17 const tmpstringbufsize = 32 18 19 func walk(fn *Node) { 20 Curfn = fn 21 22 if Debug['W'] != 0 { 23 s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym) 24 dumplist(s, Curfn.Nbody) 25 } 26 27 lno := lineno 28 29 // Final typecheck for any unused variables. 30 for i, ln := range fn.Func.Dcl { 31 if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) { 32 ln = typecheck(ln, ctxExpr|ctxAssign) 33 fn.Func.Dcl[i] = ln 34 } 35 } 36 37 // Propagate the used flag for typeswitch variables up to the NONAME in its definition. 38 for _, ln := range fn.Func.Dcl { 39 if ln.Op == ONAME && (ln.Class() == PAUTO || ln.Class() == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Name.Used() { 40 ln.Name.Defn.Left.Name.SetUsed(true) 41 } 42 } 43 44 for _, ln := range fn.Func.Dcl { 45 if ln.Op != ONAME || (ln.Class() != PAUTO && ln.Class() != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Name.Used() { 46 continue 47 } 48 if defn := ln.Name.Defn; defn != nil && defn.Op == OTYPESW { 49 if defn.Left.Name.Used() { 50 continue 51 } 52 yyerrorl(defn.Left.Pos, "%v declared and not used", ln.Sym) 53 defn.Left.Name.SetUsed(true) // suppress repeats 54 } else { 55 yyerrorl(ln.Pos, "%v declared and not used", ln.Sym) 56 } 57 } 58 59 lineno = lno 60 if nerrors != 0 { 61 return 62 } 63 walkstmtlist(Curfn.Nbody.Slice()) 64 if Debug['W'] != 0 { 65 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym) 66 dumplist(s, Curfn.Nbody) 67 } 68 69 zeroResults() 70 heapmoves() 71 if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 { 72 s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym) 73 dumplist(s, Curfn.Func.Enter) 74 } 75 } 76 77 func walkstmtlist(s []*Node) { 78 for i := range s { 79 s[i] = walkstmt(s[i]) 80 } 81 } 82 83 func samelist(a, b []*Node) bool { 84 if len(a) != len(b) { 85 return false 86 } 87 for i, n := range a { 88 if n != b[i] { 89 return false 90 } 91 } 92 return true 93 } 94 95 func paramoutheap(fn *Node) bool { 96 for _, ln := range fn.Func.Dcl { 97 switch ln.Class() { 98 case PPARAMOUT: 99 if ln.isParamStackCopy() || ln.Addrtaken() { 100 return true 101 } 102 103 case PAUTO: 104 // stop early - parameters are over 105 return false 106 } 107 } 108 109 return false 110 } 111 112 // The result of walkstmt MUST be assigned back to n, e.g. 113 // n.Left = walkstmt(n.Left) 114 func walkstmt(n *Node) *Node { 115 if n == nil { 116 return n 117 } 118 119 setlineno(n) 120 121 walkstmtlist(n.Ninit.Slice()) 122 123 switch n.Op { 124 default: 125 if n.Op == ONAME { 126 yyerror("%v is not a top level statement", n.Sym) 127 } else { 128 yyerror("%v is not a top level statement", n.Op) 129 } 130 Dump("nottop", n) 131 132 case OAS, 133 OASOP, 134 OAS2, 135 OAS2DOTTYPE, 136 OAS2RECV, 137 OAS2FUNC, 138 OAS2MAPR, 139 OCLOSE, 140 OCOPY, 141 OCALLMETH, 142 OCALLINTER, 143 OCALL, 144 OCALLFUNC, 145 ODELETE, 146 OSEND, 147 OPRINT, 148 OPRINTN, 149 OPANIC, 150 OEMPTY, 151 ORECOVER, 152 OGETG: 153 if n.Typecheck() == 0 { 154 Fatalf("missing typecheck: %+v", n) 155 } 156 wascopy := n.Op == OCOPY 157 init := n.Ninit 158 n.Ninit.Set(nil) 159 n = walkexpr(n, &init) 160 n = addinit(n, init.Slice()) 161 if wascopy && n.Op == OCONVNOP { 162 n.Op = OEMPTY // don't leave plain values as statements. 163 } 164 165 // special case for a receive where we throw away 166 // the value received. 167 case ORECV: 168 if n.Typecheck() == 0 { 169 Fatalf("missing typecheck: %+v", n) 170 } 171 init := n.Ninit 172 n.Ninit.Set(nil) 173 174 n.Left = walkexpr(n.Left, &init) 175 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, n.Left, nodnil()) 176 n = walkexpr(n, &init) 177 178 n = addinit(n, init.Slice()) 179 180 case OBREAK, 181 OCONTINUE, 182 OFALL, 183 OGOTO, 184 OLABEL, 185 ODCLCONST, 186 ODCLTYPE, 187 OCHECKNIL, 188 OVARDEF, 189 OVARKILL, 190 OVARLIVE: 191 break 192 193 case ODCL: 194 v := n.Left 195 if v.Class() == PAUTOHEAP { 196 if compiling_runtime { 197 yyerror("%v escapes to heap, not allowed in runtime.", v) 198 } 199 if prealloc[v] == nil { 200 prealloc[v] = callnew(v.Type) 201 } 202 nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v]) 203 nn.SetColas(true) 204 nn = typecheck(nn, ctxStmt) 205 return walkstmt(nn) 206 } 207 208 case OBLOCK: 209 walkstmtlist(n.List.Slice()) 210 211 case OXCASE: 212 yyerror("case statement out of place") 213 n.Op = OCASE 214 fallthrough 215 216 case OCASE: 217 n.Right = walkstmt(n.Right) 218 219 case ODEFER: 220 Curfn.Func.SetHasDefer(true) 221 fallthrough 222 case OGO: 223 switch n.Left.Op { 224 case OPRINT, OPRINTN: 225 n.Left = wrapCall(n.Left, &n.Ninit) 226 227 case ODELETE: 228 if mapfast(n.Left.List.First().Type) == mapslow { 229 n.Left = wrapCall(n.Left, &n.Ninit) 230 } else { 231 n.Left = walkexpr(n.Left, &n.Ninit) 232 } 233 234 case OCOPY: 235 n.Left = copyany(n.Left, &n.Ninit, true) 236 237 default: 238 n.Left = walkexpr(n.Left, &n.Ninit) 239 } 240 241 case OFOR, OFORUNTIL: 242 if n.Left != nil { 243 walkstmtlist(n.Left.Ninit.Slice()) 244 init := n.Left.Ninit 245 n.Left.Ninit.Set(nil) 246 n.Left = walkexpr(n.Left, &init) 247 n.Left = addinit(n.Left, init.Slice()) 248 } 249 250 n.Right = walkstmt(n.Right) 251 if n.Op == OFORUNTIL { 252 walkstmtlist(n.List.Slice()) 253 } 254 walkstmtlist(n.Nbody.Slice()) 255 256 case OIF: 257 n.Left = walkexpr(n.Left, &n.Ninit) 258 walkstmtlist(n.Nbody.Slice()) 259 walkstmtlist(n.Rlist.Slice()) 260 261 case ORETURN: 262 if n.List.Len() == 0 { 263 break 264 } 265 if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) { 266 // assign to the function out parameters, 267 // so that reorder3 can fix up conflicts 268 var rl []*Node 269 270 for _, ln := range Curfn.Func.Dcl { 271 cl := ln.Class() 272 if cl == PAUTO || cl == PAUTOHEAP { 273 break 274 } 275 if cl == PPARAMOUT { 276 if ln.isParamStackCopy() { 277 ln = walkexpr(typecheck(nod(ODEREF, ln.Name.Param.Heapaddr, nil), ctxExpr), nil) 278 } 279 rl = append(rl, ln) 280 } 281 } 282 283 if got, want := n.List.Len(), len(rl); got != want { 284 // order should have rewritten multi-value function calls 285 // with explicit OAS2FUNC nodes. 286 Fatalf("expected %v return arguments, have %v", want, got) 287 } 288 289 if samelist(rl, n.List.Slice()) { 290 // special return in disguise 291 // TODO(josharian, 1.12): is "special return" still relevant? 292 // Tests still pass w/o this. See comments on https://go-review.googlesource.com/c/go/+/118318 293 walkexprlist(n.List.Slice(), &n.Ninit) 294 n.List.Set(nil) 295 296 break 297 } 298 299 // move function calls out, to make reorder3's job easier. 300 walkexprlistsafe(n.List.Slice(), &n.Ninit) 301 302 ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit) 303 n.List.Set(reorder3(ll)) 304 break 305 } 306 walkexprlist(n.List.Slice(), &n.Ninit) 307 308 // For each return parameter (lhs), assign the corresponding result (rhs). 309 lhs := Curfn.Type.Results() 310 rhs := n.List.Slice() 311 res := make([]*Node, lhs.NumFields()) 312 for i, nl := range lhs.FieldSlice() { 313 nname := asNode(nl.Nname) 314 if nname.isParamHeapCopy() { 315 nname = nname.Name.Param.Stackcopy 316 } 317 a := nod(OAS, nname, rhs[i]) 318 res[i] = convas(a, &n.Ninit) 319 } 320 n.List.Set(res) 321 322 case ORETJMP: 323 break 324 325 case OINLMARK: 326 break 327 328 case OSELECT: 329 walkselect(n) 330 331 case OSWITCH: 332 walkswitch(n) 333 334 case ORANGE: 335 n = walkrange(n) 336 } 337 338 if n.Op == ONAME { 339 Fatalf("walkstmt ended up with name: %+v", n) 340 } 341 return n 342 } 343 344 func isSmallMakeSlice(n *Node) bool { 345 if n.Op != OMAKESLICE { 346 return false 347 } 348 l := n.Left 349 r := n.Right 350 if r == nil { 351 r = l 352 } 353 t := n.Type 354 355 return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < maxImplicitStackVarSize/t.Elem().Width) 356 } 357 358 // walk the whole tree of the body of an 359 // expression or simple statement. 360 // the types expressions are calculated. 361 // compile-time constants are evaluated. 362 // complex side effects like statements are appended to init 363 func walkexprlist(s []*Node, init *Nodes) { 364 for i := range s { 365 s[i] = walkexpr(s[i], init) 366 } 367 } 368 369 func walkexprlistsafe(s []*Node, init *Nodes) { 370 for i, n := range s { 371 s[i] = safeexpr(n, init) 372 s[i] = walkexpr(s[i], init) 373 } 374 } 375 376 func walkexprlistcheap(s []*Node, init *Nodes) { 377 for i, n := range s { 378 s[i] = cheapexpr(n, init) 379 s[i] = walkexpr(s[i], init) 380 } 381 } 382 383 // convFuncName builds the runtime function name for interface conversion. 384 // It also reports whether the function expects the data by address. 385 // Not all names are possible. For example, we never generate convE2E or convE2I. 386 func convFuncName(from, to *types.Type) (fnname string, needsaddr bool) { 387 tkind := to.Tie() 388 switch from.Tie() { 389 case 'I': 390 if tkind == 'I' { 391 return "convI2I", false 392 } 393 case 'T': 394 switch { 395 case from.Size() == 2 && from.Align == 2: 396 return "convT16", false 397 case from.Size() == 4 && from.Align == 4 && !types.Haspointers(from): 398 return "convT32", false 399 case from.Size() == 8 && from.Align == types.Types[TUINT64].Align && !types.Haspointers(from): 400 return "convT64", false 401 case from.IsString(): 402 return "convTstring", false 403 case from.IsSlice(): 404 return "convTslice", false 405 } 406 407 switch tkind { 408 case 'E': 409 if !types.Haspointers(from) { 410 return "convT2Enoptr", true 411 } 412 return "convT2E", true 413 case 'I': 414 if !types.Haspointers(from) { 415 return "convT2Inoptr", true 416 } 417 return "convT2I", true 418 } 419 } 420 Fatalf("unknown conv func %c2%c", from.Tie(), to.Tie()) 421 panic("unreachable") 422 } 423 424 // The result of walkexpr MUST be assigned back to n, e.g. 425 // n.Left = walkexpr(n.Left, init) 426 func walkexpr(n *Node, init *Nodes) *Node { 427 if n == nil { 428 return n 429 } 430 431 // Eagerly checkwidth all expressions for the back end. 432 if n.Type != nil && !n.Type.WidthCalculated() { 433 switch n.Type.Etype { 434 case TBLANK, TNIL, TIDEAL: 435 default: 436 checkwidth(n.Type) 437 } 438 } 439 440 if init == &n.Ninit { 441 // not okay to use n->ninit when walking n, 442 // because we might replace n with some other node 443 // and would lose the init list. 444 Fatalf("walkexpr init == &n->ninit") 445 } 446 447 if n.Ninit.Len() != 0 { 448 walkstmtlist(n.Ninit.Slice()) 449 init.AppendNodes(&n.Ninit) 450 } 451 452 lno := setlineno(n) 453 454 if Debug['w'] > 1 { 455 Dump("before walk expr", n) 456 } 457 458 if n.Typecheck() != 1 { 459 Fatalf("missed typecheck: %+v", n) 460 } 461 462 if n.Type.IsUntyped() { 463 Fatalf("expression has untyped type: %+v", n) 464 } 465 466 if n.Op == ONAME && n.Class() == PAUTOHEAP { 467 nn := nod(ODEREF, n.Name.Param.Heapaddr, nil) 468 nn = typecheck(nn, ctxExpr) 469 nn = walkexpr(nn, init) 470 nn.Left.SetNonNil(true) 471 return nn 472 } 473 474 opswitch: 475 switch n.Op { 476 default: 477 Dump("walk", n) 478 Fatalf("walkexpr: switch 1 unknown op %+S", n) 479 480 case ONONAME, OINDREGSP, OEMPTY, OGETG: 481 482 case OTYPE, ONAME, OLITERAL: 483 // TODO(mdempsky): Just return n; see discussion on CL 38655. 484 // Perhaps refactor to use Node.mayBeShared for these instead. 485 // If these return early, make sure to still call 486 // stringsym for constant strings. 487 488 case ONOT, ONEG, OPLUS, OBITNOT, OREAL, OIMAG, ODOTMETH, ODOTINTER, 489 ODEREF, OSPTR, OITAB, OIDATA, OADDR: 490 n.Left = walkexpr(n.Left, init) 491 492 case OEFACE, OAND, OSUB, OMUL, OADD, OOR, OXOR, OLSH, ORSH: 493 n.Left = walkexpr(n.Left, init) 494 n.Right = walkexpr(n.Right, init) 495 496 case ODOT: 497 usefield(n) 498 n.Left = walkexpr(n.Left, init) 499 500 case ODOTTYPE, ODOTTYPE2: 501 n.Left = walkexpr(n.Left, init) 502 // Set up interface type addresses for back end. 503 n.Right = typename(n.Type) 504 if n.Op == ODOTTYPE { 505 n.Right.Right = typename(n.Left.Type) 506 } 507 if !n.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() { 508 n.List.Set1(itabname(n.Type, n.Left.Type)) 509 } 510 511 case ODOTPTR: 512 usefield(n) 513 if n.Op == ODOTPTR && n.Left.Type.Elem().Width == 0 { 514 // No actual copy will be generated, so emit an explicit nil check. 515 n.Left = cheapexpr(n.Left, init) 516 517 checknil(n.Left, init) 518 } 519 520 n.Left = walkexpr(n.Left, init) 521 522 case OLEN, OCAP: 523 if isRuneCount(n) { 524 // Replace len([]rune(string)) with runtime.countrunes(string). 525 n = mkcall("countrunes", n.Type, init, conv(n.Left.Left, types.Types[TSTRING])) 526 break 527 } 528 529 n.Left = walkexpr(n.Left, init) 530 531 // replace len(*[10]int) with 10. 532 // delayed until now to preserve side effects. 533 t := n.Left.Type 534 535 if t.IsPtr() { 536 t = t.Elem() 537 } 538 if t.IsArray() { 539 safeexpr(n.Left, init) 540 setintconst(n, t.NumElem()) 541 n.SetTypecheck(1) 542 } 543 544 case OCOMPLEX: 545 // Use results from call expression as arguments for complex. 546 if n.Left == nil && n.Right == nil { 547 n.Left = n.List.First() 548 n.Right = n.List.Second() 549 } 550 n.Left = walkexpr(n.Left, init) 551 n.Right = walkexpr(n.Right, init) 552 553 case OEQ, ONE, OLT, OLE, OGT, OGE: 554 n = walkcompare(n, init) 555 556 case OANDAND, OOROR: 557 n.Left = walkexpr(n.Left, init) 558 559 // cannot put side effects from n.Right on init, 560 // because they cannot run before n.Left is checked. 561 // save elsewhere and store on the eventual n.Right. 562 var ll Nodes 563 564 n.Right = walkexpr(n.Right, &ll) 565 n.Right = addinit(n.Right, ll.Slice()) 566 n = walkinrange(n, init) 567 568 case OPRINT, OPRINTN: 569 n = walkprint(n, init) 570 571 case OPANIC: 572 n = mkcall("gopanic", nil, init, n.Left) 573 574 case ORECOVER: 575 n = mkcall("gorecover", n.Type, init, nod(OADDR, nodfp, nil)) 576 577 case OCLOSUREVAR, OCFUNC: 578 n.SetAddable(true) 579 580 case OCALLINTER, OCALLFUNC, OCALLMETH: 581 if n.Op == OCALLINTER { 582 usemethod(n) 583 } 584 585 if n.Op == OCALLFUNC && n.Left.Op == OCLOSURE { 586 // Transform direct call of a closure to call of a normal function. 587 // transformclosure already did all preparation work. 588 589 // Prepend captured variables to argument list. 590 n.List.Prepend(n.Left.Func.Enter.Slice()...) 591 592 n.Left.Func.Enter.Set(nil) 593 594 // Replace OCLOSURE with ONAME/PFUNC. 595 n.Left = n.Left.Func.Closure.Func.Nname 596 597 // Update type of OCALLFUNC node. 598 // Output arguments had not changed, but their offsets could. 599 if n.Left.Type.NumResults() == 1 { 600 n.Type = n.Left.Type.Results().Field(0).Type 601 } else { 602 n.Type = n.Left.Type.Results() 603 } 604 } 605 606 walkCall(n, init) 607 608 case OAS, OASOP: 609 init.AppendNodes(&n.Ninit) 610 611 // Recognize m[k] = append(m[k], ...) so we can reuse 612 // the mapassign call. 613 mapAppend := n.Left.Op == OINDEXMAP && n.Right.Op == OAPPEND 614 if mapAppend && !samesafeexpr(n.Left, n.Right.List.First()) { 615 Fatalf("not same expressions: %v != %v", n.Left, n.Right.List.First()) 616 } 617 618 n.Left = walkexpr(n.Left, init) 619 n.Left = safeexpr(n.Left, init) 620 621 if mapAppend { 622 n.Right.List.SetFirst(n.Left) 623 } 624 625 if n.Op == OASOP { 626 // Rewrite x op= y into x = x op y. 627 n.Right = nod(n.SubOp(), n.Left, n.Right) 628 n.Right = typecheck(n.Right, ctxExpr) 629 630 n.Op = OAS 631 n.ResetAux() 632 } 633 634 if oaslit(n, init) { 635 break 636 } 637 638 if n.Right == nil { 639 // TODO(austin): Check all "implicit zeroing" 640 break 641 } 642 643 if !instrumenting && isZero(n.Right) { 644 break 645 } 646 647 switch n.Right.Op { 648 default: 649 n.Right = walkexpr(n.Right, init) 650 651 case ORECV: 652 // x = <-c; n.Left is x, n.Right.Left is c. 653 // orderstmt made sure x is addressable. 654 n.Right.Left = walkexpr(n.Right.Left, init) 655 656 n1 := nod(OADDR, n.Left, nil) 657 r := n.Right.Left // the channel 658 n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, r, n1) 659 n = walkexpr(n, init) 660 break opswitch 661 662 case OAPPEND: 663 // x = append(...) 664 r := n.Right 665 if r.Type.Elem().NotInHeap() { 666 yyerror("%v is go:notinheap; heap allocation disallowed", r.Type.Elem()) 667 } 668 switch { 669 case isAppendOfMake(r): 670 // x = append(y, make([]T, y)...) 671 r = extendslice(r, init) 672 case r.IsDDD(): 673 r = appendslice(r, init) // also works for append(slice, string). 674 default: 675 r = walkappend(r, init, n) 676 } 677 n.Right = r 678 if r.Op == OAPPEND { 679 // Left in place for back end. 680 // Do not add a new write barrier. 681 // Set up address of type for back end. 682 r.Left = typename(r.Type.Elem()) 683 break opswitch 684 } 685 // Otherwise, lowered for race detector. 686 // Treat as ordinary assignment. 687 } 688 689 if n.Left != nil && n.Right != nil { 690 n = convas(n, init) 691 } 692 693 case OAS2: 694 init.AppendNodes(&n.Ninit) 695 walkexprlistsafe(n.List.Slice(), init) 696 walkexprlistsafe(n.Rlist.Slice(), init) 697 ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init) 698 ll = reorder3(ll) 699 n = liststmt(ll) 700 701 // a,b,... = fn() 702 case OAS2FUNC: 703 init.AppendNodes(&n.Ninit) 704 705 r := n.Rlist.First() 706 walkexprlistsafe(n.List.Slice(), init) 707 r = walkexpr(r, init) 708 709 if isIntrinsicCall(r) { 710 n.Rlist.Set1(r) 711 break 712 } 713 init.Append(r) 714 715 ll := ascompatet(n.List, r.Type) 716 n = liststmt(ll) 717 718 // x, y = <-c 719 // orderstmt made sure x is addressable. 720 case OAS2RECV: 721 init.AppendNodes(&n.Ninit) 722 723 r := n.Rlist.First() 724 walkexprlistsafe(n.List.Slice(), init) 725 r.Left = walkexpr(r.Left, init) 726 var n1 *Node 727 if n.List.First().isBlank() { 728 n1 = nodnil() 729 } else { 730 n1 = nod(OADDR, n.List.First(), nil) 731 } 732 fn := chanfn("chanrecv2", 2, r.Left.Type) 733 ok := n.List.Second() 734 call := mkcall1(fn, ok.Type, init, r.Left, n1) 735 n = nod(OAS, ok, call) 736 n = typecheck(n, ctxStmt) 737 738 // a,b = m[i] 739 case OAS2MAPR: 740 init.AppendNodes(&n.Ninit) 741 742 r := n.Rlist.First() 743 walkexprlistsafe(n.List.Slice(), init) 744 r.Left = walkexpr(r.Left, init) 745 r.Right = walkexpr(r.Right, init) 746 t := r.Left.Type 747 748 fast := mapfast(t) 749 var key *Node 750 if fast != mapslow { 751 // fast versions take key by value 752 key = r.Right 753 } else { 754 // standard version takes key by reference 755 // orderexpr made sure key is addressable. 756 key = nod(OADDR, r.Right, nil) 757 } 758 759 // from: 760 // a,b = m[i] 761 // to: 762 // var,b = mapaccess2*(t, m, i) 763 // a = *var 764 a := n.List.First() 765 766 if w := t.Elem().Width; w <= 1024 { // 1024 must match runtime/map.go:maxZero 767 fn := mapfn(mapaccess2[fast], t) 768 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key) 769 } else { 770 fn := mapfn("mapaccess2_fat", t) 771 z := zeroaddr(w) 772 r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z) 773 } 774 775 // mapaccess2* returns a typed bool, but due to spec changes, 776 // the boolean result of i.(T) is now untyped so we make it the 777 // same type as the variable on the lhs. 778 if ok := n.List.Second(); !ok.isBlank() && ok.Type.IsBoolean() { 779 r.Type.Field(1).Type = ok.Type 780 } 781 n.Rlist.Set1(r) 782 n.Op = OAS2FUNC 783 784 // don't generate a = *var if a is _ 785 if !a.isBlank() { 786 var_ := temp(types.NewPtr(t.Elem())) 787 var_.SetTypecheck(1) 788 var_.SetNonNil(true) // mapaccess always returns a non-nil pointer 789 n.List.SetFirst(var_) 790 n = walkexpr(n, init) 791 init.Append(n) 792 n = nod(OAS, a, nod(ODEREF, var_, nil)) 793 } 794 795 n = typecheck(n, ctxStmt) 796 n = walkexpr(n, init) 797 798 case ODELETE: 799 init.AppendNodes(&n.Ninit) 800 map_ := n.List.First() 801 key := n.List.Second() 802 map_ = walkexpr(map_, init) 803 key = walkexpr(key, init) 804 805 t := map_.Type 806 fast := mapfast(t) 807 if fast == mapslow { 808 // orderstmt made sure key is addressable. 809 key = nod(OADDR, key, nil) 810 } 811 n = mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key) 812 813 case OAS2DOTTYPE: 814 walkexprlistsafe(n.List.Slice(), init) 815 n.Rlist.SetFirst(walkexpr(n.Rlist.First(), init)) 816 817 case OCONVIFACE: 818 n.Left = walkexpr(n.Left, init) 819 820 fromType := n.Left.Type 821 toType := n.Type 822 823 // typeword generates the type word of the interface value. 824 typeword := func() *Node { 825 if toType.IsEmptyInterface() { 826 return typename(fromType) 827 } 828 return itabname(fromType, toType) 829 } 830 831 // Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped. 832 if isdirectiface(fromType) { 833 l := nod(OEFACE, typeword(), n.Left) 834 l.Type = toType 835 l.SetTypecheck(n.Typecheck()) 836 n = l 837 break 838 } 839 840 if staticbytes == nil { 841 staticbytes = newname(Runtimepkg.Lookup("staticbytes")) 842 staticbytes.SetClass(PEXTERN) 843 staticbytes.Type = types.NewArray(types.Types[TUINT8], 256) 844 zerobase = newname(Runtimepkg.Lookup("zerobase")) 845 zerobase.SetClass(PEXTERN) 846 zerobase.Type = types.Types[TUINTPTR] 847 } 848 849 // Optimize convT2{E,I} for many cases in which T is not pointer-shaped, 850 // by using an existing addressable value identical to n.Left 851 // or creating one on the stack. 852 var value *Node 853 switch { 854 case fromType.Size() == 0: 855 // n.Left is zero-sized. Use zerobase. 856 cheapexpr(n.Left, init) // Evaluate n.Left for side-effects. See issue 19246. 857 value = zerobase 858 case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()): 859 // n.Left is a bool/byte. Use staticbytes[n.Left]. 860 n.Left = cheapexpr(n.Left, init) 861 value = nod(OINDEX, staticbytes, byteindex(n.Left)) 862 value.SetBounded(true) 863 case n.Left.Class() == PEXTERN && n.Left.Name != nil && n.Left.Name.Readonly(): 864 // n.Left is a readonly global; use it directly. 865 value = n.Left 866 case !fromType.IsInterface() && n.Esc == EscNone && fromType.Width <= 1024: 867 // n.Left does not escape. Use a stack temporary initialized to n.Left. 868 value = temp(fromType) 869 init.Append(typecheck(nod(OAS, value, n.Left), ctxStmt)) 870 } 871 872 if value != nil { 873 // Value is identical to n.Left. 874 // Construct the interface directly: {type/itab, &value}. 875 l := nod(OEFACE, typeword(), typecheck(nod(OADDR, value, nil), ctxExpr)) 876 l.Type = toType 877 l.SetTypecheck(n.Typecheck()) 878 n = l 879 break 880 } 881 882 // Implement interface to empty interface conversion. 883 // tmp = i.itab 884 // if tmp != nil { 885 // tmp = tmp.type 886 // } 887 // e = iface{tmp, i.data} 888 if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() { 889 // Evaluate the input interface. 890 c := temp(fromType) 891 init.Append(nod(OAS, c, n.Left)) 892 893 // Get the itab out of the interface. 894 tmp := temp(types.NewPtr(types.Types[TUINT8])) 895 init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), ctxExpr))) 896 897 // Get the type out of the itab. 898 nif := nod(OIF, typecheck(nod(ONE, tmp, nodnil()), ctxExpr), nil) 899 nif.Nbody.Set1(nod(OAS, tmp, itabType(tmp))) 900 init.Append(nif) 901 902 // Build the result. 903 e := nod(OEFACE, tmp, ifaceData(c, types.NewPtr(types.Types[TUINT8]))) 904 e.Type = toType // assign type manually, typecheck doesn't understand OEFACE. 905 e.SetTypecheck(1) 906 n = e 907 break 908 } 909 910 fnname, needsaddr := convFuncName(fromType, toType) 911 912 if !needsaddr && !fromType.IsInterface() { 913 // Use a specialized conversion routine that only returns a data pointer. 914 // ptr = convT2X(val) 915 // e = iface{typ/tab, ptr} 916 fn := syslook(fnname) 917 dowidth(fromType) 918 fn = substArgTypes(fn, fromType) 919 dowidth(fn.Type) 920 call := nod(OCALL, fn, nil) 921 call.List.Set1(n.Left) 922 call = typecheck(call, ctxExpr) 923 call = walkexpr(call, init) 924 call = safeexpr(call, init) 925 e := nod(OEFACE, typeword(), call) 926 e.Type = toType 927 e.SetTypecheck(1) 928 n = e 929 break 930 } 931 932 var tab *Node 933 if fromType.IsInterface() { 934 // convI2I 935 tab = typename(toType) 936 } else { 937 // convT2x 938 tab = typeword() 939 } 940 941 v := n.Left 942 if needsaddr { 943 // Types of large or unknown size are passed by reference. 944 // Orderexpr arranged for n.Left to be a temporary for all 945 // the conversions it could see. Comparison of an interface 946 // with a non-interface, especially in a switch on interface value 947 // with non-interface cases, is not visible to orderstmt, so we 948 // have to fall back on allocating a temp here. 949 if !islvalue(v) { 950 v = copyexpr(v, v.Type, init) 951 } 952 v = nod(OADDR, v, nil) 953 } 954 955 dowidth(fromType) 956 fn := syslook(fnname) 957 fn = substArgTypes(fn, fromType, toType) 958 dowidth(fn.Type) 959 n = nod(OCALL, fn, nil) 960 n.List.Set2(tab, v) 961 n = typecheck(n, ctxExpr) 962 n = walkexpr(n, init) 963 964 case OCONV, OCONVNOP: 965 n.Left = walkexpr(n.Left, init) 966 param, result := rtconvfn(n.Left.Type, n.Type) 967 if param == Txxx { 968 break 969 } 970 fn := basicnames[param] + "to" + basicnames[result] 971 n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type) 972 973 case OANDNOT: 974 n.Left = walkexpr(n.Left, init) 975 n.Op = OAND 976 n.Right = nod(OBITNOT, n.Right, nil) 977 n.Right = typecheck(n.Right, ctxExpr) 978 n.Right = walkexpr(n.Right, init) 979 980 case ODIV, OMOD: 981 n.Left = walkexpr(n.Left, init) 982 n.Right = walkexpr(n.Right, init) 983 984 // rewrite complex div into function call. 985 et := n.Left.Type.Etype 986 987 if isComplex[et] && n.Op == ODIV { 988 t := n.Type 989 n = mkcall("complex128div", types.Types[TCOMPLEX128], init, conv(n.Left, types.Types[TCOMPLEX128]), conv(n.Right, types.Types[TCOMPLEX128])) 990 n = conv(n, t) 991 break 992 } 993 994 // Nothing to do for float divisions. 995 if isFloat[et] { 996 break 997 } 998 999 // rewrite 64-bit div and mod on 32-bit architectures. 1000 // TODO: Remove this code once we can introduce 1001 // runtime calls late in SSA processing. 1002 if Widthreg < 8 && (et == TINT64 || et == TUINT64) { 1003 if n.Right.Op == OLITERAL { 1004 // Leave div/mod by constant powers of 2. 1005 // The SSA backend will handle those. 1006 switch et { 1007 case TINT64: 1008 c := n.Right.Int64() 1009 if c < 0 { 1010 c = -c 1011 } 1012 if c != 0 && c&(c-1) == 0 { 1013 break opswitch 1014 } 1015 case TUINT64: 1016 c := uint64(n.Right.Int64()) 1017 if c != 0 && c&(c-1) == 0 { 1018 break opswitch 1019 } 1020 } 1021 } 1022 var fn string 1023 if et == TINT64 { 1024 fn = "int64" 1025 } else { 1026 fn = "uint64" 1027 } 1028 if n.Op == ODIV { 1029 fn += "div" 1030 } else { 1031 fn += "mod" 1032 } 1033 n = mkcall(fn, n.Type, init, conv(n.Left, types.Types[et]), conv(n.Right, types.Types[et])) 1034 } 1035 1036 case OINDEX: 1037 n.Left = walkexpr(n.Left, init) 1038 1039 // save the original node for bounds checking elision. 1040 // If it was a ODIV/OMOD walk might rewrite it. 1041 r := n.Right 1042 1043 n.Right = walkexpr(n.Right, init) 1044 1045 // if range of type cannot exceed static array bound, 1046 // disable bounds check. 1047 if n.Bounded() { 1048 break 1049 } 1050 t := n.Left.Type 1051 if t != nil && t.IsPtr() { 1052 t = t.Elem() 1053 } 1054 if t.IsArray() { 1055 n.SetBounded(bounded(r, t.NumElem())) 1056 if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) { 1057 Warn("index bounds check elided") 1058 } 1059 if smallintconst(n.Right) && !n.Bounded() { 1060 yyerror("index out of bounds") 1061 } 1062 } else if Isconst(n.Left, CTSTR) { 1063 n.SetBounded(bounded(r, int64(len(n.Left.Val().U.(string))))) 1064 if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) { 1065 Warn("index bounds check elided") 1066 } 1067 if smallintconst(n.Right) && !n.Bounded() { 1068 yyerror("index out of bounds") 1069 } 1070 } 1071 1072 if Isconst(n.Right, CTINT) { 1073 if n.Right.Val().U.(*Mpint).CmpInt64(0) < 0 || n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { 1074 yyerror("index out of bounds") 1075 } 1076 } 1077 1078 case OINDEXMAP: 1079 // Replace m[k] with *map{access1,assign}(maptype, m, &k) 1080 n.Left = walkexpr(n.Left, init) 1081 n.Right = walkexpr(n.Right, init) 1082 map_ := n.Left 1083 key := n.Right 1084 t := map_.Type 1085 if n.IndexMapLValue() { 1086 // This m[k] expression is on the left-hand side of an assignment. 1087 fast := mapfast(t) 1088 if fast == mapslow { 1089 // standard version takes key by reference. 1090 // orderexpr made sure key is addressable. 1091 key = nod(OADDR, key, nil) 1092 } 1093 n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key) 1094 } else { 1095 // m[k] is not the target of an assignment. 1096 fast := mapfast(t) 1097 if fast == mapslow { 1098 // standard version takes key by reference. 1099 // orderexpr made sure key is addressable. 1100 key = nod(OADDR, key, nil) 1101 } 1102 1103 if w := t.Elem().Width; w <= 1024 { // 1024 must match runtime/map.go:maxZero 1104 n = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Elem()), init, typename(t), map_, key) 1105 } else { 1106 z := zeroaddr(w) 1107 n = mkcall1(mapfn("mapaccess1_fat", t), types.NewPtr(t.Elem()), init, typename(t), map_, key, z) 1108 } 1109 } 1110 n.Type = types.NewPtr(t.Elem()) 1111 n.SetNonNil(true) // mapaccess1* and mapassign always return non-nil pointers. 1112 n = nod(ODEREF, n, nil) 1113 n.Type = t.Elem() 1114 n.SetTypecheck(1) 1115 1116 case ORECV: 1117 Fatalf("walkexpr ORECV") // should see inside OAS only 1118 1119 case OSLICEHEADER: 1120 n.Left = walkexpr(n.Left, init) 1121 n.List.SetFirst(walkexpr(n.List.First(), init)) 1122 n.List.SetSecond(walkexpr(n.List.Second(), init)) 1123 1124 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1125 n.Left = walkexpr(n.Left, init) 1126 low, high, max := n.SliceBounds() 1127 low = walkexpr(low, init) 1128 if low != nil && isZero(low) { 1129 // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k]. 1130 low = nil 1131 } 1132 high = walkexpr(high, init) 1133 max = walkexpr(max, init) 1134 n.SetSliceBounds(low, high, max) 1135 if n.Op.IsSlice3() { 1136 if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) { 1137 // Reduce x[i:j:cap(x)] to x[i:j]. 1138 if n.Op == OSLICE3 { 1139 n.Op = OSLICE 1140 } else { 1141 n.Op = OSLICEARR 1142 } 1143 n = reduceSlice(n) 1144 } 1145 } else { 1146 n = reduceSlice(n) 1147 } 1148 1149 case ONEW: 1150 if n.Esc == EscNone { 1151 if n.Type.Elem().Width >= maxImplicitStackVarSize { 1152 Fatalf("large ONEW with EscNone: %v", n) 1153 } 1154 r := temp(n.Type.Elem()) 1155 r = nod(OAS, r, nil) // zero temp 1156 r = typecheck(r, ctxStmt) 1157 init.Append(r) 1158 r = nod(OADDR, r.Left, nil) 1159 r = typecheck(r, ctxExpr) 1160 n = r 1161 } else { 1162 n = callnew(n.Type.Elem()) 1163 } 1164 1165 case OADDSTR: 1166 n = addstr(n, init) 1167 1168 case OAPPEND: 1169 // order should make sure we only see OAS(node, OAPPEND), which we handle above. 1170 Fatalf("append outside assignment") 1171 1172 case OCOPY: 1173 n = copyany(n, init, instrumenting && !compiling_runtime) 1174 1175 // cannot use chanfn - closechan takes any, not chan any 1176 case OCLOSE: 1177 fn := syslook("closechan") 1178 1179 fn = substArgTypes(fn, n.Left.Type) 1180 n = mkcall1(fn, nil, init, n.Left) 1181 1182 case OMAKECHAN: 1183 // When size fits into int, use makechan instead of 1184 // makechan64, which is faster and shorter on 32 bit platforms. 1185 size := n.Left 1186 fnname := "makechan64" 1187 argtype := types.Types[TINT64] 1188 1189 // Type checking guarantees that TIDEAL size is positive and fits in an int. 1190 // The case of size overflow when converting TUINT or TUINTPTR to TINT 1191 // will be handled by the negative range checks in makechan during runtime. 1192 if size.Type.IsKind(TIDEAL) || maxintval[size.Type.Etype].Cmp(maxintval[TUINT]) <= 0 { 1193 fnname = "makechan" 1194 argtype = types.Types[TINT] 1195 } 1196 1197 n = mkcall1(chanfn(fnname, 1, n.Type), n.Type, init, typename(n.Type), conv(size, argtype)) 1198 1199 case OMAKEMAP: 1200 t := n.Type 1201 hmapType := hmap(t) 1202 hint := n.Left 1203 1204 // var h *hmap 1205 var h *Node 1206 if n.Esc == EscNone { 1207 // Allocate hmap on stack. 1208 1209 // var hv hmap 1210 hv := temp(hmapType) 1211 zero := nod(OAS, hv, nil) 1212 zero = typecheck(zero, ctxStmt) 1213 init.Append(zero) 1214 // h = &hv 1215 h = nod(OADDR, hv, nil) 1216 1217 // Allocate one bucket pointed to by hmap.buckets on stack if hint 1218 // is not larger than BUCKETSIZE. In case hint is larger than 1219 // BUCKETSIZE runtime.makemap will allocate the buckets on the heap. 1220 // Maximum key and value size is 128 bytes, larger objects 1221 // are stored with an indirection. So max bucket size is 2048+eps. 1222 if !Isconst(hint, CTINT) || 1223 hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 { 1224 // var bv bmap 1225 bv := temp(bmap(t)) 1226 1227 zero = nod(OAS, bv, nil) 1228 zero = typecheck(zero, ctxStmt) 1229 init.Append(zero) 1230 1231 // b = &bv 1232 b := nod(OADDR, bv, nil) 1233 1234 // h.buckets = b 1235 bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap 1236 na := nod(OAS, nodSym(ODOT, h, bsym), b) 1237 na = typecheck(na, ctxStmt) 1238 init.Append(na) 1239 } 1240 } 1241 1242 if Isconst(hint, CTINT) && hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 { 1243 // Handling make(map[any]any) and 1244 // make(map[any]any, hint) where hint <= BUCKETSIZE 1245 // special allows for faster map initialization and 1246 // improves binary size by using calls with fewer arguments. 1247 // For hint <= BUCKETSIZE overLoadFactor(hint, 0) is false 1248 // and no buckets will be allocated by makemap. Therefore, 1249 // no buckets need to be allocated in this code path. 1250 if n.Esc == EscNone { 1251 // Only need to initialize h.hash0 since 1252 // hmap h has been allocated on the stack already. 1253 // h.hash0 = fastrand() 1254 rand := mkcall("fastrand", types.Types[TUINT32], init) 1255 hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap 1256 a := nod(OAS, nodSym(ODOT, h, hashsym), rand) 1257 a = typecheck(a, ctxStmt) 1258 a = walkexpr(a, init) 1259 init.Append(a) 1260 n = convnop(h, t) 1261 } else { 1262 // Call runtime.makehmap to allocate an 1263 // hmap on the heap and initialize hmap's hash0 field. 1264 fn := syslook("makemap_small") 1265 fn = substArgTypes(fn, t.Key(), t.Elem()) 1266 n = mkcall1(fn, n.Type, init) 1267 } 1268 } else { 1269 if n.Esc != EscNone { 1270 h = nodnil() 1271 } 1272 // Map initialization with a variable or large hint is 1273 // more complicated. We therefore generate a call to 1274 // runtime.makemap to intialize hmap and allocate the 1275 // map buckets. 1276 1277 // When hint fits into int, use makemap instead of 1278 // makemap64, which is faster and shorter on 32 bit platforms. 1279 fnname := "makemap64" 1280 argtype := types.Types[TINT64] 1281 1282 // Type checking guarantees that TIDEAL hint is positive and fits in an int. 1283 // See checkmake call in TMAP case of OMAKE case in OpSwitch in typecheck1 function. 1284 // The case of hint overflow when converting TUINT or TUINTPTR to TINT 1285 // will be handled by the negative range checks in makemap during runtime. 1286 if hint.Type.IsKind(TIDEAL) || maxintval[hint.Type.Etype].Cmp(maxintval[TUINT]) <= 0 { 1287 fnname = "makemap" 1288 argtype = types.Types[TINT] 1289 } 1290 1291 fn := syslook(fnname) 1292 fn = substArgTypes(fn, hmapType, t.Key(), t.Elem()) 1293 n = mkcall1(fn, n.Type, init, typename(n.Type), conv(hint, argtype), h) 1294 } 1295 1296 case OMAKESLICE: 1297 l := n.Left 1298 r := n.Right 1299 if r == nil { 1300 r = safeexpr(l, init) 1301 l = r 1302 } 1303 t := n.Type 1304 if n.Esc == EscNone { 1305 if !isSmallMakeSlice(n) { 1306 Fatalf("non-small OMAKESLICE with EscNone: %v", n) 1307 } 1308 // var arr [r]T 1309 // n = arr[:l] 1310 i := indexconst(r) 1311 if i < 0 { 1312 Fatalf("walkexpr: invalid index %v", r) 1313 } 1314 t = types.NewArray(t.Elem(), i) // [r]T 1315 var_ := temp(t) 1316 a := nod(OAS, var_, nil) // zero temp 1317 a = typecheck(a, ctxStmt) 1318 init.Append(a) 1319 r := nod(OSLICE, var_, nil) // arr[:l] 1320 r.SetSliceBounds(nil, l, nil) 1321 r = conv(r, n.Type) // in case n.Type is named. 1322 r = typecheck(r, ctxExpr) 1323 r = walkexpr(r, init) 1324 n = r 1325 } else { 1326 // n escapes; set up a call to makeslice. 1327 // When len and cap can fit into int, use makeslice instead of 1328 // makeslice64, which is faster and shorter on 32 bit platforms. 1329 1330 if t.Elem().NotInHeap() { 1331 yyerror("%v is go:notinheap; heap allocation disallowed", t.Elem()) 1332 } 1333 1334 len, cap := l, r 1335 1336 fnname := "makeslice64" 1337 argtype := types.Types[TINT64] 1338 1339 // Type checking guarantees that TIDEAL len/cap are positive and fit in an int. 1340 // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT 1341 // will be handled by the negative range checks in makeslice during runtime. 1342 if (len.Type.IsKind(TIDEAL) || maxintval[len.Type.Etype].Cmp(maxintval[TUINT]) <= 0) && 1343 (cap.Type.IsKind(TIDEAL) || maxintval[cap.Type.Etype].Cmp(maxintval[TUINT]) <= 0) { 1344 fnname = "makeslice" 1345 argtype = types.Types[TINT] 1346 } 1347 1348 m := nod(OSLICEHEADER, nil, nil) 1349 m.Type = t 1350 1351 fn := syslook(fnname) 1352 m.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype)) 1353 m.Left.SetNonNil(true) 1354 m.List.Set2(conv(len, types.Types[TINT]), conv(cap, types.Types[TINT])) 1355 1356 m = typecheck(m, ctxExpr) 1357 m = walkexpr(m, init) 1358 n = m 1359 } 1360 1361 case ORUNESTR: 1362 a := nodnil() 1363 if n.Esc == EscNone { 1364 t := types.NewArray(types.Types[TUINT8], 4) 1365 var_ := temp(t) 1366 a = nod(OADDR, var_, nil) 1367 } 1368 1369 // intstring(*[4]byte, rune) 1370 n = mkcall("intstring", n.Type, init, a, conv(n.Left, types.Types[TINT64])) 1371 1372 case OBYTES2STR: 1373 a := nodnil() 1374 if n.Esc == EscNone { 1375 // Create temporary buffer for string on stack. 1376 t := types.NewArray(types.Types[TUINT8], tmpstringbufsize) 1377 1378 a = nod(OADDR, temp(t), nil) 1379 } 1380 1381 // slicebytetostring(*[32]byte, []byte) string; 1382 n = mkcall("slicebytetostring", n.Type, init, a, n.Left) 1383 1384 // slicebytetostringtmp([]byte) string; 1385 case OBYTES2STRTMP: 1386 n.Left = walkexpr(n.Left, init) 1387 1388 if !instrumenting { 1389 // Let the backend handle OBYTES2STRTMP directly 1390 // to avoid a function call to slicebytetostringtmp. 1391 break 1392 } 1393 1394 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left) 1395 1396 // slicerunetostring(*[32]byte, []rune) string; 1397 case ORUNES2STR: 1398 a := nodnil() 1399 1400 if n.Esc == EscNone { 1401 // Create temporary buffer for string on stack. 1402 t := types.NewArray(types.Types[TUINT8], tmpstringbufsize) 1403 1404 a = nod(OADDR, temp(t), nil) 1405 } 1406 1407 n = mkcall("slicerunetostring", n.Type, init, a, n.Left) 1408 1409 case OSTR2BYTES: 1410 s := n.Left 1411 if Isconst(s, CTSTR) { 1412 sc := s.Val().U.(string) 1413 1414 // Allocate a [n]byte of the right size. 1415 t := types.NewArray(types.Types[TUINT8], int64(len(sc))) 1416 var a *Node 1417 if n.Esc == EscNone && len(sc) <= maxImplicitStackVarSize { 1418 a = nod(OADDR, temp(t), nil) 1419 } else { 1420 a = callnew(t) 1421 } 1422 p := temp(t.PtrTo()) // *[n]byte 1423 init.Append(typecheck(nod(OAS, p, a), ctxStmt)) 1424 1425 // Copy from the static string data to the [n]byte. 1426 if len(sc) > 0 { 1427 as := nod(OAS, 1428 nod(ODEREF, p, nil), 1429 nod(ODEREF, convnop(nod(OSPTR, s, nil), t.PtrTo()), nil)) 1430 as = typecheck(as, ctxStmt) 1431 as = walkstmt(as) 1432 init.Append(as) 1433 } 1434 1435 // Slice the [n]byte to a []byte. 1436 n.Op = OSLICEARR 1437 n.Left = p 1438 n = walkexpr(n, init) 1439 break 1440 } 1441 a := nodnil() 1442 1443 if n.Esc == EscNone { 1444 // Create temporary buffer for slice on stack. 1445 t := types.NewArray(types.Types[TUINT8], tmpstringbufsize) 1446 1447 a = nod(OADDR, temp(t), nil) 1448 } 1449 1450 // stringtoslicebyte(*32[byte], string) []byte; 1451 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(s, types.Types[TSTRING])) 1452 1453 case OSTR2BYTESTMP: 1454 // []byte(string) conversion that creates a slice 1455 // referring to the actual string bytes. 1456 // This conversion is handled later by the backend and 1457 // is only for use by internal compiler optimizations 1458 // that know that the slice won't be mutated. 1459 // The only such case today is: 1460 // for i, c := range []byte(string) 1461 n.Left = walkexpr(n.Left, init) 1462 1463 // stringtoslicerune(*[32]rune, string) []rune 1464 case OSTR2RUNES: 1465 a := nodnil() 1466 1467 if n.Esc == EscNone { 1468 // Create temporary buffer for slice on stack. 1469 t := types.NewArray(types.Types[TINT32], tmpstringbufsize) 1470 1471 a = nod(OADDR, temp(t), nil) 1472 } 1473 1474 n = mkcall("stringtoslicerune", n.Type, init, a, conv(n.Left, types.Types[TSTRING])) 1475 1476 case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT: 1477 if isStaticCompositeLiteral(n) && !canSSAType(n.Type) { 1478 // n can be directly represented in the read-only data section. 1479 // Make direct reference to the static data. See issue 12841. 1480 vstat := staticname(n.Type) 1481 vstat.Name.SetReadonly(true) 1482 fixedlit(inInitFunction, initKindStatic, n, vstat, init) 1483 n = vstat 1484 n = typecheck(n, ctxExpr) 1485 break 1486 } 1487 var_ := temp(n.Type) 1488 anylit(n, var_, init) 1489 n = var_ 1490 1491 case OSEND: 1492 n1 := n.Right 1493 n1 = assignconv(n1, n.Left.Type.Elem(), "chan send") 1494 n1 = walkexpr(n1, init) 1495 n1 = nod(OADDR, n1, nil) 1496 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, n.Left, n1) 1497 1498 case OCLOSURE: 1499 n = walkclosure(n, init) 1500 1501 case OCALLPART: 1502 n = walkpartialcall(n, init) 1503 } 1504 1505 // Expressions that are constant at run time but not 1506 // considered const by the language spec are not turned into 1507 // constants until walk. For example, if n is y%1 == 0, the 1508 // walk of y%1 may have replaced it by 0. 1509 // Check whether n with its updated args is itself now a constant. 1510 t := n.Type 1511 evconst(n) 1512 if n.Type != t { 1513 Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type) 1514 } 1515 if n.Op == OLITERAL { 1516 n = typecheck(n, ctxExpr) 1517 // Emit string symbol now to avoid emitting 1518 // any concurrently during the backend. 1519 if s, ok := n.Val().U.(string); ok { 1520 _ = stringsym(n.Pos, s) 1521 } 1522 } 1523 1524 updateHasCall(n) 1525 1526 if Debug['w'] != 0 && n != nil { 1527 Dump("after walk expr", n) 1528 } 1529 1530 lineno = lno 1531 return n 1532 } 1533 1534 // rtconvfn returns the parameter and result types that will be used by a 1535 // runtime function to convert from type src to type dst. The runtime function 1536 // name can be derived from the names of the returned types. 1537 // 1538 // If no such function is necessary, it returns (Txxx, Txxx). 1539 func rtconvfn(src, dst *types.Type) (param, result types.EType) { 1540 if thearch.SoftFloat { 1541 return Txxx, Txxx 1542 } 1543 1544 switch thearch.LinkArch.Family { 1545 case sys.ARM, sys.MIPS: 1546 if src.IsFloat() { 1547 switch dst.Etype { 1548 case TINT64, TUINT64: 1549 return TFLOAT64, dst.Etype 1550 } 1551 } 1552 if dst.IsFloat() { 1553 switch src.Etype { 1554 case TINT64, TUINT64: 1555 return src.Etype, TFLOAT64 1556 } 1557 } 1558 1559 case sys.I386: 1560 if src.IsFloat() { 1561 switch dst.Etype { 1562 case TINT64, TUINT64: 1563 return TFLOAT64, dst.Etype 1564 case TUINT32, TUINT, TUINTPTR: 1565 return TFLOAT64, TUINT32 1566 } 1567 } 1568 if dst.IsFloat() { 1569 switch src.Etype { 1570 case TINT64, TUINT64: 1571 return src.Etype, TFLOAT64 1572 case TUINT32, TUINT, TUINTPTR: 1573 return TUINT32, TFLOAT64 1574 } 1575 } 1576 } 1577 return Txxx, Txxx 1578 } 1579 1580 // TODO(josharian): combine this with its caller and simplify 1581 func reduceSlice(n *Node) *Node { 1582 low, high, max := n.SliceBounds() 1583 if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) { 1584 // Reduce x[i:len(x)] to x[i:]. 1585 high = nil 1586 } 1587 n.SetSliceBounds(low, high, max) 1588 if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil { 1589 // Reduce x[:] to x. 1590 if Debug_slice > 0 { 1591 Warn("slice: omit slice operation") 1592 } 1593 return n.Left 1594 } 1595 return n 1596 } 1597 1598 func ascompatee1(l *Node, r *Node, init *Nodes) *Node { 1599 // convas will turn map assigns into function calls, 1600 // making it impossible for reorder3 to work. 1601 n := nod(OAS, l, r) 1602 1603 if l.Op == OINDEXMAP { 1604 return n 1605 } 1606 1607 return convas(n, init) 1608 } 1609 1610 func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node { 1611 // check assign expression list to 1612 // an expression list. called in 1613 // expr-list = expr-list 1614 1615 // ensure order of evaluation for function calls 1616 for i := range nl { 1617 nl[i] = safeexpr(nl[i], init) 1618 } 1619 for i1 := range nr { 1620 nr[i1] = safeexpr(nr[i1], init) 1621 } 1622 1623 var nn []*Node 1624 i := 0 1625 for ; i < len(nl); i++ { 1626 if i >= len(nr) { 1627 break 1628 } 1629 // Do not generate 'x = x' during return. See issue 4014. 1630 if op == ORETURN && samesafeexpr(nl[i], nr[i]) { 1631 continue 1632 } 1633 nn = append(nn, ascompatee1(nl[i], nr[i], init)) 1634 } 1635 1636 // cannot happen: caller checked that lists had same length 1637 if i < len(nl) || i < len(nr) { 1638 var nln, nrn Nodes 1639 nln.Set(nl) 1640 nrn.Set(nr) 1641 Fatalf("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), Curfn.funcname()) 1642 } 1643 return nn 1644 } 1645 1646 // fncall reports whether assigning an rvalue of type rt to an lvalue l might involve a function call. 1647 func fncall(l *Node, rt *types.Type) bool { 1648 if l.HasCall() || l.Op == OINDEXMAP { 1649 return true 1650 } 1651 if types.Identical(l.Type, rt) { 1652 return false 1653 } 1654 // There might be a conversion required, which might involve a runtime call. 1655 return true 1656 } 1657 1658 // check assign type list to 1659 // an expression list. called in 1660 // expr-list = func() 1661 func ascompatet(nl Nodes, nr *types.Type) []*Node { 1662 if nl.Len() != nr.NumFields() { 1663 Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields()) 1664 } 1665 1666 var nn, mm Nodes 1667 for i, l := range nl.Slice() { 1668 if l.isBlank() { 1669 continue 1670 } 1671 r := nr.Field(i) 1672 1673 // Any assignment to an lvalue that might cause a function call must be 1674 // deferred until all the returned values have been read. 1675 if fncall(l, r.Type) { 1676 tmp := temp(r.Type) 1677 tmp = typecheck(tmp, ctxExpr) 1678 a := nod(OAS, l, tmp) 1679 a = convas(a, &mm) 1680 mm.Append(a) 1681 l = tmp 1682 } 1683 1684 a := nod(OAS, l, nodarg(r)) 1685 a = convas(a, &nn) 1686 updateHasCall(a) 1687 if a.HasCall() { 1688 Dump("ascompatet ucount", a) 1689 Fatalf("ascompatet: too many function calls evaluating parameters") 1690 } 1691 1692 nn.Append(a) 1693 } 1694 return append(nn.Slice(), mm.Slice()...) 1695 } 1696 1697 // nodarg returns a Node for the function argument f. 1698 // f is a *types.Field within a struct *types.Type. 1699 // 1700 // The node is for use by a caller invoking the given 1701 // function, preparing the arguments before the call 1702 // or retrieving the results after the call. 1703 // In this case, the node will correspond to an outgoing argument 1704 // slot like 8(SP). 1705 func nodarg(f *types.Field) *Node { 1706 // Build fake name for individual variable. 1707 n := newname(lookup("__")) 1708 n.Type = f.Type 1709 if f.Offset == BADWIDTH { 1710 Fatalf("nodarg: offset not computed for %v", f) 1711 } 1712 n.Xoffset = f.Offset 1713 n.Orig = asNode(f.Nname) 1714 1715 // preparing arguments for call 1716 n.Op = OINDREGSP 1717 n.Xoffset += Ctxt.FixedFrameSize() 1718 n.SetTypecheck(1) 1719 n.SetAddrtaken(true) // keep optimizers at bay 1720 return n 1721 } 1722 1723 // package all the arguments that match a ... T parameter into a []T. 1724 func mkdotargslice(typ *types.Type, args []*Node, init *Nodes, ddd *Node) *Node { 1725 esc := uint16(EscUnknown) 1726 if ddd != nil { 1727 esc = ddd.Esc 1728 } 1729 1730 if len(args) == 0 { 1731 n := nodnil() 1732 n.Type = typ 1733 return n 1734 } 1735 1736 n := nod(OCOMPLIT, nil, typenod(typ)) 1737 if ddd != nil && prealloc[ddd] != nil { 1738 prealloc[n] = prealloc[ddd] // temporary to use 1739 } 1740 n.List.Set(args) 1741 n.Esc = esc 1742 n = typecheck(n, ctxExpr) 1743 if n.Type == nil { 1744 Fatalf("mkdotargslice: typecheck failed") 1745 } 1746 n = walkexpr(n, init) 1747 return n 1748 } 1749 1750 func walkCall(n *Node, init *Nodes) { 1751 if n.Rlist.Len() != 0 { 1752 return // already walked 1753 } 1754 n.Left = walkexpr(n.Left, init) 1755 walkexprlist(n.List.Slice(), init) 1756 1757 params := n.Left.Type.Params() 1758 args := n.List.Slice() 1759 // If there's a ... parameter (which is only valid as the final 1760 // parameter) and this is not a ... call expression, 1761 // then assign the remaining arguments as a slice. 1762 if nf := params.NumFields(); nf > 0 { 1763 if last := params.Field(nf - 1); last.IsDDD() && !n.IsDDD() { 1764 tail := args[nf-1:] 1765 slice := mkdotargslice(last.Type, tail, init, n.Right) 1766 // Allow immediate GC. 1767 for i := range tail { 1768 tail[i] = nil 1769 } 1770 args = append(args[:nf-1], slice) 1771 } 1772 } 1773 1774 // If this is a method call, add the receiver at the beginning of the args. 1775 if n.Op == OCALLMETH { 1776 withRecv := make([]*Node, len(args)+1) 1777 withRecv[0] = n.Left.Left 1778 n.Left.Left = nil 1779 copy(withRecv[1:], args) 1780 args = withRecv 1781 } 1782 1783 // For any argument whose evaluation might require a function call, 1784 // store that argument into a temporary variable, 1785 // to prevent that calls from clobbering arguments already on the stack. 1786 // When instrumenting, all arguments might require function calls. 1787 var tempAssigns []*Node 1788 for i, arg := range args { 1789 updateHasCall(arg) 1790 // Determine param type. 1791 var t *types.Type 1792 if n.Op == OCALLMETH { 1793 if i == 0 { 1794 t = n.Left.Type.Recv().Type 1795 } else { 1796 t = params.Field(i - 1).Type 1797 } 1798 } else { 1799 t = params.Field(i).Type 1800 } 1801 if instrumenting || fncall(arg, t) { 1802 // make assignment of fncall to tempname 1803 tmp := temp(t) 1804 a := nod(OAS, tmp, arg) 1805 a = convas(a, init) 1806 tempAssigns = append(tempAssigns, a) 1807 // replace arg with temp 1808 args[i] = tmp 1809 } 1810 } 1811 1812 n.List.Set(tempAssigns) 1813 n.Rlist.Set(args) 1814 } 1815 1816 // generate code for print 1817 func walkprint(nn *Node, init *Nodes) *Node { 1818 // Hoist all the argument evaluation up before the lock. 1819 walkexprlistcheap(nn.List.Slice(), init) 1820 1821 // For println, add " " between elements and "\n" at the end. 1822 if nn.Op == OPRINTN { 1823 s := nn.List.Slice() 1824 t := make([]*Node, 0, len(s)*2) 1825 for i, n := range s { 1826 if i != 0 { 1827 t = append(t, nodstr(" ")) 1828 } 1829 t = append(t, n) 1830 } 1831 t = append(t, nodstr("\n")) 1832 nn.List.Set(t) 1833 } 1834 1835 // Collapse runs of constant strings. 1836 s := nn.List.Slice() 1837 t := make([]*Node, 0, len(s)) 1838 for i := 0; i < len(s); { 1839 var strs []string 1840 for i < len(s) && Isconst(s[i], CTSTR) { 1841 strs = append(strs, s[i].Val().U.(string)) 1842 i++ 1843 } 1844 if len(strs) > 0 { 1845 t = append(t, nodstr(strings.Join(strs, ""))) 1846 } 1847 if i < len(s) { 1848 t = append(t, s[i]) 1849 i++ 1850 } 1851 } 1852 nn.List.Set(t) 1853 1854 calls := []*Node{mkcall("printlock", nil, init)} 1855 for i, n := range nn.List.Slice() { 1856 if n.Op == OLITERAL { 1857 switch n.Val().Ctype() { 1858 case CTRUNE: 1859 n = defaultlit(n, types.Runetype) 1860 1861 case CTINT: 1862 n = defaultlit(n, types.Types[TINT64]) 1863 1864 case CTFLT: 1865 n = defaultlit(n, types.Types[TFLOAT64]) 1866 } 1867 } 1868 1869 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL { 1870 n = defaultlit(n, types.Types[TINT64]) 1871 } 1872 n = defaultlit(n, nil) 1873 nn.List.SetIndex(i, n) 1874 if n.Type == nil || n.Type.Etype == TFORW { 1875 continue 1876 } 1877 1878 var on *Node 1879 switch n.Type.Etype { 1880 case TINTER: 1881 if n.Type.IsEmptyInterface() { 1882 on = syslook("printeface") 1883 } else { 1884 on = syslook("printiface") 1885 } 1886 on = substArgTypes(on, n.Type) // any-1 1887 case TPTR, TCHAN, TMAP, TFUNC, TUNSAFEPTR: 1888 on = syslook("printpointer") 1889 on = substArgTypes(on, n.Type) // any-1 1890 case TSLICE: 1891 on = syslook("printslice") 1892 on = substArgTypes(on, n.Type) // any-1 1893 case TUINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINTPTR: 1894 if isRuntimePkg(n.Type.Sym.Pkg) && n.Type.Sym.Name == "hex" { 1895 on = syslook("printhex") 1896 } else { 1897 on = syslook("printuint") 1898 } 1899 case TINT, TINT8, TINT16, TINT32, TINT64: 1900 on = syslook("printint") 1901 case TFLOAT32, TFLOAT64: 1902 on = syslook("printfloat") 1903 case TCOMPLEX64, TCOMPLEX128: 1904 on = syslook("printcomplex") 1905 case TBOOL: 1906 on = syslook("printbool") 1907 case TSTRING: 1908 cs := "" 1909 if Isconst(n, CTSTR) { 1910 cs = n.Val().U.(string) 1911 } 1912 switch cs { 1913 case " ": 1914 on = syslook("printsp") 1915 case "\n": 1916 on = syslook("printnl") 1917 default: 1918 on = syslook("printstring") 1919 } 1920 default: 1921 badtype(OPRINT, n.Type, nil) 1922 continue 1923 } 1924 1925 r := nod(OCALL, on, nil) 1926 if params := on.Type.Params().FieldSlice(); len(params) > 0 { 1927 t := params[0].Type 1928 if !types.Identical(t, n.Type) { 1929 n = nod(OCONV, n, nil) 1930 n.Type = t 1931 } 1932 r.List.Append(n) 1933 } 1934 calls = append(calls, r) 1935 } 1936 1937 calls = append(calls, mkcall("printunlock", nil, init)) 1938 1939 typecheckslice(calls, ctxStmt) 1940 walkexprlist(calls, init) 1941 1942 r := nod(OEMPTY, nil, nil) 1943 r = typecheck(r, ctxStmt) 1944 r = walkexpr(r, init) 1945 r.Ninit.Set(calls) 1946 return r 1947 } 1948 1949 func callnew(t *types.Type) *Node { 1950 if t.NotInHeap() { 1951 yyerror("%v is go:notinheap; heap allocation disallowed", t) 1952 } 1953 dowidth(t) 1954 fn := syslook("newobject") 1955 fn = substArgTypes(fn, t) 1956 v := mkcall1(fn, types.NewPtr(t), nil, typename(t)) 1957 v.SetNonNil(true) 1958 return v 1959 } 1960 1961 // isReflectHeaderDataField reports whether l is an expression p.Data 1962 // where p has type reflect.SliceHeader or reflect.StringHeader. 1963 func isReflectHeaderDataField(l *Node) bool { 1964 if l.Type != types.Types[TUINTPTR] { 1965 return false 1966 } 1967 1968 var tsym *types.Sym 1969 switch l.Op { 1970 case ODOT: 1971 tsym = l.Left.Type.Sym 1972 case ODOTPTR: 1973 tsym = l.Left.Type.Elem().Sym 1974 default: 1975 return false 1976 } 1977 1978 if tsym == nil || l.Sym.Name != "Data" || tsym.Pkg.Path != "reflect" { 1979 return false 1980 } 1981 return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader" 1982 } 1983 1984 func convas(n *Node, init *Nodes) *Node { 1985 if n.Op != OAS { 1986 Fatalf("convas: not OAS %v", n.Op) 1987 } 1988 defer updateHasCall(n) 1989 1990 n.SetTypecheck(1) 1991 1992 if n.Left == nil || n.Right == nil { 1993 return n 1994 } 1995 1996 lt := n.Left.Type 1997 rt := n.Right.Type 1998 if lt == nil || rt == nil { 1999 return n 2000 } 2001 2002 if n.Left.isBlank() { 2003 n.Right = defaultlit(n.Right, nil) 2004 return n 2005 } 2006 2007 if !types.Identical(lt, rt) { 2008 n.Right = assignconv(n.Right, lt, "assignment") 2009 n.Right = walkexpr(n.Right, init) 2010 } 2011 dowidth(n.Right.Type) 2012 2013 return n 2014 } 2015 2016 // from ascompat[ee] 2017 // a,b = c,d 2018 // simultaneous assignment. there cannot 2019 // be later use of an earlier lvalue. 2020 // 2021 // function calls have been removed. 2022 func reorder3(all []*Node) []*Node { 2023 // If a needed expression may be affected by an 2024 // earlier assignment, make an early copy of that 2025 // expression and use the copy instead. 2026 var early []*Node 2027 2028 var mapinit Nodes 2029 for i, n := range all { 2030 l := n.Left 2031 2032 // Save subexpressions needed on left side. 2033 // Drill through non-dereferences. 2034 for { 2035 if l.Op == ODOT || l.Op == OPAREN { 2036 l = l.Left 2037 continue 2038 } 2039 2040 if l.Op == OINDEX && l.Left.Type.IsArray() { 2041 l.Right = reorder3save(l.Right, all, i, &early) 2042 l = l.Left 2043 continue 2044 } 2045 2046 break 2047 } 2048 2049 switch l.Op { 2050 default: 2051 Fatalf("reorder3 unexpected lvalue %#v", l.Op) 2052 2053 case ONAME: 2054 break 2055 2056 case OINDEX, OINDEXMAP: 2057 l.Left = reorder3save(l.Left, all, i, &early) 2058 l.Right = reorder3save(l.Right, all, i, &early) 2059 if l.Op == OINDEXMAP { 2060 all[i] = convas(all[i], &mapinit) 2061 } 2062 2063 case ODEREF, ODOTPTR: 2064 l.Left = reorder3save(l.Left, all, i, &early) 2065 } 2066 2067 // Save expression on right side. 2068 all[i].Right = reorder3save(all[i].Right, all, i, &early) 2069 } 2070 2071 early = append(mapinit.Slice(), early...) 2072 return append(early, all...) 2073 } 2074 2075 // if the evaluation of *np would be affected by the 2076 // assignments in all up to but not including the ith assignment, 2077 // copy into a temporary during *early and 2078 // replace *np with that temp. 2079 // The result of reorder3save MUST be assigned back to n, e.g. 2080 // n.Left = reorder3save(n.Left, all, i, early) 2081 func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node { 2082 if !aliased(n, all, i) { 2083 return n 2084 } 2085 2086 q := temp(n.Type) 2087 q = nod(OAS, q, n) 2088 q = typecheck(q, ctxStmt) 2089 *early = append(*early, q) 2090 return q.Left 2091 } 2092 2093 // what's the outer value that a write to n affects? 2094 // outer value means containing struct or array. 2095 func outervalue(n *Node) *Node { 2096 for { 2097 switch n.Op { 2098 case OXDOT: 2099 Fatalf("OXDOT in walk") 2100 case ODOT, OPAREN, OCONVNOP: 2101 n = n.Left 2102 continue 2103 case OINDEX: 2104 if n.Left.Type != nil && n.Left.Type.IsArray() { 2105 n = n.Left 2106 continue 2107 } 2108 } 2109 2110 return n 2111 } 2112 } 2113 2114 // Is it possible that the computation of n might be 2115 // affected by writes in as up to but not including the ith element? 2116 func aliased(n *Node, all []*Node, i int) bool { 2117 if n == nil { 2118 return false 2119 } 2120 2121 // Treat all fields of a struct as referring to the whole struct. 2122 // We could do better but we would have to keep track of the fields. 2123 for n.Op == ODOT { 2124 n = n.Left 2125 } 2126 2127 // Look for obvious aliasing: a variable being assigned 2128 // during the all list and appearing in n. 2129 // Also record whether there are any writes to main memory. 2130 // Also record whether there are any writes to variables 2131 // whose addresses have been taken. 2132 memwrite := false 2133 varwrite := false 2134 for _, an := range all[:i] { 2135 a := outervalue(an.Left) 2136 2137 for a.Op == ODOT { 2138 a = a.Left 2139 } 2140 2141 if a.Op != ONAME { 2142 memwrite = true 2143 continue 2144 } 2145 2146 switch n.Class() { 2147 default: 2148 varwrite = true 2149 continue 2150 2151 case PAUTO, PPARAM, PPARAMOUT: 2152 if n.Addrtaken() { 2153 varwrite = true 2154 continue 2155 } 2156 2157 if vmatch2(a, n) { 2158 // Direct hit. 2159 return true 2160 } 2161 } 2162 } 2163 2164 // The variables being written do not appear in n. 2165 // However, n might refer to computed addresses 2166 // that are being written. 2167 2168 // If no computed addresses are affected by the writes, no aliasing. 2169 if !memwrite && !varwrite { 2170 return false 2171 } 2172 2173 // If n does not refer to computed addresses 2174 // (that is, if n only refers to variables whose addresses 2175 // have not been taken), no aliasing. 2176 if varexpr(n) { 2177 return false 2178 } 2179 2180 // Otherwise, both the writes and n refer to computed memory addresses. 2181 // Assume that they might conflict. 2182 return true 2183 } 2184 2185 // does the evaluation of n only refer to variables 2186 // whose addresses have not been taken? 2187 // (and no other memory) 2188 func varexpr(n *Node) bool { 2189 if n == nil { 2190 return true 2191 } 2192 2193 switch n.Op { 2194 case OLITERAL: 2195 return true 2196 2197 case ONAME: 2198 switch n.Class() { 2199 case PAUTO, PPARAM, PPARAMOUT: 2200 if !n.Addrtaken() { 2201 return true 2202 } 2203 } 2204 2205 return false 2206 2207 case OADD, 2208 OSUB, 2209 OOR, 2210 OXOR, 2211 OMUL, 2212 ODIV, 2213 OMOD, 2214 OLSH, 2215 ORSH, 2216 OAND, 2217 OANDNOT, 2218 OPLUS, 2219 ONEG, 2220 OBITNOT, 2221 OPAREN, 2222 OANDAND, 2223 OOROR, 2224 OCONV, 2225 OCONVNOP, 2226 OCONVIFACE, 2227 ODOTTYPE: 2228 return varexpr(n.Left) && varexpr(n.Right) 2229 2230 case ODOT: // but not ODOTPTR 2231 // Should have been handled in aliased. 2232 Fatalf("varexpr unexpected ODOT") 2233 } 2234 2235 // Be conservative. 2236 return false 2237 } 2238 2239 // is the name l mentioned in r? 2240 func vmatch2(l *Node, r *Node) bool { 2241 if r == nil { 2242 return false 2243 } 2244 switch r.Op { 2245 // match each right given left 2246 case ONAME: 2247 return l == r 2248 2249 case OLITERAL: 2250 return false 2251 } 2252 2253 if vmatch2(l, r.Left) { 2254 return true 2255 } 2256 if vmatch2(l, r.Right) { 2257 return true 2258 } 2259 for _, n := range r.List.Slice() { 2260 if vmatch2(l, n) { 2261 return true 2262 } 2263 } 2264 return false 2265 } 2266 2267 // is any name mentioned in l also mentioned in r? 2268 // called by sinit.go 2269 func vmatch1(l *Node, r *Node) bool { 2270 // isolate all left sides 2271 if l == nil || r == nil { 2272 return false 2273 } 2274 switch l.Op { 2275 case ONAME: 2276 switch l.Class() { 2277 case PPARAM, PAUTO: 2278 break 2279 2280 default: 2281 // assignment to non-stack variable must be 2282 // delayed if right has function calls. 2283 if r.HasCall() { 2284 return true 2285 } 2286 } 2287 2288 return vmatch2(l, r) 2289 2290 case OLITERAL: 2291 return false 2292 } 2293 2294 if vmatch1(l.Left, r) { 2295 return true 2296 } 2297 if vmatch1(l.Right, r) { 2298 return true 2299 } 2300 for _, n := range l.List.Slice() { 2301 if vmatch1(n, r) { 2302 return true 2303 } 2304 } 2305 return false 2306 } 2307 2308 // paramstoheap returns code to allocate memory for heap-escaped parameters 2309 // and to copy non-result parameters' values from the stack. 2310 func paramstoheap(params *types.Type) []*Node { 2311 var nn []*Node 2312 for _, t := range params.Fields().Slice() { 2313 v := asNode(t.Nname) 2314 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result 2315 v = nil 2316 } 2317 if v == nil { 2318 continue 2319 } 2320 2321 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil { 2322 nn = append(nn, walkstmt(nod(ODCL, v, nil))) 2323 if stackcopy.Class() == PPARAM { 2324 nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), ctxStmt))) 2325 } 2326 } 2327 } 2328 2329 return nn 2330 } 2331 2332 // zeroResults zeros the return values at the start of the function. 2333 // We need to do this very early in the function. Defer might stop a 2334 // panic and show the return values as they exist at the time of 2335 // panic. For precise stacks, the garbage collector assumes results 2336 // are always live, so we need to zero them before any allocations, 2337 // even allocations to move params/results to the heap. 2338 // The generated code is added to Curfn's Enter list. 2339 func zeroResults() { 2340 for _, f := range Curfn.Type.Results().Fields().Slice() { 2341 v := asNode(f.Nname) 2342 if v != nil && v.Name.Param.Heapaddr != nil { 2343 // The local which points to the return value is the 2344 // thing that needs zeroing. This is already handled 2345 // by a Needzero annotation in plive.go:livenessepilogue. 2346 continue 2347 } 2348 if v.isParamHeapCopy() { 2349 // TODO(josharian/khr): Investigate whether we can switch to "continue" here, 2350 // and document more in either case. 2351 // In the review of CL 114797, Keith wrote (roughly): 2352 // I don't think the zeroing below matters. 2353 // The stack return value will never be marked as live anywhere in the function. 2354 // It is not written to until deferreturn returns. 2355 v = v.Name.Param.Stackcopy 2356 } 2357 // Zero the stack location containing f. 2358 Curfn.Func.Enter.Append(nodl(Curfn.Pos, OAS, v, nil)) 2359 } 2360 } 2361 2362 // returnsfromheap returns code to copy values for heap-escaped parameters 2363 // back to the stack. 2364 func returnsfromheap(params *types.Type) []*Node { 2365 var nn []*Node 2366 for _, t := range params.Fields().Slice() { 2367 v := asNode(t.Nname) 2368 if v == nil { 2369 continue 2370 } 2371 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class() == PPARAMOUT { 2372 nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), ctxStmt))) 2373 } 2374 } 2375 2376 return nn 2377 } 2378 2379 // heapmoves generates code to handle migrating heap-escaped parameters 2380 // between the stack and the heap. The generated code is added to Curfn's 2381 // Enter and Exit lists. 2382 func heapmoves() { 2383 lno := lineno 2384 lineno = Curfn.Pos 2385 nn := paramstoheap(Curfn.Type.Recvs()) 2386 nn = append(nn, paramstoheap(Curfn.Type.Params())...) 2387 nn = append(nn, paramstoheap(Curfn.Type.Results())...) 2388 Curfn.Func.Enter.Append(nn...) 2389 lineno = Curfn.Func.Endlineno 2390 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...) 2391 lineno = lno 2392 } 2393 2394 func vmkcall(fn *Node, t *types.Type, init *Nodes, va []*Node) *Node { 2395 if fn.Type == nil || fn.Type.Etype != TFUNC { 2396 Fatalf("mkcall %v %v", fn, fn.Type) 2397 } 2398 2399 n := fn.Type.NumParams() 2400 if n != len(va) { 2401 Fatalf("vmkcall %v needs %v args got %v", fn, n, len(va)) 2402 } 2403 2404 r := nod(OCALL, fn, nil) 2405 r.List.Set(va) 2406 if fn.Type.NumResults() > 0 { 2407 r = typecheck(r, ctxExpr|ctxMultiOK) 2408 } else { 2409 r = typecheck(r, ctxStmt) 2410 } 2411 r = walkexpr(r, init) 2412 r.Type = t 2413 return r 2414 } 2415 2416 func mkcall(name string, t *types.Type, init *Nodes, args ...*Node) *Node { 2417 return vmkcall(syslook(name), t, init, args) 2418 } 2419 2420 func mkcall1(fn *Node, t *types.Type, init *Nodes, args ...*Node) *Node { 2421 return vmkcall(fn, t, init, args) 2422 } 2423 2424 func conv(n *Node, t *types.Type) *Node { 2425 if types.Identical(n.Type, t) { 2426 return n 2427 } 2428 n = nod(OCONV, n, nil) 2429 n.Type = t 2430 n = typecheck(n, ctxExpr) 2431 return n 2432 } 2433 2434 // convnop converts node n to type t using the OCONVNOP op 2435 // and typechecks the result with ctxExpr. 2436 func convnop(n *Node, t *types.Type) *Node { 2437 n = nod(OCONVNOP, n, nil) 2438 n.Type = t 2439 n = typecheck(n, ctxExpr) 2440 return n 2441 } 2442 2443 // byteindex converts n, which is byte-sized, to a uint8. 2444 // We cannot use conv, because we allow converting bool to uint8 here, 2445 // which is forbidden in user code. 2446 func byteindex(n *Node) *Node { 2447 if types.Identical(n.Type, types.Types[TUINT8]) { 2448 return n 2449 } 2450 n = nod(OCONV, n, nil) 2451 n.Type = types.Types[TUINT8] 2452 n.SetTypecheck(1) 2453 return n 2454 } 2455 2456 func chanfn(name string, n int, t *types.Type) *Node { 2457 if !t.IsChan() { 2458 Fatalf("chanfn %v", t) 2459 } 2460 fn := syslook(name) 2461 switch n { 2462 default: 2463 Fatalf("chanfn %d", n) 2464 case 1: 2465 fn = substArgTypes(fn, t.Elem()) 2466 case 2: 2467 fn = substArgTypes(fn, t.Elem(), t.Elem()) 2468 } 2469 return fn 2470 } 2471 2472 func mapfn(name string, t *types.Type) *Node { 2473 if !t.IsMap() { 2474 Fatalf("mapfn %v", t) 2475 } 2476 fn := syslook(name) 2477 fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem()) 2478 return fn 2479 } 2480 2481 func mapfndel(name string, t *types.Type) *Node { 2482 if !t.IsMap() { 2483 Fatalf("mapfn %v", t) 2484 } 2485 fn := syslook(name) 2486 fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key()) 2487 return fn 2488 } 2489 2490 const ( 2491 mapslow = iota 2492 mapfast32 2493 mapfast32ptr 2494 mapfast64 2495 mapfast64ptr 2496 mapfaststr 2497 nmapfast 2498 ) 2499 2500 type mapnames [nmapfast]string 2501 2502 func mkmapnames(base string, ptr string) mapnames { 2503 return mapnames{base, base + "_fast32", base + "_fast32" + ptr, base + "_fast64", base + "_fast64" + ptr, base + "_faststr"} 2504 } 2505 2506 var mapaccess1 = mkmapnames("mapaccess1", "") 2507 var mapaccess2 = mkmapnames("mapaccess2", "") 2508 var mapassign = mkmapnames("mapassign", "ptr") 2509 var mapdelete = mkmapnames("mapdelete", "") 2510 2511 func mapfast(t *types.Type) int { 2512 // Check runtime/map.go:maxValueSize before changing. 2513 if t.Elem().Width > 128 { 2514 return mapslow 2515 } 2516 switch algtype(t.Key()) { 2517 case AMEM32: 2518 if !t.Key().HasHeapPointer() { 2519 return mapfast32 2520 } 2521 if Widthptr == 4 { 2522 return mapfast32ptr 2523 } 2524 Fatalf("small pointer %v", t.Key()) 2525 case AMEM64: 2526 if !t.Key().HasHeapPointer() { 2527 return mapfast64 2528 } 2529 if Widthptr == 8 { 2530 return mapfast64ptr 2531 } 2532 // Two-word object, at least one of which is a pointer. 2533 // Use the slow path. 2534 case ASTRING: 2535 return mapfaststr 2536 } 2537 return mapslow 2538 } 2539 2540 func writebarrierfn(name string, l *types.Type, r *types.Type) *Node { 2541 fn := syslook(name) 2542 fn = substArgTypes(fn, l, r) 2543 return fn 2544 } 2545 2546 func addstr(n *Node, init *Nodes) *Node { 2547 // orderexpr rewrote OADDSTR to have a list of strings. 2548 c := n.List.Len() 2549 2550 if c < 2 { 2551 Fatalf("addstr count %d too small", c) 2552 } 2553 2554 buf := nodnil() 2555 if n.Esc == EscNone { 2556 sz := int64(0) 2557 for _, n1 := range n.List.Slice() { 2558 if n1.Op == OLITERAL { 2559 sz += int64(len(n1.Val().U.(string))) 2560 } 2561 } 2562 2563 // Don't allocate the buffer if the result won't fit. 2564 if sz < tmpstringbufsize { 2565 // Create temporary buffer for result string on stack. 2566 t := types.NewArray(types.Types[TUINT8], tmpstringbufsize) 2567 2568 buf = nod(OADDR, temp(t), nil) 2569 } 2570 } 2571 2572 // build list of string arguments 2573 args := []*Node{buf} 2574 for _, n2 := range n.List.Slice() { 2575 args = append(args, conv(n2, types.Types[TSTRING])) 2576 } 2577 2578 var fn string 2579 if c <= 5 { 2580 // small numbers of strings use direct runtime helpers. 2581 // note: orderexpr knows this cutoff too. 2582 fn = fmt.Sprintf("concatstring%d", c) 2583 } else { 2584 // large numbers of strings are passed to the runtime as a slice. 2585 fn = "concatstrings" 2586 2587 t := types.NewSlice(types.Types[TSTRING]) 2588 slice := nod(OCOMPLIT, nil, typenod(t)) 2589 if prealloc[n] != nil { 2590 prealloc[slice] = prealloc[n] 2591 } 2592 slice.List.Set(args[1:]) // skip buf arg 2593 args = []*Node{buf, slice} 2594 slice.Esc = EscNone 2595 } 2596 2597 cat := syslook(fn) 2598 r := nod(OCALL, cat, nil) 2599 r.List.Set(args) 2600 r = typecheck(r, ctxExpr) 2601 r = walkexpr(r, init) 2602 r.Type = n.Type 2603 2604 return r 2605 } 2606 2607 func walkAppendArgs(n *Node, init *Nodes) { 2608 walkexprlistsafe(n.List.Slice(), init) 2609 2610 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s 2611 // and n are name or literal, but those may index the slice we're 2612 // modifying here. Fix explicitly. 2613 ls := n.List.Slice() 2614 for i1, n1 := range ls { 2615 ls[i1] = cheapexpr(n1, init) 2616 } 2617 } 2618 2619 // expand append(l1, l2...) to 2620 // init { 2621 // s := l1 2622 // n := len(s) + len(l2) 2623 // // Compare as uint so growslice can panic on overflow. 2624 // if uint(n) > uint(cap(s)) { 2625 // s = growslice(s, n) 2626 // } 2627 // s = s[:n] 2628 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) 2629 // } 2630 // s 2631 // 2632 // l2 is allowed to be a string. 2633 func appendslice(n *Node, init *Nodes) *Node { 2634 walkAppendArgs(n, init) 2635 2636 l1 := n.List.First() 2637 l2 := n.List.Second() 2638 2639 var nodes Nodes 2640 2641 // var s []T 2642 s := temp(l1.Type) 2643 nodes.Append(nod(OAS, s, l1)) // s = l1 2644 2645 elemtype := s.Type.Elem() 2646 2647 // n := len(s) + len(l2) 2648 nn := temp(types.Types[TINT]) 2649 nodes.Append(nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), nod(OLEN, l2, nil)))) 2650 2651 // if uint(n) > uint(cap(s)) 2652 nif := nod(OIF, nil, nil) 2653 nuint := conv(nn, types.Types[TUINT]) 2654 scapuint := conv(nod(OCAP, s, nil), types.Types[TUINT]) 2655 nif.Left = nod(OGT, nuint, scapuint) 2656 2657 // instantiate growslice(typ *type, []any, int) []any 2658 fn := syslook("growslice") 2659 fn = substArgTypes(fn, elemtype, elemtype) 2660 2661 // s = growslice(T, s, n) 2662 nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn))) 2663 nodes.Append(nif) 2664 2665 // s = s[:n] 2666 nt := nod(OSLICE, s, nil) 2667 nt.SetSliceBounds(nil, nn, nil) 2668 nt.SetBounded(true) 2669 nodes.Append(nod(OAS, s, nt)) 2670 2671 var ncopy *Node 2672 if elemtype.HasHeapPointer() { 2673 // copy(s[len(l1):], l2) 2674 nptr1 := nod(OSLICE, s, nil) 2675 nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil) 2676 2677 nptr2 := l2 2678 2679 Curfn.Func.setWBPos(n.Pos) 2680 2681 // instantiate typedslicecopy(typ *type, dst any, src any) int 2682 fn := syslook("typedslicecopy") 2683 fn = substArgTypes(fn, l1.Type, l2.Type) 2684 ncopy = mkcall1(fn, types.Types[TINT], &nodes, typename(elemtype), nptr1, nptr2) 2685 2686 } else if instrumenting && !compiling_runtime { 2687 // rely on runtime to instrument copy. 2688 // copy(s[len(l1):], l2) 2689 nptr1 := nod(OSLICE, s, nil) 2690 nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil) 2691 2692 nptr2 := l2 2693 2694 if l2.Type.IsString() { 2695 // instantiate func slicestringcopy(to any, fr any) int 2696 fn := syslook("slicestringcopy") 2697 fn = substArgTypes(fn, l1.Type, l2.Type) 2698 ncopy = mkcall1(fn, types.Types[TINT], &nodes, nptr1, nptr2) 2699 } else { 2700 // instantiate func slicecopy(to any, fr any, wid uintptr) int 2701 fn := syslook("slicecopy") 2702 fn = substArgTypes(fn, l1.Type, l2.Type) 2703 ncopy = mkcall1(fn, types.Types[TINT], &nodes, nptr1, nptr2, nodintconst(elemtype.Width)) 2704 } 2705 2706 } else { 2707 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) 2708 nptr1 := nod(OINDEX, s, nod(OLEN, l1, nil)) 2709 nptr1.SetBounded(true) 2710 nptr1 = nod(OADDR, nptr1, nil) 2711 2712 nptr2 := nod(OSPTR, l2, nil) 2713 2714 nwid := cheapexpr(conv(nod(OLEN, l2, nil), types.Types[TUINTPTR]), &nodes) 2715 nwid = nod(OMUL, nwid, nodintconst(elemtype.Width)) 2716 2717 // instantiate func memmove(to *any, frm *any, length uintptr) 2718 fn := syslook("memmove") 2719 fn = substArgTypes(fn, elemtype, elemtype) 2720 ncopy = mkcall1(fn, nil, &nodes, nptr1, nptr2, nwid) 2721 } 2722 ln := append(nodes.Slice(), ncopy) 2723 2724 typecheckslice(ln, ctxStmt) 2725 walkstmtlist(ln) 2726 init.Append(ln...) 2727 return s 2728 } 2729 2730 // isAppendOfMake reports whether n is of the form append(x , make([]T, y)...). 2731 // isAppendOfMake assumes n has already been typechecked. 2732 func isAppendOfMake(n *Node) bool { 2733 if Debug['N'] != 0 || instrumenting { 2734 return false 2735 } 2736 2737 if n.Typecheck() == 0 { 2738 Fatalf("missing typecheck: %+v", n) 2739 } 2740 2741 if n.Op != OAPPEND || !n.IsDDD() || n.List.Len() != 2 { 2742 return false 2743 } 2744 2745 second := n.List.Second() 2746 if second.Op != OMAKESLICE || second.Right != nil { 2747 return false 2748 } 2749 2750 // y must be either an integer constant or a variable of type int. 2751 // typecheck checks that constant arguments to make are not negative and 2752 // fit into an int. 2753 // runtime.growslice uses int as type for the newcap argument. 2754 // Constraining variables to be type int avoids the need for runtime checks 2755 // that e.g. check if an int64 value fits into an int. 2756 // TODO(moehrmann): support other integer types that always fit in an int 2757 y := second.Left 2758 if !Isconst(y, CTINT) && y.Type.Etype != TINT { 2759 return false 2760 } 2761 2762 return true 2763 } 2764 2765 // extendslice rewrites append(l1, make([]T, l2)...) to 2766 // init { 2767 // if l2 < 0 { 2768 // panicmakeslicelen() 2769 // } 2770 // s := l1 2771 // n := len(s) + l2 2772 // // Compare n and s as uint so growslice can panic on overflow of len(s) + l2. 2773 // // cap is a positive int and n can become negative when len(s) + l2 2774 // // overflows int. Interpreting n when negative as uint makes it larger 2775 // // than cap(s). growslice will check the int n arg and panic if n is 2776 // // negative. This prevents the overflow from being undetected. 2777 // if uint(n) > uint(cap(s)) { 2778 // s = growslice(T, s, n) 2779 // } 2780 // s = s[:n] 2781 // lptr := &l1[0] 2782 // sptr := &s[0] 2783 // if lptr == sptr || !hasPointers(T) { 2784 // // growslice did not clear the whole underlying array (or did not get called) 2785 // hp := &s[len(l1)] 2786 // hn := l2 * sizeof(T) 2787 // memclr(hp, hn) 2788 // } 2789 // } 2790 // s 2791 func extendslice(n *Node, init *Nodes) *Node { 2792 // isAppendOfMake made sure l2 fits in an int. 2793 l2 := conv(n.List.Second().Left, types.Types[TINT]) 2794 l2 = typecheck(l2, ctxExpr) 2795 n.List.SetSecond(l2) // walkAppendArgs expects l2 in n.List.Second(). 2796 2797 walkAppendArgs(n, init) 2798 2799 l1 := n.List.First() 2800 l2 = n.List.Second() // re-read l2, as it may have been updated by walkAppendArgs 2801 2802 var nodes []*Node 2803 2804 // if l2 < 0 2805 nifneg := nod(OIF, nod(OLT, l2, nodintconst(0)), nil) 2806 nifneg.SetLikely(false) 2807 2808 // panicmakeslicelen() 2809 nifneg.Nbody.Set1(mkcall("panicmakeslicelen", nil, init)) 2810 nodes = append(nodes, nifneg) 2811 2812 // s := l1 2813 s := temp(l1.Type) 2814 nodes = append(nodes, nod(OAS, s, l1)) 2815 2816 elemtype := s.Type.Elem() 2817 2818 // n := len(s) + l2 2819 nn := temp(types.Types[TINT]) 2820 nodes = append(nodes, nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), l2))) 2821 2822 // if uint(n) > uint(cap(s)) 2823 nuint := conv(nn, types.Types[TUINT]) 2824 capuint := conv(nod(OCAP, s, nil), types.Types[TUINT]) 2825 nif := nod(OIF, nod(OGT, nuint, capuint), nil) 2826 2827 // instantiate growslice(typ *type, old []any, newcap int) []any 2828 fn := syslook("growslice") 2829 fn = substArgTypes(fn, elemtype, elemtype) 2830 2831 // s = growslice(T, s, n) 2832 nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn))) 2833 nodes = append(nodes, nif) 2834 2835 // s = s[:n] 2836 nt := nod(OSLICE, s, nil) 2837 nt.SetSliceBounds(nil, nn, nil) 2838 nt.SetBounded(true) 2839 nodes = append(nodes, nod(OAS, s, nt)) 2840 2841 // lptr := &l1[0] 2842 l1ptr := temp(l1.Type.Elem().PtrTo()) 2843 tmp := nod(OSPTR, l1, nil) 2844 nodes = append(nodes, nod(OAS, l1ptr, tmp)) 2845 2846 // sptr := &s[0] 2847 sptr := temp(elemtype.PtrTo()) 2848 tmp = nod(OSPTR, s, nil) 2849 nodes = append(nodes, nod(OAS, sptr, tmp)) 2850 2851 // hp := &s[len(l1)] 2852 hp := nod(OINDEX, s, nod(OLEN, l1, nil)) 2853 hp.SetBounded(true) 2854 hp = nod(OADDR, hp, nil) 2855 hp = convnop(hp, types.Types[TUNSAFEPTR]) 2856 2857 // hn := l2 * sizeof(elem(s)) 2858 hn := nod(OMUL, l2, nodintconst(elemtype.Width)) 2859 hn = conv(hn, types.Types[TUINTPTR]) 2860 2861 clrname := "memclrNoHeapPointers" 2862 hasPointers := types.Haspointers(elemtype) 2863 if hasPointers { 2864 clrname = "memclrHasPointers" 2865 Curfn.Func.setWBPos(n.Pos) 2866 } 2867 2868 var clr Nodes 2869 clrfn := mkcall(clrname, nil, &clr, hp, hn) 2870 clr.Append(clrfn) 2871 2872 if hasPointers { 2873 // if l1ptr == sptr 2874 nifclr := nod(OIF, nod(OEQ, l1ptr, sptr), nil) 2875 nifclr.Nbody = clr 2876 nodes = append(nodes, nifclr) 2877 } else { 2878 nodes = append(nodes, clr.Slice()...) 2879 } 2880 2881 typecheckslice(nodes, ctxStmt) 2882 walkstmtlist(nodes) 2883 init.Append(nodes...) 2884 return s 2885 } 2886 2887 // Rewrite append(src, x, y, z) so that any side effects in 2888 // x, y, z (including runtime panics) are evaluated in 2889 // initialization statements before the append. 2890 // For normal code generation, stop there and leave the 2891 // rest to cgen_append. 2892 // 2893 // For race detector, expand append(src, a [, b]* ) to 2894 // 2895 // init { 2896 // s := src 2897 // const argc = len(args) - 1 2898 // if cap(s) - len(s) < argc { 2899 // s = growslice(s, len(s)+argc) 2900 // } 2901 // n := len(s) 2902 // s = s[:n+argc] 2903 // s[n] = a 2904 // s[n+1] = b 2905 // ... 2906 // } 2907 // s 2908 func walkappend(n *Node, init *Nodes, dst *Node) *Node { 2909 if !samesafeexpr(dst, n.List.First()) { 2910 n.List.SetFirst(safeexpr(n.List.First(), init)) 2911 n.List.SetFirst(walkexpr(n.List.First(), init)) 2912 } 2913 walkexprlistsafe(n.List.Slice()[1:], init) 2914 2915 nsrc := n.List.First() 2916 2917 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s 2918 // and n are name or literal, but those may index the slice we're 2919 // modifying here. Fix explicitly. 2920 // Using cheapexpr also makes sure that the evaluation 2921 // of all arguments (and especially any panics) happen 2922 // before we begin to modify the slice in a visible way. 2923 ls := n.List.Slice()[1:] 2924 for i, n := range ls { 2925 n = cheapexpr(n, init) 2926 if !types.Identical(n.Type, nsrc.Type.Elem()) { 2927 n = assignconv(n, nsrc.Type.Elem(), "append") 2928 n = walkexpr(n, init) 2929 } 2930 ls[i] = n 2931 } 2932 2933 argc := n.List.Len() - 1 2934 if argc < 1 { 2935 return nsrc 2936 } 2937 2938 // General case, with no function calls left as arguments. 2939 // Leave for gen, except that instrumentation requires old form. 2940 if !instrumenting || compiling_runtime { 2941 return n 2942 } 2943 2944 var l []*Node 2945 2946 ns := temp(nsrc.Type) 2947 l = append(l, nod(OAS, ns, nsrc)) // s = src 2948 2949 na := nodintconst(int64(argc)) // const argc 2950 nx := nod(OIF, nil, nil) // if cap(s) - len(s) < argc 2951 nx.Left = nod(OLT, nod(OSUB, nod(OCAP, ns, nil), nod(OLEN, ns, nil)), na) 2952 2953 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T) 2954 fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem()) 2955 2956 nx.Nbody.Set1(nod(OAS, ns, 2957 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns, 2958 nod(OADD, nod(OLEN, ns, nil), na)))) 2959 2960 l = append(l, nx) 2961 2962 nn := temp(types.Types[TINT]) 2963 l = append(l, nod(OAS, nn, nod(OLEN, ns, nil))) // n = len(s) 2964 2965 nx = nod(OSLICE, ns, nil) // ...s[:n+argc] 2966 nx.SetSliceBounds(nil, nod(OADD, nn, na), nil) 2967 nx.SetBounded(true) 2968 l = append(l, nod(OAS, ns, nx)) // s = s[:n+argc] 2969 2970 ls = n.List.Slice()[1:] 2971 for i, n := range ls { 2972 nx = nod(OINDEX, ns, nn) // s[n] ... 2973 nx.SetBounded(true) 2974 l = append(l, nod(OAS, nx, n)) // s[n] = arg 2975 if i+1 < len(ls) { 2976 l = append(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))) // n = n + 1 2977 } 2978 } 2979 2980 typecheckslice(l, ctxStmt) 2981 walkstmtlist(l) 2982 init.Append(l...) 2983 return ns 2984 } 2985 2986 // Lower copy(a, b) to a memmove call or a runtime call. 2987 // 2988 // init { 2989 // n := len(a) 2990 // if n > len(b) { n = len(b) } 2991 // if a.ptr != b.ptr { memmove(a.ptr, b.ptr, n*sizeof(elem(a))) } 2992 // } 2993 // n; 2994 // 2995 // Also works if b is a string. 2996 // 2997 func copyany(n *Node, init *Nodes, runtimecall bool) *Node { 2998 if n.Left.Type.Elem().HasHeapPointer() { 2999 Curfn.Func.setWBPos(n.Pos) 3000 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type) 3001 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right) 3002 } 3003 3004 if runtimecall { 3005 if n.Right.Type.IsString() { 3006 fn := syslook("slicestringcopy") 3007 fn = substArgTypes(fn, n.Left.Type, n.Right.Type) 3008 return mkcall1(fn, n.Type, init, n.Left, n.Right) 3009 } 3010 3011 fn := syslook("slicecopy") 3012 fn = substArgTypes(fn, n.Left.Type, n.Right.Type) 3013 return mkcall1(fn, n.Type, init, n.Left, n.Right, nodintconst(n.Left.Type.Elem().Width)) 3014 } 3015 3016 n.Left = walkexpr(n.Left, init) 3017 n.Right = walkexpr(n.Right, init) 3018 nl := temp(n.Left.Type) 3019 nr := temp(n.Right.Type) 3020 var l []*Node 3021 l = append(l, nod(OAS, nl, n.Left)) 3022 l = append(l, nod(OAS, nr, n.Right)) 3023 3024 nfrm := nod(OSPTR, nr, nil) 3025 nto := nod(OSPTR, nl, nil) 3026 3027 nlen := temp(types.Types[TINT]) 3028 3029 // n = len(to) 3030 l = append(l, nod(OAS, nlen, nod(OLEN, nl, nil))) 3031 3032 // if n > len(frm) { n = len(frm) } 3033 nif := nod(OIF, nil, nil) 3034 3035 nif.Left = nod(OGT, nlen, nod(OLEN, nr, nil)) 3036 nif.Nbody.Append(nod(OAS, nlen, nod(OLEN, nr, nil))) 3037 l = append(l, nif) 3038 3039 // if to.ptr != frm.ptr { memmove( ... ) } 3040 ne := nod(OIF, nod(ONE, nto, nfrm), nil) 3041 ne.SetLikely(true) 3042 l = append(l, ne) 3043 3044 fn := syslook("memmove") 3045 fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem()) 3046 nwid := temp(types.Types[TUINTPTR]) 3047 setwid := nod(OAS, nwid, conv(nlen, types.Types[TUINTPTR])) 3048 ne.Nbody.Append(setwid) 3049 nwid = nod(OMUL, nwid, nodintconst(nl.Type.Elem().Width)) 3050 call := mkcall1(fn, nil, init, nto, nfrm, nwid) 3051 ne.Nbody.Append(call) 3052 3053 typecheckslice(l, ctxStmt) 3054 walkstmtlist(l) 3055 init.Append(l...) 3056 return nlen 3057 } 3058 3059 func eqfor(t *types.Type) (n *Node, needsize bool) { 3060 // Should only arrive here with large memory or 3061 // a struct/array containing a non-memory field/element. 3062 // Small memory is handled inline, and single non-memory 3063 // is handled by walkcompare. 3064 switch a, _ := algtype1(t); a { 3065 case AMEM: 3066 n := syslook("memequal") 3067 n = substArgTypes(n, t, t) 3068 return n, true 3069 case ASPECIAL: 3070 sym := typesymprefix(".eq", t) 3071 n := newname(sym) 3072 n.SetClass(PFUNC) 3073 n.Sym.SetFunc(true) 3074 n.Type = functype(nil, []*Node{ 3075 anonfield(types.NewPtr(t)), 3076 anonfield(types.NewPtr(t)), 3077 }, []*Node{ 3078 anonfield(types.Types[TBOOL]), 3079 }) 3080 return n, false 3081 } 3082 Fatalf("eqfor %v", t) 3083 return nil, false 3084 } 3085 3086 // The result of walkcompare MUST be assigned back to n, e.g. 3087 // n.Left = walkcompare(n.Left, init) 3088 func walkcompare(n *Node, init *Nodes) *Node { 3089 if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != OLITERAL && n.Right.Op != OLITERAL { 3090 return walkcompareInterface(n, init) 3091 } 3092 3093 if n.Left.Type.IsString() && n.Right.Type.IsString() { 3094 return walkcompareString(n, init) 3095 } 3096 3097 n.Left = walkexpr(n.Left, init) 3098 n.Right = walkexpr(n.Right, init) 3099 3100 // Given interface value l and concrete value r, rewrite 3101 // l == r 3102 // into types-equal && data-equal. 3103 // This is efficient, avoids allocations, and avoids runtime calls. 3104 var l, r *Node 3105 if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() { 3106 l = n.Left 3107 r = n.Right 3108 } else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() { 3109 l = n.Right 3110 r = n.Left 3111 } 3112 3113 if l != nil { 3114 // Handle both == and !=. 3115 eq := n.Op 3116 var andor Op 3117 if eq == OEQ { 3118 andor = OANDAND 3119 } else { 3120 andor = OOROR 3121 } 3122 // Check for types equal. 3123 // For empty interface, this is: 3124 // l.tab == type(r) 3125 // For non-empty interface, this is: 3126 // l.tab != nil && l.tab._type == type(r) 3127 var eqtype *Node 3128 tab := nod(OITAB, l, nil) 3129 rtyp := typename(r.Type) 3130 if l.Type.IsEmptyInterface() { 3131 tab.Type = types.NewPtr(types.Types[TUINT8]) 3132 tab.SetTypecheck(1) 3133 eqtype = nod(eq, tab, rtyp) 3134 } else { 3135 nonnil := nod(brcom(eq), nodnil(), tab) 3136 match := nod(eq, itabType(tab), rtyp) 3137 eqtype = nod(andor, nonnil, match) 3138 } 3139 // Check for data equal. 3140 eqdata := nod(eq, ifaceData(l, r.Type), r) 3141 // Put it all together. 3142 expr := nod(andor, eqtype, eqdata) 3143 n = finishcompare(n, expr, init) 3144 return n 3145 } 3146 3147 // Must be comparison of array or struct. 3148 // Otherwise back end handles it. 3149 // While we're here, decide whether to 3150 // inline or call an eq alg. 3151 t := n.Left.Type 3152 var inline bool 3153 3154 maxcmpsize := int64(4) 3155 unalignedLoad := canMergeLoads() 3156 if unalignedLoad { 3157 // Keep this low enough to generate less code than a function call. 3158 maxcmpsize = 2 * int64(thearch.LinkArch.RegSize) 3159 } 3160 3161 switch t.Etype { 3162 default: 3163 return n 3164 case TARRAY: 3165 // We can compare several elements at once with 2/4/8 byte integer compares 3166 inline = t.NumElem() <= 1 || (issimple[t.Elem().Etype] && (t.NumElem() <= 4 || t.Elem().Width*t.NumElem() <= maxcmpsize)) 3167 case TSTRUCT: 3168 inline = t.NumComponents(types.IgnoreBlankFields) <= 4 3169 } 3170 3171 cmpl := n.Left 3172 for cmpl != nil && cmpl.Op == OCONVNOP { 3173 cmpl = cmpl.Left 3174 } 3175 cmpr := n.Right 3176 for cmpr != nil && cmpr.Op == OCONVNOP { 3177 cmpr = cmpr.Left 3178 } 3179 3180 // Chose not to inline. Call equality function directly. 3181 if !inline { 3182 if isvaluelit(cmpl) { 3183 var_ := temp(cmpl.Type) 3184 anylit(cmpl, var_, init) 3185 cmpl = var_ 3186 } 3187 if isvaluelit(cmpr) { 3188 var_ := temp(cmpr.Type) 3189 anylit(cmpr, var_, init) 3190 cmpr = var_ 3191 } 3192 if !islvalue(cmpl) || !islvalue(cmpr) { 3193 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr) 3194 } 3195 3196 // eq algs take pointers 3197 pl := temp(types.NewPtr(t)) 3198 al := nod(OAS, pl, nod(OADDR, cmpl, nil)) 3199 al = typecheck(al, ctxStmt) 3200 init.Append(al) 3201 3202 pr := temp(types.NewPtr(t)) 3203 ar := nod(OAS, pr, nod(OADDR, cmpr, nil)) 3204 ar = typecheck(ar, ctxStmt) 3205 init.Append(ar) 3206 3207 fn, needsize := eqfor(t) 3208 call := nod(OCALL, fn, nil) 3209 call.List.Append(pl) 3210 call.List.Append(pr) 3211 if needsize { 3212 call.List.Append(nodintconst(t.Width)) 3213 } 3214 res := call 3215 if n.Op != OEQ { 3216 res = nod(ONOT, res, nil) 3217 } 3218 n = finishcompare(n, res, init) 3219 return n 3220 } 3221 3222 // inline: build boolean expression comparing element by element 3223 andor := OANDAND 3224 if n.Op == ONE { 3225 andor = OOROR 3226 } 3227 var expr *Node 3228 compare := func(el, er *Node) { 3229 a := nod(n.Op, el, er) 3230 if expr == nil { 3231 expr = a 3232 } else { 3233 expr = nod(andor, expr, a) 3234 } 3235 } 3236 cmpl = safeexpr(cmpl, init) 3237 cmpr = safeexpr(cmpr, init) 3238 if t.IsStruct() { 3239 for _, f := range t.Fields().Slice() { 3240 sym := f.Sym 3241 if sym.IsBlank() { 3242 continue 3243 } 3244 compare( 3245 nodSym(OXDOT, cmpl, sym), 3246 nodSym(OXDOT, cmpr, sym), 3247 ) 3248 } 3249 } else { 3250 step := int64(1) 3251 remains := t.NumElem() * t.Elem().Width 3252 combine64bit := unalignedLoad && Widthreg == 8 && t.Elem().Width <= 4 && t.Elem().IsInteger() 3253 combine32bit := unalignedLoad && t.Elem().Width <= 2 && t.Elem().IsInteger() 3254 combine16bit := unalignedLoad && t.Elem().Width == 1 && t.Elem().IsInteger() 3255 for i := int64(0); remains > 0; { 3256 var convType *types.Type 3257 switch { 3258 case remains >= 8 && combine64bit: 3259 convType = types.Types[TINT64] 3260 step = 8 / t.Elem().Width 3261 case remains >= 4 && combine32bit: 3262 convType = types.Types[TUINT32] 3263 step = 4 / t.Elem().Width 3264 case remains >= 2 && combine16bit: 3265 convType = types.Types[TUINT16] 3266 step = 2 / t.Elem().Width 3267 default: 3268 step = 1 3269 } 3270 if step == 1 { 3271 compare( 3272 nod(OINDEX, cmpl, nodintconst(i)), 3273 nod(OINDEX, cmpr, nodintconst(i)), 3274 ) 3275 i++ 3276 remains -= t.Elem().Width 3277 } else { 3278 elemType := t.Elem().ToUnsigned() 3279 cmplw := nod(OINDEX, cmpl, nodintconst(i)) 3280 cmplw = conv(cmplw, elemType) // convert to unsigned 3281 cmplw = conv(cmplw, convType) // widen 3282 cmprw := nod(OINDEX, cmpr, nodintconst(i)) 3283 cmprw = conv(cmprw, elemType) 3284 cmprw = conv(cmprw, convType) 3285 // For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ... 3286 // ssa will generate a single large load. 3287 for offset := int64(1); offset < step; offset++ { 3288 lb := nod(OINDEX, cmpl, nodintconst(i+offset)) 3289 lb = conv(lb, elemType) 3290 lb = conv(lb, convType) 3291 lb = nod(OLSH, lb, nodintconst(8*t.Elem().Width*offset)) 3292 cmplw = nod(OOR, cmplw, lb) 3293 rb := nod(OINDEX, cmpr, nodintconst(i+offset)) 3294 rb = conv(rb, elemType) 3295 rb = conv(rb, convType) 3296 rb = nod(OLSH, rb, nodintconst(8*t.Elem().Width*offset)) 3297 cmprw = nod(OOR, cmprw, rb) 3298 } 3299 compare(cmplw, cmprw) 3300 i += step 3301 remains -= step * t.Elem().Width 3302 } 3303 } 3304 } 3305 if expr == nil { 3306 expr = nodbool(n.Op == OEQ) 3307 // We still need to use cmpl and cmpr, in case they contain 3308 // an expression which might panic. See issue 23837. 3309 t := temp(cmpl.Type) 3310 a1 := nod(OAS, t, cmpl) 3311 a1 = typecheck(a1, ctxStmt) 3312 a2 := nod(OAS, t, cmpr) 3313 a2 = typecheck(a2, ctxStmt) 3314 init.Append(a1, a2) 3315 } 3316 n = finishcompare(n, expr, init) 3317 return n 3318 } 3319 3320 func walkcompareInterface(n *Node, init *Nodes) *Node { 3321 // ifaceeq(i1 any-1, i2 any-2) (ret bool); 3322 if !types.Identical(n.Left.Type, n.Right.Type) { 3323 Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type) 3324 } 3325 var fn *Node 3326 if n.Left.Type.IsEmptyInterface() { 3327 fn = syslook("efaceeq") 3328 } else { 3329 fn = syslook("ifaceeq") 3330 } 3331 3332 n.Right = cheapexpr(n.Right, init) 3333 n.Left = cheapexpr(n.Left, init) 3334 lt := nod(OITAB, n.Left, nil) 3335 rt := nod(OITAB, n.Right, nil) 3336 ld := nod(OIDATA, n.Left, nil) 3337 rd := nod(OIDATA, n.Right, nil) 3338 ld.Type = types.Types[TUNSAFEPTR] 3339 rd.Type = types.Types[TUNSAFEPTR] 3340 ld.SetTypecheck(1) 3341 rd.SetTypecheck(1) 3342 call := mkcall1(fn, n.Type, init, lt, ld, rd) 3343 3344 // Check itable/type before full compare. 3345 // Note: short-circuited because order matters. 3346 var cmp *Node 3347 if n.Op == OEQ { 3348 cmp = nod(OANDAND, nod(OEQ, lt, rt), call) 3349 } else { 3350 cmp = nod(OOROR, nod(ONE, lt, rt), nod(ONOT, call, nil)) 3351 } 3352 return finishcompare(n, cmp, init) 3353 } 3354 3355 func walkcompareString(n *Node, init *Nodes) *Node { 3356 // s + "badgerbadgerbadger" == "badgerbadgerbadger" 3357 if (n.Op == OEQ || n.Op == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) { 3358 r := nod(n.Op, nod(OLEN, n.Left.List.First(), nil), nodintconst(0)) 3359 return finishcompare(n, r, init) 3360 } 3361 3362 // Rewrite comparisons to short constant strings as length+byte-wise comparisons. 3363 var cs, ncs *Node // const string, non-const string 3364 switch { 3365 case Isconst(n.Left, CTSTR) && Isconst(n.Right, CTSTR): 3366 // ignore; will be constant evaluated 3367 case Isconst(n.Left, CTSTR): 3368 cs = n.Left 3369 ncs = n.Right 3370 case Isconst(n.Right, CTSTR): 3371 cs = n.Right 3372 ncs = n.Left 3373 } 3374 if cs != nil { 3375 cmp := n.Op 3376 // Our comparison below assumes that the non-constant string 3377 // is on the left hand side, so rewrite "" cmp x to x cmp "". 3378 // See issue 24817. 3379 if Isconst(n.Left, CTSTR) { 3380 cmp = brrev(cmp) 3381 } 3382 3383 // maxRewriteLen was chosen empirically. 3384 // It is the value that minimizes cmd/go file size 3385 // across most architectures. 3386 // See the commit description for CL 26758 for details. 3387 maxRewriteLen := 6 3388 // Some architectures can load unaligned byte sequence as 1 word. 3389 // So we can cover longer strings with the same amount of code. 3390 canCombineLoads := canMergeLoads() 3391 combine64bit := false 3392 if canCombineLoads { 3393 // Keep this low enough to generate less code than a function call. 3394 maxRewriteLen = 2 * thearch.LinkArch.RegSize 3395 combine64bit = thearch.LinkArch.RegSize >= 8 3396 } 3397 3398 var and Op 3399 switch cmp { 3400 case OEQ: 3401 and = OANDAND 3402 case ONE: 3403 and = OOROR 3404 default: 3405 // Don't do byte-wise comparisons for <, <=, etc. 3406 // They're fairly complicated. 3407 // Length-only checks are ok, though. 3408 maxRewriteLen = 0 3409 } 3410 if s := cs.Val().U.(string); len(s) <= maxRewriteLen { 3411 if len(s) > 0 { 3412 ncs = safeexpr(ncs, init) 3413 } 3414 r := nod(cmp, nod(OLEN, ncs, nil), nodintconst(int64(len(s)))) 3415 remains := len(s) 3416 for i := 0; remains > 0; { 3417 if remains == 1 || !canCombineLoads { 3418 cb := nodintconst(int64(s[i])) 3419 ncb := nod(OINDEX, ncs, nodintconst(int64(i))) 3420 r = nod(and, r, nod(cmp, ncb, cb)) 3421 remains-- 3422 i++ 3423 continue 3424 } 3425 var step int 3426 var convType *types.Type 3427 switch { 3428 case remains >= 8 && combine64bit: 3429 convType = types.Types[TINT64] 3430 step = 8 3431 case remains >= 4: 3432 convType = types.Types[TUINT32] 3433 step = 4 3434 case remains >= 2: 3435 convType = types.Types[TUINT16] 3436 step = 2 3437 } 3438 ncsubstr := nod(OINDEX, ncs, nodintconst(int64(i))) 3439 ncsubstr = conv(ncsubstr, convType) 3440 csubstr := int64(s[i]) 3441 // Calculate large constant from bytes as sequence of shifts and ors. 3442 // Like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ... 3443 // ssa will combine this into a single large load. 3444 for offset := 1; offset < step; offset++ { 3445 b := nod(OINDEX, ncs, nodintconst(int64(i+offset))) 3446 b = conv(b, convType) 3447 b = nod(OLSH, b, nodintconst(int64(8*offset))) 3448 ncsubstr = nod(OOR, ncsubstr, b) 3449 csubstr |= int64(s[i+offset]) << uint8(8*offset) 3450 } 3451 csubstrPart := nodintconst(csubstr) 3452 // Compare "step" bytes as once 3453 r = nod(and, r, nod(cmp, csubstrPart, ncsubstr)) 3454 remains -= step 3455 i += step 3456 } 3457 return finishcompare(n, r, init) 3458 } 3459 } 3460 3461 var r *Node 3462 if n.Op == OEQ || n.Op == ONE { 3463 // prepare for rewrite below 3464 n.Left = cheapexpr(n.Left, init) 3465 n.Right = cheapexpr(n.Right, init) 3466 3467 lstr := conv(n.Left, types.Types[TSTRING]) 3468 rstr := conv(n.Right, types.Types[TSTRING]) 3469 lptr := nod(OSPTR, lstr, nil) 3470 rptr := nod(OSPTR, rstr, nil) 3471 llen := conv(nod(OLEN, lstr, nil), types.Types[TUINTPTR]) 3472 rlen := conv(nod(OLEN, rstr, nil), types.Types[TUINTPTR]) 3473 3474 fn := syslook("memequal") 3475 fn = substArgTypes(fn, types.Types[TUINT8], types.Types[TUINT8]) 3476 r = mkcall1(fn, types.Types[TBOOL], init, lptr, rptr, llen) 3477 3478 // quick check of len before full compare for == or !=. 3479 // memequal then tests equality up to length len. 3480 if n.Op == OEQ { 3481 // len(left) == len(right) && memequal(left, right, len) 3482 r = nod(OANDAND, nod(OEQ, llen, rlen), r) 3483 } else { 3484 // len(left) != len(right) || !memequal(left, right, len) 3485 r = nod(ONOT, r, nil) 3486 r = nod(OOROR, nod(ONE, llen, rlen), r) 3487 } 3488 } else { 3489 // sys_cmpstring(s1, s2) :: 0 3490 r = mkcall("cmpstring", types.Types[TINT], init, conv(n.Left, types.Types[TSTRING]), conv(n.Right, types.Types[TSTRING])) 3491 r = nod(n.Op, r, nodintconst(0)) 3492 } 3493 3494 return finishcompare(n, r, init) 3495 } 3496 3497 // The result of finishcompare MUST be assigned back to n, e.g. 3498 // n.Left = finishcompare(n.Left, x, r, init) 3499 func finishcompare(n, r *Node, init *Nodes) *Node { 3500 r = typecheck(r, ctxExpr) 3501 r = conv(r, n.Type) 3502 r = walkexpr(r, init) 3503 return r 3504 } 3505 3506 // isIntOrdering reports whether n is a <, ≤, >, or ≥ ordering between integers. 3507 func (n *Node) isIntOrdering() bool { 3508 switch n.Op { 3509 case OLE, OLT, OGE, OGT: 3510 default: 3511 return false 3512 } 3513 return n.Left.Type.IsInteger() && n.Right.Type.IsInteger() 3514 } 3515 3516 // walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10. 3517 // n must be an OANDAND or OOROR node. 3518 // The result of walkinrange MUST be assigned back to n, e.g. 3519 // n.Left = walkinrange(n.Left) 3520 func walkinrange(n *Node, init *Nodes) *Node { 3521 // We are looking for something equivalent to a opl b OP b opr c, where: 3522 // * a, b, and c have integer type 3523 // * b is side-effect-free 3524 // * opl and opr are each < or ≤ 3525 // * OP is && 3526 l := n.Left 3527 r := n.Right 3528 if !l.isIntOrdering() || !r.isIntOrdering() { 3529 return n 3530 } 3531 3532 // Find b, if it exists, and rename appropriately. 3533 // Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right 3534 // Output is: a opl b(==x) ANDAND/OROR b(==x) opr c 3535 a, opl, b := l.Left, l.Op, l.Right 3536 x, opr, c := r.Left, r.Op, r.Right 3537 for i := 0; ; i++ { 3538 if samesafeexpr(b, x) { 3539 break 3540 } 3541 if i == 3 { 3542 // Tried all permutations and couldn't find an appropriate b == x. 3543 return n 3544 } 3545 if i&1 == 0 { 3546 a, opl, b = b, brrev(opl), a 3547 } else { 3548 x, opr, c = c, brrev(opr), x 3549 } 3550 } 3551 3552 // If n.Op is ||, apply de Morgan. 3553 // Negate the internal ops now; we'll negate the top level op at the end. 3554 // Henceforth assume &&. 3555 negateResult := n.Op == OOROR 3556 if negateResult { 3557 opl = brcom(opl) 3558 opr = brcom(opr) 3559 } 3560 3561 cmpdir := func(o Op) int { 3562 switch o { 3563 case OLE, OLT: 3564 return -1 3565 case OGE, OGT: 3566 return +1 3567 } 3568 Fatalf("walkinrange cmpdir %v", o) 3569 return 0 3570 } 3571 if cmpdir(opl) != cmpdir(opr) { 3572 // Not a range check; something like b < a && b < c. 3573 return n 3574 } 3575 3576 switch opl { 3577 case OGE, OGT: 3578 // We have something like a > b && b ≥ c. 3579 // Switch and reverse ops and rename constants, 3580 // to make it look like a ≤ b && b < c. 3581 a, c = c, a 3582 opl, opr = brrev(opr), brrev(opl) 3583 } 3584 3585 // We must ensure that c-a is non-negative. 3586 // For now, require a and c to be constants. 3587 // In the future, we could also support a == 0 and c == len/cap(...). 3588 // Unfortunately, by this point, most len/cap expressions have been 3589 // stored into temporary variables. 3590 if !Isconst(a, CTINT) || !Isconst(c, CTINT) { 3591 return n 3592 } 3593 3594 // Ensure that Int64() does not overflow on a and c (it'll happen 3595 // for any const above 2**63; see issue #27143). 3596 if !a.CanInt64() || !c.CanInt64() { 3597 return n 3598 } 3599 3600 if opl == OLT { 3601 // We have a < b && ... 3602 // We need a ≤ b && ... to safely use unsigned comparison tricks. 3603 // If a is not the maximum constant for b's type, 3604 // we can increment a and switch to ≤. 3605 if a.Int64() >= maxintval[b.Type.Etype].Int64() { 3606 return n 3607 } 3608 a = nodintconst(a.Int64() + 1) 3609 opl = OLE 3610 } 3611 3612 bound := c.Int64() - a.Int64() 3613 if bound < 0 { 3614 // Bad news. Something like 5 <= x && x < 3. 3615 // Rare in practice, and we still need to generate side-effects, 3616 // so just leave it alone. 3617 return n 3618 } 3619 3620 // We have a ≤ b && b < c (or a ≤ b && b ≤ c). 3621 // This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a), 3622 // which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a), 3623 // which is equivalent to uint(b-a) < uint(c-a). 3624 ut := b.Type.ToUnsigned() 3625 lhs := conv(nod(OSUB, b, a), ut) 3626 rhs := nodintconst(bound) 3627 if negateResult { 3628 // Negate top level. 3629 opr = brcom(opr) 3630 } 3631 cmp := nod(opr, lhs, rhs) 3632 cmp.Pos = n.Pos 3633 cmp = addinit(cmp, l.Ninit.Slice()) 3634 cmp = addinit(cmp, r.Ninit.Slice()) 3635 // Typecheck the AST rooted at cmp... 3636 cmp = typecheck(cmp, ctxExpr) 3637 // ...but then reset cmp's type to match n's type. 3638 cmp.Type = n.Type 3639 cmp = walkexpr(cmp, init) 3640 return cmp 3641 } 3642 3643 // return 1 if integer n must be in range [0, max), 0 otherwise 3644 func bounded(n *Node, max int64) bool { 3645 if n.Type == nil || !n.Type.IsInteger() { 3646 return false 3647 } 3648 3649 sign := n.Type.IsSigned() 3650 bits := int32(8 * n.Type.Width) 3651 3652 if smallintconst(n) { 3653 v := n.Int64() 3654 return 0 <= v && v < max 3655 } 3656 3657 switch n.Op { 3658 case OAND: 3659 v := int64(-1) 3660 if smallintconst(n.Left) { 3661 v = n.Left.Int64() 3662 } else if smallintconst(n.Right) { 3663 v = n.Right.Int64() 3664 } 3665 3666 if 0 <= v && v < max { 3667 return true 3668 } 3669 3670 case OMOD: 3671 if !sign && smallintconst(n.Right) { 3672 v := n.Right.Int64() 3673 if 0 <= v && v <= max { 3674 return true 3675 } 3676 } 3677 3678 case ODIV: 3679 if !sign && smallintconst(n.Right) { 3680 v := n.Right.Int64() 3681 for bits > 0 && v >= 2 { 3682 bits-- 3683 v >>= 1 3684 } 3685 } 3686 3687 case ORSH: 3688 if !sign && smallintconst(n.Right) { 3689 v := n.Right.Int64() 3690 if v > int64(bits) { 3691 return true 3692 } 3693 bits -= int32(v) 3694 } 3695 } 3696 3697 if !sign && bits <= 62 && 1<<uint(bits) <= max { 3698 return true 3699 } 3700 3701 return false 3702 } 3703 3704 // usemethod checks interface method calls for uses of reflect.Type.Method. 3705 func usemethod(n *Node) { 3706 t := n.Left.Type 3707 3708 // Looking for either of: 3709 // Method(int) reflect.Method 3710 // MethodByName(string) (reflect.Method, bool) 3711 // 3712 // TODO(crawshaw): improve precision of match by working out 3713 // how to check the method name. 3714 if n := t.NumParams(); n != 1 { 3715 return 3716 } 3717 if n := t.NumResults(); n != 1 && n != 2 { 3718 return 3719 } 3720 p0 := t.Params().Field(0) 3721 res0 := t.Results().Field(0) 3722 var res1 *types.Field 3723 if t.NumResults() == 2 { 3724 res1 = t.Results().Field(1) 3725 } 3726 3727 if res1 == nil { 3728 if p0.Type.Etype != TINT { 3729 return 3730 } 3731 } else { 3732 if !p0.Type.IsString() { 3733 return 3734 } 3735 if !res1.Type.IsBoolean() { 3736 return 3737 } 3738 } 3739 3740 // Note: Don't rely on res0.Type.String() since its formatting depends on multiple factors 3741 // (including global variables such as numImports - was issue #19028). 3742 if s := res0.Type.Sym; s != nil && s.Name == "Method" && s.Pkg != nil && s.Pkg.Path == "reflect" { 3743 Curfn.Func.SetReflectMethod(true) 3744 } 3745 } 3746 3747 func usefield(n *Node) { 3748 if objabi.Fieldtrack_enabled == 0 { 3749 return 3750 } 3751 3752 switch n.Op { 3753 default: 3754 Fatalf("usefield %v", n.Op) 3755 3756 case ODOT, ODOTPTR: 3757 break 3758 } 3759 if n.Sym == nil { 3760 // No field name. This DOTPTR was built by the compiler for access 3761 // to runtime data structures. Ignore. 3762 return 3763 } 3764 3765 t := n.Left.Type 3766 if t.IsPtr() { 3767 t = t.Elem() 3768 } 3769 field := dotField[typeSymKey{t.Orig, n.Sym}] 3770 if field == nil { 3771 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym) 3772 } 3773 if !strings.Contains(field.Note, "go:\"track\"") { 3774 return 3775 } 3776 3777 outer := n.Left.Type 3778 if outer.IsPtr() { 3779 outer = outer.Elem() 3780 } 3781 if outer.Sym == nil { 3782 yyerror("tracked field must be in named struct type") 3783 } 3784 if !types.IsExported(field.Sym.Name) { 3785 yyerror("tracked field must be exported (upper case)") 3786 } 3787 3788 sym := tracksym(outer, field) 3789 if Curfn.Func.FieldTrack == nil { 3790 Curfn.Func.FieldTrack = make(map[*types.Sym]struct{}) 3791 } 3792 Curfn.Func.FieldTrack[sym] = struct{}{} 3793 } 3794 3795 func candiscardlist(l Nodes) bool { 3796 for _, n := range l.Slice() { 3797 if !candiscard(n) { 3798 return false 3799 } 3800 } 3801 return true 3802 } 3803 3804 func candiscard(n *Node) bool { 3805 if n == nil { 3806 return true 3807 } 3808 3809 switch n.Op { 3810 default: 3811 return false 3812 3813 // Discardable as long as the subpieces are. 3814 case ONAME, 3815 ONONAME, 3816 OTYPE, 3817 OPACK, 3818 OLITERAL, 3819 OADD, 3820 OSUB, 3821 OOR, 3822 OXOR, 3823 OADDSTR, 3824 OADDR, 3825 OANDAND, 3826 OBYTES2STR, 3827 ORUNES2STR, 3828 OSTR2BYTES, 3829 OSTR2RUNES, 3830 OCAP, 3831 OCOMPLIT, 3832 OMAPLIT, 3833 OSTRUCTLIT, 3834 OARRAYLIT, 3835 OSLICELIT, 3836 OPTRLIT, 3837 OCONV, 3838 OCONVIFACE, 3839 OCONVNOP, 3840 ODOT, 3841 OEQ, 3842 ONE, 3843 OLT, 3844 OLE, 3845 OGT, 3846 OGE, 3847 OKEY, 3848 OSTRUCTKEY, 3849 OLEN, 3850 OMUL, 3851 OLSH, 3852 ORSH, 3853 OAND, 3854 OANDNOT, 3855 ONEW, 3856 ONOT, 3857 OBITNOT, 3858 OPLUS, 3859 ONEG, 3860 OOROR, 3861 OPAREN, 3862 ORUNESTR, 3863 OREAL, 3864 OIMAG, 3865 OCOMPLEX: 3866 break 3867 3868 // Discardable as long as we know it's not division by zero. 3869 case ODIV, OMOD: 3870 if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 { 3871 break 3872 } 3873 if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 { 3874 break 3875 } 3876 return false 3877 3878 // Discardable as long as we know it won't fail because of a bad size. 3879 case OMAKECHAN, OMAKEMAP: 3880 if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 { 3881 break 3882 } 3883 return false 3884 3885 // Difficult to tell what sizes are okay. 3886 case OMAKESLICE: 3887 return false 3888 } 3889 3890 if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) { 3891 return false 3892 } 3893 3894 return true 3895 } 3896 3897 // Rewrite 3898 // go builtin(x, y, z) 3899 // into 3900 // go func(a1, a2, a3) { 3901 // builtin(a1, a2, a3) 3902 // }(x, y, z) 3903 // for print, println, and delete. 3904 3905 var wrapCall_prgen int 3906 3907 // The result of wrapCall MUST be assigned back to n, e.g. 3908 // n.Left = wrapCall(n.Left, init) 3909 func wrapCall(n *Node, init *Nodes) *Node { 3910 if n.Ninit.Len() != 0 { 3911 walkstmtlist(n.Ninit.Slice()) 3912 init.AppendNodes(&n.Ninit) 3913 } 3914 3915 t := nod(OTFUNC, nil, nil) 3916 for i, arg := range n.List.Slice() { 3917 s := lookupN("a", i) 3918 t.List.Append(symfield(s, arg.Type)) 3919 } 3920 3921 wrapCall_prgen++ 3922 sym := lookupN("wrap·", wrapCall_prgen) 3923 fn := dclfunc(sym, t) 3924 3925 a := nod(n.Op, nil, nil) 3926 a.List.Set(paramNnames(t.Type)) 3927 a = typecheck(a, ctxStmt) 3928 fn.Nbody.Set1(a) 3929 3930 funcbody() 3931 3932 fn = typecheck(fn, ctxStmt) 3933 typecheckslice(fn.Nbody.Slice(), ctxStmt) 3934 xtop = append(xtop, fn) 3935 3936 a = nod(OCALL, nil, nil) 3937 a.Left = fn.Func.Nname 3938 a.List.Set(n.List.Slice()) 3939 a = typecheck(a, ctxStmt) 3940 a = walkexpr(a, init) 3941 return a 3942 } 3943 3944 // substArgTypes substitutes the given list of types for 3945 // successive occurrences of the "any" placeholder in the 3946 // type syntax expression n.Type. 3947 // The result of substArgTypes MUST be assigned back to old, e.g. 3948 // n.Left = substArgTypes(n.Left, t1, t2) 3949 func substArgTypes(old *Node, types_ ...*types.Type) *Node { 3950 n := old.copy() 3951 3952 for _, t := range types_ { 3953 dowidth(t) 3954 } 3955 n.Type = types.SubstAny(n.Type, &types_) 3956 if len(types_) > 0 { 3957 Fatalf("substArgTypes: too many argument types") 3958 } 3959 return n 3960 } 3961 3962 // canMergeLoads reports whether the backend optimization passes for 3963 // the current architecture can combine adjacent loads into a single 3964 // larger, possibly unaligned, load. Note that currently the 3965 // optimizations must be able to handle little endian byte order. 3966 func canMergeLoads() bool { 3967 switch thearch.LinkArch.Family { 3968 case sys.ARM64, sys.AMD64, sys.I386, sys.S390X: 3969 return true 3970 case sys.PPC64: 3971 // Load combining only supported on ppc64le. 3972 return thearch.LinkArch.ByteOrder == binary.LittleEndian 3973 } 3974 return false 3975 } 3976 3977 // isRuneCount reports whether n is of the form len([]rune(string)). 3978 // These are optimized into a call to runtime.countrunes. 3979 func isRuneCount(n *Node) bool { 3980 return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES 3981 }