github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/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 "../../runtime/funcdata.h" 33 34 int 35 hasdotdotdot(Type *t) 36 { 37 for(t=t->down; t!=T; t=t->down) 38 if(t->etype == TDOT) 39 return 1; 40 return 0; 41 } 42 43 vlong 44 argsize(int doret) 45 { 46 Type *t; 47 int32 s; 48 49 //print("t=%T\n", thisfn); 50 s = 0; 51 if(hasdotdotdot(thisfn)) 52 s = align(s, thisfn->link, Aarg0, nil); 53 for(t=thisfn->down; t!=T; t=t->down) { 54 switch(t->etype) { 55 case TVOID: 56 break; 57 case TDOT: 58 if((textflag & NOSPLIT) == 0) 59 yyerror("function takes ... without textflag NOSPLIT"); 60 return ArgsSizeUnknown; 61 default: 62 s = align(s, t, Aarg1, nil); 63 s = align(s, t, Aarg2, nil); 64 break; 65 } 66 //print(" %d %T\n", s, t); 67 } 68 if(thechar == '6') 69 s = (s+7) & ~7; 70 else 71 s = (s+3) & ~3; 72 if(doret && thisfn->link->etype != TVOID) { 73 s = align(s, thisfn->link, Aarg1, nil); 74 s = align(s, thisfn->link, Aarg2, nil); 75 if(thechar == '6') 76 s = (s+7) & ~7; 77 else 78 s = (s+3) & ~3; 79 } 80 return s; 81 } 82 83 void 84 codgen(Node *n, Node *nn) 85 { 86 Prog *sp; 87 Node *n1, nod, nod1; 88 89 cursafe = 0; 90 curarg = 0; 91 maxargsafe = 0; 92 93 /* 94 * isolate name 95 */ 96 for(n1 = nn;; n1 = n1->left) { 97 if(n1 == Z) { 98 diag(nn, "can't find function name"); 99 return; 100 } 101 if(n1->op == ONAME) 102 break; 103 } 104 nearln = nn->lineno; 105 106 p = gtext(n1->sym, stkoff); 107 p->from.sym->cfunc = 1; 108 sp = p; 109 110 /* 111 * isolate first argument 112 */ 113 if(REGARG >= 0) { 114 if(typesuv[thisfn->link->etype]) { 115 nod1 = *nodret->left; 116 nodreg(&nod, &nod1, REGARG); 117 gmove(&nod, &nod1); 118 } else 119 if(firstarg && typechlp[firstargtype->etype]) { 120 nod1 = *nodret->left; 121 nod1.sym = firstarg; 122 nod1.type = firstargtype; 123 nod1.xoffset = align(0, firstargtype, Aarg1, nil); 124 nod1.etype = firstargtype->etype; 125 nodreg(&nod, &nod1, REGARG); 126 gmove(&nod, &nod1); 127 } 128 } 129 130 canreach = 1; 131 warnreach = 1; 132 gen(n); 133 if(canreach && thisfn->link->etype != TVOID) 134 diag(Z, "no return at end of function: %s", n1->sym->name); 135 noretval(3); 136 gbranch(ORETURN); 137 138 if(!debug['N'] || debug['R'] || debug['P']) 139 regopt(sp); 140 141 if(thechar=='6' || thechar=='7') /* [sic] */ 142 maxargsafe = xround(maxargsafe, 8); 143 sp->to.offset += maxargsafe; 144 } 145 146 void 147 supgen(Node *n) 148 { 149 int owarn; 150 long spc; 151 Prog *sp; 152 153 if(n == Z) 154 return; 155 suppress++; 156 owarn = warnreach; 157 warnreach = 0; 158 spc = pc; 159 sp = lastp; 160 gen(n); 161 lastp = sp; 162 pc = spc; 163 sp->link = nil; 164 suppress--; 165 warnreach = owarn; 166 } 167 168 void 169 gen(Node *n) 170 { 171 Node *l, nod, nod1; 172 Prog *sp, *spc, *spb; 173 Case *cn; 174 long sbc, scc; 175 int snbreak, sncontin; 176 int f, o, oldreach; 177 178 loop: 179 if(n == Z) 180 return; 181 nearln = n->lineno; 182 o = n->op; 183 if(debug['G']) 184 if(o != OLIST) 185 print("%L %O\n", nearln, o); 186 187 if(!canreach) { 188 switch(o) { 189 case OLABEL: 190 case OCASE: 191 case OLIST: 192 case OBREAK: 193 case OFOR: 194 case OWHILE: 195 case ODWHILE: 196 /* all handled specially - see switch body below */ 197 break; 198 default: 199 if(warnreach) { 200 warn(n, "unreachable code %O", o); 201 warnreach = 0; 202 } 203 } 204 } 205 206 switch(o) { 207 208 default: 209 complex(n); 210 cgen(n, Z); 211 break; 212 213 case OLIST: 214 gen(n->left); 215 216 rloop: 217 n = n->right; 218 goto loop; 219 220 case ORETURN: 221 canreach = 0; 222 warnreach = !suppress; 223 complex(n); 224 if(n->type == T) 225 break; 226 l = n->left; 227 if(l == Z) { 228 noretval(3); 229 gbranch(ORETURN); 230 break; 231 } 232 if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) { 233 regret(&nod, n, thisfn, 2); 234 sugen(l, &nod, n->type->width); 235 noretval(3); 236 gbranch(ORETURN); 237 break; 238 } 239 if(typecmplx[n->type->etype]) { 240 sugen(l, nodret, n->type->width); 241 noretval(3); 242 gbranch(ORETURN); 243 break; 244 } 245 regret(&nod1, n, thisfn, 2); 246 nod = nod1; 247 if(nod.op != OREGISTER) 248 regalloc(&nod, n, Z); 249 cgen(l, &nod); 250 if(nod1.op != OREGISTER) 251 gmove(&nod, &nod1); 252 regfree(&nod); 253 if(typefd[n->type->etype]) 254 noretval(1); 255 else 256 noretval(2); 257 gbranch(ORETURN); 258 break; 259 260 case OLABEL: 261 canreach = 1; 262 l = n->left; 263 if(l) { 264 l->pc = pc; 265 if(l->label) 266 patch(l->label, pc); 267 } 268 gbranch(OGOTO); /* prevent self reference in reg */ 269 patch(p, pc); 270 goto rloop; 271 272 case OGOTO: 273 canreach = 0; 274 warnreach = !suppress; 275 n = n->left; 276 if(n == Z) 277 return; 278 if(n->complex == 0) { 279 diag(Z, "label undefined: %s", n->sym->name); 280 return; 281 } 282 if(suppress) 283 return; 284 gbranch(OGOTO); 285 if(n->pc) { 286 patch(p, n->pc); 287 return; 288 } 289 if(n->label) 290 patch(n->label, pc-1); 291 n->label = p; 292 return; 293 294 case OCASE: 295 canreach = 1; 296 l = n->left; 297 if(cases == C) 298 diag(n, "case/default outside a switch"); 299 if(l == Z) { 300 newcase(); 301 cases->val = 0; 302 cases->def = 1; 303 cases->label = pc; 304 cases->isv = 0; 305 goto rloop; 306 } 307 complex(l); 308 if(l->type == T) 309 goto rloop; 310 if(l->op == OCONST) 311 if(typeword[l->type->etype] && l->type->etype != TIND) { 312 newcase(); 313 cases->val = l->vconst; 314 cases->def = 0; 315 cases->label = pc; 316 cases->isv = typev[l->type->etype]; 317 goto rloop; 318 } 319 diag(n, "case expression must be integer constant"); 320 goto rloop; 321 322 case OSWITCH: 323 l = n->left; 324 complex(l); 325 if(l->type == T) 326 break; 327 if(!typechlvp[l->type->etype] || l->type->etype == TIND) { 328 diag(n, "switch expression must be integer"); 329 break; 330 } 331 332 gbranch(OGOTO); /* entry */ 333 sp = p; 334 335 cn = cases; 336 cases = C; 337 newcase(); 338 339 sbc = breakpc; 340 breakpc = pc; 341 snbreak = nbreak; 342 nbreak = 0; 343 gbranch(OGOTO); 344 spb = p; 345 346 gen(n->right); /* body */ 347 if(canreach){ 348 gbranch(OGOTO); 349 patch(p, breakpc); 350 nbreak++; 351 } 352 353 patch(sp, pc); 354 doswit(l); 355 patch(spb, pc); 356 357 cases = cn; 358 breakpc = sbc; 359 canreach = nbreak!=0; 360 if(canreach == 0) 361 warnreach = !suppress; 362 nbreak = snbreak; 363 break; 364 365 case OWHILE: 366 case ODWHILE: 367 l = n->left; 368 gbranch(OGOTO); /* entry */ 369 sp = p; 370 371 scc = continpc; 372 continpc = pc; 373 gbranch(OGOTO); 374 spc = p; 375 376 sbc = breakpc; 377 breakpc = pc; 378 snbreak = nbreak; 379 nbreak = 0; 380 gbranch(OGOTO); 381 spb = p; 382 383 patch(spc, pc); 384 if(n->op == OWHILE) 385 patch(sp, pc); 386 bcomplex(l, Z); /* test */ 387 patch(p, breakpc); 388 if(l->op != OCONST || vconst(l) == 0) 389 nbreak++; 390 391 if(n->op == ODWHILE) 392 patch(sp, pc); 393 gen(n->right); /* body */ 394 gbranch(OGOTO); 395 patch(p, continpc); 396 397 patch(spb, pc); 398 continpc = scc; 399 breakpc = sbc; 400 canreach = nbreak!=0; 401 if(canreach == 0) 402 warnreach = !suppress; 403 nbreak = snbreak; 404 break; 405 406 case OFOR: 407 l = n->left; 408 if(!canreach && l->right->left && warnreach) { 409 warn(n, "unreachable code FOR"); 410 warnreach = 0; 411 } 412 gen(l->right->left); /* init */ 413 gbranch(OGOTO); /* entry */ 414 sp = p; 415 416 /* 417 * if there are no incoming labels in the 418 * body and the top's not reachable, warn 419 */ 420 if(!canreach && warnreach && deadheads(n)) { 421 warn(n, "unreachable code %O", o); 422 warnreach = 0; 423 } 424 425 scc = continpc; 426 continpc = pc; 427 gbranch(OGOTO); 428 spc = p; 429 430 sbc = breakpc; 431 breakpc = pc; 432 snbreak = nbreak; 433 nbreak = 0; 434 sncontin = ncontin; 435 ncontin = 0; 436 gbranch(OGOTO); 437 spb = p; 438 439 patch(spc, pc); 440 gen(l->right->right); /* inc */ 441 patch(sp, pc); 442 if(l->left != Z) { /* test */ 443 bcomplex(l->left, Z); 444 patch(p, breakpc); 445 if(l->left->op != OCONST || vconst(l->left) == 0) 446 nbreak++; 447 } 448 canreach = 1; 449 gen(n->right); /* body */ 450 if(canreach){ 451 gbranch(OGOTO); 452 patch(p, continpc); 453 ncontin++; 454 } 455 if(!ncontin && l->right->right && warnreach) { 456 warn(l->right->right, "unreachable FOR inc"); 457 warnreach = 0; 458 } 459 460 patch(spb, pc); 461 continpc = scc; 462 breakpc = sbc; 463 canreach = nbreak!=0; 464 if(canreach == 0) 465 warnreach = !suppress; 466 nbreak = snbreak; 467 ncontin = sncontin; 468 break; 469 470 case OCONTINUE: 471 if(continpc < 0) { 472 diag(n, "continue not in a loop"); 473 break; 474 } 475 gbranch(OGOTO); 476 patch(p, continpc); 477 ncontin++; 478 canreach = 0; 479 warnreach = !suppress; 480 break; 481 482 case OBREAK: 483 if(breakpc < 0) { 484 diag(n, "break not in a loop"); 485 break; 486 } 487 /* 488 * Don't complain about unreachable break statements. 489 * There are breaks hidden in yacc's output and some people 490 * write return; break; in their switch statements out of habit. 491 * However, don't confuse the analysis by inserting an 492 * unreachable reference to breakpc either. 493 */ 494 if(!canreach) 495 break; 496 gbranch(OGOTO); 497 patch(p, breakpc); 498 nbreak++; 499 canreach = 0; 500 warnreach = !suppress; 501 break; 502 503 case OIF: 504 l = n->left; 505 if(bcomplex(l, n->right)) { 506 if(typefd[l->type->etype]) 507 f = !l->fconst; 508 else 509 f = !l->vconst; 510 if(debug['c']) 511 print("%L const if %s\n", nearln, f ? "false" : "true"); 512 if(f) { 513 canreach = 1; 514 supgen(n->right->left); 515 oldreach = canreach; 516 canreach = 1; 517 gen(n->right->right); 518 /* 519 * treat constant ifs as regular ifs for 520 * reachability warnings. 521 */ 522 if(!canreach && oldreach && debug['w'] < 2) 523 warnreach = 0; 524 } 525 else { 526 canreach = 1; 527 gen(n->right->left); 528 oldreach = canreach; 529 canreach = 1; 530 supgen(n->right->right); 531 /* 532 * treat constant ifs as regular ifs for 533 * reachability warnings. 534 */ 535 if(!oldreach && canreach && debug['w'] < 2) 536 warnreach = 0; 537 canreach = oldreach; 538 } 539 } 540 else { 541 sp = p; 542 canreach = 1; 543 if(n->right->left != Z) 544 gen(n->right->left); 545 oldreach = canreach; 546 canreach = 1; 547 if(n->right->right != Z) { 548 gbranch(OGOTO); 549 patch(sp, pc); 550 sp = p; 551 gen(n->right->right); 552 } 553 patch(sp, pc); 554 canreach = canreach || oldreach; 555 if(canreach == 0) 556 warnreach = !suppress; 557 } 558 break; 559 560 case OSET: 561 case OUSED: 562 case OPREFETCH: 563 usedset(n->left, o); 564 break; 565 } 566 } 567 568 void 569 usedset(Node *n, int o) 570 { 571 if(n->op == OLIST) { 572 usedset(n->left, o); 573 usedset(n->right, o); 574 return; 575 } 576 complex(n); 577 if(o == OPREFETCH) { 578 gprefetch(n); 579 return; 580 } 581 switch(n->op) { 582 case OADDR: /* volatile */ 583 gins(ANOP, n, Z); 584 break; 585 case ONAME: 586 if(o == OSET) 587 gins(ANOP, Z, n); 588 else 589 gins(ANOP, n, Z); 590 break; 591 } 592 } 593 594 int 595 bcomplex(Node *n, Node *c) 596 { 597 Node *b, nod; 598 599 complex(n); 600 if(n->type != T) 601 if(tcompat(n, T, n->type, tnot)) 602 n->type = T; 603 if(n->type == T) { 604 gbranch(OGOTO); 605 return 0; 606 } 607 if(c != Z && n->op == OCONST && deadheads(c)) 608 return 1; 609 if(typev[n->type->etype] && machcap(Z)) { 610 b = &nod; 611 b->op = ONE; 612 b->left = n; 613 b->right = new(0, Z, Z); 614 *b->right = *nodconst(0); 615 b->right->type = n->type; 616 b->type = types[TLONG]; 617 n = b; 618 } 619 bool64(n); 620 boolgen(n, 1, Z); 621 return 0; 622 }