#include "merge.hh"
#include "funcdata.hh"
void BlockVarnode::set(Varnode *v)
{
vn = v;
const PcodeOp *op = vn->getDef();
if (op == (const PcodeOp *)0)
index = 0;
else
index = op->getParent()->getIndex();
}
int4 BlockVarnode::findFront(int4 blocknum,const vector<BlockVarnode> &list)
{
int4 min = 0;
int4 max = list.size()-1;
while(min < max) {
int4 cur = (min + max)/2;
int4 curblock = list[cur].getIndex();
if (curblock >= blocknum)
max = cur;
else
min = cur + 1;
}
if (min > max)
return -1;
if (list[min].getIndex() != blocknum)
return -1;
return min;
}
bool Merge::mergeTestRequired(HighVariable *high_out,HighVariable *high_in)
{
if (high_in == high_out) return true;
if (high_in->isTypeLock()) if (high_out->isTypeLock()) if (high_in->getType() != high_out->getType()) return false;
if (high_out->isAddrTied()) { if (high_in->isAddrTied()) {
if (high_in->getTiedVarnode()->getAddr() != high_out->getTiedVarnode()->getAddr())
return false; }
}
if (high_in->isInput()) {
if (high_out->isPersist()) return false;
if ((high_out->isAddrTied())&&(!high_in->isAddrTied())) return false;
}
else if (high_in->isExtraOut())
return false;
if (high_out->isInput()) {
if (high_in->isPersist()) return false;
if ((high_in->isAddrTied())&&(!high_out->isAddrTied())) return false;
}
else if (high_out->isExtraOut())
return false;
Symbol *symbolIn = high_in->getSymbol();
Symbol *symbolOut = high_out->getSymbol();
if (symbolIn != (Symbol *) 0 && symbolOut != (Symbol *) 0) {
if (symbolIn != symbolOut)
return false; if (high_in->getSymbolOffset() != high_out->getSymbolOffset())
return false; }
return true;
}
bool Merge::mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in)
{
if (!mergeTestRequired(high_out,high_in)) return false;
if (high_in->isNameLock() && high_out->isNameLock())
return false;
if (high_out->getType() != high_in->getType())
return false;
if (high_out->isInput()) {
Varnode *vn = high_out->getInputVarnode();
if (vn->isIllegalInput()&&(!vn->isIndirectOnly())) return false;
}
if (high_in->isInput()) {
Varnode *vn = high_in->getInputVarnode();
if (vn->isIllegalInput()&&(!vn->isIndirectOnly())) return false;
}
Symbol *symbol = high_in->getSymbol();
if (symbol != (Symbol *)0)
if (symbol->isIsolated())
return false;
symbol = high_out->getSymbol();
if (symbol != (Symbol *)0)
if (symbol->isIsolated())
return false;
return true;
}
bool Merge::mergeTestSpeculative(HighVariable *high_out,HighVariable *high_in)
{
if (!mergeTestAdjacent(high_out,high_in)) return false;
if (high_out->isPersist()) return false;
if (high_in->isPersist()) return false;
if (high_out->isInput()) return false;
if (high_in->isInput()) return false;
if (high_out->isAddrTied()) return false;
if (high_in->isAddrTied()) return false;
return true;
}
bool Merge::mergeTestBasic(Varnode *vn)
{
if (vn == (Varnode *)0) return false;
if (!vn->hasCover()) return false;
if (vn->isImplied()) return false;
if (vn->isSpacebase()) return false;
return true;
}
void Merge::mergeLinear(vector<HighVariable *> &highvec)
{
vector<HighVariable *> highstack;
vector<HighVariable *>::iterator initer,outiter;
HighVariable *high;
if (highvec.size() <= 1) return;
for(initer=highvec.begin();initer!=highvec.end();++initer)
updateHigh(*initer);
sort(highvec.begin(),highvec.end(),compareHighByBlock);
for(initer=highvec.begin();initer!=highvec.end();++initer) {
high = *initer;
for(outiter=highstack.begin();outiter!=highstack.end();++outiter) {
if (mergeTestSpeculative(*outiter,high))
if (merge(*outiter,high,true)) break;
}
if (outiter==highstack.end())
highstack.push_back(high);
}
}
void Merge::mergeRangeMust(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::const_iterator enditer)
{
HighVariable *high;
Varnode *vn;
vn = *startiter++;
if (!mergeTestBasic(vn)) {
if (!vn->isSpacebase())
throw LowlevelError("Cannot force merge of range");
}
high = vn->getHigh();
for(;startiter!=enditer;++startiter) {
vn = *startiter;
if (vn->getHigh() == high) continue;
if (!mergeTestBasic(vn)) {
if (!vn->isSpacebase())
throw LowlevelError("Cannot force merge of range");
}
if (!merge(high,vn->getHigh(),false))
throw LowlevelError("Forced merge caused intersection");
}
}
void Merge::mergeOpcode(OpCode opc)
{
BlockBasic *bl;
list<PcodeOp *>::iterator iter;
PcodeOp *op;
Varnode *vn1,*vn2;
const BlockGraph &bblocks(data.getBasicBlocks());
for(int4 i=0;i<bblocks.getSize();++i) { bl = (BlockBasic *) bblocks.getBlock(i);
for(iter=bl->beginOp();iter!=bl->endOp();++iter) {
op = *iter;
if (op->code() != opc) continue;
vn1 = op->getOut();
if (!mergeTestBasic(vn1)) continue;
for(int4 j=0;j<op->numInput();++j) {
vn2 = op->getIn(j);
if (!mergeTestBasic(vn2)) continue;
if (mergeTestRequired(vn1->getHigh(),vn2->getHigh()))
merge(vn1->getHigh(),vn2->getHigh(),false); }
}
}
}
void Merge::mergeByDatatype(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::const_iterator enditer)
{
vector<HighVariable *> highvec;
list<HighVariable *> highlist;
list<HighVariable *>::iterator hiter;
VarnodeLocSet::const_iterator iter;
Varnode *vn;
HighVariable *high;
Datatype *ct = (Datatype *)0;
for(iter=startiter;iter!=enditer;++iter) { vn = *iter;
if (vn->isFree()) continue;
high = (*iter)->getHigh();
if (high->isMark()) continue; if (!mergeTestBasic(vn)) continue;
high->setMark();
highlist.push_back(high);
}
for(hiter=highlist.begin();hiter!=highlist.end();++hiter)
(*hiter)->clearMark();
while(!highlist.empty()) {
highvec.clear();
hiter = highlist.begin();
high = *hiter;
ct = high->getType();
highvec.push_back(high);
highlist.erase(hiter++);
while(hiter != highlist.end()) {
high = *hiter;
if (ct == high->getType()) { highvec.push_back(high);
highlist.erase(hiter++);
}
else
++hiter;
}
mergeLinear(highvec); }
}
PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,Datatype *ct,const Address &addr)
{
PcodeOp *copyOp = data.newOp(1,addr);
data.opSetOpcode(copyOp,CPUI_COPY);
Varnode *outVn = data.newUnique(inVn->getSize(),ct);
data.opSetOutput(copyOp,outVn);
data.opSetInput(copyOp,inVn,0);
copyTrims.push_back(copyOp);
return copyOp;
}
void Merge::snipReads(Varnode *vn,list<PcodeOp *> &markedop)
{
if (markedop.empty()) return;
PcodeOp *copyop,*op;
BlockBasic *bl;
Address pc;
int4 slot;
PcodeOp *afterop;
if (vn->isInput()) {
bl = (BlockBasic *) data.getBasicBlocks().getBlock(0);
pc = bl->getStart();
afterop = (PcodeOp *)0;
}
else {
bl = vn->getDef()->getParent();
pc = vn->getDef()->getAddr();
if (vn->getDef()->code() == CPUI_INDIRECT) afterop = PcodeOp::getOpFromConst(vn->getDef()->getIn(1)->getAddr());
else
afterop = vn->getDef();
}
copyop = allocateCopyTrim(vn, vn->getType(), pc);
if (afterop == (PcodeOp *)0)
data.opInsertBegin(copyop,bl);
else
data.opInsertAfter(copyop,afterop);
list<PcodeOp *>::iterator iter;
for(iter=markedop.begin();iter!=markedop.end();++iter) {
op = *iter;
for(slot=0;slot<op->numInput();++slot)
if (op->getIn(slot)==vn) break; data.opSetInput(op,copyop->getOut(),slot);
}
}
void Merge::eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort)
{
list<PcodeOp *> markedop;
list<PcodeOp *>::const_iterator oiter;
map<int4,CoverBlock>::const_iterator iter,enditer;
Varnode *vn2;
int4 boundtype;
bool insertop;
for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter) {
insertop = false;
Cover single;
single.addDefPoint(vn);
PcodeOp *op = *oiter;
single.addRefPoint(op,vn); iter = single.begin();
enditer = single.end();
while(iter != enditer) {
int4 blocknum = (*iter).first;
++iter;
int4 slot = BlockVarnode::findFront(blocknum,blocksort);
if (slot == -1) continue;
while(slot < blocksort.size()) {
if (blocksort[slot].getIndex() != blocknum)
break;
vn2 = blocksort[slot].getVarnode();
slot += 1;
if (vn2 == vn) continue;
boundtype = single.containVarnodeDef(vn2);
if (boundtype == 0) continue;
if (boundtype == 2) { if (vn2->getDef() == (PcodeOp *)0) {
if (vn->getDef() == (PcodeOp *)0) {
if (vn < vn2) continue; }
else
continue;
}
else {
if (vn->getDef() != (PcodeOp *)0) {
if (vn2->getDef()->getSeqNum().getOrder() < vn->getDef()->getSeqNum().getOrder())
continue;
}
}
}
else if (boundtype == 3) { if (!vn2->isAddrForce()) continue;
if (!vn2->isWritten()) continue;
PcodeOp *indop = vn2->getDef();
if (indop->code() != CPUI_INDIRECT) continue;
if (op != PcodeOp::getOpFromConst(indop->getIn(1)->getAddr())) continue;
if (vn->copyShadow(indop->getIn(0))) continue; }
insertop = true;
break; }
if (insertop) break; }
if (insertop)
markedop.push_back(op);
}
snipReads(vn,markedop);
}
void Merge::unifyAddress(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::const_iterator enditer)
{
VarnodeLocSet::const_iterator iter;
Varnode *vn;
vector<Varnode *> isectlist;
vector<BlockVarnode> blocksort;
for(iter=startiter;iter!=enditer;++iter) {
vn = *iter;
isectlist.push_back(vn);
}
blocksort.resize(isectlist.size());
for(int4 i=0;i<isectlist.size();++i)
blocksort[i].set(isectlist[i]);
stable_sort(blocksort.begin(),blocksort.end());
for(int4 i=0;i<isectlist.size();++i)
eliminateIntersect(isectlist[i],blocksort);
}
void Merge::mergeAddrTied(void)
{
bool addrtied;
VarnodeLocSet::const_iterator startiter,enditer,iter;
for(startiter=data.beginLoc();startiter!=data.endLoc();) {
addrtied = false;
enditer = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),Varnode::written);
for(iter=startiter;iter!=enditer;++iter) {
if ((*iter)->isAddrTied()) {
addrtied = true;
break;
}
}
if (addrtied) {
unifyAddress(startiter,enditer); enditer = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),Varnode::written);
mergeRangeMust(startiter,enditer);
}
startiter = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),0);
}
}
void Merge::trimOpOutput(PcodeOp *op)
{
PcodeOp *copyop;
Varnode *uniq,*vn;
PcodeOp *afterop;
if (op->code() == CPUI_INDIRECT)
afterop = PcodeOp::getOpFromConst(op->getIn(1)->getAddr()); else
afterop = op;
vn = op->getOut();
uniq = data.newUnique(vn->getSize(),vn->getType());
copyop = data.newOp(1,op->getAddr());
data.opSetOutput(op,uniq); data.opSetOpcode(copyop,CPUI_COPY);
data.opSetOutput(copyop,vn); data.opSetInput(copyop,uniq,0);
data.opInsertAfter(copyop,afterop);
}
void Merge::trimOpInput(PcodeOp *op,int4 slot)
{
PcodeOp *copyop;
Varnode *vn;
Address pc;
if (op->code() == CPUI_MULTIEQUAL) {
BlockBasic *bb = (BlockBasic *)op->getParent()->getIn(slot);
pc = bb->getStop();
}
else
pc = op->getAddr();
vn = op->getIn(slot);
copyop = allocateCopyTrim(vn, vn->getType(), pc);
data.opSetInput(op,copyop->getOut(),slot);
if (op->code() == CPUI_MULTIEQUAL)
data.opInsertEnd(copyop,(BlockBasic *)op->getParent()->getIn(slot));
else
data.opInsertBefore(copyop,op);
}
void Merge::mergeOp(PcodeOp *op)
{
vector<HighVariable *> testlist;
HighVariable *high_out;
int4 i,nexttrim,max;
max = (op->code() == CPUI_INDIRECT) ? 1 : op->numInput();
high_out = op->getOut()->getHigh();
for(i=0;i<max;++i) {
HighVariable *high_in = op->getIn(i)->getHigh();
if (!mergeTestRequired(high_out,high_in)) {
trimOpInput(op,i);
continue;
}
for(int4 j=0;j<i;++j)
if (!mergeTestRequired(op->getIn(j)->getHigh(),high_in)) {
trimOpInput(op,i);
break;
}
}
mergeTest(high_out,testlist);
for(i=0;i<max;++i)
if (!mergeTest(op->getIn(i)->getHigh(),testlist)) break;
if (i != max) { nexttrim = 0;
while(nexttrim < max) {
trimOpInput(op,nexttrim); testlist.clear();
mergeTest(high_out,testlist);
for(i=0;i<max;++i)
if (!mergeTest(op->getIn(i)->getHigh(),testlist)) break;
if (i==max) break; nexttrim += 1;
}
if (nexttrim == max) trimOpOutput(op);
}
for(i=0;i<max;++i) { if (!mergeTestRequired(op->getOut()->getHigh(),op->getIn(i)->getHigh()))
throw LowlevelError("Non-cover related merge restriction violated, despite trims");
if (!merge(op->getOut()->getHigh(),op->getIn(i)->getHigh(),false)) {
ostringstream errstr;
errstr << "Unable to force merge of op at " << op->getSeqNum();
throw LowlevelError(errstr.str());
}
}
}
void Merge::collectCovering(vector<Varnode *> &vlist,HighVariable *high,PcodeOp *op)
{
int4 blk = op->getParent()->getIndex();
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
if (vn->getCover()->getCoverBlock(blk).contain(op))
vlist.push_back(vn);
}
}
bool Merge::collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,
vector<int4> &slotlist,PcodeOp *op)
{
int4 blk = op->getParent()->getIndex();
vector<Varnode *>::const_iterator viter;
list<PcodeOp *>::const_iterator oiter;
Varnode *vn;
PcodeOp *edgeop;
int4 slot,bound;
uintm opuindex = CoverBlock::getUIndex(op);
for(viter=vlist.begin();viter!=vlist.end();++viter) {
vn = *viter;
bound = vn->getCover()->getCoverBlock(blk).boundary(op);
if (bound == 0) return false;
if (bound == 2) continue; for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter) {
edgeop = *oiter;
if (CoverBlock::getUIndex(edgeop) == opuindex) { oplist.push_back(edgeop);
slot = edgeop->getSlot(vn);
slotlist.push_back(slot);
}
}
}
return true;
}
void Merge::snipIndirect(PcodeOp *indop)
{
PcodeOp *op = PcodeOp::getOpFromConst(indop->getIn(1)->getAddr()); vector<Varnode *> problemvn;
list<PcodeOp *> correctable;
vector<int4> correctslot;
collectCovering(problemvn,indop->getOut()->getHigh(),op);
if (problemvn.empty()) return;
if (!collectCorrectable(problemvn,correctable,correctslot,op))
throw LowlevelError("Unable to force indirect merge");
if (correctable.empty()) return;
Varnode *refvn = correctable.front()->getIn(correctslot[0]);
PcodeOp *snipop,*insertop;
snipop = allocateCopyTrim(refvn, refvn->getType(), op->getAddr());
data.opInsertBefore(snipop,op);
list<PcodeOp *>::iterator oiter;
int4 i,slot;
for(oiter=correctable.begin(),i=0;i<correctslot.size();++oiter,++i) {
insertop = *oiter;
slot = correctslot[i];
data.opSetInput(insertop,snipop->getOut(),slot);
}
}
void Merge::mergeIndirect(PcodeOp *indop)
{
Varnode *outvn = indop->getOut();
Varnode *invn0 = indop->getIn(0);
if (!outvn->isAddrForce()) { mergeOp(indop); return;
}
if (mergeTestRequired(outvn->getHigh(),invn0->getHigh()))
if (merge(invn0->getHigh(),outvn->getHigh(),false)) return;
snipIndirect(indop);
PcodeOp *newop;
newop = allocateCopyTrim(invn0, outvn->getType(), indop->getAddr());
data.opSetInput(indop,newop->getOut(),0);
data.opInsertBefore(newop,indop);
if (!mergeTestRequired(outvn->getHigh(),indop->getIn(0)->getHigh()) ||
(!merge(indop->getIn(0)->getHigh(),outvn->getHigh(),false))) throw LowlevelError("Unable to merge address forced indirect");
}
void Merge::mergeMarker(void)
{
PcodeOp *op;
list<PcodeOp *>::const_iterator iter;
for(iter=data.beginOpAlive();iter!=data.endOpAlive();++iter) {
op = *iter;
if ((!op->isMarker())||op->isIndirectCreation()) continue;
if (op->code() == CPUI_INDIRECT)
mergeIndirect(op);
else
mergeOp(op);
}
}
void Merge::mergeMultiEntry(void)
{
SymbolNameTree::const_iterator iter = data.getScopeLocal()->beginMultiEntry();
SymbolNameTree::const_iterator enditer = data.getScopeLocal()->endMultiEntry();
for(;iter!=enditer;++iter) {
vector<Varnode *> mergeList;
Symbol *symbol = *iter;
int4 numEntries = symbol->numEntries();
int4 mergeCount = 0;
int4 skipCount = 0;
int4 conflictCount = 0;
for(int4 i=0;i<numEntries;++i) {
int4 prevSize = mergeList.size();
SymbolEntry *entry = symbol->getMapEntry(i);
if (entry->getSize() != symbol->getType()->getSize())
continue;
data.findLinkedVarnodes(entry, mergeList);
if (mergeList.size() == prevSize)
skipCount += 1; }
if (mergeList.empty()) continue;
HighVariable *high = mergeList[0]->getHigh();
updateHigh(high);
for(int4 i=0;i<mergeList.size();++i) {
HighVariable *newHigh = mergeList[i]->getHigh();
if (newHigh == high) continue; updateHigh(newHigh);
if (!mergeTestRequired(high, newHigh)) {
symbol->setMergeProblems();
newHigh->setUnmerged();
conflictCount += 1;
continue;
}
if (!merge(high,newHigh,false)) { symbol->setMergeProblems();
newHigh->setUnmerged();
conflictCount += 1;
continue;
}
mergeCount += 1;
}
if (skipCount != 0 || conflictCount !=0) {
ostringstream s;
s << "Unable to";
if (mergeCount != 0)
s << " fully";
s << " merge symbol: " << symbol->getName();
if (skipCount > 0)
s << " -- Some instance varnodes not found.";
if (conflictCount > 0)
s << " -- Some merges are forbidden";
data.warningHeader(s.str());
}
}
}
void Merge::mergeAdjacent(void)
{
list<PcodeOp *>::const_iterator oiter;
PcodeOp *op;
int4 i;
HighVariable *high_in,*high_out;
Varnode *vn1,*vn2;
const Datatype *ct;
for(oiter=data.beginOpAlive();oiter!=data.endOpAlive();++oiter) {
op = *oiter;
if (op->isCall()) continue;
vn1 = op->getOut();
if (!mergeTestBasic(vn1)) continue;
high_out = vn1->getHigh();
ct = op->outputTypeLocal();
for(i=0;i<op->numInput();++i) {
if (ct != op->inputTypeLocal(i)) continue; vn2 = op->getIn(i);
if (!mergeTestBasic(vn2)) continue;
if (vn1->getSize() != vn2->getSize()) continue;
if ((vn2->getDef()==(PcodeOp *)0)&&(!vn2->isInput())) continue;
high_in = vn2->getHigh();
if (!mergeTestAdjacent(high_out,high_in)) continue;
if (!intersection(high_in,high_out)) merge(high_out,high_in,true);
}
}
}
void Merge::findSingleCopy(HighVariable *high,vector<Varnode *> &singlelist)
{
int4 i;
Varnode *vn;
PcodeOp *op;
for(i=0;i<high->numInstances();++i) {
vn = high->getInstance(i);
if (!vn->isWritten()) continue;
op = vn->getDef();
if (op->code() != CPUI_COPY) continue; if (op->getIn(0)->getHigh() == high) continue; singlelist.push_back(vn);
}
}
bool Merge::compareCopyByInVarnode(PcodeOp *op1,PcodeOp *op2)
{
Varnode *inVn1 = op1->getIn(0);
Varnode *inVn2 = op2->getIn(0);
if (inVn1 != inVn2) return (inVn1->getCreateIndex() < inVn2->getCreateIndex());
int4 index1 = op1->getParent()->getIndex();
int4 index2 = op2->getParent()->getIndex();
if (index1 != index2)
return (index1 < index2);
return (op1->getSeqNum().getOrder() < op2->getSeqNum().getOrder());
}
bool Merge::hideShadows(HighVariable *high)
{
vector<Varnode *> singlelist;
Varnode *vn1,*vn2;
int4 i,j;
bool res = false;
findSingleCopy(high,singlelist); if (singlelist.size() <= 1) return false;
for(i=0;i<singlelist.size()-1;++i) {
vn1 = singlelist[i];
if (vn1 == (Varnode *)0) continue;
for(j=i+1;j<singlelist.size();++j) {
vn2 = singlelist[j];
if (vn2 == (Varnode *)0) continue;
if (!vn1->copyShadow(vn2)) continue;
if (vn2->getCover()->containVarnodeDef(vn1)==1) {
data.opSetInput(vn1->getDef(),vn2,0);
res = true;
break;
}
else if (vn1->getCover()->containVarnodeDef(vn2)==1) {
data.opSetInput(vn2->getDef(),vn1,0);
singlelist[j] = (Varnode *)0;
res = true;
}
}
}
return res;
}
bool Merge::checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp)
{
FlowBlock *domBlock = domOp->getParent();
FlowBlock *subBlock = subOp->getParent();
if (!domBlock->dominates(subBlock))
return false;
Cover range;
range.addDefPoint(domOp->getOut());
range.addRefPoint(subOp,subOp->getIn(0));
Varnode *inVn = domOp->getIn(0);
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
if (!vn->isWritten()) continue;
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_COPY) { if (op->getIn(0) == inVn) continue; }
if (range.contain(op, 1)) { return false; }
}
return true;
}
void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 pos,int4 size)
{
vector<FlowBlock *> blockSet;
for(int4 i=0;i<size;++i)
blockSet.push_back(copy[pos+i]->getParent());
BlockBasic *domBl = (BlockBasic *)FlowBlock::findCommonBlock(blockSet);
Varnode *rootVn = copy[pos]->getIn(0);
bool domCopyIsNew;
PcodeOp *domCopy;
Varnode *domVn;
if (domBl == copy[pos]->getParent()) {
domCopyIsNew = false;
domCopy = copy[pos];
domVn = domCopy->getOut();
}
else {
domCopyIsNew = true;
domCopy = data.newOp(1,domBl->getStop());
data.opSetOpcode(domCopy, CPUI_COPY);
domVn = data.newUnique(rootVn->getSize(), rootVn->getType());
data.opSetOutput(domCopy,domVn);
data.opSetInput(domCopy,rootVn,0);
data.opInsertEnd(domCopy, domBl);
}
Cover bCover;
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
if (vn->isWritten()) {
PcodeOp *op = vn->getDef();
if (op->code() == CPUI_COPY) {
if (op->getIn(0)->copyShadow(rootVn)) continue;
}
}
bCover.merge(*vn->getCover());
}
int4 count = size;
for(int4 i=0;i<size;++i) {
PcodeOp *op = copy[pos+i];
if (op == domCopy) continue; Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter;
Cover aCover;
aCover.addDefPoint(domVn);
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter)
aCover.addRefPoint(*iter, outVn);
if (bCover.intersect(aCover)>1) {
count -= 1;
op->setMark();
}
}
if (count <= 1) { for (int4 i = 0; i < size; ++i)
copy[pos + i]->setMark();
count = 0;
if (domCopyIsNew) {
data.opDestroy(domCopy);
}
}
for(int4 i=0;i<size;++i) {
PcodeOp *op = copy[pos+i];
if (op->isMark())
op->clearMark();
else {
Varnode *outVn = op->getOut();
if (outVn != domVn) {
outVn->getHigh()->remove(outVn);
data.totalReplace(outVn, domVn);
data.opDestroy(op);
}
}
}
if (count > 0 && domCopyIsNew) {
high->merge(domVn->getHigh(),true);
}
}
void Merge::markRedundantCopies(HighVariable *high,vector<PcodeOp *> ©,int4 pos,int4 size)
{
for (int4 i = size - 1; i > 0; --i) {
PcodeOp *subOp = copy[pos + i];
if (subOp->isDead()) continue;
for (int4 j = i - 1; j >= 0; --j) {
PcodeOp *domOp = copy[pos + j];
if (domOp->isDead()) continue;
if (checkCopyPair(high, domOp, subOp)) {
data.opMarkNonPrinting(subOp);
break;
}
}
}
}
bool Merge::shadowedVarnode(const Varnode *vn)
{
const Varnode *othervn;
const HighVariable *high = vn->getHigh();
int4 num,i;
num = high->numInstances();
for(i=0;i<num;++i) {
othervn = high->getInstance(i);
if (othervn == vn) continue;
if (vn->getCover()->intersect(*othervn->getCover()) == 2) return true;
}
return false;
}
void Merge::findAllIntoCopies(HighVariable *high,vector<PcodeOp *> ©Ins,bool filterTemps)
{
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
if (!vn->isWritten()) continue;
PcodeOp *op = vn->getDef();
if (op->code() != CPUI_COPY) continue;
if (op->getIn(0)->getHigh() == high) continue;
if (filterTemps && op->getOut()->getSpace()->getType() != IPTR_INTERNAL) continue;
copyIns.push_back(op);
}
sort(copyIns.begin(),copyIns.end(),compareCopyByInVarnode);
}
void Merge::processHighDominantCopy(HighVariable *high)
{
vector<PcodeOp *> copyIns;
findAllIntoCopies(high,copyIns,true); if (copyIns.size() < 2) return;
int4 pos = 0;
while(pos < copyIns.size()) {
Varnode *inVn = copyIns[pos]->getIn(0);
int4 sz = 1;
while(pos + sz < copyIns.size()) {
Varnode *nextVn = copyIns[pos+sz]->getIn(0);
if (nextVn != inVn) break;
sz += 1;
}
if (sz > 1) buildDominantCopy(high, copyIns, pos, sz); pos += sz;
}
}
void Merge::processHighRedundantCopy(HighVariable *high)
{
vector<PcodeOp *> copyIns;
findAllIntoCopies(high,copyIns,false);
if (copyIns.size() < 2) return;
int4 pos = 0;
while(pos < copyIns.size()) {
Varnode *inVn = copyIns[pos]->getIn(0);
int4 sz = 1;
while(pos + sz < copyIns.size()) {
Varnode *nextVn = copyIns[pos+sz]->getIn(0);
if (nextVn != inVn) break;
sz += 1;
}
if (sz > 1) { markRedundantCopies(high, copyIns, pos, sz);
}
pos += sz;
}
}
void Merge::processCopyTrims(void)
{
vector<HighVariable *> multiCopy;
for(int4 i=0;i<copyTrims.size();++i) {
HighVariable *high = copyTrims[i]->getOut()->getHigh();
if (!high->hasCopyIn1()) {
multiCopy.push_back(high);
high->setCopyIn1();
}
else
high->setCopyIn2();
}
copyTrims.clear();
for(int4 i=0;i<multiCopy.size();++i) {
HighVariable *high = multiCopy[i];
if (high->hasCopyIn2()) processHighDominantCopy(high); high->clearCopyIns();
}
}
void Merge::markInternalCopies(void)
{
vector<HighVariable *> multiCopy;
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
HighVariable *h1,*h2,*h3;
Varnode *v1,*v2,*v3;
int4 val;
for(iter=data.beginOpAlive();iter!=data.endOpAlive();++iter) {
op = *iter;
switch(op->code()) {
case CPUI_COPY:
v1 = op->getOut();
h1 = v1->getHigh();
if (h1 == op->getIn(0)->getHigh()) {
data.opMarkNonPrinting(op);
}
else { if (!h1->hasCopyIn1()) { h1->setCopyIn1(); multiCopy.push_back(h1);
}
else
h1->setCopyIn2(); if (v1->hasNoDescend()) { if (shadowedVarnode(v1)) {
data.opMarkNonPrinting(op);
}
}
}
break;
case CPUI_PIECE: h1 = op->getOut()->getHigh();
h2 = op->getIn(0)->getHigh();
h3 = op->getIn(1)->getHigh();
if (!h1->isAddrTied()) break;
if (!h2->isAddrTied()) break;
if (!h3->isAddrTied()) break;
v1 = h1->getTiedVarnode();
v2 = h2->getTiedVarnode();
v3 = h3->getTiedVarnode();
if (v3->overlap(*v1) != 0) break;
if (v2->overlap(*v1) != v3->getSize()) break;
data.opMarkNonPrinting(op);
break;
case CPUI_SUBPIECE:
h1 = op->getOut()->getHigh();
h2 = op->getIn(0)->getHigh();
if (!h1->isAddrTied()) break;
if (!h2->isAddrTied()) break;
v1 = h1->getTiedVarnode();
v2 = h2->getTiedVarnode();
val = op->getIn(1)->getOffset();
if (v1->overlap(*v2) != val) break;
data.opMarkNonPrinting(op);
break;
default:
break;
}
}
for(int4 i=0;i<multiCopy.size();++i) {
HighVariable *high = multiCopy[i];
if (high->hasCopyIn2())
data.getMerge().processHighRedundantCopy(high);
high->clearCopyIns();
}
#ifdef MERGEMULTI_DEBUG
verifyHighCovers();
#endif
}
bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
{
if (high1 == high2) return true; if (intersection(high1,high2)) return false;
vector<HighVariable *> yesinter; vector<HighVariable *> nointer; map<HighEdge,bool>::iterator iterfirst = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)0) );
map<HighEdge,bool>::iterator iterlast = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)~((uintp)0)) );
map<HighEdge,bool>::iterator iter;
for(iter=iterfirst;iter!=iterlast;++iter) {
HighVariable *b = (*iter).first.b;
if (b == high1) continue;
if ((*iter).second) yesinter.push_back(b); else {
nointer.push_back(b);
b->setMark(); }
}
if (iterfirst != iterlast) { --iterlast; for(iter=iterfirst;iter!=iterlast;++iter)
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
++iterlast;
highedgemap.erase(iterfirst,iterlast);
}
iter = highedgemap.lower_bound( HighEdge(high1,(HighVariable *)0) );
while((iter!=highedgemap.end())&&((*iter).first.a == high1)) {
if (!(*iter).second) { if (!(*iter).first.b->isMark()) highedgemap.erase( iter++ ); else
++iter;
}
else ++iter;
}
vector<HighVariable *>::iterator titer;
for(titer=nointer.begin();titer!=nointer.end();++titer)
(*titer)->clearMark();
for(titer=yesinter.begin();titer!=yesinter.end();++titer) {
highedgemap[ HighEdge(high1,*titer) ] = true;
highedgemap[ HighEdge(*titer,high1) ] = true;
}
high1->merge(high2,isspeculative); high1->updateCover();
return true;
}
bool Merge::updateHigh(HighVariable *a)
{
if ((a->highflags&HighVariable::coverdirty)==0) return true;
for(int4 i=0;i<a->numInstances();++i)
a->getInstance(i)->updateCover();
a->updateCover();
purgeHigh(a);
return false;
}
void Merge::purgeHigh(HighVariable *high)
{
map<HighEdge,bool>::iterator iterfirst = highedgemap.lower_bound( HighEdge(high,(HighVariable *)0) );
map<HighEdge,bool>::iterator iterlast = highedgemap.lower_bound( HighEdge(high,(HighVariable *)~((uintp)0)) );
if (iterfirst == iterlast) return;
--iterlast; map<HighEdge,bool>::iterator iter;
for(iter=iterfirst;iter!=iterlast;++iter)
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
++iterlast;
highedgemap.erase(iterfirst,iterlast);
}
bool Merge::intersection(HighVariable *a,HighVariable *b)
{
if (a==b) return false;
bool ares = updateHigh(a);
bool bres = updateHigh(b);
if (ares && bres) { map<HighEdge,bool>::iterator iter = highedgemap.find( HighEdge(a,b) );
if (iter != highedgemap.end()) return (*iter).second; }
bool res = false;
int4 blk;
vector<int4> blockisect;
a->wholecover.intersectList(blockisect,b->wholecover,2);
for(blk=0;blk<blockisect.size();++blk) {
if (blockIntersection(a,b,blockisect[blk])) {
res = true;
break;
}
}
highedgemap[ HighEdge(a,b) ] = res; highedgemap[ HighEdge(b,a) ] = res;
return res;
}
bool Merge::blockIntersection(HighVariable *a,HighVariable *b,int4 blk)
{
vector<Varnode *> blist;
for(int4 i=0;i<b->numInstances();++i) {
Varnode *vn = b->getInstance(i);
if (1<vn->getCover()->intersectByBlock(blk,a->wholecover))
blist.push_back(vn);
}
for(int4 i=0;i<a->numInstances();++i) {
Varnode *vn = a->getInstance(i);
if (2>vn->getCover()->intersectByBlock(blk,b->wholecover)) continue;
for(int4 j=0;j<blist.size();++j) {
Varnode *vn2 = blist[j];
if (1<vn2->getCover()->intersectByBlock(blk,*vn->getCover()))
if (!vn->copyShadow(vn2))
return true;
}
}
return false;
}
void Merge::inflate(Varnode *a,HighVariable *high)
{
updateHigh(a->getHigh());
updateHigh(high);
for(int4 i=0;i<high->numInstances();++i) {
Varnode *b = high->getInstance(i);
a->cover->merge(*b->cover);
}
a->getHigh()->coverDirty();
}
bool Merge::inflateTest(Varnode *a,HighVariable *high)
{
HighVariable *ahigh = a->getHigh();
bool res = false;
updateHigh(high);
for(int4 i=0;i<ahigh->numInstances();++i) {
Varnode *b = ahigh->getInstance(i);
if (b->copyShadow(a)) continue;
if (2==b->getCover()->intersect( high->wholecover )) {
res = true;
break;
}
}
return res;
}
bool Merge::mergeTest(HighVariable *high,vector<HighVariable *> &tmplist)
{
if (!high->hasCover()) return false;
for(int4 i=0;i<tmplist.size();++i) {
HighVariable *a = tmplist[i];
if (intersection(a,high))
return false;
}
tmplist.push_back(high);
return true;
}
#ifdef MERGEMULTI_DEBUG
void Merge::verifyHighCovers(void)
{
VarnodeLocSet::const_iterator iter,enditer;
enditer = data.endLoc();
for(iter=data.beginLoc();iter!=enditer;++iter) {
Varnode *vn = *iter;
if (vn->hasCover()) {
HighVariable *high = vn->getHigh();
if (!high->hasCopyIn1()) {
high->setCopyIn1();
high->verifyCover();
}
}
}
}
#endif