📄 cccreg.c
字号:
** This is the other helper routine for changereg(). It takes the
** same args as creg(), but it merely makes sure the register change
** will not change the given instruction before calling changereg()
** on the instruction before that one.
**
** This is mutually recursive with creg().
*/
static int
cregbefore(to, from, p, dguard, dstart)
PCODE *p, *dguard, *dstart;
{
if (to == from) return 1; /* already right */
#if 1
if (uptolab && uptolab == jumplab(p)) /* Moving past boundary? */
return crossfence(to, from, p,dguard,dstart); /* Yeah, stop. */
#endif
if ((from == R_RETVAL) && dropsout(p)) /* return uses AC1 */
return 0;
switch (p->Ptype & PTF_ADRMODE) {
case PTA_REGIS: /* careful of dblwords */
if (p->Pop == P_POP) { /* only mem change used as PTA_REGIS */
if (p->Pr2 == to) return 0; /* conflict, lose */
else if (p->Pr2 == from) { /* set of reg to change from */
if (dguard != NULL) return 0; /* wrong reg val */
p->Pr2 = to; /* make it what we want */
return 1; /* win */
}
}
switch (rchange (p->Pop)) {
case PRC_RSAME: case PRC_RSET: case PRC_RCHG:
case PRC_DSET_RSAME: case PRC_DCHG_RSAME:
break; /* mem is single word, normal case */
case PRC_RCHG_DSAME: case PRC_DSAME:
case PRC_DSET: case PRC_DCHG: /* can't deal with doublewords */
if (p->Pr2 != from && p->Pr2 != from - 1 &&
p->Pr2 != to && p->Pr2 != to - 1) break; /* safe, go on */
default: /* else fall through to loserville */
return 0;
} /* break falls into standard reg chk */
if (p->Pr2 == to) return 0; /* conflict, lose */
if (p->Pr2 == from) { /* need to change index */
if (!creg(to, from, before(p), dguard, dstart)) return 0;
p->Pr2 = to; /* Change it */
return 1; /* and return success */
}
break; /* otherwise check prev instr */
case PTA_MINDEXED:
case PTA_BYTEPOINT:
if (p->Pindex == to) return 0; /* conflict, lose */
if (p->Pindex == from) { /* need to change index */
if (!creg(to, from, before(p), dguard, dstart)) return 0;
p->Pindex = to; /* Change it */
return 1; /* and return success */
}
break; /* otherwise check prev instr */
case PTA_RCONST: /* no cared-about regs used */
case PTA_ONEREG:
case PTA_PCONST:
case PTA_FCONST:
case PTA_DCONST:
case PTA_DCONST1:
case PTA_DCONST2:
break; /* Don't need addr, just back up */
default:
int_error("cregbefore: bad Ptype");
return 0;
}
p = before (p); /* back up */
return creg (to, from, p, dguard, dstart); /* tail-recurse */
}
/*
** Change register for P_ADDI R,1
** Called by changereg() for PRC_RCHG when recursive change fails.
**
** We know that p->Preg == from, but little else.
*/
static int
craddhack(to, from, p)
PCODE *p;
{
if (p->Ptype != PTV_IMMED || p->Pvalue != 1) return 0; /* pretest failed */
switch (p->Pop) { /* is opI R,1; see if P_ADDI or P_SUBI */
case P_ADD:
p->Pop = P_AOS; /* P_ADDI R,1 */
break; /* becomes P_AOS S,R */
case P_SUB:
p->Pop = P_SOS; /* similarly for P_SUBI */
break;
default: /* something else */
return 0; /* we can't handle it */
}
/* Here if was P_ADDI R,1 or P_SUBI R,1. Finish the transformation. */
p->Ptype = PTA_REGIS; /* make a reg-reg P_AOS */
p->Preg = to; /* into new register */
p->Pr2 = from; /* from old register */
return 1; /* return success */
}
/* Register information routines.
** An instruction may do only ONE of these things to a specific register:
** Name R/W Test Action
** - 0/0 ~(R|W) Nothing -- not used in any way
** REF: 1/0 R & ~W Reg value is used, but remains same.
** SET: 0/1 ~R & W Reg is set; any old value is ignored.
** MOD: 1/1 R & W Reg value is used and modified.
**
** The following combined cases can be checked for:
** USE: (REF+MOD) R Reg value is used; MAY be changed.
** CHG: (SET+MOD) W Reg value is changed; old value MAY be used.
** IN: (all) R | W Reg is used or changed by instr.
** - (REF+SET) R ^ W Reg is read, or set, but not both.
*/
static int rvread, rvwrit; /* Static for speed */
#if 0 /* 5/91 KCC size */
/*
** RBREF, RBSET, RBMOD, RBUSE, RBCHG
** RREF, RSET, RMOD, RUSE, RCHG
*/
int rbref(p) PCODE *p; { rvsset(p); return rvread & ~rvwrit; }
int rbset(p) PCODE *p; { rvsset(p); return rvwrit & ~rvread; }
int rbmod(p) PCODE *p; { rvsset(p); return rvread & rvwrit; }
int rbuse(p) PCODE *p; { rvsset(p); return rvread; }
int rbchg(p) PCODE *p; { rvsset(p); return rvwrit; }
int rbin (p) PCODE *p; { rvsset(p); return rvread | rvwrit; }
#endif
static void
rvsset(p)
PCODE *p;
{
static int r; /* Avoid stack fiddling, for speed */
rvread = rvwrit = 0;
/* First see how op deals with the Preg */
switch (rchange(p->Pop)) {
/* Single register */
case PRC_RSAME: rvread = rbits[p->Preg]; break; /* Refed */
case PRC_RSET_DSAME:
case PRC_RSET: rvwrit = rbits[p->Preg]; break; /* Set */
case PRC_RCHG_DSAME:
case PRC_RCHG: rvread = rvwrit = rbits[p->Preg];break; /* Modified */
/* Double register */
case PRC_DSAME: rvread = drbits[p->Preg]; break; /* Refed */
case PRC_DSET_RSAME:
case PRC_DSET: rvwrit = drbits[p->Preg]; break; /* Set */
case PRC_DCHG_RSAME:
case PRC_DCHG: rvread = rvwrit = drbits[p->Preg];break; /* Modified */
case PRC_UNKNOWN:
if (p->Pop == P_PUSHJ) { /* If PUSHJ, can do a little */
rvread = rbits[p->Preg]; /* Refs the stack register */
rvwrit = ~rvread; /* Sets all but stack reg */
} else /* If completely unknown, */
rvread = rvwrit = ~0; /* must assume everything! */
break;
default:
int_error("rbitset: bad rchange");
}
/* Now see if reg is used in address or as memory operand. */
switch (p->Ptype & PTF_ADRMODE) {
case PTA_REGIS: /* register to register */
r = p->Pr2; /* R used as E */
if (p->Pop == P_DPB) { /* Check special case of DPB x,R */
rvread |= rbits[r]; /* which doesn't change R */
return;
}
break; /* Drop out to check for mem change */
case PTA_MINDEXED: /* addr+offset(index) */
case PTA_BYTEPOINT: /* [bsize,,addr+offset(index)] */
if (p->Pindex) /* R used as index reg? */
rvread |= rbits[p->Pindex];
else if (!p->Pptr /* No index, is R in E? */
&& p->Poffset >= 0 /* Check for R used as E */
&& p->Poffset < NREGS) { /* (see rbinaddr() for more comment) */
r = (int) p->Poffset;
break; /* Drop out to check for mem change */
}
return;
default:
int_error("rbitset: bad adrmode");
case PTA_RCONST: /* Simple integer in pvalue */
case PTA_ONEREG: /* no address, just register */
case PTA_PCONST: /* [<pointer of addr+offset+bsize>] */
case PTA_FCONST: /* [float] */
case PTA_DCONST: /* [double] */
case PTA_DCONST1:
case PTA_DCONST2:
return;
}
/* If we come here, the instruction's memory operand was a register,
** identified by "r".
** Check further to see if this memory operand is changed or not.
** Currently we can't distinguish between setting and modifying.
**
** Note that the only instr we use which can change two words in memory
** is DMOVEM (DMOVNM is not used). We shouldn't ever see a DMOVEM r,E
** where E is a register address, but just in case, we check anyway.
**
** One special case exists (DPB x,R) where the flag testing here is
** too general; this is caught by the PTA_REGIS check in previous switch.
*/
switch (rchange(p->Pop)) {
case PRC_RSET_DSAME:
case PRC_RCHG_DSAME:
case PRC_DSET:
case PRC_DCHG:
rvread |= drbits[r]; /* Double-word mem read operand */
break;
default:
rvread |= rbits[r]; /* Single-word mem read operand */
}
if ((popflg[p->Pop & POF_OPCODE] & PF_MEMCHG) /* If op changes mem */
|| (p->Pop & POF_BOTH)) { /* or BOTH flag set, */
/* Register is munged as memory operand. */
rvwrit |= ((p->Pop & POF_OPCODE) == P_DMOVEM) ? drbits[r] : rbits[r];
}
}
/* Slightly faster versions of RBIN when not everything is needed
**
** RBINCODE(p) Mask of registers used by this pcode instruction.
** RBINREG(p) Mask of registers used as reg.
** RBINADDR(p) Mask of registers used in addr.
*/
int
rbincode(p)
PCODE *p;
{ return rbinreg(p) | rbinaddr(p);
}
int
rbinreg(p)
PCODE *p;
{
switch (rchange(p->Pop)) {
case PRC_RSAME: /* nice single word op? */
case PRC_RSET:
case PRC_RCHG:
case PRC_RCHG_DSAME:
return rbits[p->Preg];
case PRC_DSAME: /* nasty double word op? */
case PRC_DSET:
case PRC_DCHG:
case PRC_DSET_RSAME:
case PRC_DCHG_RSAME:
return drbits[p->Preg];
default:
int_error("rbinreg: bad rchange");
/* Drop thru */
case PRC_UNKNOWN: /* PUSHJ */
return -1; /* Assume all regs affected! */
}
}
/* RBINMEM - Internal rtn to get reg mask when R is used as E.
** See whether instruction uses double-word mem operand
*/
static int
rbinmem(p, r)
PCODE *p;
int r;
{
switch (rchange(p->Pop)) {
case PRC_RSAME: /* nice single word op? */
case PRC_RSET:
case PRC_RCHG:
case PRC_DSET_RSAME:
case PRC_DCHG_RSAME:
return rbits[r];
case PRC_RCHG_DSAME:
case PRC_DSAME:
case PRC_DSET:
case PRC_DCHG:
return drbits[r];
default:
int_error("rbinmem: bad rchange");
/* Drop thru */
case PRC_UNKNOWN: /* PUSHJ */
return -1; /* Assume all regs affected! */
}
}
int
rbinaddr(p)
register PCODE *p;
{
switch (p->Ptype & PTF_ADRMODE) {
case PTA_REGIS: /* register to register */
return rbinmem(p, p->Pr2); /* R used as E */
case PTA_MINDEXED: /* addr+offset(index) */
case PTA_BYTEPOINT: /* [bsize,,addr+offset(index)] */
if (p->Pindex) /* R used as index reg? */
return rbits[p->Pindex];
/* No index, check for R used as E. This is illegal for PTA_MINDEXED
** and should almost never be seen for PTA_BYTEPOINT. The only
** exception is when extracting a bitfield from a function-returned
** structure -- see the code for Q_DOT in CCGEN2's gprimary().
*/
if (!p->Pptr /* No index, is R in E? */
&& p->Poffset >= 0 /* Check for R used as E (semi-illegal) */
&& p->Poffset < NREGS)
return rbinmem(p, (int) p->Poffset);
/* Drop thru to return 0 */
case PTA_RCONST: /* Simple integer in pvalue */
case PTA_ONEREG: /* no address, just register */
case PTA_PCONST: /* [<pointer of addr+offset+bsize>] */
case PTA_FCONST: /* [float] */
case PTA_DCONST: /* [double] */
case PTA_DCONST1:
case PTA_DCONST2:
return 0;
default:
int_error("rbinaddr: bad adrmode");
return -1;
}
}
/* RRxxx(p, r) routines - same as RBxxx(p) but take a
** register number in "r" and return TRUE if that register matches
** one in the mask that RBxxx(p) would return.
*/
int rruse(p,r) PCODE *p; { rvsset(p); return (rvread) & rbits[r]; }
int rrchg(p,r) PCODE *p; { rvsset(p); return (rvwrit) & rbits[r]; }
#if 0 /* 5/91 KCC size */
int rrref(p,r) PCODE *p; { rvsset(p); return (rvread & ~rvwrit) & rbits[r]; }
int rrset(p,r) PCODE *p; { rvsset(p); return (rvwrit & ~rvread) & rbits[r]; }
int rrmod(p,r) PCODE *p; { rvsset(p); return (rvread & rvwrit) & rbits[r]; }
int rrin (p,r) PCODE *p; { rvsset(p); return (rvread | rvwrit) & rbits[r]; }
#endif
/* RINCODE(p, reg) - returns TRUE if register "reg" is used in any way
** by the specified pseudo-op.
*/
rincode(p, reg)
PCODE *p;
int reg;
{
return rinreg(p, reg) || rinaddr(p, reg);
}
/* RINADDR(p, reg) - returns TRUE if register "reg" is used in
** the address of the specified pseudo-op.
*/
int
rinaddr(p, reg)
PCODE *p;
int reg;
{
return rbinaddr(p) & rbits[reg];
}
/* RINREG(p, reg) - returns non-zero value if register "reg" is used as
** a register by the specified pseudo-op.
** This value is:
** 0 - known not to be used.
** 1 - known used, single-word op.
** 2 - known used, double-word op.
** 3 - known used, as 2nd register of double-reg op.
** 4 - Assumed used, but not sure how.
**
** Note that the default if the code can't figure something out
** is to assume the register WAS used. Anything that calls rinreg must
** double-check the instruction before assuming that it is a simple thing
** like OP R,x.
*/
int
rinreg(p, reg)
PCODE *p;
int reg;
{
switch (rchange(p->Pop)) {
case PRC_RSAME: /* nice single word op? */
case PRC_RSET:
case PRC_RCHG:
case PRC_RCHG_DSAME:
if (p->Preg == reg) /* The one we want? */
return 1; /* Say single-word op */
break;
case PRC_DSAME: /* nasty double word op? */
case PRC_DSET:
case PRC_DCHG:
case PRC_DSET_RSAME:
case PRC_DCHG_RSAME:
if (p->Preg == reg)
return 2; /* DOP R,x */
if (p->Preg+1 == reg)
return 3; /* DOP R-1, x */
break;
default:
int_error("rinreg: bad rchange");
case PRC_UNKNOWN: /* PUSHJ */
return 4; /* Assume it was used, somehow. */
}
return 0; /* Not used at all */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -