1 // Do not edit. Bootstrap copy of /Volumes/Android/buildbot/src/android/build-tools/out/obj/go/src/cmd/compile/internal/gc/gen.go 2 3 //line /Volumes/Android/buildbot/src/android/build-tools/out/obj/go/src/cmd/compile/internal/gc/gen.go:1 4 // Copyright 2009 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 package gc 9 10 import ( 11 "bootstrap/internal/obj" 12 "fmt" 13 ) 14 15 /* 16 * portable half of code generator. 17 * mainly statements and control flow. 18 */ 19 var labellist *Label 20 21 var lastlabel *Label 22 23 func Sysfunc(name string) *Node { 24 n := newname(Pkglookup(name, Runtimepkg)) 25 n.Class = PFUNC 26 return n 27 } 28 29 // addrescapes tags node n as having had its address taken 30 // by "increasing" the "value" of n.Esc to EscHeap. 31 // Storage is allocated as necessary to allow the address 32 // to be taken. 33 func addrescapes(n *Node) { 34 switch n.Op { 35 // probably a type error already. 36 // dump("addrescapes", n); 37 default: 38 break 39 40 case ONAME: 41 if n == nodfp { 42 break 43 } 44 45 // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. 46 // on PPARAM it means something different. 47 if n.Class == PAUTO && n.Esc == EscNever { 48 break 49 } 50 51 switch n.Class { 52 case PPARAMREF: 53 addrescapes(n.Name.Defn) 54 55 // if func param, need separate temporary 56 // to hold heap pointer. 57 // the function type has already been checked 58 // (we're in the function body) 59 // so the param already has a valid xoffset. 60 61 // expression to refer to stack copy 62 case PPARAM, PPARAMOUT: 63 n.Name.Param.Stackparam = Nod(OPARAM, n, nil) 64 65 n.Name.Param.Stackparam.Type = n.Type 66 n.Name.Param.Stackparam.Addable = true 67 if n.Xoffset == BADWIDTH { 68 Fatal("addrescapes before param assignment") 69 } 70 n.Name.Param.Stackparam.Xoffset = n.Xoffset 71 fallthrough 72 73 case PAUTO: 74 n.Class |= PHEAP 75 76 n.Addable = false 77 n.Ullman = 2 78 n.Xoffset = 0 79 80 // create stack variable to hold pointer to heap 81 oldfn := Curfn 82 83 Curfn = n.Name.Curfn 84 n.Name.Heapaddr = temp(Ptrto(n.Type)) 85 buf := fmt.Sprintf("&%v", n.Sym) 86 n.Name.Heapaddr.Sym = Lookup(buf) 87 n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym 88 n.Esc = EscHeap 89 if Debug['m'] != 0 { 90 fmt.Printf("%v: moved to heap: %v\n", n.Line(), n) 91 } 92 Curfn = oldfn 93 } 94 95 case OIND, ODOTPTR: 96 break 97 98 // ODOTPTR has already been introduced, 99 // so these are the non-pointer ODOT and OINDEX. 100 // In &x[0], if x is a slice, then x does not 101 // escape--the pointer inside x does, but that 102 // is always a heap pointer anyway. 103 case ODOT, OINDEX, OPAREN, OCONVNOP: 104 if !Isslice(n.Left.Type) { 105 addrescapes(n.Left) 106 } 107 } 108 } 109 110 func clearlabels() { 111 for l := labellist; l != nil; l = l.Link { 112 l.Sym.Label = nil 113 } 114 115 labellist = nil 116 lastlabel = nil 117 } 118 119 func newlab(n *Node) *Label { 120 s := n.Left.Sym 121 lab := s.Label 122 if lab == nil { 123 lab = new(Label) 124 if lastlabel == nil { 125 labellist = lab 126 } else { 127 lastlabel.Link = lab 128 } 129 lastlabel = lab 130 lab.Sym = s 131 s.Label = lab 132 } 133 134 if n.Op == OLABEL { 135 if lab.Def != nil { 136 Yyerror("label %v already defined at %v", s, lab.Def.Line()) 137 } else { 138 lab.Def = n 139 } 140 } else { 141 lab.Use = list(lab.Use, n) 142 } 143 144 return lab 145 } 146 147 func checkgoto(from *Node, to *Node) { 148 if from.Sym == to.Sym { 149 return 150 } 151 152 nf := 0 153 for fs := from.Sym; fs != nil; fs = fs.Link { 154 nf++ 155 } 156 nt := 0 157 for fs := to.Sym; fs != nil; fs = fs.Link { 158 nt++ 159 } 160 fs := from.Sym 161 for ; nf > nt; nf-- { 162 fs = fs.Link 163 } 164 if fs != to.Sym { 165 lno := int(lineno) 166 setlineno(from) 167 168 // decide what to complain about. 169 // prefer to complain about 'into block' over declarations, 170 // so scan backward to find most recent block or else dcl. 171 var block *Sym 172 173 var dcl *Sym 174 ts := to.Sym 175 for ; nt > nf; nt-- { 176 if ts.Pkg == nil { 177 block = ts 178 } else { 179 dcl = ts 180 } 181 ts = ts.Link 182 } 183 184 for ts != fs { 185 if ts.Pkg == nil { 186 block = ts 187 } else { 188 dcl = ts 189 } 190 ts = ts.Link 191 fs = fs.Link 192 } 193 194 if block != nil { 195 Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno))) 196 } else { 197 Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno))) 198 } 199 lineno = int32(lno) 200 } 201 } 202 203 func stmtlabel(n *Node) *Label { 204 if n.Sym != nil { 205 lab := n.Sym.Label 206 if lab != nil { 207 if lab.Def != nil { 208 if lab.Def.Name.Defn == n { 209 return lab 210 } 211 } 212 } 213 } 214 return nil 215 } 216 217 /* 218 * compile statements 219 */ 220 func Genlist(l *NodeList) { 221 for ; l != nil; l = l.Next { 222 gen(l.N) 223 } 224 } 225 226 /* 227 * generate code to start new proc running call n. 228 */ 229 func cgen_proc(n *Node, proc int) { 230 switch n.Left.Op { 231 default: 232 Fatal("cgen_proc: unknown call %v", Oconv(int(n.Left.Op), 0)) 233 234 case OCALLMETH: 235 cgen_callmeth(n.Left, proc) 236 237 case OCALLINTER: 238 cgen_callinter(n.Left, nil, proc) 239 240 case OCALLFUNC: 241 cgen_call(n.Left, proc) 242 } 243 } 244 245 /* 246 * generate declaration. 247 * have to allocate heap copy 248 * for escaped variables. 249 */ 250 func cgen_dcl(n *Node) { 251 if Debug['g'] != 0 { 252 Dump("\ncgen-dcl", n) 253 } 254 if n.Op != ONAME { 255 Dump("cgen_dcl", n) 256 Fatal("cgen_dcl") 257 } 258 259 if n.Class&PHEAP == 0 { 260 return 261 } 262 if compiling_runtime != 0 { 263 Yyerror("%v escapes to heap, not allowed in runtime.", n) 264 } 265 if prealloc[n] == nil { 266 prealloc[n] = callnew(n.Type) 267 } 268 Cgen_as(n.Name.Heapaddr, prealloc[n]) 269 } 270 271 /* 272 * generate discard of value 273 */ 274 func cgen_discard(nr *Node) { 275 if nr == nil { 276 return 277 } 278 279 switch nr.Op { 280 case ONAME: 281 if nr.Class&PHEAP == 0 && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF { 282 gused(nr) 283 } 284 285 // unary 286 case OADD, 287 OAND, 288 ODIV, 289 OEQ, 290 OGE, 291 OGT, 292 OLE, 293 OLSH, 294 OLT, 295 OMOD, 296 OMUL, 297 ONE, 298 OOR, 299 ORSH, 300 OSUB, 301 OXOR: 302 cgen_discard(nr.Left) 303 304 cgen_discard(nr.Right) 305 306 // binary 307 case OCAP, 308 OCOM, 309 OLEN, 310 OMINUS, 311 ONOT, 312 OPLUS: 313 cgen_discard(nr.Left) 314 315 case OIND: 316 Cgen_checknil(nr.Left) 317 318 // special enough to just evaluate 319 default: 320 var tmp Node 321 Tempname(&tmp, nr.Type) 322 323 Cgen_as(&tmp, nr) 324 gused(&tmp) 325 } 326 } 327 328 /* 329 * clearslim generates code to zero a slim node. 330 */ 331 func Clearslim(n *Node) { 332 var z Node 333 z.Op = OLITERAL 334 z.Type = n.Type 335 z.Addable = true 336 337 switch Simtype[n.Type.Etype] { 338 case TCOMPLEX64, TCOMPLEX128: 339 z.SetVal(Val{new(Mpcplx)}) 340 Mpmovecflt(&z.Val().U.(*Mpcplx).Real, 0.0) 341 Mpmovecflt(&z.Val().U.(*Mpcplx).Imag, 0.0) 342 343 case TFLOAT32, TFLOAT64: 344 var zero Mpflt 345 Mpmovecflt(&zero, 0.0) 346 z.SetVal(Val{&zero}) 347 348 case TPTR32, TPTR64, TCHAN, TMAP: 349 z.SetVal(Val{new(NilVal)}) 350 351 case TBOOL: 352 z.SetVal(Val{false}) 353 354 case TINT8, 355 TINT16, 356 TINT32, 357 TINT64, 358 TUINT8, 359 TUINT16, 360 TUINT32, 361 TUINT64: 362 z.SetVal(Val{new(Mpint)}) 363 Mpmovecfix(z.Val().U.(*Mpint), 0) 364 365 default: 366 Fatal("clearslim called on type %v", n.Type) 367 } 368 369 ullmancalc(&z) 370 Cgen(&z, n) 371 } 372 373 /* 374 * generate: 375 * res = iface{typ, data} 376 * n->left is typ 377 * n->right is data 378 */ 379 func Cgen_eface(n *Node, res *Node) { 380 /* 381 * the right node of an eface may contain function calls that uses res as an argument, 382 * so it's important that it is done first 383 */ 384 385 tmp := temp(Types[Tptr]) 386 Cgen(n.Right, tmp) 387 388 Gvardef(res) 389 390 dst := *res 391 dst.Type = Types[Tptr] 392 dst.Xoffset += int64(Widthptr) 393 Cgen(tmp, &dst) 394 395 dst.Xoffset -= int64(Widthptr) 396 Cgen(n.Left, &dst) 397 } 398 399 /* 400 * generate one of: 401 * res, resok = x.(T) 402 * res = x.(T) (when resok == nil) 403 * n.Left is x 404 * n.Type is T 405 */ 406 func cgen_dottype(n *Node, res, resok *Node, wb bool) { 407 if Debug_typeassert > 0 { 408 Warn("type assertion inlined") 409 } 410 // iface := n.Left 411 // r1 := iword(iface) 412 // if n.Left is non-empty interface { 413 // r1 = *r1 414 // } 415 // if r1 == T { 416 // res = idata(iface) 417 // resok = true 418 // } else { 419 // assert[EI]2T(x, T, nil) // (when resok == nil; does not return) 420 // resok = false // (when resok != nil) 421 // } 422 // 423 var iface Node 424 Igen(n.Left, &iface, res) 425 var r1, r2 Node 426 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte) 427 Regalloc(&r1, byteptr, nil) 428 iface.Type = byteptr 429 Cgen(&iface, &r1) 430 if !isnilinter(n.Left.Type) { 431 // Holding itab, want concrete type in second word. 432 p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1) 433 r2 = r1 434 r2.Op = OINDREG 435 r2.Xoffset = int64(Widthptr) 436 Cgen(&r2, &r1) 437 Patch(p, Pc) 438 } 439 Regalloc(&r2, byteptr, nil) 440 Cgen(typename(n.Type), &r2) 441 p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1) 442 Regfree(&r2) // not needed for success path; reclaimed on one failure path 443 iface.Xoffset += int64(Widthptr) 444 Cgen(&iface, &r1) 445 Regfree(&iface) 446 447 if resok == nil { 448 r1.Type = res.Type 449 cgen_wb(&r1, res, wb) 450 q := Gbranch(obj.AJMP, nil, 0) 451 Patch(p, Pc) 452 Regrealloc(&r2) // reclaim from above, for this failure path 453 fn := syslook("panicdottype", 0) 454 dowidth(fn.Type) 455 call := Nod(OCALLFUNC, fn, nil) 456 r1.Type = byteptr 457 r2.Type = byteptr 458 call.List = list(list(list1(&r1), &r2), typename(n.Left.Type)) 459 call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil) 460 gen(call) 461 Regfree(&r1) 462 Regfree(&r2) 463 Thearch.Gins(obj.AUNDEF, nil, nil) 464 Patch(q, Pc) 465 } else { 466 // This half is handling the res, resok = x.(T) case, 467 // which is called from gen, not cgen, and is consequently fussier 468 // about blank assignments. We have to avoid calling cgen for those. 469 r1.Type = res.Type 470 if !isblank(res) { 471 cgen_wb(&r1, res, wb) 472 } 473 Regfree(&r1) 474 if !isblank(resok) { 475 Cgen(Nodbool(true), resok) 476 } 477 q := Gbranch(obj.AJMP, nil, 0) 478 Patch(p, Pc) 479 if !isblank(res) { 480 n := nodnil() 481 n.Type = res.Type 482 Cgen(n, res) 483 } 484 if !isblank(resok) { 485 Cgen(Nodbool(false), resok) 486 } 487 Patch(q, Pc) 488 } 489 } 490 491 /* 492 * generate: 493 * res, resok = x.(T) 494 * n.Left is x 495 * n.Type is T 496 */ 497 func Cgen_As2dottype(n, res, resok *Node) { 498 if Debug_typeassert > 0 { 499 Warn("type assertion inlined") 500 } 501 // iface := n.Left 502 // r1 := iword(iface) 503 // if n.Left is non-empty interface { 504 // r1 = *r1 505 // } 506 // if r1 == T { 507 // res = idata(iface) 508 // resok = true 509 // } else { 510 // res = nil 511 // resok = false 512 // } 513 // 514 var iface Node 515 Igen(n.Left, &iface, nil) 516 var r1, r2 Node 517 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte) 518 Regalloc(&r1, byteptr, res) 519 iface.Type = byteptr 520 Cgen(&iface, &r1) 521 if !isnilinter(n.Left.Type) { 522 // Holding itab, want concrete type in second word. 523 p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1) 524 r2 = r1 525 r2.Op = OINDREG 526 r2.Xoffset = int64(Widthptr) 527 Cgen(&r2, &r1) 528 Patch(p, Pc) 529 } 530 Regalloc(&r2, byteptr, nil) 531 Cgen(typename(n.Type), &r2) 532 p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1) 533 iface.Type = n.Type 534 iface.Xoffset += int64(Widthptr) 535 Cgen(&iface, &r1) 536 if iface.Op != 0 { 537 Regfree(&iface) 538 } 539 Cgen(&r1, res) 540 q := Gbranch(obj.AJMP, nil, 0) 541 Patch(p, Pc) 542 543 fn := syslook("panicdottype", 0) 544 dowidth(fn.Type) 545 call := Nod(OCALLFUNC, fn, nil) 546 call.List = list(list(list1(&r1), &r2), typename(n.Left.Type)) 547 call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil) 548 gen(call) 549 Regfree(&r1) 550 Regfree(&r2) 551 Thearch.Gins(obj.AUNDEF, nil, nil) 552 Patch(q, Pc) 553 } 554 555 /* 556 * gather series of offsets 557 * >=0 is direct addressed field 558 * <0 is pointer to next field (+1) 559 */ 560 func Dotoffset(n *Node, oary []int64, nn **Node) int { 561 var i int 562 563 switch n.Op { 564 case ODOT: 565 if n.Xoffset == BADWIDTH { 566 Dump("bad width in dotoffset", n) 567 Fatal("bad width in dotoffset") 568 } 569 570 i = Dotoffset(n.Left, oary, nn) 571 if i > 0 { 572 if oary[i-1] >= 0 { 573 oary[i-1] += n.Xoffset 574 } else { 575 oary[i-1] -= n.Xoffset 576 } 577 break 578 } 579 580 if i < 10 { 581 oary[i] = n.Xoffset 582 i++ 583 } 584 585 case ODOTPTR: 586 if n.Xoffset == BADWIDTH { 587 Dump("bad width in dotoffset", n) 588 Fatal("bad width in dotoffset") 589 } 590 591 i = Dotoffset(n.Left, oary, nn) 592 if i < 10 { 593 oary[i] = -(n.Xoffset + 1) 594 i++ 595 } 596 597 default: 598 *nn = n 599 return 0 600 } 601 602 if i >= 10 { 603 *nn = nil 604 } 605 return i 606 } 607 608 /* 609 * make a new off the books 610 */ 611 func Tempname(nn *Node, t *Type) { 612 if Curfn == nil { 613 Fatal("no curfn for tempname") 614 } 615 616 if t == nil { 617 Yyerror("tempname called with nil type") 618 t = Types[TINT32] 619 } 620 621 // give each tmp a different name so that there 622 // a chance to registerizer them 623 s := Lookupf("autotmp_%.4d", statuniqgen) 624 statuniqgen++ 625 n := Nod(ONAME, nil, nil) 626 n.Sym = s 627 s.Def = n 628 n.Type = t 629 n.Class = PAUTO 630 n.Addable = true 631 n.Ullman = 1 632 n.Esc = EscNever 633 n.Name.Curfn = Curfn 634 Curfn.Func.Dcl = list(Curfn.Func.Dcl, n) 635 636 dowidth(t) 637 n.Xoffset = 0 638 *nn = *n 639 } 640 641 func temp(t *Type) *Node { 642 n := Nod(OXXX, nil, nil) 643 Tempname(n, t) 644 n.Sym.Def.Used = true 645 return n.Orig 646 } 647 648 func gen(n *Node) { 649 //dump("gen", n); 650 651 lno := setlineno(n) 652 653 wasregalloc := Anyregalloc() 654 655 if n == nil { 656 goto ret 657 } 658 659 if n.Ninit != nil { 660 Genlist(n.Ninit) 661 } 662 663 setlineno(n) 664 665 switch n.Op { 666 default: 667 Fatal("gen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 668 669 case OCASE, 670 OFALL, 671 OXCASE, 672 OXFALL, 673 ODCLCONST, 674 ODCLFUNC, 675 ODCLTYPE: 676 break 677 678 case OEMPTY: 679 break 680 681 case OBLOCK: 682 Genlist(n.List) 683 684 case OLABEL: 685 if isblanksym(n.Left.Sym) { 686 break 687 } 688 689 lab := newlab(n) 690 691 // if there are pending gotos, resolve them all to the current pc. 692 var p2 *obj.Prog 693 for p1 := lab.Gotopc; p1 != nil; p1 = p2 { 694 p2 = unpatch(p1) 695 Patch(p1, Pc) 696 } 697 698 lab.Gotopc = nil 699 if lab.Labelpc == nil { 700 lab.Labelpc = Pc 701 } 702 703 if n.Name.Defn != nil { 704 switch n.Name.Defn.Op { 705 // so stmtlabel can find the label 706 case OFOR, OSWITCH, OSELECT: 707 n.Name.Defn.Sym = lab.Sym 708 } 709 } 710 711 // if label is defined, emit jump to it. 712 // otherwise save list of pending gotos in lab->gotopc. 713 // the list is linked through the normal jump target field 714 // to avoid a second list. (the jumps are actually still 715 // valid code, since they're just going to another goto 716 // to the same label. we'll unwind it when we learn the pc 717 // of the label in the OLABEL case above.) 718 case OGOTO: 719 lab := newlab(n) 720 721 if lab.Labelpc != nil { 722 gjmp(lab.Labelpc) 723 } else { 724 lab.Gotopc = gjmp(lab.Gotopc) 725 } 726 727 case OBREAK: 728 if n.Left != nil { 729 lab := n.Left.Sym.Label 730 if lab == nil { 731 Yyerror("break label not defined: %v", n.Left.Sym) 732 break 733 } 734 735 lab.Used = 1 736 if lab.Breakpc == nil { 737 Yyerror("invalid break label %v", n.Left.Sym) 738 break 739 } 740 741 gjmp(lab.Breakpc) 742 break 743 } 744 745 if breakpc == nil { 746 Yyerror("break is not in a loop") 747 break 748 } 749 750 gjmp(breakpc) 751 752 case OCONTINUE: 753 if n.Left != nil { 754 lab := n.Left.Sym.Label 755 if lab == nil { 756 Yyerror("continue label not defined: %v", n.Left.Sym) 757 break 758 } 759 760 lab.Used = 1 761 if lab.Continpc == nil { 762 Yyerror("invalid continue label %v", n.Left.Sym) 763 break 764 } 765 766 gjmp(lab.Continpc) 767 break 768 } 769 770 if continpc == nil { 771 Yyerror("continue is not in a loop") 772 break 773 } 774 775 gjmp(continpc) 776 777 case OFOR: 778 sbreak := breakpc 779 p1 := gjmp(nil) // goto test 780 breakpc = gjmp(nil) // break: goto done 781 scontin := continpc 782 continpc = Pc 783 784 // define break and continue labels 785 lab := stmtlabel(n) 786 if lab != nil { 787 lab.Breakpc = breakpc 788 lab.Continpc = continpc 789 } 790 791 gen(n.Right) // contin: incr 792 Patch(p1, Pc) // test: 793 Bgen(n.Left, false, -1, breakpc) // if(!test) goto break 794 Genlist(n.Nbody) // body 795 gjmp(continpc) 796 Patch(breakpc, Pc) // done: 797 continpc = scontin 798 breakpc = sbreak 799 if lab != nil { 800 lab.Breakpc = nil 801 lab.Continpc = nil 802 } 803 804 case OIF: 805 p1 := gjmp(nil) // goto test 806 p2 := gjmp(nil) // p2: goto else 807 Patch(p1, Pc) // test: 808 Bgen(n.Left, false, int(-n.Likely), p2) // if(!test) goto p2 809 Genlist(n.Nbody) // then 810 p3 := gjmp(nil) // goto done 811 Patch(p2, Pc) // else: 812 Genlist(n.Rlist) // else 813 Patch(p3, Pc) // done: 814 815 case OSWITCH: 816 sbreak := breakpc 817 p1 := gjmp(nil) // goto test 818 breakpc = gjmp(nil) // break: goto done 819 820 // define break label 821 lab := stmtlabel(n) 822 if lab != nil { 823 lab.Breakpc = breakpc 824 } 825 826 Patch(p1, Pc) // test: 827 Genlist(n.Nbody) // switch(test) body 828 Patch(breakpc, Pc) // done: 829 breakpc = sbreak 830 if lab != nil { 831 lab.Breakpc = nil 832 } 833 834 case OSELECT: 835 sbreak := breakpc 836 p1 := gjmp(nil) // goto test 837 breakpc = gjmp(nil) // break: goto done 838 839 // define break label 840 lab := stmtlabel(n) 841 if lab != nil { 842 lab.Breakpc = breakpc 843 } 844 845 Patch(p1, Pc) // test: 846 Genlist(n.Nbody) // select() body 847 Patch(breakpc, Pc) // done: 848 breakpc = sbreak 849 if lab != nil { 850 lab.Breakpc = nil 851 } 852 853 case ODCL: 854 cgen_dcl(n.Left) 855 856 case OAS: 857 if gen_as_init(n) { 858 break 859 } 860 Cgen_as(n.Left, n.Right) 861 862 case OASWB: 863 Cgen_as_wb(n.Left, n.Right, true) 864 865 case OAS2DOTTYPE: 866 cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false) 867 868 case OCALLMETH: 869 cgen_callmeth(n, 0) 870 871 case OCALLINTER: 872 cgen_callinter(n, nil, 0) 873 874 case OCALLFUNC: 875 cgen_call(n, 0) 876 877 case OPROC: 878 cgen_proc(n, 1) 879 880 case ODEFER: 881 cgen_proc(n, 2) 882 883 case ORETURN, ORETJMP: 884 cgen_ret(n) 885 886 // Function calls turned into compiler intrinsics. 887 // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any. 888 case OGETG: 889 // nothing 890 case OSQRT: 891 cgen_discard(n.Left) 892 893 case OCHECKNIL: 894 Cgen_checknil(n.Left) 895 896 case OVARKILL: 897 gvarkill(n.Left) 898 } 899 900 ret: 901 if Anyregalloc() != wasregalloc { 902 Dump("node", n) 903 Fatal("registers left allocated") 904 } 905 906 lineno = lno 907 } 908 909 func Cgen_as(nl, nr *Node) { 910 Cgen_as_wb(nl, nr, false) 911 } 912 913 func Cgen_as_wb(nl, nr *Node, wb bool) { 914 if Debug['g'] != 0 { 915 op := "cgen_as" 916 if wb { 917 op = "cgen_as_wb" 918 } 919 Dump(op, nl) 920 Dump(op+" = ", nr) 921 } 922 923 for nr != nil && nr.Op == OCONVNOP { 924 nr = nr.Left 925 } 926 927 if nl == nil || isblank(nl) { 928 cgen_discard(nr) 929 return 930 } 931 932 if nr == nil || iszero(nr) { 933 // heaps should already be clear 934 if nr == nil && (nl.Class&PHEAP != 0) { 935 return 936 } 937 938 tl := nl.Type 939 if tl == nil { 940 return 941 } 942 if Isfat(tl) { 943 if nl.Op == ONAME { 944 Gvardef(nl) 945 } 946 Thearch.Clearfat(nl) 947 return 948 } 949 950 Clearslim(nl) 951 return 952 } 953 954 tl := nl.Type 955 if tl == nil { 956 return 957 } 958 959 cgen_wb(nr, nl, wb) 960 } 961 962 func cgen_callmeth(n *Node, proc int) { 963 // generate a rewrite in n2 for the method call 964 // (p.f)(...) goes to (f)(p,...) 965 966 l := n.Left 967 968 if l.Op != ODOTMETH { 969 Fatal("cgen_callmeth: not dotmethod: %v", l) 970 } 971 972 n2 := *n 973 n2.Op = OCALLFUNC 974 n2.Left = l.Right 975 n2.Left.Type = l.Type 976 977 if n2.Left.Op == ONAME { 978 n2.Left.Class = PFUNC 979 } 980 cgen_call(&n2, proc) 981 } 982 983 // CgenTemp creates a temporary node, assigns n to it, and returns it. 984 func CgenTemp(n *Node) *Node { 985 var tmp Node 986 Tempname(&tmp, n.Type) 987 Cgen(n, &tmp) 988 return &tmp 989 } 990 991 func checklabels() { 992 var l *NodeList 993 994 for lab := labellist; lab != nil; lab = lab.Link { 995 if lab.Def == nil { 996 for l = lab.Use; l != nil; l = l.Next { 997 yyerrorl(int(l.N.Lineno), "label %v not defined", lab.Sym) 998 } 999 continue 1000 } 1001 1002 if lab.Use == nil && lab.Used == 0 { 1003 yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym) 1004 continue 1005 } 1006 1007 if lab.Gotopc != nil { 1008 Fatal("label %v never resolved", lab.Sym) 1009 } 1010 for l = lab.Use; l != nil; l = l.Next { 1011 checkgoto(l.N, lab.Def) 1012 } 1013 } 1014 } 1015 1016 // Componentgen copies a composite value by moving its individual components. 1017 // Slices, strings and interfaces are supported. Small structs or arrays with 1018 // elements of basic type are also supported. 1019 // nr is nil when assigning a zero value. 1020 func Componentgen(nr, nl *Node) bool { 1021 return componentgen_wb(nr, nl, false) 1022 } 1023 1024 // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates. 1025 func componentgen_wb(nr, nl *Node, wb bool) bool { 1026 // Don't generate any code for complete copy of a variable into itself. 1027 // It's useless, and the VARDEF will incorrectly mark the old value as dead. 1028 // (This check assumes that the arguments passed to componentgen did not 1029 // themselves come from Igen, or else we could have Op==ONAME but 1030 // with a Type and Xoffset describing an individual field, not the entire 1031 // variable.) 1032 if nl.Op == ONAME && nl == nr { 1033 return true 1034 } 1035 1036 // Count number of moves required to move components. 1037 // If using write barrier, can only emit one pointer. 1038 // TODO(rsc): Allow more pointers, for reflect.Value. 1039 const maxMoves = 8 1040 n := 0 1041 numPtr := 0 1042 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1043 n++ 1044 if int(Simtype[t.Etype]) == Tptr && t != itable { 1045 numPtr++ 1046 } 1047 return n <= maxMoves && (!wb || numPtr <= 1) 1048 }) 1049 if n > maxMoves || wb && numPtr > 1 { 1050 return false 1051 } 1052 1053 // Must call emitVardef after evaluating rhs but before writing to lhs. 1054 emitVardef := func() { 1055 // Emit vardef if needed. 1056 if nl.Op == ONAME { 1057 switch nl.Type.Etype { 1058 case TARRAY, TSTRING, TINTER, TSTRUCT: 1059 Gvardef(nl) 1060 } 1061 } 1062 } 1063 1064 isConstString := Isconst(nr, CTSTR) 1065 1066 if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString { 1067 return false 1068 } 1069 1070 var nodl Node 1071 if cadable(nl) { 1072 nodl = *nl 1073 } else { 1074 if nr != nil && !cadable(nr) && !isConstString { 1075 return false 1076 } 1077 if nr == nil || isConstString || nl.Ullman >= nr.Ullman { 1078 Igen(nl, &nodl, nil) 1079 defer Regfree(&nodl) 1080 } 1081 } 1082 lbase := nodl.Xoffset 1083 1084 // Special case: zeroing. 1085 var nodr Node 1086 if nr == nil { 1087 // When zeroing, prepare a register containing zero. 1088 // TODO(rsc): Check that this is actually generating the best code. 1089 if Thearch.REGZERO != 0 { 1090 // cpu has a dedicated zero register 1091 Nodreg(&nodr, Types[TUINT], Thearch.REGZERO) 1092 } else { 1093 // no dedicated zero register 1094 var zero Node 1095 Nodconst(&zero, nl.Type, 0) 1096 Regalloc(&nodr, Types[TUINT], nil) 1097 Thearch.Gmove(&zero, &nodr) 1098 defer Regfree(&nodr) 1099 } 1100 1101 emitVardef() 1102 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1103 nodl.Type = t 1104 nodl.Xoffset = lbase + offset 1105 nodr.Type = t 1106 if Isfloat[t.Etype] { 1107 // TODO(rsc): Cache zero register like we do for integers? 1108 Clearslim(&nodl) 1109 } else { 1110 Thearch.Gmove(&nodr, &nodl) 1111 } 1112 return true 1113 }) 1114 return true 1115 } 1116 1117 // Special case: assignment of string constant. 1118 if isConstString { 1119 emitVardef() 1120 1121 // base 1122 nodl.Type = Ptrto(Types[TUINT8]) 1123 Regalloc(&nodr, Types[Tptr], nil) 1124 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) 1125 Datastring(nr.Val().U.(string), &p.From) 1126 p.From.Type = obj.TYPE_ADDR 1127 Thearch.Gmove(&nodr, &nodl) 1128 Regfree(&nodr) 1129 1130 // length 1131 nodl.Type = Types[Simtype[TUINT]] 1132 nodl.Xoffset += int64(Array_nel) - int64(Array_array) 1133 Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string)))) 1134 Thearch.Gmove(&nodr, &nodl) 1135 return true 1136 } 1137 1138 // General case: copy nl = nr. 1139 nodr = *nr 1140 if !cadable(nr) { 1141 if nr.Ullman >= UINF && nodl.Op == OINDREG { 1142 Fatal("miscompile") 1143 } 1144 Igen(nr, &nodr, nil) 1145 defer Regfree(&nodr) 1146 } 1147 rbase := nodr.Xoffset 1148 1149 if nodl.Op == 0 { 1150 Igen(nl, &nodl, nil) 1151 defer Regfree(&nodl) 1152 lbase = nodl.Xoffset 1153 } 1154 1155 emitVardef() 1156 var ( 1157 ptrType *Type 1158 ptrOffset int64 1159 ) 1160 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1161 if wb && int(Simtype[t.Etype]) == Tptr && t != itable { 1162 if ptrType != nil { 1163 Fatal("componentgen_wb %v", Tconv(nl.Type, 0)) 1164 } 1165 ptrType = t 1166 ptrOffset = offset 1167 return true 1168 } 1169 nodl.Type = t 1170 nodl.Xoffset = lbase + offset 1171 nodr.Type = t 1172 nodr.Xoffset = rbase + offset 1173 Thearch.Gmove(&nodr, &nodl) 1174 return true 1175 }) 1176 if ptrType != nil { 1177 nodl.Type = ptrType 1178 nodl.Xoffset = lbase + ptrOffset 1179 nodr.Type = ptrType 1180 nodr.Xoffset = rbase + ptrOffset 1181 cgen_wbptr(&nodr, &nodl) 1182 } 1183 return true 1184 } 1185 1186 // visitComponents walks the individual components of the type t, 1187 // walking into array elements, struct fields, the real and imaginary 1188 // parts of complex numbers, and on 32-bit systems the high and 1189 // low halves of 64-bit integers. 1190 // It calls f for each such component, passing the component (aka element) 1191 // type and memory offset, assuming t starts at startOffset. 1192 // If f ever returns false, visitComponents returns false without any more 1193 // calls to f. Otherwise visitComponents returns true. 1194 func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool { 1195 switch t.Etype { 1196 case TINT64: 1197 if Widthreg == 8 { 1198 break 1199 } 1200 // NOTE: Assuming little endian (signed top half at offset 4). 1201 // We don't have any 32-bit big-endian systems. 1202 if Thearch.Thechar != '5' && Thearch.Thechar != '8' { 1203 Fatal("unknown 32-bit architecture") 1204 } 1205 return f(Types[TUINT32], startOffset) && 1206 f(Types[TINT32], startOffset+4) 1207 1208 case TUINT64: 1209 if Widthreg == 8 { 1210 break 1211 } 1212 return f(Types[TUINT32], startOffset) && 1213 f(Types[TUINT32], startOffset+4) 1214 1215 case TCOMPLEX64: 1216 return f(Types[TFLOAT32], startOffset) && 1217 f(Types[TFLOAT32], startOffset+4) 1218 1219 case TCOMPLEX128: 1220 return f(Types[TFLOAT64], startOffset) && 1221 f(Types[TFLOAT64], startOffset+8) 1222 1223 case TINTER: 1224 return f(itable, startOffset) && 1225 f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr)) 1226 return true 1227 1228 case TSTRING: 1229 return f(Ptrto(Types[TUINT8]), startOffset) && 1230 f(Types[Simtype[TUINT]], startOffset+int64(Widthptr)) 1231 1232 case TARRAY: 1233 if Isslice(t) { 1234 return f(Ptrto(t.Type), startOffset+int64(Array_array)) && 1235 f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) && 1236 f(Types[Simtype[TUINT]], startOffset+int64(Array_cap)) 1237 } 1238 1239 // Short-circuit [1e6]struct{}. 1240 if t.Type.Width == 0 { 1241 return true 1242 } 1243 1244 for i := int64(0); i < t.Bound; i++ { 1245 if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) { 1246 return false 1247 } 1248 } 1249 return true 1250 1251 case TSTRUCT: 1252 if t.Type != nil && t.Type.Width != 0 { 1253 // NOTE(rsc): If this happens, the right thing to do is to say 1254 // startOffset -= t.Type.Width 1255 // but I want to see if it does. 1256 // The old version of componentgen handled this, 1257 // in code introduced in CL 6932045 to fix issue #4518. 1258 // But the test case in issue 4518 does not trigger this anymore, 1259 // so maybe this complication is no longer needed. 1260 Fatal("struct not at offset 0") 1261 } 1262 1263 for field := t.Type; field != nil; field = field.Down { 1264 if field.Etype != TFIELD { 1265 Fatal("bad struct") 1266 } 1267 if !visitComponents(field.Type, startOffset+field.Width, f) { 1268 return false 1269 } 1270 } 1271 return true 1272 } 1273 return f(t, startOffset) 1274 } 1275 1276 func cadable(n *Node) bool { 1277 // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can. 1278 return n.Addable && n.Op == ONAME 1279 } 1280