github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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 /* 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 /* 27 * the address of n has been taken and might be used after 28 * the current function returns. mark any local vars 29 * as needing to move to the heap. 30 */ 31 func addrescapes(n *Node) { 32 switch n.Op { 33 // probably a type error already. 34 // dump("addrescapes", n); 35 default: 36 break 37 38 case ONAME: 39 if n == nodfp { 40 break 41 } 42 43 // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. 44 // on PPARAM it means something different. 45 if n.Class == PAUTO && n.Esc == EscNever { 46 break 47 } 48 49 switch n.Class { 50 case PPARAMREF: 51 addrescapes(n.Defn) 52 53 // if func param, need separate temporary 54 // to hold heap pointer. 55 // the function type has already been checked 56 // (we're in the function body) 57 // so the param already has a valid xoffset. 58 59 // expression to refer to stack copy 60 case PPARAM, PPARAMOUT: 61 n.Stackparam = Nod(OPARAM, n, nil) 62 63 n.Stackparam.Type = n.Type 64 n.Stackparam.Addable = true 65 if n.Xoffset == BADWIDTH { 66 Fatal("addrescapes before param assignment") 67 } 68 n.Stackparam.Xoffset = n.Xoffset 69 fallthrough 70 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", Sconv(n.Sym, 0)) 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(), Nconv(n, 0)) 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", Sconv(s, 0), 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", Sconv(from.Left.Sym, 0), Ctxt.Line(int(block.Lastlineno))) 196 } else { 197 Yyerror("goto %v jumps over declaration of %v at %v", Sconv(from.Left.Sym, 0), Sconv(dcl, 0), 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.", Nconv(n, 0)) 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", Tconv(n.Type, 0)) 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) { 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 iface.Xoffset += int64(Widthptr) 447 Cgen(&iface, &r1) 448 Regfree(&iface) 449 450 if resok == nil { 451 r1.Type = res.Type 452 Cgen(&r1, res) 453 q := Gbranch(obj.AJMP, nil, 0) 454 Patch(p, Pc) 455 456 fn := syslook("panicdottype", 0) 457 dowidth(fn.Type) 458 call := Nod(OCALLFUNC, fn, nil) 459 r1.Type = byteptr 460 r2.Type = byteptr 461 call.List = list(list(list1(&r1), &r2), typename(n.Left.Type)) 462 call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil) 463 gen(call) 464 Regfree(&r1) 465 Regfree(&r2) 466 Thearch.Gins(obj.AUNDEF, nil, nil) 467 Patch(q, Pc) 468 } else { 469 // This half is handling the res, resok = x.(T) case, 470 // which is called from gen, not cgen, and is consequently fussier 471 // about blank assignments. We have to avoid calling cgen for those. 472 Regfree(&r2) 473 r1.Type = res.Type 474 if !isblank(res) { 475 Cgen(&r1, res) 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", Sconv(n.Left.Sym, 0)) 854 break 855 } 856 857 lab.Used = 1 858 if lab.Breakpc == nil { 859 Yyerror("invalid break label %v", Sconv(n.Left.Sym, 0)) 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", Sconv(n.Left.Sym, 0)) 879 break 880 } 881 882 lab.Used = 1 883 if lab.Continpc == nil { 884 Yyerror("invalid continue label %v", Sconv(n.Left.Sym, 0)) 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 OAS2DOTTYPE: 985 cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N) 986 987 case OCALLMETH: 988 cgen_callmeth(n, 0) 989 990 case OCALLINTER: 991 cgen_callinter(n, nil, 0) 992 993 case OCALLFUNC: 994 cgen_call(n, 0) 995 996 case OPROC: 997 cgen_proc(n, 1) 998 999 case ODEFER: 1000 cgen_proc(n, 2) 1001 1002 case ORETURN, ORETJMP: 1003 cgen_ret(n) 1004 1005 // Function calls turned into compiler intrinsics. 1006 // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any. 1007 case OGETG: 1008 // nothing 1009 case OSQRT: 1010 cgen_discard(n.Left) 1011 1012 case OCHECKNIL: 1013 Cgen_checknil(n.Left) 1014 1015 case OVARKILL: 1016 gvarkill(n.Left) 1017 } 1018 1019 ret: 1020 if Anyregalloc() != wasregalloc { 1021 Dump("node", n) 1022 Fatal("registers left allocated") 1023 } 1024 1025 lineno = lno 1026 } 1027 1028 func Cgen_as(nl *Node, nr *Node) { 1029 if Debug['g'] != 0 { 1030 Dump("cgen_as", nl) 1031 Dump("cgen_as = ", nr) 1032 } 1033 1034 for nr != nil && nr.Op == OCONVNOP { 1035 nr = nr.Left 1036 } 1037 1038 if nl == nil || isblank(nl) { 1039 cgen_discard(nr) 1040 return 1041 } 1042 1043 if nr == nil || iszero(nr) { 1044 // heaps should already be clear 1045 if nr == nil && (nl.Class&PHEAP != 0) { 1046 return 1047 } 1048 1049 tl := nl.Type 1050 if tl == nil { 1051 return 1052 } 1053 if Isfat(tl) { 1054 if nl.Op == ONAME { 1055 Gvardef(nl) 1056 } 1057 Thearch.Clearfat(nl) 1058 return 1059 } 1060 1061 Clearslim(nl) 1062 return 1063 } 1064 1065 tl := nl.Type 1066 if tl == nil { 1067 return 1068 } 1069 1070 Cgen(nr, nl) 1071 } 1072 1073 func cgen_callmeth(n *Node, proc int) { 1074 // generate a rewrite in n2 for the method call 1075 // (p.f)(...) goes to (f)(p,...) 1076 1077 l := n.Left 1078 1079 if l.Op != ODOTMETH { 1080 Fatal("cgen_callmeth: not dotmethod: %v") 1081 } 1082 1083 n2 := *n 1084 n2.Op = OCALLFUNC 1085 n2.Left = l.Right 1086 n2.Left.Type = l.Type 1087 1088 if n2.Left.Op == ONAME { 1089 n2.Left.Class = PFUNC 1090 } 1091 cgen_call(&n2, proc) 1092 } 1093 1094 func checklabels() { 1095 var l *NodeList 1096 1097 for lab := labellist; lab != nil; lab = lab.Link { 1098 if lab.Def == nil { 1099 for l = lab.Use; l != nil; l = l.Next { 1100 yyerrorl(int(l.N.Lineno), "label %v not defined", Sconv(lab.Sym, 0)) 1101 } 1102 continue 1103 } 1104 1105 if lab.Use == nil && lab.Used == 0 { 1106 yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", Sconv(lab.Sym, 0)) 1107 continue 1108 } 1109 1110 if lab.Gotopc != nil { 1111 Fatal("label %v never resolved", Sconv(lab.Sym, 0)) 1112 } 1113 for l = lab.Use; l != nil; l = l.Next { 1114 checkgoto(l.N, lab.Def) 1115 } 1116 } 1117 } 1118 1119 // Componentgen copies a composite value by moving its individual components. 1120 // Slices, strings and interfaces are supported. Small structs or arrays with 1121 // elements of basic type are also supported. 1122 // nr is nil when assigning a zero value. 1123 func Componentgen(nr *Node, nl *Node) bool { 1124 var nodl, nodr Node 1125 1126 switch nl.Type.Etype { 1127 default: 1128 return false 1129 1130 case TARRAY: 1131 t := nl.Type 1132 1133 // Slices are ok. 1134 if Isslice(t) { 1135 break 1136 } 1137 1138 // Small arrays are ok. 1139 if t.Bound > 0 && t.Bound <= 3 && !Isfat(t.Type) { 1140 break 1141 } 1142 1143 return false 1144 1145 case TSTRUCT: 1146 // Small structs with non-fat types are ok. 1147 // Zero-sized structs are treated separately elsewhere. 1148 fldcount := int64(0) 1149 1150 for t := nl.Type.Type; t != nil; t = t.Down { 1151 if Isfat(t.Type) && !Isslice(t) { 1152 return false 1153 } 1154 if t.Etype != TFIELD { 1155 Fatal("componentgen: not a TFIELD: %v", Tconv(t, obj.FmtLong)) 1156 } 1157 fldcount++ 1158 } 1159 1160 if fldcount == 0 || fldcount > 4 { 1161 return false 1162 } 1163 1164 case TSTRING, TINTER: 1165 break 1166 } 1167 1168 isConstString := Isconst(nr, CTSTR) 1169 nodl = *nl 1170 if !cadable(nl) { 1171 if nr != nil && !cadable(nr) && !isConstString { 1172 return false 1173 } 1174 Igen(nl, &nodl, nil) 1175 defer Regfree(&nodl) 1176 } 1177 1178 if nr != nil { 1179 nodr = *nr 1180 if !cadable(nr) && !isConstString { 1181 Igen(nr, &nodr, nil) 1182 defer Regfree(&nodr) 1183 } 1184 } else { 1185 // When zeroing, prepare a register containing zero. 1186 if Thearch.REGZERO != 0 { 1187 // cpu has a dedicated zero register 1188 Nodreg(&nodr, Types[TUINT], Thearch.REGZERO) 1189 } else { 1190 // no dedicated zero register 1191 var tmp Node 1192 Nodconst(&tmp, nl.Type, 0) 1193 1194 Regalloc(&nodr, Types[TUINT], nil) 1195 Thearch.Gmove(&tmp, &nodr) 1196 defer Regfree(&nodr) 1197 } 1198 } 1199 1200 // nl and nr are 'cadable' which basically means they are names (variables) now. 1201 // If they are the same variable, don't generate any code, because the 1202 // VARDEF we generate will mark the old value as dead incorrectly. 1203 // (And also the assignments are useless.) 1204 if nr != nil && nl.Op == ONAME && nr.Op == ONAME && nl == nr { 1205 return true 1206 } 1207 1208 switch nl.Type.Etype { 1209 default: 1210 return false 1211 1212 case TARRAY: 1213 // componentgen for arrays. 1214 if nl.Op == ONAME { 1215 Gvardef(nl) 1216 } 1217 t := nl.Type 1218 if !Isslice(t) { 1219 nodl.Type = t.Type 1220 nodr.Type = nodl.Type 1221 for fldcount := int64(0); fldcount < t.Bound; fldcount++ { 1222 if nr == nil { 1223 Clearslim(&nodl) 1224 } else { 1225 Thearch.Gmove(&nodr, &nodl) 1226 } 1227 nodl.Xoffset += t.Type.Width 1228 nodr.Xoffset += t.Type.Width 1229 } 1230 return true 1231 } 1232 1233 // componentgen for slices. 1234 nodl.Xoffset += int64(Array_array) 1235 1236 nodl.Type = Ptrto(nl.Type.Type) 1237 1238 if nr != nil { 1239 nodr.Xoffset += int64(Array_array) 1240 nodr.Type = nodl.Type 1241 } 1242 1243 Thearch.Gmove(&nodr, &nodl) 1244 1245 nodl.Xoffset += int64(Array_nel) - int64(Array_array) 1246 nodl.Type = Types[Simtype[TUINT]] 1247 1248 if nr != nil { 1249 nodr.Xoffset += int64(Array_nel) - int64(Array_array) 1250 nodr.Type = nodl.Type 1251 } 1252 1253 Thearch.Gmove(&nodr, &nodl) 1254 1255 nodl.Xoffset += int64(Array_cap) - int64(Array_nel) 1256 nodl.Type = Types[Simtype[TUINT]] 1257 1258 if nr != nil { 1259 nodr.Xoffset += int64(Array_cap) - int64(Array_nel) 1260 nodr.Type = nodl.Type 1261 } 1262 1263 Thearch.Gmove(&nodr, &nodl) 1264 return true 1265 1266 case TSTRING: 1267 if nl.Op == ONAME { 1268 Gvardef(nl) 1269 } 1270 nodl.Xoffset += int64(Array_array) 1271 nodl.Type = Ptrto(Types[TUINT8]) 1272 1273 if isConstString { 1274 Regalloc(&nodr, Types[Tptr], nil) 1275 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) 1276 Datastring(nr.Val.U.Sval, &p.From) 1277 p.From.Type = obj.TYPE_ADDR 1278 Regfree(&nodr) 1279 } else if nr != nil { 1280 nodr.Xoffset += int64(Array_array) 1281 nodr.Type = nodl.Type 1282 } 1283 1284 Thearch.Gmove(&nodr, &nodl) 1285 1286 nodl.Xoffset += int64(Array_nel) - int64(Array_array) 1287 nodl.Type = Types[Simtype[TUINT]] 1288 1289 if isConstString { 1290 Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval))) 1291 } else if nr != nil { 1292 nodr.Xoffset += int64(Array_nel) - int64(Array_array) 1293 nodr.Type = nodl.Type 1294 } 1295 1296 Thearch.Gmove(&nodr, &nodl) 1297 return true 1298 1299 case TINTER: 1300 if nl.Op == ONAME { 1301 Gvardef(nl) 1302 } 1303 nodl.Xoffset += int64(Array_array) 1304 nodl.Type = Ptrto(Types[TUINT8]) 1305 1306 if nr != nil { 1307 nodr.Xoffset += int64(Array_array) 1308 nodr.Type = nodl.Type 1309 } 1310 1311 Thearch.Gmove(&nodr, &nodl) 1312 1313 nodl.Xoffset += int64(Array_nel) - int64(Array_array) 1314 nodl.Type = Ptrto(Types[TUINT8]) 1315 1316 if nr != nil { 1317 nodr.Xoffset += int64(Array_nel) - int64(Array_array) 1318 nodr.Type = nodl.Type 1319 } 1320 1321 Thearch.Gmove(&nodr, &nodl) 1322 return true 1323 1324 case TSTRUCT: 1325 if nl.Op == ONAME { 1326 Gvardef(nl) 1327 } 1328 loffset := nodl.Xoffset 1329 roffset := nodr.Xoffset 1330 1331 // funarg structs may not begin at offset zero. 1332 if nl.Type.Etype == TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { 1333 loffset -= nl.Type.Type.Width 1334 } 1335 if nr != nil && nr.Type.Etype == TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { 1336 roffset -= nr.Type.Type.Width 1337 } 1338 1339 for t := nl.Type.Type; t != nil; t = t.Down { 1340 nodl.Xoffset = loffset + t.Width 1341 nodl.Type = t.Type 1342 1343 if nr == nil { 1344 Clearslim(&nodl) 1345 } else { 1346 nodr.Xoffset = roffset + t.Width 1347 nodr.Type = nodl.Type 1348 Thearch.Gmove(&nodr, &nodl) 1349 } 1350 } 1351 return true 1352 } 1353 } 1354 1355 func cadable(n *Node) bool { 1356 if !n.Addable { 1357 // dont know how it happens, 1358 // but it does 1359 return false 1360 } 1361 1362 switch n.Op { 1363 case ONAME: 1364 return true 1365 } 1366 1367 return false 1368 }