|
|
1.1 ! root 1: /* @(#) func.c: 1.4 4/28/84 */ ! 2: ! 3: /* func.c ! 4: ** ! 5: ** Function improvement routines ! 6: ** ! 7: ** ! 8: ** This file contains routines that require knowledge of a whole ! 9: ** function or more to perform their optimizations. ! 10: */ ! 11: ! 12: #include "optim.h" ! 13: #include "optutil.h" ! 14: #include "storclass.h" ! 15: #include <string.h> ! 16: #include "paths.h" ! 17: ! 18: /* Macro to add new instruction: ! 19: ** opn op code number of new instruction ! 20: ** opst op code string of new instruction ! 21: ** opn1 operand 1 for new instruction ! 22: ** opn2 operand 2 for new instruction ! 23: */ ! 24: ! 25: #define addi(opn,opst,opn1,opn2) \ ! 26: { \ ! 27: pn = insert( pn ); /* get new node */ \ ! 28: chgop( pn, opn, opst ); /* put in opcode num, str */ \ ! 29: pn->op1 = opn1; /* put in operands */ \ ! 30: pn->op2 = opn2; \ ! 31: } ! 32: #define opm ops[MAXOPS] ! 33: ! 34: #ifdef IMPREGAL ! 35: /* register allocation optimization ! 36: ** ! 37: ** F. B. Wolverton 6/16/83 ! 38: ** ! 39: ** This optimization accepts a list of autos and args from the ! 40: ** compiler and assigns them to registers if there is sufficient estimated ! 41: ** payoff. ! 42: ** ! 43: ** Scratch registers are used first, if they are available, ! 44: ** because they are "free". A variable can be put into a scratch register if ! 45: ** (a) the register is not used by any instruction in the procedure, ! 46: ** (b) the variable is dead, i.e., not used before being set, ! 47: ** following any call in the procedure ! 48: ** ! 49: ** Register 3 is considered a scratch register, if IMPSCRATCH is defined. ! 50: ** ! 51: ** Next registers r8 through r4 are assigned (and r3, if it has not been used ! 52: ** as a scratch register). ! 53: ** ! 54: ** Register variables assigned by the compiler are assigned first. A variable ! 55: ** the compiler assigned to a user register may get assigned to a scratch ! 56: ** register by the optimizer. ! 57: ** ! 58: ** Variables in the list of autos and args are assigned next. ! 59: ** ! 60: ** The cumulative cost for puting all variables up to a given variable ! 61: ** into registers is computed and used to select a cutoff. ! 62: ** All register variables assigned by the compiler remain in ! 63: ** registers. Other variables are assigned only if the ! 64: ** estimated payoff os positive. ! 65: ** ! 66: ** Instruction operands are modified to reflect the additional assignments. ! 67: ** ! 68: */ ! 69: ! 70: #define MAXREGS 10 ! 71: #define MAXVARS 20 ! 72: ! 73: /* variable storage classes */ ! 74: ! 75: #define SCLNULL 0 ! 76: #define AUTO 1 ! 77: #define REGISTER 4 ! 78: #define PARAM 9 ! 79: ! 80: /* register types */ ! 81: ! 82: #define SCRATCH 0 ! 83: #define USER 1 ! 84: ! 85: /* register status */ ! 86: ! 87: #define AVAIL 0 ! 88: #define NOTAVAIL 1 ! 89: ! 90: /* cycle estimates for BELLMAC-32B instructions */ ! 91: ! 92: #define CYCSAVE 39 /* SAVE and RESTORE with 0 user registers */ ! 93: #define CYCDELTA 5 /* delta to save and restore an additional register */ ! 94: #define CYCADD 6 /* ADD small literal to stack pointer */ ! 95: #define CYCMOVS 16 /* MOVW from register to register offset and back */ ! 96: #define CYCAWORD 7 /* MOVAW of register offset to frame pointer */ ! 97: #define CYCPUSH 10 /* PUSH a regsiter */ ! 98: #define CYCPOP 10 /* POPW a value into a register */ ! 99: ! 100: struct hinode { /* ordered table of variables with highest estimators */ ! 101: int hiestim; /* estimator of cycle payoff */ ! 102: int hiscl; /* scl of quant to put in reg */ ! 103: char* hiname; /* name of quantity: ! 104: * local offset ! 105: * argument offset*/ ! 106: int hilen; /* length in bytes of quantity */ ! 107: } high[MAXVARS]; ! 108: ! 109: int vars = 0; /* number of variables stored in 'high' array */ ! 110: int nodblflg = 0; /* flag indicating absence of doubles */ ! 111: ! 112: struct assign { ! 113: char *asrname; /* register name */ ! 114: char *asrind; /* indirect reference through register */ ! 115: int asrtype; /* register type */ ! 116: int asrsave; /* number of user registers saved */ ! 117: int asavail; /* availabilty of register */ ! 118: int asestim; /* estimator of cycle payoff of assigned variable */ ! 119: int asvscl; /* storage class of variable assigned */ ! 120: char *asvname; /* variable name */ ! 121: int asvlen; /* variable lenggth in bytes */ ! 122: } asreg[MAXREGS] = { ! 123: { "%r0", "0(%r0)", SCRATCH, 0 }, ! 124: { "%r1", "0(%r1)", SCRATCH, 0 }, ! 125: { "%r2", "0(%r2)", SCRATCH, 0 }, ! 126: { "%r3", "0(%r3)", SCRATCH, 0 }, ! 127: { "%r8", "0(%r8)", USER, 1 }, ! 128: { "%r7", "0(%r7)", USER, 2 }, ! 129: { "%r6", "0(%r6)", USER, 3 }, ! 130: { "%r5", "0(%r5)", USER, 4 }, ! 131: { "%r4", "0(%r4)", USER, 5 }, ! 132: { "%r3", "0(%r3)", USER, 6 } ! 133: }; ! 134: ! 135: /* Note that register 3 appears twice. It is used as a scratch register if ! 136: ** possible and as a user register otherwise. ! 137: */ ! 138: ! 139: char* rnames[] = { "%r8", "%r7", "%r6", "%r5", "%r4", "%r3" }; ! 140: ! 141: ! 142: /* routine to read in table of variables stored in high[] */ ! 143: ! 144: void ! 145: ratable( p ) ! 146: register char *p; ! 147: ! 148: { ! 149: extern int atoi(); ! 150: register char *q, *r; ! 151: ! 152: /* check for table overflow */ ! 153: if( vars >= MAXVARS ) return; ! 154: ! 155: /* scan to estimator and read it */ ! 156: while( *p++ != '\t' ); ! 157: high[vars].hiestim = atoi( p ); ! 158: ! 159: /* scan to storage class and read it */ ! 160: while( *p++ != '\t' ); ! 161: switch (*p) { ! 162: case 'A': high[vars].hiscl = AUTO; break; ! 163: case 'P': high[vars].hiscl = PARAM; break; ! 164: /* set doubles flag */ ! 165: case 'N': nodblflg = 1; return; ! 166: } ! 167: ! 168: /* scan to name and read it */ ! 169: while( *p++ != '\t' ); ! 170: q = p; ! 171: while( *q++ != '\t' ); ! 172: high[vars].hiname = r = getspace( q - p ); ! 173: while( p < ( q - 1 ) ) *r++ = *p++; ! 174: *r = '\0'; ! 175: ! 176: /* read length */ ! 177: high[vars].hilen = atoi(q); ! 178: ! 179: /* increment table index */ ! 180: vars++; ! 181: return; ! 182: } ! 183: ! 184: ! 185: /* main routine for register allocation optimization */ ! 186: ! 187: int ! 188: raoptim( numnreg, numauto ) ! 189: register int numnreg; /* input number of registers saved/restored */ ! 190: register int numauto; /* number of words of automatic variables */ ! 191: ! 192: { ! 193: void raavail(), ravassign(), raremove(), raopn(), raparam(), radef(); ! 194: void rainsld(), raremld(); ! 195: int rarassign(), racut(); ! 196: int iascut; /* index for assignment cutoff */ ! 197: int iasrlast; /* index of the last register variable assigned */ ! 198: int newnreg; /* new number of registers to be saved */ ! 199: register int ias; ! 200: ! 201: /* check for doubles */ ! 202: if( nodblflg == 0 ) { ! 203: vars = 0; ! 204: return( numnreg ); ! 205: } ! 206: ! 207: /* initialize assignment table */ ! 208: for( ias = 0; ias < MAXREGS; ias++ ) { ! 209: asreg[ias].asavail = AVAIL; ! 210: asreg[ias].asvscl = SCLNULL; ! 211: asreg[ias].asvlen = 0; ! 212: } ! 213: ! 214: /* determine availability of scratch registers */ ! 215: raavail( numnreg ); ! 216: ! 217: /* insert branch pointers for live/dead analysis */ ! 218: rainsld(); ! 219: ! 220: /* assign register variables */ ! 221: iasrlast = rarassign( numnreg ); ! 222: ! 223: /* assign non-register variables */ ! 224: ravassign(); ! 225: ! 226: /* remove remove branch pointers from live/dead analysis */ ! 227: raremld(); ! 228: ! 229: /* compute cutoff from cumulative payoff */ ! 230: iascut = racut( numnreg, numauto, iasrlast ); ! 231: if( iascut < 0 ) { /* if no payoff for this optimization */ ! 232: vars = 0; ! 233: return( numnreg ); ! 234: } ! 235: newnreg = asreg[iascut].asrsave; ! 236: ! 237: /* modify the instruction operands */ ! 238: raopn( iascut, newnreg ); ! 239: ! 240: /* insert moves for parameters */ ! 241: raparam( iascut ); ! 242: ! 243: /* modify def statements */ ! 244: radef( iascut ); ! 245: ! 246: /* re-initailize for next procedure */ ! 247: vars = 0; ! 248: return( newnreg ); ! 249: } ! 250: ! 251: /* determine availability of scratch registers */ ! 252: void ! 253: raavail( numnreg ) ! 254: int numnreg; /* input number of registers to be saved/restored */ ! 255: { ! 256: register NODE *pn; ! 257: register struct assign *pa; ! 258: register int iop, i; ! 259: register char *p; ! 260: struct assign *map[MAXREGS]; ! 261: ! 262: /* check availability of scratch %r3 */ ! 263: if( numnreg == 6 ) asreg[3].asavail = NOTAVAIL; ! 264: else asreg[9].asavail = NOTAVAIL; ! 265: #ifndef IMPSCRATCH ! 266: asreg[3].asavail = NOTAVAIL; ! 267: asreg[9].asavail = AVAIL; ! 268: #endif /* IMPSCRATCH */ ! 269: ! 270: /* set up mapping for scratch registers */ ! 271: for( i = 0; i < MAXREGS; i++ ) map[i] = NULL; ! 272: for( i = 0; i < MAXREGS; i++ ) { ! 273: pa = &asreg[i]; ! 274: if( pa->asrtype == SCRATCH && pa->asavail == AVAIL ) ! 275: map[*( pa-> asrname + 2 ) - '0'] = pa; ! 276: } ! 277: ! 278: /* scan for uses */ ! 279: for( ALLN( pn ) ) { /* scan nodes */ ! 280: if( pn->op == FILTER ) continue; ! 281: /* check for use of scratch registers */ ! 282: for( iop = 1; iop < MAXOPS + 1; iop++ ) { /* scan operands */ ! 283: if( ( p = pn->ops[iop] ) == NULL ) continue; ! 284: while( *p != '\0' ) { ! 285: if( *p++ != '%' ) continue; ! 286: if( *p++ != 'r' ) break; ! 287: pa = map[*p - '0']; ! 288: if( pa != NULL ) pa->asavail = NOTAVAIL; ! 289: break; ! 290: } ! 291: } ! 292: } ! 293: } ! 294: ! 295: /* insert pointers for live/dead analysis */ ! 296: void ! 297: rainsld() ! 298: { ! 299: register NODE *pn, *qn; ! 300: register char *ppn; ! 301: ! 302: for( ALLN( pn ) ) { ! 303: if( isbr( pn ) && !isret( pn ) ) { ! 304: ppn = getp( pn ); ! 305: /* use wraparound scan when looking for label */ ! 306: for( qn = ( pn->forw != &ntail ) ? pn->forw : n0.forw; ! 307: qn != pn; qn = ( qn->forw != &ntail ) ? ! 308: qn->forw : n0.forw ) { ! 309: if( islabel( qn ) ) { ! 310: if(*(ppn + 2) != *(qn->ops[0] + 2) && ! 311: *(ppn + 1) != '\0' ) ! 312: continue; /* for speed */ ! 313: if( strcmp( ppn, qn->ops[0] ) == 0 ){ ! 314: pn -> opm = (char *) qn; ! 315: break; ! 316: } ! 317: } ! 318: } ! 319: } ! 320: } ! 321: } ! 322: ! 323: /* assign register variables */ ! 324: int ! 325: rarassign( numnreg ) ! 326: register int numnreg; /* input number of registers to be saved/restored */ ! 327: { ! 328: register struct assign *pa; ! 329: register int ias, ireg, ok; ! 330: int iasrlast; ! 331: ! 332: iasrlast = -1; ! 333: ! 334: /* assign to first available register, and mark unavailable */ ! 335: for( ireg = 0; ireg < numnreg; ireg++ ) { ! 336: /* check whether is dead at CALL's etc. */ ! 337: ok = raregok( rnames[ireg], 0 ); ! 338: for( ias = 0; ias < MAXREGS; ias++ ) { ! 339: pa = &asreg[ias]; ! 340: if( pa->asavail == NOTAVAIL ) continue; ! 341: if( pa->asrtype == SCRATCH && !ok ) continue; ! 342: ! 343: /* assign it */ ! 344: pa->asavail = NOTAVAIL; ! 345: pa->asestim = 0; ! 346: pa->asvscl = REGISTER; ! 347: pa->asvname = rnames[ireg]; ! 348: pa->asvlen = 4; ! 349: if( iasrlast < ias ) iasrlast = ias; ! 350: break; ! 351: } ! 352: } ! 353: return( iasrlast ); ! 354: } ! 355: ! 356: /* assign non-register variables */ ! 357: void ! 358: ravassign() ! 359: { ! 360: register int ivar, ias, ok; ! 361: register struct assign *pa; ! 362: register struct hinode *ph; ! 363: ! 364: /* go through variables */ ! 365: for( ivar = 0; ivar < vars; ivar++ ) { ! 366: ph = &high[ivar]; ! 367: /* check to see if dead at CALL's etc. */ ! 368: ok = raregok(ph->hiname, ph->hilen); ! 369: /* assign to first register that qualifies */ ! 370: for( ias = 0; ias < MAXREGS; ias++ ) { ! 371: pa = &asreg[ias]; ! 372: if( pa->asavail == NOTAVAIL ) continue; ! 373: if( pa->asrtype == SCRATCH && !ok ) continue; ! 374: ! 375: /* assign it */ ! 376: pa->asavail = NOTAVAIL; ! 377: pa->asestim = ph->hiestim; ! 378: pa->asvscl = ph->hiscl; ! 379: pa->asvname = ph->hiname; ! 380: pa->asvlen = ph->hilen; ! 381: break; ! 382: } ! 383: } ! 384: } ! 385: ! 386: /* check if dead at CALL's etc. */ ! 387: int ! 388: raregok( name, len ) ! 389: register char *name; /* pointer to register or variable name */ ! 390: register int len; /* length of variable (0 for register) */ ! 391: { ! 392: register NODE *pn; ! 393: NODE *rald(); ! 394: ! 395: for( pn = n0.forw; pn != 0; pn = pn->forw ) { /* scan nodes */ ! 396: switch( pn->op ) { ! 397: default: continue; ! 398: case CALL: ! 399: case JSB: ! 400: case MOVBLB: ! 401: case MOVBLH: ! 402: case MOVBLW: ! 403: /* check if 'name' is live */ ! 404: if( rald( pn->forw, name, len ) != NULL ) return( 0 ); ! 405: } ! 406: } ! 407: /* dead */ ! 408: return( 1 ); ! 409: } ! 410: ! 411: /* check for register or variable dead in a block */ ! 412: /* Note that this routine may visit a block more than ! 413: * once, but that it cannot loop because any closed path ! 414: * in the program contains at least one label, and the ! 415: * routine will not scan a block beginning with a given ! 416: * label more than once. ! 417: */ ! 418: NODE * ! 419: rald( pn, name, len ) ! 420: register NODE *pn; /* pointer to block to be searched */ ! 421: register char *name; /* pointer to register or variable name */ ! 422: register int len; /* length of variable (0 for register) */ ! 423: { ! 424: NODE *qn; ! 425: register int iop; ! 426: register char *p; ! 427: int srcsize, dstsize; ! 428: ! 429: /* scan block */ ! 430: for( ; pn != 0; pn = pn->forw ) { ! 431: if( pn->op == FILTER ) continue; ! 432: /*control recursion */ ! 433: if( islabel( pn ) ) { ! 434: /* terminate recursion if this block has been visited */ ! 435: if( pn->opm == name ) return( NULL ); ! 436: /* mark block as visited */ ! 437: pn->opm = name; ! 438: continue; ! 439: } ! 440: /* if no references, its dead */ ! 441: if( isret( pn ) ) return( NULL ); ! 442: /* end of block */ ! 443: if( isbr( pn ) ) break; ! 444: /* check operands of remaining instructions */ ! 445: for( iop = 1; iop < MAXOPS + 1; iop++ ) { ! 446: p = pn->ops[iop]; ! 447: if( p == NULL ) continue; ! 448: /* look for register or variable */ ! 449: if( ( *name == '%' && usesreg( p, name ) ) || ! 450: rausesoff( p, name, len ) ) { ! 451: /* see if it's a destination */ ! 452: if( iop==2 && ( length(name) == length(p) ) ! 453: && ismove( pn, &srcsize, &dstsize )) ! 454: return( NULL ); ! 455: if( iop==3 && ( length(name) == length(p) )) { ! 456: switch ( pn->op ) { ! 457: case ANDB3: case ANDH3: case ANDW3: ! 458: case ORB3: case ORH3: case ORW3: ! 459: case XORB3: case XORH3: case XORW3: ! 460: case LLSW3: case LRSW3: ! 461: case ADDB3: case ADDH3: case ADDW3: ! 462: case SUBB3: case SUBH3: case SUBW3: ! 463: case MULW3: case UMULW3: ! 464: case DIVW3: case UDIVW3: ! 465: case MODW3: case UMODW3: ! 466: case ALSW3: case ARSW3: ! 467: return( NULL ); ! 468: } ! 469: } ! 470: /* nope, it's live */ ! 471: return( pn ); ! 472: } ! 473: } ! 474: } ! 475: /* examine next block(s) recursively */ ! 476: if( pn->opm == NULL ) return( pn ); /* dst not a simple label */ ! 477: ! 478: if( ( qn = rald( (NODE *) pn->opm, name, len ) ) != NULL ) return( qn ); ! 479: if( isuncbr( pn ) ) return( NULL ); ! 480: qn = rald( pn->forw, name, len ); ! 481: return( qn ); ! 482: } ! 483: ! 484: /* remove branch information from live/dead analysis */ ! 485: void ! 486: raremld() ! 487: { ! 488: register NODE *pn; ! 489: ! 490: for( pn = n0.forw; pn != 0; pn = pn->forw ) { ! 491: if( isbr( pn ) || islabel( pn ) ) pn->opm = NULL; ! 492: } ! 493: } ! 494: ! 495: /* compute cutoff from cumulative payoff */ ! 496: int ! 497: racut( numnreg, numauto, iasrlast ) ! 498: int numnreg; /* input number of registers saved */ ! 499: int numauto; /* number of autos */ ! 500: int iasrlast; /* index of last assigned register variable */ ! 501: { ! 502: int rsave(), rsaveo(); ! 503: int vcumul; /* cumulative payoff for variables */ ! 504: int rcumul; /* cumulative payoff for reg save/restore */ ! 505: int cumul; /* cumulative total payoff */ ! 506: int paycut; /* payoff for cutoff register */ ! 507: int oldsave; /* cycles to save and restore */ ! 508: int oldsaveo; /* cycles to save and restore with func call opt */ ! 509: int ias, iascut; ! 510: struct assign *pa; ! 511: ! 512: vcumul = 0; ! 513: iascut = iasrlast; ! 514: paycut = 0; ! 515: oldsave = rsave( numnreg, numauto ); ! 516: ! 517: for( ias = 0; ias < MAXREGS; ias ++ ) { ! 518: ! 519: /* skip if no assignment */ ! 520: pa = &asreg[ias]; ! 521: if( pa->asvscl == SCLNULL ) continue; ! 522: ! 523: /* compute cumulative variable payoff */ ! 524: vcumul += pa->asestim; ! 525: ! 526: /* compute cost/payoff from save and restore */ ! 527: rcumul = oldsave - rsave( pa->asrsave, numauto ); ! 528: ! 529: /* add cumulative payoffs, find max of last reg and all var */ ! 530: cumul = vcumul + rcumul; ! 531: if( ias >= iasrlast && cumul >= paycut ) { ! 532: paycut = cumul; ! 533: iascut = ias; ! 534: } ! 535: /* ! 536: printf( "#ias=%d %s asestim=%d %s vcumul=%d rcumul=%d cumul=%d iascut=%d\n", ! 537: ias,pa->asrname,pa->asestim,pa->asvname,vcumul,rcumul,cumul,iascut ); ! 538: */ ! 539: } ! 540: return( iascut ); ! 541: } ! 542: /* compute estimated save/restore cycles without func call optimization */ ! 543: int ! 544: rsave( n, numauto ) ! 545: int n; /* number of registers to save/restore, not including frame pointer */ ! 546: int numauto; /* number of autos */ ! 547: ! 548: { ! 549: int e; ! 550: ! 551: if( numauto ) e = CYCSAVE + n * CYCDELTA + CYCADD ; ! 552: else e = CYCSAVE + n * CYCDELTA ; ! 553: return e; ! 554: } ! 555: ! 556: /* modify the operands */ ! 557: void ! 558: raopn( iascut, newnreg ) ! 559: int iascut; /* index for assignment cutoff */ ! 560: int newnreg; /* new number of registers to be saved/restored */ ! 561: { ! 562: register char *p, *q, *q2; ! 563: NODE *pn; ! 564: register struct assign *pa, *pacut; ! 565: struct assign *pamin; ! 566: int iop; ! 567: static char* numbers[] = { "&0", "&1", "&2", "&3", "&4", "&5", "&6" }; ! 568: struct assign *map[MAXREGS]; ! 569: int i; ! 570: ! 571: /* suppress changes for registers assigned to themselves */ ! 572: pamin = &asreg[0]; ! 573: pacut = &asreg[iascut]; ! 574: for( pa = pamin; pa <= pacut; pa++ ) { ! 575: if( strcmp( pa->asvname, pa->asrname ) == 0 ) ! 576: pa->asvscl = SCLNULL; ! 577: } ! 578: ! 579: /* set up mapping for registers */ ! 580: for( i = 0; i < MAXREGS; i++ ) map[i] = NULL; ! 581: for( pa = pamin; pa <= pacut; pa++ ) ! 582: if( pa->asvscl == REGISTER ) ! 583: map[ *( pa->asvname + 2 ) - '0'] = pa; ! 584: ! 585: /* make changes on the rest */ ! 586: for( ALLN( pn ) ) { ! 587: if( pn->op == FILTER ) continue; ! 588: for( iop = 1; iop <= MAXOPS; iop++ ) { /* scan operands */ ! 589: if( ( q = pn->ops[iop] ) == NULL ) continue; ! 590: /* check for address arithmetic */ ! 591: if( ( ( pn->op == MOVAW ) || ( pn->op == PUSHAW ) ) && ! 592: ( iop == 1 ) ) continue; ! 593: /* find operands that use registers */ ! 594: for( p = q; *p != '%' && *p != '\0'; p++ ); ! 595: if( *p == '\0' ) continue; ! 596: p++; ! 597: switch( *p ) { ! 598: case 'r': /* %r0 through %r8 */ ! 599: /* change register, if appropriate */ ! 600: if( ( pa = map[*++p - '0'] ) != NULL ) { ! 601: if( *q == '%' ) ! 602: pn->ops[iop] = pa->asrname; ! 603: else { ! 604: for( q2=q; *q2!='\0'; q2++ ); ! 605: q2 = getspace( q2 - q + 1 ); ! 606: pn->ops[iop] = q2; ! 607: p = q2 + ( p - q ); ! 608: while((*q2++ = *q++) != '\0'); ! 609: *p = *(pa->asrname + 2); ! 610: } ! 611: } ! 612: break; ! 613: case 'f': /* auto */ ! 614: case 'a': /* parameter */ ! 615: /* convert to register, if apropriate */ ! 616: for( pa = pamin; pa <= pacut; pa++ ) { ! 617: if( ( *p=='f' && pa->asvscl!=AUTO ) || ! 618: (*p=='a'&&pa->asvscl!=PARAM )) ! 619: continue; /* for speed */ ! 620: if( !rausesoff( q, pa->asvname, ! 621: pa->asvlen ) ) continue; ! 622: if( *q == '*' ) ! 623: pn->ops[iop] = pa->asrind; ! 624: else pn->ops[iop] = pa->asrname; ! 625: break; ! 626: } ! 627: break; ! 628: } ! 629: } ! 630: ! 631: /* change number of registers saved and restored */ ! 632: if( pn->op==SAVE || pn->op==RET ) pn->op1 = numbers[newnreg]; ! 633: } ! 634: } ! 635: ! 636: /* uses offset addressed variable */ ! 637: int ! 638: rausesoff( oper, var, len ) ! 639: char* oper; /* pointer to operand */ ! 640: char* var; /* pointer to offset addressed variable */ ! 641: int len; /* length of the variable in bytes */ ! 642: { ! 643: register int io, iv; ! 644: ! 645: if( *oper == '*' ) oper++; ! 646: io = strtol( oper, &oper, 10 ); ! 647: iv = strtol( var, &var, 10 ); ! 648: if( *oper != '(' || *var != '(' || *(oper + 2) != *(var + 2) ) ! 649: return( 0 ); ! 650: if( io < iv || io > ( iv + len - 1 ) ) return( 0 ); ! 651: return( 1 ); ! 652: } ! 653: ! 654: /* insert moves for parameters */ ! 655: void ! 656: raparam( iascut ) ! 657: register int iascut; /* index for assignment cutoff */ ! 658: { ! 659: register NODE *pn; ! 660: register int ias; ! 661: register struct assign *pa; ! 662: ! 663: /* find save instruction */ ! 664: for( pn = n0.forw; pn != 0; pn = pn->forw ) { /* scan nodes */ ! 665: if( pn->op == SAVE ) { ! 666: ! 667: /* skip over stack pointer increment for locals */ ! 668: if( *( pn->forw->ops[1] + 2 ) == 'F' ) pn = pn->forw; ! 669: ! 670: /* insert move for each parameter assigned to reg */ ! 671: for( ias = 0; ias <= iascut; ias++ ) { ! 672: pa = &asreg[ias]; ! 673: if( pa->asvscl != PARAM ) continue; ! 674: switch( atoi( pa->asvname ) % 4 ) { ! 675: case 0: ! 676: addi( MOVW, "movw", pa->asvname, ! 677: pa->asrname ); ! 678: break; ! 679: case 1: ! 680: case 3: ! 681: addi( MOVB, "movb", pa->asvname, ! 682: pa->asrname ); ! 683: break; ! 684: case 2: ! 685: addi( MOVH, "movh", pa->asvname, ! 686: pa->asrname ); ! 687: break; ! 688: } ! 689: } ! 690: break; ! 691: } ! 692: } ! 693: } ! 694: ! 695: /* modify def statements */ ! 696: void ! 697: radef( iascut ) ! 698: int iascut; /* index for assignment cutoff */ ! 699: { ! 700: register NODE *pn; ! 701: int ias; ! 702: register struct assign *pa; ! 703: register int scl; ! 704: int val, vval, dscl; ! 705: register char *p, *q; ! 706: char *pv, *ps, *s; ! 707: ! 708: for( pn = n0.forw; pn != 0; pn = pn->forw ) { /* scan nodes */ ! 709: if( pn->op != FILTER ) continue; ! 710: p = pn->opcode; ! 711: if( ! ( p = strchr( p, '.' ) ) || *++p != 'd' ) continue; ! 712: if( ! ( p = strchr( p, '.' ) ) || *++p != 'v' ) continue; ! 713: val = atoi( pv = p += 3 ); ! 714: if( ! ( p = strchr( p, '.' ) ) || *++p != 's' ) continue; ! 715: scl = atoi( ps = p += 3 ); ! 716: switch( scl ) { ! 717: case C_AUTO: dscl = AUTO; break; ! 718: case C_ARG: dscl = PARAM; break; ! 719: case C_REG: ! 720: case C_REGPARM: dscl = REGISTER; break; ! 721: default: continue; ! 722: } ! 723: for( ias = 0; ias <= iascut; ias++ ) { ! 724: pa = &asreg[ias]; ! 725: if( dscl != pa->asvscl ) continue; ! 726: vval = ( scl == C_AUTO || scl == C_ARG ) ? ! 727: atoi( pa->asvname ) : ! 728: *( pa->asvname + 2 ) - '0' ; ! 729: if( val != vval ) continue; ! 730: q = s = getspace( length( p = pn->opcode ) + 5 ); ! 731: while( p != pv ) *q++ = *p++; /* thru .val */ ! 732: *q++ = *p++; /* tab */ ! 733: *q++ = *( pa->asrname + 2 ); /* reg no */ ! 734: while( *++p != ';' ); ! 735: while( p != ps ) *q++ = *p++; /* thru .scl */ ! 736: *q++ = *p++; /* tab */ ! 737: q += sprintf( q, "%d", /* scl value */ ! 738: ( scl == C_AUTO || scl == C_REG ) ? ! 739: C_REG : C_REGPARM ); ! 740: while( *++p != ';' ); ! 741: while( *q++ = *p++ ); /* the rest */ ! 742: pn->opcode = s; ! 743: } ! 744: } ! 745: } ! 746: ! 747: /* eliminate auto area if no more autos */ ! 748: int ! 749: raautos( numauto ) ! 750: int numauto; /* number of bytes of automatic variables */ ! 751: { ! 752: register NODE *pn, *qn; ! 753: register int iop; ! 754: register char *p; ! 755: ! 756: for( pn = n0.forw; pn != 0; pn = pn->forw ) { /* scan nodes */ ! 757: if( pn->op == FILTER ) continue; ! 758: if( pn->op == SAVE ) qn = pn->forw; ! 759: for( iop = 1; iop < MAXOPS + 1; iop++ ) { /* scan operands */ ! 760: p = pn->ops[iop]; ! 761: if( p == NULL ) continue; ! 762: /* look for uses of frame pointer */ ! 763: if( usesreg( p, "%fp" ) ) return( numauto ); ! 764: } ! 765: } ! 766: /* remove allocation of auto area */ ! 767: if( *( qn->op1 + 2 ) == 'F' ) { ! 768: DELNODE( qn ); ! 769: numauto = 0; ! 770: } ! 771: return( numauto ); ! 772: } ! 773: #endif /* IMPREGAL */ ! 774: ! 775: ! 776: #ifdef IMPIL ! 777: /* in-line substitution optimization ! 778: ** ! 779: ** F.B. Wolverton 8/12/83 ! 780: ** ! 781: */ ! 782: ! 783: #define MAXINSTR 22 /* = 20 * (cost/benefit) + 2 */ ! 784: ! 785: struct procnode { ! 786: struct procnode *pnforw; /* forward pointer for list of procs */ ! 787: struct procnode *pnback; /* backward pointer for list of procs */ ! 788: char *pnname; /* procedure name */ ! 789: int pncalls; /* num of times procedure is called */ ! 790: int pnni; /* num of instr in procedure */ ! 791: struct node *pnhead; /* proc head pointer */ ! 792: struct node *pntail; /* proc tail pointer */ ! 793: } prochead, proctail; ! 794: int proccnt; /* number of procs in table */ ! 795: int totalni = 0; /* total number of instructions in file */ ! 796: #define PNODE struct procnode ! 797: #define ALLPN( prn ) prn = prochead.pnforw; prn != &proctail; prn=prn->pnforw ! 798: #define ALLPNB( prn ) prn = proctail.pnback; prn != &prochead; prn=prn->pnback ! 799: #define PNALLN(prn,pn) pn = prn->pnhead->forw; pn != prn->pntail; pn=pn->forw ! 800: #define PNALLNB(prn,pn) pn = prn->pntail->back; pn != prn->pnhead; pn=pn->back ! 801: extern char *mktemp(); ! 802: char itmpname[50]; /* name of file for output before in-line subst */ ! 803: int outfd; /* descriptor for output file after in-line subst */ ! 804: FILE *outfp; /* pointer for output file after in-line subst */ ! 805: void iledit(), ilinsert(); ! 806: struct procnode *ilalloc(); ! 807: #define LINELEN 400 ! 808: char linebuf[LINELEN]; ! 809: int intpc = -3; /* persent limit on in-line expansion */ ! 810: char defltpc[] = MAXPC; ! 811: char *pcdecode(); ! 812: extern int zflag; /* debug flag for in-line expansion */ ! 813: extern boolean swflag; ! 814: ! 815: /* initialization for in-line substitution */ ! 816: void ! 817: ilinit() ! 818: { ! 819: /* initialize procedure list */ ! 820: prochead.pnforw = &proctail; ! 821: prochead.pnback = NULL; ! 822: proctail.pnforw = NULL; ! 823: proctail.pnback = &prochead; ! 824: proccnt = 0; ! 825: ! 826: /* default the in-line expansion limit if not set */ ! 827: if( intpc == -3 && *( pcdecode( defltpc )+1 ) != '\0' ) pcdecode( "" ); ! 828: ! 829: /* redirect stdout to tempfile to hold output before in-line subst */ ! 830: strcpy( itmpname, TMPDIR ); ! 831: strcat( itmpname, "/ccilXXXXXX" ); ! 832: mktemp( itmpname ); ! 833: if( ( outfd = dup( 1 ) ) == -1 ) ! 834: fatal( "can't get file descriptor\n", 0 ); ! 835: outfp = fdopen( outfd, "w" ); ! 836: if( freopen( itmpname, "w", stdout ) == NULL ) ! 837: fatal( "can't open file %s\n", itmpname ); ! 838: } ! 839: /* routine to decode the limit on percent in-line expansion */ ! 840: char * ! 841: pcdecode( flags ) ! 842: char *flags; /* pointer to first character of suboption for 'y' */ ! 843: { ! 844: char *p; ! 845: switch( *flags ) { ! 846: case 'u': intpc = -1; break; ! 847: case 's': intpc = -2; break; ! 848: case '\n': ! 849: case '\0': ! 850: fprintf( stderr, "Optimizer: in-line option missing, " ); ! 851: fprintf( stderr, "expansion suppressed\n"); ! 852: flags--; ! 853: intpc = -2; ! 854: break; ! 855: default: ! 856: intpc = ( int ) strtol( p = flags, &flags, 10 ); ! 857: flags--; ! 858: if( flags >= p ) break; /* break if found an integer */ ! 859: fprintf( stderr, "Optimizer: invalid in-line option " ); ! 860: fprintf( stderr, "starting with '%c', ", *p ); ! 861: fprintf( stderr, "expansion suppressed\n" ); ! 862: intpc = -2; ! 863: } ! 864: return( flags ); /* returns pointer to last character of suboption */ ! 865: } ! 866: /* routine to mark calls with bytes pushed on stack at time of call */ ! 867: ! 868: /* The purpose of this routine is to permit nested calls to be expanded ! 869: ** in-line. This routine routine does static analysis of the stack ! 870: ** size and should, therefore, precede the branch optimization. */ ! 871: ! 872: void ! 873: ilmark() ! 874: ! 875: { ! 876: register int npush = 0; /* number of bytes of ! 877: arguments pushed or moved onto the stack */ ! 878: register NODE *pn; /* pointer to instruction node being ! 879: processed */ ! 880: ! 881: /* check whether in-line expansion is being suppressed */ ! 882: if( intpc == -2 ) return; ! 883: ! 884: /* mark calls */ ! 885: for( ALLN( pn ) ) { ! 886: if( pn->op == FILTER ) continue; ! 887: switch(pn->op) { ! 888: case PUSHZB: ! 889: case PUSHZH: ! 890: case PUSHAW: ! 891: case PUSHBB: ! 892: case PUSHBH: ! 893: case PUSHW: ! 894: case PUSHD: ! 895: npush += 4; ! 896: break; ! 897: case ADDW2: ! 898: if( strncmp( pn->op2, "%sp", 3 ) != 0 ) break; ! 899: if( strncmp( pn->op1, "&.F", 3 ) == 0 ) break; ! 900: npush += atoi( pn->op1 + 1 ); ! 901: break; ! 902: case SUBW2: ! 903: if( strncmp( pn->op2, "%sp", 3 ) != 0 ) break; ! 904: npush -= atoi( pn->op1 + 1 ); ! 905: break; ! 906: case CALL: ! 907: npush -= 4 * atoi( pn->op1 + 1 ); ! 908: pn->opm = (char * ) npush; ! 909: break; ! 910: } ! 911: } ! 912: } ! 913: ! 914: /* gather statistics for in-line substitution */ ! 915: void ! 916: ilstat( numnreg, numauto ) ! 917: int numnreg; /* number of registers to save and restore */ ! 918: int numauto; /* number of words of autos */ ! 919: { ! 920: register NODE *pn, *p; ! 921: PNODE *prn, *pp; ! 922: int nn, ni, iop, nc, lastop; ! 923: char *ncp; ! 924: ! 925: /* check whether in-line expansion is being suppressed */ ! 926: if( intpc == -2 ) return; ! 927: ! 928: /* count CALL's and total number of instructions */ ! 929: lastop = 0; ! 930: for( ALLN( pn ) ) { ! 931: if( pn->op == CALL ) { ! 932: if( ( prn = ilalloc( pn->op2 ) ) == NULL ) return; ! 933: prn->pncalls++; ! 934: } ! 935: if( !islabel( pn ) && pn->op != MISC && ! 936: ( pn->op != RET || ! 937: ( lastop != RET && lastop != JMP ) ) ) { ! 938: totalni++; ! 939: lastop = pn->op; ! 940: /* ! 941: printf( "%d %s\n", totalni, pn->ops[0] ); ! 942: */ ! 943: } ! 944: } ! 945: ! 946: /* allocate a node for this proc if one does not exist */ ! 947: for( ALLN( pn ) ) { ! 948: if( islabel( pn ) ) { ! 949: if( ( prn = ilalloc( pn->opcode ) ) == NULL ) return; ! 950: break; ! 951: } ! 952: } ! 953: if( pn == 0 ) return; ! 954: ! 955: /* check conditions for being substituted in line */ ! 956: /* check for locals or saved registers */ ! 957: if( numnreg != 0 || numauto != 0 ) return; ! 958: /* check procedure size and compute total length of strings */ ! 959: nn = ni = nc = lastop = 0; ! 960: for( ALLN( pn ) ) { ! 961: register char *cp; ! 962: nn++; ! 963: for( iop = 0; iop <= MAXOPS; iop++ ) { ! 964: if( (cp = pn->ops[iop] ) != NULL ) nc += length( cp ); ! 965: } ! 966: if( !islabel( pn ) && pn->op != MISC && ! 967: ( pn->op != RET || ! 968: ( lastop != RET && lastop != JMP ) ) ) { ! 969: if( ++ni > MAXINSTR ) return; ! 970: lastop = pn->op; ! 971: /* ! 972: printf( "%d %s\n", ni, pn->ops[0] ); ! 973: */ ! 974: } ! 975: } ! 976: /* check for label expressions */ ! 977: for( ALLN( pn ) ) { ! 978: if( !islabel( pn ) ) continue; ! 979: for( ALLN( p ) ) { ! 980: register int i; ! 981: for( i = 0; i <= MAXOPS; i++ ) { ! 982: register char *cp; ! 983: cp = p->ops[i]; ! 984: if( cp == NULL ) continue; ! 985: if( *cp == *( pn->opcode ) &&/*speed*/ ! 986: strcmp(cp, pn->opcode ) == 0) continue; ! 987: while( *cp != '\0' ) { ! 988: cp++; ! 989: if( *cp == *( pn->opcode )&&/* speed */ ! 990: strcmp( cp, pn->opcode ) == 0 ) ! 991: return; ! 992: } ! 993: } ! 994: } ! 995: } ! 996: ! 997: /* check for switch tables */ ! 998: if( swflag ) { swflag = false; return; } ! 999: ! 1000: /* save the code */ ! 1001: prn->pnni = ni; ! 1002: if( ( p = (NODE *)malloc( ( nn + 2 ) * sizeof( NODE ) + nc ) ) == NULL ) ! 1003: return; ! 1004: ncp = (char *) p + ( nn + 2 ) * sizeof( NODE ); ! 1005: prn->pnhead = p; ! 1006: p->forw = p + 1; ! 1007: p->back = NULL; ! 1008: for( ALLN( pn ) ) { ! 1009: register int i; ! 1010: p++; ! 1011: p->forw = p + 1; ! 1012: p->back = p - 1; ! 1013: for( i = 0; i <= MAXOPS; i++ ) { ! 1014: if( ( p->ops[i] = pn->ops[i] ) == NULL ) continue; ! 1015: strcpy( ncp, pn->ops[i] ); ! 1016: p->ops[i] = ncp; ! 1017: ncp += length( ncp ); ! 1018: } ! 1019: p->op = pn->op; ! 1020: } ! 1021: p++; ! 1022: p->forw = NULL; ! 1023: p->back = p - 1; ! 1024: prn->pntail = p; ! 1025: ! 1026: /* reposition in list by increasing size */ ! 1027: /* remove from list */ ! 1028: prn->pnforw->pnback = prn->pnback; ! 1029: prn->pnback->pnforw = prn->pnforw; ! 1030: /* locate proper position */ ! 1031: for( ALLPNB( pp ) ) { ! 1032: if( prn->pnni >= pp->pnni ) break; ! 1033: } ! 1034: /* reinsert it */ ! 1035: prn->pnforw = pp->pnforw; ! 1036: prn->pnback = pp; ! 1037: prn->pnforw->pnback = prn; ! 1038: prn->pnback->pnforw = prn; ! 1039: } ! 1040: ! 1041: /* perform the in-line substitution for whole file */ ! 1042: void ! 1043: ilfile() ! 1044: { ! 1045: register struct procnode *prn; ! 1046: int fpc, delta; ! 1047: register char *linptr; ! 1048: ! 1049: /* eliminate nodes for progs not in the file or not called */ ! 1050: for( ALLPN( prn ) ) { ! 1051: if( prn->pnni == 0 || prn->pncalls ==0 ) { ! 1052: prn->pnforw->pnback = prn->pnback; ! 1053: prn->pnback->pnforw = prn->pnforw; ! 1054: } ! 1055: } ! 1056: ! 1057: /* apply percent limit unless no limit */ ! 1058: if( intpc != -1 ) { ! 1059: /* apply percent text increase constraint */ ! 1060: fpc = 100 * intpc; ! 1061: for( ALLPN( prn ) ) { ! 1062: delta = 100 * ( prn->pnni - 2 ) * 100 / totalni; ! 1063: fpc -= prn->pncalls * delta; ! 1064: if( fpc < 0 ) { ! 1065: while( fpc < 0 && prn->pncalls > 0 ) { ! 1066: fpc += delta; ! 1067: prn->pncalls--; ! 1068: } ! 1069: break; ! 1070: } ! 1071: } ! 1072: if( prn != &proctail ) { ! 1073: if( ( prn->pncalls ) == 0 ) prn = prn -> pnback; ! 1074: prn->pnforw = &proctail; ! 1075: prn->pnforw->pnback = prn; ! 1076: } ! 1077: } ! 1078: ! 1079: /* analytic printout */ ! 1080: if( zflag ) { ! 1081: int size, sumsize; ! 1082: sumsize = 0; ! 1083: if( zflag ) fprintf(stderr, "in-line expansion limit = %d\n", ! 1084: intpc ); ! 1085: for( ALLPN( prn ) ) { ! 1086: size = prn->pncalls * ! 1087: ( prn->pnni -2 ) * 100 / totalni; ! 1088: sumsize += size; ! 1089: fprintf( stderr, ! 1090: "%s calls=%d inst=%d sz=%d%% t_sz=%d%% \n", ! 1091: prn->pnname,prn->pncalls,prn->pnni,size, ! 1092: sumsize ); ! 1093: } ! 1094: } ! 1095: ! 1096: /* edit routines before inserting */ ! 1097: iledit(); ! 1098: ! 1099: /* read temp file and write output with inserted procedures */ ! 1100: fclose( stdout ); ! 1101: if( freopen( itmpname, "r", stdin ) == NULL ) ! 1102: fatal( "can't open file %s\n", itmpname ); ! 1103: while( ( linptr = fgets( linebuf, LINELEN, stdin ) ) != NULL ){ ! 1104: register int numauto, nargs; ! 1105: register char *cp; ! 1106: char *linp; ! 1107: ! 1108: if( *linptr == '!' ) continue; ! 1109: if( *linptr == '*' ) { ! 1110: /* insert .il flag to indicate in-line expansion */ ! 1111: if( ( linptr = fgets( linebuf, LINELEN, stdin ) ) ! 1112: == NULL ) break; ! 1113: for( cp = linebuf; *cp != '\n'; cp++ ); ! 1114: *cp = '\0'; ! 1115: for( ALLPN( prn ) ) { ! 1116: if( strcmp( linebuf, prn->pnname ) == 0 ) { ! 1117: linptr = fgets( linebuf, LINELEN, ! 1118: stdin ); ! 1119: for(cp=linebuf; *cp != '\n'; cp++) ! 1120: if(*cp == ';') linptr = cp; ! 1121: *linptr = '\0'; ! 1122: fprintf( outfp, "%s;\t.il;\t.endef\n", ! 1123: linebuf ); ! 1124: break; ! 1125: } ! 1126: } ! 1127: continue; ! 1128: } ! 1129: /* default */ ! 1130: if( *linptr != '@' ) { ! 1131: fprintf( outfp, "%s", linptr ); ! 1132: continue; ! 1133: } ! 1134: /* expand the call */ ! 1135: linp = linptr; ! 1136: numauto = (int) strtol( ++linp, &linp, 10 ); ! 1137: nargs = (int) strtol( ++linp, &linp, 10 ); ! 1138: linptr = linp; ! 1139: cp = ++linptr; ! 1140: while( *cp != '\n' ) cp++; ! 1141: *cp = '\0'; ! 1142: for( ALLPNB( prn ) ) { ! 1143: if( strcmp( linptr, prn->pnname ) == 0 ) { ! 1144: if( prn->pncalls <= 0 ) break; ! 1145: ilinsert( numauto, nargs, prn ); ! 1146: prn->pncalls--; ! 1147: fgets( linebuf, LINELEN, stdin ); ! 1148: break; ! 1149: } ! 1150: } ! 1151: } ! 1152: (void) fclose( stdin ); ! 1153: unlink( itmpname ); ! 1154: } ! 1155: ! 1156: ! 1157: /* edit routines before substitution */ ! 1158: void ! 1159: iledit() ! 1160: { ! 1161: register NODE *pn; ! 1162: register PNODE *prn; ! 1163: ! 1164: for( ALLPN( prn ) ) { ! 1165: /* replace entry label with new label */ ! 1166: for( PNALLN( prn, pn ) ) { ! 1167: if( islabel( pn ) ) { ! 1168: prn->pnhead->forw = pn; ! 1169: pn->back = prn->pnhead; ! 1170: pn->opcode = "EL"; ! 1171: break; ! 1172: } ! 1173: } ! 1174: /* replace last return with lab or follow last jump with lab */ ! 1175: for( PNALLNB( prn, pn ) ) { ! 1176: if( pn->op == RET ) { ! 1177: pn->op = LABEL; ! 1178: pn->opcode = "RL"; ! 1179: prn->pntail->back = pn; ! 1180: pn->forw = prn->pntail; ! 1181: /* remove duplicate return, if any */ ! 1182: while( islabel( pn ) ) pn = pn ->back; ! 1183: if( pn->op == RET ) DELNODE( pn ); ! 1184: break; ! 1185: } ! 1186: if( pn->op == JMP ) { ! 1187: addi( LABEL, "RL", 0, 0 ); ! 1188: prn->pntail->back = pn; ! 1189: pn->forw = prn->pntail; ! 1190: break; ! 1191: } ! 1192: } ! 1193: /* replace other returns with jump to new label */ ! 1194: for( PNALLN( prn, pn ) ) { ! 1195: if( pn->op == RET ) { ! 1196: pn->op = JMP; ! 1197: pn->opcode = "jmp"; ! 1198: pn->op1 = "RL"; ! 1199: } ! 1200: } ! 1201: } ! 1202: } ! 1203: ! 1204: ! 1205: /* insert a procedure */ ! 1206: void ! 1207: ilinsert( numauto, nargs, prn ) ! 1208: int numauto; /* numbers of words of autos in calling procedure */ ! 1209: int nargs; /* number of arguments procedure is called with */ ! 1210: PNODE *prn; /* procedure to be inserted */ ! 1211: { ! 1212: register NODE *pn, *p; ! 1213: static int ilabel = 0; ! 1214: register int i; ! 1215: register char *cp, *cpn; ! 1216: char *lab; ! 1217: ! 1218: /* rewrite labels */ ! 1219: for( PNALLN( prn, pn ) ) { ! 1220: if( !islabel( pn ) ) continue; ! 1221: cpn = pn->opcode; ! 1222: ilabel++; ! 1223: lab = getspace( 9 ); ! 1224: sprintf( lab, ".I%d\0", ilabel ); ! 1225: for( PNALLN( prn, p ) ) { ! 1226: for( i = 0; i <= MAXOPS; i++ ) { ! 1227: cp = p->ops[i]; ! 1228: if( cp == NULL ) continue; ! 1229: if( *cp == *cpn && ! 1230: strcmp( cp, cpn ) == 0 ) ! 1231: p->ops[i] = lab; ! 1232: } ! 1233: } ! 1234: } ! 1235: ! 1236: /* write out instructions, rewriting args and omitting save */ ! 1237: for( PNALLN( prn, pn ) ) { ! 1238: switch( pn->op ) { ! 1239: case SAVE: continue; ! 1240: case LABEL: ! 1241: fprintf( outfp, "%s:\n", pn->opcode ); ! 1242: break; ! 1243: case HLABEL: ! 1244: fprintf( outfp, "%s:\n", pn->opcode ); ! 1245: break; ! 1246: case MISC: ! 1247: fprintf( outfp, " %s\n", pn->opcode ); ! 1248: break; ! 1249: case CALL: ! 1250: pn->opm = NULL; ! 1251: /* fall through */ ! 1252: default: ! 1253: fprintf( outfp, " %s ", pn->opcode ); ! 1254: for( i = 1; i < MAXOPS + 1; i++ ) { ! 1255: if( (cp=pn->ops[i]) == NULL ) continue; ! 1256: if( i > 1 ) fprintf( outfp, "," ); ! 1257: if( usesreg( cp, "%ap" ) ) { ! 1258: if( *cp == '*') { ! 1259: fprintf( outfp, "*" ); ! 1260: cp++; ! 1261: } ! 1262: fprintf( outfp, "%d(%%fp)", ! 1263: atoi( cp ) + numauto ); ! 1264: } ! 1265: else fprintf( outfp, "%s", cp ); ! 1266: } ! 1267: fprintf( outfp, "\n" ); ! 1268: break; ! 1269: } ! 1270: } ! 1271: ! 1272: /* reset stack pointer if necessary */ ! 1273: if( nargs != 0 ) ! 1274: fprintf( outfp, " subw2 &%d,%%sp\n", 4 * nargs ); ! 1275: } ! 1276: ! 1277: /* allocate procedure nodes */ ! 1278: struct procnode * ! 1279: ilalloc( name ) ! 1280: char *name; /* procedure name */ ! 1281: { ! 1282: register PNODE *prn; ! 1283: ! 1284: /* check whether node already exists */ ! 1285: for( ALLPN( prn ) ) { ! 1286: if( strcmp( name, prn->pnname ) == 0 ) ! 1287: return( prn ); ! 1288: } ! 1289: ! 1290: /* allocate node */ ! 1291: if( ( prn = ( PNODE * ) ! 1292: malloc( sizeof( PNODE ) + length( name ) ) ) == NULL ) ! 1293: return( prn ); ! 1294: prn->pnforw = prochead.pnforw; ! 1295: prn->pnback = &prochead; ! 1296: prn->pnforw->pnback = prn; ! 1297: prn->pnback->pnforw = prn; ! 1298: prn->pnname = (char *) prn + sizeof( PNODE ); ! 1299: strcpy( prn->pnname, name ); ! 1300: prn->pncalls = 0; ! 1301: prn->pnni = 0; ! 1302: prn->pnhead = NULL; ! 1303: return( prn ); ! 1304: } ! 1305: #endif /* IMPIL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.