|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)register.c 1.1 86/02/03 Copyr 1985 Sun Micro"; ! 3: #endif ! 4: ! 5: /* ! 6: * Copyright (c) 1985 by Sun Microsystems, Inc. ! 7: */ ! 8: ! 9: #include "as.h" ! 10: #include "c2.h" ! 11: ! 12: extern struct ins_bkt *sopcode(); ! 13: extern NODE *insert_label(); ! 14: extern struct oper *newoperand(); ! 15: extern unsigned short make_touchop(); ! 16: int fortranprog = 0; ! 17: static struct sym_bkt *skyname; ! 18: #if TRACKSP ! 19: extern int spoffset; /* track a6-a7 distance */ ! 20: #endif TRACKSP ! 21: ! 22: extern struct ins_bkt *moveq, *subql, *addql; ! 23: ! 24: #define NREG (FP7REG-D0REG+1) ! 25: #define CONSRC 0 ! 26: #define CONDST 1 ! 27: struct regcon { ! 28: struct oper con; ! 29: subop_t size; ! 30: } regcon[ NREG ][2]; ! 31: ! 32: #define NMEM 100 /* totally arbitrary number */ ! 33: static struct memcon { ! 34: struct oper addr; ! 35: subop_t size; ! 36: struct oper value; ! 37: } memcon[ NMEM ]; ! 38: int nmem = 0; /* max memcon slot taken */ ! 39: ! 40: int bytesize[] = { ! 41: 1, /* SUBOP_B */ ! 42: 2, /* SUBOP_W */ ! 43: 4, /* SUBOP_L */ ! 44: 4, /* SUBOP_S */ ! 45: 8, /* SUBOP_D */ ! 46: 12, /* SUBOP_X */ ! 47: 12 /* SUBOP_P */ ! 48: }; ! 49: ! 50: #define BYTESIZE( s ) (bytesize[ (int)(s)]) ! 51: ! 52: int ! 53: dead_areg( p ) ! 54: NODE *p; ! 55: { ! 56: register i; ! 57: regmask m; m = p->rlive; ! 58: for (i=A6REG-1; i>=A0REG; i--) ! 59: if (!inmask(i, m )) ! 60: return i; ! 61: return -1; ! 62: } ! 63: ! 64: int ! 65: dead_dreg( p ) ! 66: NODE *p; ! 67: { ! 68: register i; ! 69: regmask m; m = p->rlive; ! 70: for (i=A0REG-1; i>=D0REG; i--) ! 71: if (!inmask(i, m )) ! 72: return i; ! 73: return -1; ! 74: } ! 75: ! 76: ! 77: int ! 78: cancache( o ) register struct oper *o; ! 79: { ! 80: /* ! 81: * currently, the only memory references we can cache are stack ! 82: * bound variables (and FORTRAN locals) ! 83: */ ! 84: extern int Xperimental; ! 85: ! 86: if (Xperimental) ! 87: switch (o->type_o){ ! 88: case T_REG: ! 89: case T_IMMED: ! 90: case T_PREDEC: ! 91: case T_POSTINC: return 0; ! 92: default: return 1; /* slut */ ! 93: } ! 94: if (o->type_o == T_DEFER || o->type_o == T_DISPL) ! 95: if (o->reg_o == FPREG || fortranprog && (o->reg_o==A0REG+4 || o->reg_o==A0REG+5)) ! 96: return 1; ! 97: return 0; ! 98: } ! 99: ! 100: static int ! 101: istmp( o ) register struct oper *o; ! 102: { ! 103: if ((o->type_o==T_DEFER && o->reg_o==FPREG) ! 104: || (o->type_o==T_DISPL && o->reg_o==FPREG && o->value_o>=0)) ! 105: return 1; ! 106: return 0; ! 107: } ! 108: ! 109: static int ! 110: isindir( o ) struct oper *o; ! 111: { ! 112: switch (o->type_o){ ! 113: case T_DEFER : ! 114: if (o->value_o == A6REG) return 0; ! 115: else return 1; ! 116: case T_DISPL: ! 117: if (o->reg_o == A6REG) return 0; ! 118: else return 1; ! 119: case T_INDEX: ! 120: return 1; ! 121: default: ! 122: return 0; ! 123: } ! 124: } ! 125: ! 126: struct oper * ! 127: get_regcon( regno ) ! 128: int regno; ! 129: { ! 130: return ®con[regno][CONSRC].con; ! 131: } ! 132: ! 133: void ! 134: forgetall() ! 135: { ! 136: register regno; ! 137: for (regno=0; regno< NREG ; regno++){ ! 138: regcon[regno][CONSRC].con.type_o = T_NULL; ! 139: regcon[regno][CONDST].con.type_o = T_NULL; ! 140: } ! 141: nmem = 0; ! 142: } ! 143: ! 144: static void ! 145: forgetlocals(forgetsky) ! 146: { ! 147: register regno; ! 148: register struct sym_bkt *sk; ! 149: register struct oper *sp; ! 150: sk = (forgetsky) ? (struct sym_bkt *)-1 : skyname ; ! 151: for (regno=0; regno< NREG ; regno++){ ! 152: if ( (sp= ®con[regno][CONSRC].con)->type_o!=T_NULL ! 153: && sp->type_o!=T_IMMED && sp->sym_o != sk) ! 154: sp->type_o = T_NULL; ! 155: regcon[regno][CONDST].con.type_o = T_NULL; /* always */ ! 156: } ! 157: nmem = 0; ! 158: } ! 159: ! 160: static struct memcon * ! 161: memfind( o, l, inexact, startaddr, startn ) ! 162: register struct oper *o; ! 163: subop_t l; ! 164: int *inexact; ! 165: struct memcon *startaddr; ! 166: int *startn; ! 167: { ! 168: /* ! 169: * lookup this operand at this length in the memory/constant ! 170: * table. Return pointer to the slot where we find it. If ! 171: * the address-length correspondence is inexact, set *inexact. ! 172: * Assume cancache(o). ! 173: * Assume there is no aliasing problem in the memory table. ! 174: */ ! 175: register i; ! 176: register struct memcon *mo; ! 177: register operand_t t=o->type_o; ! 178: int membegin = 0, memend, conbegin, conend; ! 179: int r; ! 180: switch (t){ ! 181: case T_DISPL: ! 182: r = o->reg_o; ! 183: /* FALL THROUGH */ ! 184: case T_ABSS: ! 185: case T_ABSL: ! 186: case T_NORMAL: ! 187: membegin = o->value_o; ! 188: memend = membegin + BYTESIZE(l)-1; ! 189: break; ! 190: case T_DEFER: ! 191: r = o->value_o; ! 192: memend = membegin + BYTESIZE(l)-1; ! 193: } ! 194: for (i= *startn, mo = startaddr; --i >= 0; mo++ ) ! 195: if (mo->addr.type_o != T_NULL && t == mo->addr.type_o ){ ! 196: switch ( t ){ ! 197: case T_ABSS: ! 198: case T_ABSL: ! 199: case T_NORMAL: ! 200: if (o->sym_o != mo->addr.sym_o) continue; ! 201: conbegin = mo->addr.value_o; ! 202: goto compare; ! 203: case T_DISPL: ! 204: if (mo->addr.reg_o != r) continue; ! 205: conbegin = mo->addr.value_o; ! 206: goto compare; ! 207: case T_DEFER: ! 208: if (mo->addr.value_o != r) continue; ! 209: conbegin = 0; ! 210: compare: ! 211: conend = conbegin + BYTESIZE(mo->size)-1; ! 212: if ( membegin< conend && conbegin < memend ){ ! 213: *inexact = ! (membegin==conbegin && l==mo->size); ! 214: *startn = i; ! 215: return mo; ! 216: } ! 217: } ! 218: } ! 219: *startn = 0; ! 220: return NULL; ! 221: } ! 222: ! 223: struct oper * ! 224: memlookup( o, l ) ! 225: { ! 226: /* abstract away the "inexact" problem from memfind() */ ! 227: int inexact; ! 228: int ntable = nmem; ! 229: struct memcon *m = &memcon[-1]; ! 230: ! 231: while ( (m=memfind( o, l, &inexact, m+1, &ntable)) != NULL ) ! 232: if ( !inexact ) return (&m->value); ! 233: return NULL; ! 234: } ! 235: ! 236: int ! 237: regfind( o, l, inexact, firstreg, firstpart, part ) ! 238: register struct oper *o; ! 239: subop_t l; ! 240: int *inexact; ! 241: register firstpart; ! 242: int *part; ! 243: { ! 244: /* ! 245: * lookup this operand at this length in the register ! 246: * table. Return the register number that matched. If ! 247: * the address-length correspondence is inexact, set *inexact. ! 248: * Assume cancache(o) or o->type_o==T_IMMED. ! 249: */ ! 250: register i,j; ! 251: register struct regcon *mo; ! 252: register operand_t t=o->type_o; ! 253: int membegin , memend, conbegin, conend; ! 254: int r; ! 255: switch (t){ ! 256: case T_DISPL: ! 257: r = o->reg_o; ! 258: /* FALL THROUGH */ ! 259: case T_ABSS: ! 260: case T_ABSL: ! 261: case T_NORMAL: ! 262: membegin = o->value_o; ! 263: memend = membegin + BYTESIZE(l); ! 264: break; ! 265: case T_DEFER: ! 266: r = o->value_o; ! 267: membegin = 0; ! 268: memend = BYTESIZE(l); ! 269: } ! 270: for (i=firstreg ; i<NREG; i++ ){ ! 271: for (j=firstpart; j<=CONDST; j++){ ! 272: mo = & regcon[i][j]; ! 273: if (mo->con.type_o != T_NULL && t == mo->con.type_o ){ ! 274: switch ( t ){ ! 275: case T_IMMED: ! 276: if ((mo->con.flags_o & O_FLOAT) != (o->flags_o & O_FLOAT)){ ! 277: break; ! 278: } else if (mo->con.flags_o & O_FLOAT ){ ! 279: if (mo->con.fval_o == o->fval_o){ ! 280: *inexact = 0; ! 281: return i; ! 282: } ! 283: } else if (mo->con.value_o == o->value_o ! 284: && mo->con.sym_o == o->sym_o ){ ! 285: *inexact = 0; ! 286: return i; ! 287: } ! 288: break; ! 289: case T_ABSS: ! 290: case T_ABSL: ! 291: case T_NORMAL: ! 292: if (o->sym_o != mo->con.sym_o) continue; ! 293: conbegin = mo->con.value_o; ! 294: goto compare; ! 295: case T_DISPL: ! 296: conbegin = mo->con.value_o; ! 297: if (mo->con.reg_o != r) continue; ! 298: goto compare; ! 299: case T_DEFER: ! 300: conbegin = 0; ! 301: if (mo->con.value_o != r) continue; ! 302: compare: ! 303: conend = conbegin + BYTESIZE(mo->size); ! 304: if ( membegin< conend && conbegin < memend ){ ! 305: *inexact = ! (membegin==conbegin && l==mo->size); ! 306: *part = j; ! 307: return i; ! 308: } ! 309: } ! 310: } ! 311: } ! 312: firstpart = CONSRC; ! 313: } ! 314: return -1; ! 315: } ! 316: ! 317: int ! 318: reglookup( o, l ) ! 319: struct oper *o; ! 320: subop_t l; ! 321: { ! 322: /* abstract away the "inexact" problem from regfind() */ ! 323: int inexact, part; ! 324: int r; ! 325: r = regfind( o, l, &inexact, D0REG, CONSRC, &part ); ! 326: if ( inexact ) return -1; ! 327: else return r; ! 328: } ! 329: ! 330: static void ! 331: meminsert( o , v, l ) ! 332: struct oper *o; ! 333: struct oper *v; ! 334: subop_t l; ! 335: { ! 336: /* ! 337: * look for a free slot in the memcon table to insert an entry. ! 338: * try to add at the end, but if the table is complete, then look ! 339: * for holes. If we still cannot find anything, just forget it. ! 340: * Assume that our caller already tried for an address match ! 341: * and would have inserted by easier means if possible. ! 342: */ ! 343: struct memcon *m; ! 344: if (nmem < NMEM){ ! 345: /* regular case */ ! 346: m = &memcon[nmem++]; ! 347: } else { ! 348: /* have to search */ ! 349: for (m= &memcon[0]; m > &memcon[NMEM-1]; m++){ ! 350: if (m->addr.type_o == T_NULL) goto gotone; ! 351: } ! 352: return ; /* oh, just forget it */ ! 353: } ! 354: gotone: ! 355: m->addr = *o; ! 356: m->size = l; ! 357: m->value = *v; ! 358: } ! 359: ! 360: static void ! 361: put_in_mem_table( o, v, l) ! 362: struct oper *o; ! 363: struct oper *v; ! 364: subop_t l; ! 365: { ! 366: /* ! 367: * put this address/value in the memcon table ! 368: * deal with aliasing. This is tricky. ! 369: */ ! 370: int nalias = 0, nexact = 0; ! 371: int inexact, ntabl = nmem; ! 372: struct memcon * m; ! 373: int src, dest, nbytes ; ! 374: union stuff{ /* KNOWS ABOUT 68000 MEMORY LAYOUT !!! */ ! 375: char bytes[4]; ! 376: short words[2]; ! 377: long longword; ! 378: } mine, his; ! 379: int sympart = v->sym_o!=NULL; ! 380: ! 381: ! 382: /* initialize my equivalencing structure */ ! 383: mine.longword = 0L; ! 384: if (!sympart) ! 385: switch (l){ ! 386: case SUBOP_B: mine.bytes[0] = v->value_o; break; ! 387: case SUBOP_W: mine.words[0] = v->value_o; break; ! 388: default: mine.longword = v->value_o; break; ! 389: } ! 390: ! 391: m = &memcon[-1]; ! 392: while( (m=memfind( o, l, &inexact, m+1, &ntabl )) != NULL ){ ! 393: if (inexact) { ! 394: /* ! 395: * either the address or the length don't agree. ! 396: * fix up the current entry as appropriate, then continue. ! 397: */ ! 398: if (sympart || m->value.sym_o != NULL){ ! 399: /* ! 400: * had or will have symbolic part ! 401: * cannot deal with inexact matches ! 402: */ ! 403: m->addr.type_o = T_NULL; /* forget it */ ! 404: continue; ! 405: } ! 406: /* fill in his equivalencing structure */ ! 407: his.longword = 0L; ! 408: switch (m->size){ ! 409: case SUBOP_B: his.bytes[0] = m->value.value_o; break; ! 410: case SUBOP_W: his.words[0] = m->value.value_o; break; ! 411: default: his.longword = m->value.value_o; break; ! 412: } ! 413: if (o->value_o >= m->addr.value_o){ ! 414: /* new starts after old */ ! 415: src = 0; ! 416: dest = o->value_o - m->addr.value_o; ! 417: } else { ! 418: src = m->addr.value_o - o->value_o ; ! 419: dest = 0; ! 420: } ! 421: nbytes = BYTESIZE( l ); ! 422: if (nbytes > BYTESIZE( m->size )-dest ) ! 423: nbytes = BYTESIZE(m->size)-dest; ! 424: while (nbytes--){ ! 425: his.bytes[dest++] = mine.bytes[src++]; ! 426: } ! 427: /* shovel back */ ! 428: switch (m->size){ ! 429: case SUBOP_B: m->value.value_o = his.bytes[0]; break; ! 430: case SUBOP_W: m->value.value_o = his.words[0]; break; ! 431: default: m->value.value_o = his.longword; break; ! 432: } ! 433: nalias++; ! 434: } else { ! 435: m->value = *v; ! 436: nexact++; ! 437: } ! 438: } ! 439: if ((nalias && nexact) || (nalias>4)) ! 440: sys_error("Multiple aliasing in memory table\n"); ! 441: if (nalias==0 && nexact==0){ ! 442: /* new entry -- stick it in. */ ! 443: meminsert( o , v, l ); ! 444: } ! 445: } ! 446: ! 447: ! 448: static void ! 449: forgetop( o, l ) ! 450: struct oper *o; ! 451: subop_t l; ! 452: { ! 453: int r, inexact, part; ! 454: int ntable = nmem; ! 455: struct memcon *m = &memcon[-1]; ! 456: ! 457: r = D0REG; ! 458: part = CONSRC; ! 459: while( (r = regfind( o, l, &inexact, r, part, &part )) >= D0REG){ ! 460: regcon[ r ][ part ].con.type_o = T_NULL; ! 461: if ( ++part > CONDST ){ ! 462: r++; ! 463: part = CONSRC; ! 464: } ! 465: } ! 466: ! 467: while ( (m=memfind( o, l, &inexact, m+1, &ntable)) != NULL ) ! 468: m->addr.type_o = T_NULL; ! 469: } ! 470: ! 471: static void ! 472: substitute( p, op, new ) ! 473: NODE *p; ! 474: struct oper *op, *new; ! 475: { ! 476: /* ! 477: * p is an instruction. ! 478: * op points to an operand of that instruction. ! 479: * new points to a (register) operand structure that we want to ! 480: * substitute for the one op addresses. ! 481: * Do the substitution and calculate the new properties of p ! 482: */ ! 483: *op = *new; ! 484: installinstruct( p, p->instr ); ! 485: p->rlive = compute_normal( p, p->forw->rlive); ! 486: } ! 487: ! 488: static int ! 489: track_cc( n ) ! 490: NODE *n; ! 491: { ! 492: /* ! 493: * we just moved a constant into a register. ! 494: * look for subsequent compares/ tests of ! 495: * the register, followed by jumps, even after cc is kilt ! 496: */ ! 497: register struct oper *op2, *comperand; ! 498: struct oper *o; ! 499: register NODE *p; ! 500: NODE *target; ! 501: subop_t so; ! 502: long v, compval; ! 503: static struct oper conz = { T_IMMED, 0, 0, NULL, 0, 0, 0 }; ! 504: int didchange = 0; ! 505: ! 506: if (n->op==OP_MOVE){ ! 507: op2 = n->ref[1]; ! 508: comperand = n->ref[0]; ! 509: if (comperand->type_o != T_IMMED) return 0; ! 510: } else { ! 511: /* CLR */ ! 512: op2 = n->ref[0]; ! 513: comperand = &conz; ! 514: } ! 515: if (!deladdr(op2)) return 0; ! 516: so = n->subop; ! 517: v = comperand->value_o; ! 518: for (p = n->forw; p->op!=OP_FIRST ; p = p->forw){ ! 519: switch (p->op){ ! 520: case OP_LABEL: ! 521: continue; ! 522: case OP_JUMP: ! 523: if (p->subop==JALL){ ! 524: if (p->luse == p->back){ ! 525: /* selfloop */ ! 526: break; ! 527: } ! 528: /* follow! */ ! 529: p = p->luse->back; ! 530: continue; ! 531: } ! 532: break; ! 533: case OP_TST: ! 534: if ( sameops( p->ref[0], op2 ) && p->subop==so){ ! 535: if (comperand->sym_o!=NULL) break; ! 536: compval = 0; ! 537: goto regcmp; ! 538: } ! 539: break; ! 540: case OP_CMP: ! 541: if ( !sameops(p->ref[1], op2 ) ) break; ! 542: if ( (o=p->ref[0])->type_o != T_IMMED ) break; ! 543: if ( o->sym_o != comperand->sym_o ) break; ! 544: compval = o->value_o; ! 545: regcmp: ! 546: p=p->forw; ! 547: if (p->op==OP_JUMP){ ! 548: /* this is it */ ! 549: if (inmask( CCREG, p->luse->rlive ) || ! 550: (p->subop!=JALL && inmask( CCREG, p->forw->rlive))) ! 551: break; /* too hard -- must do the cmp */ ! 552: switch(p->subop){ ! 553: case JEQ: compval = v==compval; break; ! 554: case JNE: compval = v!=compval; break; ! 555: case JLE: compval = v<=compval; break; ! 556: case JGE: compval = v>=compval; break; ! 557: case JLT: compval = v< compval; break; ! 558: case JGT: compval = v> compval; break; ! 559: case JCC: compval = ((unsigned)v) >= ((unsigned)compval); break; ! 560: case JLS: compval = ((unsigned)v) <= ((unsigned)compval); break; ! 561: case JHI: compval = ((unsigned)v) > ((unsigned)compval); break; ! 562: case JCS: compval = ((unsigned)v) < ((unsigned)compval); break; ! 563: case JALL: compval = 1; break; ! 564: case JNONE: compval = 0; break; ! 565: default: goto nojmp; ! 566: } ! 567: if (compval) target = p->luse; ! 568: else{ ! 569: target = p->forw; ! 570: if (target->op!=OP_LABEL) ! 571: target = insert_label(target); ! 572: } ! 573: cannibalize( p=new(), "jra" ); ! 574: p->op = OP_JUMP; ! 575: newreference( target, p); ! 576: p->ruse = p->rset = regmask0; ! 577: p->rlive = target->rlive; ! 578: insert( p, n ); ! 579: didchange++; ! 580: meter.nxjump++; ! 581: /* ! 582: * we just created an unconditional jump. ! 583: * Follow it, just like jumps we find in code. ! 584: */ ! 585: p = p->luse->back; ! 586: continue; ! 587: } ! 588: } ! 589: nojmp: ! 590: break; ! 591: } ! 592: return didchange; ! 593: } ! 594: ! 595: static int ! 596: addrlookup( o ) ! 597: register struct oper *o; ! 598: { ! 599: struct oper q; ! 600: int regname; ! 601: /* ! 602: * assume that o points to an index mode, indirect address node. ! 603: * find the memory address through which we are indirecting ! 604: * and see if we already have it in an address register. If so, we ! 605: * can simplify the addressing mode in disindex(). ! 606: */ ! 607: if (o->flags_o&O_PREINDEX) return -1; ! 608: if (o->flags_o&O_BSUPRESS){ ! 609: q.type_o = T_NORMAL; ! 610: q.value_o = o->disp_o; ! 611: q.sym_o = o->sym_o; ! 612: q.flags_o = o->flags_o&O_COMPLEX; ! 613: } else { ! 614: q.type_o = T_DISPL; ! 615: q.reg_o = o->reg_o; ! 616: q.value_o = o->disp_o; ! 617: q.sym_o = o->sym_o; ! 618: q.flags_o = o->flags_o&O_COMPLEX; ! 619: if (q.value_o == 0 && q.sym_o == NULL) ! 620: q.type_o = T_DEFER; ! 621: } ! 622: if (!cancache( &q)) return -1; ! 623: regname = reglookup( &q, SUBOP_L ); ! 624: if (areg(regname)) return regname; ! 625: return -1; ! 626: } ! 627: ! 628: static void ! 629: disindex( o, regname ) ! 630: register struct oper *o; ! 631: int regname; ! 632: { ! 633: register flags; ! 634: /* ! 635: * o points to an operand of type T_INDEX with the O_INDIRECT flag set. ! 636: * o is not preindexed. The memory cell through which o indirects is ! 637: * also contained in the A register named by regname. o can be simplified ! 638: * because of this: secondary displacement becomes primary displacement, ! 639: * post indexing becomes pre indexing, and the operand is no longer indirect. ! 640: * it may be simplified to T_DEFER, T_DISPL, or T_INDEX. ! 641: */ ! 642: flags = o->flags_o & ~O_INDIRECT; ! 643: o->reg_o = regname; ! 644: o->disp_o = o->disp2_o; ! 645: o->sym_o = o->sym2_o; ! 646: if (flags&O_COMPLEX2) ! 647: flags = (flags & ~O_COMPLEX2) | O_COMPLEX; ! 648: if (flags&O_WDISP2) ! 649: flags = (flags & ~O_WDISP2)|O_WDISP; ! 650: else if (flags&O_LDISP2) ! 651: flags = (flags & ~O_LDISP2)|O_LDISP; ! 652: if ((flags & O_POSTINDEX) == 0){ ! 653: if (o->disp_o == 0 && o->sym_o == NULL){ ! 654: o->type_o = T_DEFER; ! 655: } else { ! 656: o->type_o = T_DISPL; ! 657: } ! 658: } else { ! 659: o->type_o = T_INDEX; ! 660: flags = (flags& ~O_POSTINDEX)|O_PREINDEX; ! 661: } ! 662: o->flags_o = flags; ! 663: } ! 664: ! 665: static void ! 666: kill_uses( regno ) ! 667: register int regno; ! 668: { ! 669: register struct regcon *r; ! 670: register struct memcon *m, *l; ! 671: for (r = ®con[0][CONSRC]; r <= ®con[NREG-1][CONDST]; r++) ! 672: if (r->con.type_o != T_NULL && operand_uses( &r->con, regno )){ ! 673: r->con.type_o = T_NULL; ! 674: } ! 675: for (m = &memcon[0], l = &memcon[nmem]; m < l; m++) ! 676: if (m->addr.type_o != T_NULL && operand_uses( &m->addr, regno)){ ! 677: m->addr.type_o = T_NULL; ! 678: } ! 679: } ! 680: ! 681: void ! 682: con_to_reg( regno, o, size ) ! 683: struct oper *o; ! 684: subop_t size; ! 685: { ! 686: struct regcon *r = ®con[regno][CONSRC]; ! 687: ! 688: regcon[regno][CONDST].con.type_o = T_NULL; ! 689: r->con = *o; ! 690: if (dreg(regno)) ! 691: r->size = size; ! 692: else if (areg(regno)) ! 693: r->size = SUBOP_L; ! 694: else ! 695: r->size = SUBOP_X; ! 696: if (Xperimental) ! 697: kill_uses( regno ); ! 698: } ! 699: ! 700: static int ! 701: use_moveq( n ) ! 702: register NODE *n; ! 703: { ! 704: NODE *p; ! 705: static struct oper reg = { T_REG, 0, 0, NULL, 0, 0, 0 }; ! 706: /* ! 707: * doing an immediate operation with a small constant. ! 708: * we can moveq the constant into a dead D register, ! 709: * then do operations from that register. As a bonus, ! 710: * we'll have the value around. ! 711: * Avoid the case of "movl #3,d3". This will get fixed ! 712: * in quicken() later on. ! 713: */ ! 714: ! 715: if (!long_immediate(n->op) ! 716: || n->subop != SUBOP_L ! 717: || (reg.value_o=dead_dreg(n))<0 ! 718: || !operand_ok(n->instr, ®, n->ref[1], 0) ! 719: || (n->op==OP_MOVE && dreg_addr( n->ref[1] ) )){ ! 720: return 0; ! 721: } ! 722: p = new(); ! 723: p->nref = 2; ! 724: p->ref[0] = newoperand( n->ref[0] ); ! 725: p->ref[1] = newoperand( ® ); ! 726: insert( p, n->back ); ! 727: con_to_reg( reg.value_o, n->ref[0], SUBOP_L ); ! 728: substitute( n, n->ref[0], ® ); ! 729: installinstruct( p, moveq ); ! 730: p->rlive = compute_normal( p, n->rlive ); ! 731: return 1; ! 732: } ! 733: ! 734: static void ! 735: kill_cached_mem( n, touchop ) ! 736: register NODE *n; ! 737: register touchop; ! 738: { ! 739: register i; ! 740: /* if a local is modified, invalidate our cached value */ ! 741: for (i=0;i<n->nref;i++){ ! 742: if (touchop&(BW|LW|WW)) ! 743: if (isindir(n->ref[i])) ! 744: forgetlocals(0); ! 745: else if ( cancache(n->ref[i])) ! 746: forgetop( n->ref[i], n->subop ); ! 747: touchop >>= TOUCHWIDTH; ! 748: } ! 749: } ! 750: ! 751: dumpmem(){ ! 752: int i,j; ! 753: extern char *rnames[]; ! 754: static char sizes[] = "bwlsdxp"; ! 755: for (i=0; i<NREG; i++){ ! 756: printf("%s : ", rnames[i]); ! 757: for (j=0; j <= 1; j++) ! 758: if (regcon[i][j].con.type_o == T_NULL) ! 759: printf("XXXX "); ! 760: else{ ! 761: printoperand( ®con[i][j].con ); ! 762: printf("{%c} ", sizes[(int)regcon[i][j].size]); ! 763: } ! 764: printf("\n"); ! 765: } ! 766: printf("\n"); ! 767: for (i=0; i<nmem; i++){ ! 768: if (memcon[i].addr.type_o != T_NULL){ ! 769: printoperand( &memcon[i].addr ); ! 770: printf("{%c}: ", sizes[(int)memcon[i].size]); ! 771: printoperand( &memcon[i].value ); ! 772: printf("\n"); ! 773: } ! 774: } ! 775: } ! 776: ! 777: static int ! 778: substitute_move( n, o, reg, saveop ) ! 779: register NODE *n; ! 780: struct oper *o, *reg, *saveop; ! 781: { ! 782: if (n->instr == moveq) ! 783: return 0; ! 784: substitute( n, o, reg ); ! 785: if (saveop->type_o==T_IMMED && cancache(n->ref[1])) ! 786: put_in_mem_table( n->ref[1], saveop, n->subop ); ! 787: meter.nsaddr++; ! 788: return 1; ! 789: } ! 790: ! 791: /* ! 792: * we really should be doing flow analysis here. ! 793: * lacking that, recognize special case SKY code: ! 794: * 1: tstw a1@(-4) ! 795: * bge 1b ! 796: */ ! 797: # define CHECK_LABEL(n) \ ! 798: if (n->op==OP_LABEL){ \ ! 799: if (!(n->nref==1 && n->luse==n->forw->forw && emptymask(n->forw->rset) && n->forw->forw->op==OP_JUMP)) forgetall(); \ ! 800: continue; } ! 801: ! 802: # define IMMED_OR_SKY( o ) \ ! 803: (o->type_o==T_IMMED || (o->type_o==T_NORMAL && o->value_o==0 && o->sym_o==skyname)) ! 804: ! 805: /* move to self: kill unless cc live */ ! 806: # define DELETE_SELFMOVES( n ) \ ! 807: if ( n->ref[1]->value_o==regno && (!inmask( CCREG, n->forw->rlive) || areg(regno))){ \ ! 808: n = deletenode( n ); meter.redunm++; didchange++; continue; } ! 809: ! 810: # define SMALL_IMMED( o ) \ ! 811: ((o)->type_o==T_IMMED && (o)->sym_o==NULL && !((o)->flags_o&O_FLOAT) && (v=(o)->value_o)>=-128 && v<=127) ! 812: ! 813: int ! 814: content() ! 815: { ! 816: /* ! 817: * Follow the flow of control (roughly). Look at loads into ! 818: * registers. When a constant is loaded we know: ! 819: * 1) how the CC is set. ! 820: * 2) a cheap source of that constant. ! 821: * Special case if the same register is reloaded with that constant. ! 822: * SPECIAL HACK: Assume that the contents of the global var named ! 823: * "__skybase" are constant!! ! 824: */ ! 825: register NODE *n; ! 826: register v, regno; ! 827: register struct oper *o; ! 828: struct oper *op2, *op3; ! 829: int didchange=0; ! 830: int local_read, dest_reg; ! 831: int i; ! 832: struct oper saveop; ! 833: ! 834: ! 835: static struct oper reg = { T_REG, 0, 0, NULL, 0, 0, 0 }; ! 836: ! 837: /* initialize constant table to empty. Find __skybase */ ! 838: forgetall(); ! 839: if (skyname==NULL) skyname = lookup("__skybase"); ! 840: #if TRACKSP ! 841: spoffset=0; ! 842: #endif TRACKSP ! 843: ! 844: for (n=first.forw; n!=&first; n=n->forw){ ! 845: CHECK_LABEL(n); ! 846: if (!ISINSTRUC(n->op)) continue; ! 847: dest_reg = -1; ! 848: if (n->nref){ ! 849: v = make_touchop( n, n->instr->touchop_i); ! 850: kill_cached_mem( n, v ); ! 851: o = n->ref[0]; ! 852: local_read = cancache(o) && (v&(BW|LW|WW))==0; ! 853: if (IMMED_OR_SKY( o ) || local_read ){ ! 854: /* do lookup -- do we already have it */ ! 855: regno = reglookup( o, n->subop ); ! 856: if (regno>=0 ){ ! 857: /* try to substitute */ ! 858: reg.value_o = regno; ! 859: saveop = *o; ! 860: if (operand_ok(n->instr, ®, n->ref[1], 0)){ ! 861: if (n->op==OP_MOVE){ ! 862: didchange += substitute_move( n, o, ®, &saveop ); ! 863: if ( datareg_addr( n->ref[1] ) ){ ! 864: DELETE_SELFMOVES( n ); ! 865: con_to_reg( n->ref[1]->value_o, &saveop, n->subop ); ! 866: didchange += track_cc(n); ! 867: dest_reg = n->ref[1]->value_o; ! 868: } ! 869: } else { ! 870: /* not a move -- don't think, just do it */ ! 871: substitute( n, o, ® ); ! 872: meter.nsaddr++; ! 873: didchange++; ! 874: } ! 875: } ! 876: } ! 877: if (n->nref==2 && SMALL_IMMED( o )){ ! 878: didchange+= use_moveq( n ); ! 879: } ! 880: if (local_read && (op2=memlookup(o, n->subop))!= NULL){ ! 881: /* ! 882: * this is a local that contains an immediate at this ! 883: * time. substitute the immediate value for the mem-op, ! 884: * if we may. ! 885: */ ! 886: if (operand_ok(n->instr, op2, n->ref[1], 0)){ ! 887: substitute( n, o, op2 ); ! 888: meter.nsaddr++; ! 889: didchange++; ! 890: } ! 891: } ! 892: if (n->op==OP_MOVE){ ! 893: op2 = n->ref[1]; ! 894: if (datareg_addr(op2)){ ! 895: /* move to a register */ ! 896: con_to_reg( op2->value_o, o, n->subop ); ! 897: } else if (cancache( op2)){ ! 898: if(o->type_o==T_IMMED ) ! 899: put_in_mem_table( op2, o, n->subop ); ! 900: else if (o->type_o==T_REG && datareg( regno=o->value_o ) ! 901: && (op3= ®con[regno][CONSRC].con)->type_o == T_IMMED) ! 902: put_in_mem_table( op2, op3, n->subop ); ! 903: } ! 904: /* ! 905: * we may have moved a constant into a register. ! 906: * look for subsequent compares/ tests of ! 907: * the register, followed by jumps, even after cc is kilt ! 908: */ ! 909: didchange += track_cc(n); ! 910: if (op2->type_o == T_REG) ! 911: dest_reg = op2->value_o; ! 912: } ! 913: } else if (n->op==OP_MOVE && n->ref[0]->type_o==T_REG ! 914: && cancache( n->ref[1] )){ ! 915: /* movl d0,a6@(4) ; movl a6@(4),d1 */ ! 916: regcon[v=n->ref[0]->value_o][CONDST].con = *(n->ref[1]); ! 917: regcon[v][CONDST].size = n->subop; ! 918: dest_reg = v; ! 919: } else if (n->op==OP_CALL){ ! 920: forgetlocals(1); ! 921: } else if (n->op==OP_CLR){ ! 922: didchange += track_cc(n); ! 923: if (n->ref[0]->type_o == T_REG) ! 924: dest_reg = n->ref[0]->value_o; ! 925: } ! 926: /* ! 927: * try to avoid indirecting through things ! 928: * of which we already know the value ! 929: */ ! 930: for (i=n->nref, v=0; v<i; v++){ ! 931: if ((o = n->ref[v])->type_o == T_INDEX && (o->flags_o&O_INDIRECT)) ! 932: if ((regno = addrlookup( o )) >= 0 ){ ! 933: disindex( o, regno ); ! 934: substitute( n, o, o ); ! 935: meter.nsaddr++; ! 936: } ! 937: } ! 938: } ! 939: if (!emptymask(n->rset) ){ ! 940: /* kill a constant value */ ! 941: register sets = n->rset.da; ! 942: while (sets){ ! 943: v = ffs(sets)-1; ! 944: sets ^= 1<<v; ! 945: if (v<24) ! 946: v /=3; ! 947: else ! 948: v -=(24-A0REG); ! 949: if ( v == dest_reg ) ! 950: continue; ! 951: regcon[v][CONSRC].con.type_o = T_NULL; ! 952: regcon[v][CONDST].con.type_o = T_NULL; ! 953: if (Xperimental) ! 954: kill_uses( v ); ! 955: #ifdef TRACKSP ! 956: if (v==SPREG){ ! 957: /* try to keep track of distance from a6 to a7 */ ! 958: track_sp( n ); ! 959: } ! 960: #endif TRACKSP ! 961: } ! 962: sets = n->rset.f & 0377; /* registers only, no cc */ ! 963: while (sets){ ! 964: v = ffs(sets)-1; ! 965: sets ^= 1<<v; ! 966: v += FP0REG; ! 967: if ( v == dest_reg ) ! 968: continue; ! 969: regcon[v][CONSRC].con.type_o = T_NULL; ! 970: regcon[v][CONDST].con.type_o = T_NULL; ! 971: } ! 972: } ! 973: } ! 974: return didchange; ! 975: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.