#include "condexe.hh"
ConditionMarker::ConditionMarker(void)
{
initop = (PcodeOp *)0;
basevn = (Varnode *)0;
boolvn = (Varnode *)0;
bool2vn = (Varnode *)0;
bool3vn = (Varnode *)0;
binaryop = (PcodeOp *)0;
}
ConditionMarker::~ConditionMarker(void)
{
basevn->clearMark();
if (boolvn != (Varnode *)0)
boolvn->clearMark();
if (bool2vn != (Varnode *)0)
bool2vn->clearMark();
if (bool3vn != (Varnode *)0)
bool3vn->clearMark();
if (binaryop != (PcodeOp *)0) {
binaryop->getIn(0)->clearMark();
binaryop->getIn(1)->clearMark();
}
}
void ConditionMarker::setupInitOp(PcodeOp *op)
{
initop = op;
basevn = op->getIn(1);
Varnode *curvn = basevn;
curvn->setMark();
if (curvn->isWritten()) {
PcodeOp *tmp = curvn->getDef();
if (tmp->code() == CPUI_BOOL_NEGATE) {
boolvn = tmp->getIn(0);
curvn = boolvn;
curvn->setMark();
}
}
if (curvn->isWritten()) {
PcodeOp *tmp = curvn->getDef();
if (tmp->isBoolOutput()&&(tmp->getEvalType()==PcodeOp::binary)) {
binaryop = tmp;
Varnode *binvn = binaryop->getIn(0);
if (!binvn->isConstant()) {
if (binvn->isWritten()) {
PcodeOp *negop = binvn->getDef();
if (negop->code() == CPUI_BOOL_NEGATE) {
if (!negop->getIn(0)->isConstant()) {
bool2vn = negop->getIn(0);
bool2vn->setMark();
}
}
}
binvn->setMark();
}
binvn = binaryop->getIn(1);
if (!binvn->isConstant()) {
if (binvn->isWritten()) {
PcodeOp *negop = binvn->getDef();
if (negop->code() == CPUI_BOOL_NEGATE) {
if (!negop->getIn(0)->isConstant()) {
bool3vn = negop->getIn(0);
bool3vn->setMark();
}
}
}
binvn->setMark();
}
}
}
}
Varnode *ConditionMarker::findMatch(PcodeOp *op)
{
PcodeOp *curop;
state = 0;
Varnode *curvn = op->getIn(1);
multion = false;
binon = false;
matchflip = op->isBooleanFlip();
for(;;) {
if (curvn->isMark()) return curvn;
bool popstate = true;
if (curvn->isWritten()) {
curop = curvn->getDef();
if (curop->code() == CPUI_BOOL_NEGATE) {
curvn = curop->getIn(0);
if (!binon) matchflip = !matchflip;
popstate = false;
}
else if (curop->isBoolOutput()&&(curop->getEvalType()==PcodeOp::binary)) {
if (!binon) {
opstate[state] = curop;
slotstate[state] = 0;
flipstate[state] = matchflip;
state += 1;
curvn = curop->getIn(0);
binon = true;
popstate = false;
}
}
}
if (popstate) {
while(state > 0) {
curop = opstate[state-1];
matchflip = flipstate[state-1];
slotstate[state-1] += 1;
if (slotstate[state-1] < curop->numInput()) {
curvn = curop->getIn(slotstate[state-1]);
break;
}
state -= 1;
if (opstate[state]->code() == CPUI_MULTIEQUAL)
multion = false;
else
binon = false;
}
if (state==0) break;
}
}
return (Varnode *)0;
}
bool ConditionMarker::varnodeSame(Varnode *a,Varnode *b)
{
if (a == b) return true;
if (a->isConstant() && b->isConstant())
return (a->getOffset() == b->getOffset());
return false;
}
bool ConditionMarker::varnodeComplement(Varnode *a,Varnode *b)
{
if (a->isConstant() && b->isConstant()) {
uintb vala = a->getOffset();
uintb valb = b->getOffset();
if ((vala==0)&&(valb==1)) return true;
if ((vala==1)&&(valb==0)) return true;
return false;
}
PcodeOp *negop;
if (a->isWritten()) {
negop = a->getDef();
if (negop->code() == CPUI_BOOL_NEGATE)
if (negop->getIn(0) == b)
return true;
}
if (b->isWritten()) {
negop = b->getDef();
if (negop->code() == CPUI_BOOL_NEGATE)
if (negop->getIn(0) == a)
return true;
}
return false;
}
bool ConditionMarker::sameOpComplement(PcodeOp *bin1op,PcodeOp *bin2op)
{
OpCode opcode = bin1op->code();
if ((opcode == CPUI_INT_SLESS)||(opcode==CPUI_INT_LESS)) {
int4 constslot = 0;
if (bin1op->getIn(1)->isConstant())
constslot = 1;
if (!bin1op->getIn(constslot)->isConstant()) return false;
if (!bin2op->getIn(1-constslot)->isConstant()) return false;
if (!varnodeSame(bin1op->getIn(1-constslot),bin2op->getIn(constslot))) return false;
uintb val1 = bin1op->getIn(constslot)->getOffset();
uintb val2 = bin2op->getIn(1-constslot)->getOffset();
if (constslot!=0) {
uintb tmp = val2;
val2 = val1;
val1 = tmp;
}
if (val1 + 1 != val2) return false;
if ((val2 == 0)&&(opcode==CPUI_INT_LESS)) return false; if (opcode==CPUI_INT_SLESS) { int4 sz = bin1op->getIn(constslot)->getSize();
if (signbit_negative(val2,sz) && (!signbit_negative(val1,sz)))
return false;
}
return true;
}
return false;
}
bool ConditionMarker::andOrComplement(PcodeOp *bin1op,PcodeOp *bin2op)
{
if (bin1op->code() == CPUI_BOOL_AND) {
if (bin2op->code() != CPUI_BOOL_OR) return false;
}
else if (bin1op->code() == CPUI_BOOL_OR) {
if (bin2op->code() != CPUI_BOOL_AND) return false;
}
else
return false;
if (varnodeComplement( bin1op->getIn(0), bin2op->getIn(0))) {
if (varnodeComplement( bin1op->getIn(1), bin2op->getIn(1)))
return true;
}
else if (varnodeComplement( bin1op->getIn(0), bin2op->getIn(1))) {
if (varnodeComplement( bin1op->getIn(1), bin2op->getIn(0)))
return true;
}
return false;
}
bool ConditionMarker::finalJudgement(Varnode *vn)
{
if (initop->isBooleanFlip())
matchflip = !matchflip;
if ((vn == basevn)&&(!binon)) return true;
if (boolvn != (Varnode *)0)
matchflip = !matchflip;
if ((vn == boolvn)&&(!binon)) return true;
if ((binaryop == (PcodeOp *)0)||(!binon))
return false;
PcodeOp *binary2op = (PcodeOp *)0;
for(int4 i=0;i<state;++i) { binary2op = opstate[i];
if (binary2op->isBoolOutput()) break;
}
if (binaryop->code() == binary2op->code()) {
if (varnodeSame(binaryop->getIn(0),binary2op->getIn(0)) &&
varnodeSame(binaryop->getIn(1),binary2op->getIn(1)))
return true;
if (sameOpComplement(binaryop,binary2op)) {
matchflip = !matchflip;
return true;
}
return false;
}
matchflip = !matchflip;
if (andOrComplement(binaryop,binary2op))
return true;
int4 slot1 = 0;
int4 slot2 = 0;
bool reorder;
if (binaryop->code() != get_booleanflip(binary2op->code(),reorder))
return false;
if (reorder) slot2 = 1;
if (!varnodeSame(binaryop->getIn(slot1),binary2op->getIn(slot2)))
return false;
if (!varnodeSame(binaryop->getIn(1-slot1),binary2op->getIn(1-slot2)))
return false;
return true;
}
bool ConditionMarker::verifyCondition(PcodeOp *op,PcodeOp *iop)
{
setupInitOp(iop);
Varnode *matchvn = findMatch(op);
if (matchvn == (Varnode *)0) return false;
if (!finalJudgement(matchvn)) return false;
if (!multion)
multislot = -1;
else {
for(int4 i=0;i<state;++i)
if (opstate[i]->code()==CPUI_MULTIEQUAL) {
multislot = slotstate[i];
break;
}
}
return true;
}
void ConditionalExecution::buildHeritageArray(void)
{
heritageyes.clear();
Architecture *glb = fd->getArch();
heritageyes.resize(glb->numSpaces(),false);
for(int4 i=0;i<glb->numSpaces();++i) {
AddrSpace *spc = glb->getSpace(i);
if (spc == (AddrSpace *)0) continue;
int4 index = spc->getIndex();
if (!spc->isHeritaged()) continue;
if (fd->numHeritagePasses(spc) > 0)
heritageyes[index] = true; }
}
bool ConditionalExecution::testIBlock(void)
{
if (iblock->sizeIn() != 2) return false;
if (iblock->sizeOut() != 2) return false;
cbranch = iblock->lastOp();
if (cbranch == (PcodeOp *)0) return false;
if (cbranch->code() != CPUI_CBRANCH) return false;
return true;
}
bool ConditionalExecution::findInitPre(void)
{
FlowBlock *tmp = iblock->getIn(prea_inslot);
FlowBlock *last = iblock;
while((tmp->sizeOut()==1)&&(tmp->sizeIn()==1)) {
last = tmp;
tmp = tmp->getIn(0);
}
if (tmp->sizeOut() != 2) return false;
initblock = (BlockBasic *)tmp;
tmp = iblock->getIn(1-prea_inslot);
while((tmp->sizeOut()==1)&&(tmp->sizeIn()==1))
tmp = tmp->getIn(0);
if (tmp != initblock) return false;
if (initblock == iblock) return false;
init2a_true = (initblock->getTrueOut() == last);
return true;
}
bool ConditionalExecution::verifySameCondition(void)
{
PcodeOp *init_cbranch = initblock->lastOp();
if (init_cbranch == (PcodeOp *)0) return false;
if (init_cbranch->code() != CPUI_CBRANCH) return false;
ConditionMarker tester;
if (!tester.verifyCondition(cbranch,init_cbranch))
return false;
if (tester.getFlip())
init2a_true = !init2a_true;
int4 multislot = tester.getMultiSlot();
if (multislot != -1) {
directsplit = true;
posta_outslot = (multislot == prea_inslot) ? 0 : 1;
if (init2a_true)
posta_outslot = 1 - posta_outslot;
}
return true;
}
bool ConditionalExecution::testMultiRead(Varnode *vn,PcodeOp *op)
{
if (op->getParent() == iblock) {
if (!directsplit) {
if (op->code() == CPUI_COPY) return true; return false;
}
}
if (op->code() == CPUI_RETURN) {
if ((op->numInput() < 2)||(op->getIn(1) != vn)) return false; returnop.push_back(op); }
return true;
}
bool ConditionalExecution::testOpRead(Varnode *vn,PcodeOp *op)
{
if (op->getParent() == iblock) return true;
if ((op->code() == CPUI_RETURN)&&(!directsplit)) {
if ((op->numInput() < 2)||(op->getIn(1) != vn)) return false; PcodeOp *copyop = vn->getDef();
if (copyop->code() == CPUI_COPY) {
Varnode *invn = copyop->getIn(0);
if (!invn->isWritten()) return false;
PcodeOp *upop = invn->getDef();
if ((upop->getParent() == iblock)&&(upop->code() != CPUI_MULTIEQUAL))
return false;
returnop.push_back(op);
return true;
}
}
return false;
}
void ConditionalExecution::predefineDirectMulti(PcodeOp *op)
{
PcodeOp *newop = fd->newOp(posta_block->sizeIn()+1,posta_block->getStart());
Varnode *outvn = op->getOut();
Varnode *newoutvn;
newoutvn = fd->newVarnodeOut(outvn->getSize(),outvn->getAddr(),newop);
fd->opSetOpcode(newop,CPUI_MULTIEQUAL);
Varnode *vn;
int4 inslot = iblock->getOutRevIndex(posta_outslot);
for(int4 i=0;i<posta_block->sizeIn();++i) {
if (i==inslot)
vn = op->getIn(1-camethruposta_slot);
else
vn = newoutvn;
fd->opSetInput(newop,vn,i);
}
fd->opSetInput(newop,op->getIn(camethruposta_slot),posta_block->sizeIn());
fd->opInsertBegin(newop,posta_block);
replacement[posta_block->getIndex()] = newoutvn;
}
void ConditionalExecution::adjustDirectMulti(void)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
iter = posta_block->beginOp();
int4 inslot = iblock->getOutRevIndex(posta_outslot);
while(iter != posta_block->endOp()) {
op = *iter++;
if (op->code() != CPUI_MULTIEQUAL) continue;
Varnode *vn = op->getIn(inslot);
if (vn->isWritten()&&(vn->getDef()->getParent() == iblock)) {
if (vn->getDef()->code() != CPUI_MULTIEQUAL)
throw LowlevelError("Cannot push non-trivial operation");
fd->opSetInput(op,vn->getDef()->getIn(1-camethruposta_slot),inslot);
vn = vn->getDef()->getIn(camethruposta_slot);
}
fd->opInsertInput(op,vn,op->numInput());
}
}
Varnode *ConditionalExecution::getNewMulti(PcodeOp *op,BlockBasic *bl)
{
PcodeOp *newop = fd->newOp(bl->sizeIn(),bl->getStart());
Varnode *outvn = op->getOut();
Varnode *newoutvn;
newoutvn = fd->newUniqueOut(outvn->getSize(),newop);
fd->opSetOpcode(newop,CPUI_MULTIEQUAL);
for(int4 i=0;i<bl->sizeIn();++i)
fd->opSetInput(newop,outvn,i);
fd->opInsertBegin(newop,bl);
return newoutvn;
}
Varnode *ConditionalExecution::getReplacementRead(PcodeOp *op,BlockBasic *bl)
{
map<int4,Varnode *>::const_iterator iter;
iter = replacement.find(bl->getIndex());
if (iter != replacement.end())
return (*iter).second;
BlockBasic *curbl = bl;
while(curbl->getImmedDom() != iblock) {
curbl = (BlockBasic *)curbl->getImmedDom(); if (curbl == (FlowBlock *)0)
throw LowlevelError("Conditional execution: Could not find dominator");
}
iter = replacement.find(curbl->getIndex());
if (iter != replacement.end()) {
replacement[bl->getIndex()] = (*iter).second;
return (*iter).second;
}
Varnode *res;
if (curbl->sizeIn()==1) {
int4 slot = (curbl->getInRevIndex(0) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot;
res = op->getIn(slot);
}
else
res = getNewMulti(op,curbl);
replacement[curbl->getIndex()] = res;
if (curbl != bl)
replacement[bl->getIndex()] = res;
return res;
}
void ConditionalExecution::doReplacement(PcodeOp *op)
{
if (op->code() == CPUI_COPY) {
if (op->getOut()->hasNoDescend()) return;
}
replacement.clear();
if (directsplit)
predefineDirectMulti(op);
Varnode *vn = op->getOut();
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while(iter != vn->endDescend()) {
PcodeOp *readop = *iter;
int4 slot = readop->getSlot(vn);
BlockBasic *bl = readop->getParent();
Varnode *rvn;
if (bl == iblock) {
if (directsplit)
fd->opSetInput(readop,op->getIn(1-camethruposta_slot),slot); else
fd->opUnsetInput(readop,slot);
}
else {
if (readop->code() == CPUI_MULTIEQUAL) {
BlockBasic *inbl = (BlockBasic *)bl->getIn(slot);
if (inbl == iblock) {
int4 s = (bl->getInRevIndex(slot) == posta_outslot) ? camethruposta_slot : 1-camethruposta_slot;
rvn = op->getIn(s);
}
else
rvn = getReplacementRead(op,inbl);
}
else
rvn = getReplacementRead(op,bl);
fd->opSetInput(readop,rvn,slot);
}
iter = vn->beginDescend();
}
}
void ConditionalExecution::fixReturnOp(void)
{
for(int4 i=0;i<returnop.size();++i) {
PcodeOp *retop = returnop[i];
Varnode *retvn = retop->getIn(1);
PcodeOp *iblockop = retvn->getDef();
Varnode *invn;
if (iblockop->code() == CPUI_COPY)
invn = iblockop->getIn(0); else
invn = retvn;
PcodeOp *newcopyop = fd->newOp(1,retop->getAddr());
fd->opSetOpcode(newcopyop,CPUI_COPY);
Varnode *outvn = fd->newVarnodeOut(retvn->getSize(),retvn->getAddr(),newcopyop); fd->opSetInput(newcopyop,invn,0);
fd->opSetInput(retop,outvn,1);
fd->opInsertBefore(newcopyop,retop);
}
}
bool ConditionalExecution::testRemovability(PcodeOp *op)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *readop;
Varnode *vn;
if (op->code() == CPUI_MULTIEQUAL) {
vn = op->getOut();
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
readop = *iter;
if (!testMultiRead(vn,readop))
return false;
}
}
else {
if (op->isFlowBreak() || op->isCall()) return false;
if ((op->code()==CPUI_LOAD)||(op->code()==CPUI_STORE))
return false;
if (op->code()==CPUI_INDIRECT) return false;
vn = op->getOut();
if (vn != (Varnode *)0) {
bool hasnodescend = true;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
readop = *iter;
if (!testOpRead(vn,readop))
return false;
hasnodescend = false;
}
if (hasnodescend && (!heritageyes[vn->getSpace()->getIndex()])) return false;
}
}
return true;
}
bool ConditionalExecution::verify(void)
{
prea_inslot = 0;
posta_outslot = 0;
directsplit = false;
if (!testIBlock()) return false;
if (!findInitPre()) return false;
if (!verifySameCondition()) return false;
iblock2posta_true = (posta_outslot == 1);
camethruposta_slot = (init2a_true==iblock2posta_true) ? prea_inslot : 1-prea_inslot;
posta_block = (BlockBasic *)iblock->getOut(posta_outslot);
postb_block = (BlockBasic *)iblock->getOut(1-posta_outslot);
returnop.clear();
list<PcodeOp *>::const_iterator iter;
iter = iblock->endOp();
if (iter != iblock->beginOp())
--iter; while(iter != iblock->beginOp()) {
--iter;
if (!testRemovability( *iter ))
return false;
}
return true;
}
ConditionalExecution::ConditionalExecution(Funcdata *f)
{
fd = f;
buildHeritageArray(); }
bool ConditionalExecution::trial(BlockBasic *ib)
{
iblock = ib;
if (!verify()) return false;
PcodeOp *cbranch_copy;
BlockBasic *initblock_copy;
BlockBasic *iblock_copy;
int4 prea_inslot_copy;
bool init2a_true_copy;
bool iblock2posta_true_copy;
int4 camethruposta_slot_copy;
int4 posta_outslot_copy;
BlockBasic *posta_block_copy;
BlockBasic *postb_block_copy;
bool directsplit_copy;
for(;;) {
if (!directsplit) return true;
cbranch_copy = cbranch;
initblock_copy = initblock;
iblock_copy = iblock;
prea_inslot_copy = prea_inslot;
init2a_true_copy = init2a_true;
iblock2posta_true_copy = iblock2posta_true;
camethruposta_slot_copy = camethruposta_slot;
posta_outslot_copy = posta_outslot;
posta_block_copy = posta_block;
postb_block_copy = postb_block;
directsplit_copy = directsplit;
iblock = posta_block;
if (!verify()) {
cbranch = cbranch_copy;
initblock = initblock_copy;
iblock = iblock_copy;
prea_inslot = prea_inslot_copy;
init2a_true = init2a_true_copy;
iblock2posta_true = iblock2posta_true_copy;
camethruposta_slot = camethruposta_slot_copy;
posta_outslot = posta_outslot_copy;
posta_block = posta_block_copy;
postb_block = postb_block_copy;
directsplit = directsplit_copy;
return true;
}
}
}
void ConditionalExecution::execute(void)
{
list<PcodeOp *>::iterator iter;
PcodeOp *op;
fixReturnOp(); if (!directsplit) {
iter = iblock->beginOp();
while(iter != iblock->endOp()) {
op = *iter++;
if (!op->isBranch())
doReplacement(op); fd->opDestroy(op); }
fd->removeFromFlowSplit(iblock,(posta_outslot != camethruposta_slot));
}
else {
adjustDirectMulti();
iter = iblock->beginOp();
while(iter != iblock->endOp()) {
op = *iter++;
if (op->code() == CPUI_MULTIEQUAL) { doReplacement(op);
fd->opDestroy(op);
}
}
fd->switchEdge(iblock->getIn(camethruposta_slot),iblock,posta_block);
}
}
int4 ActionConditionalExe::apply(Funcdata &data)
{
bool changethisround;
int4 numhits = 0;
int4 i;
if (data.hasUnreachableBlocks()) return 0;
ConditionalExecution condexe(&data);
const BlockGraph &bblocks( data.getBasicBlocks() );
do {
changethisround = false;
for(i=0;i<bblocks.getSize();++i) {
BlockBasic *bb = (BlockBasic *)bblocks.getBlock(i);
if (condexe.trial(bb)) {
condexe.execute(); numhits += 1;
changethisround = true;
}
}
} while(changethisround);
count += numhits; return 0;
}
bool RuleOrPredicate::MultiPredicate::discoverZeroSlot(Varnode *vn)
{
if (!vn->isWritten()) return false;
op = vn->getDef();
if (op->code() != CPUI_MULTIEQUAL) return false;
if (op->numInput() != 2) return false;
for(zeroSlot=0;zeroSlot<2;++zeroSlot) {
Varnode *tmpvn = op->getIn(zeroSlot);
if (!tmpvn->isWritten()) continue;
PcodeOp *copyop = tmpvn->getDef();
if (copyop->code() != CPUI_COPY) continue; Varnode *zerovn = copyop->getIn(0);
if (!zerovn->isConstant()) continue;
if (zerovn->getOffset() != 0) continue; otherVn = op->getIn(1-zeroSlot); if (otherVn->isFree()) return false;
return true;
}
return false;
}
bool RuleOrPredicate::MultiPredicate::discoverCbranch(void)
{
const FlowBlock *baseBlock = op->getParent();
zeroBlock = baseBlock->getIn(zeroSlot);
const FlowBlock *otherBlock = baseBlock->getIn(1-zeroSlot);
if (zeroBlock->sizeOut() == 1) {
if (zeroBlock->sizeIn() != 1) return false;
condBlock = zeroBlock->getIn(0);
}
else if (zeroBlock->sizeOut() == 2)
condBlock = zeroBlock;
else
return false;
if (condBlock->sizeOut() != 2) return false;
if (otherBlock->sizeOut() == 1) {
if (otherBlock->sizeIn() != 1) return false;
if (condBlock != otherBlock->getIn(0)) return false;
}
else if (otherBlock->sizeOut() == 2) {
if (condBlock != otherBlock) return false;
}
else
return false;
cbranch = condBlock->lastOp();
if (cbranch == (PcodeOp *)0) return false;
if (cbranch->code() != CPUI_CBRANCH) return false;
return true;
}
void RuleOrPredicate::MultiPredicate::discoverPathIsTrue(void)
{
if (condBlock->getTrueOut() == zeroBlock)
zeroPathIsTrue = true;
else if (condBlock->getFalseOut() == zeroBlock)
zeroPathIsTrue = false;
else { zeroPathIsTrue = (condBlock->getTrueOut() == op->getParent()); }
}
bool RuleOrPredicate::MultiPredicate::discoverConditionalZero(Varnode *vn)
{
Varnode *boolvn = cbranch->getIn(1);
if (!boolvn->isWritten()) return false;
PcodeOp *compareop = boolvn->getDef();
OpCode opc = compareop->code();
if (opc == CPUI_INT_NOTEQUAL) zeroPathIsTrue = !zeroPathIsTrue;
else if (opc != CPUI_INT_EQUAL) return false;
Varnode *a1 = compareop->getIn(0);
Varnode *a2 = compareop->getIn(1);
Varnode *zerovn;
if (a1 == vn) zerovn = a2;
else if (a2 == vn)
zerovn = a1;
else
return false;
if (!zerovn->isConstant()) return false;
if (zerovn->getOffset() != 0) return false; if (cbranch->isBooleanFlip())
zeroPathIsTrue = !zeroPathIsTrue;
return true;
}
void RuleOrPredicate::getOpList(vector<uint4> &oplist) const
{
oplist.push_back(CPUI_INT_OR);
oplist.push_back(CPUI_INT_XOR);
}
int4 RuleOrPredicate::checkSingle(Varnode *vn,MultiPredicate &branch,PcodeOp *op,Funcdata &data)
{
if (vn->isFree()) return 0;
if (!branch.discoverCbranch()) return 0;
if (branch.op->getOut()->loneDescend() != op) return 0; branch.discoverPathIsTrue();
if (!branch.discoverConditionalZero(vn)) return 0;
if (branch.zeroPathIsTrue) return 0; data.opSetInput(branch.op,vn,branch.zeroSlot);
data.opRemoveInput(op,1);
data.opSetOpcode(op,CPUI_COPY);
data.opSetInput(op,branch.op->getOut(),0);
return 1;
}
int4 RuleOrPredicate::applyOp(PcodeOp *op,Funcdata &data)
{
MultiPredicate branch0;
MultiPredicate branch1;
bool test0 = branch0.discoverZeroSlot(op->getIn(0));
bool test1 = branch1.discoverZeroSlot(op->getIn(1));
if ((test0==false) && (test1==false)) return 0;
if (!test0) return checkSingle(op->getIn(0),branch1,op,data);
else if (!test1) return checkSingle(op->getIn(1),branch0,op,data);
if (!branch0.discoverCbranch()) return 0;
if (!branch1.discoverCbranch()) return 0;
if (branch0.condBlock == branch1.condBlock) {
if (branch0.zeroBlock == branch1.zeroBlock) return 0; }
else { ConditionMarker condmarker;
if (!condmarker.verifyCondition(branch0.cbranch,branch1.cbranch)) return 0;
if (condmarker.getMultiSlot() != -1) return 0;
branch0.discoverPathIsTrue();
branch1.discoverPathIsTrue();
bool finalBool = branch0.zeroPathIsTrue == branch1.zeroPathIsTrue;
if (condmarker.getFlip())
finalBool = !finalBool;
if (finalBool) return 0; }
int4 order = branch0.op->compareOrder(branch1.op);
if (order == 0) return 0; BlockBasic *finalBlock;
bool slot0SetsBranch0; if (order < 0) { finalBlock = branch1.op->getParent();
slot0SetsBranch0 = branch1.zeroSlot == 0;
}
else { finalBlock = branch0.op->getParent();
slot0SetsBranch0 = branch0.zeroSlot == 1;
}
PcodeOp *newMulti = data.newOp(2,finalBlock->getStart());
data.opSetOpcode(newMulti,CPUI_MULTIEQUAL);
if (slot0SetsBranch0) {
data.opSetInput(newMulti,branch0.otherVn,0);
data.opSetInput(newMulti,branch1.otherVn,1);
}
else {
data.opSetInput(newMulti,branch1.otherVn,0);
data.opSetInput(newMulti,branch0.otherVn,1);
}
Varnode *newvn = data.newUniqueOut(branch0.otherVn->getSize(),newMulti);
data.opInsertBegin(newMulti,finalBlock);
data.opRemoveInput(op,1);
data.opSetInput(op,newvn,0);
data.opSetOpcode(op,CPUI_COPY);
return 1;
}