Collapse double multiplies during ptrarith

This commit is contained in:
caheckman 2020-04-30 11:20:09 -04:00
parent 9802ba970e
commit 6df091eeee
3 changed files with 70 additions and 35 deletions

View file

@ -507,8 +507,9 @@ public:
void switchEdge(FlowBlock *inblock,BlockBasic *outbefore,FlowBlock *outafter); void switchEdge(FlowBlock *inblock,BlockBasic *outbefore,FlowBlock *outafter);
void spliceBlockBasic(BlockBasic *bl); ///< Merge the given basic block with the block it flows into void spliceBlockBasic(BlockBasic *bl); ///< Merge the given basic block with the block it flows into
void installSwitchDefaults(void); ///< Make sure default switch cases are properly labeled void installSwitchDefaults(void); ///< Make sure default switch cases are properly labeled
static bool replaceLessequal(Funcdata &data,PcodeOp *op); ///< Replace INT_LESSEQUAL and INT_SLESSEQUAL expressions bool replaceLessequal(PcodeOp *op); ///< Replace INT_LESSEQUAL and INT_SLESSEQUAL expressions
static bool distributeIntMult(Funcdata &data,PcodeOp *op); ///< Distribute constant coefficient to additive input bool distributeIntMultAdd(PcodeOp *op); ///< Distribute constant coefficient to additive input
bool collapseIntMultMult(Varnode *vn); ///< Collapse constant coefficients for two chained CPUI_INT_MULT
static bool compareCallspecs(const FuncCallSpecs *a,const FuncCallSpecs *b); static bool compareCallspecs(const FuncCallSpecs *a,const FuncCallSpecs *b);
#ifdef OPACTION_DEBUG #ifdef OPACTION_DEBUG

View file

@ -969,10 +969,9 @@ void Funcdata::overrideFlow(const Address &addr,uint4 type)
/// - `c <= x` with `c-1 < x` OR /// - `c <= x` with `c-1 < x` OR
/// - `x <= c` with `x < c+1` /// - `x <= c` with `x < c+1`
/// ///
/// \param data is the function being analyzed
/// \param op is comparison PcodeOp /// \param op is comparison PcodeOp
/// \return true if a valid replacement was performed /// \return true if a valid replacement was performed
bool Funcdata::replaceLessequal(Funcdata &data,PcodeOp *op) bool Funcdata::replaceLessequal(PcodeOp *op)
{ {
Varnode *vn; Varnode *vn;
@ -995,17 +994,17 @@ bool Funcdata::replaceLessequal(Funcdata &data,PcodeOp *op)
if (op->code() == CPUI_INT_SLESSEQUAL) { if (op->code() == CPUI_INT_SLESSEQUAL) {
if ((val<0)&&(val+diff>0)) return false; // Check for sign overflow if ((val<0)&&(val+diff>0)) return false; // Check for sign overflow
if ((val>0)&&(val+diff<0)) return false; if ((val>0)&&(val+diff<0)) return false;
data.opSetOpcode(op,CPUI_INT_SLESS); opSetOpcode(op,CPUI_INT_SLESS);
} }
else { // Check for unsigned overflow else { // Check for unsigned overflow
if ((diff==-1)&&(val==0)) return false; if ((diff==-1)&&(val==0)) return false;
if ((diff==1)&&(val==-1)) return false; if ((diff==1)&&(val==-1)) return false;
data.opSetOpcode(op,CPUI_INT_LESS); opSetOpcode(op,CPUI_INT_LESS);
} }
uintb res = (val+diff) & calc_mask(vn->getSize()); uintb res = (val+diff) & calc_mask(vn->getSize());
Varnode *newvn = data.newConstant(vn->getSize(),res); Varnode *newvn = newConstant(vn->getSize(),res);
newvn->copySymbol(vn); // Preserve data-type (and any Symbol info) newvn->copySymbol(vn); // Preserve data-type (and any Symbol info)
data.opSetInput(op,newvn,i); opSetInput(op,newvn,i);
return true; return true;
} }
@ -1013,10 +1012,9 @@ bool Funcdata::replaceLessequal(Funcdata &data,PcodeOp *op)
/// in some situations we may need to distribute the coefficient before simplifying further. /// in some situations we may need to distribute the coefficient before simplifying further.
/// The given PcodeOp is a INT_MULT where the second input is a constant. We also /// The given PcodeOp is a INT_MULT where the second input is a constant. We also
/// know the first input is formed with INT_ADD. Distribute the coefficient to the INT_ADD inputs. /// know the first input is formed with INT_ADD. Distribute the coefficient to the INT_ADD inputs.
/// \param data is the function being analyzed
/// \param op is the given PcodeOp /// \param op is the given PcodeOp
/// \return \b truee if the action was performed /// \return \b true if the action was performed
bool Funcdata::distributeIntMult(Funcdata &data,PcodeOp *op) bool Funcdata::distributeIntMultAdd(PcodeOp *op)
{ {
Varnode *newvn0,*newvn1; Varnode *newvn0,*newvn1;
@ -1031,40 +1029,73 @@ bool Funcdata::distributeIntMult(Funcdata &data,PcodeOp *op)
if (vn0->isConstant()) { if (vn0->isConstant()) {
uintb val = coeff * vn0->getOffset(); uintb val = coeff * vn0->getOffset();
val &= calc_mask(size); val &= calc_mask(size);
newvn0 = data.newConstant(size,val); newvn0 = newConstant(size,val);
} }
else { else {
PcodeOp *newop0 = data.newOp(2,op->getAddr()); PcodeOp *newop0 = newOp(2,op->getAddr());
data.opSetOpcode(newop0,CPUI_INT_MULT); opSetOpcode(newop0,CPUI_INT_MULT);
newvn0 = data.newUniqueOut(size,newop0); newvn0 = newUniqueOut(size,newop0);
data.opSetInput(newop0, vn0, 0); // To first input of original add opSetInput(newop0, vn0, 0); // To first input of original add
Varnode *newcvn = data.newConstant(size,coeff); Varnode *newcvn = newConstant(size,coeff);
data.opSetInput(newop0, newcvn, 1); opSetInput(newop0, newcvn, 1);
data.opInsertBefore(newop0, op); opInsertBefore(newop0, op);
} }
if (vn1->isConstant()) { if (vn1->isConstant()) {
uintb val = coeff * vn1->getOffset(); uintb val = coeff * vn1->getOffset();
val &= calc_mask(size); val &= calc_mask(size);
newvn1 = data.newConstant(size,val); newvn1 = newConstant(size,val);
} }
else { else {
PcodeOp *newop1 = data.newOp(2,op->getAddr()); PcodeOp *newop1 = newOp(2,op->getAddr());
data.opSetOpcode(newop1,CPUI_INT_MULT); opSetOpcode(newop1,CPUI_INT_MULT);
newvn1 = data.newUniqueOut(size,newop1); newvn1 = newUniqueOut(size,newop1);
data.opSetInput(newop1, vn1, 0); // To second input of original add opSetInput(newop1, vn1, 0); // To second input of original add
Varnode *newcvn = data.newConstant(size,coeff); Varnode *newcvn = newConstant(size,coeff);
data.opSetInput(newop1, newcvn, 1); opSetInput(newop1, newcvn, 1);
data.opInsertBefore(newop1, op); opInsertBefore(newop1, op);
} }
data.opSetInput( op, newvn0, 0); // new ADD's inputs are outputs of new MULTs opSetInput( op, newvn0, 0); // new ADD's inputs are outputs of new MULTs
data.opSetInput( op, newvn1, 1); opSetInput( op, newvn1, 1);
data.opSetOpcode(op, CPUI_INT_ADD); opSetOpcode(op, CPUI_INT_ADD);
return true; return true;
} }
/// If:
/// - The given Varnode is defined by a CPUI_INT_MULT.
/// - The second input to the INT_MULT is a constant.
/// - The first input is defined by another CPUI_INT_MULT,
/// - This multiply is also by a constant.
///
/// The constants are combined and \b true is returned.
/// Otherwise no change is made and \b false is returned.
/// \param vn is the given Varnode
/// \return \b true if a change was made
bool Funcdata::collapseIntMultMult(Varnode *vn)
{
if (!vn->isWritten()) return false;
PcodeOp *op = vn->getDef();
if (op->code() != CPUI_INT_MULT) return false;
Varnode *constVnFirst = op->getIn(1);
if (!constVnFirst->isConstant()) return false;
if (!op->getIn(0)->isWritten()) return false;
PcodeOp *otherMultOp = op->getIn(0)->getDef();
if (otherMultOp->code() != CPUI_INT_MULT) return false;
Varnode *constVnSecond = otherMultOp->getIn(1);
if (!constVnSecond->isConstant()) return false;
Varnode *invn = otherMultOp->getIn(0);
if (invn->isFree()) return false;
int4 size = invn->getSize();
uintb val = (constVnFirst->getOffset() * constVnSecond->getOffset()) & calc_mask(size);
Varnode *newvn = newConstant(size,val);
opSetInput(op,newvn,1);
opSetInput(op,invn,0);
return true;
}
/// \brief Trace a boolean value to a set of PcodeOps that can be changed to flip the boolean value /// \brief Trace a boolean value to a set of PcodeOps that can be changed to flip the boolean value
/// ///
/// The boolean Varnode is either the output of the given PcodeOp or the /// The boolean Varnode is either the output of the given PcodeOp or the
@ -1162,7 +1193,7 @@ void opFlipInPlaceExecute(Funcdata &data,vector<PcodeOp *> &fliplist)
data.opSwapInput(op,0,1); data.opSwapInput(op,0,1);
if ((opc == CPUI_INT_LESSEQUAL)||(opc == CPUI_INT_SLESSEQUAL)) if ((opc == CPUI_INT_LESSEQUAL)||(opc == CPUI_INT_SLESSEQUAL))
Funcdata::replaceLessequal(data,op); data.replaceLessequal(op);
} }
} }
} }

View file

@ -126,9 +126,9 @@ int4 RuleCollectTerms::applyOp(PcodeOp *op,Funcdata &data)
vn2 = getMultCoeff(vn2,coef2); vn2 = getMultCoeff(vn2,coef2);
if (vn1 == vn2) { // Terms that can be combined if (vn1 == vn2) { // Terms that can be combined
if (order[i-1]->getMultiplier() != (PcodeOp *)0) if (order[i-1]->getMultiplier() != (PcodeOp *)0)
return Funcdata::distributeIntMult(data,order[i-1]->getMultiplier()) ? 1 : 0; return data.distributeIntMultAdd(order[i-1]->getMultiplier()) ? 1 : 0;
if (order[i]->getMultiplier() != (PcodeOp *)0) if (order[i]->getMultiplier() != (PcodeOp *)0)
return Funcdata::distributeIntMult(data,order[i]->getMultiplier()) ? 1 : 0; return data.distributeIntMultAdd(order[i]->getMultiplier()) ? 1 : 0;
coef1 = (coef1 + coef2) & calc_mask(vn1->getSize()); // The new coefficient coef1 = (coef1 + coef2) & calc_mask(vn1->getSize()); // The new coefficient
Varnode *newcoeff = data.newConstant(vn1->getSize(),coef1); Varnode *newcoeff = data.newConstant(vn1->getSize(),coef1);
Varnode *zerocoeff = data.newConstant(vn1->getSize(),0); Varnode *zerocoeff = data.newConstant(vn1->getSize(),0);
@ -609,7 +609,7 @@ void RuleIntLessEqual::getOpList(vector<uint4> &oplist) const
int4 RuleIntLessEqual::applyOp(PcodeOp *op,Funcdata &data) int4 RuleIntLessEqual::applyOp(PcodeOp *op,Funcdata &data)
{ {
if (Funcdata::replaceLessequal(data,op)) if (data.replaceLessequal(op))
return 1; return 1;
return 0; return 0;
} }
@ -5917,10 +5917,13 @@ bool AddTreeState::apply(void)
calcSubtype(); calcSubtype();
if (!valid) return false; if (!valid) return false;
while(valid && distributeOp != (PcodeOp *)0) { while(valid && distributeOp != (PcodeOp *)0) {
if (!Funcdata::distributeIntMult(data, distributeOp)) { if (!data.distributeIntMultAdd(distributeOp)) {
valid = false; valid = false;
break; break;
} }
// Collapse any z = (x * #c) * #d expressions produced by the distribute
data.collapseIntMultMult(distributeOp->getIn(0));
data.collapseIntMultMult(distributeOp->getIn(1));
clear(); clear();
spanAddTree(baseOp,1); spanAddTree(baseOp,1);
if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) { if (distributeOp != (PcodeOp *)0 && !isDistributeUsed) {