⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccreg.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	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 <stdlib.h>	/* 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, &reglist, &reglist};

/* 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(&reglist) || !empty(&spillist))
	{
	int_warn("vrendchk: leftover regs");
	/* Try to release all regs */

	while (!empty(&reglist))
	    {
#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()), &reglist);
}

/* VRDGET - Same as VRGET but assigns a double-word register.
*/
VREG *
vrdget(void)
{
#if	DEBUG_KCC
    puts ("vrdget ()");
#endif

    return vrlink(vrsetrr(vrdalloc(), rrdfind()), &reglist);
}

/* 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), &reglist);
}

/* 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), &reglist);
}

/* 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(&reglist))
	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, &reglist);
	}

    /*
     * 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. */
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -