#ifndef lint static char sccsid[] = "@(#)c22.c 1.9 (Berkeley/CCI) 05/12/88"; #endif /* * C object code improver-- third part */ #include "c2.h" #include #include rmove() { register struct node *p; register int r, r1; clearreg(); for (p=first.forw; p!=0; p = p->forw) { if (debug) { printf("Regs: "); for (r=0; r<=NREG; r++) if (regs[r][0]) { r1=regs[r][0]; printf("%d: %d%d %s\n", r, r1&0xF, r1>>4, regs[r]+1); } printf("-\n"); } switch (p->op) { case CVT: case MOVZ: splitrand(p); repladdr(p); r = isreg(regs[RT1]); r1 = isreg(regs[RT2]); dest(regs[RT2],p->subop, p->op!=CVT || r<0); if (r>=0 && r1>=0) { p->op = MOV; p->subop = LONG; p->pop = 0; nchange++; goto case_mov; } if(p->op == CVT) { if (r1>=0) savereg(r1, regs[RT1], p->subop); } else ccloc[0] = 0; break; case MOV: case_mov: splitrand(p); if ((r = findrand(regs[RT1],p->subop)) >= 0) { if (r == isreg(regs[RT2])) if(p->forw->op!=CBR) { delnode(p); redunm++; nchange++; break; } else { p->op=TST; p->pop=0; while(*p->code++ != ','); redunm++; nchange++; goto case_tst; } } repladdr(p); r = isreg(regs[RT1]); r1 = isreg(regs[RT2]); dest(regs[RT2],p->subop, 1); if ((regs[ACC][0]) && equstr(regs[RT2],regs[ACC]+1)) *(short *)(regs[ACC]) = 0; if (r>=0) { if (r1>=0) { if (r == r1 && p->forw->op!=CBR) { delnode(p); redunm++; nchange++; break; } if(regs[r][0]) savereg(r1, regs[r]+1, p->subop); } else savereg(r, regs[RT2], p->subop); } else if (r1>=0) savereg(r1, regs[RT1], p->subop); else setcon(regs[RT1], regs[RT2], p->subop); break; /* .rx,.wx or .rx,.rx,.wx */ case ADD: case SUB: case AND: case OR: case XOR: case MUL: case DIV: #ifdef EMOD case EDIV: case EMOD: #endif EMOD case SHAL: case SHAR: case SHL: case SHR: case ADDA: case SUBA: /* .rx,.wx */ case MFPR: case COM: case NEG: splitrand(p); repladdr(p); dest(lastrand,p->subop, p->op!=ADDA && p->op!=SUBA); break; /* .mx or .wx */ case STF: if(equstr(p->code, regs[ACC]+1) && p->subop==regs[ACC][0]) { delnode(p); nst++; nchange++; break; } savereg(ACC, p->code, p->subop); case INC: case DEC: case CVFL: dest(p->code,p->subop, 1); break; case CLR: dest(p->code,p->subop, 1); if ((regs[ACC][0]) && equstr(p->code,regs[ACC]+1)) *(short *)(regs[ACC]) = 0; if ((r = isreg(p->code)) < 0) setcon("$0", p->code, p->subop); else savereg(r, "$0", p->subop); break; /* .rx */ case LDF: if(equstr(p->code, regs[ACC]+1) && p->subop==regs[ACC][0]) { delnode(p); nld++; nchange++; break; } savereg(ACC, p->code, p->subop); goto case_tst; case LNF: if(equstr(p->code, regs[ACC]+1) && p->subop==regs[ACC][0]) { p->op = NEGF; p->pop = 0; p->code = 0; regs[ACC][0] = 0; break; } case CVLF: case LDFD: case ADDF: case SUBF: case MULF: case DIVF: regs[ACC][0] = 0; case TST: case_tst: case PUSH: splitrand(p); lastrand=regs[RT1+1]; /* fool repladdr into doing 1 operand */ repladdr(p); lastrand=regs[RT1]; if (p->op==TST && equstr(lastrand, ccloc+1) && ((0xf&(ccloc[0]>>4))==p->subop || equtype(ccloc[0],p->subop))) { delnode(p); nrtst++; nchange++; break; } if (p->op==PUSH && p->subop!=LONG && (isreg(lastrand)>=0 || *lastrand=='$')) { p->subop = LONG; p->pop = 0; nchange++; } if (p->op==TST || p->op==PUSH) setcc(lastrand,p->subop); break; /* .rx,.rx,.rx */ case PROBE: case CASE: /* .rx,.rx */ case MTPR: case CALLS: case CALLF: case CMP: case BIT: case CMPF: case CMPF2: splitrand(p); /* fool repladdr into doing right number of operands */ lastrand=byondrd(p); if (p->op==CALLF || p->op==CALLS) clearreg(); else repladdr(p); case TSTF: ccloc[0]=0; case PUSHD: break; /* acc only */ case CVDF: case NEGF: case SINF: case COSF: case ATANF: case LOGF: case SQRTF: case EXPF: regs[ACC][0] = 0; break; #ifndef EMOD /* .rx,.rx,.wx,.wx */ case EDIV: splitrand(p); lastrand = regs[RT3]; repladdr(p); dest(regs[RT3], p->subop, 1); dest(regs[RT4], p->subop, 0); break; #endif EMOD /* .rx,.rx,.rx,wx */ case EMUL: splitrand(p); lastrand = regs[RT4]; repladdr(p); dest(regs[RT4],QUAD, 1); /* fourth operand is a quad */ break; case CBR: if (p->subop>=JBC) { splitrand(p); lastrand=regs[RT3]; /* 2 operands can be optimized */ repladdr(p); ccloc[0] = 0; } else reduncbr(p); break; case JBR: redunbr(p); default: clearreg(); } } } jumpsw() { register struct node *p, *p1, *pt; register int t, nj; t = 0; nj = 0; for (p=first.forw; p!=0; p = p->forw) p->seq = ++t; for (p=first.forw; p!=0; p = p1) { p1 = p->forw; if (p->op == CBR && p1->op==JBR && p->ref && p1->ref && abs(p->seq - p->ref->seq) > abs(p1->seq - p1->ref->seq)) { if (p->ref==p1->ref) continue; p->subop = revbr[p->subop]; p->pop=0; pt = p1->ref; p1->ref = p->ref; p->ref = pt; t = p1->labno; p1->labno = p->labno; p->labno = t; #ifdef COPYCODE if (p->labno == 0) { pt = (struct node *)p1->code; p1->code = p->code; p->code = (char *)pt; } #endif nrevbr++; nj++; } } return(nj); } addaob() { register struct node *p, *p1, *p2, *p3; for (p = &first; (p1 = p->forw)!=0; p = p1) { if (p->op==INC && p->subop==LONG) { if (p1->op==LABEL && p1->refc==1 && p1->forw->op==CMP && p1->forw->subop==LONG && (p2=p1->forw->forw)->op==CBR && p2->subop==JLE && (p3=p2->ref->back)->op==JBR && p3->subop==0 && p3->ref==p1 && p3->forw->op==LABEL && p3->forw==p2->ref) { /* change INC LAB: CMP to LAB: INC CMP */ p->back->forw=p1; p1->back=p->back; p->forw=p1->forw; p1->forw->back=p; p->back=p1; p1->forw=p; p1=p->forw; /* adjust beginning value by 1 */ p2=alloc(sizeof first); p2->op = DEC; p2->subop = LONG; p2->pop=0; p2->forw=p3; p2->back=p3->back; p3->back->forw=p2; p3->back=p2; p2->code=p->code; p2->labno=0; } if (p1->op==CMP && p1->subop==LONG && (p2=p1->forw)->op==CBR && p2->forw->op!=CBR) { register char *cp1,*cp2; splitrand(p1); if (!equstr(p->code,regs[RT1])) continue; if ((p2->subop==JLE || p2->subop==JLT) && checkaobdisp(p2)){ if (p2->subop==JLE) p->op = AOBLEQ; else p->op = AOBLSS; p->subop = 0; cp2=regs[RT1]; cp1=regs[RT2]; while (*cp2++= *cp1++); /* limit */ cp2=regs[RT2]; cp1=p->code; while (*cp2++= *cp1++); /* index */ p->pop=0; newcode(p); p->labno = p2->labno; delnode(p2); delnode(p1); naob++; } } } } } ispow2(n) register long n; {/* -1 -> no; else -> log to base 2 */ register int log; if (n==0 || n&(n-1)) return(-1); log=0; for (;;) {n >>= 1; if (n==0) return(log); ++log; if (n== -1) return(log);} } equop(p1, p2) register struct node *p1, *p2; { register char *cp1, *cp2; if (p1->op != p2->op || p1->subop != p2->subop) return(0); if (p1->op == NIL && p1->subop == 0 && p1->pop != p2->pop) return(0); if (p1->op != NIL && ord(p1->op) < ord(MOV)) return(0); switch (p1->op) { case EROU: case JSW: case TEXT: case DATA: case BSS: case ALIGN: case WGEN: case END: /* sufficient? */ return(0); } if (p1->op==MOVA && p1->labno!=p2->labno) return(0); cp1 = p1->code; cp2 = p2->code; if (cp1==0 && cp2==0) return(1); if (cp1==0 || cp2==0) return(0); while (*cp1 == *cp2++) if (*cp1++ == 0) return(1); return(0); } delnode(p) register struct node *p; { p->back->forw = p->forw; p->forw->back = p->back; } decref(p) register struct node *p; { if (p && --p->refc <= 0) { nrlab++; nchange++; delnode(p); } } struct node * nonlab(ap) struct node *ap; { register struct node *p; p = ap; while (p && p->op==LABEL) p = p->forw; return(p); } clearuse() { register struct node **i; for (i=uses+NREG; i>uses;) *--i=0; useacc = 0; } clearreg() { register char **i; for (i=regs+NREG+1; i>regs;){ **--i=0; **i=0; } conloc[0] = 0; ccloc[0] = 0; } savereg(ai, s, type) register char *s; { register char *p, *sp; sp = p = regs[ai]; /* if any indexing, must be parameter or local */ /* indirection (as in "*-4(fp)") is ok, however */ *p++ = type; if (*s=='*' || *s=='$') *p++ = *s++; if (natural(s)) strcpy(p, s); else {*sp = 0; return;} } dest(s,type, ccflg) register char *s; { register int i; if ((i = isreg(s)) >= 0) { *(short *)(regs[i]) = 0; /* if register destination, that reg is a goner */ if (DOUBLE==(type&0xF) || DOUBLE==((type>>4)&0xF) || type==QUAD) *(short *)(regs[i+1]) = 0; } for (i=NREG; --i>=0;) if (regs[i][1]=='*' && equstr(s, regs[i]+2)) *(short *)(regs[i]) = 0; /* previous indirection through destination is invalid */ while ((i = findrand(s,0)) >= 0) /* previous values of destination are invalid */ *(short *)(regs[i]) = 0; if (!natural(s)) {/* wild store, everything except constants vanishes */ for (i=NREG; --i>=0;) if (regs[i][1] != '$') *(short *)(regs[i]) = 0; conloc[0] = 0; ccloc[0] = 0; } else { if(ccflg)setcc(s,type); /* natural destinations set condition codes */ if (equstr(s, conloc)) conloc[0] = 0; } } splitrand(p) struct node *p; { /* separate operands at commas, set up 'regs' and 'lastrand' */ register char *p1, *p2; register char **preg; preg=regs+RT1; if (p1=p->code) while (*p1) { lastrand=p2= *preg++; while (*p1) if (','==(*p2++= *p1++)) {--p2; break;} *p2=0; } while (preg<(regs+RT1+5)) *(*preg++)=0; } compat(have, want) register int have, want; { register int hsrc, hdst; extern int bitsize[]; if (0==(want &= 0xF)) return(1); /* anything satisfies a wildcard want */ hsrc=have&0xF; if (0==(hdst=((have>>4)&0xF)) || hdst>=OP2) hdst=hsrc; if (want>=QUAD) return(bitsize[hdst]==bitsize[want] && bitsize[hsrc]==bitsize[want]); return(hsrc==want && hdst>=want && hdst=regs;) { if (**i && equstr(*i+1, as) && compat(**i,type)) return(i-regs); } return(-1); } isreg(s) register char *s; { if (*s++!='r' || !isdigit(*s++)) return(-1); if (*s==0) return(*--s-'0'); if (*(s-1)=='1' && isdigit(*s++) && *s==0) return(10+*--s-'0'); return(-1); } /* check() { register struct node *p, *lp; lp = &first; for (p=first.forw; p!=0; p = p->forw) { if (p->back != lp) abort(-1); lp = p; } } */ newcode(p) struct node *p; { register char *p1,*p2,**preg; preg=regs+RT1; p2=line; while (*(p1= *preg++)) {while (*p2++= *p1++); *(p2-1)=',';} *--p2=0; p->code=copy(line); } repladdr(p) struct node *p; { register int r; register char *p1; register char **preg; register int nrepl; preg=regs+RT1; nrepl=0; while (lastrand!=(p1= *preg++)) if (0<=(r=findrand(p1,p->subop))) { *p1++='r'; if (r>9) {*p1++='1'; r -= 10;} *p1++=r+'0'; *p1=0; nchange++; nrepl++; nsaddr++; } if (nrepl) newcode(p); } /* conditional branches which are never/always taken */ reduncbr(p) register struct node *p; { register struct node *p1; register char *ap1, *ap2; p1 = p->back; if (p1->op==CMP) { splitrand(p1); ap1 = findcon(regs[RT1], p1->subop); ap2 = findcon(regs[RT2], p1->subop); } else { if(!ccloc[0]) return; ap1 = findcon(ccloc+1, ccloc[0]); ap2 = "$0"; } switch (compare(p->subop, ap1, ap2)) { case 0: /* branch never taken */ delnode(p); nredunj++; nchange++; decref(p->ref); if(p->forw->op!=CBR && (p1->op==TST || p1->op==CMP)) { delnode(p1); nrtst++; } break; case 1: /* branch always taken */ p->op = JBR; p->subop = 0; p->pop = 0; nchange++; if(nonlab(p->ref)->op!=CBR && (p1->op==TST || p1->op==CMP)) { delnode(p1); nrtst++; } } } /* a jump to a redundant compare (start of a 'for') */ redunbr(p) register struct node *p; { register struct node *p1; register char *ap1, *ap2; if ((p1 = p->ref) == 0) return; p1 = nonlab(p1); if (p1->op==TST || p1->op==CMP) splitrand(p1); else return; if (p1->forw->op==CBR) { ap1 = findcon(regs[RT1], p1->subop); if (p1->op==TST) ap2 = "$0"; else ap2 = findcon(regs[RT2], p1->subop); p1 = p1->forw; if (compare(p1->subop, ap1, ap2) > 0) { nredunj++; nchange++; decref(p->ref); p->ref = p1->ref; p->labno = p1->labno; #ifdef COPYCODE if (p->labno == 0) p->code = p1->code; if (p->ref) #endif p->ref->refc++; } } else if (p1->op==TST && equstr(regs[RT1],ccloc+1) && equtype(ccloc[0],p1->subop)) { p1=insertl(p1->forw); decref(p->ref); p->ref=p1; p->labno=p1->labno; nrtst++; nchange++; } } char * findcon(p, type) register char *p; { register int r; if (*p=='$') return(p); if ((r = isreg(p)) >= 0 && compat(regs[r][0],type)) return(regs[r]+1); if (equstr(p, conloc) && equtype(conloc[0], type)) return(conval+1); return(p); } /* compare constants: 0 - branch taken; 1 - not taken; -1 - don't know */ compare(op, acp1, acp2) char *acp1, *acp2; { register char *cp1, *cp2; register int n1, n2, sign; cp1 = acp1; cp2 = acp2; if (*cp1++ != '$' || *cp2++ != '$') return(-1); n1 = 0; sign=1; if (*cp1=='-') {++cp1; sign= -1;} while (isdigit(*cp1)) {n1 *= 10; n1 += *cp1++ - '0';} n1 *= sign; n2 = 0; sign=1; if (*cp2=='-') {++cp2; sign= -1;} while (isdigit(*cp2)) {n2 *= 10; n2 += *cp2++ - '0';} n2 *= sign; if (*cp1=='+') cp1++; if (*cp2=='+') cp2++; do { if (*cp1++ != *cp2) return(-1); } while (*cp2++); switch(op) { case JEQ: return(n1 == n2); case JNE: return(n1 != n2); case JLE: return(n1 <= n2); case JGE: return(n1 >= n2); case JLT: return(n1 < n2); case JGT: return(n1 > n2); case JLO: return((unsigned)n1 < (unsigned)n2); case JHI: return((unsigned)n1 > (unsigned)n2); case JLOS: return((unsigned)n1 <= (unsigned)n2); case JHIS: return((unsigned)n1 >= (unsigned)n2); } return(-1); } setcon(cv, cl, type) register char *cv, *cl; { register char *p; if (*cv != '$') return; if (!natural(cl)) return; p = conloc; while (*p++ = *cl++); p = conval; *p++ = type; while (*p++ = *cv++); } setcc(ap,type) char *ap; { register char *p, *p1; p = ap; if (!natural(p)) { ccloc[0] = 0; return; } p1 = ccloc; *p1++ = type; while (*p1++ = *p++); } indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */ while (*p) if (*p++=='[') return(1); return(0); } natural(p) register char *p; {/* 1->simple local, parameter, global, or register; 0->otherwise */ if (*p=='*' || *p=='(' || *p=='$') return(0); while (*p++); p--; if (*--p==']' || *p==')' && !(*(p-2)=='f' || fortflg && (*--p=='1' || *p=='2') && *--p=='1')) return(0); return(1); } /* ** Tell if an argument is most likely static. */ isstatic(cp) register char *cp; { if (*cp == '_' || *cp == 'L') return (1); return (0); } checkaobdisp(p) register struct node *p; { register struct node *q; register int i; if (!aobflag) return(1); /* backward search */ i = 0; q = p; while (i++ < MAXAOBDISP && ((q= q->back) !=&first)) { if (p->ref == q) return(1); } /* forward search */ i = 0; q = p; while (i++ < MAXAOBDISP && ((q= q->forw) !=0)) { if (p->ref == q) return(1); } return(0); } struct intleavetab intltab[] = { ADDF, FLOAT, 1, ADDF, DOUBLE, 1, SUBF, FLOAT, 1, SUBF, DOUBLE, 1, MULF, FLOAT, 1, MULF, DOUBLE, 1, DIVF, FLOAT, 1, DIVF, DOUBLE, 1, SINF, FLOAT, 1, COSF, FLOAT, 1, ATANF, FLOAT, 1, LOGF, FLOAT, 1, SQRTF, FLOAT, 1, EXPF, FLOAT, 1, LDF, FLOAT, 0, LDF, DOUBLE, 0, LNF, FLOAT, 0, LNF, DOUBLE, 0, STF, FLOAT, 0, CMPF, FLOAT, 0, CMPF, DOUBLE, 0, CMPF2, FLOAT, 0, TSTF, FLOAT, 0, TSTF, DOUBLE, 0, PUSHD, DOUBLE, 0, CVLF, U(LONG,FLOAT), 0, CVFL, U(FLOAT,LONG), 0, LDFD, U(FLOAT,DOUBLE),0, CVDF, U(DOUBLE,FLOAT),0, NEGF, FLOAT, 0, NIL, 0, 0}; interleave() { register struct node *p, *p1; register struct intleavetab *t; register int r; int count; for (p= first.forw; p!=0; p = p->forw){ count = 0; for (t =intltab; t->op != NIL; t++){ if (t->op == p->op && t->subop == p->subop){ count = t->intleavect; break; } } if (count < 1) continue; p1 = p->forw; clearuse(); clearreg(); while ((p1 != 0) && (p1->op != CBR) && (p1->subop == FLOAT || p1->subop == DOUBLE || ((p1->subop&0xF0)==DOUBLE<<4) || ((p1->subop&0xF)==DOUBLE )|| ((p1->subop&0xF0)==FLOAT<<4) || (p1->subop&0xF)==FLOAT)) { if (((r = isreg(p1->code)) >= 0)){ uses[r] = p1; if ((p1->subop == DOUBLE) || ((p->subop&0xF0)==DOUBLE<<4) || ((p->subop&0xF)==DOUBLE)) uses[r+1] = p1; } else checkreg(p1,p1->code); p1 = p1->forw; } if (p1 == 0) return; if (!(sideeffect(p, p1))) insertblk(p,p1); } } insertblk(p, p1) struct node *p, *p1; { p1->back->forw = p1->forw; p1->forw->back = p1->back; p1->forw = p->forw; p->forw->back = p1; p->forw = p1; p1->back = p; } OpCode termop[] = { JBR, CBR, JMP, LABEL, DLABEL, EROU, JSW, TST, CMP, BIT, CALLF, CALLS, CASE, AOBLEQ, AOBLSS, CMPF, CMPF2, TSTF, MOVBLK, MFPR, MTPR, PROBE, MOVO, TEXT, DATA, BSS, ALIGN, END, LGEN, SET, LCOMM, COMM, NIL }; sideeffect(p,p1) struct node *p, *p1; { register struct node *q; register int r; register OpCode *t; register char *cp; int i; if (p1->op == NIL) return(1); /* special instructions */ for (t = termop; *t!=NIL; t++){ if (*t == p1->op) return(1); } if ((p1->forw != NULL) && (p1->forw->op == CBR)) return(1); splitrand(p1); r = isreg(lastrand); if (uses[r] && r >= 0 ) return(1); if ((p1->op == EDIV) && (r = isreg(regs[RT3]) >= 0) && (uses[r])) return(1); for (q = p1->back ; q!=p; q=q->back) { if ((p1->op == PUSH || p1->op == PUSHA) && (q->op == PUSHD || q->op == PUSH || q->op == PUSHA)) return(1); /* keep args in order */ if (((i = strlen(q->code)) >= 5 && /* cvdl -(sp); pushl r0*/ (strcmp(q->code+i-5,"-(sp)") == 0 )) || (strcmp(lastrand,"-(sp)") == 0)) return(1); if (equstr(q->code, lastrand)) return(1); if (q->op == STF || q->op == CVFL || q->op == CVLF) { if (equstr(q->code, regs[RT1])) return(1); if (has3ops(p1) || p1->op == EMUL || p1->op == EDIV) if (equstr(q->code, regs[RT2])) return(1); /* handle the case std -56(fp) pushl -60(fp) pushl -56(fp); */ if ((p1->forw != NULL) && (q->op == STF) && (q->subop == DOUBLE)){ if (!strncmp(q->code,p1->forw->code,strlen(q->code))) return(1); } } } return(0); } checkreg(p,s) struct node *p; char *s; { char *cp2; register int r; /* check for (r),[r] */ do if (*s=='(' || *s=='[') {/* get register number */ char t; cp2= ++s; while (*++s!=')' && *s!=']'); t= *s; *s=0; if ((r=isreg(cp2)) >= 0) { uses[r]=p; } *s=t; } while (*++s); }