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