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