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)
{
Varnode *base,*vn,*newvn,*outvn;
PcodeOp *longform,*newsub,*prevop;
int4 i,j,offset,insize;
base = op->getIn(0);
Varnode *base = op->getIn(0);
if (!base->isWritten()) return 0;
offset = op->getIn(1)->getOffset();
outvn = op->getOut();
int4 offset = op->getIn(1)->getOffset();
Varnode *outvn = op->getOut();
if (outvn->isPrecisLo()||outvn->isPrecisHi()) return 0;
insize = base->getSize();
longform = base->getDef();
j = -1;
int4 insize = base->getSize();
PcodeOp *longform = base->getDef();
int4 j = -1;
switch( longform->code() ) { // Determine if this op commutes with SUBPIECE
// case CPUI_COPY:
case CPUI_INT_LEFT:
j = 1; // Special processing for shift amount param
if (offset != 0) return 0;
if (!longform->getIn(0)->isWritten()) return 0;
prevop = longform->getIn(0)->getDef();
if (prevop->code()==CPUI_INT_ZEXT) {
}
else if (prevop->code()==CPUI_PIECE) {
if (longform->getIn(0)->isWritten()) {
OpCode opc = longform->getIn(0)->getDef()->code();
if (opc != CPUI_INT_ZEXT && opc != CPUI_PIECE)
return 0;
}
else
return 0;
@ -4558,17 +4553,24 @@ int4 RuleSubCommute::applyOp(PcodeOp *op,Funcdata &data)
}
}
for(i=0;i<longform->numInput();++i) {
vn = longform->getIn(i);
Varnode *lastIn = (Varnode *)0;
Varnode *newVn = (Varnode *)0;
for(int4 i=0;i<longform->numInput();++i) {
Varnode *vn = longform->getIn(i);
if (i!=j) {
newsub = data.newOp(2,op->getAddr()); // Commuted SUBPIECE op
data.opSetOpcode(newsub,CPUI_SUBPIECE);
newvn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is subpiece
data.opSetInput(longform,newvn,i);
data.opSetInput(newsub,vn,0); // of old varnode
data.opSetInput(newsub,data.newConstant(4,offset),1);
data.opInsertBefore(newsub,longform);
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);
newVn = data.newUniqueOut(outvn->getSize(),newsub); // New varnode is SUBPIECE of old varnode
data.opSetInput(longform,newVn,i);
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.opInsertBefore(newsub,longform);
}
else
data.opSetInput(longform,newVn,i);
}
lastIn = vn;
}
data.opSetOutput(longform,outvn);
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;
hcount += 1;
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:
if ((rvn->mask & 1)==0)
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;
}
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:
sa = (int4)op->getIn(1)->getOffset() * 8;
newmask = rvn->mask << sa;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -940,6 +940,22 @@ bool Varnode::isBooleanValue(bool useAnnotation) const
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
/// 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
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 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 findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const;
bool findPieceShadow(int4 leastByte,const Varnode *piece) const;