Add original unix v6
This commit is contained in:
+621
@@ -0,0 +1,621 @@
|
||||
#
|
||||
/*
|
||||
* C compiler part 2 -- expression optimizer
|
||||
*
|
||||
*/
|
||||
|
||||
#include "c1h.c"
|
||||
|
||||
optim(atree)
|
||||
struct tnode *atree;
|
||||
{
|
||||
register op, dope;
|
||||
int d1, d2;
|
||||
struct tnode *t;
|
||||
register struct tnode *tree;
|
||||
|
||||
if ((tree=atree)==0)
|
||||
return(0);
|
||||
if ((op = tree->op)==0)
|
||||
return(tree);
|
||||
if (op==NAME && tree->class==AUTO) {
|
||||
tree->class = OFFS;
|
||||
tree->regno = 5;
|
||||
tree->offset = tree->nloc;
|
||||
}
|
||||
dope = opdope[op];
|
||||
if ((dope&LEAF) != 0)
|
||||
return(tree);
|
||||
if ((dope&BINARY) == 0)
|
||||
return(unoptim(tree));
|
||||
/* is known to be binary */
|
||||
if (tree->type==CHAR)
|
||||
tree->type = INT;
|
||||
if ((dope&COMMUTE)!=0) {
|
||||
acomm: d1 = tree->type;
|
||||
tree = acommute(tree);
|
||||
tree->type = d1;
|
||||
/*
|
||||
* PDP-11 special:
|
||||
* replace a&b by a NAND ~ b.
|
||||
* This will be undone when in
|
||||
* truth-value context.
|
||||
*/
|
||||
if (tree->op!=AND)
|
||||
return(tree);
|
||||
tree->op = NAND;
|
||||
tree->tr2 = block(1, COMPL, tree->tr2->type, 0, tree->tr2);
|
||||
}
|
||||
again:
|
||||
tree->tr1 = optim(tree->tr1);
|
||||
tree->tr2 = optim(tree->tr2);
|
||||
if ((dope&RELAT) != 0) {
|
||||
if ((d1=degree(tree->tr1)) < (d2=degree(tree->tr2))
|
||||
|| d1==d2 && tree->tr1->op==NAME && tree->tr2->op!=NAME) {
|
||||
t = tree->tr1;
|
||||
tree->tr1 = tree->tr2;
|
||||
tree->tr2 = t;
|
||||
tree->op = maprel[op-EQUAL];
|
||||
}
|
||||
if (tree->tr1->type==CHAR && tree->tr2->op==CON
|
||||
&& (dcalc(tree->tr1) <= 12 || tree->tr1->op==STAR)
|
||||
&& tree->tr2->value <= 127 && tree->tr2->value >= 0)
|
||||
tree->tr2->type = CHAR;
|
||||
}
|
||||
d1 = max(degree(tree->tr1), islong(tree->type));
|
||||
d2 = max(degree(tree->tr2), 0);
|
||||
if (tree->tr1->type==LONG && dope&RELAT)
|
||||
d1 = 10;
|
||||
switch (op) {
|
||||
|
||||
case LTIMES:
|
||||
case LDIV:
|
||||
case LMOD:
|
||||
case LASTIMES:
|
||||
case LASDIV:
|
||||
case LASMOD:
|
||||
tree->degree = 10;
|
||||
break;
|
||||
|
||||
/*
|
||||
* PDP-11 special:
|
||||
* generate new =&~ operator out of =&
|
||||
* by complementing the RHS.
|
||||
*/
|
||||
case ASSAND:
|
||||
op = ASSNAND;
|
||||
tree->op = op;
|
||||
tree->tr2 = block(2, COMPL, tree->tr2->type, 0, tree->tr2);
|
||||
goto again;
|
||||
|
||||
case NAND:
|
||||
if (isconstant(tree->tr2) && tree->tr2->value==0)
|
||||
return(tree->tr1);
|
||||
goto def;
|
||||
|
||||
case CALL:
|
||||
tree->degree = 10;
|
||||
break;
|
||||
|
||||
case QUEST:
|
||||
case COLON:
|
||||
tree->degree = max(d1, d2);
|
||||
break;
|
||||
|
||||
case MINUS:
|
||||
if (t = isconstant(tree->tr2)) {
|
||||
tree->op = PLUS;
|
||||
if (t->type==DOUBLE)
|
||||
/* PDP-11 FP representation */
|
||||
t->value =^ 0100000;
|
||||
else
|
||||
t->value = -t->value;
|
||||
goto acomm;
|
||||
}
|
||||
goto def;
|
||||
|
||||
case DIVIDE:
|
||||
case ASDIV:
|
||||
case ASTIMES:
|
||||
if (tree->tr2->op==CON && tree->tr2->value==1)
|
||||
return(tree->tr1);
|
||||
if (ispow2(tree) == 0) {
|
||||
|
||||
case MOD:
|
||||
case ASMOD:
|
||||
d1 =+ 2;
|
||||
d2 =+ 2;
|
||||
}
|
||||
if (tree->type==LONG)
|
||||
return(hardlongs(tree));
|
||||
goto constant;
|
||||
|
||||
case LSHIFT:
|
||||
case RSHIFT:
|
||||
case ASRSH:
|
||||
case ASLSH:
|
||||
if (tree->tr2->op==CON && tree->tr2->value==0)
|
||||
return(tree->tr1);
|
||||
/*
|
||||
* PDP-11 special: turn right shifts into negative
|
||||
* left shifts
|
||||
*/
|
||||
if (op==LSHIFT||op==ASLSH)
|
||||
goto constant;
|
||||
if (tree->tr2->op==CON && tree->tr2->value==1)
|
||||
goto constant;
|
||||
op =+ (LSHIFT-RSHIFT);
|
||||
tree->op = op;
|
||||
tree->tr2 = block(1, NEG, tree->type, 0, tree->tr2);
|
||||
goto again;
|
||||
|
||||
constant:
|
||||
if (tree->tr1->op==CON && tree->tr2->op==CON) {
|
||||
const(op, &tree->tr1->value, tree->tr2->value);
|
||||
return(tree->tr1);
|
||||
}
|
||||
|
||||
|
||||
def:
|
||||
default:
|
||||
tree->degree = d1==d2? d1+islong(tree->type): max(d1, d2);
|
||||
break;
|
||||
}
|
||||
return(tree);
|
||||
}
|
||||
|
||||
unoptim(atree)
|
||||
struct tnode *atree;
|
||||
{
|
||||
register struct tnode *subtre, *tree;
|
||||
register int *p;
|
||||
double static fv;
|
||||
struct { int integer; };
|
||||
|
||||
if ((tree=atree)==0)
|
||||
return(0);
|
||||
if (tree->op==CBRANCH) {
|
||||
tree->btree = optim(tree->btree);
|
||||
return(tree);
|
||||
}
|
||||
subtre = tree->tr1 = optim(tree->tr1);
|
||||
switch (tree->op) {
|
||||
|
||||
case FSEL:
|
||||
tree->tr1 = block(2, RSHIFT, INT, 0, subtre,
|
||||
block(1, CON, INT, 0, tree->bitoffs));
|
||||
tree->op = AND;
|
||||
tree->type = INT;
|
||||
tree->tr2 = block(1, CON, INT, 0, (1<<tree->flen)-1);
|
||||
return(optim(tree));
|
||||
|
||||
case AMPER:
|
||||
if (subtre->op==STAR)
|
||||
return(subtre->tr1);
|
||||
if (subtre->op==NAME && subtre->class == OFFS) {
|
||||
p = block(2, PLUS, tree->type, 1, subtre, tree);
|
||||
subtre->type = tree->type;
|
||||
tree->op = CON;
|
||||
tree->type = INT;
|
||||
tree->degree = 0;
|
||||
tree->value = subtre->offset;
|
||||
subtre->class = REG;
|
||||
subtre->nloc = subtre->regno;
|
||||
subtre->offset = 0;
|
||||
return(p);
|
||||
}
|
||||
break;
|
||||
|
||||
case STAR:
|
||||
if (subtre->op==AMPER)
|
||||
return(subtre->tr1);
|
||||
if (subtre->op==NAME && subtre->class==REG) {
|
||||
subtre->type = tree->type;
|
||||
subtre->class = OFFS;
|
||||
subtre->regno = subtre->nloc;
|
||||
return(subtre);
|
||||
}
|
||||
p = subtre->tr1;
|
||||
if ((subtre->op==INCAFT||subtre->op==DECBEF)&&tree->type!=LONG
|
||||
&& p->op==NAME && p->class==REG && p->type==subtre->type) {
|
||||
p->type = tree->type;
|
||||
p->op = subtre->op==INCAFT? AUTOI: AUTOD;
|
||||
return(p);
|
||||
}
|
||||
if (subtre->op==PLUS && p->op==NAME && p->class==REG) {
|
||||
if (subtre->tr2->op==CON) {
|
||||
p->offset =+ subtre->tr2->value;
|
||||
p->class = OFFS;
|
||||
p->type = tree->type;
|
||||
p->regno = p->nloc;
|
||||
return(p);
|
||||
}
|
||||
if (subtre->tr2->op==AMPER) {
|
||||
subtre = subtre->tr2->tr1;
|
||||
subtre->class =+ XOFFS-EXTERN;
|
||||
subtre->regno = p->nloc;
|
||||
subtre->type = tree->type;
|
||||
return(subtre);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXCLA:
|
||||
if ((opdope[subtre->op]&RELAT)==0)
|
||||
break;
|
||||
tree = subtre;
|
||||
tree->op = notrel[tree->op-EQUAL];
|
||||
break;
|
||||
|
||||
case NEG:
|
||||
case COMPL:
|
||||
if (tree->type==CHAR)
|
||||
tree->type = INT;
|
||||
if (tree->op == subtre->op)
|
||||
return(subtre->tr1);
|
||||
if (subtre->op==ITOL) {
|
||||
subtre->op = tree->op;
|
||||
subtre->type = INT;
|
||||
tree->op = ITOL;
|
||||
}
|
||||
}
|
||||
if (subtre->op == CON) switch(tree->op) {
|
||||
|
||||
case NEG:
|
||||
subtre->value = -subtre->value;
|
||||
return(subtre);
|
||||
|
||||
case COMPL:
|
||||
subtre->value = ~subtre->value;
|
||||
return(subtre);
|
||||
|
||||
case ITOF:
|
||||
fv = subtre->value;
|
||||
p = &fv;
|
||||
p++;
|
||||
if (*p++==0 && *p++==0 && *p++==0) {
|
||||
subtre->type = DOUBLE;
|
||||
subtre->value = fv.integer;
|
||||
subtre->op = SFCON;
|
||||
return(subtre);
|
||||
}
|
||||
break;
|
||||
}
|
||||
tree->degree = max(islong(tree->type), degree(subtre));
|
||||
return(tree);
|
||||
}
|
||||
|
||||
struct acl {
|
||||
int nextl;
|
||||
int nextn;
|
||||
struct tnode *nlist[20];
|
||||
struct tnode *llist[21];
|
||||
};
|
||||
|
||||
acommute(atree)
|
||||
{
|
||||
struct acl acl;
|
||||
int d, i, op, flt;
|
||||
register struct tnode *t1, **t2, *tree;
|
||||
struct tnode *t;
|
||||
|
||||
acl.nextl = 0;
|
||||
acl.nextn = 0;
|
||||
tree = atree;
|
||||
op = tree->op;
|
||||
flt = isfloat(tree);
|
||||
insert(op, tree, &acl);
|
||||
acl.nextl--;
|
||||
t2 = &acl.llist[acl.nextl];
|
||||
if (!flt) {
|
||||
/* put constants together */
|
||||
for (i=acl.nextl;i>0&&t2[0]->op==CON&&t2[-1]->op==CON;i--) {
|
||||
acl.nextl--;
|
||||
t2--;
|
||||
const(op, &t2[0]->value, t2[1]->value);
|
||||
}
|
||||
}
|
||||
if (op==PLUS || op==OR) {
|
||||
/* toss out "+0" */
|
||||
if (acl.nextl>0 && (t1 = isconstant(*t2)) && t1->value==0) {
|
||||
acl.nextl--;
|
||||
t2--;
|
||||
}
|
||||
if (acl.nextl <= 0)
|
||||
return(*t2);
|
||||
/* subsume constant in "&x+c" */
|
||||
if (op==PLUS && t2[0]->op==CON && t2[-1]->op==AMPER) {
|
||||
t2--;
|
||||
t2[0]->tr1->offset =+ t2[1]->value;
|
||||
acl.nextl--;
|
||||
}
|
||||
} else if (op==TIMES || op==AND) {
|
||||
t1 = acl.llist[acl.nextl];
|
||||
if (t1->op==CON) {
|
||||
if (t1->value==0)
|
||||
return(t1);
|
||||
if (op==TIMES && t1->value==1 && acl.nextl>0)
|
||||
if (--acl.nextl <= 0)
|
||||
return(acl.llist[0]);
|
||||
}
|
||||
}
|
||||
if (op==PLUS && !flt)
|
||||
distrib(&acl);
|
||||
tree = *(t2 = &acl.llist[0]);
|
||||
d = max(degree(tree), islong(tree->type));
|
||||
if (op==TIMES && !flt)
|
||||
d++;
|
||||
for (i=0; i<acl.nextl; i++) {
|
||||
t1 = acl.nlist[i];
|
||||
t1->tr2 = t = *++t2;
|
||||
t1->degree = d = d==degree(t)? d+islong(t1->type): max(d, degree(t));
|
||||
t1->tr1 = tree;
|
||||
tree = t1;
|
||||
if (tree->type==LONG) {
|
||||
if (tree->op==TIMES)
|
||||
tree = hardlongs(tree);
|
||||
else if (tree->op==PLUS && (t = isconstant(tree->tr1))
|
||||
&& t->value < 0) {
|
||||
tree->op = MINUS;
|
||||
t->value = - t->value;
|
||||
t = tree->tr1;
|
||||
tree->tr1 = tree->tr2;
|
||||
tree->tr2 = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tree->op==TIMES && ispow2(tree))
|
||||
tree->degree = max(degree(tree->tr1), islong(tree->type));
|
||||
return(tree);
|
||||
}
|
||||
|
||||
distrib(list)
|
||||
struct acl *list;
|
||||
{
|
||||
/*
|
||||
* Find a list member of the form c1c2*x such
|
||||
* that c1c2 divides no other such constant, is divided by
|
||||
* at least one other (say in the form c1*y), and which has
|
||||
* fewest divisors. Reduce this pair to c1*(y+c2*x)
|
||||
* and iterate until no reductions occur.
|
||||
*/
|
||||
register struct tnode **p1, **p2;
|
||||
struct tnode *t;
|
||||
int ndmaj, ndmin;
|
||||
struct tnode **dividend, **divisor;
|
||||
struct tnode **maxnod, **mindiv;
|
||||
|
||||
loop:
|
||||
maxnod = &list->llist[list->nextl];
|
||||
ndmaj = 1000;
|
||||
dividend = 0;
|
||||
for (p1 = list->llist; p1 <= maxnod; p1++) {
|
||||
if ((*p1)->op!=TIMES || (*p1)->tr2->op!=CON)
|
||||
continue;
|
||||
ndmin = 0;
|
||||
for (p2 = list->llist; p2 <= maxnod; p2++) {
|
||||
if (p1==p2 || (*p2)->op!=TIMES || (*p2)->tr2->op!=CON)
|
||||
continue;
|
||||
if ((*p1)->tr2->value == (*p2)->tr2->value) {
|
||||
(*p2)->tr2 = (*p1)->tr1;
|
||||
(*p2)->op = PLUS;
|
||||
(*p1)->tr1 = (*p2);
|
||||
*p1 = optim(*p1);
|
||||
squash(p2, maxnod);
|
||||
list->nextl--;
|
||||
goto loop;
|
||||
}
|
||||
if (((*p2)->tr2->value % (*p1)->tr2->value) == 0)
|
||||
goto contmaj;
|
||||
if (((*p1)->tr2->value % (*p2)->tr2->value) == 0) {
|
||||
ndmin++;
|
||||
mindiv = p2;
|
||||
}
|
||||
}
|
||||
if (ndmin > 0 && ndmin < ndmaj) {
|
||||
ndmaj = ndmin;
|
||||
dividend = p1;
|
||||
divisor = mindiv;
|
||||
}
|
||||
contmaj:;
|
||||
}
|
||||
if (dividend==0)
|
||||
return;
|
||||
t = list->nlist[--list->nextn];
|
||||
p1 = dividend;
|
||||
p2 = divisor;
|
||||
t->op = PLUS;
|
||||
t->type = (*p1)->type;
|
||||
t->tr1 = (*p1);
|
||||
t->tr2 = (*p2)->tr1;
|
||||
(*p1)->tr2->value =/ (*p2)->tr2->value;
|
||||
(*p2)->tr1 = t;
|
||||
t = optim(*p2);
|
||||
if (p1 < p2) {
|
||||
*p1 = t;
|
||||
squash(p2, maxnod);
|
||||
} else {
|
||||
*p2 = t;
|
||||
squash(p1, maxnod);
|
||||
}
|
||||
list->nextl--;
|
||||
goto loop;
|
||||
}
|
||||
|
||||
squash(p, maxp)
|
||||
struct tnode **p, **maxp;
|
||||
{
|
||||
register struct tnode **np;
|
||||
|
||||
for (np = p; np < maxp; np++)
|
||||
*np = *(np+1);
|
||||
}
|
||||
|
||||
const(op, vp, av)
|
||||
int *vp;
|
||||
{
|
||||
register int v;
|
||||
|
||||
v = av;
|
||||
switch (op) {
|
||||
|
||||
case PLUS:
|
||||
*vp =+ v;
|
||||
return;
|
||||
|
||||
case TIMES:
|
||||
*vp =* v;
|
||||
return;
|
||||
|
||||
case AND:
|
||||
*vp =& v;
|
||||
return;
|
||||
|
||||
case OR:
|
||||
*vp =| v;
|
||||
return;
|
||||
|
||||
case EXOR:
|
||||
*vp =^ v;
|
||||
return;
|
||||
|
||||
case DIVIDE:
|
||||
case MOD:
|
||||
if (v==0)
|
||||
error("Divide check");
|
||||
else
|
||||
if (op==DIVIDE)
|
||||
*vp =/ v;
|
||||
else
|
||||
*vp =% v;
|
||||
return;
|
||||
|
||||
case RSHIFT:
|
||||
*vp =>> v;
|
||||
return;
|
||||
|
||||
case LSHIFT:
|
||||
*vp =<< v;
|
||||
return;
|
||||
|
||||
case NAND:
|
||||
*vp =& ~ v;
|
||||
return;
|
||||
}
|
||||
error("C error: const");
|
||||
}
|
||||
|
||||
insert(op, atree, alist)
|
||||
struct acl *alist;
|
||||
{
|
||||
register d;
|
||||
register struct acl *list;
|
||||
register struct tnode *tree;
|
||||
int d1, i;
|
||||
struct tnode *t;
|
||||
|
||||
tree = atree;
|
||||
list = alist;
|
||||
if (tree->op == op) {
|
||||
ins: list->nlist[list->nextn++] = tree;
|
||||
insert(op, tree->tr1, list);
|
||||
insert(op, tree->tr2, list);
|
||||
return;
|
||||
}
|
||||
tree = optim(tree);
|
||||
if (tree->op == op)
|
||||
goto ins;
|
||||
if (!isfloat(tree)) {
|
||||
/* c1*(x+c2) -> c1*x+c1*c2 */
|
||||
if ((tree->op==TIMES||tree->op==LSHIFT)
|
||||
&& tree->tr2->op==CON && tree->tr2->value>0
|
||||
&& tree->tr1->op==PLUS && tree->tr1->tr2->op==CON) {
|
||||
d = tree->tr2->value;
|
||||
if (tree->op==TIMES)
|
||||
tree->tr2->value =* tree->tr1->tr2->value;
|
||||
else
|
||||
tree->tr2->value = tree->tr1->tr2->value << d;
|
||||
tree->tr1->tr2->value = d;
|
||||
tree->tr1->op = tree->op;
|
||||
tree->op = PLUS;
|
||||
if (op==PLUS)
|
||||
goto ins;
|
||||
}
|
||||
}
|
||||
d = degree(tree);
|
||||
for (i=0; i<list->nextl; i++) {
|
||||
if ((d1=degree(list->llist[i]))<d) {
|
||||
t = list->llist[i];
|
||||
list->llist[i] = tree;
|
||||
tree = t;
|
||||
d = d1;
|
||||
}
|
||||
}
|
||||
list->llist[list->nextl++] = tree;
|
||||
}
|
||||
|
||||
block(an, args)
|
||||
{
|
||||
register int *p;
|
||||
int *oldp;
|
||||
register *argp, n;
|
||||
|
||||
oldp = p = spacep;
|
||||
n = an+3;
|
||||
argp = &args;
|
||||
do
|
||||
*p++ = *argp++;
|
||||
while (--n);
|
||||
if (p >= &treespace[ossiz]) {
|
||||
error("Exp. ov. pass 2");
|
||||
exit(1);
|
||||
}
|
||||
spacep = p;
|
||||
return(oldp);
|
||||
}
|
||||
|
||||
islong(t)
|
||||
{
|
||||
if (t==LONG)
|
||||
return(2);
|
||||
return(1);
|
||||
}
|
||||
|
||||
isconstant(at)
|
||||
struct tnode *at;
|
||||
{
|
||||
register struct tnode *t;
|
||||
|
||||
t = at;
|
||||
if (t->op==CON || t->op==SFCON)
|
||||
return(t);
|
||||
if (t->op==ITOL && t->tr1->op==CON)
|
||||
return(t->tr1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
hardlongs(at)
|
||||
struct tnode *at;
|
||||
{
|
||||
register struct tnode *t;
|
||||
|
||||
t = at;
|
||||
switch(t->op) {
|
||||
|
||||
case TIMES:
|
||||
case DIVIDE:
|
||||
case MOD:
|
||||
t->op =+ LTIMES-TIMES;
|
||||
break;
|
||||
|
||||
case ASTIMES:
|
||||
case ASDIV:
|
||||
case ASMOD:
|
||||
t->op =+ LASTIMES-ASTIMES;
|
||||
t->tr1 = block(1, AMPER, LONG+PTR, 0, t->tr1);
|
||||
break;
|
||||
|
||||
default:
|
||||
return(t);
|
||||
}
|
||||
return(optim(t));
|
||||
}
|
||||
Reference in New Issue
Block a user