github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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 case ORETJMP: 493 cgen_ret(n); 494 break; 495 496 case OCHECKNIL: 497 cgen_checknil(n->left); 498 } 499 500 ret: 501 if(anyregalloc() != wasregalloc) { 502 dump("node", n); 503 fatal("registers left allocated"); 504 } 505 506 lineno = lno; 507 } 508 509 /* 510 * generate call to non-interface method 511 * proc=0 normal call 512 * proc=1 goroutine run in new proc 513 * proc=2 defer call save away stack 514 */ 515 void 516 cgen_callmeth(Node *n, int proc) 517 { 518 Node n2; 519 Node *l; 520 521 // generate a rewrite in n2 for the method call 522 // (p.f)(...) goes to (f)(p,...) 523 524 l = n->left; 525 if(l->op != ODOTMETH) 526 fatal("cgen_callmeth: not dotmethod: %N"); 527 528 n2 = *n; 529 n2.op = OCALLFUNC; 530 n2.left = l->right; 531 n2.left->type = l->type; 532 533 if(n2.left->op == ONAME) 534 n2.left->class = PFUNC; 535 cgen_call(&n2, proc); 536 } 537 538 /* 539 * generate code to start new proc running call n. 540 */ 541 static void 542 cgen_proc(Node *n, int proc) 543 { 544 switch(n->left->op) { 545 default: 546 fatal("cgen_proc: unknown call %O", n->left->op); 547 548 case OCALLMETH: 549 cgen_callmeth(n->left, proc); 550 break; 551 552 case OCALLINTER: 553 cgen_callinter(n->left, N, proc); 554 break; 555 556 case OCALLFUNC: 557 cgen_call(n->left, proc); 558 break; 559 } 560 561 } 562 563 /* 564 * generate declaration. 565 * nothing to do for on-stack automatics, 566 * but might have to allocate heap copy 567 * for escaped variables. 568 */ 569 static void 570 cgen_dcl(Node *n) 571 { 572 if(debug['g']) 573 dump("\ncgen-dcl", n); 574 if(n->op != ONAME) { 575 dump("cgen_dcl", n); 576 fatal("cgen_dcl"); 577 } 578 if(!(n->class & PHEAP)) 579 return; 580 if(n->alloc == nil) 581 n->alloc = callnew(n->type); 582 cgen_as(n->heapaddr, n->alloc); 583 } 584 585 /* 586 * generate discard of value 587 */ 588 static void 589 cgen_discard(Node *nr) 590 { 591 Node tmp; 592 593 if(nr == N) 594 return; 595 596 switch(nr->op) { 597 case ONAME: 598 if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF) 599 gused(nr); 600 break; 601 602 // unary 603 case OADD: 604 case OAND: 605 case ODIV: 606 case OEQ: 607 case OGE: 608 case OGT: 609 case OLE: 610 case OLSH: 611 case OLT: 612 case OMOD: 613 case OMUL: 614 case ONE: 615 case OOR: 616 case ORSH: 617 case OSUB: 618 case OXOR: 619 cgen_discard(nr->left); 620 cgen_discard(nr->right); 621 break; 622 623 // binary 624 case OCAP: 625 case OCOM: 626 case OLEN: 627 case OMINUS: 628 case ONOT: 629 case OPLUS: 630 cgen_discard(nr->left); 631 break; 632 633 // special enough to just evaluate 634 default: 635 tempname(&tmp, nr->type); 636 cgen_as(&tmp, nr); 637 gused(&tmp); 638 } 639 } 640 641 /* 642 * clearslim generates code to zero a slim node. 643 */ 644 void 645 clearslim(Node *n) 646 { 647 Node z; 648 Mpflt zero; 649 650 memset(&z, 0, sizeof(z)); 651 z.op = OLITERAL; 652 z.type = n->type; 653 z.addable = 1; 654 655 switch(simtype[n->type->etype]) { 656 case TCOMPLEX64: 657 case TCOMPLEX128: 658 z.val.u.cval = mal(sizeof(*z.val.u.cval)); 659 mpmovecflt(&z.val.u.cval->real, 0.0); 660 mpmovecflt(&z.val.u.cval->imag, 0.0); 661 break; 662 663 case TFLOAT32: 664 case TFLOAT64: 665 mpmovecflt(&zero, 0.0); 666 z.val.ctype = CTFLT; 667 z.val.u.fval = &zero; 668 break; 669 670 case TPTR32: 671 case TPTR64: 672 case TCHAN: 673 case TMAP: 674 z.val.ctype = CTNIL; 675 break; 676 677 case TBOOL: 678 z.val.ctype = CTBOOL; 679 break; 680 681 case TINT8: 682 case TINT16: 683 case TINT32: 684 case TINT64: 685 case TUINT8: 686 case TUINT16: 687 case TUINT32: 688 case TUINT64: 689 z.val.ctype = CTINT; 690 z.val.u.xval = mal(sizeof(*z.val.u.xval)); 691 mpmovecfix(z.val.u.xval, 0); 692 break; 693 694 default: 695 fatal("clearslim called on type %T", n->type); 696 } 697 698 ullmancalc(&z); 699 cgen(&z, n); 700 } 701 702 /* 703 * generate assignment: 704 * nl = nr 705 * nr == N means zero nl. 706 */ 707 void 708 cgen_as(Node *nl, Node *nr) 709 { 710 Type *tl; 711 712 if(debug['g']) { 713 dump("cgen_as", nl); 714 dump("cgen_as = ", nr); 715 } 716 717 while(nr != N && nr->op == OCONVNOP) 718 nr = nr->left; 719 720 if(nl == N || isblank(nl)) { 721 cgen_discard(nr); 722 return; 723 } 724 725 if(nr == N || isnil(nr)) { 726 // externals and heaps should already be clear 727 if(nr == N) { 728 if(nl->class == PEXTERN) 729 return; 730 if(nl->class & PHEAP) 731 return; 732 } 733 734 tl = nl->type; 735 if(tl == T) 736 return; 737 if(isfat(tl)) { 738 clearfat(nl); 739 return; 740 } 741 clearslim(nl); 742 return; 743 } 744 745 tl = nl->type; 746 if(tl == T) 747 return; 748 749 cgen(nr, nl); 750 } 751 752 /* 753 * generate: 754 * res = iface{typ, data} 755 * n->left is typ 756 * n->right is data 757 */ 758 void 759 cgen_eface(Node *n, Node *res) 760 { 761 /* 762 * the right node of an eface may contain function calls that uses res as an argument, 763 * so it's important that it is done first 764 */ 765 Node dst; 766 dst = *res; 767 dst.type = types[tptr]; 768 dst.xoffset += widthptr; 769 cgen(n->right, &dst); 770 dst.xoffset -= widthptr; 771 cgen(n->left, &dst); 772 } 773 774 /* 775 * generate: 776 * res = s[lo, hi]; 777 * n->left is s 778 * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) 779 * caller (cgen) guarantees res is an addable ONAME. 780 * 781 * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. 782 */ 783 void 784 cgen_slice(Node *n, Node *res) 785 { 786 Node src, dst, *cap, *len, *offs, *add; 787 788 cap = n->list->n; 789 len = n->list->next->n; 790 offs = N; 791 if(n->list->next->next) 792 offs = n->list->next->next->n; 793 794 // dst.len = hi [ - lo ] 795 dst = *res; 796 dst.xoffset += Array_nel; 797 dst.type = types[simtype[TUINT]]; 798 cgen(len, &dst); 799 800 if(n->op != OSLICESTR) { 801 // dst.cap = cap [ - lo ] 802 dst = *res; 803 dst.xoffset += Array_cap; 804 dst.type = types[simtype[TUINT]]; 805 cgen(cap, &dst); 806 } 807 808 // dst.array = src.array [ + lo *width ] 809 dst = *res; 810 dst.xoffset += Array_array; 811 dst.type = types[TUINTPTR]; 812 813 if(isnil(n->left)) { 814 tempname(&src, n->left->type); 815 cgen(n->left, &src); 816 } else 817 src = *n->left; 818 if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR) 819 src.xoffset += Array_array; 820 src.type = types[TUINTPTR]; 821 822 if(n->op == OSLICEARR || n->op == OSLICE3ARR) { 823 if(!isptr[n->left->type->etype]) 824 fatal("slicearr is supposed to work on pointer: %+N\n", n); 825 cgen(&src, &dst); 826 cgen_checknil(&dst); 827 if(offs != N) { 828 add = nod(OADD, &dst, offs); 829 typecheck(&add, Erv); 830 cgen(add, &dst); 831 } 832 } else if(offs == N) { 833 cgen(&src, &dst); 834 } else { 835 add = nod(OADD, &src, offs); 836 typecheck(&add, Erv); 837 cgen(add, &dst); 838 } 839 } 840 841 /* 842 * gather series of offsets 843 * >=0 is direct addressed field 844 * <0 is pointer to next field (+1) 845 */ 846 int 847 dotoffset(Node *n, int64 *oary, Node **nn) 848 { 849 int i; 850 851 switch(n->op) { 852 case ODOT: 853 if(n->xoffset == BADWIDTH) { 854 dump("bad width in dotoffset", n); 855 fatal("bad width in dotoffset"); 856 } 857 i = dotoffset(n->left, oary, nn); 858 if(i > 0) { 859 if(oary[i-1] >= 0) 860 oary[i-1] += n->xoffset; 861 else 862 oary[i-1] -= n->xoffset; 863 break; 864 } 865 if(i < 10) 866 oary[i++] = n->xoffset; 867 break; 868 869 case ODOTPTR: 870 if(n->xoffset == BADWIDTH) { 871 dump("bad width in dotoffset", n); 872 fatal("bad width in dotoffset"); 873 } 874 i = dotoffset(n->left, oary, nn); 875 if(i < 10) 876 oary[i++] = -(n->xoffset+1); 877 break; 878 879 default: 880 *nn = n; 881 return 0; 882 } 883 if(i >= 10) 884 *nn = N; 885 return i; 886 } 887 888 /* 889 * make a new off the books 890 */ 891 void 892 tempname(Node *nn, Type *t) 893 { 894 Node *n; 895 Sym *s; 896 897 if(curfn == N) 898 fatal("no curfn for tempname"); 899 900 if(t == T) { 901 yyerror("tempname called with nil type"); 902 t = types[TINT32]; 903 } 904 905 // give each tmp a different name so that there 906 // a chance to registerizer them 907 snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); 908 statuniqgen++; 909 s = lookup(namebuf); 910 n = nod(ONAME, N, N); 911 n->sym = s; 912 s->def = n; 913 n->type = t; 914 n->class = PAUTO; 915 n->addable = 1; 916 n->ullman = 1; 917 n->esc = EscNever; 918 n->curfn = curfn; 919 curfn->dcl = list(curfn->dcl, n); 920 921 dowidth(t); 922 n->xoffset = 0; 923 *nn = *n; 924 } 925 926 Node* 927 temp(Type *t) 928 { 929 Node *n; 930 931 n = nod(OXXX, N, N); 932 tempname(n, t); 933 n->sym->def->used = 1; 934 return n; 935 }