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