504 lines
15 KiB
C++
504 lines
15 KiB
C++
/*
|
|
* File: hlIcode.c
|
|
* Purpose: High-level icode routines
|
|
* Date: September-October 1993
|
|
* (C) Cristina Cifuentes
|
|
*/
|
|
#include <cassert>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include "dcc.h"
|
|
using namespace std;
|
|
#define ICODE_DELTA 25
|
|
|
|
/* Masks off bits set by duReg[] */
|
|
dword maskDuReg[] = { 0x00,
|
|
0xFEEFFE, 0xFDDFFD, 0xFBB00B, 0xF77007, /* word regs */
|
|
0xFFFFEF, 0xFFFFDF, 0xFFFFBF, 0xFFFF7F,
|
|
0xFFFEFF, 0xFFFDFF, 0xFFFBFF, 0xFFF7FF, /* seg regs */
|
|
0xFFEFFF, 0xFFDFFF, 0xFFBFFF, 0xFF7FFF, /* byte regs */
|
|
0xFEFFFF, 0xFDFFFF, 0xFBFFFF, 0xF7FFFF,
|
|
0xEFFFFF, /* tmp reg */
|
|
0xFFFFB7, 0xFFFF77, 0xFFFF9F, 0xFFFF5F, /* index regs */
|
|
0xFFFFBF, 0xFFFF7F, 0xFFFFDF, 0xFFFFF7 };
|
|
|
|
static char buf[lineSize]; /* Line buffer for hl icode output */
|
|
|
|
|
|
|
|
/* Places the new HLI_ASSIGN high-level operand in the high-level icode array */
|
|
void ICODE::setAsgn(COND_EXPR *lhs, COND_EXPR *rhs)
|
|
{
|
|
type = HIGH_LEVEL;
|
|
ic.hl.opcode = HLI_ASSIGN;
|
|
assert(ic.hl.oper.asgn.lhs==0); //prevent memory leaks
|
|
assert(ic.hl.oper.asgn.rhs==0); //prevent memory leaks
|
|
ic.hl.oper.asgn.lhs = lhs;
|
|
ic.hl.oper.asgn.rhs = rhs;
|
|
}
|
|
/* Places the new HLI_CALL high-level operand in the high-level icode array */
|
|
void ICODE::newCallHl()
|
|
{
|
|
type = HIGH_LEVEL;
|
|
ic.hl.opcode = HLI_CALL;
|
|
ic.hl.oper.call.proc = ic.ll.immed.proc.proc;
|
|
ic.hl.oper.call.args = new STKFRAME;
|
|
if (ic.ll.immed.proc.cb != 0)
|
|
ic.hl.oper.call.args->cb = ic.ll.immed.proc.cb;
|
|
else
|
|
ic.hl.oper.call.args->cb =ic.hl.oper.call.proc->cbParam;
|
|
}
|
|
|
|
|
|
/* Places the new HLI_POP/HLI_PUSH/HLI_RET high-level operand in the high-level icode
|
|
* array */
|
|
void ICODE::setUnary(hlIcode op, COND_EXPR *exp)
|
|
{
|
|
assert(ic.hl.oper.exp==0);
|
|
type = HIGH_LEVEL;
|
|
ic.hl.opcode = op;
|
|
ic.hl.oper.exp = exp;
|
|
}
|
|
|
|
|
|
/* Places the new HLI_JCOND high-level operand in the high-level icode array */
|
|
void ICODE::setJCond(COND_EXPR *cexp)
|
|
{
|
|
assert(ic.hl.oper.exp==0);
|
|
type = HIGH_LEVEL;
|
|
ic.hl.opcode = HLI_JCOND;
|
|
ic.hl.oper.exp = cexp;
|
|
}
|
|
|
|
|
|
/* Sets the invalid field to TRUE as this low-level icode is no longer valid,
|
|
* it has been replaced by a high-level icode. */
|
|
void ICODE ::invalidate()
|
|
{
|
|
invalid = TRUE;
|
|
}
|
|
|
|
|
|
/* Removes the defined register regi from the lhs subtree. If all registers
|
|
* of this instruction are unused, the instruction is invalidated (ie.
|
|
* removed) */
|
|
boolT ICODE::removeDefRegi (byte regi, Int thisDefIdx, LOCAL_ID *locId)
|
|
{
|
|
Int numDefs;
|
|
|
|
numDefs = du1.numRegsDef;
|
|
if (numDefs == thisDefIdx)
|
|
for ( ; numDefs > 0; numDefs--)
|
|
{
|
|
if ((du1.idx[numDefs-1][0] != 0)||(du.lastDefRegi))
|
|
break;
|
|
}
|
|
|
|
if (numDefs == 0)
|
|
{
|
|
invalidate();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
switch (ic.hl.opcode) {
|
|
case HLI_ASSIGN:
|
|
removeRegFromLong (regi, locId,ic.hl.oper.asgn.lhs);
|
|
du1.numRegsDef--;
|
|
du.def &= maskDuReg[regi];
|
|
break;
|
|
case HLI_POP:
|
|
case HLI_PUSH:
|
|
removeRegFromLong (regi, locId, ic.hl.oper.exp);
|
|
du1.numRegsDef--;
|
|
du.def &= maskDuReg[regi];
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/* Translates LOW_LEVEL icodes to HIGH_LEVEL icodes - 1st stage.
|
|
* Note: this process should be done before data flow analysis, which
|
|
* refines the HIGH_LEVEL icodes. */
|
|
void Function::highLevelGen()
|
|
{ Int i, /* idx into icode array */
|
|
numIcode; /* number of icode instructions */
|
|
ICODE * pIcode; /* ptr to current icode node */
|
|
COND_EXPR *lhs, *rhs; /* left- and right-hand side of expression */
|
|
flags32 flg; /* icode flags */
|
|
|
|
numIcode = Icode.GetNumIcodes();
|
|
for (i = 0; i < numIcode; i++)
|
|
{
|
|
pIcode = Icode.GetIcode(i);
|
|
if ((pIcode->ic.ll.flg & NOT_HLL) == NOT_HLL)
|
|
pIcode->invalidate();
|
|
if ((pIcode->type == LOW_LEVEL) && (pIcode->invalid == FALSE))
|
|
{
|
|
flg = pIcode->ic.ll.flg;
|
|
if ((flg & IM_OPS) != IM_OPS) /* not processing IM_OPS yet */
|
|
if ((flg & NO_OPS) != NO_OPS) /* if there are opers */
|
|
{
|
|
if ((flg & NO_SRC) != NO_SRC) /* if there is src op */
|
|
rhs = COND_EXPR::id (pIcode, SRC, this, i, pIcode, NONE);
|
|
lhs = COND_EXPR::id (pIcode, DST, this, i, pIcode, NONE);
|
|
}
|
|
|
|
switch (pIcode->ic.ll.opcode) {
|
|
case iADD: rhs = COND_EXPR::boolOp (lhs, rhs, ADD);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iAND: rhs = COND_EXPR::boolOp (lhs, rhs, AND);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iCALL:
|
|
case iCALLF: pIcode->newCallHl();
|
|
break;
|
|
|
|
case iDEC:
|
|
rhs = COND_EXPR::idKte (1, 2);
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, SUB);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iDIV:
|
|
case iIDIV:/* should be signed div */
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, DIV);
|
|
if (pIcode->ic.ll.flg & B)
|
|
{
|
|
lhs = COND_EXPR::idReg (rAL, 0, &localId);
|
|
pIcode->setRegDU( rAL, eDEF);
|
|
}
|
|
else
|
|
{
|
|
lhs = COND_EXPR::idReg (rAX, 0, &localId);
|
|
pIcode->setRegDU( rAX, eDEF);
|
|
}
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iIMUL: rhs = COND_EXPR::boolOp (lhs, rhs, MUL);
|
|
lhs = COND_EXPR::id (pIcode, LHS_OP, this, i, pIcode,
|
|
NONE);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iINC: rhs = COND_EXPR::idKte (1, 2);
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, ADD);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iLEA: rhs = COND_EXPR::unary (ADDRESSOF, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMOD: rhs = COND_EXPR::boolOp (lhs, rhs, MOD);
|
|
if (pIcode->ic.ll.flg & B)
|
|
{
|
|
lhs = COND_EXPR::idReg (rAH, 0, &localId);
|
|
pIcode->setRegDU( rAH, eDEF);
|
|
}
|
|
else
|
|
{
|
|
lhs = COND_EXPR::idReg (rDX, 0, &localId);
|
|
pIcode->setRegDU( rDX, eDEF);
|
|
}
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMOV: pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMUL: rhs = COND_EXPR::boolOp (lhs, rhs, MUL);
|
|
lhs = COND_EXPR::id (pIcode, LHS_OP, this, i, pIcode,
|
|
NONE);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iNEG: rhs = COND_EXPR::unary (NEGATION, lhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iNOT: rhs = COND_EXPR::boolOp (NULL, rhs, NOT);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iOR: rhs = COND_EXPR::boolOp (lhs, rhs, OR);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iPOP: pIcode->setUnary(HLI_POP, lhs);
|
|
break;
|
|
|
|
case iPUSH: pIcode->setUnary(HLI_PUSH, lhs);
|
|
break;
|
|
|
|
case iRET:
|
|
case iRETF: pIcode->setUnary(HLI_RET, NULL);
|
|
break;
|
|
|
|
case iSHL: rhs = COND_EXPR::boolOp (lhs, rhs, SHL);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSAR: /* signed */
|
|
case iSHR: rhs = COND_EXPR::boolOp (lhs, rhs, SHR); /* unsigned*/
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSIGNEX: pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSUB: rhs = COND_EXPR::boolOp (lhs, rhs, SUB);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iXCHG:
|
|
break;
|
|
|
|
case iXOR: rhs = COND_EXPR::boolOp (lhs, rhs, XOR);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Modifies the given conditional operator to its inverse. This is used
|
|
* in if..then[..else] statements, to reflect the condition that takes the
|
|
* then part. */
|
|
void inverseCondOp (COND_EXPR **exp)
|
|
{
|
|
static condOp invCondOp[] = {GREATER, GREATER_EQUAL, NOT_EQUAL, EQUAL,
|
|
LESS_EQUAL, LESS, DUMMY,DUMMY,DUMMY,DUMMY,
|
|
DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY,
|
|
DUMMY, DBL_OR, DBL_AND};
|
|
if (*exp == NULL)
|
|
return;
|
|
|
|
if ((*exp)->type == BOOLEAN_OP)
|
|
{
|
|
switch ((*exp)->expr.boolExpr.op)
|
|
{
|
|
case LESS_EQUAL: case LESS: case EQUAL:
|
|
case NOT_EQUAL: case GREATER: case GREATER_EQUAL:
|
|
(*exp)->expr.boolExpr.op = invCondOp[(*exp)->expr.boolExpr.op];
|
|
break;
|
|
|
|
case AND: case OR: case XOR: case NOT: case ADD:
|
|
case SUB: case MUL: case DIV: case SHR: case SHL: case MOD:
|
|
*exp = COND_EXPR::unary (NEGATION, *exp);
|
|
break;
|
|
|
|
case DBL_AND: case DBL_OR:
|
|
(*exp)->expr.boolExpr.op = invCondOp[(*exp)->expr.boolExpr.op];
|
|
inverseCondOp (&(*exp)->expr.boolExpr.lhs);
|
|
inverseCondOp (&(*exp)->expr.boolExpr.rhs);
|
|
break;
|
|
} /* eos */
|
|
|
|
}
|
|
else if ((*exp)->type == NEGATION) //TODO: memleak here
|
|
*exp = (*exp)->expr.unaryExp;
|
|
|
|
/* other types are left unmodified */
|
|
}
|
|
|
|
|
|
/* Returns the string that represents the procedure call of tproc (ie. with
|
|
* actual parameters) */
|
|
std::string writeCall (Function * tproc, STKFRAME * args, Function * pproc, Int *numLoc)
|
|
{
|
|
Int i; /* counter of # arguments */
|
|
string condExp;
|
|
ostringstream s;
|
|
s<<tproc->name<<" (";
|
|
for (i = 0; i < args->sym.size(); i++)
|
|
{
|
|
s << walkCondExpr (args->sym[i].actual, pproc, numLoc);
|
|
if (i < (args->sym.size() - 1))
|
|
s << ", ";
|
|
}
|
|
s << ")";
|
|
return s.str();
|
|
}
|
|
|
|
|
|
/* Displays the output of a HLI_JCOND icode. */
|
|
char *writeJcond (HLTYPE h, Function * pProc, Int *numLoc)
|
|
{
|
|
memset (buf, ' ', sizeof(buf));
|
|
buf[0] = '\0';
|
|
strcat (buf, "if ");
|
|
inverseCondOp (&h.oper.exp);
|
|
std::string e = walkCondExpr (h.oper.exp, pProc, numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, " {\n");
|
|
return (buf);
|
|
}
|
|
|
|
|
|
/* Displays the inverse output of a HLI_JCOND icode. This is used in the case
|
|
* when the THEN clause of an if..then..else is empty. The clause is
|
|
* negated and the ELSE clause is used instead. */
|
|
char *writeJcondInv (HLTYPE h, Function * pProc, Int *numLoc)
|
|
{
|
|
memset (buf, ' ', sizeof(buf));
|
|
buf[0] = '\0';
|
|
strcat (buf, "if ");
|
|
std::string e = walkCondExpr (h.oper.exp, pProc, numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, " {\n");
|
|
return (buf);
|
|
}
|
|
|
|
|
|
/* Returns a string with the contents of the current high-level icode.
|
|
* Note: this routine does not output the contens of HLI_JCOND icodes. This is
|
|
* done in a separate routine to be able to support the removal of
|
|
* empty THEN clauses on an if..then..else. */
|
|
char *write1HlIcode (HLTYPE h, Function * pProc, Int *numLoc)
|
|
{
|
|
std::string e;
|
|
|
|
memset (buf, ' ', sizeof(buf));
|
|
buf[0] = '\0';
|
|
switch (h.opcode) {
|
|
case HLI_ASSIGN:
|
|
e = walkCondExpr (h.oper.asgn.lhs, pProc, numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, " = ");
|
|
e = walkCondExpr (h.oper.asgn.rhs, pProc, numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, ";\n");
|
|
break;
|
|
case HLI_CALL:
|
|
e = writeCall (h.oper.call.proc, h.oper.call.args, pProc,
|
|
numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, ";\n");
|
|
break;
|
|
case HLI_RET:
|
|
e = walkCondExpr (h.oper.exp, pProc, numLoc);
|
|
if (! e.empty())
|
|
{
|
|
strcat (buf, "return (");
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, ");\n");
|
|
}
|
|
break;
|
|
case HLI_POP:
|
|
strcat (buf, "HLI_POP ");
|
|
e = walkCondExpr (h.oper.exp, pProc, numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, "\n");
|
|
break;
|
|
case HLI_PUSH: strcat (buf, "HLI_PUSH ");
|
|
e = walkCondExpr (h.oper.exp, pProc, numLoc);
|
|
strcat (buf, e.c_str());
|
|
strcat (buf, "\n");
|
|
break;
|
|
}
|
|
return (buf);
|
|
}
|
|
|
|
|
|
Int power2 (Int i)
|
|
/* Returns the value of 2 to the power of i */
|
|
{
|
|
if (i == 0)
|
|
return (1);
|
|
return (2 << (i-1));
|
|
}
|
|
|
|
|
|
/* Writes the registers/stack variables that are used and defined by this
|
|
* instruction. */
|
|
void ICODE::writeDU(Int idx)
|
|
{
|
|
static char buf[100];
|
|
Int i, j;
|
|
|
|
memset (buf, ' ', sizeof(buf));
|
|
buf[0] = '\0';
|
|
for (i = 0; i < (INDEXBASE-1); i++)
|
|
{
|
|
if ((du.def & power2(i)) != 0)
|
|
{
|
|
strcat (buf, allRegs[i]);
|
|
strcat (buf, " ");
|
|
}
|
|
}
|
|
if (buf[0] != '\0')
|
|
printf ("Def (reg) = %s\n", buf);
|
|
|
|
memset (buf, ' ', sizeof(buf));
|
|
buf[0] = '\0';
|
|
for (i = 0; i < INDEXBASE; i++)
|
|
{
|
|
if ((du.use & power2(i)) != 0)
|
|
{
|
|
strcat (buf, allRegs[i]);
|
|
strcat (buf, " ");
|
|
}
|
|
}
|
|
if (buf[0] != '\0')
|
|
printf ("Use (reg) = %s\n", buf);
|
|
|
|
/* Print du1 chain */
|
|
printf ("# regs defined = %d\n", du1.numRegsDef);
|
|
for (i = 0; i < MAX_REGS_DEF; i++)
|
|
{
|
|
if (du1.idx[i][0] != 0)
|
|
{
|
|
printf ("%d: du1[%d][] = ", idx, i);
|
|
for (j = 0; j < MAX_USES; j++)
|
|
{
|
|
if (du1.idx[i][j] == 0)
|
|
break;
|
|
printf ("%d ", du1.idx[i][j]);
|
|
}
|
|
printf ("\n");
|
|
}
|
|
}
|
|
|
|
/* For HLI_CALL, print # parameter bytes */
|
|
if (ic.hl.opcode == HLI_CALL)
|
|
printf ("# param bytes = %d\n", ic.hl.oper.call.args->cb);
|
|
printf ("\n");
|
|
}
|
|
|
|
|
|
/* Frees the storage allocated to h->hlIcode */
|
|
void freeHlIcode (ICODE * icode, Int numIcodes)
|
|
{
|
|
Int i;
|
|
HLTYPE h;
|
|
|
|
for (i = 0; i < numIcodes; i++)
|
|
{
|
|
h = icode[i].ic.hl;
|
|
switch (h.opcode)
|
|
{
|
|
case HLI_ASSIGN:
|
|
h.oper.asgn.lhs->release();
|
|
h.oper.asgn.rhs->release();
|
|
break;
|
|
case HLI_POP:
|
|
case HLI_PUSH:
|
|
case HLI_JCOND:
|
|
h.oper.exp->release();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|