github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/cmd/compile/internal/gc/walk.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gc 6 7 import ( 8 "cmd/internal/obj" 9 "fmt" 10 "strings" 11 ) 12 13 var mpzero Mpint 14 15 // The constant is known to runtime. 16 const ( 17 tmpstringbufsize = 32 18 ) 19 20 func walk(fn *Node) { 21 Curfn = fn 22 23 if Debug['W'] != 0 { 24 s := fmt.Sprintf("\nbefore %v", Curfn.Func.Nname.Sym) 25 dumplist(s, Curfn.Nbody) 26 } 27 28 lno := int(lineno) 29 30 // Final typecheck for any unused variables. 31 // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below. 32 for l := fn.Func.Dcl; l != nil; l = l.Next { 33 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO { 34 typecheck(&l.N, Erv|Easgn) 35 } 36 } 37 38 // Propagate the used flag for typeswitch variables up to the NONAME in it's definition. 39 for l := fn.Func.Dcl; l != nil; l = l.Next { 40 if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Name.Defn != nil && l.N.Name.Defn.Op == OTYPESW && l.N.Used { 41 l.N.Name.Defn.Left.Used = true 42 } 43 } 44 45 for l := fn.Func.Dcl; l != nil; l = l.Next { 46 if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used { 47 continue 48 } 49 if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW { 50 if defn.Left.Used { 51 continue 52 } 53 lineno = defn.Left.Lineno 54 Yyerror("%v declared and not used", l.N.Sym) 55 defn.Left.Used = true // suppress repeats 56 } else { 57 lineno = l.N.Lineno 58 Yyerror("%v declared and not used", l.N.Sym) 59 } 60 } 61 62 lineno = int32(lno) 63 if nerrors != 0 { 64 return 65 } 66 walkstmtlist(Curfn.Nbody) 67 if Debug['W'] != 0 { 68 s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym) 69 dumplist(s, Curfn.Nbody) 70 } 71 72 heapmoves() 73 if Debug['W'] != 0 && Curfn.Func.Enter != nil { 74 s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym) 75 dumplist(s, Curfn.Func.Enter) 76 } 77 } 78 79 func walkstmtlist(l *NodeList) { 80 for ; l != nil; l = l.Next { 81 walkstmt(&l.N) 82 } 83 } 84 85 func samelist(a *NodeList, b *NodeList) bool { 86 for ; a != nil && b != nil; a, b = a.Next, b.Next { 87 if a.N != b.N { 88 return false 89 } 90 } 91 return a == b 92 } 93 94 func paramoutheap(fn *Node) bool { 95 for l := fn.Func.Dcl; l != nil; l = l.Next { 96 switch l.N.Class { 97 case PPARAMOUT, 98 PPARAMOUT | PHEAP: 99 return l.N.Addrtaken 100 101 // stop early - parameters are over 102 case PAUTO, 103 PAUTO | PHEAP: 104 return false 105 } 106 } 107 108 return false 109 } 110 111 // adds "adjust" to all the argument locations for the call n. 112 // n must be a defer or go node that has already been walked. 113 func adjustargs(n *Node, adjust int) { 114 var arg *Node 115 var lhs *Node 116 117 callfunc := n.Left 118 for args := callfunc.List; args != nil; args = args.Next { 119 arg = args.N 120 if arg.Op != OAS { 121 Yyerror("call arg not assignment") 122 } 123 lhs = arg.Left 124 if lhs.Op == ONAME { 125 // This is a temporary introduced by reorder1. 126 // The real store to the stack appears later in the arg list. 127 continue 128 } 129 130 if lhs.Op != OINDREG { 131 Yyerror("call argument store does not use OINDREG") 132 } 133 134 // can't really check this in machine-indep code. 135 //if(lhs->val.u.reg != D_SP) 136 // yyerror("call arg assign not indreg(SP)"); 137 lhs.Xoffset += int64(adjust) 138 } 139 } 140 141 func walkstmt(np **Node) { 142 n := *np 143 if n == nil { 144 return 145 } 146 if n.Dodata == 2 { // don't walk, generated by anylit. 147 return 148 } 149 150 setlineno(n) 151 152 walkstmtlist(n.Ninit) 153 154 switch n.Op { 155 default: 156 if n.Op == ONAME { 157 Yyerror("%v is not a top level statement", n.Sym) 158 } else { 159 Yyerror("%v is not a top level statement", Oconv(int(n.Op), 0)) 160 } 161 Dump("nottop", n) 162 163 case OAS, 164 OASOP, 165 OAS2, 166 OAS2DOTTYPE, 167 OAS2RECV, 168 OAS2FUNC, 169 OAS2MAPR, 170 OCLOSE, 171 OCOPY, 172 OCALLMETH, 173 OCALLINTER, 174 OCALL, 175 OCALLFUNC, 176 ODELETE, 177 OSEND, 178 OPRINT, 179 OPRINTN, 180 OPANIC, 181 OEMPTY, 182 ORECOVER, 183 OGETG: 184 if n.Typecheck == 0 { 185 Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign)) 186 } 187 init := n.Ninit 188 n.Ninit = nil 189 walkexpr(&n, &init) 190 addinit(&n, init) 191 if (*np).Op == OCOPY && n.Op == OCONVNOP { 192 n.Op = OEMPTY // don't leave plain values as statements. 193 } 194 195 // special case for a receive where we throw away 196 // the value received. 197 case ORECV: 198 if n.Typecheck == 0 { 199 Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign)) 200 } 201 init := n.Ninit 202 n.Ninit = nil 203 204 walkexpr(&n.Left, &init) 205 n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil()) 206 walkexpr(&n, &init) 207 208 addinit(&n, init) 209 210 case OBREAK, 211 ODCL, 212 OCONTINUE, 213 OFALL, 214 OGOTO, 215 OLABEL, 216 ODCLCONST, 217 ODCLTYPE, 218 OCHECKNIL, 219 OVARKILL: 220 break 221 222 case OBLOCK: 223 walkstmtlist(n.List) 224 225 case OXCASE: 226 Yyerror("case statement out of place") 227 n.Op = OCASE 228 fallthrough 229 230 case OCASE: 231 walkstmt(&n.Right) 232 233 case ODEFER: 234 hasdefer = true 235 switch n.Left.Op { 236 case OPRINT, OPRINTN: 237 walkprintfunc(&n.Left, &n.Ninit) 238 239 case OCOPY: 240 n.Left = copyany(n.Left, &n.Ninit, 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 && 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 Fatalf("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 Fatalf("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign)) 350 } 351 352 *np = n 353 } 354 355 func isSmallMakeSlice(n *Node) bool { 356 if n.Op != OMAKESLICE { 357 return false 358 } 359 l := n.Left 360 r := n.Right 361 if r == nil { 362 r = l 363 } 364 t := n.Type 365 366 return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val().U.(*Mpint)) < (1<<16)/t.Type.Width) 367 } 368 369 /* 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 Fatalf("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 Fatalf("missed typecheck: %v\n", Nconv(n, obj.FmtSign)) 431 } 432 433 switch n.Op { 434 default: 435 Dump("walk", n) 436 Fatalf("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 Fatalf("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 Fatalf("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 Fatalf("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) && strlit(n.Right) == strlit(n.Left.List.Next.N) { 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 Fatalf("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 Fatalf("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 Fatalf("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 Fatalf("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 Fatalf("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 Fatalf("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 Fatalf("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 { 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 func applywritebarrier(n *Node, init **NodeList) *Node { 2229 if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) { 2230 if Debug_wb > 1 { 2231 Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0)) 2232 } 2233 n.Op = OASWB 2234 return n 2235 } 2236 return n 2237 } 2238 2239 func convas(n *Node, init **NodeList) *Node { 2240 if n.Op != OAS { 2241 Fatalf("convas: not OAS %v", Oconv(int(n.Op), 0)) 2242 } 2243 2244 n.Typecheck = 1 2245 2246 var lt *Type 2247 var rt *Type 2248 if n.Left == nil || n.Right == nil { 2249 goto out 2250 } 2251 2252 lt = n.Left.Type 2253 rt = n.Right.Type 2254 if lt == nil || rt == nil { 2255 goto out 2256 } 2257 2258 if isblank(n.Left) { 2259 defaultlit(&n.Right, nil) 2260 goto out 2261 } 2262 2263 if n.Left.Op == OINDEXMAP { 2264 map_ := n.Left.Left 2265 key := n.Left.Right 2266 val := n.Right 2267 walkexpr(&map_, init) 2268 walkexpr(&key, init) 2269 walkexpr(&val, init) 2270 2271 // orderexpr made sure key and val are addressable. 2272 key = Nod(OADDR, key, nil) 2273 2274 val = Nod(OADDR, val, nil) 2275 n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val) 2276 goto out 2277 } 2278 2279 if !Eqtype(lt, rt) { 2280 n.Right = assignconv(n.Right, lt, "assignment") 2281 walkexpr(&n.Right, init) 2282 } 2283 2284 out: 2285 ullmancalc(n) 2286 return n 2287 } 2288 2289 /* 2290 * from ascompat[te] 2291 * evaluating actual function arguments. 2292 * f(a,b) 2293 * if there is exactly one function expr, 2294 * then it is done first. otherwise must 2295 * make temp variables 2296 */ 2297 func reorder1(all *NodeList) *NodeList { 2298 var n *Node 2299 2300 c := 0 // function calls 2301 t := 0 // total parameters 2302 2303 for l := all; l != nil; l = l.Next { 2304 n = l.N 2305 t++ 2306 ullmancalc(n) 2307 if n.Ullman >= UINF { 2308 c++ 2309 } 2310 } 2311 2312 if c == 0 || t == 1 { 2313 return all 2314 } 2315 2316 var g *NodeList // fncalls assigned to tempnames 2317 var f *Node // last fncall assigned to stack 2318 var r *NodeList // non fncalls and tempnames assigned to stack 2319 d := 0 2320 var a *Node 2321 for l := all; l != nil; l = l.Next { 2322 n = l.N 2323 if n.Ullman < UINF { 2324 r = list(r, n) 2325 continue 2326 } 2327 2328 d++ 2329 if d == c { 2330 f = n 2331 continue 2332 } 2333 2334 // make assignment of fncall to tempname 2335 a = temp(n.Right.Type) 2336 2337 a = Nod(OAS, a, n.Right) 2338 g = list(g, a) 2339 2340 // put normal arg assignment on list 2341 // with fncall replaced by tempname 2342 n.Right = a.Left 2343 2344 r = list(r, n) 2345 } 2346 2347 if f != nil { 2348 g = list(g, f) 2349 } 2350 return concat(g, r) 2351 } 2352 2353 /* 2354 * from ascompat[ee] 2355 * a,b = c,d 2356 * simultaneous assignment. there cannot 2357 * be later use of an earlier lvalue. 2358 * 2359 * function calls have been removed. 2360 */ 2361 func reorder3(all *NodeList) *NodeList { 2362 var l *Node 2363 2364 // If a needed expression may be affected by an 2365 // earlier assignment, make an early copy of that 2366 // expression and use the copy instead. 2367 var early *NodeList 2368 2369 var mapinit *NodeList 2370 for list := all; list != nil; list = list.Next { 2371 l = list.N.Left 2372 2373 // Save subexpressions needed on left side. 2374 // Drill through non-dereferences. 2375 for { 2376 if l.Op == ODOT || l.Op == OPAREN { 2377 l = l.Left 2378 continue 2379 } 2380 2381 if l.Op == OINDEX && Isfixedarray(l.Left.Type) { 2382 reorder3save(&l.Right, all, list, &early) 2383 l = l.Left 2384 continue 2385 } 2386 2387 break 2388 } 2389 2390 switch l.Op { 2391 default: 2392 Fatalf("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp)) 2393 2394 case ONAME: 2395 break 2396 2397 case OINDEX, OINDEXMAP: 2398 reorder3save(&l.Left, all, list, &early) 2399 reorder3save(&l.Right, all, list, &early) 2400 if l.Op == OINDEXMAP { 2401 list.N = convas(list.N, &mapinit) 2402 } 2403 2404 case OIND, ODOTPTR: 2405 reorder3save(&l.Left, all, list, &early) 2406 } 2407 2408 // Save expression on right side. 2409 reorder3save(&list.N.Right, all, list, &early) 2410 } 2411 2412 early = concat(mapinit, early) 2413 return concat(early, all) 2414 } 2415 2416 /* 2417 * if the evaluation of *np would be affected by the 2418 * assignments in all up to but not including stop, 2419 * copy into a temporary during *early and 2420 * replace *np with that temp. 2421 */ 2422 func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) { 2423 n := *np 2424 if !aliased(n, all, stop) { 2425 return 2426 } 2427 2428 q := temp(n.Type) 2429 q = Nod(OAS, q, n) 2430 typecheck(&q, Etop) 2431 *early = list(*early, q) 2432 *np = q.Left 2433 } 2434 2435 /* 2436 * what's the outer value that a write to n affects? 2437 * outer value means containing struct or array. 2438 */ 2439 func outervalue(n *Node) *Node { 2440 for { 2441 if n.Op == OXDOT { 2442 Fatalf("OXDOT in walk") 2443 } 2444 if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP { 2445 n = n.Left 2446 continue 2447 } 2448 2449 if n.Op == OINDEX && Isfixedarray(n.Left.Type) { 2450 n = n.Left 2451 continue 2452 } 2453 2454 break 2455 } 2456 2457 return n 2458 } 2459 2460 /* 2461 * Is it possible that the computation of n might be 2462 * affected by writes in as up to but not including stop? 2463 */ 2464 func aliased(n *Node, all *NodeList, stop *NodeList) bool { 2465 if n == nil { 2466 return false 2467 } 2468 2469 // Look for obvious aliasing: a variable being assigned 2470 // during the all list and appearing in n. 2471 // Also record whether there are any writes to main memory. 2472 // Also record whether there are any writes to variables 2473 // whose addresses have been taken. 2474 memwrite := 0 2475 2476 varwrite := 0 2477 var a *Node 2478 for l := all; l != stop; l = l.Next { 2479 a = outervalue(l.N.Left) 2480 if a.Op != ONAME { 2481 memwrite = 1 2482 continue 2483 } 2484 2485 switch n.Class { 2486 default: 2487 varwrite = 1 2488 continue 2489 2490 case PAUTO, PPARAM, PPARAMOUT: 2491 if n.Addrtaken { 2492 varwrite = 1 2493 continue 2494 } 2495 2496 if vmatch2(a, n) { 2497 // Direct hit. 2498 return true 2499 } 2500 } 2501 } 2502 2503 // The variables being written do not appear in n. 2504 // However, n might refer to computed addresses 2505 // that are being written. 2506 2507 // If no computed addresses are affected by the writes, no aliasing. 2508 if memwrite == 0 && varwrite == 0 { 2509 return false 2510 } 2511 2512 // If n does not refer to computed addresses 2513 // (that is, if n only refers to variables whose addresses 2514 // have not been taken), no aliasing. 2515 if varexpr(n) { 2516 return false 2517 } 2518 2519 // Otherwise, both the writes and n refer to computed memory addresses. 2520 // Assume that they might conflict. 2521 return true 2522 } 2523 2524 /* 2525 * does the evaluation of n only refer to variables 2526 * whose addresses have not been taken? 2527 * (and no other memory) 2528 */ 2529 func varexpr(n *Node) bool { 2530 if n == nil { 2531 return true 2532 } 2533 2534 switch n.Op { 2535 case OLITERAL: 2536 return true 2537 2538 case ONAME: 2539 switch n.Class { 2540 case PAUTO, PPARAM, PPARAMOUT: 2541 if !n.Addrtaken { 2542 return true 2543 } 2544 } 2545 2546 return false 2547 2548 case OADD, 2549 OSUB, 2550 OOR, 2551 OXOR, 2552 OMUL, 2553 ODIV, 2554 OMOD, 2555 OLSH, 2556 ORSH, 2557 OAND, 2558 OANDNOT, 2559 OPLUS, 2560 OMINUS, 2561 OCOM, 2562 OPAREN, 2563 OANDAND, 2564 OOROR, 2565 ODOT, // but not ODOTPTR 2566 OCONV, 2567 OCONVNOP, 2568 OCONVIFACE, 2569 ODOTTYPE: 2570 return varexpr(n.Left) && varexpr(n.Right) 2571 } 2572 2573 // Be conservative. 2574 return false 2575 } 2576 2577 /* 2578 * is the name l mentioned in r? 2579 */ 2580 func vmatch2(l *Node, r *Node) bool { 2581 if r == nil { 2582 return false 2583 } 2584 switch r.Op { 2585 // match each right given left 2586 case ONAME: 2587 return l == r 2588 2589 case OLITERAL: 2590 return false 2591 } 2592 2593 if vmatch2(l, r.Left) { 2594 return true 2595 } 2596 if vmatch2(l, r.Right) { 2597 return true 2598 } 2599 for ll := r.List; ll != nil; ll = ll.Next { 2600 if vmatch2(l, ll.N) { 2601 return true 2602 } 2603 } 2604 return false 2605 } 2606 2607 /* 2608 * is any name mentioned in l also mentioned in r? 2609 * called by sinit.go 2610 */ 2611 func vmatch1(l *Node, r *Node) bool { 2612 /* 2613 * isolate all left sides 2614 */ 2615 if l == nil || r == nil { 2616 return false 2617 } 2618 switch l.Op { 2619 case ONAME: 2620 switch l.Class { 2621 case PPARAM, PPARAMREF, PAUTO: 2622 break 2623 2624 // assignment to non-stack variable 2625 // must be delayed if right has function calls. 2626 default: 2627 if r.Ullman >= UINF { 2628 return true 2629 } 2630 } 2631 2632 return vmatch2(l, r) 2633 2634 case OLITERAL: 2635 return false 2636 } 2637 2638 if vmatch1(l.Left, r) { 2639 return true 2640 } 2641 if vmatch1(l.Right, r) { 2642 return true 2643 } 2644 for ll := l.List; ll != nil; ll = ll.Next { 2645 if vmatch1(ll.N, r) { 2646 return true 2647 } 2648 } 2649 return false 2650 } 2651 2652 /* 2653 * walk through argin parameters. 2654 * generate and return code to allocate 2655 * copies of escaped parameters to the heap. 2656 */ 2657 func paramstoheap(argin **Type, out int) *NodeList { 2658 var savet Iter 2659 var v *Node 2660 var as *Node 2661 2662 var nn *NodeList 2663 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) { 2664 v = t.Nname 2665 if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result 2666 v = nil 2667 } 2668 2669 // For precise stacks, the garbage collector assumes results 2670 // are always live, so zero them always. 2671 if out != 0 { 2672 // Defer might stop a panic and show the 2673 // return values as they exist at the time of panic. 2674 // Make sure to zero them on entry to the function. 2675 nn = list(nn, Nod(OAS, nodarg(t, 1), nil)) 2676 } 2677 2678 if v == nil || v.Class&PHEAP == 0 { 2679 continue 2680 } 2681 2682 // generate allocation & copying code 2683 if compiling_runtime != 0 { 2684 Yyerror("%v escapes to heap, not allowed in runtime.", v) 2685 } 2686 if prealloc[v] == nil { 2687 prealloc[v] = callnew(v.Type) 2688 } 2689 nn = list(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v])) 2690 if v.Class&^PHEAP != PPARAMOUT { 2691 as = Nod(OAS, v, v.Name.Param.Stackparam) 2692 v.Name.Param.Stackparam.Typecheck = 1 2693 typecheck(&as, Etop) 2694 as = applywritebarrier(as, &nn) 2695 nn = list(nn, as) 2696 } 2697 } 2698 2699 return nn 2700 } 2701 2702 /* 2703 * walk through argout parameters copying back to stack 2704 */ 2705 func returnsfromheap(argin **Type) *NodeList { 2706 var savet Iter 2707 var v *Node 2708 2709 var nn *NodeList 2710 for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) { 2711 v = t.Nname 2712 if v == nil || v.Class != PHEAP|PPARAMOUT { 2713 continue 2714 } 2715 nn = list(nn, Nod(OAS, v.Name.Param.Stackparam, v)) 2716 } 2717 2718 return nn 2719 } 2720 2721 /* 2722 * take care of migrating any function in/out args 2723 * between the stack and the heap. adds code to 2724 * curfn's before and after lists. 2725 */ 2726 func heapmoves() { 2727 lno := lineno 2728 lineno = Curfn.Lineno 2729 nn := paramstoheap(getthis(Curfn.Type), 0) 2730 nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0)) 2731 nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1)) 2732 Curfn.Func.Enter = concat(Curfn.Func.Enter, nn) 2733 lineno = Curfn.Func.Endlineno 2734 Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type)) 2735 lineno = lno 2736 } 2737 2738 func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node { 2739 if fn.Type == nil || fn.Type.Etype != TFUNC { 2740 Fatalf("mkcall %v %v", fn, fn.Type) 2741 } 2742 2743 var args *NodeList 2744 n := fn.Type.Intuple 2745 for i := 0; i < n; i++ { 2746 args = list(args, va[i]) 2747 } 2748 2749 r := Nod(OCALL, fn, nil) 2750 r.List = args 2751 if fn.Type.Outtuple > 0 { 2752 typecheck(&r, Erv|Efnstruct) 2753 } else { 2754 typecheck(&r, Etop) 2755 } 2756 walkexpr(&r, init) 2757 r.Type = t 2758 return r 2759 } 2760 2761 func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node { 2762 return vmkcall(syslook(name, 0), t, init, args) 2763 } 2764 2765 func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node { 2766 return vmkcall(fn, t, init, args) 2767 } 2768 2769 func conv(n *Node, t *Type) *Node { 2770 if Eqtype(n.Type, t) { 2771 return n 2772 } 2773 n = Nod(OCONV, n, nil) 2774 n.Type = t 2775 typecheck(&n, Erv) 2776 return n 2777 } 2778 2779 func chanfn(name string, n int, t *Type) *Node { 2780 if t.Etype != TCHAN { 2781 Fatalf("chanfn %v", t) 2782 } 2783 fn := syslook(name, 1) 2784 switch n { 2785 default: 2786 Fatalf("chanfn %d", n) 2787 case 1: 2788 substArgTypes(fn, t.Type) 2789 case 2: 2790 substArgTypes(fn, t.Type, t.Type) 2791 } 2792 return fn 2793 } 2794 2795 func mapfn(name string, t *Type) *Node { 2796 if t.Etype != TMAP { 2797 Fatalf("mapfn %v", t) 2798 } 2799 fn := syslook(name, 1) 2800 substArgTypes(fn, t.Down, t.Type, t.Down, t.Type) 2801 return fn 2802 } 2803 2804 func mapfndel(name string, t *Type) *Node { 2805 if t.Etype != TMAP { 2806 Fatalf("mapfn %v", t) 2807 } 2808 fn := syslook(name, 1) 2809 substArgTypes(fn, t.Down, t.Type, t.Down) 2810 return fn 2811 } 2812 2813 func writebarrierfn(name string, l *Type, r *Type) *Node { 2814 fn := syslook(name, 1) 2815 substArgTypes(fn, l, r) 2816 return fn 2817 } 2818 2819 func addstr(n *Node, init **NodeList) *Node { 2820 // orderexpr rewrote OADDSTR to have a list of strings. 2821 c := count(n.List) 2822 2823 if c < 2 { 2824 Yyerror("addstr count %d too small", c) 2825 } 2826 2827 buf := nodnil() 2828 if n.Esc == EscNone { 2829 sz := int64(0) 2830 for l := n.List; l != nil; l = l.Next { 2831 if n.Op == OLITERAL { 2832 sz += int64(len(n.Val().U.(string))) 2833 } 2834 } 2835 2836 // Don't allocate the buffer if the result won't fit. 2837 if sz < tmpstringbufsize { 2838 // Create temporary buffer for result string on stack. 2839 t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8]) 2840 2841 buf = Nod(OADDR, temp(t), nil) 2842 } 2843 } 2844 2845 // build list of string arguments 2846 args := list1(buf) 2847 2848 for l := n.List; l != nil; l = l.Next { 2849 args = list(args, conv(l.N, Types[TSTRING])) 2850 } 2851 2852 var fn string 2853 if c <= 5 { 2854 // small numbers of strings use direct runtime helpers. 2855 // note: orderexpr knows this cutoff too. 2856 fn = fmt.Sprintf("concatstring%d", c) 2857 } else { 2858 // large numbers of strings are passed to the runtime as a slice. 2859 fn = "concatstrings" 2860 2861 t := typ(TARRAY) 2862 t.Type = Types[TSTRING] 2863 t.Bound = -1 2864 slice := Nod(OCOMPLIT, nil, typenod(t)) 2865 if prealloc[n] != nil { 2866 prealloc[slice] = prealloc[n] 2867 } 2868 slice.List = args.Next // skip buf arg 2869 args = list1(buf) 2870 args = list(args, slice) 2871 slice.Esc = EscNone 2872 } 2873 2874 cat := syslook(fn, 1) 2875 r := Nod(OCALL, cat, nil) 2876 r.List = args 2877 typecheck(&r, Erv) 2878 walkexpr(&r, init) 2879 r.Type = n.Type 2880 2881 return r 2882 } 2883 2884 // expand append(l1, l2...) to 2885 // init { 2886 // s := l1 2887 // if n := len(l1) + len(l2) - cap(s); n > 0 { 2888 // s = growslice_n(s, n) 2889 // } 2890 // s = s[:len(l1)+len(l2)] 2891 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) 2892 // } 2893 // s 2894 // 2895 // l2 is allowed to be a string. 2896 func appendslice(n *Node, init **NodeList) *Node { 2897 walkexprlistsafe(n.List, init) 2898 2899 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s 2900 // and n are name or literal, but those may index the slice we're 2901 // modifying here. Fix explicitly. 2902 for l := n.List; l != nil; l = l.Next { 2903 l.N = cheapexpr(l.N, init) 2904 } 2905 2906 l1 := n.List.N 2907 l2 := n.List.Next.N 2908 2909 s := temp(l1.Type) // var s []T 2910 var l *NodeList 2911 l = list(l, Nod(OAS, s, l1)) // s = l1 2912 2913 nt := temp(Types[TINT]) 2914 2915 nif := Nod(OIF, nil, nil) 2916 2917 // n := len(s) + len(l2) - cap(s) 2918 nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil)))) 2919 2920 nif.Left = Nod(OGT, nt, Nodintconst(0)) 2921 2922 // instantiate growslice_n(Type*, []any, int) []any 2923 fn := syslook("growslice_n", 1) // growslice_n(<type>, old []T, n int64) (ret []T) 2924 substArgTypes(fn, s.Type.Type, s.Type.Type) 2925 2926 // s = growslice_n(T, s, n) 2927 nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt))) 2928 2929 l = list(l, nif) 2930 2931 if haspointers(l1.Type.Type) { 2932 // copy(s[len(l1):len(l1)+len(l2)], l2) 2933 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil)))) 2934 2935 nptr1.Etype = 1 2936 nptr2 := l2 2937 fn := syslook("typedslicecopy", 1) 2938 substArgTypes(fn, l1.Type, l2.Type) 2939 nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2) 2940 l = list(l, nt) 2941 } else if flag_race != 0 { 2942 // rely on runtime to instrument copy. 2943 // copy(s[len(l1):len(l1)+len(l2)], l2) 2944 nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil)))) 2945 2946 nptr1.Etype = 1 2947 nptr2 := l2 2948 var fn *Node 2949 if l2.Type.Etype == TSTRING { 2950 fn = syslook("slicestringcopy", 1) 2951 } else { 2952 fn = syslook("slicecopy", 1) 2953 } 2954 substArgTypes(fn, l1.Type, l2.Type) 2955 nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width)) 2956 l = list(l, nt) 2957 } else { 2958 // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) 2959 nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil)) 2960 2961 nptr1.Bounded = true 2962 nptr1 = Nod(OADDR, nptr1, nil) 2963 2964 nptr2 := Nod(OSPTR, l2, nil) 2965 2966 fn := syslook("memmove", 1) 2967 substArgTypes(fn, s.Type.Type, s.Type.Type) 2968 2969 nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l) 2970 2971 nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width)) 2972 nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid) 2973 l = list(l, nt) 2974 } 2975 2976 // s = s[:len(l1)+len(l2)] 2977 nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil)) 2978 2979 nt = Nod(OSLICE, s, Nod(OKEY, nil, nt)) 2980 nt.Etype = 1 2981 l = list(l, Nod(OAS, s, nt)) 2982 2983 typechecklist(l, Etop) 2984 walkstmtlist(l) 2985 *init = concat(*init, l) 2986 return s 2987 } 2988 2989 // Rewrite append(src, x, y, z) so that any side effects in 2990 // x, y, z (including runtime panics) are evaluated in 2991 // initialization statements before the append. 2992 // For normal code generation, stop there and leave the 2993 // rest to cgen_append. 2994 // 2995 // For race detector, expand append(src, a [, b]* ) to 2996 // 2997 // init { 2998 // s := src 2999 // const argc = len(args) - 1 3000 // if cap(s) - len(s) < argc { 3001 // s = growslice(s, len(s)+argc) 3002 // } 3003 // n := len(s) 3004 // s = s[:n+argc] 3005 // s[n] = a 3006 // s[n+1] = b 3007 // ... 3008 // } 3009 // s 3010 func walkappend(n *Node, init **NodeList, dst *Node) *Node { 3011 if !samesafeexpr(dst, n.List.N) { 3012 l := n.List 3013 l.N = safeexpr(l.N, init) 3014 walkexpr(&l.N, init) 3015 } 3016 walkexprlistsafe(n.List.Next, init) 3017 3018 // walkexprlistsafe will leave OINDEX (s[n]) alone if both s 3019 // and n are name or literal, but those may index the slice we're 3020 // modifying here. Fix explicitly. 3021 // Using cheapexpr also makes sure that the evaluation 3022 // of all arguments (and especially any panics) happen 3023 // before we begin to modify the slice in a visible way. 3024 for l := n.List.Next; l != nil; l = l.Next { 3025 l.N = cheapexpr(l.N, init) 3026 } 3027 3028 nsrc := n.List.N 3029 3030 // Resolve slice type of multi-valued return. 3031 if Istype(nsrc.Type, TSTRUCT) { 3032 nsrc.Type = nsrc.Type.Type.Type 3033 } 3034 argc := count(n.List) - 1 3035 if argc < 1 { 3036 return nsrc 3037 } 3038 3039 // General case, with no function calls left as arguments. 3040 // Leave for gen, except that race detector requires old form 3041 if flag_race == 0 { 3042 return n 3043 } 3044 3045 var l *NodeList 3046 3047 ns := temp(nsrc.Type) 3048 l = list(l, Nod(OAS, ns, nsrc)) // s = src 3049 3050 na := Nodintconst(int64(argc)) // const argc 3051 nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc 3052 nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na) 3053 3054 fn := syslook("growslice", 1) // growslice(<type>, old []T, mincap int) (ret []T) 3055 substArgTypes(fn, ns.Type.Type, ns.Type.Type) 3056 3057 nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, Nod(OADD, Nod(OLEN, ns, nil), na)))) 3058 3059 l = list(l, nx) 3060 3061 nn := temp(Types[TINT]) 3062 l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s) 3063 3064 nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc] 3065 nx.Etype = 1 3066 l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc] 3067 3068 for a := n.List.Next; a != nil; a = a.Next { 3069 nx = Nod(OINDEX, ns, nn) // s[n] ... 3070 nx.Bounded = true 3071 l = list(l, Nod(OAS, nx, a.N)) // s[n] = arg 3072 if a.Next != nil { 3073 l = list(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1 3074 } 3075 } 3076 3077 typechecklist(l, Etop) 3078 walkstmtlist(l) 3079 *init = concat(*init, l) 3080 return ns 3081 } 3082 3083 // Lower copy(a, b) to a memmove call or a runtime call. 3084 // 3085 // init { 3086 // n := len(a) 3087 // if n > len(b) { n = len(b) } 3088 // memmove(a.ptr, b.ptr, n*sizeof(elem(a))) 3089 // } 3090 // n; 3091 // 3092 // Also works if b is a string. 3093 // 3094 func copyany(n *Node, init **NodeList, runtimecall int) *Node { 3095 if haspointers(n.Left.Type.Type) { 3096 fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type) 3097 return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right) 3098 } 3099 3100 if runtimecall != 0 { 3101 var fn *Node 3102 if n.Right.Type.Etype == TSTRING { 3103 fn = syslook("slicestringcopy", 1) 3104 } else { 3105 fn = syslook("slicecopy", 1) 3106 } 3107 substArgTypes(fn, n.Left.Type, n.Right.Type) 3108 return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width)) 3109 } 3110 3111 walkexpr(&n.Left, init) 3112 walkexpr(&n.Right, init) 3113 nl := temp(n.Left.Type) 3114 nr := temp(n.Right.Type) 3115 var l *NodeList 3116 l = list(l, Nod(OAS, nl, n.Left)) 3117 l = list(l, Nod(OAS, nr, n.Right)) 3118 3119 nfrm := Nod(OSPTR, nr, nil) 3120 nto := Nod(OSPTR, nl, nil) 3121 3122 nlen := temp(Types[TINT]) 3123 3124 // n = len(to) 3125 l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil))) 3126 3127 // if n > len(frm) { n = len(frm) } 3128 nif := Nod(OIF, nil, nil) 3129 3130 nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil)) 3131 nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil))) 3132 l = list(l, nif) 3133 3134 // Call memmove. 3135 fn := syslook("memmove", 1) 3136 3137 substArgTypes(fn, nl.Type.Type, nl.Type.Type) 3138 nwid := temp(Types[TUINTPTR]) 3139 l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR]))) 3140 nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width)) 3141 l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid)) 3142 3143 typechecklist(l, Etop) 3144 walkstmtlist(l) 3145 *init = concat(*init, l) 3146 return nlen 3147 } 3148 3149 func eqfor(t *Type, needsize *int) *Node { 3150 // Should only arrive here with large memory or 3151 // a struct/array containing a non-memory field/element. 3152 // Small memory is handled inline, and single non-memory 3153 // is handled during type check (OCMPSTR etc). 3154 a := algtype1(t, nil) 3155 3156 if a != AMEM && a != -1 { 3157 Fatalf("eqfor %v", t) 3158 } 3159 3160 if a == AMEM { 3161 n := syslook("memequal", 1) 3162 substArgTypes(n, t, t) 3163 *needsize = 1 3164 return n 3165 } 3166 3167 sym := typesymprefix(".eq", t) 3168 n := newname(sym) 3169 n.Class = PFUNC 3170 ntype := Nod(OTFUNC, nil, nil) 3171 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t)))) 3172 ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t)))) 3173 ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL]))) 3174 typecheck(&ntype, Etype) 3175 n.Type = ntype.Type 3176 *needsize = 0 3177 return n 3178 } 3179 3180 func countfield(t *Type) int { 3181 n := 0 3182 for t1 := t.Type; t1 != nil; t1 = t1.Down { 3183 n++ 3184 } 3185 return n 3186 } 3187 3188 func walkcompare(np **Node, init **NodeList) { 3189 n := *np 3190 3191 // Given interface value l and concrete value r, rewrite 3192 // l == r 3193 // to 3194 // x, ok := l.(type(r)); ok && x == r 3195 // Handle != similarly. 3196 // This avoids the allocation that would be required 3197 // to convert r to l for comparison. 3198 var l *Node 3199 3200 var r *Node 3201 if Isinter(n.Left.Type) && !Isinter(n.Right.Type) { 3202 l = n.Left 3203 r = n.Right 3204 } else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) { 3205 l = n.Right 3206 r = n.Left 3207 } 3208 3209 if l != nil { 3210 x := temp(r.Type) 3211 if haspointers(r.Type) { 3212 a := Nod(OAS, x, nil) 3213 typecheck(&a, Etop) 3214 *init = list(*init, a) 3215 } 3216 ok := temp(Types[TBOOL]) 3217 3218 // l.(type(r)) 3219 a := Nod(ODOTTYPE, l, nil) 3220 3221 a.Type = r.Type 3222 3223 // x, ok := l.(type(r)) 3224 expr := Nod(OAS2, nil, nil) 3225 3226 expr.List = list1(x) 3227 expr.List = list(expr.List, ok) 3228 expr.Rlist = list1(a) 3229 typecheck(&expr, Etop) 3230 walkexpr(&expr, init) 3231 3232 if n.Op == OEQ { 3233 r = Nod(OANDAND, ok, Nod(OEQ, x, r)) 3234 } else { 3235 r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r)) 3236 } 3237 *init = list(*init, expr) 3238 finishcompare(np, n, r, init) 3239 return 3240 } 3241 3242 // Must be comparison of array or struct. 3243 // Otherwise back end handles it. 3244 t := n.Left.Type 3245 3246 switch t.Etype { 3247 default: 3248 return 3249 3250 case TARRAY: 3251 if Isslice(t) { 3252 return 3253 } 3254 3255 case TSTRUCT: 3256 break 3257 } 3258 3259 cmpl := n.Left 3260 for cmpl != nil && cmpl.Op == OCONVNOP { 3261 cmpl = cmpl.Left 3262 } 3263 cmpr := n.Right 3264 for cmpr != nil && cmpr.Op == OCONVNOP { 3265 cmpr = cmpr.Left 3266 } 3267 3268 if !islvalue(cmpl) || !islvalue(cmpr) { 3269 Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr) 3270 } 3271 3272 l = temp(Ptrto(t)) 3273 a := Nod(OAS, l, Nod(OADDR, cmpl, nil)) 3274 a.Right.Etype = 1 // addr does not escape 3275 typecheck(&a, Etop) 3276 *init = list(*init, a) 3277 3278 r = temp(Ptrto(t)) 3279 a = Nod(OAS, r, Nod(OADDR, cmpr, nil)) 3280 a.Right.Etype = 1 // addr does not escape 3281 typecheck(&a, Etop) 3282 *init = list(*init, a) 3283 3284 andor := OANDAND 3285 if n.Op == ONE { 3286 andor = OOROR 3287 } 3288 3289 var expr *Node 3290 if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] { 3291 // Four or fewer elements of a basic type. 3292 // Unroll comparisons. 3293 var li *Node 3294 var ri *Node 3295 for i := 0; int64(i) < t.Bound; i++ { 3296 li = Nod(OINDEX, l, Nodintconst(int64(i))) 3297 ri = Nod(OINDEX, r, Nodintconst(int64(i))) 3298 a = Nod(int(n.Op), li, ri) 3299 if expr == nil { 3300 expr = a 3301 } else { 3302 expr = Nod(andor, expr, a) 3303 } 3304 } 3305 3306 if expr == nil { 3307 expr = Nodbool(n.Op == OEQ) 3308 } 3309 finishcompare(np, n, expr, init) 3310 return 3311 } 3312 3313 if t.Etype == TSTRUCT && countfield(t) <= 4 { 3314 // Struct of four or fewer fields. 3315 // Inline comparisons. 3316 var li *Node 3317 var ri *Node 3318 for t1 := t.Type; t1 != nil; t1 = t1.Down { 3319 if isblanksym(t1.Sym) { 3320 continue 3321 } 3322 li = Nod(OXDOT, l, newname(t1.Sym)) 3323 ri = Nod(OXDOT, r, newname(t1.Sym)) 3324 a = Nod(int(n.Op), li, ri) 3325 if expr == nil { 3326 expr = a 3327 } else { 3328 expr = Nod(andor, expr, a) 3329 } 3330 } 3331 3332 if expr == nil { 3333 expr = Nodbool(n.Op == OEQ) 3334 } 3335 finishcompare(np, n, expr, init) 3336 return 3337 } 3338 3339 // Chose not to inline. Call equality function directly. 3340 var needsize int 3341 call := Nod(OCALL, eqfor(t, &needsize), nil) 3342 3343 call.List = list(call.List, l) 3344 call.List = list(call.List, r) 3345 if needsize != 0 { 3346 call.List = list(call.List, Nodintconst(t.Width)) 3347 } 3348 r = call 3349 if n.Op != OEQ { 3350 r = Nod(ONOT, r, nil) 3351 } 3352 3353 finishcompare(np, n, r, init) 3354 return 3355 } 3356 3357 func finishcompare(np **Node, n, r *Node, init **NodeList) { 3358 // Using np here to avoid passing &r to typecheck. 3359 *np = r 3360 typecheck(np, Erv) 3361 walkexpr(np, init) 3362 r = *np 3363 if r.Type != n.Type { 3364 r = Nod(OCONVNOP, r, nil) 3365 r.Type = n.Type 3366 r.Typecheck = 1 3367 *np = r 3368 } 3369 } 3370 3371 func samecheap(a *Node, b *Node) bool { 3372 var ar *Node 3373 var br *Node 3374 for a != nil && b != nil && a.Op == b.Op { 3375 switch a.Op { 3376 default: 3377 return false 3378 3379 case ONAME: 3380 return a == b 3381 3382 case ODOT, ODOTPTR: 3383 ar = a.Right 3384 br = b.Right 3385 if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym { 3386 return false 3387 } 3388 3389 case OINDEX: 3390 ar = a.Right 3391 br = b.Right 3392 if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 { 3393 return false 3394 } 3395 } 3396 3397 a = a.Left 3398 b = b.Left 3399 } 3400 3401 return false 3402 } 3403 3404 func walkrotate(np **Node) { 3405 if Thearch.Thechar == '7' || Thearch.Thechar == '9' { 3406 return 3407 } 3408 3409 n := *np 3410 3411 // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value. 3412 l := n.Left 3413 3414 r := n.Right 3415 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 { 3416 return 3417 } 3418 3419 // Want same, side effect-free expression on lhs of both shifts. 3420 if !samecheap(l.Left, r.Left) { 3421 return 3422 } 3423 3424 // Constants adding to width? 3425 w := int(l.Type.Width * 8) 3426 3427 if Smallintconst(l.Right) && Smallintconst(r.Right) { 3428 sl := int(Mpgetfix(l.Right.Val().U.(*Mpint))) 3429 if sl >= 0 { 3430 sr := int(Mpgetfix(r.Right.Val().U.(*Mpint))) 3431 if sr >= 0 && sl+sr == w { 3432 // Rewrite left shift half to left rotate. 3433 if l.Op == OLSH { 3434 n = l 3435 } else { 3436 n = r 3437 } 3438 n.Op = OLROT 3439 3440 // Remove rotate 0 and rotate w. 3441 s := int(Mpgetfix(n.Right.Val().U.(*Mpint))) 3442 3443 if s == 0 || s == w { 3444 n = n.Left 3445 } 3446 3447 *np = n 3448 return 3449 } 3450 } 3451 return 3452 } 3453 3454 // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31). 3455 return 3456 } 3457 3458 /* 3459 * walkmul rewrites integer multiplication by powers of two as shifts. 3460 */ 3461 func walkmul(np **Node, init **NodeList) { 3462 n := *np 3463 if !Isint[n.Type.Etype] { 3464 return 3465 } 3466 3467 var nr *Node 3468 var nl *Node 3469 if n.Right.Op == OLITERAL { 3470 nl = n.Left 3471 nr = n.Right 3472 } else if n.Left.Op == OLITERAL { 3473 nl = n.Right 3474 nr = n.Left 3475 } else { 3476 return 3477 } 3478 3479 neg := 0 3480 3481 // x*0 is 0 (and side effects of x). 3482 var pow int 3483 var w int 3484 if Mpgetfix(nr.Val().U.(*Mpint)) == 0 { 3485 cheapexpr(nl, init) 3486 Nodconst(n, n.Type, 0) 3487 goto ret 3488 } 3489 3490 // nr is a constant. 3491 pow = powtwo(nr) 3492 3493 if pow < 0 { 3494 return 3495 } 3496 if pow >= 1000 { 3497 // negative power of 2, like -16 3498 neg = 1 3499 3500 pow -= 1000 3501 } 3502 3503 w = int(nl.Type.Width * 8) 3504 if pow+1 >= w { // too big, shouldn't happen 3505 return 3506 } 3507 3508 nl = cheapexpr(nl, init) 3509 3510 if pow == 0 { 3511 // x*1 is x 3512 n = nl 3513 3514 goto ret 3515 } 3516 3517 n = Nod(OLSH, nl, Nodintconst(int64(pow))) 3518 3519 ret: 3520 if neg != 0 { 3521 n = Nod(OMINUS, n, nil) 3522 } 3523 3524 typecheck(&n, Erv) 3525 walkexpr(&n, init) 3526 *np = n 3527 } 3528 3529 /* 3530 * walkdiv rewrites division by a constant as less expensive 3531 * operations. 3532 */ 3533 func walkdiv(np **Node, init **NodeList) { 3534 // if >= 0, nr is 1<<pow // 1 if nr is negative. 3535 3536 // TODO(minux) 3537 if Thearch.Thechar == '7' || Thearch.Thechar == '9' { 3538 return 3539 } 3540 3541 n := *np 3542 if n.Right.Op != OLITERAL { 3543 return 3544 } 3545 3546 // nr is a constant. 3547 nl := cheapexpr(n.Left, init) 3548 3549 nr := n.Right 3550 3551 // special cases of mod/div 3552 // by a constant 3553 w := int(nl.Type.Width * 8) 3554 3555 s := 0 // 1 if nr is negative. 3556 pow := powtwo(nr) // if >= 0, nr is 1<<pow 3557 if pow >= 1000 { 3558 // negative power of 2 3559 s = 1 3560 3561 pow -= 1000 3562 } 3563 3564 if pow+1 >= w { 3565 // divisor too large. 3566 return 3567 } 3568 3569 if pow < 0 { 3570 // try to do division by multiply by (2^w)/d 3571 // see hacker's delight chapter 10 3572 // TODO: support 64-bit magic multiply here. 3573 var m Magic 3574 m.W = w 3575 3576 if Issigned[nl.Type.Etype] { 3577 m.Sd = Mpgetfix(nr.Val().U.(*Mpint)) 3578 Smagic(&m) 3579 } else { 3580 m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint))) 3581 Umagic(&m) 3582 } 3583 3584 if m.Bad != 0 { 3585 return 3586 } 3587 3588 // We have a quick division method so use it 3589 // for modulo too. 3590 if n.Op == OMOD { 3591 // rewrite as A%B = A - (A/B*B). 3592 n1 := Nod(ODIV, nl, nr) 3593 3594 n2 := Nod(OMUL, n1, nr) 3595 n = Nod(OSUB, nl, n2) 3596 goto ret 3597 } 3598 3599 switch Simtype[nl.Type.Etype] { 3600 default: 3601 return 3602 3603 // n1 = nl * magic >> w (HMUL) 3604 case TUINT8, TUINT16, TUINT32: 3605 nc := Nod(OXXX, nil, nil) 3606 3607 Nodconst(nc, nl.Type, int64(m.Um)) 3608 n1 := Nod(OHMUL, nl, nc) 3609 typecheck(&n1, Erv) 3610 if m.Ua != 0 { 3611 // Select a Go type with (at least) twice the width. 3612 var twide *Type 3613 switch Simtype[nl.Type.Etype] { 3614 default: 3615 return 3616 3617 case TUINT8, TUINT16: 3618 twide = Types[TUINT32] 3619 3620 case TUINT32: 3621 twide = Types[TUINT64] 3622 3623 case TINT8, TINT16: 3624 twide = Types[TINT32] 3625 3626 case TINT32: 3627 twide = Types[TINT64] 3628 } 3629 3630 // add numerator (might overflow). 3631 // n2 = (n1 + nl) 3632 n2 := Nod(OADD, conv(n1, twide), conv(nl, twide)) 3633 3634 // shift by m.s 3635 nc := Nod(OXXX, nil, nil) 3636 3637 Nodconst(nc, Types[TUINT], int64(m.S)) 3638 n = conv(Nod(ORSH, n2, nc), nl.Type) 3639 } else { 3640 // n = n1 >> m.s 3641 nc := Nod(OXXX, nil, nil) 3642 3643 Nodconst(nc, Types[TUINT], int64(m.S)) 3644 n = Nod(ORSH, n1, nc) 3645 } 3646 3647 // n1 = nl * magic >> w 3648 case TINT8, TINT16, TINT32: 3649 nc := Nod(OXXX, nil, nil) 3650 3651 Nodconst(nc, nl.Type, m.Sm) 3652 n1 := Nod(OHMUL, nl, nc) 3653 typecheck(&n1, Erv) 3654 if m.Sm < 0 { 3655 // add the numerator. 3656 n1 = Nod(OADD, n1, nl) 3657 } 3658 3659 // shift by m.s 3660 nc = Nod(OXXX, nil, nil) 3661 3662 Nodconst(nc, Types[TUINT], int64(m.S)) 3663 n2 := conv(Nod(ORSH, n1, nc), nl.Type) 3664 3665 // add 1 iff n1 is negative. 3666 nc = Nod(OXXX, nil, nil) 3667 3668 Nodconst(nc, Types[TUINT], int64(w)-1) 3669 n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative. 3670 n = Nod(OSUB, n2, n3) 3671 3672 // apply sign. 3673 if m.Sd < 0 { 3674 n = Nod(OMINUS, n, nil) 3675 } 3676 } 3677 3678 goto ret 3679 } 3680 3681 switch pow { 3682 case 0: 3683 if n.Op == OMOD { 3684 // nl % 1 is zero. 3685 Nodconst(n, n.Type, 0) 3686 } else if s != 0 { 3687 // divide by -1 3688 n.Op = OMINUS 3689 3690 n.Right = nil 3691 } else { 3692 // divide by 1 3693 n = nl 3694 } 3695 3696 default: 3697 if Issigned[n.Type.Etype] { 3698 if n.Op == OMOD { 3699 // signed modulo 2^pow is like ANDing 3700 // with the last pow bits, but if nl < 0, 3701 // nl & (2^pow-1) is (nl+1)%2^pow - 1. 3702 nc := Nod(OXXX, nil, nil) 3703 3704 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1) 3705 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0. 3706 if pow == 1 { 3707 typecheck(&n1, Erv) 3708 n1 = cheapexpr(n1, init) 3709 3710 // n = (nl+ε)&1 -ε where ε=1 iff nl<0. 3711 n2 := Nod(OSUB, nl, n1) 3712 3713 nc := Nod(OXXX, nil, nil) 3714 Nodconst(nc, nl.Type, 1) 3715 n3 := Nod(OAND, n2, nc) 3716 n = Nod(OADD, n3, n1) 3717 } else { 3718 // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0. 3719 nc := Nod(OXXX, nil, nil) 3720 3721 Nodconst(nc, nl.Type, (1<<uint(pow))-1) 3722 n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0. 3723 typecheck(&n2, Erv) 3724 n2 = cheapexpr(n2, init) 3725 3726 n3 := Nod(OADD, nl, n2) 3727 n4 := Nod(OAND, n3, nc) 3728 n = Nod(OSUB, n4, n2) 3729 } 3730 3731 break 3732 } else { 3733 // arithmetic right shift does not give the correct rounding. 3734 // if nl >= 0, nl >> n == nl / nr 3735 // if nl < 0, we want to add 2^n-1 first. 3736 nc := Nod(OXXX, nil, nil) 3737 3738 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1) 3739 n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0. 3740 if pow == 1 { 3741 // nl+1 is nl-(-1) 3742 n.Left = Nod(OSUB, nl, n1) 3743 } else { 3744 // Do a logical right right on -1 to keep pow bits. 3745 nc := Nod(OXXX, nil, nil) 3746 3747 Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow)) 3748 n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc) 3749 n.Left = Nod(OADD, nl, conv(n2, nl.Type)) 3750 } 3751 3752 // n = (nl + 2^pow-1) >> pow 3753 n.Op = ORSH 3754 3755 nc = Nod(OXXX, nil, nil) 3756 Nodconst(nc, Types[Simtype[TUINT]], int64(pow)) 3757 n.Right = nc 3758 n.Typecheck = 0 3759 } 3760 3761 if s != 0 { 3762 n = Nod(OMINUS, n, nil) 3763 } 3764 break 3765 } 3766 3767 nc := Nod(OXXX, nil, nil) 3768 if n.Op == OMOD { 3769 // n = nl & (nr-1) 3770 n.Op = OAND 3771 3772 Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1) 3773 } else { 3774 // n = nl >> pow 3775 n.Op = ORSH 3776 3777 Nodconst(nc, Types[Simtype[TUINT]], int64(pow)) 3778 } 3779 3780 n.Typecheck = 0 3781 n.Right = nc 3782 } 3783 3784 goto ret 3785 3786 ret: 3787 typecheck(&n, Erv) 3788 walkexpr(&n, init) 3789 *np = n 3790 } 3791 3792 // return 1 if integer n must be in range [0, max), 0 otherwise 3793 func bounded(n *Node, max int64) bool { 3794 if n.Type == nil || !Isint[n.Type.Etype] { 3795 return false 3796 } 3797 3798 sign := Issigned[n.Type.Etype] 3799 bits := int32(8 * n.Type.Width) 3800 3801 if Smallintconst(n) { 3802 v := Mpgetfix(n.Val().U.(*Mpint)) 3803 return 0 <= v && v < max 3804 } 3805 3806 switch n.Op { 3807 case OAND: 3808 v := int64(-1) 3809 if Smallintconst(n.Left) { 3810 v = Mpgetfix(n.Left.Val().U.(*Mpint)) 3811 } else if Smallintconst(n.Right) { 3812 v = Mpgetfix(n.Right.Val().U.(*Mpint)) 3813 } 3814 3815 if 0 <= v && v < max { 3816 return true 3817 } 3818 3819 case OMOD: 3820 if !sign && Smallintconst(n.Right) { 3821 v := Mpgetfix(n.Right.Val().U.(*Mpint)) 3822 if 0 <= v && v <= max { 3823 return true 3824 } 3825 } 3826 3827 case ODIV: 3828 if !sign && Smallintconst(n.Right) { 3829 v := Mpgetfix(n.Right.Val().U.(*Mpint)) 3830 for bits > 0 && v >= 2 { 3831 bits-- 3832 v >>= 1 3833 } 3834 } 3835 3836 case ORSH: 3837 if !sign && Smallintconst(n.Right) { 3838 v := Mpgetfix(n.Right.Val().U.(*Mpint)) 3839 if v > int64(bits) { 3840 return true 3841 } 3842 bits -= int32(v) 3843 } 3844 } 3845 3846 if !sign && bits <= 62 && 1<<uint(bits) <= max { 3847 return true 3848 } 3849 3850 return false 3851 } 3852 3853 func usefield(n *Node) { 3854 if obj.Fieldtrack_enabled == 0 { 3855 return 3856 } 3857 3858 switch n.Op { 3859 default: 3860 Fatalf("usefield %v", Oconv(int(n.Op), 0)) 3861 3862 case ODOT, ODOTPTR: 3863 break 3864 } 3865 3866 t := n.Left.Type 3867 if Isptr[t.Etype] { 3868 t = t.Type 3869 } 3870 field := dotField[typeSym{t.Orig, n.Right.Sym}] 3871 if field == nil { 3872 Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym) 3873 } 3874 if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") { 3875 return 3876 } 3877 3878 // dedup on list 3879 if field.Lastfn == Curfn { 3880 return 3881 } 3882 field.Lastfn = Curfn 3883 field.Outer = n.Left.Type 3884 if Isptr[field.Outer.Etype] { 3885 field.Outer = field.Outer.Type 3886 } 3887 if field.Outer.Sym == nil { 3888 Yyerror("tracked field must be in named struct type") 3889 } 3890 if !exportname(field.Sym.Name) { 3891 Yyerror("tracked field must be exported (upper case)") 3892 } 3893 3894 Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field) 3895 } 3896 3897 func candiscardlist(l *NodeList) bool { 3898 for ; l != nil; l = l.Next { 3899 if !candiscard(l.N) { 3900 return false 3901 } 3902 } 3903 return true 3904 } 3905 3906 func candiscard(n *Node) bool { 3907 if n == nil { 3908 return true 3909 } 3910 3911 switch n.Op { 3912 default: 3913 return false 3914 3915 // Discardable as long as the subpieces are. 3916 case ONAME, 3917 ONONAME, 3918 OTYPE, 3919 OPACK, 3920 OLITERAL, 3921 OADD, 3922 OSUB, 3923 OOR, 3924 OXOR, 3925 OADDSTR, 3926 OADDR, 3927 OANDAND, 3928 OARRAYBYTESTR, 3929 OARRAYRUNESTR, 3930 OSTRARRAYBYTE, 3931 OSTRARRAYRUNE, 3932 OCAP, 3933 OCMPIFACE, 3934 OCMPSTR, 3935 OCOMPLIT, 3936 OMAPLIT, 3937 OSTRUCTLIT, 3938 OARRAYLIT, 3939 OPTRLIT, 3940 OCONV, 3941 OCONVIFACE, 3942 OCONVNOP, 3943 ODOT, 3944 OEQ, 3945 ONE, 3946 OLT, 3947 OLE, 3948 OGT, 3949 OGE, 3950 OKEY, 3951 OLEN, 3952 OMUL, 3953 OLSH, 3954 ORSH, 3955 OAND, 3956 OANDNOT, 3957 ONEW, 3958 ONOT, 3959 OCOM, 3960 OPLUS, 3961 OMINUS, 3962 OOROR, 3963 OPAREN, 3964 ORUNESTR, 3965 OREAL, 3966 OIMAG, 3967 OCOMPLEX: 3968 break 3969 3970 // Discardable as long as we know it's not division by zero. 3971 case ODIV, OMOD: 3972 if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 { 3973 break 3974 } 3975 if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 { 3976 break 3977 } 3978 return false 3979 3980 // Discardable as long as we know it won't fail because of a bad size. 3981 case OMAKECHAN, OMAKEMAP: 3982 if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 { 3983 break 3984 } 3985 return false 3986 3987 // Difficult to tell what sizes are okay. 3988 case OMAKESLICE: 3989 return false 3990 } 3991 3992 if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) { 3993 return false 3994 } 3995 3996 return true 3997 } 3998 3999 // rewrite 4000 // print(x, y, z) 4001 // into 4002 // func(a1, a2, a3) { 4003 // print(a1, a2, a3) 4004 // }(x, y, z) 4005 // and same for println. 4006 4007 var walkprintfunc_prgen int 4008 4009 func walkprintfunc(np **Node, init **NodeList) { 4010 n := *np 4011 4012 if n.Ninit != nil { 4013 walkstmtlist(n.Ninit) 4014 *init = concat(*init, n.Ninit) 4015 n.Ninit = nil 4016 } 4017 4018 t := Nod(OTFUNC, nil, nil) 4019 num := 0 4020 var printargs *NodeList 4021 var a *Node 4022 var buf string 4023 for l := n.List; l != nil; l = l.Next { 4024 buf = fmt.Sprintf("a%d", num) 4025 num++ 4026 a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type)) 4027 t.List = list(t.List, a) 4028 printargs = list(printargs, a.Left) 4029 } 4030 4031 fn := Nod(ODCLFUNC, nil, nil) 4032 walkprintfunc_prgen++ 4033 buf = fmt.Sprintf("print·%d", walkprintfunc_prgen) 4034 fn.Func.Nname = newname(Lookup(buf)) 4035 fn.Func.Nname.Name.Defn = fn 4036 fn.Func.Nname.Name.Param.Ntype = t 4037 declare(fn.Func.Nname, PFUNC) 4038 4039 oldfn := Curfn 4040 Curfn = nil 4041 funchdr(fn) 4042 4043 a = Nod(int(n.Op), nil, nil) 4044 a.List = printargs 4045 typecheck(&a, Etop) 4046 walkstmt(&a) 4047 4048 fn.Nbody = list1(a) 4049 4050 funcbody(fn) 4051 4052 typecheck(&fn, Etop) 4053 typechecklist(fn.Nbody, Etop) 4054 xtop = list(xtop, fn) 4055 Curfn = oldfn 4056 4057 a = Nod(OCALL, nil, nil) 4058 a.Left = fn.Func.Nname 4059 a.List = n.List 4060 typecheck(&a, Etop) 4061 walkexpr(&a, init) 4062 *np = a 4063 }