github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/gen.go (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/gen.go 2 3 // Copyright 2009 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package gc 8 9 import ( 10 "rsc.io/tmp/bootstrap/internal/obj" 11 "fmt" 12 ) 13 14 /* 15 * portable half of code generator. 16 * mainly statements and control flow. 17 */ 18 var labellist *Label 19 20 var lastlabel *Label 21 22 func Sysfunc(name string) *Node { 23 n := newname(Pkglookup(name, Runtimepkg)) 24 n.Class = PFUNC 25 return n 26 } 27 28 /* 29 * the address of n has been taken and might be used after 30 * the current function returns. mark any local vars 31 * as needing to move to the heap. 32 */ 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.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.Stackparam = Nod(OPARAM, n, nil) 64 65 n.Stackparam.Type = n.Type 66 n.Stackparam.Addable = true 67 if n.Xoffset == BADWIDTH { 68 Fatal("addrescapes before param assignment") 69 } 70 n.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.Curfn 84 n.Heapaddr = temp(Ptrto(n.Type)) 85 buf := fmt.Sprintf("&%v", n.Sym) 86 n.Heapaddr.Sym = Lookup(buf) 87 n.Heapaddr.Orig.Sym = n.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: 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.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 n.Alloc == nil { 266 n.Alloc = callnew(n.Type) 267 } 268 Cgen_as(n.Heapaddr, n.Alloc) 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.Val.U.Cval = new(Mpcplx) 340 Mpmovecflt(&z.Val.U.Cval.Real, 0.0) 341 Mpmovecflt(&z.Val.U.Cval.Imag, 0.0) 342 343 case TFLOAT32, TFLOAT64: 344 var zero Mpflt 345 Mpmovecflt(&zero, 0.0) 346 z.Val.Ctype = CTFLT 347 z.Val.U.Fval = &zero 348 349 case TPTR32, TPTR64, TCHAN, TMAP: 350 z.Val.Ctype = CTNIL 351 352 case TBOOL: 353 z.Val.Ctype = CTBOOL 354 355 case TINT8, 356 TINT16, 357 TINT32, 358 TINT64, 359 TUINT8, 360 TUINT16, 361 TUINT32, 362 TUINT64: 363 z.Val.Ctype = CTINT 364 z.Val.U.Xval = new(Mpint) 365 Mpmovecfix(z.Val.U.Xval, 0) 366 367 default: 368 Fatal("clearslim called on type %v", n.Type) 369 } 370 371 ullmancalc(&z) 372 Cgen(&z, n) 373 } 374 375 /* 376 * generate: 377 * res = iface{typ, data} 378 * n->left is typ 379 * n->right is data 380 */ 381 func Cgen_eface(n *Node, res *Node) { 382 /* 383 * the right node of an eface may contain function calls that uses res as an argument, 384 * so it's important that it is done first 385 */ 386 387 tmp := temp(Types[Tptr]) 388 Cgen(n.Right, tmp) 389 390 Gvardef(res) 391 392 dst := *res 393 dst.Type = Types[Tptr] 394 dst.Xoffset += int64(Widthptr) 395 Cgen(tmp, &dst) 396 397 dst.Xoffset -= int64(Widthptr) 398 Cgen(n.Left, &dst) 399 } 400 401 /* 402 * generate one of: 403 * res, resok = x.(T) 404 * res = x.(T) (when resok == nil) 405 * n.Left is x 406 * n.Type is T 407 */ 408 func cgen_dottype(n *Node, res, resok *Node, wb bool) { 409 if Debug_typeassert > 0 { 410 Warn("type assertion inlined") 411 } 412 // iface := n.Left 413 // r1 := iword(iface) 414 // if n.Left is non-empty interface { 415 // r1 = *r1 416 // } 417 // if r1 == T { 418 // res = idata(iface) 419 // resok = true 420 // } else { 421 // assert[EI]2T(x, T, nil) // (when resok == nil; does not return) 422 // resok = false // (when resok != nil) 423 // } 424 // 425 var iface Node 426 Igen(n.Left, &iface, res) 427 var r1, r2 Node 428 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte) 429 Regalloc(&r1, byteptr, nil) 430 iface.Type = byteptr 431 Cgen(&iface, &r1) 432 if !isnilinter(n.Left.Type) { 433 // Holding itab, want concrete type in second word. 434 Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0)) 435 p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1) 436 r2 = r1 437 r2.Op = OINDREG 438 r2.Xoffset = int64(Widthptr) 439 Cgen(&r2, &r1) 440 Patch(p, Pc) 441 } 442 Regalloc(&r2, byteptr, nil) 443 Cgen(typename(n.Type), &r2) 444 Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2) 445 p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1) 446 Regfree(&r2) // not needed for success path; reclaimed on one failure path 447 iface.Xoffset += int64(Widthptr) 448 Cgen(&iface, &r1) 449 Regfree(&iface) 450 451 if resok == nil { 452 r1.Type = res.Type 453 cgen_wb(&r1, res, wb) 454 q := Gbranch(obj.AJMP, nil, 0) 455 Patch(p, Pc) 456 Regrealloc(&r2) // reclaim from above, for this failure path 457 fn := syslook("panicdottype", 0) 458 dowidth(fn.Type) 459 call := Nod(OCALLFUNC, fn, nil) 460 r1.Type = byteptr 461 r2.Type = byteptr 462 call.List = list(list(list1(&r1), &r2), typename(n.Left.Type)) 463 call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil) 464 gen(call) 465 Regfree(&r1) 466 Regfree(&r2) 467 Thearch.Gins(obj.AUNDEF, nil, nil) 468 Patch(q, Pc) 469 } else { 470 // This half is handling the res, resok = x.(T) case, 471 // which is called from gen, not cgen, and is consequently fussier 472 // about blank assignments. We have to avoid calling cgen for those. 473 r1.Type = res.Type 474 if !isblank(res) { 475 cgen_wb(&r1, res, wb) 476 } 477 Regfree(&r1) 478 if !isblank(resok) { 479 Cgen(Nodbool(true), resok) 480 } 481 q := Gbranch(obj.AJMP, nil, 0) 482 Patch(p, Pc) 483 if !isblank(res) { 484 n := nodnil() 485 n.Type = res.Type 486 Cgen(n, res) 487 } 488 if !isblank(resok) { 489 Cgen(Nodbool(false), resok) 490 } 491 Patch(q, Pc) 492 } 493 } 494 495 /* 496 * generate: 497 * res, resok = x.(T) 498 * n.Left is x 499 * n.Type is T 500 */ 501 func Cgen_As2dottype(n, res, resok *Node) { 502 if Debug_typeassert > 0 { 503 Warn("type assertion inlined") 504 } 505 // iface := n.Left 506 // r1 := iword(iface) 507 // if n.Left is non-empty interface { 508 // r1 = *r1 509 // } 510 // if r1 == T { 511 // res = idata(iface) 512 // resok = true 513 // } else { 514 // res = nil 515 // resok = false 516 // } 517 // 518 var iface Node 519 Igen(n.Left, &iface, nil) 520 var r1, r2 Node 521 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte) 522 Regalloc(&r1, byteptr, res) 523 iface.Type = byteptr 524 Cgen(&iface, &r1) 525 if !isnilinter(n.Left.Type) { 526 // Holding itab, want concrete type in second word. 527 Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0)) 528 p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1) 529 r2 = r1 530 r2.Op = OINDREG 531 r2.Xoffset = int64(Widthptr) 532 Cgen(&r2, &r1) 533 Patch(p, Pc) 534 } 535 Regalloc(&r2, byteptr, nil) 536 Cgen(typename(n.Type), &r2) 537 Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2) 538 p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1) 539 iface.Type = n.Type 540 iface.Xoffset += int64(Widthptr) 541 Cgen(&iface, &r1) 542 if iface.Op != 0 { 543 Regfree(&iface) 544 } 545 Cgen(&r1, res) 546 q := Gbranch(obj.AJMP, nil, 0) 547 Patch(p, Pc) 548 549 fn := syslook("panicdottype", 0) 550 dowidth(fn.Type) 551 call := Nod(OCALLFUNC, fn, nil) 552 call.List = list(list(list1(&r1), &r2), typename(n.Left.Type)) 553 call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil) 554 gen(call) 555 Regfree(&r1) 556 Regfree(&r2) 557 Thearch.Gins(obj.AUNDEF, nil, nil) 558 Patch(q, Pc) 559 } 560 561 /* 562 * generate: 563 * res = s[lo, hi]; 564 * n->left is s 565 * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) 566 * caller (cgen) guarantees res is an addable ONAME. 567 * 568 * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. 569 */ 570 func Cgen_slice(n *Node, res *Node) { 571 cap := n.List.N 572 len := n.List.Next.N 573 var offs *Node 574 if n.List.Next.Next != nil { 575 offs = n.List.Next.Next.N 576 } 577 578 // evaluate base pointer first, because it is the only 579 // possibly complex expression. once that is evaluated 580 // and stored, updating the len and cap can be done 581 // without making any calls, so without doing anything that 582 // might cause preemption or garbage collection. 583 // this makes the whole slice update atomic as far as the 584 // garbage collector can see. 585 base := temp(Types[TUINTPTR]) 586 587 tmplen := temp(Types[TINT]) 588 var tmpcap *Node 589 if n.Op != OSLICESTR { 590 tmpcap = temp(Types[TINT]) 591 } else { 592 tmpcap = tmplen 593 } 594 595 var src Node 596 if isnil(n.Left) { 597 Tempname(&src, n.Left.Type) 598 Cgen(n.Left, &src) 599 } else { 600 src = *n.Left 601 } 602 if n.Op == OSLICE || n.Op == OSLICE3 || n.Op == OSLICESTR { 603 src.Xoffset += int64(Array_array) 604 } 605 606 if n.Op == OSLICEARR || n.Op == OSLICE3ARR { 607 if !Isptr[n.Left.Type.Etype] { 608 Fatal("slicearr is supposed to work on pointer: %v\n", Nconv(n, obj.FmtSign)) 609 } 610 Cgen(&src, base) 611 Cgen_checknil(base) 612 } else { 613 src.Type = Types[Tptr] 614 Cgen(&src, base) 615 } 616 617 // committed to the update 618 Gvardef(res) 619 620 // compute len and cap. 621 // len = n-i, cap = m-i, and offs = i*width. 622 // computing offs last lets the multiply overwrite i. 623 Cgen((*Node)(len), tmplen) 624 625 if n.Op != OSLICESTR { 626 Cgen(cap, tmpcap) 627 } 628 629 // if new cap != 0 { base += add } 630 // This avoids advancing base past the end of the underlying array/string, 631 // so that it cannot point at the next object in memory. 632 // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero. 633 // In essence we are replacing x[i:j:k] where i == j == k 634 // or x[i:j] where i == j == cap(x) with x[0:0:0]. 635 if offs != nil { 636 p1 := gjmp(nil) 637 p2 := gjmp(nil) 638 Patch(p1, Pc) 639 640 var con Node 641 Nodconst(&con, tmpcap.Type, 0) 642 cmp := Nod(OEQ, tmpcap, &con) 643 typecheck(&cmp, Erv) 644 Bgen(cmp, true, -1, p2) 645 646 add := Nod(OADD, base, offs) 647 typecheck(&add, Erv) 648 Cgen(add, base) 649 650 Patch(p2, Pc) 651 } 652 653 // dst.array = src.array [ + lo *width ] 654 dst := *res 655 656 dst.Xoffset += int64(Array_array) 657 dst.Type = Types[Tptr] 658 Cgen(base, &dst) 659 660 // dst.len = hi [ - lo ] 661 dst = *res 662 663 dst.Xoffset += int64(Array_nel) 664 dst.Type = Types[Simtype[TUINT]] 665 Cgen(tmplen, &dst) 666 667 if n.Op != OSLICESTR { 668 // dst.cap = cap [ - lo ] 669 dst = *res 670 671 dst.Xoffset += int64(Array_cap) 672 dst.Type = Types[Simtype[TUINT]] 673 Cgen(tmpcap, &dst) 674 } 675 } 676 677 /* 678 * gather series of offsets 679 * >=0 is direct addressed field 680 * <0 is pointer to next field (+1) 681 */ 682 func Dotoffset(n *Node, oary []int64, nn **Node) int { 683 var i int 684 685 switch n.Op { 686 case ODOT: 687 if n.Xoffset == BADWIDTH { 688 Dump("bad width in dotoffset", n) 689 Fatal("bad width in dotoffset") 690 } 691 692 i = Dotoffset(n.Left, oary, nn) 693 if i > 0 { 694 if oary[i-1] >= 0 { 695 oary[i-1] += n.Xoffset 696 } else { 697 oary[i-1] -= n.Xoffset 698 } 699 break 700 } 701 702 if i < 10 { 703 oary[i] = n.Xoffset 704 i++ 705 } 706 707 case ODOTPTR: 708 if n.Xoffset == BADWIDTH { 709 Dump("bad width in dotoffset", n) 710 Fatal("bad width in dotoffset") 711 } 712 713 i = Dotoffset(n.Left, oary, nn) 714 if i < 10 { 715 oary[i] = -(n.Xoffset + 1) 716 i++ 717 } 718 719 default: 720 *nn = n 721 return 0 722 } 723 724 if i >= 10 { 725 *nn = nil 726 } 727 return i 728 } 729 730 /* 731 * make a new off the books 732 */ 733 func Tempname(nn *Node, t *Type) { 734 if Curfn == nil { 735 Fatal("no curfn for tempname") 736 } 737 738 if t == nil { 739 Yyerror("tempname called with nil type") 740 t = Types[TINT32] 741 } 742 743 // give each tmp a different name so that there 744 // a chance to registerizer them 745 s := Lookupf("autotmp_%.4d", statuniqgen) 746 statuniqgen++ 747 n := Nod(ONAME, nil, nil) 748 n.Sym = s 749 s.Def = n 750 n.Type = t 751 n.Class = PAUTO 752 n.Addable = true 753 n.Ullman = 1 754 n.Esc = EscNever 755 n.Curfn = Curfn 756 Curfn.Func.Dcl = list(Curfn.Func.Dcl, n) 757 758 dowidth(t) 759 n.Xoffset = 0 760 *nn = *n 761 } 762 763 func temp(t *Type) *Node { 764 n := Nod(OXXX, nil, nil) 765 Tempname(n, t) 766 n.Sym.Def.Used = true 767 return n.Orig 768 } 769 770 func gen(n *Node) { 771 //dump("gen", n); 772 773 lno := setlineno(n) 774 775 wasregalloc := Anyregalloc() 776 777 if n == nil { 778 goto ret 779 } 780 781 if n.Ninit != nil { 782 Genlist(n.Ninit) 783 } 784 785 setlineno(n) 786 787 switch n.Op { 788 default: 789 Fatal("gen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) 790 791 case OCASE, 792 OFALL, 793 OXCASE, 794 OXFALL, 795 ODCLCONST, 796 ODCLFUNC, 797 ODCLTYPE: 798 break 799 800 case OEMPTY: 801 break 802 803 case OBLOCK: 804 Genlist(n.List) 805 806 case OLABEL: 807 if isblanksym(n.Left.Sym) { 808 break 809 } 810 811 lab := newlab(n) 812 813 // if there are pending gotos, resolve them all to the current pc. 814 var p2 *obj.Prog 815 for p1 := lab.Gotopc; p1 != nil; p1 = p2 { 816 p2 = unpatch(p1) 817 Patch(p1, Pc) 818 } 819 820 lab.Gotopc = nil 821 if lab.Labelpc == nil { 822 lab.Labelpc = Pc 823 } 824 825 if n.Defn != nil { 826 switch n.Defn.Op { 827 // so stmtlabel can find the label 828 case OFOR, OSWITCH, OSELECT: 829 n.Defn.Sym = lab.Sym 830 } 831 } 832 833 // if label is defined, emit jump to it. 834 // otherwise save list of pending gotos in lab->gotopc. 835 // the list is linked through the normal jump target field 836 // to avoid a second list. (the jumps are actually still 837 // valid code, since they're just going to another goto 838 // to the same label. we'll unwind it when we learn the pc 839 // of the label in the OLABEL case above.) 840 case OGOTO: 841 lab := newlab(n) 842 843 if lab.Labelpc != nil { 844 gjmp(lab.Labelpc) 845 } else { 846 lab.Gotopc = gjmp(lab.Gotopc) 847 } 848 849 case OBREAK: 850 if n.Left != nil { 851 lab := n.Left.Sym.Label 852 if lab == nil { 853 Yyerror("break label not defined: %v", n.Left.Sym) 854 break 855 } 856 857 lab.Used = 1 858 if lab.Breakpc == nil { 859 Yyerror("invalid break label %v", n.Left.Sym) 860 break 861 } 862 863 gjmp(lab.Breakpc) 864 break 865 } 866 867 if breakpc == nil { 868 Yyerror("break is not in a loop") 869 break 870 } 871 872 gjmp(breakpc) 873 874 case OCONTINUE: 875 if n.Left != nil { 876 lab := n.Left.Sym.Label 877 if lab == nil { 878 Yyerror("continue label not defined: %v", n.Left.Sym) 879 break 880 } 881 882 lab.Used = 1 883 if lab.Continpc == nil { 884 Yyerror("invalid continue label %v", n.Left.Sym) 885 break 886 } 887 888 gjmp(lab.Continpc) 889 break 890 } 891 892 if continpc == nil { 893 Yyerror("continue is not in a loop") 894 break 895 } 896 897 gjmp(continpc) 898 899 case OFOR: 900 sbreak := breakpc 901 p1 := gjmp(nil) // goto test 902 breakpc = gjmp(nil) // break: goto done 903 scontin := continpc 904 continpc = Pc 905 906 // define break and continue labels 907 lab := stmtlabel(n) 908 if lab != nil { 909 lab.Breakpc = breakpc 910 lab.Continpc = continpc 911 } 912 913 gen(n.Nincr) // contin: incr 914 Patch(p1, Pc) // test: 915 Bgen(n.Ntest, false, -1, breakpc) // if(!test) goto break 916 Genlist(n.Nbody) // body 917 gjmp(continpc) 918 Patch(breakpc, Pc) // done: 919 continpc = scontin 920 breakpc = sbreak 921 if lab != nil { 922 lab.Breakpc = nil 923 lab.Continpc = nil 924 } 925 926 case OIF: 927 p1 := gjmp(nil) // goto test 928 p2 := gjmp(nil) // p2: goto else 929 Patch(p1, Pc) // test: 930 Bgen(n.Ntest, false, int(-n.Likely), p2) // if(!test) goto p2 931 Genlist(n.Nbody) // then 932 p3 := gjmp(nil) // goto done 933 Patch(p2, Pc) // else: 934 Genlist(n.Nelse) // else 935 Patch(p3, Pc) // done: 936 937 case OSWITCH: 938 sbreak := breakpc 939 p1 := gjmp(nil) // goto test 940 breakpc = gjmp(nil) // break: goto done 941 942 // define break label 943 lab := stmtlabel(n) 944 if lab != nil { 945 lab.Breakpc = breakpc 946 } 947 948 Patch(p1, Pc) // test: 949 Genlist(n.Nbody) // switch(test) body 950 Patch(breakpc, Pc) // done: 951 breakpc = sbreak 952 if lab != nil { 953 lab.Breakpc = nil 954 } 955 956 case OSELECT: 957 sbreak := breakpc 958 p1 := gjmp(nil) // goto test 959 breakpc = gjmp(nil) // break: goto done 960 961 // define break label 962 lab := stmtlabel(n) 963 if lab != nil { 964 lab.Breakpc = breakpc 965 } 966 967 Patch(p1, Pc) // test: 968 Genlist(n.Nbody) // select() body 969 Patch(breakpc, Pc) // done: 970 breakpc = sbreak 971 if lab != nil { 972 lab.Breakpc = nil 973 } 974 975 case ODCL: 976 cgen_dcl(n.Left) 977 978 case OAS: 979 if gen_as_init(n) { 980 break 981 } 982 Cgen_as(n.Left, n.Right) 983 984 case OASWB: 985 Cgen_as_wb(n.Left, n.Right, true) 986 987 case OAS2DOTTYPE: 988 cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false) 989 990 case OCALLMETH: 991 cgen_callmeth(n, 0) 992 993 case OCALLINTER: 994 cgen_callinter(n, nil, 0) 995 996 case OCALLFUNC: 997 cgen_call(n, 0) 998 999 case OPROC: 1000 cgen_proc(n, 1) 1001 1002 case ODEFER: 1003 cgen_proc(n, 2) 1004 1005 case ORETURN, ORETJMP: 1006 cgen_ret(n) 1007 1008 // Function calls turned into compiler intrinsics. 1009 // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any. 1010 case OGETG: 1011 // nothing 1012 case OSQRT: 1013 cgen_discard(n.Left) 1014 1015 case OCHECKNIL: 1016 Cgen_checknil(n.Left) 1017 1018 case OVARKILL: 1019 gvarkill(n.Left) 1020 } 1021 1022 ret: 1023 if Anyregalloc() != wasregalloc { 1024 Dump("node", n) 1025 Fatal("registers left allocated") 1026 } 1027 1028 lineno = lno 1029 } 1030 1031 func Cgen_as(nl, nr *Node) { 1032 Cgen_as_wb(nl, nr, false) 1033 } 1034 1035 func Cgen_as_wb(nl, nr *Node, wb bool) { 1036 if Debug['g'] != 0 { 1037 op := "cgen_as" 1038 if wb { 1039 op = "cgen_as_wb" 1040 } 1041 Dump(op, nl) 1042 Dump(op+" = ", nr) 1043 } 1044 1045 for nr != nil && nr.Op == OCONVNOP { 1046 nr = nr.Left 1047 } 1048 1049 if nl == nil || isblank(nl) { 1050 cgen_discard(nr) 1051 return 1052 } 1053 1054 if nr == nil || iszero(nr) { 1055 // heaps should already be clear 1056 if nr == nil && (nl.Class&PHEAP != 0) { 1057 return 1058 } 1059 1060 tl := nl.Type 1061 if tl == nil { 1062 return 1063 } 1064 if Isfat(tl) { 1065 if nl.Op == ONAME { 1066 Gvardef(nl) 1067 } 1068 Thearch.Clearfat(nl) 1069 return 1070 } 1071 1072 Clearslim(nl) 1073 return 1074 } 1075 1076 tl := nl.Type 1077 if tl == nil { 1078 return 1079 } 1080 1081 cgen_wb(nr, nl, wb) 1082 } 1083 1084 func cgen_callmeth(n *Node, proc int) { 1085 // generate a rewrite in n2 for the method call 1086 // (p.f)(...) goes to (f)(p,...) 1087 1088 l := n.Left 1089 1090 if l.Op != ODOTMETH { 1091 Fatal("cgen_callmeth: not dotmethod: %v") 1092 } 1093 1094 n2 := *n 1095 n2.Op = OCALLFUNC 1096 n2.Left = l.Right 1097 n2.Left.Type = l.Type 1098 1099 if n2.Left.Op == ONAME { 1100 n2.Left.Class = PFUNC 1101 } 1102 cgen_call(&n2, proc) 1103 } 1104 1105 // CgenTemp creates a temporary node, assigns n to it, and returns it. 1106 func CgenTemp(n *Node) *Node { 1107 var tmp Node 1108 Tempname(&tmp, n.Type) 1109 Cgen(n, &tmp) 1110 return &tmp 1111 } 1112 1113 func checklabels() { 1114 var l *NodeList 1115 1116 for lab := labellist; lab != nil; lab = lab.Link { 1117 if lab.Def == nil { 1118 for l = lab.Use; l != nil; l = l.Next { 1119 yyerrorl(int(l.N.Lineno), "label %v not defined", lab.Sym) 1120 } 1121 continue 1122 } 1123 1124 if lab.Use == nil && lab.Used == 0 { 1125 yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym) 1126 continue 1127 } 1128 1129 if lab.Gotopc != nil { 1130 Fatal("label %v never resolved", lab.Sym) 1131 } 1132 for l = lab.Use; l != nil; l = l.Next { 1133 checkgoto(l.N, lab.Def) 1134 } 1135 } 1136 } 1137 1138 // Componentgen copies a composite value by moving its individual components. 1139 // Slices, strings and interfaces are supported. Small structs or arrays with 1140 // elements of basic type are also supported. 1141 // nr is nil when assigning a zero value. 1142 func Componentgen(nr, nl *Node) bool { 1143 return componentgen_wb(nr, nl, false) 1144 } 1145 1146 // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates. 1147 func componentgen_wb(nr, nl *Node, wb bool) bool { 1148 // Don't generate any code for complete copy of a variable into itself. 1149 // It's useless, and the VARDEF will incorrectly mark the old value as dead. 1150 // (This check assumes that the arguments passed to componentgen did not 1151 // themselves come from Igen, or else we could have Op==ONAME but 1152 // with a Type and Xoffset describing an individual field, not the entire 1153 // variable.) 1154 if nl.Op == ONAME && nl == nr { 1155 return true 1156 } 1157 1158 // Count number of moves required to move components. 1159 // If using write barrier, can only emit one pointer. 1160 // TODO(rsc): Allow more pointers, for reflect.Value. 1161 const maxMoves = 8 1162 n := 0 1163 numPtr := 0 1164 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1165 n++ 1166 if int(Simtype[t.Etype]) == Tptr && t != itable { 1167 numPtr++ 1168 } 1169 return n <= maxMoves && (!wb || numPtr <= 1) 1170 }) 1171 if n > maxMoves || wb && numPtr > 1 { 1172 return false 1173 } 1174 1175 // Must call emitVardef after evaluating rhs but before writing to lhs. 1176 emitVardef := func() { 1177 // Emit vardef if needed. 1178 if nl.Op == ONAME { 1179 switch nl.Type.Etype { 1180 case TARRAY, TSTRING, TINTER, TSTRUCT: 1181 Gvardef(nl) 1182 } 1183 } 1184 } 1185 1186 isConstString := Isconst(nr, CTSTR) 1187 1188 if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString { 1189 return false 1190 } 1191 1192 var nodl Node 1193 if cadable(nl) { 1194 nodl = *nl 1195 } else { 1196 if nr != nil && !cadable(nr) && !isConstString { 1197 return false 1198 } 1199 if nr == nil || isConstString || nl.Ullman >= nr.Ullman { 1200 Igen(nl, &nodl, nil) 1201 defer Regfree(&nodl) 1202 } 1203 } 1204 lbase := nodl.Xoffset 1205 1206 // Special case: zeroing. 1207 var nodr Node 1208 if nr == nil { 1209 // When zeroing, prepare a register containing zero. 1210 // TODO(rsc): Check that this is actually generating the best code. 1211 if Thearch.REGZERO != 0 { 1212 // cpu has a dedicated zero register 1213 Nodreg(&nodr, Types[TUINT], Thearch.REGZERO) 1214 } else { 1215 // no dedicated zero register 1216 var zero Node 1217 Nodconst(&zero, nl.Type, 0) 1218 Regalloc(&nodr, Types[TUINT], nil) 1219 Thearch.Gmove(&zero, &nodr) 1220 defer Regfree(&nodr) 1221 } 1222 1223 emitVardef() 1224 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1225 nodl.Type = t 1226 nodl.Xoffset = lbase + offset 1227 nodr.Type = t 1228 if Isfloat[t.Etype] { 1229 // TODO(rsc): Cache zero register like we do for integers? 1230 Clearslim(&nodl) 1231 } else { 1232 Thearch.Gmove(&nodr, &nodl) 1233 } 1234 return true 1235 }) 1236 return true 1237 } 1238 1239 // Special case: assignment of string constant. 1240 if isConstString { 1241 emitVardef() 1242 1243 // base 1244 nodl.Type = Ptrto(Types[TUINT8]) 1245 Regalloc(&nodr, Types[Tptr], nil) 1246 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) 1247 Datastring(nr.Val.U.Sval, &p.From) 1248 p.From.Type = obj.TYPE_ADDR 1249 Thearch.Gmove(&nodr, &nodl) 1250 Regfree(&nodr) 1251 1252 // length 1253 nodl.Type = Types[Simtype[TUINT]] 1254 nodl.Xoffset += int64(Array_nel) - int64(Array_array) 1255 Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval))) 1256 Thearch.Gmove(&nodr, &nodl) 1257 return true 1258 } 1259 1260 // General case: copy nl = nr. 1261 nodr = *nr 1262 if !cadable(nr) { 1263 if nr.Ullman >= UINF && nodl.Op == OINDREG { 1264 Fatal("miscompile") 1265 } 1266 Igen(nr, &nodr, nil) 1267 defer Regfree(&nodr) 1268 } 1269 rbase := nodr.Xoffset 1270 1271 if nodl.Op == 0 { 1272 Igen(nl, &nodl, nil) 1273 defer Regfree(&nodl) 1274 lbase = nodl.Xoffset 1275 } 1276 1277 emitVardef() 1278 var ( 1279 ptrType *Type 1280 ptrOffset int64 1281 ) 1282 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1283 if wb && int(Simtype[t.Etype]) == Tptr && t != itable { 1284 if ptrType != nil { 1285 Fatal("componentgen_wb %v", Tconv(nl.Type, 0)) 1286 } 1287 ptrType = t 1288 ptrOffset = offset 1289 return true 1290 } 1291 nodl.Type = t 1292 nodl.Xoffset = lbase + offset 1293 nodr.Type = t 1294 nodr.Xoffset = rbase + offset 1295 Thearch.Gmove(&nodr, &nodl) 1296 return true 1297 }) 1298 if ptrType != nil { 1299 nodl.Type = ptrType 1300 nodl.Xoffset = lbase + ptrOffset 1301 nodr.Type = ptrType 1302 nodr.Xoffset = rbase + ptrOffset 1303 cgen_wbptr(&nodr, &nodl) 1304 } 1305 return true 1306 } 1307 1308 // visitComponents walks the individual components of the type t, 1309 // walking into array elements, struct fields, the real and imaginary 1310 // parts of complex numbers, and on 32-bit systems the high and 1311 // low halves of 64-bit integers. 1312 // It calls f for each such component, passing the component (aka element) 1313 // type and memory offset, assuming t starts at startOffset. 1314 // If f ever returns false, visitComponents returns false without any more 1315 // calls to f. Otherwise visitComponents returns true. 1316 func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool { 1317 switch t.Etype { 1318 case TINT64: 1319 if Widthreg == 8 { 1320 break 1321 } 1322 // NOTE: Assuming little endian (signed top half at offset 4). 1323 // We don't have any 32-bit big-endian systems. 1324 if Thearch.Thechar != '5' && Thearch.Thechar != '8' { 1325 Fatal("unknown 32-bit architecture") 1326 } 1327 return f(Types[TUINT32], startOffset) && 1328 f(Types[TINT32], startOffset+4) 1329 1330 case TUINT64: 1331 if Widthreg == 8 { 1332 break 1333 } 1334 return f(Types[TUINT32], startOffset) && 1335 f(Types[TUINT32], startOffset+4) 1336 1337 case TCOMPLEX64: 1338 return f(Types[TFLOAT32], startOffset) && 1339 f(Types[TFLOAT32], startOffset+4) 1340 1341 case TCOMPLEX128: 1342 return f(Types[TFLOAT64], startOffset) && 1343 f(Types[TFLOAT64], startOffset+8) 1344 1345 case TINTER: 1346 return f(itable, startOffset) && 1347 f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr)) 1348 return true 1349 1350 case TSTRING: 1351 return f(Ptrto(Types[TUINT8]), startOffset) && 1352 f(Types[Simtype[TUINT]], startOffset+int64(Widthptr)) 1353 1354 case TARRAY: 1355 if Isslice(t) { 1356 return f(Ptrto(t.Type), startOffset+int64(Array_array)) && 1357 f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) && 1358 f(Types[Simtype[TUINT]], startOffset+int64(Array_cap)) 1359 } 1360 1361 // Short-circuit [1e6]struct{}. 1362 if t.Type.Width == 0 { 1363 return true 1364 } 1365 1366 for i := int64(0); i < t.Bound; i++ { 1367 if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) { 1368 return false 1369 } 1370 } 1371 return true 1372 1373 case TSTRUCT: 1374 if t.Type != nil && t.Type.Width != 0 { 1375 // NOTE(rsc): If this happens, the right thing to do is to say 1376 // startOffset -= t.Type.Width 1377 // but I want to see if it does. 1378 // The old version of componentgen handled this, 1379 // in code introduced in CL 6932045 to fix issue #4518. 1380 // But the test case in issue 4518 does not trigger this anymore, 1381 // so maybe this complication is no longer needed. 1382 Fatal("struct not at offset 0") 1383 } 1384 1385 for field := t.Type; field != nil; field = field.Down { 1386 if field.Etype != TFIELD { 1387 Fatal("bad struct") 1388 } 1389 if !visitComponents(field.Type, startOffset+field.Width, f) { 1390 return false 1391 } 1392 } 1393 return true 1394 } 1395 return f(t, startOffset) 1396 } 1397 1398 func cadable(n *Node) bool { 1399 // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can. 1400 return n.Addable && n.Op == ONAME 1401 }