github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 // makeslice(et *Type, nel int64, max int64) (ary []any) 1510 fn := syslook("makeslice") 1511 1512 fn = substArgTypes(fn, t.Elem()) // any-1 1513 n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64])) 1514 } 1515 1516 case ORUNESTR: 1517 a := nodnil() 1518 if n.Esc == EscNone { 1519 t := aindex(Nodintconst(4), Types[TUINT8]) 1520 var_ := temp(t) 1521 a = Nod(OADDR, var_, nil) 1522 } 1523 1524 // intstring(*[4]byte, rune) 1525 n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64])) 1526 1527 case OARRAYBYTESTR: 1528 a := nodnil() 1529 if n.Esc == EscNone { 1530 // Create temporary buffer for string on stack. 1531 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8]) 1532 1533 a = Nod(OADDR, temp(t), nil) 1534 } 1535 1536 // slicebytetostring(*[32]byte, []byte) string; 1537 n = mkcall("slicebytetostring", n.Type, init, a, n.Left) 1538 1539 // slicebytetostringtmp([]byte) string; 1540 case OARRAYBYTESTRTMP: 1541 n = mkcall("slicebytetostringtmp", n.Type, init, n.Left) 1542 1543 // slicerunetostring(*[32]byte, []rune) string; 1544 case OARRAYRUNESTR: 1545 a := nodnil() 1546 1547 if n.Esc == EscNone { 1548 // Create temporary buffer for string on stack. 1549 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8]) 1550 1551 a = Nod(OADDR, temp(t), nil) 1552 } 1553 1554 n = mkcall("slicerunetostring", n.Type, init, a, n.Left) 1555 1556 // stringtoslicebyte(*32[byte], string) []byte; 1557 case OSTRARRAYBYTE: 1558 a := nodnil() 1559 1560 if n.Esc == EscNone { 1561 // Create temporary buffer for slice on stack. 1562 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8]) 1563 1564 a = Nod(OADDR, temp(t), nil) 1565 } 1566 1567 n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING])) 1568 1569 // stringtoslicebytetmp(string) []byte; 1570 case OSTRARRAYBYTETMP: 1571 n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING])) 1572 1573 // stringtoslicerune(*[32]rune, string) []rune 1574 case OSTRARRAYRUNE: 1575 a := nodnil() 1576 1577 if n.Esc == EscNone { 1578 // Create temporary buffer for slice on stack. 1579 t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32]) 1580 1581 a = Nod(OADDR, temp(t), nil) 1582 } 1583 1584 n = mkcall("stringtoslicerune", n.Type, init, a, n.Left) 1585 1586 // ifaceeq(i1 any-1, i2 any-2) (ret bool); 1587 case OCMPIFACE: 1588 if !Eqtype(n.Left.Type, n.Right.Type) { 1589 Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type) 1590 } 1591 var fn *Node 1592 if n.Left.Type.IsEmptyInterface() { 1593 fn = syslook("efaceeq") 1594 } else { 1595 fn = syslook("ifaceeq") 1596 } 1597 1598 n.Right = cheapexpr(n.Right, init) 1599 n.Left = cheapexpr(n.Left, init) 1600 fn = substArgTypes(fn, n.Right.Type, n.Left.Type) 1601 r := mkcall1(fn, n.Type, init, n.Left, n.Right) 1602 // TODO(marvin): Fix Node.EType type union. 1603 if Op(n.Etype) == ONE { 1604 r = Nod(ONOT, r, nil) 1605 } 1606 1607 // check itable/type before full compare. 1608 // TODO(marvin): Fix Node.EType type union. 1609 if Op(n.Etype) == OEQ { 1610 r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r) 1611 } else { 1612 r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r) 1613 } 1614 r = typecheck(r, Erv) 1615 r = walkexpr(r, init) 1616 r.Type = n.Type 1617 n = r 1618 1619 case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT: 1620 if isStaticCompositeLiteral(n) { 1621 // n can be directly represented in the read-only data section. 1622 // Make direct reference to the static data. See issue 12841. 1623 vstat := staticname(n.Type, 0) 1624 if n.Op == OSTRUCTLIT { 1625 structlit(0, 1, n, vstat, init) 1626 } else { 1627 arraylit(0, 1, n, vstat, init) 1628 } 1629 n = vstat 1630 n = typecheck(n, Erv) 1631 break 1632 } 1633 var_ := temp(n.Type) 1634 anylit(0, n, var_, init) 1635 n = var_ 1636 1637 case OSEND: 1638 n1 := n.Right 1639 n1 = assignconv(n1, n.Left.Type.Elem(), "chan send") 1640 n1 = walkexpr(n1, init) 1641 n1 = Nod(OADDR, n1, nil) 1642 n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1) 1643 1644 case OCLOSURE: 1645 n = walkclosure(n, init) 1646 1647 case OCALLPART: 1648 n = walkpartialcall(n, init) 1649 } 1650 1651 // Expressions that are constant at run time but not 1652 // considered const by the language spec are not turned into 1653 // constants until walk. For example, if n is y%1 == 0, the 1654 // walk of y%1 may have replaced it by 0. 1655 // Check whether n with its updated args is itself now a constant. 1656 t := n.Type 1657 1658 evconst(n) 1659 n.Type = t 1660 if n.Op == OLITERAL { 1661 n = typecheck(n, Erv) 1662 } 1663 1664 ullmancalc(n) 1665 1666 if Debug['w'] != 0 && n != nil { 1667 Dump("walk", n) 1668 } 1669 1670 lineno = lno 1671 return n 1672 } 1673 1674 // TODO(josharian): combine this with its caller and simplify 1675 func reduceSlice(n *Node) *Node { 1676 low, high, max := n.SliceBounds() 1677 if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) { 1678 // Reduce x[i:len(x)] to x[i:]. 1679 high = nil 1680 } 1681 n.SetSliceBounds(low, high, max) 1682 if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil { 1683 // Reduce x[:] to x. 1684 if Debug_slice > 0 { 1685 Warn("slice: omit slice operation") 1686 } 1687 return n.Left 1688 } 1689 return n 1690 } 1691 1692 func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node { 1693 // convas will turn map assigns into function calls, 1694 // making it impossible for reorder3 to work. 1695 n := Nod(OAS, l, r) 1696 1697 if l.Op == OINDEXMAP { 1698 return n 1699 } 1700 1701 return convas(n, init) 1702 } 1703 1704 func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node { 1705 // check assign expression list to 1706 // a expression list. called in 1707 // expr-list = expr-list 1708 1709 // ensure order of evaluation for function calls 1710 for i := range nl { 1711 nl[i] = safeexpr(nl[i], init) 1712 } 1713 for i1 := range nr { 1714 nr[i1] = safeexpr(nr[i1], init) 1715 } 1716 1717 var nn []*Node 1718 i := 0 1719 for ; i < len(nl); i++ { 1720 if i >= len(nr) { 1721 break 1722 } 1723 // Do not generate 'x = x' during return. See issue 4014. 1724 if op == ORETURN && samesafeexpr(nl[i], nr[i]) { 1725 continue 1726 } 1727 nn = append(nn, ascompatee1(op, nl[i], nr[i], init)) 1728 } 1729 1730 // cannot happen: caller checked that lists had same length 1731 if i < len(nl) || i < len(nr) { 1732 var nln, nrn Nodes 1733 nln.Set(nl) 1734 nrn.Set(nr) 1735 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) 1736 } 1737 return nn 1738 } 1739 1740 // l is an lv and rt is the type of an rv 1741 // return 1 if this implies a function call 1742 // evaluating the lv or a function call 1743 // in the conversion of the types 1744 func fncall(l *Node, rt *Type) bool { 1745 if l.Ullman >= UINF || l.Op == OINDEXMAP { 1746 return true 1747 } 1748 var r Node 1749 if needwritebarrier(l, &r) { 1750 return true 1751 } 1752 if Eqtype(l.Type, rt) { 1753 return false 1754 } 1755 return true 1756 } 1757 1758 // check assign type list to 1759 // a expression list. called in 1760 // expr-list = func() 1761 func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node { 1762 r, saver := IterFields(nr) 1763 1764 var nn, mm []*Node 1765 var ullmanOverflow bool 1766 var i int 1767 for i = 0; i < nl.Len(); i++ { 1768 if r == nil { 1769 break 1770 } 1771 l := nl.Index(i) 1772 if isblank(l) { 1773 r = saver.Next() 1774 continue 1775 } 1776 1777 // any lv that causes a fn call must be 1778 // deferred until all the return arguments 1779 // have been pulled from the output arguments 1780 if fncall(l, r.Type) { 1781 tmp := temp(r.Type) 1782 tmp = typecheck(tmp, Erv) 1783 a := Nod(OAS, l, tmp) 1784 a = convas(a, init) 1785 mm = append(mm, a) 1786 l = tmp 1787 } 1788 1789 a := Nod(OAS, l, nodarg(r, fp)) 1790 a = convas(a, init) 1791 ullmancalc(a) 1792 if a.Ullman >= UINF { 1793 Dump("ascompatet ucount", a) 1794 ullmanOverflow = true 1795 } 1796 1797 nn = append(nn, a) 1798 r = saver.Next() 1799 } 1800 1801 if i < nl.Len() || r != nil { 1802 Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields()) 1803 } 1804 1805 if ullmanOverflow { 1806 Fatalf("ascompatet: too many function calls evaluating parameters") 1807 } 1808 return append(nn, mm...) 1809 } 1810 1811 // package all the arguments that match a ... T parameter into a []T. 1812 func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node { 1813 esc := uint16(EscUnknown) 1814 if ddd != nil { 1815 esc = ddd.Esc 1816 } 1817 1818 tslice := typSlice(l.Type.Elem()) 1819 tslice.Noalg = true 1820 1821 var n *Node 1822 if len(lr0) == 0 { 1823 n = nodnil() 1824 n.Type = tslice 1825 } else { 1826 n = Nod(OCOMPLIT, nil, typenod(tslice)) 1827 if ddd != nil && prealloc[ddd] != nil { 1828 prealloc[n] = prealloc[ddd] // temporary to use 1829 } 1830 n.List.Set(lr0) 1831 n.Esc = esc 1832 n = typecheck(n, Erv) 1833 if n.Type == nil { 1834 Fatalf("mkdotargslice: typecheck failed") 1835 } 1836 n = walkexpr(n, init) 1837 } 1838 1839 a := Nod(OAS, nodarg(l, fp), n) 1840 nn = append(nn, convas(a, init)) 1841 return nn 1842 } 1843 1844 // helpers for shape errors 1845 func dumptypes(nl *Type, what string) string { 1846 s := "" 1847 for _, l := range nl.Fields().Slice() { 1848 if s != "" { 1849 s += ", " 1850 } 1851 s += Fldconv(l, 0) 1852 } 1853 if s == "" { 1854 s = fmt.Sprintf("[no arguments %s]", what) 1855 } 1856 return s 1857 } 1858 1859 func dumpnodetypes(l []*Node, what string) string { 1860 s := "" 1861 for _, r := range l { 1862 if s != "" { 1863 s += ", " 1864 } 1865 s += Tconv(r.Type, 0) 1866 } 1867 if s == "" { 1868 s = fmt.Sprintf("[no arguments %s]", what) 1869 } 1870 return s 1871 } 1872 1873 // check assign expression list to 1874 // a type list. called in 1875 // return expr-list 1876 // func(expr-list) 1877 func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node { 1878 lr0 := lr 1879 l, savel := IterFields(nl) 1880 var r *Node 1881 if len(lr) > 0 { 1882 r = lr[0] 1883 } 1884 var nn []*Node 1885 1886 // f(g()) where g has multiple return values 1887 if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() { 1888 // optimization - can do block copy 1889 if eqtypenoname(r.Type, nl) { 1890 arg := nodarg(nl, fp) 1891 r = Nod(OCONVNOP, r, nil) 1892 r.Type = arg.Type 1893 nn = []*Node{convas(Nod(OAS, arg, r), init)} 1894 goto ret 1895 } 1896 1897 // conversions involved. 1898 // copy into temporaries. 1899 var alist []*Node 1900 1901 for _, l := range r.Type.Fields().Slice() { 1902 tmp := temp(l.Type) 1903 alist = append(alist, tmp) 1904 } 1905 1906 a := Nod(OAS2, nil, nil) 1907 a.List.Set(alist) 1908 a.Rlist.Set(lr) 1909 a = typecheck(a, Etop) 1910 a = walkstmt(a) 1911 init.Append(a) 1912 lr = alist 1913 r = lr[0] 1914 l, savel = IterFields(nl) 1915 } 1916 1917 for { 1918 if l != nil && l.Isddd { 1919 // the ddd parameter must be last 1920 ll := savel.Next() 1921 1922 if ll != nil { 1923 Yyerror("... must be last argument") 1924 } 1925 1926 // special case -- 1927 // only if we are assigning a single ddd 1928 // argument to a ddd parameter then it is 1929 // passed through unencapsulated 1930 if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) { 1931 a := Nod(OAS, nodarg(l, fp), r) 1932 a = convas(a, init) 1933 nn = append(nn, a) 1934 break 1935 } 1936 1937 // normal case -- make a slice of all 1938 // remaining arguments and pass it to 1939 // the ddd parameter. 1940 nn = mkdotargslice(lr, nn, l, fp, init, call.Right) 1941 1942 break 1943 } 1944 1945 if l == nil || r == nil { 1946 if l != nil || r != nil { 1947 l1 := dumptypes(nl, "expected") 1948 l2 := dumpnodetypes(lr0, "given") 1949 if l != nil { 1950 Yyerror("not enough arguments to %v\n\t%s\n\t%s", op, l1, l2) 1951 } else { 1952 Yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2) 1953 } 1954 } 1955 1956 break 1957 } 1958 1959 a := Nod(OAS, nodarg(l, fp), r) 1960 a = convas(a, init) 1961 nn = append(nn, a) 1962 1963 l = savel.Next() 1964 r = nil 1965 lr = lr[1:] 1966 if len(lr) > 0 { 1967 r = lr[0] 1968 } 1969 } 1970 1971 ret: 1972 for _, n := range nn { 1973 n.Typecheck = 1 1974 } 1975 return nn 1976 } 1977 1978 // generate code for print 1979 func walkprint(nn *Node, init *Nodes) *Node { 1980 var r *Node 1981 var n *Node 1982 var on *Node 1983 var t *Type 1984 var et EType 1985 1986 op := nn.Op 1987 all := nn.List 1988 var calls []*Node 1989 notfirst := false 1990 1991 // Hoist all the argument evaluation up before the lock. 1992 walkexprlistcheap(all.Slice(), init) 1993 1994 calls = append(calls, mkcall("printlock", nil, init)) 1995 for i1, n1 := range all.Slice() { 1996 if notfirst { 1997 calls = append(calls, mkcall("printsp", nil, init)) 1998 } 1999 2000 notfirst = op == OPRINTN 2001 2002 n = n1 2003 if n.Op == OLITERAL { 2004 switch n.Val().Ctype() { 2005 case CTRUNE: 2006 n = defaultlit(n, runetype) 2007 2008 case CTINT: 2009 n = defaultlit(n, Types[TINT64]) 2010 2011 case CTFLT: 2012 n = defaultlit(n, Types[TFLOAT64]) 2013 } 2014 } 2015 2016 if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL { 2017 n = defaultlit(n, Types[TINT64]) 2018 } 2019 n = defaultlit(n, nil) 2020 all.SetIndex(i1, n) 2021 if n.Type == nil || n.Type.Etype == TFORW { 2022 continue 2023 } 2024 2025 t = n.Type 2026 et = n.Type.Etype 2027 if n.Type.IsInterface() { 2028 if n.Type.IsEmptyInterface() { 2029 on = syslook("printeface") 2030 } else { 2031 on = syslook("printiface") 2032 } 2033 on = substArgTypes(on, n.Type) // any-1 2034 } else if n.Type.IsPtr() || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR { 2035 on = syslook("printpointer") 2036 on = substArgTypes(on, n.Type) // any-1 2037 } else if n.Type.IsSlice() { 2038 on = syslook("printslice") 2039 on = substArgTypes(on, n.Type) // any-1 2040 } else if Isint[et] { 2041 if et == TUINT64 { 2042 if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" { 2043 on = syslook("printhex") 2044 } else { 2045 on = syslook("printuint") 2046 } 2047 } else { 2048 on = syslook("printint") 2049 } 2050 } else if Isfloat[et] { 2051 on = syslook("printfloat") 2052 } else if Iscomplex[et] { 2053 on = syslook("printcomplex") 2054 } else if et == TBOOL { 2055 on = syslook("printbool") 2056 } else if et == TSTRING { 2057 on = syslook("printstring") 2058 } else { 2059 badtype(OPRINT, n.Type, nil) 2060 continue 2061 } 2062 2063 t = on.Type.Params().Field(0).Type 2064 2065 if !Eqtype(t, n.Type) { 2066 n = Nod(OCONV, n, nil) 2067 n.Type = t 2068 } 2069 2070 r = Nod(OCALL, on, nil) 2071 r.List.Append(n) 2072 calls = append(calls, r) 2073 } 2074 2075 if op == OPRINTN { 2076 calls = append(calls, mkcall("printnl", nil, nil)) 2077 } 2078 2079 calls = append(calls, mkcall("printunlock", nil, init)) 2080 2081 typecheckslice(calls, Etop) 2082 walkexprlist(calls, init) 2083 2084 r = Nod(OEMPTY, nil, nil) 2085 r = typecheck(r, Etop) 2086 r = walkexpr(r, init) 2087 r.Ninit.Set(calls) 2088 return r 2089 } 2090 2091 func callnew(t *Type) *Node { 2092 dowidth(t) 2093 fn := syslook("newobject") 2094 fn = substArgTypes(fn, t) 2095 v := mkcall1(fn, Ptrto(t), nil, typename(t)) 2096 v.NonNil = true 2097 return v 2098 } 2099 2100 func iscallret(n *Node) bool { 2101 n = outervalue(n) 2102 return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP) 2103 } 2104 2105 func isstack(n *Node) bool { 2106 n = outervalue(n) 2107 2108 // If n is *autotmp and autotmp = &foo, replace n with foo. 2109 // We introduce such temps when initializing struct literals. 2110 if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") { 2111 defn := n.Left.Name.Defn 2112 if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR { 2113 n = defn.Right.Left 2114 } 2115 } 2116 2117 switch n.Op { 2118 case OINDREG: 2119 return n.Reg == int16(Thearch.REGSP) 2120 2121 case ONAME: 2122 switch n.Class { 2123 case PAUTO, PPARAM, PPARAMOUT: 2124 return true 2125 } 2126 } 2127 2128 return false 2129 } 2130 2131 func (n *Node) isGlobal() bool { 2132 n = outervalue(n) 2133 return n.Op == ONAME && n.Class == PEXTERN 2134 } 2135 2136 // Do we need a write barrier for the assignment l = r? 2137 func needwritebarrier(l *Node, r *Node) bool { 2138 if !use_writebarrier { 2139 return false 2140 } 2141 2142 if l == nil || isblank(l) { 2143 return false 2144 } 2145 2146 // No write barrier for write of non-pointers. 2147 dowidth(l.Type) 2148 2149 if !haspointers(l.Type) { 2150 return false 2151 } 2152 2153 // No write barrier for write to stack. 2154 if isstack(l) { 2155 return false 2156 } 2157 2158 // No write barrier for implicit zeroing. 2159 if r == nil { 2160 return false 2161 } 2162 2163 // Ignore no-op conversions when making decision. 2164 // Ensures that xp = unsafe.Pointer(&x) is treated 2165 // the same as xp = &x. 2166 for r.Op == OCONVNOP { 2167 r = r.Left 2168 } 2169 2170 // No write barrier for zeroing or initialization to constant. 2171 if iszero(r) || r.Op == OLITERAL { 2172 return false 2173 } 2174 2175 // No write barrier for storing static (read-only) data. 2176 if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") { 2177 return false 2178 } 2179 2180 // No write barrier for storing address of stack values, 2181 // which are guaranteed only to be written to the stack. 2182 if r.Op == OADDR && isstack(r.Left) { 2183 return false 2184 } 2185 2186 // No write barrier for storing address of global, which 2187 // is live no matter what. 2188 if r.Op == OADDR && r.Left.isGlobal() { 2189 return false 2190 } 2191 2192 // No write barrier for storing global function, which is live 2193 // no matter what. 2194 if r.Op == ONAME && r.Class == PFUNC { 2195 return false 2196 } 2197 2198 // Otherwise, be conservative and use write barrier. 2199 return true 2200 } 2201 2202 // TODO(rsc): Perhaps componentgen should run before this. 2203 2204 func applywritebarrier(n *Node) *Node { 2205 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) { 2206 if Debug_wb > 1 { 2207 Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0)) 2208 } 2209 n.Op = OASWB 2210 return n 2211 } 2212 return n 2213 } 2214 2215 func convas(n *Node, init *Nodes) *Node { 2216 if n.Op != OAS { 2217 Fatalf("convas: not OAS %v", n.Op) 2218 } 2219 2220 n.Typecheck = 1 2221 2222 var lt *Type 2223 var rt *Type 2224 if n.Left == nil || n.Right == nil { 2225 goto out 2226 } 2227 2228 lt = n.Left.Type 2229 rt = n.Right.Type 2230 if lt == nil || rt == nil { 2231 goto out 2232 } 2233 2234 if isblank(n.Left) { 2235 n.Right = defaultlit(n.Right, nil) 2236 goto out 2237 } 2238 2239 if n.Left.Op == OINDEXMAP { 2240 map_ := n.Left.Left 2241 key := n.Left.Right 2242 val := n.Right 2243 map_ = walkexpr(map_, init) 2244 key = walkexpr(key, init) 2245 val = walkexpr(val, init) 2246 2247 // orderexpr made sure key and val are addressable. 2248 key = Nod(OADDR, key, nil) 2249 2250 val = Nod(OADDR, val, nil) 2251 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val) 2252 goto out 2253 } 2254 2255 if !Eqtype(lt, rt) { 2256 n.Right = assignconv(n.Right, lt, "assignment") 2257 n.Right = walkexpr(n.Right, init) 2258 } 2259 2260 out: 2261 ullmancalc(n) 2262 return n 2263 } 2264 2265 // from ascompat[te] 2266 // evaluating actual function arguments. 2267 // f(a,b) 2268 // if there is exactly one function expr, 2269 // then it is done first. otherwise must 2270 // make temp variables 2271 func reorder1(all []*Node) []*Node { 2272 c := 0 // function calls 2273 t := 0 // total parameters 2274 2275 for _, n := range all { 2276 t++ 2277 ullmancalc(n) 2278 if n.Ullman >= UINF { 2279 c++ 2280 } 2281 } 2282 2283 if c == 0 || t == 1 { 2284 return all 2285 } 2286 2287 var g []*Node // fncalls assigned to tempnames 2288 var f *Node // last fncall assigned to stack 2289 var r []*Node // non fncalls and tempnames assigned to stack 2290 d := 0 2291 var a *Node 2292 for _, n := range all { 2293 if n.Ullman < UINF { 2294 r = append(r, n) 2295 continue 2296 } 2297 2298 d++ 2299 if d == c { 2300 f = n 2301 continue 2302 } 2303 2304 // make assignment of fncall to tempname 2305 a = temp(n.Right.Type) 2306 2307 a = Nod(OAS, a, n.Right) 2308 g = append(g, a) 2309 2310 // put normal arg assignment on list 2311 // with fncall replaced by tempname 2312 n.Right = a.Left 2313 2314 r = append(r, n) 2315 } 2316 2317 if f != nil { 2318 g = append(g, f) 2319 } 2320 return append(g, r...) 2321 } 2322 2323 // from ascompat[ee] 2324 // a,b = c,d 2325 // simultaneous assignment. there cannot 2326 // be later use of an earlier lvalue. 2327 // 2328 // function calls have been removed. 2329 func reorder3(all []*Node) []*Node { 2330 var l *Node 2331 2332 // If a needed expression may be affected by an 2333 // earlier assignment, make an early copy of that 2334 // expression and use the copy instead. 2335 var early []*Node 2336 2337 var mapinit Nodes 2338 for i, n := range all { 2339 l = n.Left 2340 2341 // Save subexpressions needed on left side. 2342 // Drill through non-dereferences. 2343 for { 2344 if l.Op == ODOT || l.Op == OPAREN { 2345 l = l.Left 2346 continue 2347 } 2348 2349 if l.Op == OINDEX && l.Left.Type.IsArray() { 2350 l.Right = reorder3save(l.Right, all, i, &early) 2351 l = l.Left 2352 continue 2353 } 2354 2355 break 2356 } 2357 2358 switch l.Op { 2359 default: 2360 Fatalf("reorder3 unexpected lvalue %#v", l.Op) 2361 2362 case ONAME: 2363 break 2364 2365 case OINDEX, OINDEXMAP: 2366 l.Left = reorder3save(l.Left, all, i, &early) 2367 l.Right = reorder3save(l.Right, all, i, &early) 2368 if l.Op == OINDEXMAP { 2369 all[i] = convas(all[i], &mapinit) 2370 } 2371 2372 case OIND, ODOTPTR: 2373 l.Left = reorder3save(l.Left, all, i, &early) 2374 } 2375 2376 // Save expression on right side. 2377 all[i].Right = reorder3save(all[i].Right, all, i, &early) 2378 } 2379 2380 early = append(mapinit.Slice(), early...) 2381 return append(early, all...) 2382 } 2383 2384 // if the evaluation of *np would be affected by the 2385 // assignments in all up to but not including the ith assignment, 2386 // copy into a temporary during *early and 2387 // replace *np with that temp. 2388 // The result of reorder3save MUST be assigned back to n, e.g. 2389 // n.Left = reorder3save(n.Left, all, i, early) 2390 func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node { 2391 if !aliased(n, all, i) { 2392 return n 2393 } 2394 2395 q := temp(n.Type) 2396 q = Nod(OAS, q, n) 2397 q = typecheck(q, Etop) 2398 *early = append(*early, q) 2399 return q.Left 2400 } 2401 2402 // what's the outer value that a write to n affects? 2403 // outer value means containing struct or array. 2404 func outervalue(n *Node) *Node { 2405 for { 2406 if n.Op == OXDOT { 2407 Fatalf("OXDOT in walk") 2408 } 2409 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP { 2410 n = n.Left 2411 continue 2412 } 2413 2414 if n.Op == OINDEX && n.Left.Type != nil && n.Left.Type.IsArray() { 2415 n = n.Left 2416 continue 2417 } 2418 2419 break 2420 } 2421 2422 return n 2423 } 2424 2425 // Is it possible that the computation of n might be 2426 // affected by writes in as up to but not including the ith element? 2427 func aliased(n *Node, all []*Node, i int) bool { 2428 if n == nil { 2429 return false 2430 } 2431 2432 // Treat all fields of a struct as referring to the whole struct. 2433 // We could do better but we would have to keep track of the fields. 2434 for n.Op == ODOT { 2435 n = n.Left 2436 } 2437 2438 // Look for obvious aliasing: a variable being assigned 2439 // during the all list and appearing in n. 2440 // Also record whether there are any writes to main memory. 2441 // Also record whether there are any writes to variables 2442 // whose addresses have been taken. 2443 memwrite := 0 2444 2445 varwrite := 0 2446 var a *Node 2447 for _, an := range all[:i] { 2448 a = outervalue(an.Left) 2449 2450 for a.Op == ODOT { 2451 a = a.Left 2452 } 2453 2454 if a.Op != ONAME { 2455 memwrite = 1 2456 continue 2457 } 2458 2459 switch n.Class { 2460 default: 2461 varwrite = 1 2462 continue 2463 2464 case PAUTO, PPARAM, PPARAMOUT: 2465 if n.Addrtaken { 2466 varwrite = 1 2467 continue 2468 } 2469 2470 if vmatch2(a, n) { 2471 // Direct hit. 2472 return true 2473 } 2474 } 2475 } 2476 2477 // The variables being written do not appear in n. 2478 // However, n might refer to computed addresses 2479 // that are being written. 2480 2481 // If no computed addresses are affected by the writes, no aliasing. 2482 if memwrite == 0 && varwrite == 0 { 2483 return false 2484 } 2485 2486 // If n does not refer to computed addresses 2487 // (that is, if n only refers to variables whose addresses 2488 // have not been taken), no aliasing. 2489 if varexpr(n) { 2490 return false 2491 } 2492 2493 // Otherwise, both the writes and n refer to computed memory addresses. 2494 // Assume that they might conflict. 2495 return true 2496 } 2497 2498 // does the evaluation of n only refer to variables 2499 // whose addresses have not been taken? 2500 // (and no other memory) 2501 func varexpr(n *Node) bool { 2502 if n == nil { 2503 return true 2504 } 2505 2506 switch n.Op { 2507 case OLITERAL: 2508 return true 2509 2510 case ONAME: 2511 switch n.Class { 2512 case PAUTO, PPARAM, PPARAMOUT: 2513 if !n.Addrtaken { 2514 return true 2515 } 2516 } 2517 2518 return false 2519 2520 case OADD, 2521 OSUB, 2522 OOR, 2523 OXOR, 2524 OMUL, 2525 ODIV, 2526 OMOD, 2527 OLSH, 2528 ORSH, 2529 OAND, 2530 OANDNOT, 2531 OPLUS, 2532 OMINUS, 2533 OCOM, 2534 OPAREN, 2535 OANDAND, 2536 OOROR, 2537 OCONV, 2538 OCONVNOP, 2539 OCONVIFACE, 2540 ODOTTYPE: 2541 return varexpr(n.Left) && varexpr(n.Right) 2542 2543 case ODOT: // but not ODOTPTR 2544 // Should have been handled in aliased. 2545 Fatalf("varexpr unexpected ODOT") 2546 } 2547 2548 // Be conservative. 2549 return false 2550 } 2551 2552 // is the name l mentioned in r? 2553 func vmatch2(l *Node, r *Node) bool { 2554 if r == nil { 2555 return false 2556 } 2557 switch r.Op { 2558 // match each right given left 2559 case ONAME: 2560 return l == r 2561 2562 case OLITERAL: 2563 return false 2564 } 2565 2566 if vmatch2(l, r.Left) { 2567 return true 2568 } 2569 if vmatch2(l, r.Right) { 2570 return true 2571 } 2572 for _, n := range r.List.Slice() { 2573 if vmatch2(l, n) { 2574 return true 2575 } 2576 } 2577 return false 2578 } 2579 2580 // is any name mentioned in l also mentioned in r? 2581 // called by sinit.go 2582 func vmatch1(l *Node, r *Node) bool { 2583 // isolate all left sides 2584 if l == nil || r == nil { 2585 return false 2586 } 2587 switch l.Op { 2588 case ONAME: 2589 switch l.Class { 2590 case PPARAM, PAUTO: 2591 break 2592 2593 // assignment to non-stack variable 2594 // must be delayed if right has function calls. 2595 default: 2596 if r.Ullman >= UINF { 2597 return true 2598 } 2599 } 2600 2601 return vmatch2(l, r) 2602 2603 case OLITERAL: 2604 return false 2605 } 2606 2607 if vmatch1(l.Left, r) { 2608 return true 2609 } 2610 if vmatch1(l.Right, r) { 2611 return true 2612 } 2613 for _, n := range l.List.Slice() { 2614 if vmatch1(n, r) { 2615 return true 2616 } 2617 } 2618 return false 2619 } 2620 2621 // paramstoheap returns code to allocate memory for heap-escaped parameters 2622 // and to copy non-result prameters' values from the stack. 2623 // If out is true, then code is also produced to zero-initialize their 2624 // stack memory addresses. 2625 func paramstoheap(params *Type) []*Node { 2626 var nn []*Node 2627 for _, t := range params.Fields().Slice() { 2628 // For precise stacks, the garbage collector assumes results 2629 // are always live, so zero them always. 2630 if params.StructType().Funarg == FunargResults { 2631 // Defer might stop a panic and show the 2632 // return values as they exist at the time of panic. 2633 // Make sure to zero them on entry to the function. 2634 nn = append(nn, Nod(OAS, nodarg(t, 1), nil)) 2635 } 2636 2637 v := t.Nname 2638 if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result 2639 v = nil 2640 } 2641 if v == nil { 2642 continue 2643 } 2644 2645 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil { 2646 nn = append(nn, walkstmt(Nod(ODCL, v, nil))) 2647 if stackcopy.Class == PPARAM { 2648 nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop))) 2649 } 2650 } 2651 } 2652 2653 return nn 2654 } 2655 2656 // returnsfromheap returns code to copy values for heap-escaped parameters 2657 // back to the stack. 2658 func returnsfromheap(params *Type) []*Node { 2659 var nn []*Node 2660 for _, t := range params.Fields().Slice() { 2661 v := t.Nname 2662 if v == nil { 2663 continue 2664 } 2665 if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT { 2666 nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop))) 2667 } 2668 } 2669 2670 return nn 2671 } 2672 2673 // heapmoves generates code to handle migrating heap-escaped parameters 2674 // between the stack and the heap. The generated code is added to Curfn's 2675 // Enter and Exit lists. 2676 func heapmoves() { 2677 lno := lineno 2678 lineno = Curfn.Lineno 2679 nn := paramstoheap(Curfn.Type.Recvs()) 2680 nn = append(nn, paramstoheap(Curfn.Type.Params())...) 2681 nn = append(nn, paramstoheap(Curfn.Type.Results())...) 2682 Curfn.Func.Enter.Append(nn...) 2683 lineno = Curfn.Func.Endlineno 2684 Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...) 2685 lineno = lno 2686 } 2687 2688 func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node { 2689 if fn.Type == nil || fn.Type.Etype != TFUNC { 2690 Fatalf("mkcall %v %v", fn, fn.Type) 2691 } 2692 2693 n := fn.Type.Params().NumFields() 2694 2695 r := Nod(OCALL, fn, nil) 2696 r.List.Set(va[:n]) 2697 if fn.Type.Results().NumFields() > 0 { 2698 r = typecheck(r, Erv|Efnstruct) 2699 } else { 2700 r = typecheck(r, Etop) 2701 } 2702 r = walkexpr(r, init) 2703 r.Type = t 2704 return r 2705 } 2706 2707 func mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node { 2708 return vmkcall(syslook(name), t, init, args) 2709 } 2710 2711 func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node { 2712 return vmkcall(fn, t, init, args) 2713 } 2714 2715 func conv(n *Node, t *Type) *Node { 2716 if Eqtype(n.Type, t) { 2717 return n 2718 } 2719 n = Nod(OCONV, n, nil) 2720 n.Type = t 2721 n = typecheck(n, Erv) 2722 return n 2723 } 2724 2725 func chanfn(name string, n int, t *Type) *Node { 2726 if !t.IsChan() { 2727 Fatalf("chanfn %v", t) 2728 } 2729 fn := syslook(name) 2730 switch n { 2731 default: 2732 Fatalf("chanfn %d", n) 2733 case 1: 2734 fn = substArgTypes(fn, t.Elem()) 2735 case 2: 2736 fn = substArgTypes(fn, t.Elem(), t.Elem()) 2737 } 2738 return fn 2739 } 2740 2741 func mapfn(name string, t *Type) *Node { 2742 if !t.IsMap() { 2743 Fatalf("mapfn %v", t) 2744 } 2745 fn := syslook(name) 2746 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key(), t.Val()) 2747 return fn 2748 } 2749 2750 func mapfndel(name string, t *Type) *Node { 2751 if !t.IsMap() { 2752 Fatalf("mapfn %v", t) 2753 } 2754 fn := syslook(name) 2755 fn = substArgTypes(fn, t.Key(), t.Val(), t.Key()) 2756 return fn 2757 } 2758 2759 func writebarrierfn(name string, l *Type, r *Type) *Node { 2760 fn := syslook(name) 2761 fn = substArgTypes(fn, l, r) 2762 return fn 2763 } 2764 2765 func addstr(n *Node, init *Nodes) *Node { 2766 // orderexpr rewrote OADDSTR to have a list of strings. 2767 c := n.List.Len() 2768 2769 if c < 2 { 2770 Yyerror("addstr count %d too small", c) 2771 } 2772 2773 buf := nodnil() 2774 if n.Esc == EscNone { 2775 sz := int64(0) 2776 for _, n1 := range n.List.Slice() { 2777 if n1.Op == OLITERAL { 2778 sz += int64(len(n1.Val().U.(string))) 2779 } 2780 } 2781 2782 // Don't allocate the buffer if the result won't fit. 2783 if sz < tmpstringbufsize { 2784 // Create temporary buffer for result string on stack. 2785 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8]) 2786 2787 buf = Nod(OADDR, temp(t), nil) 2788 } 2789 } 2790 2791 // build list of string arguments 2792 args := []*Node{buf} 2793 for _, n2 := range n.List.Slice() { 2794 args = append(args, conv(n2, Types[TSTRING])) 2795 } 2796 2797 var fn string 2798 if c <= 5 { 2799 // small numbers of strings use direct runtime helpers. 2800 // note: orderexpr knows this cutoff too. 2801 fn = fmt.Sprintf("concatstring%d", c) 2802 } else { 2803 // large numbers of strings are passed to the runtime as a slice. 2804 fn = "concatstrings" 2805 2806 t := typSlice(Types[TSTRING]) 2807 slice := Nod(OCOMPLIT, nil, typenod(t)) 2808 if prealloc[n] != nil { 2809 prealloc[slice] = prealloc[n] 2810 } 2811 slice.List.Set(args[1:]) // skip buf arg 2812 args = []*Node{buf, slice} 2813 slice.Esc = EscNone 2814 } 2815 2816 cat := syslook(fn) 2817 r := Nod(OCALL, cat, nil) 2818 r.List.Set(args) 2819 r = typecheck(r, Erv) 2820 r = walkexpr(r, init) 2821 r.Type = n.Type 2822 2823 return r 2824 } 2825 2826 // expand append(l1, l2...) to 2827 // init { 2828 // s := l1 2829 // n := len(s) + len(l2) 2830 // // Compare as uint so growslice can panic on overflow. 2831 // if uint(n) > uint(cap(s)) { 2832 // s = growslice(s, n) 2833 // } 2834 // s = s[:n] 2835 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) 2836 // } 2837 // s 2838 // 2839 // l2 is allowed to be a string. 2840 func appendslice(n *Node, init *Nodes) *Node { 2841 walkexprlistsafe(n.List.Slice(), init) 2842 2843 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s 2844 // and n are name or literal, but those may index the slice we're 2845 // modifying here. Fix explicitly. 2846 ls := n.List.Slice() 2847 for i1, n1 := range ls { 2848 ls[i1] = cheapexpr(n1, init) 2849 } 2850 2851 l1 := n.List.First() 2852 l2 := n.List.Second() 2853 2854 var l []*Node 2855 2856 // var s []T 2857 s := temp(l1.Type) 2858 l = append(l, Nod(OAS, s, l1)) // s = l1 2859 2860 // n := len(s) + len(l2) 2861 nn := temp(Types[TINT]) 2862 l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)))) 2863 2864 // if uint(n) > uint(cap(s)) 2865 nif := Nod(OIF, nil, nil) 2866 nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil)) 2867 nif.Left.Left.Type = Types[TUINT] 2868 nif.Left.Right.Type = Types[TUINT] 2869 2870 // instantiate growslice(Type*, []any, int) []any 2871 fn := syslook("growslice") 2872 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem()) 2873 2874 // s = growslice(T, s, n) 2875 nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn))) 2876 l = append(l, nif) 2877 2878 // s = s[:n] 2879 nt := Nod(OSLICE, s, nil) 2880 nt.SetSliceBounds(nil, nn, nil) 2881 nt.Etype = 1 2882 l = append(l, Nod(OAS, s, nt)) 2883 2884 if haspointers(l1.Type.Elem()) { 2885 // copy(s[len(l1):], l2) 2886 nptr1 := Nod(OSLICE, s, nil) 2887 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil) 2888 nptr1.Etype = 1 2889 nptr2 := l2 2890 fn := syslook("typedslicecopy") 2891 fn = substArgTypes(fn, l1.Type, l2.Type) 2892 var ln Nodes 2893 ln.Set(l) 2894 nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2) 2895 l = append(ln.Slice(), nt) 2896 } else if instrumenting { 2897 // rely on runtime to instrument copy. 2898 // copy(s[len(l1):], l2) 2899 nptr1 := Nod(OSLICE, s, nil) 2900 nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil) 2901 nptr1.Etype = 1 2902 nptr2 := l2 2903 var fn *Node 2904 if l2.Type.IsString() { 2905 fn = syslook("slicestringcopy") 2906 } else { 2907 fn = syslook("slicecopy") 2908 } 2909 fn = substArgTypes(fn, l1.Type, l2.Type) 2910 var ln Nodes 2911 ln.Set(l) 2912 nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width)) 2913 l = append(ln.Slice(), nt) 2914 } else { 2915 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) 2916 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil)) 2917 nptr1.Bounded = true 2918 2919 nptr1 = Nod(OADDR, nptr1, nil) 2920 2921 nptr2 := Nod(OSPTR, l2, nil) 2922 2923 fn := syslook("memmove") 2924 fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem()) 2925 2926 var ln Nodes 2927 ln.Set(l) 2928 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln) 2929 2930 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width)) 2931 nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid) 2932 l = append(ln.Slice(), nt) 2933 } 2934 2935 typecheckslice(l, Etop) 2936 walkstmtlist(l) 2937 init.Append(l...) 2938 return s 2939 } 2940 2941 // Rewrite append(src, x, y, z) so that any side effects in 2942 // x, y, z (including runtime panics) are evaluated in 2943 // initialization statements before the append. 2944 // For normal code generation, stop there and leave the 2945 // rest to cgen_append. 2946 // 2947 // For race detector, expand append(src, a [, b]* ) to 2948 // 2949 // init { 2950 // s := src 2951 // const argc = len(args) - 1 2952 // if cap(s) - len(s) < argc { 2953 // s = growslice(s, len(s)+argc) 2954 // } 2955 // n := len(s) 2956 // s = s[:n+argc] 2957 // s[n] = a 2958 // s[n+1] = b 2959 // ... 2960 // } 2961 // s 2962 func walkappend(n *Node, init *Nodes, dst *Node) *Node { 2963 if !samesafeexpr(dst, n.List.First()) { 2964 n.List.SetIndex(0, safeexpr(n.List.Index(0), init)) 2965 n.List.SetIndex(0, walkexpr(n.List.Index(0), init)) 2966 } 2967 walkexprlistsafe(n.List.Slice()[1:], init) 2968 2969 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s 2970 // and n are name or literal, but those may index the slice we're 2971 // modifying here. Fix explicitly. 2972 // Using cheapexpr also makes sure that the evaluation 2973 // of all arguments (and especially any panics) happen 2974 // before we begin to modify the slice in a visible way. 2975 ls := n.List.Slice()[1:] 2976 for i, n := range ls { 2977 ls[i] = cheapexpr(n, init) 2978 } 2979 2980 nsrc := n.List.First() 2981 2982 argc := n.List.Len() - 1 2983 if argc < 1 { 2984 return nsrc 2985 } 2986 2987 // General case, with no function calls left as arguments. 2988 // Leave for gen, except that instrumentation requires old form. 2989 if !instrumenting { 2990 return n 2991 } 2992 2993 var l []*Node 2994 2995 ns := temp(nsrc.Type) 2996 l = append(l, Nod(OAS, ns, nsrc)) // s = src 2997 2998 na := Nodintconst(int64(argc)) // const argc 2999 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc 3000 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na) 3001 3002 fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T) 3003 fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem()) 3004 3005 nx.Nbody.Set1(Nod(OAS, ns, 3006 mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns, 3007 Nod(OADD, Nod(OLEN, ns, nil), na)))) 3008 3009 l = append(l, nx) 3010 3011 nn := temp(Types[TINT]) 3012 l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s) 3013 3014 nx = Nod(OSLICE, ns, nil) // ...s[:n+argc] 3015 nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil) 3016 nx.Etype = 1 3017 l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc] 3018 3019 ls = n.List.Slice()[1:] 3020 for i, n := range ls { 3021 nx = Nod(OINDEX, ns, nn) // s[n] ... 3022 nx.Bounded = true 3023 l = append(l, Nod(OAS, nx, n)) // s[n] = arg 3024 if i+1 < len(ls) { 3025 l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1 3026 } 3027 } 3028 3029 typecheckslice(l, Etop) 3030 walkstmtlist(l) 3031 init.Append(l...) 3032 return ns 3033 } 3034 3035 // Lower copy(a, b) to a memmove call or a runtime call. 3036 // 3037 // init { 3038 // n := len(a) 3039 // if n > len(b) { n = len(b) } 3040 // memmove(a.ptr, b.ptr, n*sizeof(elem(a))) 3041 // } 3042 // n; 3043 // 3044 // Also works if b is a string. 3045 // 3046 func copyany(n *Node, init *Nodes, runtimecall bool) *Node { 3047 if haspointers(n.Left.Type.Elem()) { 3048 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type) 3049 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right) 3050 } 3051 3052 if runtimecall { 3053 var fn *Node 3054 if n.Right.Type.IsString() { 3055 fn = syslook("slicestringcopy") 3056 } else { 3057 fn = syslook("slicecopy") 3058 } 3059 fn = substArgTypes(fn, n.Left.Type, n.Right.Type) 3060 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width)) 3061 } 3062 3063 n.Left = walkexpr(n.Left, init) 3064 n.Right = walkexpr(n.Right, init) 3065 nl := temp(n.Left.Type) 3066 nr := temp(n.Right.Type) 3067 var l []*Node 3068 l = append(l, Nod(OAS, nl, n.Left)) 3069 l = append(l, Nod(OAS, nr, n.Right)) 3070 3071 nfrm := Nod(OSPTR, nr, nil) 3072 nto := Nod(OSPTR, nl, nil) 3073 3074 nlen := temp(Types[TINT]) 3075 3076 // n = len(to) 3077 l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil))) 3078 3079 // if n > len(frm) { n = len(frm) } 3080 nif := Nod(OIF, nil, nil) 3081 3082 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil)) 3083 nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil))) 3084 l = append(l, nif) 3085 3086 // Call memmove. 3087 fn := syslook("memmove") 3088 3089 fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem()) 3090 nwid := temp(Types[TUINTPTR]) 3091 l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR]))) 3092 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width)) 3093 l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid)) 3094 3095 typecheckslice(l, Etop) 3096 walkstmtlist(l) 3097 init.Append(l...) 3098 return nlen 3099 } 3100 3101 func eqfor(t *Type, needsize *int) *Node { 3102 // Should only arrive here with large memory or 3103 // a struct/array containing a non-memory field/element. 3104 // Small memory is handled inline, and single non-memory 3105 // is handled during type check (OCMPSTR etc). 3106 switch a, _ := algtype1(t); a { 3107 case AMEM: 3108 n := syslook("memequal") 3109 n = substArgTypes(n, t, t) 3110 *needsize = 1 3111 return n 3112 case ASPECIAL: 3113 sym := typesymprefix(".eq", t) 3114 n := newname(sym) 3115 n.Class = PFUNC 3116 ntype := Nod(OTFUNC, nil, nil) 3117 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t)))) 3118 ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t)))) 3119 ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL]))) 3120 ntype = typecheck(ntype, Etype) 3121 n.Type = ntype.Type 3122 *needsize = 0 3123 return n 3124 } 3125 Fatalf("eqfor %v", t) 3126 return nil 3127 } 3128 3129 // The result of walkcompare MUST be assigned back to n, e.g. 3130 // n.Left = walkcompare(n.Left, init) 3131 func walkcompare(n *Node, init *Nodes) *Node { 3132 // Given interface value l and concrete value r, rewrite 3133 // l == r 3134 // into types-equal && data-equal. 3135 // This is efficient, avoids allocations, and avoids runtime calls. 3136 var l, r *Node 3137 if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() { 3138 l = n.Left 3139 r = n.Right 3140 } else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() { 3141 l = n.Right 3142 r = n.Left 3143 } 3144 3145 if l != nil { 3146 // Handle both == and !=. 3147 eq := n.Op 3148 var andor Op 3149 if eq == OEQ { 3150 andor = OANDAND 3151 } else { 3152 andor = OOROR 3153 } 3154 // Check for types equal. 3155 // For empty interface, this is: 3156 // l.tab == type(r) 3157 // For non-empty interface, this is: 3158 // l.tab != nil && l.tab._type == type(r) 3159 var eqtype *Node 3160 tab := Nod(OITAB, l, nil) 3161 rtyp := typename(r.Type) 3162 if l.Type.IsEmptyInterface() { 3163 tab.Type = Ptrto(Types[TUINT8]) 3164 tab.Typecheck = 1 3165 eqtype = Nod(eq, tab, rtyp) 3166 } else { 3167 nonnil := Nod(Brcom(eq), nodnil(), tab) 3168 match := Nod(eq, itabType(tab), rtyp) 3169 eqtype = Nod(andor, nonnil, match) 3170 } 3171 // Check for data equal. 3172 eqdata := Nod(eq, ifaceData(l, r.Type), r) 3173 // Put it all together. 3174 expr := Nod(andor, eqtype, eqdata) 3175 n = finishcompare(n, expr, init) 3176 return n 3177 } 3178 3179 // Must be comparison of array or struct. 3180 // Otherwise back end handles it. 3181 // While we're here, decide whether to 3182 // inline or call an eq alg. 3183 t := n.Left.Type 3184 var inline bool 3185 switch t.Etype { 3186 default: 3187 return n 3188 case TARRAY: 3189 inline = t.NumElem() <= 1 || (t.NumElem() <= 4 && issimple[t.Elem().Etype]) 3190 case TSTRUCT: 3191 inline = t.NumFields() <= 4 3192 } 3193 3194 cmpl := n.Left 3195 for cmpl != nil && cmpl.Op == OCONVNOP { 3196 cmpl = cmpl.Left 3197 } 3198 cmpr := n.Right 3199 for cmpr != nil && cmpr.Op == OCONVNOP { 3200 cmpr = cmpr.Left 3201 } 3202 3203 if !islvalue(cmpl) || !islvalue(cmpr) { 3204 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr) 3205 } 3206 3207 // Chose not to inline. Call equality function directly. 3208 if !inline { 3209 // eq algs take pointers 3210 pl := temp(Ptrto(t)) 3211 al := Nod(OAS, pl, Nod(OADDR, cmpl, nil)) 3212 al.Right.Etype = 1 // addr does not escape 3213 al = typecheck(al, Etop) 3214 init.Append(al) 3215 3216 pr := temp(Ptrto(t)) 3217 ar := Nod(OAS, pr, Nod(OADDR, cmpr, nil)) 3218 ar.Right.Etype = 1 // addr does not escape 3219 ar = typecheck(ar, Etop) 3220 init.Append(ar) 3221 3222 var needsize int 3223 call := Nod(OCALL, eqfor(t, &needsize), nil) 3224 call.List.Append(pl) 3225 call.List.Append(pr) 3226 if needsize != 0 { 3227 call.List.Append(Nodintconst(t.Width)) 3228 } 3229 res := call 3230 if n.Op != OEQ { 3231 res = Nod(ONOT, res, nil) 3232 } 3233 n = finishcompare(n, res, init) 3234 return n 3235 } 3236 3237 // inline: build boolean expression comparing element by element 3238 andor := OANDAND 3239 if n.Op == ONE { 3240 andor = OOROR 3241 } 3242 var expr *Node 3243 compare := func(el, er *Node) { 3244 a := Nod(n.Op, el, er) 3245 if expr == nil { 3246 expr = a 3247 } else { 3248 expr = Nod(andor, expr, a) 3249 } 3250 } 3251 cmpl = safeexpr(cmpl, init) 3252 cmpr = safeexpr(cmpr, init) 3253 if t.IsStruct() { 3254 for _, f := range t.Fields().Slice() { 3255 sym := f.Sym 3256 if isblanksym(sym) { 3257 continue 3258 } 3259 compare( 3260 NodSym(OXDOT, cmpl, sym), 3261 NodSym(OXDOT, cmpr, sym), 3262 ) 3263 } 3264 } else { 3265 for i := 0; int64(i) < t.NumElem(); i++ { 3266 compare( 3267 Nod(OINDEX, cmpl, Nodintconst(int64(i))), 3268 Nod(OINDEX, cmpr, Nodintconst(int64(i))), 3269 ) 3270 } 3271 } 3272 if expr == nil { 3273 expr = Nodbool(n.Op == OEQ) 3274 } 3275 n = finishcompare(n, expr, init) 3276 return n 3277 } 3278 3279 // The result of finishcompare MUST be assigned back to n, e.g. 3280 // n.Left = finishcompare(n.Left, x, r, init) 3281 func finishcompare(n, r *Node, init *Nodes) *Node { 3282 // Use nn here to avoid passing r to typecheck. 3283 nn := r 3284 nn = typecheck(nn, Erv) 3285 nn = walkexpr(nn, init) 3286 r = nn 3287 if r.Type != n.Type { 3288 r = Nod(OCONVNOP, r, nil) 3289 r.Type = n.Type 3290 r.Typecheck = 1 3291 nn = r 3292 } 3293 return nn 3294 } 3295 3296 func samecheap(a *Node, b *Node) bool { 3297 var ar *Node 3298 var br *Node 3299 for a != nil && b != nil && a.Op == b.Op { 3300 switch a.Op { 3301 default: 3302 return false 3303 3304 case ONAME: 3305 return a == b 3306 3307 case ODOT, ODOTPTR: 3308 if a.Sym != b.Sym { 3309 return false 3310 } 3311 3312 case OINDEX: 3313 ar = a.Right 3314 br = b.Right 3315 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 { 3316 return false 3317 } 3318 } 3319 3320 a = a.Left 3321 b = b.Left 3322 } 3323 3324 return false 3325 } 3326 3327 // The result of walkrotate MUST be assigned back to n, e.g. 3328 // n.Left = walkrotate(n.Left) 3329 func walkrotate(n *Node) *Node { 3330 //TODO: enable LROT on ARM64 once the old backend is gone 3331 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) { 3332 return n 3333 } 3334 3335 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value. 3336 l := n.Left 3337 3338 r := n.Right 3339 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 { 3340 return n 3341 } 3342 3343 // Want same, side effect-free expression on lhs of both shifts. 3344 if !samecheap(l.Left, r.Left) { 3345 return n 3346 } 3347 3348 // Constants adding to width? 3349 w := int(l.Type.Width * 8) 3350 3351 if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 { 3352 // only supports 32-bit and 64-bit rotates 3353 return n 3354 } 3355 3356 if Smallintconst(l.Right) && Smallintconst(r.Right) { 3357 sl := int(l.Right.Int64()) 3358 if sl >= 0 { 3359 sr := int(r.Right.Int64()) 3360 if sr >= 0 && sl+sr == w { 3361 // Rewrite left shift half to left rotate. 3362 if l.Op == OLSH { 3363 n = l 3364 } else { 3365 n = r 3366 } 3367 n.Op = OLROT 3368 3369 // Remove rotate 0 and rotate w. 3370 s := int(n.Right.Int64()) 3371 3372 if s == 0 || s == w { 3373 n = n.Left 3374 } 3375 return n 3376 } 3377 } 3378 return n 3379 } 3380 3381 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31). 3382 return n 3383 } 3384 3385 // isIntOrdering reports whether n is a <, ≤, >, or ≥ ordering between integers. 3386 func (n *Node) isIntOrdering() bool { 3387 switch n.Op { 3388 case OLE, OLT, OGE, OGT: 3389 default: 3390 return false 3391 } 3392 return n.Left.Type.IsInteger() && n.Right.Type.IsInteger() 3393 } 3394 3395 // walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10. 3396 // n must be an OANDAND or OOROR node. 3397 // The result of walkinrange MUST be assigned back to n, e.g. 3398 // n.Left = walkinrange(n.Left) 3399 func walkinrange(n *Node, init *Nodes) *Node { 3400 // We are looking for something equivalent to a opl b OP b opr c, where: 3401 // * a, b, and c have integer type 3402 // * b is side-effect-free 3403 // * opl and opr are each < or ≤ 3404 // * OP is && 3405 l := n.Left 3406 r := n.Right 3407 if !l.isIntOrdering() || !r.isIntOrdering() { 3408 return n 3409 } 3410 3411 // Find b, if it exists, and rename appropriately. 3412 // Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right 3413 // Output is: a opl b(==x) ANDAND/OROR b(==x) opr c 3414 a, opl, b := l.Left, l.Op, l.Right 3415 x, opr, c := r.Left, r.Op, r.Right 3416 for i := 0; ; i++ { 3417 if samesafeexpr(b, x) { 3418 break 3419 } 3420 if i == 3 { 3421 // Tried all permutations and couldn't find an appropriate b == x. 3422 return n 3423 } 3424 if i&1 == 0 { 3425 a, opl, b = b, Brrev(opl), a 3426 } else { 3427 x, opr, c = c, Brrev(opr), x 3428 } 3429 } 3430 3431 // If n.Op is ||, apply de Morgan. 3432 // Negate the internal ops now; we'll negate the top level op at the end. 3433 // Henceforth assume &&. 3434 negateResult := n.Op == OOROR 3435 if negateResult { 3436 opl = Brcom(opl) 3437 opr = Brcom(opr) 3438 } 3439 3440 cmpdir := func(o Op) int { 3441 switch o { 3442 case OLE, OLT: 3443 return -1 3444 case OGE, OGT: 3445 return +1 3446 } 3447 Fatalf("walkinrange cmpdir %v", o) 3448 return 0 3449 } 3450 if cmpdir(opl) != cmpdir(opr) { 3451 // Not a range check; something like b < a && b < c. 3452 return n 3453 } 3454 3455 switch opl { 3456 case OGE, OGT: 3457 // We have something like a > b && b ≥ c. 3458 // Switch and reverse ops and rename constants, 3459 // to make it look like a ≤ b && b < c. 3460 a, c = c, a 3461 opl, opr = Brrev(opr), Brrev(opl) 3462 } 3463 3464 // We must ensure that c-a is non-negative. 3465 // For now, require a and c to be constants. 3466 // In the future, we could also support a == 0 and c == len/cap(...). 3467 // Unfortunately, by this point, most len/cap expressions have been 3468 // stored into temporary variables. 3469 if !Isconst(a, CTINT) || !Isconst(c, CTINT) { 3470 return n 3471 } 3472 3473 if opl == OLT { 3474 // We have a < b && ... 3475 // We need a ≤ b && ... to safely use unsigned comparison tricks. 3476 // If a is not the maximum constant for b's type, 3477 // we can increment a and switch to ≤. 3478 if a.Int64() >= Maxintval[b.Type.Etype].Int64() { 3479 return n 3480 } 3481 a = Nodintconst(a.Int64() + 1) 3482 opl = OLE 3483 } 3484 3485 bound := c.Int64() - a.Int64() 3486 if bound < 0 { 3487 // Bad news. Something like 5 <= x && x < 3. 3488 // Rare in practice, and we still need to generate side-effects, 3489 // so just leave it alone. 3490 return n 3491 } 3492 3493 // We have a ≤ b && b < c (or a ≤ b && b ≤ c). 3494 // This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a), 3495 // which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a), 3496 // which is equivalent to uint(b-a) < uint(c-a). 3497 ut := b.Type.toUnsigned() 3498 lhs := conv(Nod(OSUB, b, a), ut) 3499 rhs := Nodintconst(bound) 3500 if negateResult { 3501 // Negate top level. 3502 opr = Brcom(opr) 3503 } 3504 cmp := Nod(opr, lhs, rhs) 3505 cmp.Lineno = n.Lineno 3506 cmp = addinit(cmp, l.Ninit.Slice()) 3507 cmp = addinit(cmp, r.Ninit.Slice()) 3508 cmp = typecheck(cmp, Erv) 3509 cmp = walkexpr(cmp, init) 3510 return cmp 3511 } 3512 3513 // walkmul rewrites integer multiplication by powers of two as shifts. 3514 // The result of walkmul MUST be assigned back to n, e.g. 3515 // n.Left = walkmul(n.Left, init) 3516 func walkmul(n *Node, init *Nodes) *Node { 3517 if !n.Type.IsInteger() { 3518 return n 3519 } 3520 3521 var nr *Node 3522 var nl *Node 3523 if n.Right.Op == OLITERAL { 3524 nl = n.Left 3525 nr = n.Right 3526 } else if n.Left.Op == OLITERAL { 3527 nl = n.Right 3528 nr = n.Left 3529 } else { 3530 return n 3531 } 3532 3533 neg := 0 3534 3535 // x*0 is 0 (and side effects of x). 3536 var pow int 3537 var w int 3538 if nr.Int64() == 0 { 3539 cheapexpr(nl, init) 3540 Nodconst(n, n.Type, 0) 3541 goto ret 3542 } 3543 3544 // nr is a constant. 3545 pow = powtwo(nr) 3546 3547 if pow < 0 { 3548 return n 3549 } 3550 if pow >= 1000 { 3551 // negative power of 2, like -16 3552 neg = 1 3553 3554 pow -= 1000 3555 } 3556 3557 w = int(nl.Type.Width * 8) 3558 if pow+1 >= w { // too big, shouldn't happen 3559 return n 3560 } 3561 3562 nl = cheapexpr(nl, init) 3563 3564 if pow == 0 { 3565 // x*1 is x 3566 n = nl 3567 3568 goto ret 3569 } 3570 3571 n = Nod(OLSH, nl, Nodintconst(int64(pow))) 3572 3573 ret: 3574 if neg != 0 { 3575 n = Nod(OMINUS, n, nil) 3576 } 3577 3578 n = typecheck(n, Erv) 3579 n = walkexpr(n, init) 3580 return n 3581 } 3582 3583 // walkdiv rewrites division by a constant as less expensive 3584 // operations. 3585 // The result of walkdiv MUST be assigned back to n, e.g. 3586 // n.Left = walkdiv(n.Left, init) 3587 func walkdiv(n *Node, init *Nodes) *Node { 3588 // if >= 0, nr is 1<<pow // 1 if nr is negative. 3589 3590 // TODO(minux) 3591 if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) { 3592 return n 3593 } 3594 3595 if n.Right.Op != OLITERAL { 3596 return n 3597 } 3598 3599 // nr is a constant. 3600 nl := cheapexpr(n.Left, init) 3601 3602 nr := n.Right 3603 3604 // special cases of mod/div 3605 // by a constant 3606 w := int(nl.Type.Width * 8) 3607 3608 s := 0 // 1 if nr is negative. 3609 pow := powtwo(nr) // if >= 0, nr is 1<<pow 3610 if pow >= 1000 { 3611 // negative power of 2 3612 s = 1 3613 3614 pow -= 1000 3615 } 3616 3617 if pow+1 >= w { 3618 // divisor too large. 3619 return n 3620 } 3621 3622 if pow < 0 { 3623 // try to do division by multiply by (2^w)/d 3624 // see hacker's delight chapter 10 3625 // TODO: support 64-bit magic multiply here. 3626 var m Magic 3627 m.W = w 3628 3629 if nl.Type.IsSigned() { 3630 m.Sd = nr.Int64() 3631 Smagic(&m) 3632 } else { 3633 m.Ud = uint64(nr.Int64()) 3634 Umagic(&m) 3635 } 3636 3637 if m.Bad != 0 { 3638 return n 3639 } 3640 3641 // We have a quick division method so use it 3642 // for modulo too. 3643 if n.Op == OMOD { 3644 // rewrite as A%B = A - (A/B*B). 3645 n1 := Nod(ODIV, nl, nr) 3646 3647 n2 := Nod(OMUL, n1, nr) 3648 n = Nod(OSUB, nl, n2) 3649 goto ret 3650 } 3651 3652 switch Simtype[nl.Type.Etype] { 3653 default: 3654 return n 3655 3656 // n1 = nl * magic >> w (HMUL) 3657 case TUINT8, TUINT16, TUINT32: 3658 var nc Node 3659 3660 Nodconst(&nc, nl.Type, int64(m.Um)) 3661 n1 := Nod(OHMUL, nl, &nc) 3662 n1 = typecheck(n1, Erv) 3663 if m.Ua != 0 { 3664 // Select a Go type with (at least) twice the width. 3665 var twide *Type 3666 switch Simtype[nl.Type.Etype] { 3667 default: 3668 return n 3669 3670 case TUINT8, TUINT16: 3671 twide = Types[TUINT32] 3672 3673 case TUINT32: 3674 twide = Types[TUINT64] 3675 3676 case TINT8, TINT16: 3677 twide = Types[TINT32] 3678 3679 case TINT32: 3680 twide = Types[TINT64] 3681 } 3682 3683 // add numerator (might overflow). 3684 // n2 = (n1 + nl) 3685 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide)) 3686 3687 // shift by m.s 3688 var nc Node 3689 3690 Nodconst(&nc, Types[TUINT], int64(m.S)) 3691 n = conv(Nod(ORSH, n2, &nc), nl.Type) 3692 } else { 3693 // n = n1 >> m.s 3694 var nc Node 3695 3696 Nodconst(&nc, Types[TUINT], int64(m.S)) 3697 n = Nod(ORSH, n1, &nc) 3698 } 3699 3700 // n1 = nl * magic >> w 3701 case TINT8, TINT16, TINT32: 3702 var nc Node 3703 3704 Nodconst(&nc, nl.Type, m.Sm) 3705 n1 := Nod(OHMUL, nl, &nc) 3706 n1 = typecheck(n1, Erv) 3707 if m.Sm < 0 { 3708 // add the numerator. 3709 n1 = Nod(OADD, n1, nl) 3710 } 3711 3712 // shift by m.s 3713 var ns Node 3714 3715 Nodconst(&ns, Types[TUINT], int64(m.S)) 3716 n2 := conv(Nod(ORSH, n1, &ns), nl.Type) 3717 3718 // add 1 iff n1 is negative. 3719 var nneg Node 3720 3721 Nodconst(&nneg, Types[TUINT], int64(w)-1) 3722 n3 := Nod(ORSH, nl, &nneg) // n4 = -1 iff n1 is negative. 3723 n = Nod(OSUB, n2, n3) 3724 3725 // apply sign. 3726 if m.Sd < 0 { 3727 n = Nod(OMINUS, n, nil) 3728 } 3729 } 3730 3731 goto ret 3732 } 3733 3734 switch pow { 3735 case 0: 3736 if n.Op == OMOD { 3737 // nl % 1 is zero. 3738 Nodconst(n, n.Type, 0) 3739 } else if s != 0 { 3740 // divide by -1 3741 n.Op = OMINUS 3742 3743 n.Right = nil 3744 } else { 3745 // divide by 1 3746 n = nl 3747 } 3748 3749 default: 3750 if n.Type.IsSigned() { 3751 if n.Op == OMOD { 3752 // signed modulo 2^pow is like ANDing 3753 // with the last pow bits, but if nl < 0, 3754 // nl & (2^pow-1) is (nl+1)%2^pow - 1. 3755 var nc Node 3756 3757 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1) 3758 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0. 3759 if pow == 1 { 3760 n1 = typecheck(n1, Erv) 3761 n1 = cheapexpr(n1, init) 3762 3763 // n = (nl+ε)&1 -ε where ε=1 iff nl<0. 3764 n2 := Nod(OSUB, nl, n1) 3765 3766 var nc Node 3767 Nodconst(&nc, nl.Type, 1) 3768 n3 := Nod(OAND, n2, &nc) 3769 n = Nod(OADD, n3, n1) 3770 } else { 3771 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0. 3772 var nc Node 3773 3774 Nodconst(&nc, nl.Type, (1<<uint(pow))-1) 3775 n2 := Nod(OAND, n1, &nc) // n2 = 2^pow-1 iff nl<0. 3776 n2 = typecheck(n2, Erv) 3777 n2 = cheapexpr(n2, init) 3778 3779 n3 := Nod(OADD, nl, n2) 3780 n4 := Nod(OAND, n3, &nc) 3781 n = Nod(OSUB, n4, n2) 3782 } 3783 3784 break 3785 } else { 3786 // arithmetic right shift does not give the correct rounding. 3787 // if nl >= 0, nl >> n == nl / nr 3788 // if nl < 0, we want to add 2^n-1 first. 3789 var nc Node 3790 3791 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-1) 3792 n1 := Nod(ORSH, nl, &nc) // n1 = -1 iff nl < 0. 3793 if pow == 1 { 3794 // nl+1 is nl-(-1) 3795 n.Left = Nod(OSUB, nl, n1) 3796 } else { 3797 // Do a logical right right on -1 to keep pow bits. 3798 var nc Node 3799 3800 Nodconst(&nc, Types[Simtype[TUINT]], int64(w)-int64(pow)) 3801 n2 := Nod(ORSH, conv(n1, nl.Type.toUnsigned()), &nc) 3802 n.Left = Nod(OADD, nl, conv(n2, nl.Type)) 3803 } 3804 3805 // n = (nl + 2^pow-1) >> pow 3806 n.Op = ORSH 3807 3808 var n2 Node 3809 Nodconst(&n2, Types[Simtype[TUINT]], int64(pow)) 3810 n.Right = &n2 3811 n.Typecheck = 0 3812 } 3813 3814 if s != 0 { 3815 n = Nod(OMINUS, n, nil) 3816 } 3817 break 3818 } 3819 3820 var nc Node 3821 if n.Op == OMOD { 3822 // n = nl & (nr-1) 3823 n.Op = OAND 3824 3825 Nodconst(&nc, nl.Type, nr.Int64()-1) 3826 } else { 3827 // n = nl >> pow 3828 n.Op = ORSH 3829 3830 Nodconst(&nc, Types[Simtype[TUINT]], int64(pow)) 3831 } 3832 3833 n.Typecheck = 0 3834 n.Right = &nc 3835 } 3836 3837 goto ret 3838 3839 ret: 3840 n = typecheck(n, Erv) 3841 n = walkexpr(n, init) 3842 return n 3843 } 3844 3845 // return 1 if integer n must be in range [0, max), 0 otherwise 3846 func bounded(n *Node, max int64) bool { 3847 if n.Type == nil || !n.Type.IsInteger() { 3848 return false 3849 } 3850 3851 sign := n.Type.IsSigned() 3852 bits := int32(8 * n.Type.Width) 3853 3854 if Smallintconst(n) { 3855 v := n.Int64() 3856 return 0 <= v && v < max 3857 } 3858 3859 switch n.Op { 3860 case OAND: 3861 v := int64(-1) 3862 if Smallintconst(n.Left) { 3863 v = n.Left.Int64() 3864 } else if Smallintconst(n.Right) { 3865 v = n.Right.Int64() 3866 } 3867 3868 if 0 <= v && v < max { 3869 return true 3870 } 3871 3872 case OMOD: 3873 if !sign && Smallintconst(n.Right) { 3874 v := n.Right.Int64() 3875 if 0 <= v && v <= max { 3876 return true 3877 } 3878 } 3879 3880 case ODIV: 3881 if !sign && Smallintconst(n.Right) { 3882 v := n.Right.Int64() 3883 for bits > 0 && v >= 2 { 3884 bits-- 3885 v >>= 1 3886 } 3887 } 3888 3889 case ORSH: 3890 if !sign && Smallintconst(n.Right) { 3891 v := n.Right.Int64() 3892 if v > int64(bits) { 3893 return true 3894 } 3895 bits -= int32(v) 3896 } 3897 } 3898 3899 if !sign && bits <= 62 && 1<<uint(bits) <= max { 3900 return true 3901 } 3902 3903 return false 3904 } 3905 3906 // usemethod check interface method calls for uses of reflect.Type.Method. 3907 func usemethod(n *Node) { 3908 t := n.Left.Type 3909 3910 // Looking for either of: 3911 // Method(int) reflect.Method 3912 // MethodByName(string) (reflect.Method, bool) 3913 // 3914 // TODO(crawshaw): improve precision of match by working out 3915 // how to check the method name. 3916 if n := t.Params().NumFields(); n != 1 { 3917 return 3918 } 3919 if n := t.Results().NumFields(); n != 1 && n != 2 { 3920 return 3921 } 3922 p0 := t.Params().Field(0) 3923 res0 := t.Results().Field(0) 3924 var res1 *Field 3925 if t.Results().NumFields() == 2 { 3926 res1 = t.Results().Field(1) 3927 } 3928 3929 if res1 == nil { 3930 if p0.Type.Etype != TINT { 3931 return 3932 } 3933 } else { 3934 if !p0.Type.IsString() { 3935 return 3936 } 3937 if !res1.Type.IsBoolean() { 3938 return 3939 } 3940 } 3941 if Tconv(res0.Type, 0) != "reflect.Method" { 3942 return 3943 } 3944 3945 Curfn.Func.ReflectMethod = true 3946 } 3947 3948 func usefield(n *Node) { 3949 if obj.Fieldtrack_enabled == 0 { 3950 return 3951 } 3952 3953 switch n.Op { 3954 default: 3955 Fatalf("usefield %v", n.Op) 3956 3957 case ODOT, ODOTPTR: 3958 break 3959 } 3960 if n.Sym == nil { 3961 // No field name. This DOTPTR was built by the compiler for access 3962 // to runtime data structures. Ignore. 3963 return 3964 } 3965 3966 t := n.Left.Type 3967 if t.IsPtr() { 3968 t = t.Elem() 3969 } 3970 field := dotField[typeSym{t.Orig, n.Sym}] 3971 if field == nil { 3972 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym) 3973 } 3974 if !strings.Contains(field.Note, "go:\"track\"") { 3975 return 3976 } 3977 3978 outer := n.Left.Type 3979 if outer.IsPtr() { 3980 outer = outer.Elem() 3981 } 3982 if outer.Sym == nil { 3983 Yyerror("tracked field must be in named struct type") 3984 } 3985 if !exportname(field.Sym.Name) { 3986 Yyerror("tracked field must be exported (upper case)") 3987 } 3988 3989 sym := tracksym(outer, field) 3990 if Curfn.Func.FieldTrack == nil { 3991 Curfn.Func.FieldTrack = make(map[*Sym]struct{}) 3992 } 3993 Curfn.Func.FieldTrack[sym] = struct{}{} 3994 } 3995 3996 func candiscardlist(l Nodes) bool { 3997 for _, n := range l.Slice() { 3998 if !candiscard(n) { 3999 return false 4000 } 4001 } 4002 return true 4003 } 4004 4005 func candiscard(n *Node) bool { 4006 if n == nil { 4007 return true 4008 } 4009 4010 switch n.Op { 4011 default: 4012 return false 4013 4014 // Discardable as long as the subpieces are. 4015 case ONAME, 4016 ONONAME, 4017 OTYPE, 4018 OPACK, 4019 OLITERAL, 4020 OADD, 4021 OSUB, 4022 OOR, 4023 OXOR, 4024 OADDSTR, 4025 OADDR, 4026 OANDAND, 4027 OARRAYBYTESTR, 4028 OARRAYRUNESTR, 4029 OSTRARRAYBYTE, 4030 OSTRARRAYRUNE, 4031 OCAP, 4032 OCMPIFACE, 4033 OCMPSTR, 4034 OCOMPLIT, 4035 OMAPLIT, 4036 OSTRUCTLIT, 4037 OARRAYLIT, 4038 OPTRLIT, 4039 OCONV, 4040 OCONVIFACE, 4041 OCONVNOP, 4042 ODOT, 4043 OEQ, 4044 ONE, 4045 OLT, 4046 OLE, 4047 OGT, 4048 OGE, 4049 OKEY, 4050 OLEN, 4051 OMUL, 4052 OLSH, 4053 ORSH, 4054 OAND, 4055 OANDNOT, 4056 ONEW, 4057 ONOT, 4058 OCOM, 4059 OPLUS, 4060 OMINUS, 4061 OOROR, 4062 OPAREN, 4063 ORUNESTR, 4064 OREAL, 4065 OIMAG, 4066 OCOMPLEX: 4067 break 4068 4069 // Discardable as long as we know it's not division by zero. 4070 case ODIV, OMOD: 4071 if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 { 4072 break 4073 } 4074 if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 { 4075 break 4076 } 4077 return false 4078 4079 // Discardable as long as we know it won't fail because of a bad size. 4080 case OMAKECHAN, OMAKEMAP: 4081 if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 { 4082 break 4083 } 4084 return false 4085 4086 // Difficult to tell what sizes are okay. 4087 case OMAKESLICE: 4088 return false 4089 } 4090 4091 if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) { 4092 return false 4093 } 4094 4095 return true 4096 } 4097 4098 // rewrite 4099 // print(x, y, z) 4100 // into 4101 // func(a1, a2, a3) { 4102 // print(a1, a2, a3) 4103 // }(x, y, z) 4104 // and same for println. 4105 4106 var walkprintfunc_prgen int 4107 4108 // The result of walkprintfunc MUST be assigned back to n, e.g. 4109 // n.Left = walkprintfunc(n.Left, init) 4110 func walkprintfunc(n *Node, init *Nodes) *Node { 4111 if n.Ninit.Len() != 0 { 4112 walkstmtlist(n.Ninit.Slice()) 4113 init.AppendNodes(&n.Ninit) 4114 } 4115 4116 t := Nod(OTFUNC, nil, nil) 4117 num := 0 4118 var printargs []*Node 4119 var a *Node 4120 var buf string 4121 for _, n1 := range n.List.Slice() { 4122 buf = fmt.Sprintf("a%d", num) 4123 num++ 4124 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type)) 4125 t.List.Append(a) 4126 printargs = append(printargs, a.Left) 4127 } 4128 4129 fn := Nod(ODCLFUNC, nil, nil) 4130 walkprintfunc_prgen++ 4131 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen) 4132 fn.Func.Nname = newname(Lookup(buf)) 4133 fn.Func.Nname.Name.Defn = fn 4134 fn.Func.Nname.Name.Param.Ntype = t 4135 declare(fn.Func.Nname, PFUNC) 4136 4137 oldfn := Curfn 4138 Curfn = nil 4139 funchdr(fn) 4140 4141 a = Nod(n.Op, nil, nil) 4142 a.List.Set(printargs) 4143 a = typecheck(a, Etop) 4144 a = walkstmt(a) 4145 4146 fn.Nbody.Set1(a) 4147 4148 funcbody(fn) 4149 4150 fn = typecheck(fn, Etop) 4151 typecheckslice(fn.Nbody.Slice(), Etop) 4152 xtop = append(xtop, fn) 4153 Curfn = oldfn 4154 4155 a = Nod(OCALL, nil, nil) 4156 a.Left = fn.Func.Nname 4157 a.List.Set(n.List.Slice()) 4158 a = typecheck(a, Etop) 4159 a = walkexpr(a, init) 4160 return a 4161 }