📄 ccreg.c
字号:
if (vr->Vrflags & VRF_SPILLED) /* Nope, so ensure 1st reg active */
(void) vrtoreal(vr);
vr->Vrflags |= VRF_LOCK; /* Lock it to that phys reg, */
(void) vrtoreal(vr2); /* while we ensure 2nd active too! */
vr->Vrflags &= ~VRF_LOCK; /* OK, can unlock 1st now */
return vr->Vrloc;
}
/* VRISPAIR - Return true if virtual register is a doubleword pair
*/
int
vrispair(VREG *reg)
{
#if DEBUG_KCC
printf ("vrispair (%%%o)\n", reg);
#endif
return (reg->Vrflags & VRF_REGPAIR) != 0;
}
/* VRUFCREG - Vreg version of ufcreg().
** If changereg() fails to change a reg (S) to the desired # (R), it
** emits a MOVE R,S. Often the code generator later realizes the exact
** # didn't matter and so the MOVE to R can be flushed; this routine does
** exactly that for a virtual reg by updating it to reflect the new
** real reg it's associated with (S) once the MOVE is flushed.
**
** Currently only used by switch case jump generation to avoid
** lossage that would ensue from CCCODE's calls to ufcreg.
*/
void
vrufcreg(VREG *vr)
{
#if DEBUG_KCC
printf ("vrufcreg (%%%o)\n", vr);
#endif
regis[vrtoreal(vr)] = NULL; /* Swap in, deassign it */
regis[vr->Vrloc = ufcreg(vr->Vrloc)] = vr; /*Maybe flush MOVE; reassign*/
}
/* RFREE - True if real register is NOT assigned to a virtual reg.
** A function is necessary because the outside world can't see regis[]
*/
int
rfree(int rr)
{
#if DEBUG_KCC
printf ("rfree (%%%o)\n", rr);
#endif
return regis[rr] == NULL;
}
#if 0
/* RHASVAL - True if real reg is still assigned and VRF_HASVAL is set
** indicating it contains a needed value.
**
** This isn't actually used by anything yet.
*/
int
rhasval(rr)
{
return (regis[rr] ? regis[rr]->Vrflags&VRF_HASVAL : 0);
}
#endif
/* From this point, all routines are internal auxiliaries */
/* RRFIND - Find or create an unused real register.
** If none exist, we spill what is likely to be the
** earliest allocated register (since our register allocation
** will tend to act like a stack this is a win).
*/
static int
rrfind (void)
{
VREG *vr;
int r;
#if DEBUG_KCC
puts ("rrfind ()");
#endif
if (r_preserve)
{
r = r_preserve;
r_preserve = 0;
return r;
}
updrfree(); /* update regfree[] to pbuf contents */
for (r = r_minnopreserve; r <= r_maxnopreserve; r++) /* FW 2A(47) */
if (regfree[r])
return r;
for (r = r_minnopreserve; r <= r_maxnopreserve; r++) /* FW 2A(47) */
if (regis[r] == NULL)
return r;
/* All registers in use, have to decide which one to spill to stack.
** The heuristic for this is to use the "oldest" thing on the register
** list (this is the least recently created -- not necessary the least
** recently used -- register)
** This is where VRF_LOCK has its effect of DELAYING regs from being
** spilled. Also, for time being, don't spill 2nd reg of a pair.
*/
for (vr = reglist.Vrprev; vr != ®list; vr = vr->Vrprev)
{
if (!(vr->Vrflags & (VRF_LOCK | VRF_REG2ND)))
{
r = vr->Vrloc; /* Remember phys reg # */
vrspill(vr); /* Spill this reg to stack! */
return r;
}
}
/*extremely rare to fall thru here (never happens in KCC & LIBC sources)*/
efatal("rrfind: no regs, use keyword [register] or simplify expr");
return -1; /* should never get here */
}
/* UPDRFIND - auxiliary for rrfind() and rrdfind().
** Sees which registers are in use in the peephole buffer.
** We try to avoid assigning these so that common subexpression
** elimination will have the greatest opportunity to work.
**
** Since this is merely a heuristic and since it is called intensively,
** we care more about speed than accuracy.
** In particular, we don't even bother looking at the opcode or
** addressing mode of each instruction.
*/
static void
updrfree()
{
int r;
PCODE *p;
#if DEBUG_KCC
puts ("updrfree ()");
#endif
for (r = r_minnopreserve; r <= r_maxnopreserve; r++) /* FW 2A(47) */
regfree[r] = (regis[r] == NULL);
for (p = previous; p != NULL && p->Pop != P_PUSHJ; p = before(p))
regfree[p->Preg] = 0;
}
/* RRDFIND - Find (or create) a real double-register pair, returning the
** # of the first real reg of the pair.
** We have to be careful not to return the very last register.
*/
static int
rrdfind (void)
{
VREG *vr;
VREG *vrok[NREGS];
int i;
int nvrs;
int r;
#if DEBUG_KCC
puts ("rrdfind ()");
#endif
if (r_preserve)
{
r = r_preserve;
r_preserve = 0;
return r;
}
updrfree(); /* update regfree[] to pbuf contents */
for (r = r_minnopreserve; r < r_maxnopreserve; r++) /* FW 2A(47) */
{
if (regfree[r] && regfree[r + 1])
return r;
#if DEBUG_KCC
else
printf ("unable to use %d and %d (not free in regfree[])\n",
r, r + 1);
#endif
}
for (r = r_minnopreserve; r < r_maxnopreserve; r++) /* FW 2A(47) */
{
if ((regis[r] == NULL) && (regis[r + 1] == NULL))
return r;
#if DEBUG_KCC
else
printf ("unable to use %d and %d (not free in regis[])\n",
r, r + 1);
#endif
}
/* None free, scan the reglist in the same way as for rrfind. But
** since we need a pair, we must look for the first virtual reg or
** combination thereof that forms a pair.
** Note that for time being, we avoid spilling just the 2nd reg of a pair.
*/
nvrs = 0;
for (vr = reglist.Vrprev; vr != ®list; vr = vr->Vrprev)
{
if (vr->Vrflags & (VRF_LOCK | VRF_REG2ND)) /* If locked, */
{
#if DEBUG_KCC
printf ("rejecting %d because flags = %%%o\n",
vr->Vrloc, vr->Vrflags);
#endif
continue; /* don't consider it */
}
if (vr->Vrflags & VRF_REGPAIR)
{
r = vr->Vrloc; /* Remember phys reg # */
vrspill(vr); /* Spill this reg to stack! */
return r;
}
/* Not a pair, see if forms pair with anything already seen. */
for (i = 0; i < nvrs; ++i)
{
if (((r = vrok[i]->Vrloc) == (vr->Vrloc + 1))
|| (r == (vr->Vrloc - 1)))
{
if (r > vr->Vrloc) /* get low phys reg # */
r = vr->Vrloc;
vrspill(vr); /* Spill both to stack */
vrspill(vrok[i]);
return r;
}
}
/* Nope, add to array and keep looking. Should never have more
** than NREGS active registers, so array bounds ought to be safe.
*/
vrok[nvrs++] = vr;
}
/* extremely rare to fall thru here (never in KCC & LIBC sources)*/
#if DEBUG_KCC
puts ("entering last-ditch code");
#endif
for (vr = reglist.Vrprev; vr != ®list; vr = vr->Vrprev)
{
if (!vr->Vrflags)
{
if (((vr->Vrloc + 1) <= r_maxnopreserve) /* FW 2A(47) */
&& (regis[vr->Vrloc + 1] == NULL))
{
vrspill(vr);
return r;
}
else if (((vr->Vrloc - 1) >= r_minnopreserve)
&& (regis[vr->Vrloc - 1] == NULL))
{
vrspill(vr);
return (r - 1);
}
}
}
#if DEBUG_KCC /* Only turn on if int_error message below gets printed */
vrdumplists ();
#endif
efatal("rrdfind: no regs, use keyword [register] or simplify expr");
return -1;
}
/* VRSETRR - Set a virtual register's location(s) to be some real reg(s).
** If the vreg is a pair, both are set.
*/
static VREG *
vrsetrr(VREG *vr, int rr)
{
#if DEBUG_KCC
printf ("vrsetrr (%%%o, %%%o)\n", vr, rr);
#endif
if (vr->Vrflags & VRF_REGPAIR)
vr1setrr(vr->Vrmate, rr+1);
return vr1setrr(vr, rr);
}
/* VR1SETRR - Set a virtual register's location to be some real reg
*/
static VREG *
vr1setrr(vr, rr)
VREG *vr;
{
#if DEBUG_KCC
printf ("vr1setrr (%%%o, %%%o)\n", vr, rr);
#endif
return regis[vr->Vrloc = rr] = vr;
}
/* VRUNLINK - Unlink a virtual reg from whatever list it's on.
** If the vreg is a pair, both are unlinked.
*/
static void
vrunlink(vr)
VREG *vr;
{
#if DEBUG_KCC
printf ("vrunlink (%%%o)\n", vr);
#endif
if (vr->Vrflags & VRF_REGPAIR)
vr1unlink(vr->Vrmate);
vr1unlink(vr);
}
/* VR1UNLINK - Remove a register from whatever list it's on.
** This is the first half of changing from one list to another
*/
static void
vr1unlink(reg)
VREG *reg;
{
#if DEBUG_KCC
printf ("vr1unlink (%%%o)\n", reg);
#endif
if (reg->Vrnext == reg)
efatal("vr1unlink: list head");
reg->Vrnext->Vrprev = reg->Vrprev;
reg->Vrprev->Vrnext = reg->Vrnext;
#if DEBUG_KCC
vrdumplists ();
#endif
}
/* VRLINK - Link a register that may be the 1st of a pair; if so, link
** the 2nd reg as well.
*/
static VREG *
vrlink(reg, list)
VREG *reg, *list;
{
#if DEBUG_KCC
printf ("vrlink (%%%o, %%%o)\n", reg, list);
#endif
if (reg->Vrflags & VRF_REGPAIR)
vr1link(reg->Vrmate, list); /* Is pair, link 2nd first */
return vr1link(reg, list);
}
/* VR1LINK - Add a register to a list
** Used when a new vreg is created and when moving between lists
*/
static VREG *
vr1link(reg, list)
VREG *reg, *list;
{
#if DEBUG_KCC
printf ("vr1link (%%%o, %%%o)\n", reg, list);
#endif
reg->Vrnext = list->Vrnext;
list->Vrnext->Vrprev = reg;
reg->Vrprev = list;
list->Vrnext = reg;
#if DEBUG_KCC
vrdumplists ();
#endif
return reg;
}
/* VRALLOC - Allocate a new virtual register structure
** VRDALLOC - Same, but returns 1st of a double register pair, linked together.
*/
static VREG *
vralloc()
{
VREG *rp;
#if DEBUG_KCC
puts ("vralloc ()");
#endif
if (empty(&freelist))
{
rp = (VREG *)calloc(1, sizeof (VREG));
if (rp == NULL)
efatal("Out of memory for virtual registers");
}
else
{
rp = freelist.Vrnext;
vr1unlink(rp);
}
rp->Vrflags = 0;
rp->Vrloc = 0; /* FW 2A(41) */
rp->Vrtype = NULL; /* FW 2A(41) */
rp->Vroldstk = 0; /* FW 2A(41) */
rp->Vrnext = NULL; /* FW 2A(41) */
rp->Vrprev = NULL; /* FW 2A(41) */
rp->Vrmate = NULL; /* FW 2A(41) */
return rp;
}
static VREG *
vrdalloc()
{
VREG *vr1 = vralloc();
VREG *vr2 = vralloc();
#if DEBUG_KCC
puts ("vrdalloc ()");
#endif
vr1->Vrflags |= VRF_REGPAIR;
vr2->Vrflags |= VRF_REG2ND;
vr1->Vrmate = vr2;
vr2->Vrmate = vr1;
return vr1;
}
#if DEBUG_KCC
static void
vrdumplists (void)
{
VREG *vr;
int r;
puts ("\nreglist:");
for (vr = reglist.Vrprev; vr != ®list; vr = vr->Vrprev)
{
printf ("@%%%o, flags: %s, loc: %%%o, typespec: %%%o, mate: %%%o\n",
vr, vrdumpflags (vr->Vrflags), vr->Vrloc,
vr->Vrtype->Tspec, vr->Vrmate);
}
puts ("spillist:");
for (vr = spillist.Vrprev; vr != &spillist; vr = vr->Vrprev)
{
printf ("@%%%o, flags: %s, loc: %%%o, typespec: %%%o, mate: %%%o\n",
vr, vrdumpflags (vr->Vrflags), vr->Vrloc,
vr->Vrtype->Tspec, vr->Vrmate);
}
puts ("freelist:");
for (vr = freelist.Vrprev; vr != &freelist; vr = vr->Vrprev)
{
printf ("@%%%o\n", vr); /* the rest is silence */
}
for (r = r_minnopreserve; r <= r_maxnopreserve; r++) /* FW 2A(47) */
{
printf ("regfree[%d] = %s\tregis[%d] = %%%o\n",
r, (regfree[r] ? "free" : "used"), r, regis[r]);
}
}
static char *
vrdumpflags (int flags)
{
static
char fchars[6];
fchars[0] = flags & VRF_SPILLED ? 'S' : ' ';
fchars[1] = flags & VRF_REGPAIR ? '1' : ' ';
fchars[2] = flags & VRF_REG2ND ? '2' : ' ';
fchars[3] = flags & VRF_LOCK ? 'L' : ' ';
fchars[4] = flags & VRF_SPECIAL ? 'D' : ' ';
fchars[5] = '\0';
return fchars;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -