github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/cc/pgen.c (about) 1 // Inferno utils/6c/sgen.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 #include "gc.h" 32 #include "../../pkg/runtime/funcdata.h" 33 34 enum { BitsPerPointer = 2 }; 35 36 static void dumpgcargs(Type *fn, Sym *sym); 37 38 static Sym* 39 makefuncdatasym(char *namefmt, int64 funcdatakind) 40 { 41 Node nod; 42 Sym *sym; 43 static int32 nsym; 44 static char namebuf[40]; 45 46 snprint(namebuf, sizeof(namebuf), namefmt, nsym++); 47 sym = slookup(namebuf); 48 sym->class = CSTATIC; 49 memset(&nod, 0, sizeof nod); 50 nod.op = ONAME; 51 nod.sym = sym; 52 nod.class = CSTATIC; 53 gins(AFUNCDATA, nodconst(funcdatakind), &nod); 54 linksym(sym)->type = SRODATA; 55 return sym; 56 } 57 58 int 59 hasdotdotdot(void) 60 { 61 Type *t; 62 63 for(t=thisfn->down; t!=T; t=t->down) 64 if(t->etype == TDOT) 65 return 1; 66 return 0; 67 } 68 69 vlong 70 argsize(void) 71 { 72 Type *t; 73 int32 s; 74 75 //print("t=%T\n", thisfn); 76 s = align(0, thisfn->link, Aarg0, nil); 77 for(t=thisfn->down; t!=T; t=t->down) { 78 switch(t->etype) { 79 case TVOID: 80 break; 81 case TDOT: 82 if((textflag & NOSPLIT) == 0) 83 yyerror("function takes ... without textflag NOSPLIT"); 84 return ArgsSizeUnknown; 85 default: 86 s = align(s, t, Aarg1, nil); 87 s = align(s, t, Aarg2, nil); 88 break; 89 } 90 //print(" %d %T\n", s, t); 91 } 92 if(thechar == '6') 93 s = (s+7) & ~7; 94 else 95 s = (s+3) & ~3; 96 return s; 97 } 98 99 void 100 codgen(Node *n, Node *nn) 101 { 102 Prog *sp; 103 Node *n1, nod, nod1; 104 Sym *gcargs; 105 Sym *gclocals; 106 int isvarargs; 107 108 cursafe = 0; 109 curarg = 0; 110 maxargsafe = 0; 111 112 /* 113 * isolate name 114 */ 115 for(n1 = nn;; n1 = n1->left) { 116 if(n1 == Z) { 117 diag(nn, "can't find function name"); 118 return; 119 } 120 if(n1->op == ONAME) 121 break; 122 } 123 nearln = nn->lineno; 124 125 p = gtext(n1->sym, stkoff); 126 sp = p; 127 128 /* 129 * generate funcdata symbol for this function. 130 * data is filled in at the end of codgen(). 131 */ 132 isvarargs = hasdotdotdot(); 133 gcargs = nil; 134 if(!isvarargs) 135 gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); 136 gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); 137 138 /* 139 * isolate first argument 140 */ 141 if(REGARG >= 0) { 142 if(typesuv[thisfn->link->etype]) { 143 nod1 = *nodret->left; 144 nodreg(&nod, &nod1, REGARG); 145 gmove(&nod, &nod1); 146 } else 147 if(firstarg && typechlp[firstargtype->etype]) { 148 nod1 = *nodret->left; 149 nod1.sym = firstarg; 150 nod1.type = firstargtype; 151 nod1.xoffset = align(0, firstargtype, Aarg1, nil); 152 nod1.etype = firstargtype->etype; 153 nodreg(&nod, &nod1, REGARG); 154 gmove(&nod, &nod1); 155 } 156 } 157 158 retok = 0; 159 160 canreach = 1; 161 warnreach = 1; 162 gen(n); 163 if(canreach && thisfn->link->etype != TVOID) 164 diag(Z, "no return at end of function: %s", n1->sym->name); 165 noretval(3); 166 gbranch(ORETURN); 167 168 if(!debug['N'] || debug['R'] || debug['P']) 169 regopt(sp); 170 171 if(thechar=='6' || thechar=='7') /* [sic] */ 172 maxargsafe = xround(maxargsafe, 8); 173 sp->to.offset += maxargsafe; 174 175 if(!isvarargs) 176 dumpgcargs(thisfn, gcargs); 177 178 // TODO(rsc): "stkoff" is not right. It does not account for 179 // the possibility of data stored in .safe variables. 180 // Unfortunately those move up and down just like 181 // the argument frame (and in fact dovetail with it) 182 // so the number we need is not available or even 183 // well-defined. Probably we need to make the safe 184 // area its own section. 185 // That said, we've been using stkoff for months 186 // and nothing too terrible has happened. 187 gextern(gclocals, nodconst(-stkoff), 0, 4); // locals 188 gclocals->type = typ(0, T); 189 gclocals->type->width = 4; 190 } 191 192 void 193 supgen(Node *n) 194 { 195 int owarn; 196 long spc; 197 Prog *sp; 198 199 if(n == Z) 200 return; 201 suppress++; 202 owarn = warnreach; 203 warnreach = 0; 204 spc = pc; 205 sp = lastp; 206 gen(n); 207 lastp = sp; 208 pc = spc; 209 sp->link = nil; 210 suppress--; 211 warnreach = owarn; 212 } 213 214 void 215 gen(Node *n) 216 { 217 Node *l, nod; 218 Prog *sp, *spc, *spb; 219 Case *cn; 220 long sbc, scc; 221 int snbreak, sncontin; 222 int f, o, oldreach; 223 224 loop: 225 if(n == Z) 226 return; 227 nearln = n->lineno; 228 o = n->op; 229 if(debug['G']) 230 if(o != OLIST) 231 print("%L %O\n", nearln, o); 232 233 if(!canreach) { 234 switch(o) { 235 case OLABEL: 236 case OCASE: 237 case OLIST: 238 case OBREAK: 239 case OFOR: 240 case OWHILE: 241 case ODWHILE: 242 /* all handled specially - see switch body below */ 243 break; 244 default: 245 if(warnreach) { 246 warn(n, "unreachable code %O", o); 247 warnreach = 0; 248 } 249 } 250 } 251 252 switch(o) { 253 254 default: 255 complex(n); 256 cgen(n, Z); 257 break; 258 259 case OLIST: 260 gen(n->left); 261 262 rloop: 263 n = n->right; 264 goto loop; 265 266 case ORETURN: 267 canreach = 0; 268 warnreach = !suppress; 269 complex(n); 270 if(n->type == T) 271 break; 272 l = n->left; 273 if(l == Z) { 274 noretval(3); 275 gbranch(ORETURN); 276 break; 277 } 278 if(typecmplx[n->type->etype]) { 279 sugen(l, nodret, n->type->width); 280 noretval(3); 281 gbranch(ORETURN); 282 break; 283 } 284 regret(&nod, n); 285 cgen(l, &nod); 286 regfree(&nod); 287 if(typefd[n->type->etype]) 288 noretval(1); 289 else 290 noretval(2); 291 gbranch(ORETURN); 292 break; 293 294 case OLABEL: 295 canreach = 1; 296 l = n->left; 297 if(l) { 298 l->pc = pc; 299 if(l->label) 300 patch(l->label, pc); 301 } 302 gbranch(OGOTO); /* prevent self reference in reg */ 303 patch(p, pc); 304 goto rloop; 305 306 case OGOTO: 307 canreach = 0; 308 warnreach = !suppress; 309 n = n->left; 310 if(n == Z) 311 return; 312 if(n->complex == 0) { 313 diag(Z, "label undefined: %s", n->sym->name); 314 return; 315 } 316 if(suppress) 317 return; 318 gbranch(OGOTO); 319 if(n->pc) { 320 patch(p, n->pc); 321 return; 322 } 323 if(n->label) 324 patch(n->label, pc-1); 325 n->label = p; 326 return; 327 328 case OCASE: 329 canreach = 1; 330 l = n->left; 331 if(cases == C) 332 diag(n, "case/default outside a switch"); 333 if(l == Z) { 334 newcase(); 335 cases->val = 0; 336 cases->def = 1; 337 cases->label = pc; 338 cases->isv = 0; 339 goto rloop; 340 } 341 complex(l); 342 if(l->type == T) 343 goto rloop; 344 if(l->op == OCONST) 345 if(typeword[l->type->etype] && l->type->etype != TIND) { 346 newcase(); 347 cases->val = l->vconst; 348 cases->def = 0; 349 cases->label = pc; 350 cases->isv = typev[l->type->etype]; 351 goto rloop; 352 } 353 diag(n, "case expression must be integer constant"); 354 goto rloop; 355 356 case OSWITCH: 357 l = n->left; 358 complex(l); 359 if(l->type == T) 360 break; 361 if(!typechlvp[l->type->etype] || l->type->etype == TIND) { 362 diag(n, "switch expression must be integer"); 363 break; 364 } 365 366 gbranch(OGOTO); /* entry */ 367 sp = p; 368 369 cn = cases; 370 cases = C; 371 newcase(); 372 373 sbc = breakpc; 374 breakpc = pc; 375 snbreak = nbreak; 376 nbreak = 0; 377 gbranch(OGOTO); 378 spb = p; 379 380 gen(n->right); /* body */ 381 if(canreach){ 382 gbranch(OGOTO); 383 patch(p, breakpc); 384 nbreak++; 385 } 386 387 patch(sp, pc); 388 doswit(l); 389 patch(spb, pc); 390 391 cases = cn; 392 breakpc = sbc; 393 canreach = nbreak!=0; 394 if(canreach == 0) 395 warnreach = !suppress; 396 nbreak = snbreak; 397 break; 398 399 case OWHILE: 400 case ODWHILE: 401 l = n->left; 402 gbranch(OGOTO); /* entry */ 403 sp = p; 404 405 scc = continpc; 406 continpc = pc; 407 gbranch(OGOTO); 408 spc = p; 409 410 sbc = breakpc; 411 breakpc = pc; 412 snbreak = nbreak; 413 nbreak = 0; 414 gbranch(OGOTO); 415 spb = p; 416 417 patch(spc, pc); 418 if(n->op == OWHILE) 419 patch(sp, pc); 420 bcomplex(l, Z); /* test */ 421 patch(p, breakpc); 422 if(l->op != OCONST || vconst(l) == 0) 423 nbreak++; 424 425 if(n->op == ODWHILE) 426 patch(sp, pc); 427 gen(n->right); /* body */ 428 gbranch(OGOTO); 429 patch(p, continpc); 430 431 patch(spb, pc); 432 continpc = scc; 433 breakpc = sbc; 434 canreach = nbreak!=0; 435 if(canreach == 0) 436 warnreach = !suppress; 437 nbreak = snbreak; 438 break; 439 440 case OFOR: 441 l = n->left; 442 if(!canreach && l->right->left && warnreach) { 443 warn(n, "unreachable code FOR"); 444 warnreach = 0; 445 } 446 gen(l->right->left); /* init */ 447 gbranch(OGOTO); /* entry */ 448 sp = p; 449 450 /* 451 * if there are no incoming labels in the 452 * body and the top's not reachable, warn 453 */ 454 if(!canreach && warnreach && deadheads(n)) { 455 warn(n, "unreachable code %O", o); 456 warnreach = 0; 457 } 458 459 scc = continpc; 460 continpc = pc; 461 gbranch(OGOTO); 462 spc = p; 463 464 sbc = breakpc; 465 breakpc = pc; 466 snbreak = nbreak; 467 nbreak = 0; 468 sncontin = ncontin; 469 ncontin = 0; 470 gbranch(OGOTO); 471 spb = p; 472 473 patch(spc, pc); 474 gen(l->right->right); /* inc */ 475 patch(sp, pc); 476 if(l->left != Z) { /* test */ 477 bcomplex(l->left, Z); 478 patch(p, breakpc); 479 if(l->left->op != OCONST || vconst(l->left) == 0) 480 nbreak++; 481 } 482 canreach = 1; 483 gen(n->right); /* body */ 484 if(canreach){ 485 gbranch(OGOTO); 486 patch(p, continpc); 487 ncontin++; 488 } 489 if(!ncontin && l->right->right && warnreach) { 490 warn(l->right->right, "unreachable FOR inc"); 491 warnreach = 0; 492 } 493 494 patch(spb, pc); 495 continpc = scc; 496 breakpc = sbc; 497 canreach = nbreak!=0; 498 if(canreach == 0) 499 warnreach = !suppress; 500 nbreak = snbreak; 501 ncontin = sncontin; 502 break; 503 504 case OCONTINUE: 505 if(continpc < 0) { 506 diag(n, "continue not in a loop"); 507 break; 508 } 509 gbranch(OGOTO); 510 patch(p, continpc); 511 ncontin++; 512 canreach = 0; 513 warnreach = !suppress; 514 break; 515 516 case OBREAK: 517 if(breakpc < 0) { 518 diag(n, "break not in a loop"); 519 break; 520 } 521 /* 522 * Don't complain about unreachable break statements. 523 * There are breaks hidden in yacc's output and some people 524 * write return; break; in their switch statements out of habit. 525 * However, don't confuse the analysis by inserting an 526 * unreachable reference to breakpc either. 527 */ 528 if(!canreach) 529 break; 530 gbranch(OGOTO); 531 patch(p, breakpc); 532 nbreak++; 533 canreach = 0; 534 warnreach = !suppress; 535 break; 536 537 case OIF: 538 l = n->left; 539 if(bcomplex(l, n->right)) { 540 if(typefd[l->type->etype]) 541 f = !l->fconst; 542 else 543 f = !l->vconst; 544 if(debug['c']) 545 print("%L const if %s\n", nearln, f ? "false" : "true"); 546 if(f) { 547 canreach = 1; 548 supgen(n->right->left); 549 oldreach = canreach; 550 canreach = 1; 551 gen(n->right->right); 552 /* 553 * treat constant ifs as regular ifs for 554 * reachability warnings. 555 */ 556 if(!canreach && oldreach && debug['w'] < 2) 557 warnreach = 0; 558 } 559 else { 560 canreach = 1; 561 gen(n->right->left); 562 oldreach = canreach; 563 canreach = 1; 564 supgen(n->right->right); 565 /* 566 * treat constant ifs as regular ifs for 567 * reachability warnings. 568 */ 569 if(!oldreach && canreach && debug['w'] < 2) 570 warnreach = 0; 571 canreach = oldreach; 572 } 573 } 574 else { 575 sp = p; 576 canreach = 1; 577 if(n->right->left != Z) 578 gen(n->right->left); 579 oldreach = canreach; 580 canreach = 1; 581 if(n->right->right != Z) { 582 gbranch(OGOTO); 583 patch(sp, pc); 584 sp = p; 585 gen(n->right->right); 586 } 587 patch(sp, pc); 588 canreach = canreach || oldreach; 589 if(canreach == 0) 590 warnreach = !suppress; 591 } 592 break; 593 594 case OSET: 595 case OUSED: 596 case OPREFETCH: 597 usedset(n->left, o); 598 break; 599 } 600 } 601 602 void 603 usedset(Node *n, int o) 604 { 605 if(n->op == OLIST) { 606 usedset(n->left, o); 607 usedset(n->right, o); 608 return; 609 } 610 complex(n); 611 if(o == OPREFETCH) { 612 gprefetch(n); 613 return; 614 } 615 switch(n->op) { 616 case OADDR: /* volatile */ 617 gins(ANOP, n, Z); 618 break; 619 case ONAME: 620 if(o == OSET) 621 gins(ANOP, Z, n); 622 else 623 gins(ANOP, n, Z); 624 break; 625 } 626 } 627 628 int 629 bcomplex(Node *n, Node *c) 630 { 631 Node *b, nod; 632 633 complex(n); 634 if(n->type != T) 635 if(tcompat(n, T, n->type, tnot)) 636 n->type = T; 637 if(n->type == T) { 638 gbranch(OGOTO); 639 return 0; 640 } 641 if(c != Z && n->op == OCONST && deadheads(c)) 642 return 1; 643 if(typev[n->type->etype] && machcap(Z)) { 644 b = &nod; 645 b->op = ONE; 646 b->left = n; 647 b->right = new(0, Z, Z); 648 *b->right = *nodconst(0); 649 b->right->type = n->type; 650 b->type = types[TLONG]; 651 n = b; 652 } 653 bool64(n); 654 boolgen(n, 1, Z); 655 return 0; 656 } 657 658 // Updates the bitvector with a set bit for each pointer containing 659 // value in the type description starting at offset. 660 static void 661 walktype1(Type *t, int32 offset, Bvec *bv, int param) 662 { 663 Type *t1; 664 int32 o; 665 int32 widthptr; 666 667 widthptr = ewidth[TIND]; 668 switch(t->etype) { 669 case TCHAR: 670 case TUCHAR: 671 case TSHORT: 672 case TUSHORT: 673 case TINT: 674 case TUINT: 675 case TLONG: 676 case TULONG: 677 case TVLONG: 678 case TUVLONG: 679 case TFLOAT: 680 case TDOUBLE: 681 // non-pointer types 682 for(o = 0; o < t->width; o++) 683 bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar 684 break; 685 686 case TIND: 687 pointer: 688 // pointer types 689 if((offset + t->offset) % widthptr != 0) 690 yyerror("unaligned pointer"); 691 bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr 692 break; 693 694 case TARRAY: 695 if(param) // unlike Go, C passes arrays by reference 696 goto pointer; 697 // array in struct or union is an actual array 698 for(o = 0; o < t->width; o += t->link->width) 699 walktype1(t->link, offset+o, bv, 0); 700 break; 701 702 case TSTRUCT: 703 // build map recursively 704 for(t1 = t->link; t1 != T; t1 = t1->down) 705 walktype1(t1, offset, bv, 0); 706 break; 707 708 case TUNION: 709 walktype1(t->link, offset, bv, 0); 710 break; 711 712 default: 713 yyerror("can't handle arg type %s\n", tnames[t->etype]); 714 } 715 } 716 717 // Compute a bit vector to describe the pointer containing locations 718 // in the argument list. Adds the data to gcsym and returns the offset 719 // of end of the bit vector. 720 static void 721 dumpgcargs(Type *fn, Sym *sym) 722 { 723 Bvec *bv; 724 Type *t; 725 int32 i; 726 int32 argbytes; 727 int32 symoffset, argoffset; 728 729 // Dump the length of the bitmap array. This value is always one for 730 // functions written in C. 731 symoffset = 0; 732 gextern(sym, nodconst(1), symoffset, 4); 733 symoffset += 4; 734 argbytes = (argsize() + ewidth[TIND] - 1); 735 bv = bvalloc((argbytes / ewidth[TIND]) * BitsPerPointer); 736 argoffset = align(0, fn->link, Aarg0, nil); 737 if(argoffset > 0) { 738 // The C calling convention returns structs by copying them to a 739 // location pointed to by a hidden first argument. This first 740 // argument is a pointer. 741 if(argoffset != ewidth[TIND]) 742 yyerror("passbyptr arg not the right size"); 743 bvset(bv, 1); // 2 = live ptr 744 } 745 for(t = fn->down; t != T; t = t->down) { 746 if(t->etype == TVOID) 747 continue; 748 argoffset = align(argoffset, t, Aarg1, nil); 749 walktype1(t, argoffset, bv, 1); 750 argoffset = align(argoffset, t, Aarg2, nil); 751 } 752 // Dump the length of the bitmap. 753 gextern(sym, nodconst(bv->n), symoffset, 4); 754 symoffset += 4; 755 // Dump the words of the bitmap. 756 for(i = 0; i < bv->n; i += 32) { 757 gextern(sym, nodconst(bv->b[i/32]), symoffset, 4); 758 symoffset += 4; 759 } 760 free(bv); 761 // Finalize the gc symbol. 762 sym->type = typ(0, T); 763 sym->type->width = symoffset; 764 }