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