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