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