/*
* prepass to move things around
* does nothing, but tries to make
* the actual scheduler work better
*/
for(s=sch; s<=se; s++) {
if(!(s->p.mark & LOAD))
continue;
/* always good to put nonconflict loads together */
for(t=s+1; t<=se; t++) {
if(!(t->p.mark & LOAD))
continue;
if(t->p.mark & BRANCH)
break;
if(conflict(s, t))
break;
for(u=t-1; u>s; u--)
if(depend(u, t))
goto no11;
u = s+1;
stmp = *t;
memmove(s+2, u, (uchar*)t - (uchar*)u);
*u = stmp;
break;
}
no11:
ar = 0; /* dest is really reference */
ad = 0; /* source/dest is really address */
ld = 0; /* opcode is load instruction */
sz = 20; /* size of load/store for overlap computation */
/*
* flags based on opcode
*/
switch(p->as) {
case ATEXT:
curtext = realp;
autosize = p->to.offset + 4;
ad = 1;
break;
case ABL:
c = p->reg;
if(c == NREG)
c = REGLINK;
s->set.ireg |= 1<<c;
ar = 1;
ad = 1;
break;
case ACMP:
case ACMPF:
case ACMPD:
ar = 1;
s->set.cc |= E_PSR;
p->mark |= FCMP;
break;
case AB:
ar = 1;
ad = 1;
break;
case AMOVB:
case AMOVBU:
sz = 1;
ld = 1;
break;
case AMOVH:
case AMOVHU:
sz = 2;
ld = 1;
break;
case AMOVF:
case AMOVW:
sz = 4;
ld = 1;
break;
case AMOVD:
sz = 8;
ld = 1;
break;
case ADIV:
case ADIVU:
case AMUL:
case AMULU:
case AMOD:
case AMODU:
case AADD:
case AAND:
case ANOR:
case AORR:
case ASLL:
case ASRA:
case ASRL:
case AROR:
case ASUB:
case AEOR:
case AADDD:
case AADDF:
case ASUBD:
case ASUBF:
case AMULF:
case AMULD:
case ADIVF:
if(p->reg == NREG) {
if(p->to.type == D_REG || p->to.type == D_FREG)
p->reg = p->to.reg;
if(p->reg == NREG)
print("botch %P\n", p);
}
break;
}
/*
* flags based on 'to' field
*/
c = p->to.class;
if(c == 0) {
c = aclass(&p->to) + 1;
p->to.class = c;
}
c--;
switch(c) {
default:
print("unknown class %d %D\n", c, &p->to);
case C_ZCON:
case C_ICON:
case C_SCON:
case C_SICON:
case C_LCON:
case C_NONE:
case C_SBRA:
case C_LBRA:
break;
case C_PSR:
s->set.cc |= E_PSR;
break;
case C_ZOREG:
case C_SOREG:
case C_LOREG:
c = p->to.reg;
s->used.ireg |= 1<<c;
if(ad)
break;
s->size = sz;
s->offset = regoff(&p->to);
m = ANYMEM;
if(c == REGSB)
m = E_MEMSB;
if(c == REGSP)
m = E_MEMSP;
if(ar)
s->used.cc |= m;
else
s->set.cc |= m;
break;
case C_SACON:
case C_LACON:
s->used.ireg |= 1<<REGSP;
break;
case C_SECON:
case C_LECON:
s->used.ireg |= 1<<REGSB;
break;
case C_REG:
if(ar)
s->used.ireg |= 1<<p->to.reg;
else
s->set.ireg |= 1<<p->to.reg;
break;
case C_REGREG:
if(ar){
s->used.ireg |= 1<<p->to.reg;
s->used.ireg |= 1<<p->to.offset;
}else{
s->set.ireg |= 1<<p->to.reg;
s->set.ireg |= 1<<p->to.offset;
}
break;
case C_FREG:
/* do better -- determine double prec */
if(ar) {
s->used.freg |= 1<<p->to.reg;
s->used.freg |= 1<<(p->to.reg|1);
} else {
s->set.freg |= 1<<p->to.reg;
s->set.freg |= 1<<(p->to.reg|1);
}
if(ld && p->from.type == D_REG)
p->mark |= LOAD;
break;
case C_SAUTO:
case C_LAUTO:
s->used.ireg |= 1<<REGSP;
if(ad)
break;
s->size = sz;
s->offset = regoff(&p->to);
/*
* flags based on 'from' field
*/
c = p->from.class;
if(c == 0) {
c = aclass(&p->from) + 1;
p->from.class = c;
}
c--;
switch(c) {
default:
print("unknown class %d %D\n", c, &p->from);
case C_ZCON:
case C_ICON:
case C_SCON:
case C_SICON:
case C_LCON:
case C_NONE:
case C_SBRA:
case C_LBRA:
break;
case C_PSR:
s->used.cc |= E_PSR;
break;
case C_ZOREG:
case C_SOREG:
case C_LOREG:
c = p->from.reg;
s->used.ireg |= 1<<c;
if(ld)
p->mark |= LOAD;
s->size = sz;
s->offset = regoff(&p->from);
m = ANYMEM;
if(c == REGSB)
m = E_MEMSB;
if(c == REGSP)
m = E_MEMSP;
s->used.cc |= m;
break;
case C_SACON:
case C_LACON:
s->used.ireg |= 1<<REGSP;
break;
case C_SECON:
case C_LECON:
s->used.ireg |= 1<<REGSB;
break;
case C_REG:
s->used.ireg |= 1<<p->from.reg;
break;
case C_REGREG:
s->used.ireg |= 1<<p->from.reg;
s->used.ireg |= 1<<p->from.offset;
break;
case C_FREG:
/* do better -- determine double prec */
s->used.freg |= 1<<p->from.reg;
s->used.freg |= 1<<(p->from.reg|1);
if(ld && p->to.type == D_REG)
p->mark |= LOAD;
break;
case C_SAUTO:
case C_LAUTO:
s->used.ireg |= 1<<REGSP;
if(ld)
p->mark |= LOAD;
if(ad)
break;
s->size = sz;
s->offset = regoff(&p->from);
/*
* special case.
* loads from same address cannot pass.
* this is for hardware fifo's and the like
*/
if(sa->used.cc & sb->used.cc & E_MEM)
if(sa->p.reg == sb->p.reg)
if(regoff(&sa->p.from) == regoff(&sb->p.from))
return 1;
x = (sa->set.cc & (sb->set.cc|sb->used.cc)) |
(sb->set.cc & sa->used.cc);
if(x) {
/*
* allow SB and SP to pass each other.
* allow SB to pass SB iff doffsets are ok
* anything else conflicts
*/
if(x != E_MEMSP && x != E_MEMSB)
return 1;
x = sa->set.cc | sb->set.cc |
sa->used.cc | sb->used.cc;
if(x & E_MEM)
return 1;
if(offoverlap(sa, sb))
return 1;
}