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