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