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