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