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

📄 ccjskp.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 3 页
字号:
/*	CCJSKP.C - Peephole Optimizer - skips and jumps
**
**	(c) Copyright Ken Harrenstien 1989
**		All changes after v.101, 29-Jul-1988
**	(c) Copyright Ken Harrenstien, SRI International 1985, 1986
**		All changes after v.67, 8-Aug-1985
**
** Original version by David Eppstein / Stanford University / 12 Jun 85
*/

#include "cc.h"
#include "ccgen.h"

/* Imported functions */
extern PCODE *before(PCODE *), *after(PCODE *);
extern void reflabel(SYMBOL *, int), dropinstr(PCODE *);
extern int unsetz(PCODE *), oneinstr(PCODE *);
extern int rinaddr(PCODE *, int), rrchg(PCODE *, int), rinreg(PCODE *, int);
extern int sameaddr(PCODE *, PCODE *, INT);
extern int changereg(int, int, PCODE *), immedop(int);
extern void swappseudo(PCODE *, PCODE *);

/* Exported functions */
typedef SYMBOL *label;

void foldskip(PCODE *p, int safechange);	/* CCCODE */
void foldjump(PCODE *prev, label lab);	/* CCCODE */
int deadjump(void);		/* CCGEN1 */
int dropsout(PCODE *);		/* CCCREG, CCCSE, CCOPT */
void unskip(PCODE *);		/* CCCREG */
int unjump(label lab);		/* CCGEN2 */
void optlab(label lab);		/* CCCODE */
int foldtrna(PCODE *);		/* CCOUT */
void inskip(PCODE *);		/* CCCODE, CCOPT */

/* Internal functions */
static void dropjump(PCODE *), crossjump(PCODE *, SYMBOL *),
	    jumptoskip(PCODE *);
static int  invskip(PCODE *), newskip(PCODE *);
#if 0
static void dropjump(), crossjump(), jumptoskip();
static int invskip(), newskip();
#endif



/* DEADJUMP(p) - See if currently emitted code will be dead.
**
** There are three cases (yes the third one actually happens):
**  (1) The last op was an unskipped P_JRST, i.e. an unconditional jump
**  (2) The last op was an unskipped P_POPJ, i.e. an unconditional return
**  (3) The last op was an P_IFIW, i.e. we're in a switch jump table
*/

int
deadjump(void)
{
    if (previous) switch (previous->Pop) {
	case P_JRST:		/* jump, return, or jump table? */
	case P_POPJ:
	case P_IFIW:
	    return !prevskips(previous); /* yes, verify not skipped over */
    }
    return 0;				/* can't see or not jump, fail */
}

/* DROPSOUT(p) - See if operation can possibly affect following instructions
**
** It can't if it's a JRST, it's a POPJ, or its POF_OPSKIP field is POS_SKPA
** and it skips to an operation that can't affect the stream.
*/

int
dropsout(PCODE *p)
{
    if (p == NULL) return 0;
    if (p->Pop == P_JRST || p->Pop == P_POPJ) return 1;
    if ((p->Pop & POF_OPSKIP) != POS_SKPA) return 0;
    if ((p = after(p)) == NULL || (p = after(p)) == NULL) return 0;
    return dropsout(p);
}

/* DROPJUMP(p) - Remove a jump instruction
**
** Actually this removes any instruction, but it is necessary to use if
** the instruction might be a jump so the label's refcount can be maintained.
*/

static void
dropjump(p)
PCODE *p;
{
    if ((p->Ptype & PTF_ADRMODE) == PTA_MINDEXED)
	reflabel(p->Pptr, -1);
    dropinstr(p);	/* drop the instruction & fix up previous */
}

/* INVSKIP(p) - Invert an embedded skip
**
** Takes a skip instruction in the peephole buffer and makes the code there
** skip on the opposite condition.  No new code is emmited (unlike makeskip()).
** Checks to make sure skip can't be itself skipped over.
*/

static int
invskip(p)
PCODE *p;
{
    int r;
    PCODE *q, *b;

    if (p == NULL) return 0;		/* nothing to invert */

    if (!isskip(p->Pop)) return 0;

    if (p->Pop == P_CAI+POF_ISSKIP+POS_SKPLE
      && p->Ptype == PTA_RCONST+PTF_SKIPPED
      && (q = before(p)) != NULL
      && q->Ptype == PTA_RCONST
      && q->Preg == p->Preg
      && q->Pop == P_CAI+POF_ISSKIP+POS_SKPL
      && q->Pvalue == p->Pvalue - 1) {		/* Invert the sequence: */
	q->Pop = P_CAI+POF_ISSKIP+POS_SKPE;	/*    CAIL R,n / CAILE R,n+1 */
	p->Pop = P_CAI+POF_ISSKIP+POS_SKPN;	/* to CAIE R,n / CAIN R,n+1 */
	return 1;
    }

    r = revop(p->Pop);
    if (!(r & POF_OPSKIP)) {		/* was POS_SKPA, now no skip at all */
	r &=~ POF_ISSKIP;		/* so don't think of it as a skip */
	if (r == P_TRN) {		/* was TRNA, don't need to check */
	    dropinstr(p);		/* if skipped, just drop it entirely */
	    return 1;			/* that's all for now. */
	}
	if ((q = before (p)) != NULL && (q->Pop & POF_OPSKIP) == POS_SKPA) {
	    if (!invskip(before(q))) return 0; /* two unflippable POS_SKPAs */
	    swappseudo(p, q);		/* flipped before, now them */
	    return 1;			/* win win */
	}
    }

    if (!prevskips (p)) {
	p->Pop = r;			/* single skip, invert it */
	return 1;			/* return success */
    }

    /* look for three-word flip from double comparison */
    if ((p->Ptype & PTF_ADRMODE) != PTA_REGIS || !(p->Pop & POSF_CMPSKIP) ||
	(p->Pop & POF_OPCODE) != P_CAM || (q = before (p)) == NULL ||
	(b = before (q)) == NULL || b->Pop != (p->Pop ^ POSF_EQSKIP) ||
	(b->Ptype & PTF_ADRMODE) != PTA_REGIS || b->Preg != p->Preg ||
	b->Pr2 != p->Pr2) return 0;

    /* have a doubleword compare, invert the whole thing */
    q->Pop = revop(q->Pop);
    p->Pop = revop(b->Pop);
    b->Pop = r;
    return 1;
}

/* FOLDSKIP(p) - Turn P_CAIx R,0 into something better
**
** The safechange argument is zero if it might be part of a switch
** (in which case we can't safely change the value in the reg).
*/

void
foldskip(PCODE *p, int safechange)
{
    PCODE *q;

#if SYS_CSI		/*  Reg linkage */
    if (Register_Preserve (p->Pr2))
	return;			/* avoid faulty optimizations */
#endif

    if (p == NULL) return;

    /*
    ** fold:  P_MOVE S,x
    ** 	      P_ADD S,y
    ** 	      P_CAMN R,S
    **
    ** into:  P_SUB R,x
    ** 	      P_SUB R,y
    ** 	      P_CAIN R,0
    **
    ** (only for P_CAMN and P_CAME, to avoid wrap problems).
    */

    if ((p->Pop == P_CAM+POF_ISSKIP+POS_SKPE
      || p->Pop == P_CAM+POF_ISSKIP+POS_SKPN) &&
	p->Ptype == PTA_REGIS)
    for (q = before (p); q != NULL; q = before (q)) {
	if (prevskips (q) || q->Preg != p->Pr2) break;
	switch (q->Pop) {
	case P_ADD: case P_SUB:
	    q->Preg = p->Preg;		/* swap adds across to other reg */
	    q->Pop ^= (P_ADD ^ P_SUB);	/* making them subtracts instead */
	    continue;

	case P_MOVE: case P_MOVN:
	    q->Preg = p->Preg;		/* same for P_MOVE and P_MOVN */
	    q->Pop = (q->Pop == P_MOVE? P_SUB : P_ADD); /* turned into P_SUB and P_ADD */
	    p->Pop ^= (P_CAM ^ P_CAI);	/* make immediate comparison */
	    p->Ptype = PTA_RCONST;		/* against number */
	    p->Pvalue = 0;		/* number is zero */
	}
	break;				/* escape loop if not explicit cont */
    }

    if ((p->Pop & POF_OPCODE) != P_CAI) return; /* must be P_CAIx */
    q = before(p);			/* look before it */

    if (q != NULL && q->Ptype == PTA_REGIS /* !prevskips */
#if SYS_CSI		/*  Reg linkage */
     && (Register_Nopreserve (q->Pr2))/* avoid faulty optimizations */
#endif
     && q->Preg == p->Preg && q->Pop == P_MOVE && safechange) {

	/*
	** fold:  P_MOVE  R,S
	**        P_CAIx  R,c
	**
	** into:  P_CAIx  S,c
	*/

	p->Preg = (char) (q->Pr2);		/* flatten tested register */ // FW KCC-NT
	q->Pop = P_NOP;			/* flush useless move */
	q = before(q);			/* try for more optimizations */
    }

    if (q->Preg == p->Preg && q->Ptype == PTV_IMMED && safechange)
	switch(q->Pop) {
	    case P_SUB:
		if (!unsetz (q)) break;
	    case P_ADD:

		/*
		** fold:  P_ADDI  R,n
		**        P_CAIx  R,m
		**
		** into:  P_CAIx  R,m-n
		*/

		p->Pvalue -= q->Pvalue;
		q->Pop = P_NOP;			/* flush folded addition */
		q = before(q);			/* look for more before it */
	}

    /*
    ** fold:  P_CAIGE R,1
    ** into:  P_CAIG  R,0
    */

    if ((p->Ptype & PTF_ADRMODE) != PTA_RCONST) return;	/* rest of opts need numbers */

    switch (p->Pop & POF_OPSKIP) {
    case POS_SKPG:    case POS_SKPLE:		/* skip that can be adjusted up? */
	if (p->Pvalue == -1 || p->Pvalue == -2) { /* worthwhile to do it? */
	    p->Pvalue++;		/* yes, increment value */
	    p->Pop ^= POSF_EQSKIP;		/* and adjust skip to match */
	}
	break;

    case POS_SKPL:    case POS_SKPGE:		/* skip that can be adjusted down? */
	if (p->Pvalue == 1 || p->Pvalue == 2) {	/* worthwhile to do it? */
	    p->Pvalue--;		/* yes, decrement value */
	    p->Pop ^= POSF_EQSKIP;		/* and adjust skip to match */
	}
	break;
    }

    /*
    ** Fold remaining comparisons against one into P_AOSx which will
    ** later become P_AOJx.  We make P_AOS R,R rather than P_AOS R so we
    ** don't confuse the rest of code generation too badly.
    ** 
    ** All optimizations after this one can safely assume that the
    ** value being compared against is zero.
    */

    switch ((int) p->Pvalue) {
    case 1:
	if (!safechange) return;	/* not for switch you don't */
	p->Pop ^= (P_CAI ^ P_SOS);		/* make P_SOSx */
	p->Ptype ^= (PTA_RCONST ^ PTA_REGIS);	/* from and to register */
	p->Pr2 = p->Preg;		/* same register */
	return;				/* that's all */

    case -1:
	if (!safechange) return;	/* not for switch you don't */
	p->Pop ^= (P_CAI ^ P_AOS);		/* make P_AOSx */
	p->Ptype ^= (PTA_RCONST ^ PTA_REGIS);	/* from and to register */
	p->Pr2 = p->Preg;		/* same register */
	return;				/* that's all */

    case 0: break;			/* zero is ok to continue with */
    default: return;			/* anything else we can't handle */
    }

    /*
    ** The remaining optimizations fold a test against zero with
    ** the previous instruction.
    */

    if (q->Preg != p->Preg) {
	if ((q->Pop == P_IDIV || q->Pop == P_UIDIV)
		&& q->Preg + 1 == p->Preg
		&& safechange
		&& q->Ptype == PTV_IMMED /* !prvsk */
		&& ((q->Pvalue-1)&q->Pvalue) == 0) {

	    /*
	    ** fold:  P_IDIVI R-1,2^n
	    **        P_CAIx  R,0
	    **
	    ** into:  P_TRNx  R,2^n-1
	    */

	    switch (p->Pop & POF_OPSKIP) {
	    case POS_SKPE:
	    case POS_SKPN:
		p->Pop ^= (P_CAI ^ P_TRN);
		p->Preg = q->Preg;
		p->Ptype = PTA_RCONST;
		p->Pvalue = q->Pvalue - 1;
		q->Pop = P_NOP;
		q = before(q);		/* now look at before the P_IDIVI */
		if (q->Ptype == PTA_REGIS /* !prevskips */ && q->Pop == P_MOVE &&
		    q->Preg == p->Preg) {
		    p->Preg = (char) (q->Pr2);	// FW KCC-NT
		    q->Pop = P_NOP;	/* flatten failed changereg() */
		}
	    }
	}
	return;
    }

    if (prevskips (q)) return;
    switch (q->Pop) {
    case P_AND:
	if (!safechange) return;
	switch (p->Pop & POF_OPSKIP) {
	case POS_SKPE:
	case POS_SKPN:

	    /*
	    ** fold:  P_AND  R,mask
	    **	      P_CAIE R,0
	    **
	    ** into:  P_TDNE R,mask
	    */

	    if (q->Ptype == PTV_IMMED) {
		q->Ptype = PTA_RCONST;
		q->Pop = p->Pop ^ (P_CAI ^ P_TRN);
	    } else q->Pop = p->Pop ^ (P_CAI ^ P_TDN);
	    break;

	default: return;
	}
	break;

    case P_MOVE:
	/*
	** fold:  P_MOVE  R,addr
	**        P_CAIx  R,0
	**
	** into:  P_SKIPx R,addr
	*/
	q->Pop = p->Pop ^ (P_CAI ^ P_SKIP);
	break;

    case P_ADD:
	if (q->Ptype != PTV_IMMED || !safechange) return;
	if (p->Pop != P_CAI+POF_ISSKIP+POS_SKPE && p->Pop != P_CAI+POF_ISSKIP+POS_SKPN) return;
	/* Now that we know we'll do the optimization, safe to clobber instr */
	q->Pvalue = - q->Pvalue;

⌨️ 快捷键说明

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