github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/gc/gen.c (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 /* 6 * portable half of code generator. 7 * mainly statements and control flow. 8 */ 9 10 #include <u.h> 11 #include <libc.h> 12 #include "go.h" 13 14 static void cgen_dcl(Node *n); 15 static void cgen_proc(Node *n, int proc); 16 static void checkgoto(Node*, Node*); 17 18 static Label *labellist; 19 static Label *lastlabel; 20 21 Node* 22 sysfunc(char *name) 23 { 24 Node *n; 25 26 n = newname(pkglookup(name, runtimepkg)); 27 n->class = PFUNC; 28 return n; 29 } 30 31 /* 32 * the address of n has been taken and might be used after 33 * the current function returns. mark any local vars 34 * as needing to move to the heap. 35 */ 36 void 37 addrescapes(Node *n) 38 { 39 char buf[100]; 40 Node *oldfn; 41 42 switch(n->op) { 43 default: 44 // probably a type error already. 45 // dump("addrescapes", n); 46 break; 47 48 case ONAME: 49 if(n == nodfp) 50 break; 51 52 // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. 53 // on PPARAM it means something different. 54 if(n->class == PAUTO && n->esc == EscNever) 55 break; 56 57 if(debug['N'] && n->esc != EscUnknown) 58 fatal("without escape analysis, only PAUTO's should have esc: %N", n); 59 60 switch(n->class) { 61 case PPARAMREF: 62 addrescapes(n->defn); 63 break; 64 case PPARAM: 65 case PPARAMOUT: 66 // if func param, need separate temporary 67 // to hold heap pointer. 68 // the function type has already been checked 69 // (we're in the function body) 70 // so the param already has a valid xoffset. 71 72 // expression to refer to stack copy 73 n->stackparam = nod(OPARAM, n, N); 74 n->stackparam->type = n->type; 75 n->stackparam->addable = 1; 76 if(n->xoffset == BADWIDTH) 77 fatal("addrescapes before param assignment"); 78 n->stackparam->xoffset = n->xoffset; 79 // fallthrough 80 81 case PAUTO: 82 n->class |= PHEAP; 83 n->addable = 0; 84 n->ullman = 2; 85 n->xoffset = 0; 86 87 // create stack variable to hold pointer to heap 88 oldfn = curfn; 89 curfn = n->curfn; 90 n->heapaddr = temp(ptrto(n->type)); 91 snprint(buf, sizeof buf, "&%S", n->sym); 92 n->heapaddr->sym = lookup(buf); 93 n->heapaddr->orig->sym = n->heapaddr->sym; 94 if(!debug['N']) 95 n->esc = EscHeap; 96 if(debug['m']) 97 print("%L: moved to heap: %N\n", n->lineno, n); 98 curfn = oldfn; 99 break; 100 } 101 break; 102 103 case OIND: 104 case ODOTPTR: 105 break; 106 107 case ODOT: 108 case OINDEX: 109 // ODOTPTR has already been introduced, 110 // so these are the non-pointer ODOT and OINDEX. 111 // In &x[0], if x is a slice, then x does not 112 // escape--the pointer inside x does, but that 113 // is always a heap pointer anyway. 114 if(!isslice(n->left->type)) 115 addrescapes(n->left); 116 break; 117 } 118 } 119 120 void 121 clearlabels(void) 122 { 123 Label *l; 124 125 for(l=labellist; l!=L; l=l->link) 126 l->sym->label = L; 127 128 labellist = L; 129 lastlabel = L; 130 } 131 132 static Label* 133 newlab(Node *n) 134 { 135 Sym *s; 136 Label *lab; 137 138 s = n->left->sym; 139 if((lab = s->label) == L) { 140 lab = mal(sizeof(*lab)); 141 if(lastlabel == nil) 142 labellist = lab; 143 else 144 lastlabel->link = lab; 145 lastlabel = lab; 146 lab->sym = s; 147 s->label = lab; 148 } 149 150 if(n->op == OLABEL) { 151 if(lab->def != N) 152 yyerror("label %S already defined at %L", s, lab->def->lineno); 153 else 154 lab->def = n; 155 } else 156 lab->use = list(lab->use, n); 157 158 return lab; 159 } 160 161 void 162 checklabels(void) 163 { 164 Label *lab; 165 NodeList *l; 166 167 for(lab=labellist; lab!=L; lab=lab->link) { 168 if(lab->def == N) { 169 for(l=lab->use; l; l=l->next) 170 yyerrorl(l->n->lineno, "label %S not defined", lab->sym); 171 continue; 172 } 173 if(lab->use == nil && !lab->used) { 174 yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym); 175 continue; 176 } 177 if(lab->gotopc != P) 178 fatal("label %S never resolved", lab->sym); 179 for(l=lab->use; l; l=l->next) 180 checkgoto(l->n, lab->def); 181 } 182 } 183 184 static void 185 checkgoto(Node *from, Node *to) 186 { 187 int nf, nt; 188 Sym *block, *dcl, *fs, *ts; 189 int lno; 190 191 if(from->sym == to->sym) 192 return; 193 194 nf = 0; 195 for(fs=from->sym; fs; fs=fs->link) 196 nf++; 197 nt = 0; 198 for(fs=to->sym; fs; fs=fs->link) 199 nt++; 200 fs = from->sym; 201 for(; nf > nt; nf--) 202 fs = fs->link; 203 if(fs != to->sym) { 204 lno = lineno; 205 setlineno(from); 206 207 // decide what to complain about. 208 // prefer to complain about 'into block' over declarations, 209 // so scan backward to find most recent block or else dcl. 210 block = S; 211 dcl = S; 212 ts = to->sym; 213 for(; nt > nf; nt--) { 214 if(ts->pkg == nil) 215 block = ts; 216 else 217 dcl = ts; 218 ts = ts->link; 219 } 220 while(ts != fs) { 221 if(ts->pkg == nil) 222 block = ts; 223 else 224 dcl = ts; 225 ts = ts->link; 226 fs = fs->link; 227 } 228 229 if(block) 230 yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno); 231 else 232 yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno); 233 lineno = lno; 234 } 235 } 236 237 static Label* 238 stmtlabel(Node *n) 239 { 240 Label *lab; 241 242 if(n->sym != S) 243 if((lab = n->sym->label) != L) 244 if(lab->def != N) 245 if(lab->def->defn == n) 246 return lab; 247 return L; 248 } 249 250 /* 251 * compile statements 252 */ 253 void 254 genlist(NodeList *l) 255 { 256 for(; l; l=l->next) 257 gen(l->n); 258 } 259 260 void 261 gen(Node *n) 262 { 263 int32 lno; 264 Prog *scontin, *sbreak; 265 Prog *p1, *p2, *p3; 266 Label *lab; 267 int32 wasregalloc; 268 269 //dump("gen", n); 270 271 lno = setlineno(n); 272 wasregalloc = anyregalloc(); 273 274 if(n == N) 275 goto ret; 276 277 if(n->ninit) 278 genlist(n->ninit); 279 280 setlineno(n); 281 282 switch(n->op) { 283 default: 284 fatal("gen: unknown op %+hN", n); 285 break; 286 287 case OCASE: 288 case OFALL: 289 case OXCASE: 290 case OXFALL: 291 case ODCLCONST: 292 case ODCLFUNC: 293 case ODCLTYPE: 294 break; 295 296 case OEMPTY: 297 break; 298 299 case OBLOCK: 300 genlist(n->list); 301 break; 302 303 case OLABEL: 304 lab = newlab(n); 305 306 // if there are pending gotos, resolve them all to the current pc. 307 for(p1=lab->gotopc; p1; p1=p2) { 308 p2 = unpatch(p1); 309 patch(p1, pc); 310 } 311 lab->gotopc = P; 312 if(lab->labelpc == P) 313 lab->labelpc = pc; 314 315 if(n->defn) { 316 switch(n->defn->op) { 317 case OFOR: 318 case OSWITCH: 319 case OSELECT: 320 // so stmtlabel can find the label 321 n->defn->sym = lab->sym; 322 } 323 } 324 break; 325 326 case OGOTO: 327 // if label is defined, emit jump to it. 328 // otherwise save list of pending gotos in lab->gotopc. 329 // the list is linked through the normal jump target field 330 // to avoid a second list. (the jumps are actually still 331 // valid code, since they're just going to another goto 332 // to the same label. we'll unwind it when we learn the pc 333 // of the label in the OLABEL case above.) 334 lab = newlab(n); 335 if(lab->labelpc != P) 336 gjmp(lab->labelpc); 337 else 338 lab->gotopc = gjmp(lab->gotopc); 339 break; 340 341 case OBREAK: 342 if(n->left != N) { 343 lab = n->left->sym->label; 344 if(lab == L) { 345 yyerror("break label not defined: %S", n->left->sym); 346 break; 347 } 348 lab->used = 1; 349 if(lab->breakpc == P) { 350 yyerror("invalid break label %S", n->left->sym); 351 break; 352 } 353 gjmp(lab->breakpc); 354 break; 355 } 356 if(breakpc == P) { 357 yyerror("break is not in a loop"); 358 break; 359 } 360 gjmp(breakpc); 361 break; 362 363 case OCONTINUE: 364 if(n->left != N) { 365 lab = n->left->sym->label; 366 if(lab == L) { 367 yyerror("continue label not defined: %S", n->left->sym); 368 break; 369 } 370 lab->used = 1; 371 if(lab->continpc == P) { 372 yyerror("invalid continue label %S", n->left->sym); 373 break; 374 } 375 gjmp(lab->continpc); 376 break; 377 } 378 if(continpc == P) { 379 yyerror("continue is not in a loop"); 380 break; 381 } 382 gjmp(continpc); 383 break; 384 385 case OFOR: 386 sbreak = breakpc; 387 p1 = gjmp(P); // goto test 388 breakpc = gjmp(P); // break: goto done 389 scontin = continpc; 390 continpc = pc; 391 392 // define break and continue labels 393 if((lab = stmtlabel(n)) != L) { 394 lab->breakpc = breakpc; 395 lab->continpc = continpc; 396 } 397 gen(n->nincr); // contin: incr 398 patch(p1, pc); // test: 399 bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break 400 genlist(n->nbody); // body 401 gjmp(continpc); 402 patch(breakpc, pc); // done: 403 continpc = scontin; 404 breakpc = sbreak; 405 if(lab) { 406 lab->breakpc = P; 407 lab->continpc = P; 408 } 409 break; 410 411 case OIF: 412 p1 = gjmp(P); // goto test 413 p2 = gjmp(P); // p2: goto else 414 patch(p1, pc); // test: 415 bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2 416 genlist(n->nbody); // then 417 p3 = gjmp(P); // goto done 418 patch(p2, pc); // else: 419 genlist(n->nelse); // else 420 patch(p3, pc); // done: 421 break; 422 423 case OSWITCH: 424 sbreak = breakpc; 425 p1 = gjmp(P); // goto test 426 breakpc = gjmp(P); // break: goto done 427 428 // define break label 429 if((lab = stmtlabel(n)) != L) 430 lab->breakpc = breakpc; 431 432 patch(p1, pc); // test: 433 genlist(n->nbody); // switch(test) body 434 patch(breakpc, pc); // done: 435 breakpc = sbreak; 436 if(lab != L) 437 lab->breakpc = P; 438 break; 439 440 case OSELECT: 441 sbreak = breakpc; 442 p1 = gjmp(P); // goto test 443 breakpc = gjmp(P); // break: goto done 444 445 // define break label 446 if((lab = stmtlabel(n)) != L) 447 lab->breakpc = breakpc; 448 449 patch(p1, pc); // test: 450 genlist(n->nbody); // select() body 451 patch(breakpc, pc); // done: 452 breakpc = sbreak; 453 if(lab != L) 454 lab->breakpc = P; 455 break; 456 457 case OASOP: 458 cgen_asop(n); 459 break; 460 461 case ODCL: 462 cgen_dcl(n->left); 463 break; 464 465 case OAS: 466 if(gen_as_init(n)) 467 break; 468 cgen_as(n->left, n->right); 469 break; 470 471 case OCALLMETH: 472 cgen_callmeth(n, 0); 473 break; 474 475 case OCALLINTER: 476 cgen_callinter(n, N, 0); 477 break; 478 479 case OCALLFUNC: 480 cgen_call(n, 0); 481 break; 482 483 case OPROC: 484 cgen_proc(n, 1); 485 break; 486 487 case ODEFER: 488 cgen_proc(n, 2); 489 break; 490 491 case ORETURN: 492 cgen_ret(n); 493 break; 494 495 case OCHECKNOTNIL: 496 checkref(n->left, 1); 497 } 498 499 ret: 500 if(anyregalloc() != wasregalloc) { 501 dump("node", n); 502 fatal("registers left allocated"); 503 } 504 505 lineno = lno; 506 } 507 508 /* 509 * generate call to non-interface method 510 * proc=0 normal call 511 * proc=1 goroutine run in new proc 512 * proc=2 defer call save away stack 513 */ 514 void 515 cgen_callmeth(Node *n, int proc) 516 { 517 Node n2; 518 Node *l; 519 520 // generate a rewrite in n2 for the method call 521 // (p.f)(...) goes to (f)(p,...) 522 523 l = n->left; 524 if(l->op != ODOTMETH) 525 fatal("cgen_callmeth: not dotmethod: %N"); 526 527 n2 = *n; 528 n2.op = OCALLFUNC; 529 n2.left = l->right; 530 n2.left->type = l->type; 531 532 if(n2.left->op == ONAME) 533 n2.left->class = PFUNC; 534 cgen_call(&n2, proc); 535 } 536 537 /* 538 * generate code to start new proc running call n. 539 */ 540 static void 541 cgen_proc(Node *n, int proc) 542 { 543 switch(n->left->op) { 544 default: 545 fatal("cgen_proc: unknown call %O", n->left->op); 546 547 case OCALLMETH: 548 cgen_callmeth(n->left, proc); 549 break; 550 551 case OCALLINTER: 552 cgen_callinter(n->left, N, proc); 553 break; 554 555 case OCALLFUNC: 556 cgen_call(n->left, proc); 557 break; 558 } 559 560 } 561 562 /* 563 * generate declaration. 564 * nothing to do for on-stack automatics, 565 * but might have to allocate heap copy 566 * for escaped variables. 567 */ 568 static void 569 cgen_dcl(Node *n) 570 { 571 if(debug['g']) 572 dump("\ncgen-dcl", n); 573 if(n->op != ONAME) { 574 dump("cgen_dcl", n); 575 fatal("cgen_dcl"); 576 } 577 if(!(n->class & PHEAP)) 578 return; 579 if(n->alloc == nil) 580 n->alloc = callnew(n->type); 581 cgen_as(n->heapaddr, n->alloc); 582 } 583 584 /* 585 * generate discard of value 586 */ 587 static void 588 cgen_discard(Node *nr) 589 { 590 Node tmp; 591 592 if(nr == N) 593 return; 594 595 switch(nr->op) { 596 case ONAME: 597 if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF) 598 gused(nr); 599 break; 600 601 // unary 602 case OADD: 603 case OAND: 604 case ODIV: 605 case OEQ: 606 case OGE: 607 case OGT: 608 case OLE: 609 case OLSH: 610 case OLT: 611 case OMOD: 612 case OMUL: 613 case ONE: 614 case OOR: 615 case ORSH: 616 case OSUB: 617 case OXOR: 618 cgen_discard(nr->left); 619 cgen_discard(nr->right); 620 break; 621 622 // binary 623 case OCAP: 624 case OCOM: 625 case OLEN: 626 case OMINUS: 627 case ONOT: 628 case OPLUS: 629 cgen_discard(nr->left); 630 break; 631 632 // special enough to just evaluate 633 default: 634 tempname(&tmp, nr->type); 635 cgen_as(&tmp, nr); 636 gused(&tmp); 637 } 638 } 639 640 /* 641 * clearslim generates code to zero a slim node. 642 */ 643 void 644 clearslim(Node *n) 645 { 646 Node z; 647 Mpflt zero; 648 649 memset(&z, 0, sizeof(z)); 650 z.op = OLITERAL; 651 z.type = n->type; 652 z.addable = 1; 653 654 switch(simtype[n->type->etype]) { 655 case TCOMPLEX64: 656 case TCOMPLEX128: 657 z.val.u.cval = mal(sizeof(*z.val.u.cval)); 658 mpmovecflt(&z.val.u.cval->real, 0.0); 659 mpmovecflt(&z.val.u.cval->imag, 0.0); 660 break; 661 662 case TFLOAT32: 663 case TFLOAT64: 664 mpmovecflt(&zero, 0.0); 665 z.val.ctype = CTFLT; 666 z.val.u.fval = &zero; 667 break; 668 669 case TPTR32: 670 case TPTR64: 671 case TCHAN: 672 case TMAP: 673 z.val.ctype = CTNIL; 674 break; 675 676 case TBOOL: 677 z.val.ctype = CTBOOL; 678 break; 679 680 case TINT8: 681 case TINT16: 682 case TINT32: 683 case TINT64: 684 case TUINT8: 685 case TUINT16: 686 case TUINT32: 687 case TUINT64: 688 z.val.ctype = CTINT; 689 z.val.u.xval = mal(sizeof(*z.val.u.xval)); 690 mpmovecfix(z.val.u.xval, 0); 691 break; 692 693 default: 694 fatal("clearslim called on type %T", n->type); 695 } 696 697 ullmancalc(&z); 698 cgen(&z, n); 699 } 700 701 /* 702 * generate assignment: 703 * nl = nr 704 * nr == N means zero nl. 705 */ 706 void 707 cgen_as(Node *nl, Node *nr) 708 { 709 Type *tl; 710 711 if(debug['g']) { 712 dump("cgen_as", nl); 713 dump("cgen_as = ", nr); 714 } 715 716 while(nr != N && nr->op == OCONVNOP) 717 nr = nr->left; 718 719 if(nl == N || isblank(nl)) { 720 cgen_discard(nr); 721 return; 722 } 723 724 if(nr == N || isnil(nr)) { 725 // externals and heaps should already be clear 726 if(nr == N) { 727 if(nl->class == PEXTERN) 728 return; 729 if(nl->class & PHEAP) 730 return; 731 } 732 733 tl = nl->type; 734 if(tl == T) 735 return; 736 if(isfat(tl)) { 737 clearfat(nl); 738 return; 739 } 740 clearslim(nl); 741 return; 742 } 743 744 tl = nl->type; 745 if(tl == T) 746 return; 747 748 cgen(nr, nl); 749 } 750 751 /* 752 * generate: 753 * res = iface{typ, data} 754 * n->left is typ 755 * n->right is data 756 */ 757 void 758 cgen_eface(Node *n, Node *res) 759 { 760 /* 761 * the right node of an eface may contain function calls that uses res as an argument, 762 * so it's important that it is done first 763 */ 764 Node dst; 765 dst = *res; 766 dst.type = types[tptr]; 767 dst.xoffset += widthptr; 768 cgen(n->right, &dst); 769 dst.xoffset -= widthptr; 770 cgen(n->left, &dst); 771 } 772 773 /* 774 * generate: 775 * res = s[lo, hi]; 776 * n->left is s 777 * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) 778 * caller (cgen) guarantees res is an addable ONAME. 779 */ 780 void 781 cgen_slice(Node *n, Node *res) 782 { 783 Node src, dst, *cap, *len, *offs, *add; 784 785 cap = n->list->n; 786 len = n->list->next->n; 787 offs = N; 788 if(n->list->next->next) 789 offs = n->list->next->next->n; 790 791 // dst.len = hi [ - lo ] 792 dst = *res; 793 dst.xoffset += Array_nel; 794 dst.type = types[simtype[TUINT]]; 795 cgen(len, &dst); 796 797 if(n->op != OSLICESTR) { 798 // dst.cap = cap [ - lo ] 799 dst = *res; 800 dst.xoffset += Array_cap; 801 dst.type = types[simtype[TUINT]]; 802 cgen(cap, &dst); 803 } 804 805 // dst.array = src.array [ + lo *width ] 806 dst = *res; 807 dst.xoffset += Array_array; 808 dst.type = types[TUINTPTR]; 809 810 if(n->op == OSLICEARR) { 811 if(!isptr[n->left->type->etype]) 812 fatal("slicearr is supposed to work on pointer: %+N\n", n); 813 checkref(n->left, 0); 814 } 815 816 if(isnil(n->left)) { 817 tempname(&src, n->left->type); 818 cgen(n->left, &src); 819 } else 820 src = *n->left; 821 src.xoffset += Array_array; 822 src.type = types[TUINTPTR]; 823 824 if(offs == N) { 825 cgen(&src, &dst); 826 } else { 827 add = nod(OADD, &src, offs); 828 typecheck(&add, Erv); 829 cgen(add, &dst); 830 } 831 } 832 833 /* 834 * gather series of offsets 835 * >=0 is direct addressed field 836 * <0 is pointer to next field (+1) 837 */ 838 int 839 dotoffset(Node *n, int64 *oary, Node **nn) 840 { 841 int i; 842 843 switch(n->op) { 844 case ODOT: 845 if(n->xoffset == BADWIDTH) { 846 dump("bad width in dotoffset", n); 847 fatal("bad width in dotoffset"); 848 } 849 i = dotoffset(n->left, oary, nn); 850 if(i > 0) { 851 if(oary[i-1] >= 0) 852 oary[i-1] += n->xoffset; 853 else 854 oary[i-1] -= n->xoffset; 855 break; 856 } 857 if(i < 10) 858 oary[i++] = n->xoffset; 859 break; 860 861 case ODOTPTR: 862 if(n->xoffset == BADWIDTH) { 863 dump("bad width in dotoffset", n); 864 fatal("bad width in dotoffset"); 865 } 866 i = dotoffset(n->left, oary, nn); 867 if(i < 10) 868 oary[i++] = -(n->xoffset+1); 869 break; 870 871 default: 872 *nn = n; 873 return 0; 874 } 875 if(i >= 10) 876 *nn = N; 877 return i; 878 } 879 880 /* 881 * make a new off the books 882 */ 883 void 884 tempname(Node *nn, Type *t) 885 { 886 Node *n; 887 Sym *s; 888 889 if(curfn == N) 890 fatal("no curfn for tempname"); 891 892 if(t == T) { 893 yyerror("tempname called with nil type"); 894 t = types[TINT32]; 895 } 896 897 // give each tmp a different name so that there 898 // a chance to registerizer them 899 snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); 900 statuniqgen++; 901 s = lookup(namebuf); 902 n = nod(ONAME, N, N); 903 n->sym = s; 904 s->def = n; 905 n->type = t; 906 n->class = PAUTO; 907 n->addable = 1; 908 n->ullman = 1; 909 n->esc = EscNever; 910 n->curfn = curfn; 911 curfn->dcl = list(curfn->dcl, n); 912 913 dowidth(t); 914 n->xoffset = 0; 915 *nn = *n; 916 } 917 918 Node* 919 temp(Type *t) 920 { 921 Node *n; 922 923 n = nod(OXXX, N, N); 924 tempname(n, t); 925 n->sym->def->used = 1; 926 return n; 927 }