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