/* CCREG.C - Register management ** ** (c) Copyright Ken Harrenstien 1989 ** All changes after v.45, 6-Apr-1988 ** (c) Copyright Ken Harrenstien, SRI International 1985, 1986 ** All changes after v.26, 8-Aug-1985 ** ** Original version by David Eppstein / Stanford University / 8 Mar 1985 */ #include /* calloc() */ #include "cc.h" #include "ccgen.h" /* Exported functions */ void vrinit(void); /* Init regs for new routine */ void vrendchk(void); /* Check regs at end of routine */ VREG *vrget(void), *vrdget(void); /* Allocate virtual register or pair */ VREG *vrretget(void), *vrretdget(void); /* Same but use return-value regs */ void vrfree(VREG *); /* Release vreg */ void vrallspill(void); /* Spill all active regs onto stack */ VREG *vrwiden(VREG *reg, int low); /* Widen a vreg into a pair */ void vrlowiden(VREG *); /* Common case: widen vreg in low direction */ void vrnarrow(VREG *); /* Narrow a vreg pair into single vreg */ int vrreal(VREG *); /* Get real reg # for active virtual reg */ int vrtoreal(VREG *); /* Ensure reg is active, return real # */ int vrstoreal(VREG *, VREG *); /* Same for 2 regs, return # of 1st */ int vrispair(VREG *); /* TRUE if vreg is 1st of a vreg pair */ void vrufcreg(VREG *); /* Undo MOVE of failed changereg w/o freeing */ int rfree(int); /* TRUE if real register is assigned */ #if 0 int rhasval(); /* TRUE if real register has a value */ #endif /* Imported functions */ extern PCODE *before(PCODE *); /* CCCODE */ extern void code00(int, int, int), code8(int, VREG *, INT), code12(int, VREG *, INT); /* CCCODE */ extern int ufcreg(int); /* CCCREG */ /* Internal functions */ static void vr1free(VREG *), vrspill(VREG *), vr1spill(VREG *); static int rrfind(void); static void updrfree(void); static int rrdfind(void); static VREG *vrsetrr(VREG *, int), *vr1setrr(VREG *, int); static void vrunlink(VREG *), vr1unlink(VREG *); static VREG *vrlink(VREG *, VREG *), *vr1link(VREG *, VREG *), *vralloc(void), *vrdalloc(void); #if DEBUG_KCC static void vrdumplists (void); static char *vrdumpflags (int); #endif #define empty(vr) ((vr)->Vrnext == (vr)) /* TRUE if list is empty */ /* virtual regs not now in use */ static VREG freelist = {0, 0, (TYPE *)NULL, 0, &freelist, &freelist}; /* regs associated with real regs */ static VREG reglist = {0, 0, (TYPE *)NULL, 0, ®list, ®list}; /* regs spilled onto the stack */ static VREG spillist = {0, 0, (TYPE *)NULL, 0, &spillist, &spillist}; static VREG *regis[NREGS]; /* who is using which registers */ static int regfree[NREGS]; /* what regs are used in code */ /* Special vregs which the macros VR_RETVAL and VR_SP point to. These ** exist only so routines can force the use of certain physical regs in ** special places, by providing the appropriate phys reg value. These ** vregs are never strung on a list or used in any other way. */ VREG vr_retval = { VRF_SPECIAL|VRF_LOCK, R_RETVAL }; VREG vr_sp = { VRF_SPECIAL|VRF_LOCK, R_SP }; #if SYS_CSI /* For FORTRAN linkage */ VREG vr_fap = { VRF_SPECIAL|VRF_LOCK, R_FAP }; VREG vr_zero = { VRF_SPECIAL|VRF_LOCK, R_ZERO }; #endif /* ** VRINIT - Initialize for start of new code ** Called at the start of each function or code initializer by inicode() ** VRENDCHK - Perform wrap-up checks at end of code. ** Called at end of each function or initializer by gend(). */ void vrinit(void) { int i; #if DEBUG_KCC puts ("vrinit ()"); #endif vrendchk(); for (i = 0; i < NREGS; i++) regis[i] = NULL; } void vrendchk(void) { #if DEBUG_KCC puts ("vrendchk ()"); #endif if (!empty(®list) || !empty(&spillist)) { int_warn("vrendchk: leftover regs"); /* Try to release all regs */ while (!empty(®list)) { #if DEBUG_KCC printf ("reglist=%d\t", reglist.Vrnext->Vrloc); #endif vrfree(reglist.Vrnext); } while (!empty(&spillist)) { #if DEBUG_KCC printf ("spillist=%d\t", spillist.Vrnext->Vrloc); #endif vrfree(spillist.Vrnext); } } } /* VRGET - Assign a new virtual register with corresponding real register. */ VREG * vrget(void) { #if DEBUG_KCC puts ("vrget ()"); #endif return vr1link(vr1setrr(vralloc(), rrfind()), ®list); } /* VRDGET - Same as VRGET but assigns a double-word register. */ VREG * vrdget(void) { #if DEBUG_KCC puts ("vrdget ()"); #endif return vrlink(vrsetrr(vrdalloc(), rrdfind()), ®list); } /* VRRETGET - Get a register for holding a return value */ VREG * vrretget(void) { #if DEBUG_KCC puts ("vrretget ()"); #endif if (regis[R_RETVAL] != NULL) /* Ensure return reg is free */ vrspill(regis[R_RETVAL]); return vr1link(vr1setrr(vralloc(), R_RETVAL), ®list); } /* VRRETDGET - Get a double register for holding return value */ VREG * vrretdget(void) { #if DEBUG_KCC puts ("vrretdget ()"); #endif if (regis[R_RETVAL] != NULL) vrspill(regis[R_RETVAL]); if (regis[R_RETDBL] != NULL) vrspill(regis[R_RETDBL]); return vrlink(vrsetrr(vrdalloc(), R_RETVAL), ®list); } /* VRFREE - Forget about a no-longer-in-use register ** */ void vrfree(VREG *vr) { #if DEBUG_KCC printf ("vrfree (%%%o)\n", vr); #endif if (vr->Vrflags & VRF_REGPAIR) /* If 1st of a pair, */ vr1free(vr->Vrmate); /* free 2nd first */ vr1free(vr); } static void vr1free(VREG *vr) { #if DEBUG_KCC printf ("vr1free (%%%o)\n", vr); #endif if (vr->Vrflags & VRF_SPECIAL) return; if (vr->Vrflags & VRF_SPILLED) int_warn("vr1free: spilled reg"); else regis[vr->Vrloc] = NULL; /* Say real reg now free */ vr1unlink(vr); /* Unlink reg(s), move to freelist */ vr1link(vr, &freelist); /* No need to clear flags as vralloc() will do this. */ } /* VRALLSPILL - Spill all registers ** This is needed to save values over subr calls and conditional exprs. */ void vrallspill(void) { #if DEBUG_KCC puts ("vrallspill ()"); #endif while (!empty(®list)) vrspill(reglist.Vrnext); } /* VRSPILL - Spill a virtual register. ** Either we needed to reallocate it or we are calling a function. ** In either case the register moves onto the stack. */ static void vrspill(VREG *vr) { #if DEBUG_KCC printf ("vrspill (%%%o)\n", vr); #endif vr1spill(vr); /* Must ALWAYS push 1st reg first!!!! */ if (vr->Vrflags & VRF_REGPAIR) vr1spill(vr->Vrmate); /* then 2nd if a pair */ } static void vr1spill(VREG *vr) { #if DEBUG_KCC printf ("vr1spill (%%%o)\n", vr); #endif if (vr->Vrflags & VRF_SPILLED) efatal("vr1spill: reg already spilled"); vr1unlink(vr); /* remove from assigned list */ if (Register_Nopreserve(vr->Vrloc) || XF4_call_spill) { spillist.Vrnext->Vroldstk = stackoffset;/* remember where we are */ #if DEBUG_KCC printf (">>> calling code00 ();\n"); #endif code00(P_PUSH, R_SP, vr->Vrloc); /* push on stack, don't release */ #if DEBUG_KCC printf (">>> returned from code00 ();\n"); #endif regis[vr->Vrloc] = NULL; /* no longer here */ vr->Vrloc = (int) ++stackoffset; /* Stack bigger now, note new loc */ vr->Vrflags |= VRF_SPILLED; vr1link(vr, &spillist); /* it's now spilled */ } } /* VRWIDEN - Make single register into a register pair and returns that. ** If "low" argument non-zero, register becomes the low word. ** Contents of additional word are indeterminate. */ VREG * vrwiden(VREG *reg, int low) /* Old existing register */ { VREG *nreg; /* New added register */ VREG *vr1, *vr2; /* 1st and 2nd regs of pair */ int rr; #if DEBUG_KCC printf ("vrwiden (%%%o, %s)\n", reg, (low ? "TRUE" : "FALSE")); #endif if (reg->Vrflags & (VRF_REGPAIR|VRF_REG2ND)) { efatal("vrwiden: reg already wide"); return reg; } /* Turn a single vreg into a vreg pair */ reg->Vrmate = nreg = vralloc(); /* Get another vreg to make a pair */ nreg->Vrmate = reg; /* Link them together */ vr1link(nreg, reg); /* Add new to same list after old */ if (low) { vr1 = nreg, vr2 = reg; vr1->Vrloc = reg->Vrloc-1; } else { vr1 = reg, vr2 = nreg; vr2->Vrloc = reg->Vrloc+1; } vr1->Vrflags |= VRF_REGPAIR; vr2->Vrflags |= VRF_REG2ND; if (reg->Vrflags & VRF_SPILLED) { /* On stack, don't need to find reg */ nreg->Vrflags |= VRF_SPILLED; /* Pretend new reg also spilled */ nreg->Vroldstk = reg->Vroldstk; /* Preserve this just in case */ return vr1; /* (note reg not really on stk!) */ } /* Existing reg is in a real reg, see if neighbor is free */ if (regis[nreg->Vrloc] == NULL /* New reg available? */ && vr1->Vrloc >= R_RETVAL /* And pair is within range of */ && vr2->Vrloc <= r_maxnopreserve) /* useable registers? FW 2A(47) */ { regis[nreg->Vrloc] = nreg; /* Win! Take the new reg */ return vr1; /* and return */ } /* Can't use neighboring real reg, find another pair of real regs. ** We lock old reg while hunting to avoid unpleasant surprises. */ if (reg->Vrflags & VRF_LOCK) { int_warn("vrwiden: virtual register with rr=%d locked\n", reg->Vrloc); rr = rrdfind(); } else { reg->Vrflags |= VRF_LOCK; rr = rrdfind(); reg->Vrflags &= ~VRF_LOCK; } #if DEBUG_KCC printf (">>> calling code00 ();\n"); #endif code00(P_MOVE, (low ? rr+1 : rr), reg->Vrloc); /* Copy old reg */ #if DEBUG_KCC printf (">>> returned from code00 ();\n"); #endif regis[reg->Vrloc] = NULL; /* Free old real reg, and */ return vrsetrr(vr1, rr); /* set up new ones instead */ } /* VRLOWIDEN - Widen a single virtual reg in low direction. ** No return value is needed since the vreg pointer doesn't change. */ void vrlowiden(VREG *vr) { #if DEBUG_KCC printf ("vrlowiden (%%%o)\n", vr); #endif (void) vrwiden(vr, 0); /* Widen, existing word becomes 1st */ } /* VRNARROW - Extract one word of a doubleword register ** The pointer furnished as arg must point to the 1st or 2nd reg of ** the pair, and that one is retained while the other is flushed. */ void vrnarrow(VREG *vr) { #if DEBUG_KCC printf ("vrnarrow (%%%o)\n", vr); #endif if (vr->Vrflags & (VRF_REGPAIR|VRF_REG2ND)) { /* Flush flags and ensure that vr1free doesn't complain if ** the vreg happens to be spilled at moment. */ vr->Vrflags &= ~(VRF_REGPAIR|VRF_REG2ND|VRF_SPILLED); vr1free(vr->Vrmate); /* Flush other reg */ } else efatal("vrnarrow: already narrow"); } /* VRREAL - return real (physical) register # for an active virtual reg. ** If reg is not active (is on stack) then generates internal error, ** but tries to recover by getting it anyway. */ int vrreal(VREG *vr) { #if DEBUG_KCC printf ("vrreal (%%%o)\n", vr); #endif if (!(vr->Vrflags & VRF_SPILLED)) return vr->Vrloc; int_error("vrreal: using spilled reg"); return vrtoreal(vr); } /* VRTOREAL - Return a physical register number for some virtual register ** Pulls it back off the stack if necessary ** ** FW, 2A(41) : now it may happen, e.g. in a comparison operation involving ** two doubles, that vrtoreal () is called from one of the code* () routines, ** and its argument is the _second_half_ of a double virtreg that is on the ** spilled list. Formerly, this case was handled poorly; the second half ** would be unspilled, but the first half would remain spilled, and the ** lists would get out of sync, causing a failure later on, typically from ** rrdfind (). The appropriate action is to unspill the double and return ** the realreg for its second half. */ int vrtoreal (VREG *reg) { #if DEBUG_KCC printf ("vrtoreal (%%%o)\n", reg); #endif /* Check for spilled register now somewhere on stack */ if (reg->Vrflags & VRF_SPILLED) { int stkloc; VREG *vr; /* Unspill. First check for the second-half case, FW 2A(41) */ vr = (reg->Vrflags & VRF_REG2ND) ? reg->Vrmate : reg; /* FW 2A(41) */ vr->Vrflags &= ~VRF_SPILLED; vrunlink (vr); /* Unlink from spill list */ stkloc = vr->Vrloc; /* Note location on stack */ if (vr->Vrflags & VRF_REGPAIR) { vr->Vrmate->Vrflags &= ~VRF_SPILLED; vrsetrr (vr, rrdfind()); code12 (P_DMOVE, vr, stkloc - stackoffset); } else { vr1setrr (vr, rrfind()); code12 (P_MOVE, vr, stkloc - stackoffset); } /* drop stack to top remaining spilled reg */ if (vr->Vrnext == spillist.Vrnext) { code8 (P_ADJSP, VR_SP, spillist.Vrnext->Vroldstk - stackoffset); stackoffset = spillist.Vrnext->Vroldstk; } vrlink(vr, ®list); } /* * In a realreg now no matter what, so just return it. * This works whether the given reg was a single or either half * of a double, FW 2A(41) */ return reg->Vrloc; } /* VRSTOREAL - Same as vrtoreal but for two registers at once. ** This ensures that we don't mistakenly spill one of the regs that ** a two-reg instruction needs. */ int vrstoreal(VREG *vr, VREG *vr2) { #if DEBUG_KCC printf ("vrstoreal (%%%o, %%%o)\n", vr, vr2); #endif if (vr->Vrflags & VRF_LOCK) /* If 1st reg already locked, */ { (void) vrtoreal(vr2); /* use fast method that avoids */ return vr->Vrloc; /* unlocking the 1st reg when done. */ } 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