An optimized division corner case

This commit is contained in:
caheckman 2020-08-04 15:25:21 -04:00
parent 90f6b5c7e5
commit 77b1a6bf4b
3 changed files with 89 additions and 15 deletions

View file

@ -6970,7 +6970,12 @@ Varnode *RuleDivOpt::findForm(PcodeOp *op,int4 &n,uintb &y,int4 &xsize,OpCode &e
if (curOp->code() != CPUI_INT_MULT) return (Varnode *)0; // There MUST be an INT_MULT
Varnode *inVn = curOp->getIn(0);
if (!inVn->isWritten()) return (Varnode *)0;
if (curOp->getIn(1)->isConstantExtended(y) < 0) return (Varnode *)0; // There MUST be a constant
if (inVn->isConstantExtended(y) >= 0) {
inVn = curOp->getIn(1);
if (!inVn->isWritten()) return (Varnode *)0;
}
else if (curOp->getIn(1)->isConstantExtended(y) < 0)
return (Varnode *)0; // There MUST be a constant
Varnode *resVn;
PcodeOp *extOp = inVn->getDef();
@ -7062,29 +7067,81 @@ uintb RuleDivOpt::calcDivisor(uintb n,uint8 y,int4 xsize)
/// - `V >> 0x1f`
/// - `V s>> 0x1f`
///
/// Allow for the value to be COPYed around.
/// \param firstVn is the first given Varnode
/// \param replaceVn is the Varnode to replace it with in each extraction
/// \param data is the function holding the Varnodes
void RuleDivOpt::moveSignBitExtraction(Varnode *firstVn,Varnode *replaceVn,Funcdata &data)
{
list<PcodeOp *>::const_iterator iter = firstVn->beginDescend();
while(iter!=firstVn->endDescend()) {
PcodeOp *op = *iter;
++iter; // Increment before modifying the op
OpCode opc = op->code();
if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) {
Varnode *constVn = op->getIn(1);
if (constVn->isConstant()) {
int4 sa = firstVn->getSize() * 8 - 1;
if (sa == (int4)constVn->getOffset()) {
data.opSetInput(op,replaceVn,0);
vector<Varnode *> testList;
testList.push_back(firstVn);
if (firstVn->isWritten()) {
PcodeOp *op = firstVn->getDef();
if (op->code() == CPUI_INT_SRIGHT) {
// Same sign bit could be extracted from previous shifted version
testList.push_back(op->getIn(0));
}
}
for(int4 i=0;i<testList.size();++i) {
Varnode *vn = testList[i];
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while(iter!=vn->endDescend()) {
PcodeOp *op = *iter;
++iter; // Increment before modifying the op
OpCode opc = op->code();
if (opc == CPUI_INT_RIGHT || opc == CPUI_INT_SRIGHT) {
Varnode *constVn = op->getIn(1);
if (constVn->isWritten()) {
PcodeOp *constOp = constVn->getDef();
if (constOp->code() == CPUI_COPY)
constVn = constOp->getIn(0);
else if (constOp->code() == CPUI_INT_AND) {
constVn = constOp->getIn(0);
Varnode *otherVn = constOp->getIn(1);
if (!otherVn->isConstant()) continue;
if (constVn->getOffset() != (constVn->getOffset() & otherVn->getOffset())) continue;
}
}
if (constVn->isConstant()) {
int4 sa = firstVn->getSize() * 8 - 1;
if (sa == (int4)constVn->getOffset()) {
data.opSetInput(op,replaceVn,0);
}
}
}
else if (opc == CPUI_COPY) {
testList.push_back(op->getOut());
}
}
}
}
/// A form ending in a SUBPIECE, may be contained in a working form ending at
/// the SUBPIECE followed by INT_SRIGHT. The containing form would supersede.
/// \param op is the root of the form to check
/// \return \b true if it is (possibly) contained in a superseding form
bool RuleDivOpt::checkFormOverlap(PcodeOp *op)
{
if (op->code() != CPUI_SUBPIECE) return false;
Varnode *vn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *superOp = *iter;
OpCode opc = superOp->code();
if (opc != CPUI_INT_RIGHT && opc != CPUI_INT_SRIGHT) continue;
Varnode *cvn = superOp->getIn(1);
if (!cvn->isConstant()) return true; // Might be a form where constant has propagated yet
int4 n,xsize;
uintb y;
OpCode extopc;
Varnode *inVn = findForm(superOp, n, y, xsize, extopc);
if (inVn != (Varnode *)0) return true;
}
return false;
}
/// \class RuleDivOpt
/// \brief Convert INT_MULT and shift forms into INT_DIV or INT_SDIV
///
@ -7107,6 +7164,7 @@ int4 RuleDivOpt::applyOp(PcodeOp *op,Funcdata &data)
OpCode extOpc;
Varnode *inVn = findForm(op,n,y,xsize,extOpc);
if (inVn == (Varnode *)0) return 0;
if (checkFormOverlap(op)) return 0;
if (extOpc == CPUI_INT_SEXT)
xsize -= 1; // one less bit for signed, because of signbit
uintb divisor = calcDivisor(n,y,xsize);