mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
Add rule to simplify lzcount followed by right shift
This commit is contained in:
parent
14880b53c4
commit
e4ab760242
3 changed files with 71 additions and 0 deletions
|
@ -5386,6 +5386,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||||
actprop->addRule( new RulePopcountBoolXor("analysis") );
|
actprop->addRule( new RulePopcountBoolXor("analysis") );
|
||||||
actprop->addRule( new RuleOrMultiBool("analysis") );
|
actprop->addRule( new RuleOrMultiBool("analysis") );
|
||||||
actprop->addRule( new RuleXorSwap("analysis") );
|
actprop->addRule( new RuleXorSwap("analysis") );
|
||||||
|
actprop->addRule( new RuleLzcountShiftBool("analysis") );
|
||||||
actprop->addRule( new RuleSubvarAnd("subvar") );
|
actprop->addRule( new RuleSubvarAnd("subvar") );
|
||||||
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
actprop->addRule( new RuleSubvarSubpiece("subvar") );
|
||||||
actprop->addRule( new RuleSplitFlow("subvar") );
|
actprop->addRule( new RuleSplitFlow("subvar") );
|
||||||
|
|
|
@ -10125,3 +10125,63 @@ int4 RuleXorSwap::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \class RuleLzcountShiftBool
|
||||||
|
/// \brief Simplify equality checks that use lzcount.
|
||||||
|
///
|
||||||
|
/// Some compilers check if a value is equal to zero by checking the most
|
||||||
|
/// significant bit in lzcount; for instance on a 32-bit system,
|
||||||
|
/// it being equal to 32 would have the 5th bit set.
|
||||||
|
/// - `lzcount(a ^ 3) >> 5 => a ^ 3 == 0 => a == 3` (by RuleXorCollapse)
|
||||||
|
/// - `lzcount(a - 3) >> 5 => a - 3 == 0 => a == 3` (by RuleEqual2Zero)
|
||||||
|
void RuleLzcountShiftBool::getOpList(vector<uint4> &oplist) const
|
||||||
|
|
||||||
|
{
|
||||||
|
oplist.push_back(CPUI_LZCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int4 RuleLzcountShiftBool::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *outVn = op->getOut();
|
||||||
|
list<PcodeOp *>::const_iterator iter, iter2;
|
||||||
|
uintb max_return = 8 * op->getIn(0)->getSize();
|
||||||
|
if (popcount(max_return) != 1) {
|
||||||
|
// This rule only makes sense with sizes that are powers of 2; if the maximum value
|
||||||
|
// returned by lzcount was, say, 24, then both 16 >> 4 and 24 >> 4
|
||||||
|
// are 1, and thus the check does not make sense. (Such processors couldn't
|
||||||
|
// use lzcount for checking equality in any case.)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
|
||||||
|
PcodeOp *baseOp = *iter;
|
||||||
|
if (baseOp->code() != CPUI_INT_RIGHT && baseOp->code() != CPUI_INT_SRIGHT) continue;
|
||||||
|
Varnode *vn1 = baseOp->getIn(1);
|
||||||
|
if (!vn1->isConstant()) continue;
|
||||||
|
uintb shift = vn1->getOffset();
|
||||||
|
if ((max_return >> shift) == 1) {
|
||||||
|
// Becomes a comparison with zero
|
||||||
|
PcodeOp* newOp = data.newOp(2, baseOp->getAddr());
|
||||||
|
data.opSetOpcode(newOp, CPUI_INT_EQUAL);
|
||||||
|
Varnode* b = data.newConstant(op->getIn(0)->getSize(), 0);
|
||||||
|
data.opSetInput(newOp, op->getIn(0), 0);
|
||||||
|
data.opSetInput(newOp, b, 1);
|
||||||
|
|
||||||
|
// CPUI_INT_EQUAL must produce a 1-byte boolean result
|
||||||
|
Varnode* eqResVn = data.newUniqueOut(1, newOp);
|
||||||
|
data.opSetOutput(newOp, eqResVn);
|
||||||
|
|
||||||
|
data.opInsertBefore(newOp, baseOp);
|
||||||
|
|
||||||
|
// Because the old output had size op->getIn(0)->getSize(),
|
||||||
|
// we have to guarantee that a Varnode of this size gets outputted
|
||||||
|
// to the descending PcodeOps. This is handled here with CPUI_INT_ZEXT.
|
||||||
|
data.opRemoveInput(baseOp, 1);
|
||||||
|
data.opSetOpcode(baseOp, CPUI_INT_ZEXT);
|
||||||
|
data.opSetInput(baseOp, eqResVn, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1585,4 +1585,14 @@ public:
|
||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RuleLzcountShiftBool : public Rule {
|
||||||
|
public:
|
||||||
|
RuleLzcountShiftBool(const string &g) : Rule( g, 0, "lzcountshiftbool") {} ///< Constructor
|
||||||
|
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||||
|
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||||
|
return new RuleLzcountShiftBool(getGroup());
|
||||||
|
}
|
||||||
|
virtual void getOpList(vector<uint4> &oplist) const;
|
||||||
|
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue