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