github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/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 if(isblanksym(n->left->sym)) 305 break; 306 307 lab = newlab(n); 308 309 // if there are pending gotos, resolve them all to the current pc. 310 for(p1=lab->gotopc; p1; p1=p2) { 311 p2 = unpatch(p1); 312 patch(p1, pc); 313 } 314 lab->gotopc = P; 315 if(lab->labelpc == P) 316 lab->labelpc = pc; 317 318 if(n->defn) { 319 switch(n->defn->op) { 320 case OFOR: 321 case OSWITCH: 322 case OSELECT: 323 // so stmtlabel can find the label 324 n->defn->sym = lab->sym; 325 } 326 } 327 break; 328 329 case OGOTO: 330 // if label is defined, emit jump to it. 331 // otherwise save list of pending gotos in lab->gotopc. 332 // the list is linked through the normal jump target field 333 // to avoid a second list. (the jumps are actually still 334 // valid code, since they're just going to another goto 335 // to the same label. we'll unwind it when we learn the pc 336 // of the label in the OLABEL case above.) 337 lab = newlab(n); 338 if(lab->labelpc != P) 339 gjmp(lab->labelpc); 340 else 341 lab->gotopc = gjmp(lab->gotopc); 342 break; 343 344 case OBREAK: 345 if(n->left != N) { 346 lab = n->left->sym->label; 347 if(lab == L) { 348 yyerror("break label not defined: %S", n->left->sym); 349 break; 350 } 351 lab->used = 1; 352 if(lab->breakpc == P) { 353 yyerror("invalid break label %S", n->left->sym); 354 break; 355 } 356 gjmp(lab->breakpc); 357 break; 358 } 359 if(breakpc == P) { 360 yyerror("break is not in a loop"); 361 break; 362 } 363 gjmp(breakpc); 364 break; 365 366 case OCONTINUE: 367 if(n->left != N) { 368 lab = n->left->sym->label; 369 if(lab == L) { 370 yyerror("continue label not defined: %S", n->left->sym); 371 break; 372 } 373 lab->used = 1; 374 if(lab->continpc == P) { 375 yyerror("invalid continue label %S", n->left->sym); 376 break; 377 } 378 gjmp(lab->continpc); 379 break; 380 } 381 if(continpc == P) { 382 yyerror("continue is not in a loop"); 383 break; 384 } 385 gjmp(continpc); 386 break; 387 388 case OFOR: 389 sbreak = breakpc; 390 p1 = gjmp(P); // goto test 391 breakpc = gjmp(P); // break: goto done 392 scontin = continpc; 393 continpc = pc; 394 395 // define break and continue labels 396 if((lab = stmtlabel(n)) != L) { 397 lab->breakpc = breakpc; 398 lab->continpc = continpc; 399 } 400 gen(n->nincr); // contin: incr 401 patch(p1, pc); // test: 402 bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break 403 genlist(n->nbody); // body 404 gjmp(continpc); 405 patch(breakpc, pc); // done: 406 continpc = scontin; 407 breakpc = sbreak; 408 if(lab) { 409 lab->breakpc = P; 410 lab->continpc = P; 411 } 412 break; 413 414 case OIF: 415 p1 = gjmp(P); // goto test 416 p2 = gjmp(P); // p2: goto else 417 patch(p1, pc); // test: 418 bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2 419 genlist(n->nbody); // then 420 p3 = gjmp(P); // goto done 421 patch(p2, pc); // else: 422 genlist(n->nelse); // else 423 patch(p3, pc); // done: 424 break; 425 426 case OSWITCH: 427 sbreak = breakpc; 428 p1 = gjmp(P); // goto test 429 breakpc = gjmp(P); // break: goto done 430 431 // define break label 432 if((lab = stmtlabel(n)) != L) 433 lab->breakpc = breakpc; 434 435 patch(p1, pc); // test: 436 genlist(n->nbody); // switch(test) body 437 patch(breakpc, pc); // done: 438 breakpc = sbreak; 439 if(lab != L) 440 lab->breakpc = P; 441 break; 442 443 case OSELECT: 444 sbreak = breakpc; 445 p1 = gjmp(P); // goto test 446 breakpc = gjmp(P); // break: goto done 447 448 // define break label 449 if((lab = stmtlabel(n)) != L) 450 lab->breakpc = breakpc; 451 452 patch(p1, pc); // test: 453 genlist(n->nbody); // select() body 454 patch(breakpc, pc); // done: 455 breakpc = sbreak; 456 if(lab != L) 457 lab->breakpc = P; 458 break; 459 460 case OASOP: 461 cgen_asop(n); 462 break; 463 464 case ODCL: 465 cgen_dcl(n->left); 466 break; 467 468 case OAS: 469 if(gen_as_init(n)) 470 break; 471 cgen_as(n->left, n->right); 472 break; 473 474 case OCALLMETH: 475 cgen_callmeth(n, 0); 476 break; 477 478 case OCALLINTER: 479 cgen_callinter(n, N, 0); 480 break; 481 482 case OCALLFUNC: 483 cgen_call(n, 0); 484 break; 485 486 case OPROC: 487 cgen_proc(n, 1); 488 break; 489 490 case ODEFER: 491 cgen_proc(n, 2); 492 break; 493 494 case ORETURN: 495 case ORETJMP: 496 cgen_ret(n); 497 break; 498 499 case OCHECKNIL: 500 cgen_checknil(n->left); 501 break; 502 503 case OVARKILL: 504 gvarkill(n->left); 505 break; 506 } 507 508 ret: 509 if(anyregalloc() != wasregalloc) { 510 dump("node", n); 511 fatal("registers left allocated"); 512 } 513 514 lineno = lno; 515 } 516 517 /* 518 * generate call to non-interface method 519 * proc=0 normal call 520 * proc=1 goroutine run in new proc 521 * proc=2 defer call save away stack 522 */ 523 void 524 cgen_callmeth(Node *n, int proc) 525 { 526 Node n2; 527 Node *l; 528 529 // generate a rewrite in n2 for the method call 530 // (p.f)(...) goes to (f)(p,...) 531 532 l = n->left; 533 if(l->op != ODOTMETH) 534 fatal("cgen_callmeth: not dotmethod: %N"); 535 536 n2 = *n; 537 n2.op = OCALLFUNC; 538 n2.left = l->right; 539 n2.left->type = l->type; 540 541 if(n2.left->op == ONAME) 542 n2.left->class = PFUNC; 543 cgen_call(&n2, proc); 544 } 545 546 /* 547 * generate code to start new proc running call n. 548 */ 549 static void 550 cgen_proc(Node *n, int proc) 551 { 552 switch(n->left->op) { 553 default: 554 fatal("cgen_proc: unknown call %O", n->left->op); 555 556 case OCALLMETH: 557 cgen_callmeth(n->left, proc); 558 break; 559 560 case OCALLINTER: 561 cgen_callinter(n->left, N, proc); 562 break; 563 564 case OCALLFUNC: 565 cgen_call(n->left, proc); 566 break; 567 } 568 569 } 570 571 /* 572 * generate declaration. 573 * have to allocate heap copy 574 * for escaped variables. 575 */ 576 static void 577 cgen_dcl(Node *n) 578 { 579 if(debug['g']) 580 dump("\ncgen-dcl", n); 581 if(n->op != ONAME) { 582 dump("cgen_dcl", n); 583 fatal("cgen_dcl"); 584 } 585 if(!(n->class & PHEAP)) 586 return; 587 if(n->alloc == nil) 588 n->alloc = callnew(n->type); 589 cgen_as(n->heapaddr, n->alloc); 590 } 591 592 /* 593 * generate discard of value 594 */ 595 static void 596 cgen_discard(Node *nr) 597 { 598 Node tmp; 599 600 if(nr == N) 601 return; 602 603 switch(nr->op) { 604 case ONAME: 605 if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF) 606 gused(nr); 607 break; 608 609 // unary 610 case OADD: 611 case OAND: 612 case ODIV: 613 case OEQ: 614 case OGE: 615 case OGT: 616 case OLE: 617 case OLSH: 618 case OLT: 619 case OMOD: 620 case OMUL: 621 case ONE: 622 case OOR: 623 case ORSH: 624 case OSUB: 625 case OXOR: 626 cgen_discard(nr->left); 627 cgen_discard(nr->right); 628 break; 629 630 // binary 631 case OCAP: 632 case OCOM: 633 case OLEN: 634 case OMINUS: 635 case ONOT: 636 case OPLUS: 637 cgen_discard(nr->left); 638 break; 639 640 case OIND: 641 cgen_checknil(nr->left); 642 break; 643 644 // special enough to just evaluate 645 default: 646 tempname(&tmp, nr->type); 647 cgen_as(&tmp, nr); 648 gused(&tmp); 649 } 650 } 651 652 /* 653 * clearslim generates code to zero a slim node. 654 */ 655 void 656 clearslim(Node *n) 657 { 658 Node z; 659 Mpflt zero; 660 661 memset(&z, 0, sizeof(z)); 662 z.op = OLITERAL; 663 z.type = n->type; 664 z.addable = 1; 665 666 switch(simtype[n->type->etype]) { 667 case TCOMPLEX64: 668 case TCOMPLEX128: 669 z.val.u.cval = mal(sizeof(*z.val.u.cval)); 670 mpmovecflt(&z.val.u.cval->real, 0.0); 671 mpmovecflt(&z.val.u.cval->imag, 0.0); 672 break; 673 674 case TFLOAT32: 675 case TFLOAT64: 676 mpmovecflt(&zero, 0.0); 677 z.val.ctype = CTFLT; 678 z.val.u.fval = &zero; 679 break; 680 681 case TPTR32: 682 case TPTR64: 683 case TCHAN: 684 case TMAP: 685 z.val.ctype = CTNIL; 686 break; 687 688 case TBOOL: 689 z.val.ctype = CTBOOL; 690 break; 691 692 case TINT8: 693 case TINT16: 694 case TINT32: 695 case TINT64: 696 case TUINT8: 697 case TUINT16: 698 case TUINT32: 699 case TUINT64: 700 z.val.ctype = CTINT; 701 z.val.u.xval = mal(sizeof(*z.val.u.xval)); 702 mpmovecfix(z.val.u.xval, 0); 703 break; 704 705 default: 706 fatal("clearslim called on type %T", n->type); 707 } 708 709 ullmancalc(&z); 710 cgen(&z, n); 711 } 712 713 /* 714 * generate assignment: 715 * nl = nr 716 * nr == N means zero nl. 717 */ 718 void 719 cgen_as(Node *nl, Node *nr) 720 { 721 Type *tl; 722 723 if(debug['g']) { 724 dump("cgen_as", nl); 725 dump("cgen_as = ", nr); 726 } 727 728 while(nr != N && nr->op == OCONVNOP) 729 nr = nr->left; 730 731 if(nl == N || isblank(nl)) { 732 cgen_discard(nr); 733 return; 734 } 735 736 if(nr == N || isnil(nr)) { 737 // externals and heaps should already be clear 738 if(nr == N) { 739 if(nl->class == PEXTERN) 740 return; 741 if(nl->class & PHEAP) 742 return; 743 } 744 745 tl = nl->type; 746 if(tl == T) 747 return; 748 if(isfat(tl)) { 749 if(nl->op == ONAME) 750 gvardef(nl); 751 clearfat(nl); 752 return; 753 } 754 clearslim(nl); 755 return; 756 } 757 758 tl = nl->type; 759 if(tl == T) 760 return; 761 762 cgen(nr, nl); 763 } 764 765 /* 766 * generate: 767 * res = iface{typ, data} 768 * n->left is typ 769 * n->right is data 770 */ 771 void 772 cgen_eface(Node *n, Node *res) 773 { 774 /* 775 * the right node of an eface may contain function calls that uses res as an argument, 776 * so it's important that it is done first 777 */ 778 Node dst; 779 Node *tmp; 780 781 tmp = temp(types[tptr]); 782 cgen(n->right, tmp); 783 784 gvardef(res); 785 786 dst = *res; 787 dst.type = types[tptr]; 788 dst.xoffset += widthptr; 789 cgen(tmp, &dst); 790 791 dst.xoffset -= widthptr; 792 cgen(n->left, &dst); 793 } 794 795 /* 796 * generate: 797 * res = s[lo, hi]; 798 * n->left is s 799 * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) 800 * caller (cgen) guarantees res is an addable ONAME. 801 * 802 * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. 803 */ 804 void 805 cgen_slice(Node *n, Node *res) 806 { 807 Node src, dst, *cap, *len, *offs, *add, *base; 808 809 cap = n->list->n; 810 len = n->list->next->n; 811 offs = N; 812 if(n->list->next->next) 813 offs = n->list->next->next->n; 814 815 // evaluate base pointer first, because it is the only 816 // possibly complex expression. once that is evaluated 817 // and stored, updating the len and cap can be done 818 // without making any calls, so without doing anything that 819 // might cause preemption or garbage collection. 820 // this makes the whole slice update atomic as far as the 821 // garbage collector can see. 822 823 base = temp(types[TUINTPTR]); 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 if(offs != N) { 839 add = nod(OADD, base, offs); 840 typecheck(&add, Erv); 841 cgen(add, base); 842 } 843 } else if(offs == N) { 844 src.type = types[tptr]; 845 cgen(&src, base); 846 } else { 847 src.type = types[tptr]; 848 add = nod(OADDPTR, &src, offs); 849 typecheck(&add, Erv); 850 cgen(add, base); 851 } 852 853 // committed to the update 854 gvardef(res); 855 856 // dst.array = src.array [ + lo *width ] 857 dst = *res; 858 dst.xoffset += Array_array; 859 dst.type = types[tptr]; 860 861 cgen(base, &dst); 862 863 // dst.len = hi [ - lo ] 864 dst = *res; 865 dst.xoffset += Array_nel; 866 dst.type = types[simtype[TUINT]]; 867 cgen(len, &dst); 868 869 if(n->op != OSLICESTR) { 870 // dst.cap = cap [ - lo ] 871 dst = *res; 872 dst.xoffset += Array_cap; 873 dst.type = types[simtype[TUINT]]; 874 cgen(cap, &dst); 875 } 876 } 877 878 /* 879 * gather series of offsets 880 * >=0 is direct addressed field 881 * <0 is pointer to next field (+1) 882 */ 883 int 884 dotoffset(Node *n, int64 *oary, Node **nn) 885 { 886 int i; 887 888 switch(n->op) { 889 case ODOT: 890 if(n->xoffset == BADWIDTH) { 891 dump("bad width in dotoffset", n); 892 fatal("bad width in dotoffset"); 893 } 894 i = dotoffset(n->left, oary, nn); 895 if(i > 0) { 896 if(oary[i-1] >= 0) 897 oary[i-1] += n->xoffset; 898 else 899 oary[i-1] -= n->xoffset; 900 break; 901 } 902 if(i < 10) 903 oary[i++] = n->xoffset; 904 break; 905 906 case ODOTPTR: 907 if(n->xoffset == BADWIDTH) { 908 dump("bad width in dotoffset", n); 909 fatal("bad width in dotoffset"); 910 } 911 i = dotoffset(n->left, oary, nn); 912 if(i < 10) 913 oary[i++] = -(n->xoffset+1); 914 break; 915 916 default: 917 *nn = n; 918 return 0; 919 } 920 if(i >= 10) 921 *nn = N; 922 return i; 923 } 924 925 /* 926 * make a new off the books 927 */ 928 void 929 tempname(Node *nn, Type *t) 930 { 931 Node *n; 932 Sym *s; 933 934 if(curfn == N) 935 fatal("no curfn for tempname"); 936 937 if(t == T) { 938 yyerror("tempname called with nil type"); 939 t = types[TINT32]; 940 } 941 942 // give each tmp a different name so that there 943 // a chance to registerizer them 944 snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); 945 statuniqgen++; 946 s = lookup(namebuf); 947 n = nod(ONAME, N, N); 948 n->sym = s; 949 s->def = n; 950 n->type = t; 951 n->class = PAUTO; 952 n->addable = 1; 953 n->ullman = 1; 954 n->esc = EscNever; 955 n->curfn = curfn; 956 curfn->dcl = list(curfn->dcl, n); 957 958 dowidth(t); 959 n->xoffset = 0; 960 *nn = *n; 961 } 962 963 Node* 964 temp(Type *t) 965 { 966 Node *n; 967 968 n = nod(OXXX, N, N); 969 tempname(n, t); 970 n->sym->def->used = 1; 971 return n->orig; 972 }