github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 case OIND: 634 cgen_checknil(nr->left); 635 break; 636 637 // special enough to just evaluate 638 default: 639 tempname(&tmp, nr->type); 640 cgen_as(&tmp, nr); 641 gused(&tmp); 642 } 643 } 644 645 /* 646 * clearslim generates code to zero a slim node. 647 */ 648 void 649 clearslim(Node *n) 650 { 651 Node z; 652 Mpflt zero; 653 654 memset(&z, 0, sizeof(z)); 655 z.op = OLITERAL; 656 z.type = n->type; 657 z.addable = 1; 658 659 switch(simtype[n->type->etype]) { 660 case TCOMPLEX64: 661 case TCOMPLEX128: 662 z.val.u.cval = mal(sizeof(*z.val.u.cval)); 663 mpmovecflt(&z.val.u.cval->real, 0.0); 664 mpmovecflt(&z.val.u.cval->imag, 0.0); 665 break; 666 667 case TFLOAT32: 668 case TFLOAT64: 669 mpmovecflt(&zero, 0.0); 670 z.val.ctype = CTFLT; 671 z.val.u.fval = &zero; 672 break; 673 674 case TPTR32: 675 case TPTR64: 676 case TCHAN: 677 case TMAP: 678 z.val.ctype = CTNIL; 679 break; 680 681 case TBOOL: 682 z.val.ctype = CTBOOL; 683 break; 684 685 case TINT8: 686 case TINT16: 687 case TINT32: 688 case TINT64: 689 case TUINT8: 690 case TUINT16: 691 case TUINT32: 692 case TUINT64: 693 z.val.ctype = CTINT; 694 z.val.u.xval = mal(sizeof(*z.val.u.xval)); 695 mpmovecfix(z.val.u.xval, 0); 696 break; 697 698 default: 699 fatal("clearslim called on type %T", n->type); 700 } 701 702 ullmancalc(&z); 703 cgen(&z, n); 704 } 705 706 /* 707 * generate assignment: 708 * nl = nr 709 * nr == N means zero nl. 710 */ 711 void 712 cgen_as(Node *nl, Node *nr) 713 { 714 Type *tl; 715 716 if(debug['g']) { 717 dump("cgen_as", nl); 718 dump("cgen_as = ", nr); 719 } 720 721 while(nr != N && nr->op == OCONVNOP) 722 nr = nr->left; 723 724 if(nl == N || isblank(nl)) { 725 cgen_discard(nr); 726 return; 727 } 728 729 if(nr == N || isnil(nr)) { 730 // externals and heaps should already be clear 731 if(nr == N) { 732 if(nl->class == PEXTERN) 733 return; 734 if(nl->class & PHEAP) 735 return; 736 } 737 738 tl = nl->type; 739 if(tl == T) 740 return; 741 if(isfat(tl)) { 742 clearfat(nl); 743 return; 744 } 745 clearslim(nl); 746 return; 747 } 748 749 tl = nl->type; 750 if(tl == T) 751 return; 752 753 cgen(nr, nl); 754 } 755 756 /* 757 * generate: 758 * res = iface{typ, data} 759 * n->left is typ 760 * n->right is data 761 */ 762 void 763 cgen_eface(Node *n, Node *res) 764 { 765 /* 766 * the right node of an eface may contain function calls that uses res as an argument, 767 * so it's important that it is done first 768 */ 769 Node dst; 770 dst = *res; 771 dst.type = types[tptr]; 772 dst.xoffset += widthptr; 773 cgen(n->right, &dst); 774 dst.xoffset -= widthptr; 775 cgen(n->left, &dst); 776 } 777 778 /* 779 * generate: 780 * res = s[lo, hi]; 781 * n->left is s 782 * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) 783 * caller (cgen) guarantees res is an addable ONAME. 784 * 785 * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. 786 */ 787 void 788 cgen_slice(Node *n, Node *res) 789 { 790 Node src, dst, *cap, *len, *offs, *add; 791 792 cap = n->list->n; 793 len = n->list->next->n; 794 offs = N; 795 if(n->list->next->next) 796 offs = n->list->next->next->n; 797 798 // dst.len = hi [ - lo ] 799 dst = *res; 800 dst.xoffset += Array_nel; 801 dst.type = types[simtype[TUINT]]; 802 cgen(len, &dst); 803 804 if(n->op != OSLICESTR) { 805 // dst.cap = cap [ - lo ] 806 dst = *res; 807 dst.xoffset += Array_cap; 808 dst.type = types[simtype[TUINT]]; 809 cgen(cap, &dst); 810 } 811 812 // dst.array = src.array [ + lo *width ] 813 dst = *res; 814 dst.xoffset += Array_array; 815 dst.type = types[TUINTPTR]; 816 817 if(isnil(n->left)) { 818 tempname(&src, n->left->type); 819 cgen(n->left, &src); 820 } else 821 src = *n->left; 822 if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR) 823 src.xoffset += Array_array; 824 src.type = types[TUINTPTR]; 825 826 if(n->op == OSLICEARR || n->op == OSLICE3ARR) { 827 if(!isptr[n->left->type->etype]) 828 fatal("slicearr is supposed to work on pointer: %+N\n", n); 829 cgen(&src, &dst); 830 cgen_checknil(&dst); 831 if(offs != N) { 832 add = nod(OADD, &dst, offs); 833 typecheck(&add, Erv); 834 cgen(add, &dst); 835 } 836 } else if(offs == N) { 837 cgen(&src, &dst); 838 } else { 839 add = nod(OADD, &src, offs); 840 typecheck(&add, Erv); 841 cgen(add, &dst); 842 } 843 } 844 845 /* 846 * gather series of offsets 847 * >=0 is direct addressed field 848 * <0 is pointer to next field (+1) 849 */ 850 int 851 dotoffset(Node *n, int64 *oary, Node **nn) 852 { 853 int i; 854 855 switch(n->op) { 856 case ODOT: 857 if(n->xoffset == BADWIDTH) { 858 dump("bad width in dotoffset", n); 859 fatal("bad width in dotoffset"); 860 } 861 i = dotoffset(n->left, oary, nn); 862 if(i > 0) { 863 if(oary[i-1] >= 0) 864 oary[i-1] += n->xoffset; 865 else 866 oary[i-1] -= n->xoffset; 867 break; 868 } 869 if(i < 10) 870 oary[i++] = n->xoffset; 871 break; 872 873 case ODOTPTR: 874 if(n->xoffset == BADWIDTH) { 875 dump("bad width in dotoffset", n); 876 fatal("bad width in dotoffset"); 877 } 878 i = dotoffset(n->left, oary, nn); 879 if(i < 10) 880 oary[i++] = -(n->xoffset+1); 881 break; 882 883 default: 884 *nn = n; 885 return 0; 886 } 887 if(i >= 10) 888 *nn = N; 889 return i; 890 } 891 892 /* 893 * make a new off the books 894 */ 895 void 896 tempname(Node *nn, Type *t) 897 { 898 Node *n; 899 Sym *s; 900 901 if(curfn == N) 902 fatal("no curfn for tempname"); 903 904 if(t == T) { 905 yyerror("tempname called with nil type"); 906 t = types[TINT32]; 907 } 908 909 // give each tmp a different name so that there 910 // a chance to registerizer them 911 snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); 912 statuniqgen++; 913 s = lookup(namebuf); 914 n = nod(ONAME, N, N); 915 n->sym = s; 916 s->def = n; 917 n->type = t; 918 n->class = PAUTO; 919 n->addable = 1; 920 n->ullman = 1; 921 n->esc = EscNever; 922 n->curfn = curfn; 923 curfn->dcl = list(curfn->dcl, n); 924 925 dowidth(t); 926 n->xoffset = 0; 927 *nn = *n; 928 } 929 930 Node* 931 temp(Type *t) 932 { 933 Node *n; 934 935 n = nod(OXXX, N, N); 936 tempname(n, t); 937 n->sym->def->used = 1; 938 return n; 939 }