P8000/WEGA/contrib/lcc/cmd/c2/c20.c

1102 lines
19 KiB
C

#
/*
* C object code improver
*/
#include "c2.h"
int dddflg = 0;
char *rline();
struct optab cctab[] = {
"eq", JEQ,
"z", JEQ,
"ne", JNE,
"nz", JNE,
"le", JLE,
"ge", JGE,
"lt", JLT,
"gt", JGT,
"c", JLO,
"ult", JLO,
"ugt", JHI,
"ule", JLOS,
"uge", JHIS,
"nc", JHIS,
"pl", PL,
"mi", MI,
0, 0};
struct optab optab[] = {
"jpr eq", CBR | JEQ<<8,
"jpr ne", CBR | JNE<<8,
"jpr le", CBR | JLE<<8,
"jpr ge", CBR | JGE<<8,
"jpr lt", CBR | JLT<<8,
"jpr gt", CBR | JGT<<8,
"jpr c", CBR | JLO<<8,
"jpr ugt", CBR | JHI<<8,
"jpr ule", CBR | JLOS<<8,
"jpr uge", CBR | JHIS<<8,
"jpr pl", CBR | PL<<8,
"jpr mi", CBR | MI<<8,
"jpr", JMP,
"djnz", DJNZ,
"{", EROU,
"ld", LD,
"ldk", LDK,
"ldir", LDI,
"lddr", LDD,
"clr", CLR,
"com", COM,
"inc", INC,
"dec", DEC,
"neg", NEG,
"test", TST,
"sra", ASR,
"sla", ASL,
"exts", SXT,
"cp", CMP,
"add", ADD,
"sub", SUB,
"or", OR,
"and", AND,
"set", SET,
"res", RES,
"bit", BIT,
"mult", MUL,
"div", DIV,
"ex", EX,
"pop", POP,
"push", PUSH,
"srl", SRL,
"sll", SLL,
"sdl", SDL,
"sda", SDA,
"xor", XOR,
".psec", CP,
".data", CD,
".data", BSS,
".code", CODE,
"//", CMT,
" .even", EVEN,
"callr", CALL,
0, 0};
char revbr[] = {JNE, JEQ, MI, PL, JGT, JLT, JGE, JLE, JHIS, JLOS, JHI, JLO};
int isn = 9000;
int lastseg = CD;
main(argc, argv)
char **argv;
{
register int niter, maxiter, isend;
extern end;
register c;
if (argc>1 && argv[1][0]=='+') {
debug++;
if(argv[1][1]=='+'){
debug++;
if(argv[1][2]=='+')
debug++;
}
argc--;
argv++;
}
if (argc>1) {
if (freopen(argv[1], "r", stdin) == NULL) {
fprintf(stderr, "lpopt: can't find %s\n", argv[1]);
exit(1);
}
}
for(c = 0; c < 10; c++)
address[c] = (char *)0;
if (argc>2) {
if (freopen(argv[2], "w", stdout) == NULL) {
fprintf(stderr, "lpopt: can't create %s\n", argv[2]);
exit(1);
}
}
addrseg = 0;
lasta = (char *)malloc(0xfff8);
firstr = lasta;
address[0] = lasta;
lastr = lasta + 0xfff8;
maxiter = 0;
opsetup();
do {
nchange = 0;
isend = input();
if(!isend) break;
niter = 0;
do {
refcount();
do {
iterate();
niter++;
} while (nchange);
clearreg();
comjump();
rmove();
} while (nchange );
addsob();
output();
if (niter > maxiter)
maxiter = niter;
addrseg = 0;
lasta = address[0];
lastr = lasta + 0xfff8;
} while (isend);
if (debug) {
fprintf(stderr, "%d iterations\n", maxiter);
fprintf(stderr, "%d jumps to jumps\n", nbrbr);
fprintf(stderr, "%d inst. after jumps\n", iaftbr);
fprintf(stderr, "%d jumps to .+2\n", njp1);
fprintf(stderr, "%d redundant labels\n", nrlab);
fprintf(stderr, "%d cross-jumps\n", nxjump);
fprintf(stderr, "%d code motions\n", ncmot);
fprintf(stderr, "%d branches reversed\n", nrevbr);
fprintf(stderr, "%d redundant moves\n", redunm);
fprintf(stderr, "%d simplified addresses\n", nsaddr);
fprintf(stderr, "%d loops inverted\n", loopiv);
fprintf(stderr, "%d redundant jumps\n", nredunj);
fprintf(stderr, "%d common seqs before jmp's\n", ncomj);
fprintf(stderr, "%d skips over jumps\n", nskip);
fprintf(stderr, "%d sob's added\n", nsob);
fprintf(stderr, "%d redundant tst's\n", nrtst);
fprintf(stderr, "%d literals eliminated\n", nlit);
for(addrseg=0;address[addrseg];addrseg++);
fprintf(stderr, "%d *64K core\n",addrseg+1);
}
exit(0);
}
input()
{
register struct node *p, *lastp;
register int oper;
register char *cc, *c1, *c2;
struct optab *ct;
static char tp[10];
lastp = &first;
do {
oper = getchar();
if(oper == EOF)
exit(0);
putchar(oper);
} while ( oper != '{');
getchar(); putchar('\n');
for (;;) {
oper = getline();
if(oper == CP && *(line+5)) {
if(!(strcmp(line+5," data"))) {
dddflg = 1;
if(debug > 1)
puts("dddflg erhoeht");
goto weiter;
}
printf("\t%s\n",line);
do {
cc = rline();
puts(cc);
} while(oper = strcmp(cc,"\t.code"));
continue;
}
weiter:
p = (struct node *)alloc(sizeof first);
p->op = oper&0377;
p->code = (char *)0;
p->subop = 0;
switch (oper&0377) {
case LABEL:
if (line[0] == 'L') {
p->op = LABEL;
p->labno = getnum(line+1);
if(dddflg){
if(debug > 1)
puts("label mit 100");
p->ref = (struct node*)100;
}
} else {
p->op = DLABEL;
p->labno = 0;
p->code = copy(1, line);
}
break;
case CMT:
p->op = 0;
p->labno = 0;
p->code = copy(1,line);
break;
case CBR:
p->subop = oper >> 8;
case JMP:
case JSW:
if(*curlp != 'L') {
c2 = tp;
for(cc = curlp; *cc && *cc!='\t' && *cc!=' '
&& *cc!=',' && *cc!='\n';)
*c2++ = *cc++;
*c2++ = 0;
ct = cctab;
for(;ct->opstring!=0;ct++) {
c1 = ct->opstring;
c2 = tp;
while(*c2 == *c1++)
if(*c2++ == 0) {
p->subop = ct->opcode;
p->op -= 2;
curlp = ++cc;
goto jp;
}
}
}
jp:
if (*curlp=='L' && (p->labno = getnum(curlp+1)))
p->code = 0;
else {
p->labno = 0;
p->code = copy(1, curlp);
}
break;
case XL1:
xl1 = getnum(line);
break;
case XL2:
xl2 = getnum(line);
break;
case EROU:
break;
case CODE:
if(debug > 1)
puts("dddflg runter!");
dddflg = 0;
default:
p->subop = oper>>8;
p->labno = 0;
p->code = copy(1, curlp);
break;
}
p->forw = 0;
p->back = lastp;
lastp->forw = p;
lastp = p;
if(p->op != LABEL || !dddflg)
p->ref = 0;
if(debug > 2) {
printf("input line is: ");
dbprint(p);
}
if (oper==EROU)
return(1);
if (oper==END)
return(0);
}
}
getline()
{
register char *lp;
register c;
register c1;
lp = line;
while ((c = getchar())==' ' || c=='\t')
;
if(c=='}') {
getchar();
return(EROU);
}
do {
if (c == '/')
if ((c1=getchar()) != c)
ungetc(c1,stdin);
else
{
*lp++ = c;
do
*lp++ = c;
while((c = getchar()) != '\n');
*lp = 0;
return(CMT);
}
if (c == ':') {
c = LABEL;
if ((c1=getchar()) == ':')
{
getchar();
*lp++ = ':';
} else if(c1 == '=' && *line == '~') {
getchar();
if(*(line+2)=='1')
c = XL1;
else
c = XL2;
lp = line;
while((c1 = getchar()) != '\n')
*lp++ = c1;
}
*lp = 0;
return(c);
}
if (c=='\n') {
*lp++ = 0;
return(oplook());
}
if (lp >= &line[LSIZE-2]) {
fprintf(stderr, "lpopt: Sorry, input line too long\n");
exit(1);
}
*lp++ = c;
} while ((c = getchar()) != EOF);
*lp++ = 0;
return(END);
}
getnum(ap)
char *ap;
{
register char *p;
register n, c;
p = ap;
n = 0;
while ((c = *p++) >= '0' && c <= '9')
n = n*10 + c - '0';
if (*--p != 0)
return(0);
return(n);
}
output()
{
register struct node *t;
register struct optab *oper;
register int byte;
t = &first;
while (t = t->forw) {
switch (t->op) {
case END:
return;
case LABEL:
printf("L%d:\n", t->labno);
continue;
case DLABEL:
printf("%s:\n", t->code);
continue;
case XL1:
printf(" ~L1 := %d\n",xl1);
continue;
case XL2:
printf(" ~L2 := %d\n",xl2);
continue;
case CD:
lastseg = DATA;
goto def;
case BSS:
lastseg = BSS;
goto def;
case EROU:
printf("\t}\n");
return;
case CODE:
case CP:
lastseg = CODE;
def:
default:
if ((byte = t->subop)==BYTE ||byte==LONG)
t->subop = 0;
for (oper = optab; oper->opstring!=0; oper++)
if ((oper->opcode&0377) == t->op
&& (oper->opcode>>8) == t->subop) {
printf("\t%s", oper->opstring);
if (byte==BYTE)
putchar('b');
else if(byte==LONG)
putchar('l');
break;
}
if (t->code)
printf("\t%s\n", t->code);
else if (t->op == JMP)
printf("\tL%d\n", t->labno);
else if (t->op == CBR)
printf(",L%d\n", t->labno);
else
printf("\n");
continue;
case JSW:
printf("\t.addr L%d\n", t->labno);
continue;
case DJNZ:
printf("\tdjnz %s",t->code);
if (t->labno)
printf(",L%d\n",t->labno);
continue;
case 0:
if (t->code)
printf("\t%s\n", t->code);
continue;
}
}/*while*/
}
char *
copy(na, ap)
char *ap;
{
register char *p, *np;
register char *onp;
register n;
p = ap;
n = 0;
if (*p==0)
return(0);
do
n++;
while (*p++);
if (na>1) {
p = (&ap)[1];
while (*p++)
n++;
}
if(strchr(ap,'_'))
n += 2;
onp = np = alloc(n);
p = ap;
while (*np++ = *p++)
;
if (na>1) {
p = (&ap)[1];
np--;
while (*np++ = *p++);
}
return(onp);
}
opsetup()
{
register struct optab *optp, **ophp;
register char *p;
for (optp = optab; p = optp->opstring; optp++) {
ophp = &ophash[(((p[0]<<3)+(p[1]<<1)+p[2])&077777) % OPHS];
while (*ophp++)
if (ophp > &ophash[OPHS])
ophp = ophash;
*--ophp = optp;
}
}
oplook()
{
register struct optab *optp;
register char *lp, *np;
char c;
static char tmpop[32];
register struct optab **ophp;
if (line[0]=='\0') {
curlp = line;
return(0);
}
np = tmpop;
for (lp = line; *lp && *lp!=' ' && *lp!='\t';)
*np++ = *lp++;
*np++ = 0;
while (*lp=='\t' || *lp==' ')
lp++;
curlp = lp;
c = tmpop[2];
if((tmpop[2]=='b'||tmpop[2]=='l'||tmpop[2]=='s'||tmpop[2]=='d') &&
((tmpop[0]=='l'&&tmpop[1]=='d')||(tmpop[0]=='c'&&tmpop[1]=='p')||
(tmpop[0]=='o'&&tmpop[1]=='r')||(tmpop[0]=='e'&&tmpop[1]=='x')))
tmpop[2] = 0;
ophp = &ophash[(((tmpop[0]<<3)+(tmpop[1]<<1)+tmpop[2])&077777) % OPHS];
tmpop[2] = c;
while (optp = *ophp) {
np = optp->opstring;
lp = tmpop;
while (*lp == *np++)
if (*lp++ == 0)
return(optp->opcode);
c = *lp++;
if((c=='b'||c=='l'||c=='s'||c=='d') && *lp++==0 && *--np==0)
if(c=='b')
return(optp->opcode + (BYTE<<8));
else if(c=='l')
return(optp->opcode + (LONG<<8));
ophp++;
if (ophp >= &ophash[OPHS])
ophp = ophash;
}
if (line[0] == '\.' && line[1] == 'a' && line[6] == 'L') {
lp = line+7;
while (*lp)
if (*lp<'0' || *lp++>'9')
return(0);
curlp = line+6;
return(JSW);
}
curlp = line;
return(0);
}
refcount()
{
register struct node *p, *lp;
static struct node *labhash[LABHS];
register struct node **hp, *tp;
char *sss;
if(debug > 1)
printf("refcount works\n");
for (hp = labhash; hp < &labhash[LABHS];)
*hp++ = 0;
for (p = first.forw; p!=0; p = p->forw) {
if(debug > 2){
printf("refcount (1) works on:");
dbprint(p);
}
if(p->code&&!strchr(p->code,'|')&&(sss = strchr(p->code,'_')))
mycode(sss);
if(p->op==0 && p->code && p->code[0]=='I') {
if(p->forw->op==END ||p->forw->op==0 &&p->forw->code &&
(p->forw->code[0]=='G'||p->forw->code[0]=='I')){
elim(p);
p = p->forw;
continue;
}
}
if (p->op==LABEL) {
labhash[p->labno % LABHS] = p;
if(p->ref == (struct node *)100)
p->refc = 100;
else
p->refc = 0;
}
}
for (p = first.forw; p!=0; p = p->forw) {
if(debug > 2){
printf("refcount (2) works on:");
dbprint(p);
}
if (p->op && p->op <= JSW) {
p->ref = 0;
lp = labhash[p->labno % LABHS];
if (lp==0 || p->labno!=lp->labno)
for (lp = first.forw; lp!=0; lp = lp->forw) {
if (lp->op==LABEL && p->labno==lp->labno)
break;
}
if (lp) {
tp = nonlab(lp)->back;
if (tp!=lp) {
p->labno = tp->labno;
lp = tp;
}
p->ref = lp;
lp->refc++;
}
}
}
for (p = first.forw; p!=0; p = p->forw)
if (p->op==LABEL && p->refc==0
&& (lp = nonlab(p))->op && lp->op!=JSW)
decref(p);
}
iterate()
{
register struct node *p, *rp, *p1;
if(debug > 1)
printf("iterate works\n");
nchange = 0;
for (p = first.forw; p!=0; p = p->forw) {
if (p->op && p->op <= JSW) {
if(debug > 2){
printf("iterate works on:");
dbprint(p);
}
rp = nonlab(p->ref);
if (rp->op==JMP && rp->labno && p->labno!=rp->labno) {
nbrbr++;
p->labno = rp->labno;
decref(p->ref);
rp->ref->refc++;
p->ref = rp->ref;
nchange++;
}
}
if (p->op==CBR && (p1 = p->forw)->op==JMP && p1->labno) {
rp = p->ref;
do
rp = rp->back;
while (rp->op==LABEL);
if (rp==p1) {
decref(p->ref);
p->ref = p1->ref;
p->labno = p1->labno;
p1->forw->back = p;
p->forw = p1->forw;
p->subop = revbr[p->subop];
nchange++;
nskip++;
}
}
if(p->op==CBR && (p1 = p->forw)->op==CBR &&
p->labno==p1->labno && p->subop==revbr[p1->subop]) {
elim(p1);
p->subop = 0;
p->op += 2;
nchange++;
}
if (p->op==JMP) {
while (p->forw && p->forw->op!=LABEL
&& p->forw->op!=DLABEL
&& p->forw->op!=EROU && p->forw->op!=END
&& p->forw->op!=0 && p->forw->op!=DATA) {
nchange++;
iaftbr++;
if (p->forw->ref)
decref(p->forw->ref);
p->forw = p->forw->forw;
p->forw->back = p;
}
rp = p->forw;
while (rp && rp->op==LABEL) {
if (p->ref == rp) {
elim(p);
p = p->back;
decref(rp);
nchange++;
njp1++;
break;
}
rp = rp->forw;
}
}
if (p->op==JMP) {
xjump(p);
p = codemove(p);
}
if ((p->op==CBR || p->op == JMP) && p->ref == p->forw) {
decref(p->forw);
elim(p);
p = p->back;
nchange++;
}
}
}
xjump(p1)
register struct node *p1;
{
register struct node *p2, *p3;
if ((p2 = p1->ref)==0)
return;
if(debug > 2){
printf("xjump works on:");
dbprint(p1);
}
for (;;) {
while ((p1 = p1->back) && p1->op==LABEL);
while ((p2 = p2->back) && p2->op==LABEL);
if (!equop(p1, p2) || p1==p2 || p1->op>=CODE && p1->op<=CMT)
return;
p3 = insertl(p2);
p1->op = JMP;
p1->subop = 0;
p1->ref = p3;
p1->labno = p3->labno;
p1->code = 0;
nxjump++;
nchange++;
}
}
struct node *
insertl(oldp)
register struct node *oldp;
{
register struct node *lp;
if (oldp->op == LABEL) {
oldp->refc++;
return(oldp);
}
if (oldp->back->op == LABEL) {
oldp = oldp->back;
oldp->refc++;
return(oldp);
}
lp = (struct node *)alloc(sizeof first);
lp->op = LABEL;
lp->subop = 0;
lp->labno = isn++;
lp->ref = 0;
lp->code = 0;
lp->refc = 1;
lp->back = oldp->back;
lp->forw = oldp;
oldp->back->forw = lp;
oldp->back = lp;
if(debug > 2){
printf("insertl inserts oper:");
dbprint(lp);
}
return(lp);
}
struct node *
codemove(p)
struct node *p;
{
register struct node *p1, *p2, *p3;
register struct node *t, *tl;
register n;
p1 = p;
if(debug > 2){
printf("codemove works on:");
dbprint(p1);
}
if ((p1->op!=JMP) || (p2 = p1->ref)==0)
return(p1);
while (p2->op == LABEL)
if ((p2 = p2->back) == 0)
return(p1);
if (p2->op!=JMP)
goto ivloop;
p2 = p2->forw;
p3 = p1->ref;
while (p3) {
if (p3->op==JMP) {
if (p1==p3)
return(p1);
ncmot++;
nchange++;
p1->back->forw = p2;
p1->forw->back = p3;
p2->back->forw = p3->forw;
p3->forw->back = p2->back;
p2->back = p1->back;
p3->forw = p1->forw;
decref(p1->ref);
return(p2);
} else
p3 = p3->forw;
}
return(p1);
ivloop:
if (p1->forw->op!=LABEL)
return(p1);
p3 = p2 = p2->forw;
n = 16;
do {
if ((p3 = p3->forw) == 0 || p3==p1 || --n==0)
return(p1);
} while (p3->op && p3->op > CBR || p3->labno!=p1->forw->labno);
do
if ((p1 = p1->back) == 0)
return(p);
while (p1!=p3);
p1 = p;
tl = insertl(p1);
p3->subop = revbr[p3->subop];
decref(p3->ref);
p2->back->forw = p1;
p3->forw->back = p1;
p1->back->forw = p2;
p1->forw->back = p3;
t = p1->back;
p1->back = p2->back;
p2->back = t;
t = p1->forw;
p1->forw = p3->forw;
p3->forw = t;
p2 = insertl(p1->forw);
p3->labno = p2->labno;
p3->ref = p2;
decref(tl);
if (tl->refc<=0)
nrlab--;
loopiv++;
nchange++;
return(p3);
}
comjump()
{
register struct node *p1, *p2, *p3;
if(debug > 1)
printf("comjump works\n");
for (p1 = first.forw; p1!=0; p1 = p1->forw)
if (p1->op==JMP && (p2 = p1->ref) && p2->refc > 1)
for (p3 = p1->forw; p3!=0; p3 = p3->forw)
if (p3->op && p3->op<=JMP && p3->ref == p2)
backjmp(p1, p3);
}
/*
reljmp()
{
register struct node *p;
nchange = 0;
for( p = first.forw; p != 0; p = p->forw)
if((p->op==JMP || p->op==CBR) && p->labno && !toofar(p)) {
p->op--;
nchange++;
}
}
*/
backjmp(ap1, ap2)
struct node *ap1, *ap2;
{
register struct node *p1, *p2, *p3;
if(debug > 1)
printf("backjmp works\n");
p1 = ap1;
p2 = ap2;
for(;;) {
while ((p1 = p1->back) && p1->op==LABEL);
p2 = p2->back;
if (equop(p1, p2)) {
p3 = insertl(p1);
elim(p2);
p2 = p2->forw;
decref(p2->ref);
p2->labno = p3->labno;
p2->ref = p3;
nchange++;
ncomj++;
} else
return;
}
}
/*
retc()
{
register struct node *p, *p1;
p = first.forw;
while(p!=0 &&(p->op!=CALL || !equstr(p->code,"csv")))
p = p->forw;
p1 = p->forw;
while(p1->op==0 && p1->code[0]=='!')
p1 = p1->forw;
if(p1->op==JMP && equstr(p1->code,"cret")) {
elim(p);
p1->op = 0;
p1->code = "ret";
return(1);
}
return(0);
}
*/
/* mycode for short addresses */
mycode(str)
char *str;
{
register char *s = str;
char *anf, *ende;
char *stkp;
unsigned xli;
while(*s) {
while(*s && *s != '_')
s++;
if(!*s)
return;
/* _... gefunden */
anf = s++;
if(strncmp(s,"stkseg",6) || *(s+6) != '+') {
/* kein stkseg */
s = ++anf;
continue;
}
/* stkseg gefunden, hinter '+' */
s += 7;
xli = 0;
if(*s == '~' && *(s+1) == 'L') {
s += 2;
if(*s == '1')
xli = xl1;
else if(*s == '2')
xli = xl2;
else {
fprintf(stderr, "lpopt: illegal ~L");
continue;
}
s += 2;
}
/* hinter ~Li+ auf '%' */
if(*s == '%') {
s++;
if(*(s-2) == '+')
xli += hexa(s);
else
xli -= hexa(s);
}
while(*s && *s!='(')
s++;
if(*s != '(')
return;
ende = s;
break;
} /* while */
if(xli > 0xff)
return;
while (*s++);
s--;
for(;s >= ende; s--)
*(s+2) = *s;
*(s+2) = '|';
for(; s >= anf; s--)
*(s+1) = *s;
*(s+1) = '|';
if(debug > 2)
printf("mycode gives: %s\n",str);
return;
}
dbprint(t)
struct node *t;
{
register struct optab *oper;
register int byte;
printf("\t*(%lx)*",t);
byte = t->subop;
switch(t->op) {
case END:
printf("end\n");
return;
case LABEL:
printf("L%d:\n", t->labno);
return;
case DLABEL:
printf("%s:\n", t->code);
return;
case XL1:
printf(" ~L1 := %d\n",xl1);
return;
case XL2:
printf(" ~L2 := %d\n",xl2);
return;
case CD:
lastseg = DATA;
goto def;
case BSS:
lastseg = BSS;
goto def;
case EROU:
printf("\t{\n");
return;
def:
default:
if (byte == BYTE ||byte==LONG)
t->subop = 0;
for (oper = optab; oper->opstring!=0; oper++)
if ((oper->opcode&0377) == t->op
&& (oper->opcode>>8) == t->subop) {
printf("\t%s", oper->opstring);
if (byte==BYTE)
putchar('b');
else if(byte==LONG)
putchar('l');
t->subop = byte;
break;
}
if (t->code)
printf("\t%s\n", t->code);
else if (t->op == JMP)
printf("\tL%d\n", t->labno);
else if (t->op == CBR)
printf(",L%d\n", t->labno);
else
printf("\n");
t->subop = byte;
return;
case JSW:
printf("\t.addr L%d\n", t->labno);
return;
case DJNZ:
printf("\tdjnz %s",t->code);
if (t->labno)
printf(",L%d\n",t->labno);
return;
case 0:
if (t->code)
printf("\t%s\n", t->code);
else
printf("Leerzeile\n");
return;
}
}
char *
rline()
{
static char fff[120];
register char *c;
register x;
c = fff;
while((x = getchar())!='\n'){
*c++ = x;
}
*c = 0;
return(fff);
}