GP-2957 Sub-flow through INT_DIV and INT_REM

This commit is contained in:
caheckman 2024-09-20 15:56:02 +00:00
parent 16388dc261
commit 8847d2a6b9
4 changed files with 65 additions and 26 deletions

View file

@ -4439,28 +4439,23 @@ bool RuleSubCommute::cancelExtensions(PcodeOp *longform,PcodeOp *subOp,Varnode *
int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data) int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data)
{ {
Varnode *base,*vn,*newvn,*outvn; Varnode *base = op->getIn(0);
PcodeOp *longform,*newsub,*prevop;
int4 i,j,offset,insize;
base = op->getIn(0);
if (!base->isWritten()) return 0; if (!base->isWritten()) return 0;
offset = op->getIn(1)->getOffset(); int4 offset = op->getIn(1)->getOffset();
outvn = op->getOut(); Varnode *outvn = op->getOut();
if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0; if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0;
insize = base->getSize(); int4 insize = base->getSize();
longform = base->getDef(); PcodeOp *longform = base->getDef();
j = -1; int4 j = -1;
switch( longform->code() ) { // Determine if this op commutes with SUBPIECE switch( longform->code() ) { // Determine if this op commutes with SUBPIECE
// case CPUI_COPY: // case CPUI_COPY:
case CPUI_INT_LEFT: case CPUI_INT_LEFT:
j = 1; // Special processing for shift amount param j = 1; // Special processing for shift amount param
if (offset != 0) return 0; if (offset != 0) return 0;
if (!longform->getIn(0)->isWritten()) return 0; if (longform->getIn(0)->isWritten()) {
prevop = longform->getIn(0)->getDef(); OpCode opc = longform->getIn(0)->getDef()->code();
if (prevop->code()==CPUI_INT_ZEXT) { if (opc != CPUI_INT_ZEXT && opc != CPUI_PIECE)
} return 0;
else if (prevop->code()==CPUI_PIECE) {
} }
else else
return 0; return 0;
@ -4558,17 +4553,24 @@ int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data)
} }
} }
for(i=0;i<longform->numInput();++i) { Varnode *lastIn = (Varnode *)0;
vn = longform->getIn(i); Varnode *newVn = (Varnode *)0;
for(int4 i=0;i<longform->numInput();++i) {
Varnode *vn = longform->getIn(i);
if (i!=j) { if (i!=j) {
newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op if (lastIn != vn || newVn == (Varnode *)0) { // Don't duplicate the SUBPIECE if inputs are the same
PcodeOp *newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op
data.opSetOpcode(newsub,CPUI_SUBPIECE); data.opSetOpcode(newsub,CPUI_SUBPIECE);
newvn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is subpiece newVn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is SUBPIECE of old varnode
data.opSetInput(longform,newvn,i); data.opSetInput(longform,newVn,i);
data.opSetInput(newsub,vn,0); // of old varnode data.opSetInput(newsub,vn,0); // vn may be free, so set as input after setting newVn
data.opSetInput(newsub,data.newConstant(4,offset),1); data.opSetInput(newsub,data.newConstant(4,offset),1);
data.opInsertBefore(newsub,longform); data.opInsertBefore(newsub,longform);
} }
else
data.opSetInput(longform,newVn,i);
}
lastIn = vn;
} }
data.opSetOutput(longform,outvn); data.opSetOutput(longform,outvn);
data.opDestroy(op); // Get rid of old SUBPIECE data.opDestroy(op); // Get rid of old SUBPIECE

View file

@ -443,6 +443,16 @@ bool SubvariableFlow::traceForward(ReplaceVarnode *rvn)
if (!createLink(rop,rvn->mask<<sa,-1,outvn)) return false; if (!createLink(rop,rvn->mask<<sa,-1,outvn)) return false;
hcount += 1; hcount += 1;
break; break;
case CPUI_INT_DIV:
case CPUI_INT_REM:
if ((rvn->mask & 1)==0) return false; // Logical value must be least sig bits
if ((bitsize & 7)!=0) return false; // Must be a whole number of bytes
if (!op->getIn(0)->isZeroExtended(flowsize)) return false;
if (!op->getIn(1)->isZeroExtended(flowsize)) return false;
rop = createOpDown(op->code(),2,op,rvn,slot);
if (!createLink(rop,rvn->mask,-1,outvn)) return false;
hcount += 1;
break;
case CPUI_INT_ADD: case CPUI_INT_ADD:
if ((rvn->mask & 1)==0) if ((rvn->mask & 1)==0)
return false; // Cannot account for carry return false; // Cannot account for carry
@ -768,6 +778,16 @@ bool SubvariableFlow::traceBackward(ReplaceVarnode *rvn)
if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false; if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false;
} }
return true; return true;
case CPUI_INT_DIV:
case CPUI_INT_REM:
if ((rvn->mask & 1) == 0) return false;
if ((bitsize & 7)!=0) return false; // Must be a whole number of bytes
if (!op->getIn(0)->isZeroExtended(flowsize)) return false;
if (!op->getIn(1)->isZeroExtended(flowsize)) return false;
rop = createOp(op->code(),2,rvn);
if (!createLink(rop,rvn->mask,0,op->getIn(0))) return false;
if (!createLink(rop,rvn->mask,1,op->getIn(1))) return false;
return true;
case CPUI_SUBPIECE: case CPUI_SUBPIECE:
sa = (int4)op->getIn(1)->getOffset() * 8; sa = (int4)op->getIn(1)->getOffset() * 8;
newmask = rvn->mask << sa; newmask = rvn->mask << sa;

View file

@ -940,6 +940,22 @@ bool Varnode::isBooleanValue(bool useAnnotation) const
return false; return false;
} }
/// If we can prove that the upper bits of \b this are zero, return \b true.
/// \param baseSize is the maximum number of least significant bytes that are allowed to be non-zero
/// \return \b true if all the most significant bytes are zero
bool Varnode::isZeroExtended(int4 baseSize) const
{
if (baseSize >= size) return false;
if (size > sizeof(uintb)) {
if (!isWritten()) return false;
if (def->code() != CPUI_INT_ZEXT) return false;
if (def->getIn(0)->getSize() > baseSize) return false;
return true;
}
uintb mask = nzm >> 8*baseSize;
return (mask == 0);
}
/// Make a local determination if \b this and \b op2 hold the same value. We check if /// Make a local determination if \b this and \b op2 hold the same value. We check if
/// there is a common ancester for which both \b this and \b op2 are created from a direct /// there is a common ancester for which both \b this and \b op2 are created from a direct

View file

@ -340,6 +340,7 @@ public:
void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches void copySymbolIfValid(const Varnode *vn); ///< Copy symbol info from \b vn if constant value matches
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value
bool isZeroExtended(int4 baseSize) const; ///< Is \b this zero extended from something of the given size
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source? bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
bool findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const; bool findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const;
bool findPieceShadow(int4 leastByte,const Varnode *piece) const; bool findPieceShadow(int4 leastByte,const Varnode *piece) const;