github.com/aloncn/graphics-go@v0.0.1/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, needwritebarrier(n.List.N, n.Rlist.N)) 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 case OVARLIVE: 873 gvarlive(n.Left) 874 } 875 876 ret: 877 if Anyregalloc() != wasregalloc { 878 Dump("node", n) 879 Fatalf("registers left allocated") 880 } 881 882 lineno = lno 883 } 884 885 func Cgen_as(nl, nr *Node) { 886 Cgen_as_wb(nl, nr, false) 887 } 888 889 func Cgen_as_wb(nl, nr *Node, wb bool) { 890 if Debug['g'] != 0 { 891 op := "cgen_as" 892 if wb { 893 op = "cgen_as_wb" 894 } 895 Dump(op, nl) 896 Dump(op+" = ", nr) 897 } 898 899 for nr != nil && nr.Op == OCONVNOP { 900 nr = nr.Left 901 } 902 903 if nl == nil || isblank(nl) { 904 cgen_discard(nr) 905 return 906 } 907 908 if nr == nil || iszero(nr) { 909 // heaps should already be clear 910 if nr == nil && (nl.Class&PHEAP != 0) { 911 return 912 } 913 914 tl := nl.Type 915 if tl == nil { 916 return 917 } 918 if Isfat(tl) { 919 if nl.Op == ONAME { 920 Gvardef(nl) 921 } 922 Thearch.Clearfat(nl) 923 return 924 } 925 926 Clearslim(nl) 927 return 928 } 929 930 tl := nl.Type 931 if tl == nil { 932 return 933 } 934 935 cgen_wb(nr, nl, wb) 936 } 937 938 func cgen_callmeth(n *Node, proc int) { 939 // generate a rewrite in n2 for the method call 940 // (p.f)(...) goes to (f)(p,...) 941 942 l := n.Left 943 944 if l.Op != ODOTMETH { 945 Fatalf("cgen_callmeth: not dotmethod: %v", l) 946 } 947 948 n2 := *n 949 n2.Op = OCALLFUNC 950 n2.Left = l.Right 951 n2.Left.Type = l.Type 952 953 if n2.Left.Op == ONAME { 954 n2.Left.Class = PFUNC 955 } 956 cgen_call(&n2, proc) 957 } 958 959 // CgenTemp creates a temporary node, assigns n to it, and returns it. 960 func CgenTemp(n *Node) *Node { 961 var tmp Node 962 Tempname(&tmp, n.Type) 963 Cgen(n, &tmp) 964 return &tmp 965 } 966 967 func checklabels() { 968 for lab := labellist; lab != nil; lab = lab.Link { 969 if lab.Def == nil { 970 for _, n := range lab.Use { 971 yyerrorl(int(n.Lineno), "label %v not defined", lab.Sym) 972 } 973 continue 974 } 975 976 if lab.Use == nil && !lab.Used { 977 yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym) 978 continue 979 } 980 981 if lab.Gotopc != nil { 982 Fatalf("label %v never resolved", lab.Sym) 983 } 984 for _, n := range lab.Use { 985 checkgoto(n, lab.Def) 986 } 987 } 988 } 989 990 // Componentgen copies a composite value by moving its individual components. 991 // Slices, strings and interfaces are supported. Small structs or arrays with 992 // elements of basic type are also supported. 993 // nr is nil when assigning a zero value. 994 func Componentgen(nr, nl *Node) bool { 995 return componentgen_wb(nr, nl, false) 996 } 997 998 // componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates. 999 func componentgen_wb(nr, nl *Node, wb bool) bool { 1000 // Don't generate any code for complete copy of a variable into itself. 1001 // It's useless, and the VARDEF will incorrectly mark the old value as dead. 1002 // (This check assumes that the arguments passed to componentgen did not 1003 // themselves come from Igen, or else we could have Op==ONAME but 1004 // with a Type and Xoffset describing an individual field, not the entire 1005 // variable.) 1006 if nl.Op == ONAME && nl == nr { 1007 return true 1008 } 1009 1010 // Count number of moves required to move components. 1011 // If using write barrier, can only emit one pointer. 1012 // TODO(rsc): Allow more pointers, for reflect.Value. 1013 const maxMoves = 8 1014 n := 0 1015 numPtr := 0 1016 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1017 n++ 1018 if Simtype[t.Etype] == Tptr && t != itable { 1019 numPtr++ 1020 } 1021 return n <= maxMoves && (!wb || numPtr <= 1) 1022 }) 1023 if n > maxMoves || wb && numPtr > 1 { 1024 return false 1025 } 1026 1027 // Must call emitVardef after evaluating rhs but before writing to lhs. 1028 emitVardef := func() { 1029 // Emit vardef if needed. 1030 if nl.Op == ONAME { 1031 switch nl.Type.Etype { 1032 case TARRAY, TSTRING, TINTER, TSTRUCT: 1033 Gvardef(nl) 1034 } 1035 } 1036 } 1037 1038 isConstString := Isconst(nr, CTSTR) 1039 1040 if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString { 1041 return false 1042 } 1043 1044 var nodl Node 1045 if cadable(nl) { 1046 nodl = *nl 1047 } else { 1048 if nr != nil && !cadable(nr) && !isConstString { 1049 return false 1050 } 1051 if nr == nil || isConstString || nl.Ullman >= nr.Ullman { 1052 Igen(nl, &nodl, nil) 1053 defer Regfree(&nodl) 1054 } 1055 } 1056 lbase := nodl.Xoffset 1057 1058 // Special case: zeroing. 1059 var nodr Node 1060 if nr == nil { 1061 // When zeroing, prepare a register containing zero. 1062 // TODO(rsc): Check that this is actually generating the best code. 1063 if Thearch.REGZERO != 0 { 1064 // cpu has a dedicated zero register 1065 Nodreg(&nodr, Types[TUINT], Thearch.REGZERO) 1066 } else { 1067 // no dedicated zero register 1068 var zero Node 1069 Nodconst(&zero, nl.Type, 0) 1070 Regalloc(&nodr, Types[TUINT], nil) 1071 Thearch.Gmove(&zero, &nodr) 1072 defer Regfree(&nodr) 1073 } 1074 1075 emitVardef() 1076 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1077 nodl.Type = t 1078 nodl.Xoffset = lbase + offset 1079 nodr.Type = t 1080 if Isfloat[t.Etype] { 1081 // TODO(rsc): Cache zero register like we do for integers? 1082 Clearslim(&nodl) 1083 } else { 1084 Thearch.Gmove(&nodr, &nodl) 1085 } 1086 return true 1087 }) 1088 return true 1089 } 1090 1091 // Special case: assignment of string constant. 1092 if isConstString { 1093 emitVardef() 1094 1095 // base 1096 nodl.Type = Ptrto(Types[TUINT8]) 1097 Regalloc(&nodr, Types[Tptr], nil) 1098 p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr) 1099 Datastring(nr.Val().U.(string), &p.From) 1100 p.From.Type = obj.TYPE_ADDR 1101 Thearch.Gmove(&nodr, &nodl) 1102 Regfree(&nodr) 1103 1104 // length 1105 nodl.Type = Types[Simtype[TUINT]] 1106 nodl.Xoffset += int64(Array_nel) - int64(Array_array) 1107 Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string)))) 1108 Thearch.Gmove(&nodr, &nodl) 1109 return true 1110 } 1111 1112 // General case: copy nl = nr. 1113 nodr = *nr 1114 if !cadable(nr) { 1115 if nr.Ullman >= UINF && nodl.Op == OINDREG { 1116 Fatalf("miscompile") 1117 } 1118 Igen(nr, &nodr, nil) 1119 defer Regfree(&nodr) 1120 } 1121 rbase := nodr.Xoffset 1122 1123 if nodl.Op == 0 { 1124 Igen(nl, &nodl, nil) 1125 defer Regfree(&nodl) 1126 lbase = nodl.Xoffset 1127 } 1128 1129 emitVardef() 1130 var ( 1131 ptrType *Type 1132 ptrOffset int64 1133 ) 1134 visitComponents(nl.Type, 0, func(t *Type, offset int64) bool { 1135 if wb && Simtype[t.Etype] == Tptr && t != itable { 1136 if ptrType != nil { 1137 Fatalf("componentgen_wb %v", Tconv(nl.Type, 0)) 1138 } 1139 ptrType = t 1140 ptrOffset = offset 1141 return true 1142 } 1143 nodl.Type = t 1144 nodl.Xoffset = lbase + offset 1145 nodr.Type = t 1146 nodr.Xoffset = rbase + offset 1147 Thearch.Gmove(&nodr, &nodl) 1148 return true 1149 }) 1150 if ptrType != nil { 1151 nodl.Type = ptrType 1152 nodl.Xoffset = lbase + ptrOffset 1153 nodr.Type = ptrType 1154 nodr.Xoffset = rbase + ptrOffset 1155 cgen_wbptr(&nodr, &nodl) 1156 } 1157 return true 1158 } 1159 1160 // visitComponents walks the individual components of the type t, 1161 // walking into array elements, struct fields, the real and imaginary 1162 // parts of complex numbers, and on 32-bit systems the high and 1163 // low halves of 64-bit integers. 1164 // It calls f for each such component, passing the component (aka element) 1165 // type and memory offset, assuming t starts at startOffset. 1166 // If f ever returns false, visitComponents returns false without any more 1167 // calls to f. Otherwise visitComponents returns true. 1168 func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool { 1169 switch t.Etype { 1170 case TINT64: 1171 if Widthreg == 8 { 1172 break 1173 } 1174 // NOTE: Assuming little endian (signed top half at offset 4). 1175 // We don't have any 32-bit big-endian systems. 1176 if Thearch.Thechar != '5' && Thearch.Thechar != '8' { 1177 Fatalf("unknown 32-bit architecture") 1178 } 1179 return f(Types[TUINT32], startOffset) && 1180 f(Types[TINT32], startOffset+4) 1181 1182 case TUINT64: 1183 if Widthreg == 8 { 1184 break 1185 } 1186 return f(Types[TUINT32], startOffset) && 1187 f(Types[TUINT32], startOffset+4) 1188 1189 case TCOMPLEX64: 1190 return f(Types[TFLOAT32], startOffset) && 1191 f(Types[TFLOAT32], startOffset+4) 1192 1193 case TCOMPLEX128: 1194 return f(Types[TFLOAT64], startOffset) && 1195 f(Types[TFLOAT64], startOffset+8) 1196 1197 case TINTER: 1198 return f(itable, startOffset) && 1199 f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr)) 1200 1201 case TSTRING: 1202 return f(Ptrto(Types[TUINT8]), startOffset) && 1203 f(Types[Simtype[TUINT]], startOffset+int64(Widthptr)) 1204 1205 case TARRAY: 1206 if Isslice(t) { 1207 return f(Ptrto(t.Type), startOffset+int64(Array_array)) && 1208 f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) && 1209 f(Types[Simtype[TUINT]], startOffset+int64(Array_cap)) 1210 } 1211 1212 // Short-circuit [1e6]struct{}. 1213 if t.Type.Width == 0 { 1214 return true 1215 } 1216 1217 for i := int64(0); i < t.Bound; i++ { 1218 if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) { 1219 return false 1220 } 1221 } 1222 return true 1223 1224 case TSTRUCT: 1225 if t.Type != nil && t.Type.Width != 0 { 1226 // NOTE(rsc): If this happens, the right thing to do is to say 1227 // startOffset -= t.Type.Width 1228 // but I want to see if it does. 1229 // The old version of componentgen handled this, 1230 // in code introduced in CL 6932045 to fix issue #4518. 1231 // But the test case in issue 4518 does not trigger this anymore, 1232 // so maybe this complication is no longer needed. 1233 Fatalf("struct not at offset 0") 1234 } 1235 1236 for field := t.Type; field != nil; field = field.Down { 1237 if field.Etype != TFIELD { 1238 Fatalf("bad struct") 1239 } 1240 if !visitComponents(field.Type, startOffset+field.Width, f) { 1241 return false 1242 } 1243 } 1244 return true 1245 } 1246 return f(t, startOffset) 1247 } 1248 1249 func cadable(n *Node) bool { 1250 // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can. 1251 return n.Addable && n.Op == ONAME 1252 }