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