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