📄 cccode.c
字号:
/* CCCODE.C - Emit pseudo-code into peephole buffer
**
** (c) Copyright Ken Harrenstien 1989
** All changes after v.315, 26-Apr-1988
** (c) Copyright Ken Harrenstien, SRI International 1985, 1986
** All changes after v.146, 8-Aug-1985
**
** Original version (c) 1981 K. Chen
*/
#include "cc.h"
#include "ccgen.h"
#include <string.h> /* For memcpy, memcmp */
#include <stdlib.h> /* for calloc() */
/* Imported functions */
extern PCODE *findrset(PCODE *, int); /* CCOPT */
extern int rincode(PCODE *, int), rinaddr(PCODE *, int),
rrchg(PCODE *, int),
findconst(PCODE *), localbyte(PCODE *, PCODE *); /* CCOPT */
extern void foldbp(PCODE *), foldbyte(PCODE *),
foldplus(PCODE *),
foldboth(void), foldadjbp(PCODE *), optlsh(PCODE *); /* CCOPT */
extern INT foldstack(INT), hackstack(SYMBOL *); /* CCOPT */
extern void realcode(PCODE *), outlab(SYMBOL *); /* CCOUT */
extern void reflabel(SYMBOL *, int), cleanlabs(void),
freelabel(SYMBOL *); /* CCSYM */
extern int changereg(int, int, PCODE *), ufcreg(int),
pnegreg(int, PCODE *), pushneg(int, PCODE *); /* CCCREG */
extern void foldmove(PCODE *); /* CCCREG */
extern int sameaddr(PCODE *, PCODE *, INT),
alias(PCODE *, PCODE *, INT); /* CCCSE */
extern void foldidx(PCODE *); /* CCCSE */
extern void foldskip(PCODE *, int),
foldjump(PCODE *, SYMBOL *), optlab(SYMBOL *),
inskip(PCODE *); /* CCJSKP */
extern VREG *vrget(void);
extern void vrfree (VREG *);
extern int vrreal (VREG *);
extern int vrstoreal (VREG *, VREG *);
extern int vrtoreal(VREG *);
extern int rbinreg (PCODE *);
extern int rbinaddr (PCODE *);
/* Exported functions */
PCODE *before(PCODE *), *after(PCODE *);
void fixprev(void), flushcode(void), dropinstr(PCODE *),
swappseudo(PCODE *, PCODE *);
int codcreg(VREG *, VREG *), immedop(int op);
void code0(int, VREG *, VREG *);
void codek0(int, VREG *, VREG *);
void code00(int, int, int); /* Reg linkage, was static */
void code1(int, VREG *, INT);
void code3(int, VREG *, SYMBOL *);
void code4(int, VREG *, VREG *);
void code40(int op, int r, int s, INT bsiz);/* Reg linkage, was static */
void code4s(int, VREG *, VREG *, int, INT);
void code5(int, VREG *);
void code6(int, VREG *, SYMBOL *);
void code8(int, VREG *, INT);
void code9(int, VREG *, double, int);
void code10(int, VREG *, SYMBOL *, INT, INT);
void code12(int, VREG *, INT);
void code13(int, VREG *, INT);
void code15(int, SYMBOL *, INT, VREG *);
void code16(int, VREG *, SYMBOL *, VREG *);
void code17(INT);
void codebp(int, int, INT, int, SYMBOL *, INT);
void codek4(int, VREG *, VREG *);
void codemdx(int, int, SYMBOL *, INT, int);
void codestr(char *, int);
void codgolab(SYMBOL *);
void codlabel(SYMBOL *);
void codr1(int, int, INT);
void codr10(int, int, SYMBOL *, INT, INT);
void code4m(int op, VREG *reg, VREG *idx, char *mnem),
code5m(int, VREG *, char *);
PCODE *chkmref(PCODE *begp, PCODE *endp, INT *aoff);
/* Internal functions */
static void codrmdx(int, int, int, SYMBOL *, INT, int);
static void codr8(int, int, INT);
static void flsprev(void);
static PCODE *newcode(int, int, int);
static void codrrx(PCODE *, PCODE *);
static int rrpre1(PCODE *), rrpre2(PCODE *, PCODE *);
static void rrpre3(PCODE *, PCODE *, int), rrpopt(PCODE *), rrpop2(PCODE *);
static PCODE *chkref(PCODE *, PCODE *, int);
static void foldxref(PCODE *);
static void optjrst(PCODE *p);
#if DEBUG_KCC /* 5/91 KCC size */
/* PEEPHOLER DEBUGGING ROUTINES */
/* SHOALL and SHOCURCOD are intended to be called directly by
** IDDT during debugging, e.g. as in PUSHJ 17,SHOALL$X
*/
#if __STDC__
static void shoall(void), shocurcod(void), shopcod(FILE *, PCODE *, INT),
shoop(FILE *, unsigned), shohdr(char *, int, int), shocum(void),
shocmp(FILE *);
#else
static void shoall(), shocurcod(), shopcod(), shoop(),
shohdr(), shocum(), shocmp();
#endif
static void
shoall()
{
INT i;
for (i = mincode; i < maxcode; i++)
shopcod(outmsgs, &codes[i&(MAXCODE-1)], i&(MAXCODE-1));
}
static void
shocurcod()
{
shopcod(outmsgs, previous, codes-previous);
}
/* SHOHDR - Called at start of each CODEnn function.
** Ensures consistent trace of all calls from CCGEN2 to CCCODE.
*/
static void
shohdr(loc, op, r)
char *loc;
int op, r;
{
fprintf(fpho, "%s: %o=", loc, op);
shoop(fpho, op);
if (r)
fprintf(fpho, " %o,", r);
else
fputc(' ', fpho);
}
/* SHOPCOD - Show one pseudo-code entry
** Used as auxiliary for other debug printing routines, never called
** directly by IDDT.
*/
static void
shopcod(f,p,idx)
FILE *f;
PCODE *p;
INT idx;
{
unsigned int i;
fprintf(f,"codes[%d] %6lo/ %4o %5o %2o %6o %6lo %2o %lo+%lo\n\t",
idx, p, p->Ptype, p->Pop, p->Preg, p->Pptr,
p->Poffset, p->Pindex, p->Pdouble1, p->Pdouble2);
/* Output value of Pop field */
shoop(f, p->Pop);
/* Output value of Ptype field */
fputs(" <", f);
if (p->Ptype&PTF_IMM)
fputs("Imm,", f);
if (p->Ptype&PTF_SKIPPED)
fputs("Skipped,", f);
if (p->Ptype&PTF_IND)
fputs("Indirect", f);
fputs("> ", f);
/* Now interpret the rest of the instruction according to mode */
switch (i = (p->Ptype&PTF_ADRMODE))
{
case PTA_ONEREG: /* no address, just register */
fprintf(f, "ONEREG R=%o,", p->Preg);
break;
case PTA_REGIS: /* register to register */
fprintf(f, "REGIS R=%o, R=%o", p->Preg, p->Pr2);
break;
case PTA_MINDEXED: /* addr+offset(index) */
fprintf(f, "MINDEXED R=%o, Addr=%s+%o(%o) siz %o", p->Preg,
(p->Pptr ? p->Pptr->Sname : ""),
p->Poffset, p->Pindex, p->Pbsize);
break;
case PTA_BYTEPOINT: /* [bsize,,addr+offset(index)] */
fprintf(f, "BYTEPOINT R=%o, BP=[%o,,%s+%o(%o)]", p->Preg,
p->Pbsize,
(p->Pptr ? p->Pptr->Sname : ""),
p->Poffset,
p->Pindex);
break;
case PTA_PCONST: /* [<pointer of addr+offset+bsize>] */
if (p->Pbsize)
fprintf(f, "PCONST R=%o, bptr%d=[%s+%o]", p->Preg,
p->Pbsize,
(p->Pptr ? p->Pptr->Sname : ""),
p->Poffset);
else
fprintf(f, "PCONST R=%o, Wptr=[%s+%o]", p->Preg,
(p->Pptr ? p->Pptr->Sname : ""),
p->Poffset);
break;
case PTA_RCONST: /* Simple integer in pvalue */
fprintf(f, "RCONST R=%o, Constant=%o", p->Preg, p->Pvalue);
break;
case PTA_FCONST: /* [single-prec float] */
fprintf(f, "FCONST R=%o, Fltcon=%g", p->Preg, p->Pfloat);
break;
case PTA_DCONST: /* [double-prec float] */
fprintf(f, "DCONST R=%o, Dblcon=%g", p->Preg, p->Pdouble);
break;
case PTA_DCONST1: /* [1st wd of double float] */
fprintf(f, "DCONST1 R=%o, 1st wd of dblcon=%g", p->Preg, p->Pdouble);
break;
case PTA_DCONST2: /* [2nd wd of double float] */
fprintf(f, "DCONST2 R=%o, 2nd wd of dblcon=%g", p->Preg, p->Pdouble);
break;
default:
fprintf(f, "Illegal ADRMODE value = %o", i);
}
fputc('\n', f);
}
/* SHOOP - Auxiliary for above two routines, just outputs string for opcode.
*/
static void
shoop(f, op)
FILE *f;
unsigned op;
{
/* Test conditions, indexed by POF_OPSKIP field */
static char *shoskt[] = { "", "A", "E", "N", "L", "GE", "G", "LE" };
fputs(popostr[op&POF_OPCODE], f);
if (op&(~POF_OPCODE))
{
if (op&POF_ISSKIP)
fputs("+skp", f);
if (op&POF_OPSKIP)
{
fputc('+', f);
fputs(shoskt[(op&POF_OPSKIP)>>POF_OPSKIP_SHF], f);
}
if (op&POF_BOTH)
fputs("+B", f);
}
}
/* More debug stuff. Pcode buffer compare, to show what's changed. */
static INT cmpcnt = 0; /* Count of times compare done */
static PCODE *oldcodes = NULL;
static INT omaxcode = 0, omincode = 0;
static void
shocum()
{
fprintf(fpho, "----------- Update %3d -----------------\n", cmpcnt++);
shocmp(fpho);
fprintf(fpho, "----------------------------------------\n");
}
/* SHOCMP - Output a buffer comparison */
static void
shocmp(f)
FILE *f;
{
PCODE *p, *q;
INT i, lim;
if (oldcodes == NULL) /* Ensure old buffer copy exists */
if ((oldcodes = (PCODE *)calloc(sizeof(codes), 1)) == NULL)
{
error("No memory for pcode buffer");
return;
}
/* First check for new code prior to last stuff */
if (mincode < omincode)
{
fprintf(f," NEW---- stuff prior to start of last check:\n");
for (i = mincode; i < omincode; ++i)
{
fprintf(f, " NEW ");
shopcod(f, &codes[i&(MAXCODE-1)], i&(MAXCODE-1));
}
}
/* Then check for old code prior to current new start */
else if (omincode < mincode)
{
fprintf(f," OLD---- stuff flushed from start of current code:\n");
for (i = omincode; i < mincode; ++i)
{
fprintf(f, " OLD ");
shopcod(f, &oldcodes[i&(MAXCODE-1)], i&(MAXCODE-1));
}
}
/* Now compare stuff that's in both buffers */
lim = (maxcode < omaxcode) ? maxcode : omaxcode; /* Find smallest */
for (i = mincode; i < lim; ++i)
{
p = &codes[i&(MAXCODE-1)];
q = &oldcodes[i&(MAXCODE-1)];
if (memcmp((char *)p, (char *)q, sizeof(PCODE)) == 0)
continue; /* Compared OK, keep going */
fprintf(f, " ----Changed\n OLD ");
shopcod(f, q, i&(MAXCODE-1));
fprintf(f, " ----to\n NEW ");
shopcod(f, p, i&(MAXCODE-1));
fprintf(f, " -----------\n");
}
/* Now check for new code added after last stuff */
if (maxcode > omaxcode)
{
fprintf(f," ADD---- New stuff:\n");
for (i = omaxcode; i < maxcode; ++i)
{
fprintf(f, " ADD ");
shopcod(f, &codes[i&(MAXCODE-1)], i&(MAXCODE-1));
}
}
/* Then check for old code still existing at end */
else if (maxcode < omaxcode)
{
fprintf(f," OLD---- stuff flushed from end:\n");
for (i = maxcode; i < omaxcode; ++i)
{
fprintf(f, " OLD ");
shopcod(f, &oldcodes[i&(MAXCODE-1)], i&(MAXCODE-1));
}
}
/* Now update our copy in preparation for next check */
#if __STDC__
memcpy((void *)oldcodes, (void *)codes, sizeof(codes));
#else
memcpy((char *)oldcodes, (char *)codes, sizeof(codes));
#endif
omincode = mincode;
omaxcode = maxcode;
}
#endif
/* BASIC PSEUDO-CODE AUXILIARIES */
/* NEWCODE - Get a new pseudo-code record.
** Sets "previous" to the returned pointer, for global access.
*/
static int prvskip = 0; /* Used by newcode/flushcode to remember if skipping */
#define OVERINC 20 /* Number of ops to force out on overflow */
static PCODE *
newcode(type, op, reg)
{
PCODE *p;
int i;
int skipped;
/* fixprev(); */ /* Don't need if all other code is careful */
if (previous)
skipped = isskip(previous->Pop) /* If prev was skip, */
? PTF_SKIPPED : 0; /* say new instr is skipped! */
else
skipped = prvskip; /* No prev, ask flushcode */
p = &codes[maxcode++ & (MAXCODE - 1)]; /* Get ptr to new instr */
if (maxcode >= mincode + MAXCODE - 1) /* Overflow? If so, */
for (i = 0; i < OVERINC; i++) /* force some instrs out */
realcode(&codes[(mincode++)&(MAXCODE-1)]);
p->Ptype = type | skipped;
p->Pop = op;
p->Preg = reg;
return previous = p; /* Set "previous" to new instr */
}
/* BEFORE(p) - Return live instruction preceding this one.
** AFTER(p) - Return live instruction succeeding this one.
*/
PCODE *
before(p)
PCODE *p;
{
PCODE *b;
if (p == NULL)
return NULL; /* make sure we have a real pseudo */
b = &codes[mincode&(MAXCODE-1)];
while (1)
{
if (p == b)
break; /* start of buffer, can't back up */
--p; /* back before here */
if (p < &codes[0])
p = &codes[MAXCODE-1]; /* wrap in circular buffer */
if (p->Pop != P_NOP)
return p; /* got a real op, return with it */
}
return NULL;
}
PCODE *
after(p)
PCODE *p;
{
PCODE *b = &codes[maxcode&(MAXCODE-1)];
if (p == NULL)
return NULL; /* make sure we have a real pseudo */
while (1)
{
if (++p > &codes[MAXCODE-1])
p = &codes[0]; /* wrap */
if (p == b)
break; /* end of buffer, no more code */
if (p->Pop != P_NOP)
return p; /* got a real op, return with it */
}
return NULL;
}
/* SWAPPSEUDO(a,b) - swap two pseudo code locations
*/
void
swappseudo(a,b)
PCODE *a, *b;
{
PCODE temp;
temp = *b; /* Copy the structure to temp place */
*b = *a;
*a = temp;
}
/* FIXPREV() - Make sure "previous" points to something.
**
** This should be called after a pseudo-code which might be the last
** in the buffer is P_NOPed out. It sets previous to the new last
** instruction in the peephole buffer.
**
** Someday this might also change maxcode to save buffer space.
*/
void
fixprev(void)
{
if (previous && previous->Pop == P_NOP)
{
previous = before(previous);
--maxcode; /* We know at least one flushed, but */
/* not sure how far back. 1 is better than nothing. */
}
}
/* DROPINSTR(p) - Flush pseudo-code instruction (make it a NOP)
** FLSPREV() - Flush instruction that "previous" points to.
*/
void
dropinstr(p)
PCODE *p;
{
if (p)
{
p->Pop = P_NOP;
fixprev(); /* Fix up in case "previous" is now (or was) a NOP */
}
}
static void
flsprev(void)
{
dropinstr(previous);
}
/* FLUSHCODE() - Flush peephole buffer (emit everything)
*/
void
flushcode(void)
{
if (mincode < maxcode)
{
prvskip = (previous && isskip(previous->Pop)) /* If prev was skip, */
? PTF_SKIPPED : 0; /* remember fact for newcode */
do
realcode(&codes[(mincode++)&(MAXCODE-1)]);
while (mincode < maxcode)
;
#if DEBUG_KCC /* 5/91 KCC size */
if (debpho)
{
fprintf(fpho,"FLUSHCODE:\n");
shocum(); /* Show stuff forced out. */
}
#endif
}
previous = NULL;
}
/* CODCREG - Change register.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -