|
|
1.1 ! root 1: /* ! 2: * C compiler. ! 3: * Pattern selection. ! 4: */ ! 5: #ifdef vax ! 6: #include "INC$LIB:cc1.h" ! 7: #else ! 8: #include "cc1.h" ! 9: #endif ! 10: ! 11: #if !TINY ! 12: #define consnap(x, p) if (sflag>x) snapf(p) ! 13: #define consnapv(x, p, v) if (sflag>x) snapf(p, v) ! 14: #else ! 15: #define consnap(x, p) /* consnap */ ! 16: #define consnapv(x, p, v) /* consnapv */ ! 17: #endif ! 18: ! 19: /* ! 20: * Code selection. ! 21: * This routine is a near duplicate of output(). ! 22: * This routine must succeed or a nomatch fatal error will result. ! 23: */ ! 24: select(tp, c, r) ! 25: register TREE *tp; ! 26: { ! 27: register TREE *ap; ! 28: register op; ! 29: register TREE *xp; ! 30: int flag; ! 31: int rel; ! 32: int r1; ! 33: ! 34: #if !TINY ! 35: if (sflag > 1) { ! 36: snapf("select(%P, %C, ", tp, c); ! 37: snapf(c<MFLOW ? "%R" : c<MEQ ? "%d" : "L%d", r); ! 38: snapf(") %A\n", tp->t_op); ! 39: } ! 40: #endif ! 41: /* Process a few operators by hand */ ! 42: op = tp->t_op; ! 43: if (op == COMMA) { ! 44: if (code1(&tp->t_lp, MEFFECT, ANYR) == 0 ! 45: || code1(&tp->t_rp, c, r) == 0) ! 46: return (0); ! 47: tp->t_used = tp->t_lp->t_used | tp->t_rp->t_used; ! 48: tp->t_treg = tp->t_rp->t_treg; ! 49: tp->t_rreg = tp->t_rp->t_rreg; ! 50: return (1); ! 51: } ! 52: if (op == QUEST) { ! 53: if (code1(&tp->t_lp, MFLOW, 0) == 0) ! 54: return (0); ! 55: ap = tp->t_rp; ! 56: if (code1(&ap->t_lp, c, r) == 0) ! 57: return (0); ! 58: ap->t_rreg = NONE; ! 59: if (c==MLVALUE || c==MRVALUE) { ! 60: r = ap->t_lp->t_rreg; ! 61: ap->t_rreg = r; ! 62: } ! 63: if (code1(&ap->t_rp, c, r) == 0) ! 64: return (0); ! 65: ap->t_treg = NONE; ! 66: ap->t_used = ap->t_lp->t_used | ap->t_rp->t_used; ! 67: tp->t_rreg = ap->t_rreg; ! 68: tp->t_treg = NONE; ! 69: tp->t_used = tp->t_lp->t_used | ap->t_used; ! 70: return (1); ! 71: } ! 72: /* Conditionals may be unravelled to generate simpler code. ! 73: * 'r' is true or false depending on which condition should goto 'l'. */ ! 74: if (c == MFLOW) { ! 75: if (op == NOT) { ! 76: if (code1(&tp->t_lp, c, !r) == 0) ! 77: return(0); ! 78: tp->t_used = tp->t_lp->t_used; ! 79: return(1); ! 80: } ! 81: if (op == LEAF) { ! 82: ap = tp->t_lp; ! 83: if (ap->t_op==ICON || ap->t_op==LCON) ! 84: return (1); ! 85: } ! 86: if (op==ANDAND || op==OROR) { ! 87: r1 = r; ! 88: if ((op==OROR) != r) ! 89: r1 = !r1; ! 90: if (code1(&tp->t_lp, MFLOW, r1) == 0 ! 91: || code1(&tp->t_rp, MFLOW, r) == 0) ! 92: return (0); ! 93: tp->t_used = tp->t_lp->t_used | tp->t_rp->t_used; ! 94: tp->t_rreg = NONE; ! 95: tp->t_treg = NONE; ! 96: return (1); ! 97: } ! 98: rel = NE; ! 99: flag = 0; ! 100: if (isrelop(op)) { ! 101: rel = op; ! 102: if (isnval(tp->t_rp, 0) && tp->t_lp->t_op != QUEST) { ! 103: if (rel == ULE) ! 104: rel = EQ; ! 105: else if (rel == UGT) ! 106: rel = NE; ! 107: ap = tp->t_lp; ! 108: flag = 1; ! 109: while ((op = ap->t_op) == COMMA) ! 110: ap = ap->t_rp; ! 111: if (isrelop(op) || isflow(op)) { ! 112: switch (rel) { ! 113: case EQ: ! 114: case LE: ! 115: case ULE: ! 116: r = !r; ! 117: case NE: ! 118: case GT: ! 119: case UGT: ! 120: if (code1(&tp->t_lp, c, r) == 0) ! 121: return(0); ! 122: tp->t_used = tp->t_lp->t_used; ! 123: return(1); ! 124: } ! 125: } ! 126: } ! 127: } ! 128: if (r == 0) ! 129: rel = otherel[rel-EQ]; ! 130: c = MEQ + rel - EQ; ! 131: r = ANYR; ! 132: if (flag) { ! 133: if (code1(&tp->t_lp, c, r) == 0) ! 134: return (0); ! 135: tp->t_used = tp->t_lp->t_used; ! 136: return (1); ! 137: } ! 138: } ! 139: if (op == CALL) { ! 140: #if 0 ! 141: if (c != pertype[tp->t_type].p_frcxt ! 142: && (c==MRVALUE || c==MLVALUE)) ! 143: return (0); ! 144: #endif ! 145: tp->t_used = FNUSED; ! 146: if (tp->t_rp != NULL) { ! 147: if (selargs(&tp->t_rp) == 0) ! 148: return (0); ! 149: tp->t_used |= tp->t_rp->t_used; ! 150: } ! 151: ap = tp->t_lp; ! 152: if (!isadr(ap->t_flag)) { ! 153: #if ICALLS ! 154: /* Does the machine allow ! 155: * an extra level of indirection ! 156: * on calls? */ ! 157: if (ap->t_op != STAR) ! 158: cbotch("call no star"); ! 159: xp = ap->t_lp; ! 160: if (!isadr(xp->t_flag)) { ! 161: if (!isofs(xp->t_flag)) ! 162: store(ap, 0); ! 163: else { ! 164: xp = findoffs(xp); ! 165: if (select(xp, MLVALUE, ANYL) == 0) ! 166: return (0); ! 167: tp->t_used |= xp->t_used; ! 168: } ! 169: } ! 170: #else ! 171: if (!isofs(ap->t_flag)) ! 172: cbotch("call not ofs"); ! 173: ap = findoffs(ap); ! 174: if (select(ap, MLVALUE, ANYL) == 0) ! 175: return (0); ! 176: tp->t_used |= ap->t_used; ! 177: #endif ! 178: } ! 179: tp->t_treg = NONE; ! 180: tp->t_rreg = pertype[tp->t_type].p_frreg; ! 181: if ((c!=MLVALUE&&c!=MRVALUE)||(isrealreg(r)&&r!=tp->t_rreg)) ! 182: selfix(tp, c, r); ! 183: return (1); ! 184: } ! 185: /* Everything not previously dispatched by hand ! 186: * must be found in the code tables by seltree */ ! 187: if (seltree(tp, c, r)) { ! 188: if ((c==MLVALUE||c==MRVALUE) && isrealreg(r) && r!=tp->t_rreg) ! 189: selfix(tp, c, r); ! 190: return (1); ! 191: } ! 192: /* RVALUE patterns can be fixed up into anything */ ! 193: if (c != MRVALUE && seltree(tp, MRVALUE, ANYR)) { ! 194: selfix(tp, c, r); ! 195: return (1); ! 196: } ! 197: #if 0 ! 198: /* The m68000 needed this, maybe it won't next time */ ! 199: if (c != MLVALUE && seltree(tp, MLVALUE, ANYL)) { ! 200: if (c != MEFFECT) ! 201: selfix(tp, c, r); ! 202: return (1); ! 203: } ! 204: #endif ! 205: /* FAILURE is a fatal error */ ! 206: return (0); ! 207: } ! 208: ! 209: /* ! 210: * If the selector cannot find a template that will satisfy the context or the ! 211: * requested register, an MRVALUE case will do if the result is 'fixed up'. ! 212: * A FIXUP tree node tells the output part of the coder that a fixup is ! 213: * needed at this point in the tree. ! 214: * Context mismatch FIXUP's are generally benign: ! 215: * they either push a register onto the stack as a function argument, ! 216: * or test a register and generate a conditional branch. ! 217: * Register mismatch FIXUP's appear to be caused ! 218: * by table errors or overzealous node coercion ! 219: * and should to be avoided at all costs; ! 220: * they often lead to shuffling values back and forth between registers. ! 221: * The typical culprit is a code table pattern ! 222: * which specifies both a node register and an ADR subnode ! 223: * rather than a TREG subnode shared with the node register. ! 224: * seltree() coerces the ADR node into the wrong register ! 225: * and the fixup copies it to the requested reg. ! 226: */ ! 227: selfix(tp, c, r) ! 228: register TREE *tp; ! 229: { ! 230: register TREE *ap; ! 231: TREE rnode; ! 232: ! 233: #if !TINY ! 234: if (sflag > 1) { ! 235: snapf("selfix(%P, %C, ", tp, c); ! 236: snapf(c<MFLOW ? "%R" : c<MEQ ? "%d" : "L%d", r); ! 237: snapf(") %A\n", tp->t_op); ! 238: } ! 239: #endif ! 240: ap = copynode(tp); ! 241: fixtoptype(tp); ! 242: rnode.t_op = REG; ! 243: rnode.t_type = tp->t_type; ! 244: rnode.t_size = tp->t_size; ! 245: rnode.t_reg = tp->t_rreg; ! 246: tp->t_op = FIXUP; ! 247: tp->t_lp = &rnode; ! 248: tp->t_rp = NULL; ! 249: walk(tp, amd); ! 250: #if !TINY ! 251: rnode.t_treg = NONE; ! 252: rnode.t_rreg = NONE; ! 253: rnode.t_used = 0; ! 254: rnode.t_patp = NULL; ! 255: if (sflag > 2) snapf("%W%E%W", "Selfix", tp, NULL); ! 256: #endif ! 257: if (select(tp, c, r) == 0) ! 258: cbotch("node will not fix"); ! 259: tp->t_lp = ap; ! 260: tp->t_used = ap->t_used; ! 261: if (isrealreg(r)) ! 262: setused(tp, r); ! 263: } ! 264: ! 265: /* ! 266: * Add register 'r' to the used set of the tree node pointed to by 'tp'. ! 267: */ ! 268: setused(tp, r) ! 269: TREE *tp; ! 270: { ! 271: tp->t_used |= reg[r].r_phys; ! 272: } ! 273: ! 274: /* ! 275: * Run down the (possibly null) ! 276: * argument list of a function, making ! 277: * the required recursive calls to the ! 278: * walker and/or the code selector. ! 279: * If the node is a BLK pointer, ! 280: * it the address of a structure argument and ! 281: * must get special treatment. ! 282: */ ! 283: selargs(tpp) ! 284: register TREE **tpp; ! 285: { ! 286: register TREE *tp; ! 287: ! 288: if ((tp = *tpp) == NULL) ! 289: return (1); ! 290: if (tp->t_op == ARGLST) { ! 291: if (selargs(&tp->t_lp)==0) ! 292: return (0); ! 293: if (selargs(&tp->t_rp)==0) ! 294: return (0); ! 295: tp->t_used = 0; ! 296: if (tp->t_lp != NULL) ! 297: tp->t_used |= tp->t_lp->t_used; ! 298: if (tp->t_rp != NULL) ! 299: tp->t_used |= tp->t_rp->t_used; ! 300: return (1); ! 301: } ! 302: if (isblkp(tp->t_type)) ! 303: return (code1(tpp, MBLARG, MBLREG)); ! 304: return (code1(tpp, MFNARG, ANYR)); ! 305: } ! 306: ! 307: /* ! 308: * Set up an address in an rvalue context. ! 309: * This routine knows how to pool ! 310: * constants on demand, how to use registers ! 311: * as indexing temporaries and as plain old ! 312: * value temporaries, and how to give up and ! 313: * put a value into memory. ! 314: * If the top operator is one of the leaf ! 315: * nodes the register used in the setup of an ! 316: * offset address is not made busy. ! 317: * It is marked used by the tree. ! 318: * These trees are more like a TREG than a RHS ! 319: * in their use of a register. ! 320: */ ! 321: selrv(ttp, flag, didstorep) ! 322: TREE *ttp; ! 323: int *didstorep; ! 324: { ! 325: register TREE *tp, *ap; ! 326: register op, leaf; ! 327: int lab, r; ! 328: ! 329: leaf = 1; ! 330: tp = ttp; ! 331: op = tp->t_op; ! 332: if (op==CONVERT || op==CAST || op==FIXUP || op==LEAF) ! 333: leaf = 2; ! 334: #if !TINY ! 335: if (sflag > 1) ! 336: snapf("selrv(%P, %d, ...) leaf=%d\n", tp, flag, leaf); ! 337: #endif ! 338: tp = flag ? tp->t_rp : tp->t_lp; ! 339: /* Pool constants into memory */ ! 340: if ((tp->t_flag&T_IMM) != 0) { ! 341: for (ap=tp; ap->t_op==LEAF; ap=ap->t_lp) ! 342: ; ! 343: pool(ap); ! 344: walk(tp, amd); ! 345: return; ! 346: } ! 347: /* The tree is offset addressible, ! 348: * load the offset node into an index reg */ ! 349: if (isofs(tp->t_flag)) { ! 350: ap = findoffs(tp); ! 351: consnapv(2, "Rv offs %P\n", ap); ! 352: if ((r = rallo(ap, ttp->t_used, leaf)) >= 0) { ! 353: consnapv(2, "Offs %R\n", r); ! 354: if (leaf == 1) ! 355: setbusy(r); ! 356: if (select(ap, MLVALUE, r)) { ! 357: ttp->t_used |= ap->t_used; ! 358: return; ! 359: } ! 360: if (leaf == 1) ! 361: clrbusy(r); ! 362: } ! 363: } ! 364: /* Try to load the tree into a register */ ! 365: if ((r = rallo(tp, ttp->t_used, 0)) >= 0) { ! 366: setbusy(r); ! 367: if (select(tp, MRVALUE, r)) { ! 368: tp->t_flag = 0; ! 369: ttp->t_used |= tp->t_used; ! 370: return; ! 371: } ! 372: clrbusy(r); ! 373: } ! 374: /* Store the tree into a stack temporary */ ! 375: store(ttp, flag); ! 376: walk(tp, amd); ! 377: *didstorep = 1; ! 378: } ! 379: ! 380: /* ! 381: * This function sets up a left context subtree in an addressing context. ! 382: * The 'index' argument is a preferred register; if negative, ! 383: * then indirection is legal. ! 384: * This routine is the pits, comparable ! 385: * in pittiness to the part of output() ! 386: * responsible for undoing this madness. ! 387: */ ! 388: sellv(ttp, index, flag, didstorep) ! 389: TREE *ttp; ! 390: int *didstorep; ! 391: { ! 392: register TREE *tp, *tp1, *tp2; ! 393: int newindex; ! 394: ! 395: tp = flag ? ttp->t_rp : ttp->t_lp; ! 396: #if !TINY ! 397: if (sflag > 1) ! 398: snapf("sellv(%P, %R, %d, ...)\n", tp, index, flag); ! 399: #endif ! 400: if (tp->t_op == FIELD) { ! 401: tp->t_used = ttp->t_used; ! 402: sellv(tp, index, 0, didstorep); ! 403: ttp->t_used |= tp->t_used; ! 404: return; ! 405: } ! 406: if (!isofs(tp->t_flag)) ! 407: cbotch("sellv: not an ofs"); ! 408: /* If we can indirect through a stack temporary, ! 409: * we still try first to do it in a register, ! 410: * but we give up with much less grief. */ ! 411: if (index < 0) { ! 412: tp1 = findoffs(tp); ! 413: consnapv(2, "Lv offs %P\n", tp1); ! 414: if ((index = rallo(tp1, ttp->t_used, 1)) >= 0) { ! 415: consnapv(2, "Index %R\n", index); ! 416: setbusy(index); ! 417: if (select(tp1, MLVALUE, index)) { ! 418: tp->t_used |= tp1->t_used; ! 419: ttp->t_used |= tp1->t_used; ! 420: return; ! 421: } ! 422: clrbusy(index); ! 423: } ! 424: /* The store puts a stack temp under tp ! 425: * which must have tp->t_op == STAR */ ! 426: store(tp, 0); ! 427: walk(tp, amd); ! 428: *didstorep = 1; ! 429: return; ! 430: } ! 431: /* We cannot indirect through a temp, ! 432: * so we may have to fake it. */ ! 433: tp2 = findoffs(tp); ! 434: consnapv(2, "Offs %P\n", tp2); ! 435: for (tp1 = tp; tp1->t_lp != tp2; tp1 = tp1->t_lp); ! 436: /* If the offset is not directly addressible ! 437: * then we will have to generate code to load ! 438: * it into the index register. */ ! 439: if (!isadr(tp2->t_flag)) { ! 440: /* If the preferred index is useable ! 441: * then attempt to use it */ ! 442: if ((ttp->t_used®[index].r_phys) == 0) { ! 443: if (select(tp2, MLVALUE, index)) { ! 444: tp->t_used |= tp2->t_used; ! 445: ttp->t_used |= tp2->t_used; ! 446: return; ! 447: } ! 448: } ! 449: /* Since the preferred index is already used, ! 450: * try to use another one. */ ! 451: if ((newindex = rallo(tp2, ttp->t_used, 1)) >= 0) { ! 452: setbusy(newindex); ! 453: if (select(tp2, MLVALUE, newindex)) { ! 454: ttp->t_used |= tp2->t_used; ! 455: tp->t_used |= tp2->t_used; ! 456: return; ! 457: } ! 458: clrbusy(newindex); ! 459: } ! 460: /* We can't do it ourselves, but an index has been ! 461: * reserved to load from a stack temp, so give up ! 462: * and store the offset. */ ! 463: store(tp1, 0); ! 464: walk(tp, amd); ! 465: *didstorep = 1; ! 466: } ! 467: /* tp2 either was addressible to begin with, ! 468: * or was just made into an addressible temp */ ! 469: tp2 = tp1->t_lp; ! 470: if (tp2->t_op != LEAF) { ! 471: tp2 = leafnode(tp2); ! 472: tp2->t_flag = tp1->t_lp->t_flag; ! 473: tp1->t_lp = tp2; ! 474: } ! 475: /* Select the addressible offset node ! 476: * into an index register */ ! 477: if (select(tp2, MLVALUE, index) == 0) ! 478: cbotch("sellv"); ! 479: /* This flag is for the benefit of output() */ ! 480: tp->t_flag |= T_INDIR; ! 481: tp->t_used |= tp2->t_used; ! 482: ttp->t_used |= tp2->t_used; ! 483: } ! 484: ! 485: /* ! 486: * Store a subtree of the node pointed to by 'ttp'. ! 487: * The 'flag' argument tells which subtree; ! 488: * true means store the right side. ! 489: * Then rewrite the subtree to refer to the storage location. ! 490: */ ! 491: store(ttp, flag) ! 492: TREE *ttp; ! 493: { ! 494: register TREE *ap; ! 495: register TREE *tp; ! 496: register int sideflag; ! 497: ! 498: if (nstorelist >= NSTORE) ! 499: cbotch("more than %d stores", NSTORE); ! 500: sideflag = MRADDR; ! 501: if (ttp->t_op>=INCBEF && ttp->t_op<=DECAFT) { ! 502: if (flag != 0) ! 503: cbotch("store"); ! 504: tp = copynode(ttp); ! 505: sideflag = MRVALUE; ! 506: } else if (flag != 0) ! 507: tp = ttp->t_rp; ! 508: else ! 509: tp = ttp->t_lp; ! 510: ap = tempnode(tp, 1); ! 511: if (sideflag == MRVALUE) ! 512: ap = leafnode(ap); ! 513: walk(ap, amd); ! 514: if (sideflag == MRVALUE) ! 515: *ttp = *ap; ! 516: else if (flag != 0) ! 517: ttp->t_rp = ap; ! 518: else ! 519: ttp->t_lp = ap; ! 520: amd(ttp); ! 521: ap = tempnode(tp, 0); ! 522: ap = leftnode(ASSIGN, ap, ap->t_type, ap->t_size); ! 523: while (tp->t_op == LEAF) ! 524: tp = tp->t_lp; ! 525: if (tp->t_type != ap->t_type) ! 526: tp = leftnode(CONVERT, tp, ap->t_type, ap->t_size); ! 527: else if ((tp->t_flag&T_LEAF) != 0) ! 528: tp = leafnode(tp); ! 529: ap->t_rp = ripout(tp, 0); ! 530: fixtoptype(ap); ! 531: walk(ap, amd); ! 532: storelist[nstorelist++] = ap; ! 533: } ! 534: ! 535: /* ! 536: * Return true if the top of the argument tree is a conversion of some type ! 537: * and the conversion makes the data wider (e.g. int to long). ! 538: */ ! 539: iswiden(tp) ! 540: register TREE *tp; ! 541: { ! 542: register TREE *lp; ! 543: ! 544: if (tp->t_op!=CONVERT && tp->t_op!=CAST) ! 545: return (0); ! 546: lp = tp->t_lp; ! 547: if (wtype[tp->t_type] < wtype[lp->t_type]) ! 548: return (0); ! 549: return (1); ! 550: } ! 551: ! 552: /* ! 553: * This routine determines if a pattern and a set of expression flags mismatch, ! 554: * and a call to 'sellv' or 'selrv' is needed. ! 555: * Also used by output(). ! 556: */ ! 557: selmiss(pflag, eflag) ! 558: FLAG pflag; ! 559: FLAG eflag; ! 560: { ! 561: if ((pflag&eflag&~T_OFS) == 0) ! 562: return (1); ! 563: return (0); ! 564: } ! 565: ! 566: /* ! 567: * Remove any fix nodes which may have been generated ! 568: * before a temp was substituted for an expression by store. ! 569: */ ! 570: TREE * ! 571: ripout(tp, flag) ! 572: register TREE *tp; ! 573: { ! 574: register op; ! 575: ! 576: op = tp->t_op; ! 577: if (!isleaf(op)) { ! 578: tp->t_lp = ripout(tp->t_lp, flag); ! 579: if (op!=FIELD && tp->t_rp!=NULL) ! 580: tp->t_rp = ripout(tp->t_rp, flag); ! 581: } ! 582: if (op==FIXUP || (op==LEAF && flag!=0)) ! 583: tp = tp->t_lp; ! 584: return (tp); ! 585: } ! 586:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.