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