645 lines
18 KiB
C++
645 lines
18 KiB
C++
/*
|
|
* File: hlIcode.c
|
|
* Purpose: High-level icode routines
|
|
* Date: September-October 1993
|
|
* (C) Cristina Cifuentes
|
|
*/
|
|
#include "dcc.h"
|
|
|
|
#include <QtCore/QDebug>
|
|
#include <QtCore/QString>
|
|
|
|
#include <cassert>
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <sstream>
|
|
using namespace std;
|
|
|
|
/* Places the new HLI_ASSIGN high-level operand in the high-level icode array */
|
|
void HLTYPE::setAsgn(Expr *lhs, Expr *rhs)
|
|
{
|
|
assert(lhs);
|
|
set(lhs,rhs);
|
|
|
|
}
|
|
void ICODE::checkHlCall()
|
|
{
|
|
//assert((ll()->immed.proc.cb != 0) or 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_ICODE;
|
|
hlU()->setCall(ll()->src().proc.proc);
|
|
|
|
if (ll()->src().proc.cb != 0)
|
|
hlU()->call.args->cb = ll()->src().proc.cb;
|
|
else if(hl()->call.proc)
|
|
hlU()->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, Expr *_exp)
|
|
{
|
|
type = HIGH_LEVEL_ICODE;
|
|
hlU()->set(op,_exp);
|
|
}
|
|
|
|
|
|
/* Places the new HLI_JCOND high-level operand in the high-level icode array */
|
|
void ICODE::setJCond(Expr *cexp)
|
|
{
|
|
type = HIGH_LEVEL_ICODE;
|
|
hlU()->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 (eReg regi, int thisDefIdx, LOCAL_ID *locId)
|
|
{
|
|
int numDefs;
|
|
|
|
numDefs = du1.getNumRegsDef();
|
|
if (numDefs == thisDefIdx)
|
|
{
|
|
for ( ; numDefs > 0; numDefs--)
|
|
{
|
|
|
|
if (du1.used(numDefs-1) or (du.lastDefRegi.testReg(regi)))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (numDefs == 0)
|
|
{
|
|
invalidate();
|
|
return true;
|
|
}
|
|
HlTypeSupport *p=hlU()->get();
|
|
if(p and p->removeRegFromLong(regi,locId))
|
|
{
|
|
du1.removeDef(regi); //du1.numRegsDef--;
|
|
//du.def &= maskDuReg[regi];
|
|
du.def.clrReg(regi);
|
|
}
|
|
return false;
|
|
}
|
|
HLTYPE LLInst::createCall()
|
|
{
|
|
HLTYPE res(HLI_CALL);
|
|
res.call.proc = src().proc.proc;
|
|
res.call.args = new STKFRAME;
|
|
|
|
if (src().proc.cb != 0)
|
|
res.call.args->cb = src().proc.cb;
|
|
else if(res.call.proc)
|
|
res.call.args->cb =res.call.proc->cbParam;
|
|
else
|
|
{
|
|
printf("Function with no cb set, and no valid oper.call.proc , probaby indirect call\n");
|
|
res.call.args->cb = 0;
|
|
}
|
|
return res;
|
|
}
|
|
#if 0
|
|
HLTYPE LLInst::toHighLevel(COND_EXPR *lhs,COND_EXPR *rhs,Function *func)
|
|
{
|
|
HLTYPE res(HLI_INVALID);
|
|
if ( testFlags(NOT_HLL) )
|
|
return res;
|
|
flg = getFlag();
|
|
|
|
switch (getOpcode())
|
|
{
|
|
case iADD:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, ADD);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iAND:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, AND);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iCALL:
|
|
case iCALLF:
|
|
//TODO: this is noop pIcode->checkHlCall();
|
|
res=createCall();
|
|
break;
|
|
|
|
case iDEC:
|
|
rhs = AstIdent::idKte (1, 2);
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, SUB);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iDIV:
|
|
case iIDIV:/* should be signed div */
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, DIV);
|
|
if ( ll->testFlags(B) )
|
|
{
|
|
lhs = AstIdent::idReg (rAL, 0, &localId);
|
|
pIcode->setRegDU( rAL, eDEF);
|
|
}
|
|
else
|
|
{
|
|
lhs = AstIdent::idReg (rAX, 0, &localId);
|
|
pIcode->setRegDU( rAX, eDEF);
|
|
}
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iIMUL:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, MUL);
|
|
lhs = AstIdent::id (*pIcode, LHS_OP, func, i, *pIcode, NONE);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iINC:
|
|
rhs = AstIdent::idKte (1, 2);
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, ADD);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iLEA:
|
|
rhs = COND_EXPR::unary (ADDRESSOF, rhs);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMOD:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, MOD);
|
|
if ( ll->testFlags(B) )
|
|
{
|
|
lhs = AstIdent::idReg (rAH, 0, &localId);
|
|
pIcode->setRegDU( rAH, eDEF);
|
|
}
|
|
else
|
|
{
|
|
lhs = AstIdent::idReg (rDX, 0, &localId);
|
|
pIcode->setRegDU( rDX, eDEF);
|
|
}
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMOV: res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMUL:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, MUL);
|
|
lhs = AstIdent::id (*pIcode, LHS_OP, this, i, *pIcode, NONE);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iNEG:
|
|
rhs = COND_EXPR::unary (NEGATION, lhs);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iNOT:
|
|
rhs = COND_EXPR::boolOp (NULL, rhs, NOT);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iOR:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, OR);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iPOP: res.set(HLI_POP, lhs);
|
|
break;
|
|
|
|
case iPUSH: res.set(HLI_PUSH, lhs);
|
|
break;
|
|
|
|
case iRET:
|
|
case iRETF:
|
|
res.set(HLI_RET, NULL);
|
|
break;
|
|
|
|
case iSHL:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, SHL);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSAR: /* signed */
|
|
case iSHR:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, SHR); /* unsigned*/
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSIGNEX:
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSUB:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, SUB);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iXCHG:
|
|
break;
|
|
|
|
case iXOR:
|
|
rhs = COND_EXPR::boolOp (lhs, rhs, XOR);
|
|
res.setAsgn(lhs, rhs);
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
#endif
|
|
static bool needsLhs(unsigned opc)
|
|
{
|
|
switch (opc)
|
|
{
|
|
case iCALL:
|
|
case iCALLF:
|
|
case iRET:
|
|
case iRETF:
|
|
default: return false;
|
|
case iADD:
|
|
case iAND:
|
|
case iDEC:
|
|
case iDIV:
|
|
case iIDIV:/* should be signed div */
|
|
case iIMUL:
|
|
case iINC:
|
|
case iLEA:
|
|
case iMOD:
|
|
case iMOV:
|
|
case iMUL:
|
|
case iNEG:
|
|
case iNOT:
|
|
case iOR:
|
|
case iPOP:
|
|
case iPUSH:
|
|
case iSHL:
|
|
case iSAR: /* signed */
|
|
case iSHR:
|
|
case iSIGNEX:
|
|
case iSUB:
|
|
case iXCHG:
|
|
case iXOR:
|
|
return true;
|
|
}
|
|
}
|
|
/* 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()
|
|
{
|
|
size_t numIcode; /* number of icode instructions */
|
|
iICODE pIcode; /* ptr to current icode node */
|
|
Expr *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)
|
|
{
|
|
Expr *lhs=nullptr;
|
|
assert(numIcode==Icode.size());
|
|
pIcode = i; //Icode.GetIcode(i)
|
|
LLInst *ll = pIcode->ll();
|
|
LLOperand *dst_ll = ll->get(DST);
|
|
LLOperand *src_ll = ll->get(SRC);
|
|
if ( ll->testFlags(NOT_HLL) )
|
|
pIcode->invalidate();
|
|
if ((pIcode->type != LOW_LEVEL_ICODE) or not pIcode->valid() )
|
|
continue;
|
|
_flg = ll->getFlag();
|
|
if (not ll->testFlags(IM_OPS)) /* not processing IM_OPS yet */
|
|
if ( not ll->testFlags(NO_OPS) ) /* if there are opers */
|
|
{
|
|
if ( not ll->testFlags(NO_SRC) ) /* if there is src op */
|
|
rhs = AstIdent::id (*pIcode->ll(), SRC, this, i, *pIcode, NONE);
|
|
if(ll->m_dst.isSet() or (ll->getOpcode()==iMOD))
|
|
lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
|
|
}
|
|
if(ll->getOpcode()==iPUSH) {
|
|
if(ll->srcIsImmed()) {
|
|
lhs = new Constant(src_ll->opz,src_ll->byteWidth());
|
|
}
|
|
// lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
|
|
}
|
|
if(needsLhs(ll->getOpcode()))
|
|
assert(lhs!=nullptr);
|
|
switch (ll->getOpcode())
|
|
{
|
|
case iADD:
|
|
rhs = new BinaryOperator(ADD,lhs, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iAND:
|
|
rhs = BinaryOperator::And(lhs, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iCALL:
|
|
case iCALLF:
|
|
pIcode->type = HIGH_LEVEL_ICODE;
|
|
pIcode->hl( ll->createCall() );
|
|
break;
|
|
|
|
case iDEC:
|
|
rhs = new BinaryOperator(SUB,lhs, new Constant(1, 2));
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iDIV:
|
|
case iIDIV:/* should be signed div */
|
|
{
|
|
eReg v = ( dst_ll->byteWidth()==1) ? rAL:rAX;
|
|
rhs = new BinaryOperator(DIV,lhs, rhs);
|
|
lhs = new RegisterNode(LLOperand(v, dst_ll->byteWidth()), &localId);
|
|
pIcode->setRegDU( v, eDEF);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
}
|
|
break;
|
|
|
|
case iIMUL:
|
|
rhs = new BinaryOperator(MUL,lhs, rhs);
|
|
lhs = AstIdent::id (*ll, LHS_OP, this, i, *pIcode, NONE);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iINC:
|
|
rhs = new BinaryOperator(ADD,lhs, new Constant(1, 2));
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iLEA:
|
|
rhs =UnaryOperator::Create(ADDRESSOF, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMOD:
|
|
{
|
|
rhs = new BinaryOperator(MOD,lhs, rhs);
|
|
eReg lhs_reg = (dst_ll->byteWidth()==1) ? rAH : rDX;
|
|
lhs = new RegisterNode(LLOperand(lhs_reg, dst_ll->byteWidth()), &localId);
|
|
pIcode->setRegDU( lhs_reg, eDEF);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
}
|
|
break;
|
|
|
|
case iMOV:
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iMUL:
|
|
rhs = new BinaryOperator(MUL,lhs, rhs);
|
|
lhs = AstIdent::id (*ll, LHS_OP, this, i, *pIcode, NONE);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iNEG:
|
|
rhs = UnaryOperator::Create(NEGATION, lhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iNOT:
|
|
rhs = new BinaryOperator(NOT,nullptr, rhs); // TODO: change this to unary NOT ?
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iOR:
|
|
rhs = new BinaryOperator(OR,lhs, rhs);
|
|
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, nullptr);
|
|
break;
|
|
|
|
case iSHL:
|
|
rhs = new BinaryOperator(SHL,lhs, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSAR: /* signed */
|
|
case iSHR:
|
|
rhs = new BinaryOperator(SHR,lhs, rhs); /* unsigned*/
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSIGNEX: pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iSUB:
|
|
rhs = new BinaryOperator(SUB,lhs, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
|
|
case iXCHG:
|
|
break;
|
|
|
|
case iXOR:
|
|
rhs = new BinaryOperator(XOR,lhs, rhs);
|
|
pIcode->setAsgn(lhs, rhs);
|
|
break;
|
|
//TODO: default: // mostly to silence static analyzer warnings ?
|
|
// delete rhs;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
\fn COND_EXPR::inverse
|
|
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.
|
|
*/
|
|
|
|
|
|
/* Returns the string that represents the procedure call of tproc (ie. with
|
|
* actual parameters) */
|
|
QString Function::writeCall (Function * tproc, STKFRAME & args, int *numLoc)
|
|
{
|
|
//string condExp;
|
|
QString ostr;
|
|
ostr+=tproc->name+" (";
|
|
for(const STKSYM &sym : args)
|
|
{
|
|
if(sym.actual)
|
|
ostr += sym.actual->walkCondExpr(this, numLoc);
|
|
else
|
|
ostr += "";
|
|
if((&sym)!=&(args.back()))
|
|
ostr += ", ";
|
|
}
|
|
ostr += ")";
|
|
return ostr;
|
|
}
|
|
|
|
|
|
/* Displays the output of a HLI_JCOND icode. */
|
|
QString writeJcond (const HLTYPE &h, Function * pProc, int *numLoc)
|
|
{
|
|
if(h.opcode==HLI_INVALID)
|
|
{
|
|
return "if (*HLI_INVALID*) {\n";
|
|
}
|
|
|
|
assert(h.expr());
|
|
Expr *inverted=h.expr()->inverse();
|
|
//inverseCondOp (&h.exp);
|
|
QString inverted_form = inverted->walkCondExpr (pProc, numLoc);
|
|
delete inverted;
|
|
|
|
return QString("if %1 {\n").arg(inverted_form);
|
|
}
|
|
|
|
|
|
/* 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. */
|
|
QString writeJcondInv(HLTYPE h, Function * pProc, int *numLoc)
|
|
{
|
|
QString _form;
|
|
|
|
if(h.expr()==nullptr)
|
|
_form = "( *failed condition recovery* )";
|
|
else
|
|
_form = h.expr()->walkCondExpr (pProc, numLoc);
|
|
return QString("if %1 {\n").arg(_form);
|
|
}
|
|
|
|
QString AssignType::writeOut(Function *pProc, int *numLoc) const
|
|
{
|
|
return QString("%1 = %2;\n")
|
|
.arg(m_lhs->walkCondExpr (pProc, numLoc))
|
|
.arg(m_rhs->walkCondExpr (pProc, numLoc));
|
|
}
|
|
QString CallType::writeOut(Function *pProc, int *numLoc) const
|
|
{
|
|
return pProc->writeCall (proc, *args, numLoc) + ";\n";
|
|
}
|
|
QString ExpType::writeOut(Function *pProc, int *numLoc) const
|
|
{
|
|
if(v==nullptr)
|
|
return "";
|
|
return v->walkCondExpr (pProc, numLoc);
|
|
}
|
|
|
|
void HLTYPE::set(Expr *l, Expr *r)
|
|
{
|
|
assert(l);
|
|
assert(r);
|
|
opcode = HLI_ASSIGN;
|
|
//assert((asgn.lhs==0) and (asgn.rhs==0)); //prevent memory leaks
|
|
assert(dynamic_cast<UnaryOperator *>(l));
|
|
asgn.m_lhs=l;
|
|
asgn.m_rhs=r;
|
|
}
|
|
/** 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.
|
|
*/
|
|
QString HLTYPE::write1HlIcode (Function * pProc, int *numLoc) const
|
|
{
|
|
const HlTypeSupport *p = get();
|
|
switch (opcode)
|
|
{
|
|
case HLI_ASSIGN:
|
|
return p->writeOut(pProc,numLoc);
|
|
case HLI_CALL:
|
|
return p->writeOut(pProc,numLoc);
|
|
case HLI_RET:
|
|
{
|
|
QString e;
|
|
e = p->writeOut(pProc,numLoc);
|
|
if (not e.isEmpty())
|
|
return QString("return (%1);\n").arg(e);
|
|
break;
|
|
}
|
|
case HLI_POP:
|
|
return QString("HLI_POP %1\n").arg(p->writeOut(pProc,numLoc));
|
|
case HLI_PUSH:
|
|
return QString("HLI_PUSH %1\n").arg(p->writeOut(pProc,numLoc));
|
|
case HLI_JCOND: //Handled elsewhere
|
|
break;
|
|
default:
|
|
qCritical() << " HLTYPE::write1HlIcode - Unhandled opcode" << opcode;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
//TODO: replace all "< (INDEX_BX_SI-1)" with machine_x86::lastReg
|
|
|
|
//TODO: replace all >= INDEX_BX_SI with machine_x86::isRegExpression
|
|
|
|
|
|
/* Writes the registers/stack variables that are used and defined by this
|
|
* instruction. */
|
|
void ICODE::writeDU()
|
|
{
|
|
int my_idx = loc_ip;
|
|
{
|
|
QString ostr_contents;
|
|
{
|
|
QTextStream ostr(&ostr_contents);
|
|
Machine_X86::writeRegVector(ostr,du.def);
|
|
}
|
|
if (not ostr_contents.isEmpty())
|
|
qDebug() << QString("Def (reg) = %1\n").arg(ostr_contents);
|
|
}
|
|
{
|
|
QString ostr_contents;
|
|
{
|
|
QTextStream ostr(&ostr_contents);
|
|
Machine_X86::writeRegVector(ostr,du.use);
|
|
}
|
|
if (not ostr_contents.isEmpty())
|
|
qDebug() << QString("Use (reg) = %1\n").arg(ostr_contents);
|
|
}
|
|
|
|
/* Print du1 chain */
|
|
printf ("# regs defined = %d\n", du1.getNumRegsDef());
|
|
for (int i = 0; i < MAX_REGS_DEF; i++)
|
|
{
|
|
if (not du1.used(i))
|
|
continue;
|
|
printf ("%d: du1[%d][] = ", my_idx, i);
|
|
for(auto 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");
|
|
}
|