dcc/src/hlicode.cpp

503 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[] */
uint32_t maskDuReg[] = { 0x00,
0xFEEFFE, 0xFDDFFD, 0xFBB00B, 0xF77007, /* uint16_t regs */
0xFFFFEF, 0xFFFFDF, 0xFFFFBF, 0xFFFF7F,
0xFFFEFF, 0xFFFDFF, 0xFFFBFF, 0xFFF7FF, /* seg regs */
0xFFEFFF, 0xFFDFFF, 0xFFBFFF, 0xFF7FFF, /* uint8_t 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 HLTYPE::setAsgn(COND_EXPR *lhs, COND_EXPR *rhs)
{
set(lhs,rhs);
}
void ICODE::checkHlCall()
{
//assert((ll()->immed.proc.cb != 0)||ll()->immed.proc.proc!=0);
}
/* Places the new HLI_CALL high-level operand in the high-level icode array */
void ICODE::newCallHl()
{
type = HIGH_LEVEL;
hl()->opcode = HLI_CALL;
hl()->call.proc = ll()->src.proc.proc;
hl()->call.args = new STKFRAME;
if (ll()->src.proc.cb != 0)
hl()->call.args->cb = ll()->src.proc.cb;
else if(hl()->call.proc)
hl()->call.args->cb =hl()->call.proc->cbParam;
else
{
printf("Function with no cb set, and no valid oper.call.proc , probaby indirect call\n");
hl()->call.args->cb = 0;
}
}
/* 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)
{
type = HIGH_LEVEL;
hl()->set(op,exp);
}
/* Places the new HLI_JCOND high-level operand in the high-level icode array */
void ICODE::setJCond(COND_EXPR *cexp)
{
type = HIGH_LEVEL;
hl()->set(HLI_JCOND,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)
*/
bool ICODE::removeDefRegi (uint8_t 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.any()))
// break;
// }
// }
if (numDefs == thisDefIdx)
{
for ( ; numDefs > 0; numDefs--)
{
if (du1.used(numDefs-1)||(du.lastDefRegi[regi]))
break;
}
}
if (numDefs == 0)
{
invalidate();
return true;
}
HlTypeSupport *p=hl()->get();
if(p and p->removeRegFromLong(regi,locId))
{
du1.numRegsDef--;
du.def &= maskDuReg[regi];
}
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 */
iICODE pIcode; /* ptr to current icode node */
COND_EXPR *lhs, *rhs; /* left- and right-hand side of expression */
uint32_t flg; /* icode flags */
numIcode = Icode.size();
for (iICODE i = Icode.begin(); i!=Icode.end() ; ++i)
{
assert(numIcode==Icode.size());
pIcode = i; //Icode.GetIcode(i)
LLInst *ll = pIcode->ll();
if ( ll->testFlags(NOT_HLL) )
pIcode->invalidate();
if ((pIcode->type == LOW_LEVEL) && pIcode->valid() )
{
flg = ll->getFlag();
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 (ll->getOpcode())
{
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->checkHlCall();
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 ( ll->testFlags(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 ( ll->testFlags(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. */
COND_EXPR *COND_EXPR::inverse ()
{
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};
COND_EXPR *res=0;
if (type == BOOLEAN_OP)
{
switch (expr.boolExpr.op)
{
case LESS_EQUAL: case LESS: case EQUAL:
case NOT_EQUAL: case GREATER: case GREATER_EQUAL:
res = this->clone();
res->expr.boolExpr.op = invCondOp[expr.boolExpr.op];
return res;
case AND: case OR: case XOR: case NOT: case ADD:
case SUB: case MUL: case DIV: case SHR: case SHL: case MOD:
return COND_EXPR::unary (NEGATION, this->clone());
case DBL_AND: case DBL_OR:
res = this->clone();
res->expr.boolExpr.op = invCondOp[expr.boolExpr.op];
res->expr.boolExpr.lhs=expr.boolExpr.lhs->inverse ();
res->expr.boolExpr.rhs=expr.boolExpr.rhs->inverse ();
return res;
} /* eos */
}
else if (type == NEGATION) //TODO: memleak here
{
return expr.unaryExp->clone();
}
return this->clone();
/* 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 ");
COND_EXPR *inverted=h.expr()->inverse();
//inverseCondOp (&h.exp);
std::string e = walkCondExpr (inverted, pProc, numLoc);
delete inverted;
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.expr(), pProc, numLoc);
strcat (buf, e.c_str());
strcat (buf, " {\n");
return (buf);
}
string AssignType::writeOut(Function *pProc, int *numLoc)
{
ostringstream ostr;
ostr << walkCondExpr (lhs, pProc, numLoc);
ostr << " = ";
ostr << walkCondExpr (rhs, pProc, numLoc);
ostr << ";\n";
return ostr.str();
}
string CallType::writeOut(Function *pProc, int *numLoc)
{
ostringstream ostr;
ostr << writeCall (proc, args, pProc,numLoc);
ostr << ";\n";
return ostr.str();
}
string ExpType::writeOut(Function *pProc, int *numLoc)
{
return walkCondExpr (v, pProc, numLoc);
}
/* 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. */
string HLTYPE::write1HlIcode (Function * pProc, int *numLoc)
{
string e;
ostringstream ostr;
HlTypeSupport *p = get();
switch (opcode)
{
case HLI_ASSIGN:
return p->writeOut(pProc,numLoc);
case HLI_CALL:
return p->writeOut(pProc,numLoc);
case HLI_RET:
e = p->writeOut(pProc,numLoc);
if (! e.empty())
ostr << "return (" << e << ");\n";
break;
case HLI_POP:
ostr << "HLI_POP ";
ostr << p->writeOut(pProc,numLoc);
ostr << "\n";
break;
case HLI_PUSH:
ostr << "HLI_PUSH ";
ostr << p->writeOut(pProc,numLoc);
ostr << "\n";
break;
}
return ostr.str();
}
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)
{
{
ostringstream ostr;
for (int i = 0; i < (INDEXBASE-1); i++)
if (du.def[i])
ostr << allRegs[i] << " ";
if (!ostr.str().empty())
printf ("Def (reg) = %s\n", ostr.str().c_str());
}
{
ostringstream ostr;
for (int i = 0; i < (INDEXBASE-1); i++)
if (du.def[i])
ostr << allRegs[i] << " ";
if (!ostr.str().empty())
printf ("Def (reg) = %s\n", ostr.str().c_str());
for (int i = 0; i < INDEXBASE; i++)
{
if (du.use[i])
ostr << allRegs[i] << " ";
}
if (!ostr.str().empty())
printf ("Use (reg) = %s\n", ostr.str().c_str());
}
/* Print du1 chain */
printf ("# regs defined = %d\n", du1.numRegsDef);
for (int i = 0; i < MAX_REGS_DEF; i++)
{
if (du1.used(i))
{
printf ("%d: du1[%d][] = ", idx, i);
for(std::list<ICODE>::iterator j : du1.idx[i].uses)
{
printf ("%d ", j->loc_ip);
}
printf ("\n");
}
}
/* For HLI_CALL, print # parameter bytes */
if (hl()->opcode == HLI_CALL)
printf ("# param bytes = %d\n", hl()->call.args->cb);
printf ("\n");
}