mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +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
|
@ -10125,3 +10125,63 @@ int4 RuleXorSwap::applyOp(PcodeOp *op,Funcdata &data)
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue