progress towards dominant COPY model

This commit is contained in:
caheckman 2019-04-30 12:13:58 -04:00
parent ec9e31483a
commit 00bbc8516b
6 changed files with 150 additions and 20 deletions

View File

@ -720,6 +720,39 @@ FlowBlock *FlowBlock::findCommonBlock(FlowBlock *bl1,FlowBlock *bl2)
return common;
}
/// Find the most immediate dominating FlowBlock of all blocks in the given set.
/// The container must not be empty.
/// \param blockSet is the given set of blocks
/// \return the most immediate dominating FlowBlock
FlowBlock *FlowBlock::findCommonBlock(const vector<FlowBlock *> &blockSet)
{
vector<FlowBlock *> markedSet;
FlowBlock *res = blockSet[0];
int4 bestIndex = res->getIndex();
res->setMark();
markedSet.push_back(res);
for(int4 i=0;i<blockSet.size();++i) {
if (bestIndex == 0)
break;
FlowBlock *bl = blockSet[i];
while(bl->getIndex() > bestIndex) {
if (bl->isMark()) break;
bl->setMark();
markedSet.push_back(bl);
bl = bl->getImmedDom();
}
if (bl->isMark()) continue;
res = bl;
bestIndex = res->getIndex();
res->setMark();
markedSet.push_back(res);
}
for(int4 i=0;i<markedSet.size();++i)
markedSet[i]->clearMark();
return res;
}
/// Add the given FlowBlock to the list and make \b this the parent
/// Update \b index so that it has the minimum over all components
/// \param bl is the given FlowBlock

View File

@ -257,6 +257,7 @@ public:
static bool compareBlockIndex(const FlowBlock *bl1,const FlowBlock *bl2); ///< Compare FlowBlock by index
static bool compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2); ///< Final FlowBlock comparison
static FlowBlock *findCommonBlock(FlowBlock *bl1,FlowBlock *bl2); ///< Find the common dominator of two FlowBlocks
static FlowBlock *findCommonBlock(const vector<FlowBlock *> &blockSet); ///< Find common dominator of multiple FlowBlocks
};
/// \brief A control-flow block built out of sub-components

View File

@ -3579,6 +3579,7 @@ bool ActionCopyMarker::shadowedVarnode(const Varnode *vn)
int4 ActionCopyMarker::apply(Funcdata &data)
{
vector<HighVariable *> multiCopy;
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
HighVariable *h1,*h2,*h3;
@ -3597,8 +3598,10 @@ int4 ActionCopyMarker::apply(Funcdata &data)
}
else { // COPY between different HighVariables
if (h1->hasCopyIn()) { // If we've seen other COPYs into this high
if (!h1->isCopyProcessed()) // and we haven't searched before,
data.getMerge().markRedundantCopies(h1); // search for redundant COPYs
if (!h1->isCopyProcessed()) { // and we haven't searched before,
multiCopy.push_back(h1);
h1->setCopyProcessed();
}
}
else
h1->setCopyIn();
@ -3641,6 +3644,8 @@ int4 ActionCopyMarker::apply(Funcdata &data)
break;
}
}
for(int4 i=0;i<multiCopy.size();++i)
data.getMerge().processCopyTrims(multiCopy[i]);
return 0;
}

View File

@ -957,20 +957,119 @@ bool Merge::checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp)
return true;
}
void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> &copy,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 created by removing all the COPYs from rootVn
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; // No intersections from domVn already proven
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) { // Don't bother if we only replace one COPY with another
for (int4 i = 0; i < size; ++i)
copy[pos + i]->setMark();
count = 0;
if (domCopyIsNew) {
data.opDestroy(domCopy);
}
}
// Replace all non-intersecting COPYs with read of dominating Varnode
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(),false);
}
}
/// \brief Search for and mark redundant COPY ops into the given high as \e non-printing
///
/// Trimming during the merge process can insert multiple COPYs from the same source. In some
/// cases, one or more COPYs may be redundant and shouldn't be printed. This method searches
/// for redundancy among COPY ops that assign to the given HighVariable.
/// \param high is the given HighVariable
/// \return \b true if any redundant COPYs were discovered
bool Merge::markRedundantCopies(HighVariable *high)
/// \param copy is the list of COPYs coming from the same source HighVariable
/// \param pos is the starting index of a set of COPYs coming from the same Varnode
/// \param size is the number of Varnodes in the set coming from the same Varnode
void Merge::markRedundantCopies(HighVariable *high,vector<PcodeOp *> &copy,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) {
// Make sure earlier index provides dominant op
PcodeOp *domOp = copy[pos + j];
if (domOp->isDead()) continue;
if (checkCopyPair(high, domOp, subOp)) {
data.opSetFlag(subOp, PcodeOp::nonprinting);
break;
}
}
}
}
void Merge::processCopyTrims(HighVariable *high)
{
bool hasRedundant = false;
vector<PcodeOp *> copyIns;
high->setCopyProcessed();
// Find all the COPY ops into this HighVariable from a different HighVariable
for(int4 i=0;i<high->numInstances();++i) {
Varnode *vn = high->getInstance(i);
@ -994,21 +1093,11 @@ bool Merge::markRedundantCopies(HighVariable *high)
sz += 1;
}
if (sz > 1) { // If there is more than one COPY in a group
for(int4 i=sz-1;i>0;--i) {
PcodeOp *subOp = copyIns[pos+i];
for(int4 j=i-1;j>=0;--j) {
// Make sure earlier index provides dominant op
if (checkCopyPair(high,copyIns[pos+j],subOp)) {
data.opSetFlag(subOp, PcodeOp::nonprinting);
hasRedundant = true;
break;
}
}
}
buildDominantCopy(high, copyIns, pos, sz);
markRedundantCopies(high, copyIns, pos, sz);
}
pos += sz;
}
return hasRedundant;
}
/// \brief Perform low-level details of merging two HighVariables if possible

View File

@ -105,6 +105,8 @@ class Merge {
void mergeLinear(vector<HighVariable *> &highvec);
bool merge(HighVariable *high1,HighVariable *high2,bool isspeculative);
bool checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp);
void buildDominantCopy(HighVariable *high,vector<PcodeOp *> &copy,int4 pos,int4 size);
void markRedundantCopies(HighVariable *high,vector<PcodeOp *> &copy,int4 pos,int4 size);
public:
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
bool intersection(HighVariable *a,HighVariable *b);
@ -118,7 +120,7 @@ public:
void mergeMarker(void);
void mergeAdjacent(void);
bool hideShadows(HighVariable *high);
bool markRedundantCopies(HighVariable *high);
void processCopyTrims(HighVariable *high);
};
/// \brief Compare HighVariables by the blocks they cover

View File

@ -63,7 +63,6 @@ private:
void updateFlags(void) const; ///< (Re)derive boolean properties of \b this from the member Varnodes
void updateCover(void) const; ///< (Re)derive the cover of \b this from the member Varnodes
void updateType(void) const; ///< (Re)derive the data-type for \b this from the member Varnodes
void setCopyProcessed(void) const { highflags |= copy_processed; } ///< Mark that \b this has had its COPY ins processed
public:
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
@ -114,6 +113,7 @@ public:
void setCopyIn(void) const { highflags |= copy_in; } ///< Mark the existence of COPY ops into \b this
bool hasCopyIn(void) const { return ((highflags&copy_in)!=0); } ///< Are there COPY ops into \b this
bool isCopyProcessed(void) const { return ((highflags&copy_processed)!=0); } ///< Have COPY ops into \b this been processed
void setCopyProcessed(void) const { highflags |= copy_processed; } ///< Mark that \b this has had its COPY ins processed
/// \brief Determine if \b this HighVariable has an associated cover.
///