Merge remote-tracking branch 'origin/caheckman_x86parityflag'

This commit is contained in:
Ryan Kurtz 2019-12-17 11:31:26 -05:00
commit 2f1292b174
4 changed files with 175 additions and 2 deletions

View file

@ -4745,6 +4745,7 @@ void universal_action(Architecture *conf)
actprop->addRule( new RuleFloatRange("analysis") );
actprop->addRule( new RulePiece2Zext("analysis") );
actprop->addRule( new RulePiece2Sext("analysis") );
actprop->addRule( new RulePopcountBoolXor("analysis") );
actprop->addRule( new RuleSubvarAnd("subvar") );
actprop->addRule( new RuleSubvarSubpiece("subvar") );
actprop->addRule( new RuleSplitFlow("subvar") );

View file

@ -8470,3 +8470,161 @@ int4 RuleThreeWayCompare::applyOp(PcodeOp *op,Funcdata &data)
}
return 1;
}
/// \class RulePopcountBoolXor
/// \brief Simplify boolean expressions that are combined through POPCOUNT
///
/// Expressions involving boolean values (b1 and b2) are converted, such as:
/// - `popcount((b1 << 6) | (b2 << 2)) & 1 => b1 ^ b2`
void RulePopcountBoolXor::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_POPCOUNT);
}
int4 RulePopcountBoolXor::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter;
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) {
PcodeOp *baseOp = *iter;
if (baseOp->code() != CPUI_INT_AND) continue;
Varnode *tmpVn = baseOp->getIn(1);
if (!tmpVn->isConstant()) continue;
if (tmpVn->getOffset() != 1) continue; // Masking 1 bit means we are checking parity of POPCOUNT input
if (tmpVn->getSize() != 1) continue; // Must be boolean sized output
Varnode *inVn = op->getIn(0);
if (!inVn->isWritten()) return 0;
int4 count = popcount(inVn->getNZMask());
if (count == 1) {
int4 leastPos = leastsigbit_set(inVn->getNZMask());
int4 constRes;
Varnode *b1 = getBooleanResult(inVn, leastPos, constRes);
if (b1 == (Varnode *)0) continue;
data.opSetOpcode(baseOp, CPUI_COPY); // Recognized popcount( b1 << #pos ) & 1
data.opRemoveInput(baseOp, 1); // Simplify to COPY(b1)
data.opSetInput(baseOp, b1, 0);
return 1;
}
if (count == 2) {
int4 pos0 = leastsigbit_set(inVn->getNZMask());
int4 pos1 = mostsigbit_set(inVn->getNZMask());
int4 constRes0,constRes1;
Varnode *b1 = getBooleanResult(inVn, pos0, constRes0);
if (b1 == (Varnode *)0 && constRes0 != 1) continue;
Varnode *b2 = getBooleanResult(inVn, pos1, constRes1);
if (b2 == (Varnode *)0 && constRes1 != 1) continue;
if (b1 == (Varnode *)0 && b2 == (Varnode *)0) continue;
if (b1 == (Varnode *)0)
b1 = data.newConstant(1, 1);
if (b2 == (Varnode *)0)
b2 = data.newConstant(1, 1);
data.opSetOpcode(baseOp, CPUI_INT_XOR); // Recognized popcount ( b1 << #pos1 | b2 << #pos2 ) & 1
data.opSetInput(baseOp, b1, 0);
data.opSetInput(baseOp, b2, 1);
return 1;
}
}
return 0;
}
/// \brief Extract boolean Varnode producing bit at given Varnode and position
///
/// The boolean value may be shifted, extended and combined with other booleans through a
/// series of operations. We return the Varnode that is the
/// actual result of the boolean operation. If the given Varnode is constant, return
/// null but pass back whether the given bit position is 0 or 1. If no boolean value can be
/// found, return null and pass back -1.
/// \param vn is the given Varnode containing the extended/shifted boolean
/// \param bitPos is the bit position of the desired boolean value
/// \param constRes is used to pass back a constant boolean result
/// \return the boolean Varnode producing the desired value or null
Varnode *RulePopcountBoolXor::getBooleanResult(Varnode *vn,int4 bitPos,int4 &constRes)
{
constRes = -1;
uintb mask = 1;
mask <<= bitPos;
Varnode *vn0;
Varnode *vn1;
int4 sa;
for(;;) {
if (vn->isConstant()) {
constRes = (vn->getOffset() >> bitPos) & 1;
return (Varnode *)0;
}
if (!vn->isWritten()) return (Varnode *)0;
if (bitPos == 0 && vn->getSize() == 1 && vn->getNZMask() == mask)
return vn;
PcodeOp *op = vn->getDef();
switch(op->code()) {
case CPUI_INT_AND:
if (!op->getIn(1)->isConstant()) return (Varnode *)0;
vn = op->getIn(0);
break;
case CPUI_INT_XOR:
case CPUI_INT_OR:
vn0 = op->getIn(0);
vn1 = op->getIn(1);
if ((vn0->getNZMask() & mask) != 0) {
if ((vn1->getNZMask() & mask) != 0)
return (Varnode *)0; // Don't have a unique path
vn = vn0;
}
else if ((vn1->getNZMask() & mask) != 0) {
vn = vn1;
}
else
return (Varnode *)0;
break;
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
vn = op->getIn(0);
if (bitPos >= vn->getSize() * 8) return (Varnode *)0;
break;
case CPUI_SUBPIECE:
sa = (int4)op->getIn(1)->getOffset() * 8;
bitPos += sa;
mask <<= sa;
vn = op->getIn(0);
break;
case CPUI_PIECE:
vn0 = op->getIn(0);
vn1 = op->getIn(1);
sa = (int4)vn1->getSize() * 8;
if (bitPos >= sa) {
vn = vn0;
bitPos -= sa;
mask >>= sa;
}
else {
vn = vn1;
}
break;
case CPUI_INT_LEFT:
vn1 = op->getIn(1);
if (!vn1->isConstant()) return (Varnode *)0;
sa = (int4) vn1->getOffset();
if (sa > bitPos) return (Varnode *)0;
bitPos -= sa;
mask >>= sa;
vn = op->getIn(0);
break;
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
vn1 = op->getIn(1);
if (!vn1->isConstant()) return (Varnode *)0;
sa = (int4) vn1->getOffset();
vn = op->getIn(0);
bitPos += sa;
if (bitPos >= vn->getSize() * 8) return (Varnode *)0;
mask <<= sa;
break;
default:
return (Varnode *)0;
}
}
return (Varnode *)0; // Never reach here
}

View file

@ -1420,4 +1420,16 @@ public:
static int4 testCompareEquivalence(PcodeOp *lessop,PcodeOp *lessequalop);
};
class RulePopcountBoolXor : public Rule {
public:
RulePopcountBoolXor(const string &g) : Rule( g, 0, "popcountboolxor") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const {
if (!grouplist.contains(getGroup())) return (Rule *)0;
return new RulePopcountBoolXor(getGroup());
}
virtual void getOpList(vector<uint4> &oplist) const;
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
static Varnode *getBooleanResult(Varnode *vn,int4 bitPos,int4 &constRes);
};
#endif

View file

@ -1233,7 +1233,8 @@ macro subCarryFlags ( op1, op2 ) {
macro resultflags(result) {
SF = result s< 0;
ZF = result == 0;
# PF, AF not implemented
PF = popcount(result) & 1;
# AF not implemented
}
macro shiftresultflags(result,count) {
@ -1245,7 +1246,8 @@ macro shiftresultflags(result,count) {
local newZF = (result == 0);
ZF = (!notzero & ZF) | (notzero & newZF);
# PF, AF not implemented
PF = popcount(result) & 1;
# AF not implemented
}
macro subflags(op1,op2) {