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