#include "blockaction.hh"
#include "funcdata.hh"
FlowBlock *FloatingEdge::getCurrentEdge(int4 &outedge,FlowBlock *graph)
{
while(top->getParent() != graph)
top = top->getParent(); while(bottom->getParent() != graph)
bottom = bottom->getParent();
outedge = top->getOutIndex(bottom);
if (outedge < 0)
return (FlowBlock *)0; return top;
}
void LoopBody::extendToContainer(const LoopBody &container,vector<FlowBlock *> &body) const
{
int4 i = 0;
if (!container.head->isMark()) { container.head->setMark(); body.push_back(container.head);
i = 1; }
for(int4 j=0;j<container.tails.size();++j) {
FlowBlock *tail = container.tails[j];
if (!tail->isMark()) { tail->setMark();
body.push_back(tail); }
}
if (head != container.head) { int4 sizein = head->sizeIn();
for(int4 k=0;k<sizein;++k) {
if (head->isGotoIn(k)) continue; FlowBlock *bl = head->getIn(k);
if (bl->isMark()) continue; bl->setMark();
body.push_back(bl);
}
}
while(i < body.size()) {
FlowBlock *curblock = body[i++];
int4 sizein = curblock->sizeIn();
for(int4 k=0;k<sizein;++k) {
if (curblock->isGotoIn(k)) continue; FlowBlock *bl = curblock->getIn(k);
if (bl->isMark()) continue; bl->setMark();
body.push_back(bl);
}
}
}
FlowBlock *LoopBody::getCurrentBounds(FlowBlock **top,FlowBlock *graph)
{
while(head->getParent() != graph)
head = head->getParent(); FlowBlock *bottom;
for(int4 i=0;i<tails.size();++i) {
bottom = tails[i];
while(bottom->getParent() != graph)
bottom = bottom->getParent();
tails[i] = bottom;
if (bottom != head) { *top = head;
return bottom;
}
}
return (FlowBlock *)0;
}
void LoopBody::findBase(vector<FlowBlock *> &body)
{
head->setMark();
body.push_back(head);
for(int4 j=0;j<tails.size();++j) {
FlowBlock *tail = tails[j];
if (!tail->isMark()) {
tail->setMark();
body.push_back(tail);
}
}
uniquecount = body.size(); int4 i=1;
while(i < body.size()) {
FlowBlock *curblock = body[i++];
int4 sizein = curblock->sizeIn();
for(int4 k=0;k<sizein;++k) {
if (curblock->isGotoIn(k)) continue; FlowBlock *bl = curblock->getIn(k);
if (bl->isMark()) continue; bl->setMark();
body.push_back(bl);
}
}
}
void LoopBody::extend(vector<FlowBlock *> &body) const
{
vector<FlowBlock *> trial;
int4 i=0;
while(i<body.size()) {
FlowBlock *bl = body[i++];
int4 sizeout = bl->sizeOut();
for(int4 j=0;j<sizeout;++j) {
if (bl->isGotoOut(j)) continue; FlowBlock *curbl = bl->getOut(j);
if (curbl->isMark()) continue;
if (curbl == exitblock) continue;
int4 count = curbl->getVisitCount();
if (count == 0)
trial.push_back(curbl); count += 1;
curbl->setVisitCount(count);
if (count == curbl->sizeIn()) {
curbl->setMark();
body.push_back(curbl);
}
}
}
for(i=0;i<trial.size();++i)
trial[i]->setVisitCount(0); }
void LoopBody::findExit(const vector<FlowBlock *> &body)
{
vector<FlowBlock *> trialexit;
FlowBlock *tail;
for(int4 j=0;j<tails.size();++j) {
tail = tails[j];
int4 sizeout = tail->sizeOut();
for(int4 i=0;i<sizeout;++i) {
if (tail->isGotoOut(i)) continue; FlowBlock *curbl = tail->getOut(i);
if (!curbl->isMark()) {
if (immed_container == (LoopBody *)0) {
exitblock = curbl;
return;
}
trialexit.push_back(curbl);
}
}
}
for(int4 i=0;i<body.size();++i) {
FlowBlock *bl = body[i];
if ((i>0)&&(i<uniquecount)) continue; int4 sizeout = bl->sizeOut();
for(int4 j=0;j<sizeout;++j) {
if (bl->isGotoOut(j)) continue; FlowBlock *curbl = bl->getOut(j);
if (!curbl->isMark()) {
if (immed_container == (LoopBody *)0) {
exitblock = curbl;
return;
}
trialexit.push_back(curbl);
}
}
}
exitblock = (FlowBlock *)0; if (trialexit.empty())
return;
if (immed_container != (LoopBody *)0) {
vector<FlowBlock *> extension;
extendToContainer(*immed_container,extension);
for(int4 i=0;i<trialexit.size();++i) {
FlowBlock *bl = trialexit[i];
if (bl->isMark()) {
exitblock = bl;
break;
}
}
clearMarks(extension);
}
}
void LoopBody::orderTails(void)
{
if (tails.size() <= 1) return;
if (exitblock == (FlowBlock *)0) return;
int4 prefindex;
FlowBlock *trial;
for(prefindex=0;prefindex < tails.size(); ++prefindex) {
trial = tails[prefindex];
int4 sizeout = trial->sizeOut();
int4 j;
for(j=0;j<sizeout;++j)
if (trial->getOut(j) == exitblock) break;
if (j<sizeout) break;
}
if (prefindex >= tails.size()) return;
if (prefindex == 0) return;
tails[prefindex] = tails[0]; tails[0] = trial;
}
void LoopBody::labelExitEdges(const vector<FlowBlock *> &body)
{
vector<FlowBlock *> toexitblock;
for(int4 i=uniquecount;i<body.size();++i) { FlowBlock *curblock = body[i];
int4 sizeout = curblock->sizeOut();
for(int4 k=0;k<sizeout;++k) {
if (curblock->isGotoOut(k)) continue; FlowBlock *bl = curblock->getOut(k);
if (bl == exitblock) {
toexitblock.push_back(curblock);
continue; }
if (!bl->isMark())
exitedges.push_back(FloatingEdge(curblock,bl));
}
}
if (head != (FlowBlock *)0) {
int4 sizeout = head->sizeOut();
for(int4 k=0;k<sizeout;++k) {
if (head->isGotoOut(k)) continue; FlowBlock *bl = head->getOut(k);
if (bl == exitblock) {
toexitblock.push_back(head);
continue; }
if (!bl->isMark())
exitedges.push_back(FloatingEdge(head,bl));
}
}
for(int4 i=tails.size()-1;i>=0;--i) { FlowBlock *curblock = tails[i];
if (curblock == head) continue;
int4 sizeout = curblock->sizeOut();
for(int4 k=0;k<sizeout;++k) {
if (curblock->isGotoOut(k)) continue; FlowBlock *bl = curblock->getOut(k);
if (bl == exitblock) {
toexitblock.push_back(curblock);
continue; }
if (!bl->isMark())
exitedges.push_back(FloatingEdge(curblock,bl));
}
}
for(int4 i=0;i<toexitblock.size();++i) { FlowBlock *bl = toexitblock[i];
exitedges.push_back(FloatingEdge(bl,exitblock));
}
}
void LoopBody::labelContainments(const vector<FlowBlock *> &body,const vector<LoopBody *> &looporder)
{
vector<LoopBody *> containlist;
for(int4 i=0;i<body.size();++i) {
FlowBlock *curblock = body[i];
if (curblock != head) {
LoopBody *subloop = LoopBody::find(curblock,looporder);
if (subloop != (LoopBody *)0) {
containlist.push_back(subloop);
subloop->depth += 1;
}
}
}
for(int4 i=0;i<containlist.size();++i) { LoopBody *lb = containlist[i];
if ((lb->immed_container == (LoopBody *)0)||(lb->immed_container->depth < depth))
lb->immed_container = this;
}
}
void LoopBody::emitLikelyEdges(list<FloatingEdge> &likely,FlowBlock *graph)
{
while(head->getParent() != graph)
head = head->getParent();
if (exitblock != (FlowBlock *)0) {
while(exitblock->getParent() != graph)
exitblock = exitblock->getParent();
}
for(int4 i=0;i<tails.size();++i) {
FlowBlock *tail = tails[i];
while(tail->getParent() != graph)
tail = tail->getParent();
tails[i] = tail;
if (tail == exitblock) exitblock = (FlowBlock *)0;
}
list<FloatingEdge>::iterator iter,enditer;
iter = exitedges.begin();;
enditer = exitedges.end();
FlowBlock *holdin = (FlowBlock *)0;
FlowBlock *holdout = (FlowBlock *)0;
while(iter != enditer) {
int4 outedge;
FlowBlock *inbl = (*iter).getCurrentEdge(outedge,graph);
++iter;
if (inbl == (FlowBlock *)0) continue;
FlowBlock *outbl = inbl->getOut(outedge);
if (iter==enditer) {
if (outbl == exitblock) { holdin = inbl; holdout = outbl;
break;
}
}
likely.push_back(FloatingEdge(inbl,outbl));
}
for(int4 i=tails.size()-1;i>=0;--i) { if ((holdin!=(FlowBlock *)0)&&(i==0))
likely.push_back(FloatingEdge(holdin,holdout)); FlowBlock *tail = tails[i];
int4 sizeout = tail->sizeOut();
for(int4 j=0;j<sizeout;++j) {
FlowBlock *bl = tail->getOut(j);
if (bl == head) likely.push_back(FloatingEdge(tail,head)); }
}
}
void LoopBody::setExitMarks(FlowBlock *graph)
{
list<FloatingEdge>::iterator iter;
for(iter=exitedges.begin();iter!=exitedges.end();++iter) {
int4 outedge;
FlowBlock *inloop = (*iter).getCurrentEdge(outedge,graph);
if (inloop != (FlowBlock *)0)
inloop->setLoopExit(outedge);
}
}
void LoopBody::clearExitMarks(FlowBlock *graph)
{
list<FloatingEdge>::iterator iter;
for(iter=exitedges.begin();iter!=exitedges.end();++iter) {
int4 outedge;
FlowBlock *inloop = (*iter).getCurrentEdge(outedge,graph);
if (inloop != (FlowBlock *)0)
inloop->clearLoopExit(outedge);
}
}
void LoopBody::mergeIdenticalHeads(vector<LoopBody *> &looporder)
{
int4 i=0;
int4 j=i+1;
LoopBody *curbody = looporder[i];
while(j < looporder.size()) {
LoopBody *nextbody = looporder[j++];
if (nextbody->head == curbody->head) {
curbody->addTail( nextbody->tails[0] );
nextbody->head = (FlowBlock *)0; }
else {
i += 1;
looporder[i] = nextbody;
curbody = nextbody;
}
}
i += 1; looporder.resize(i);
}
bool LoopBody::compare_ends(LoopBody *a,LoopBody *b)
{
int4 aindex = a->head->getIndex();
int4 bindex = b->head->getIndex();
if (aindex != bindex)
return (aindex < bindex);
aindex = a->tails[0]->getIndex(); bindex = b->tails[0]->getIndex();
return (aindex < bindex);
}
int4 LoopBody::compare_head(LoopBody *a,FlowBlock *looptop)
{
int4 aindex = a->head->getIndex();
int4 bindex = looptop->getIndex();
if (aindex != bindex)
return (aindex < bindex) ? -1 : 1;
return 0;
}
void TraceDAG::BranchPoint::createTraces(void)
{
int4 sizeout = top->sizeOut();
for(int4 i=0;i<sizeout;++i) {
if (!top->isLoopDAGOut(i)) continue;
paths.push_back( new BlockTrace(this,paths.size(),i) );
}
}
void TraceDAG::BranchPoint::markPath(void)
{
BranchPoint *cur = this;
do {
cur->ismark = !cur->ismark;
cur = cur->parent;
} while(cur != (BranchPoint *)0);
}
int4 TraceDAG::BranchPoint::distance(BranchPoint *op2)
{
BranchPoint *cur = op2;
do {
if (cur->ismark) { return (depth - cur->depth) + (op2->depth - cur->depth);
}
cur = cur->parent;
} while(cur != (BranchPoint *)0);
return depth + op2->depth + 1;
}
FlowBlock *TraceDAG::BranchPoint::getPathStart(int4 i)
{
int4 res=0;
int4 sizeout = top->sizeOut();
for(int4 j=0;j<sizeout;++j) {
if (!top->isLoopDAGOut(j)) continue;
if (res == i)
return top->getOut(j);
res += 1;
}
return (FlowBlock *)0;
}
TraceDAG::BranchPoint::BranchPoint(void)
{
parent = (BranchPoint *)0;
depth = 0;
pathout = -1;
ismark = false;
top = (FlowBlock *)0;
}
TraceDAG::BranchPoint::BranchPoint(BlockTrace *parenttrace)
{
parent = parenttrace->top;
depth = parent->depth + 1;
pathout = parenttrace->pathout;
ismark = false;
top = parenttrace->destnode;
createTraces();
}
TraceDAG::BranchPoint::~BranchPoint(void)
{
for(int4 i=0;i<paths.size();++i)
delete paths[i];
}
TraceDAG::BlockTrace::BlockTrace(BranchPoint *t,int4 po,int4 eo)
{
flags = 0;
top = t;
pathout = po;
bottom = top->top;
destnode = bottom->getOut(eo);
edgelump = 1;
derivedbp = (BranchPoint *)0;
}
TraceDAG::BlockTrace::BlockTrace(BranchPoint *root,int4 po,FlowBlock *bl)
{
flags = 0;
top = root;
pathout = po;
bottom = (FlowBlock *)0;
destnode = bl;
edgelump = 1;
derivedbp = (BranchPoint *)0;
}
bool TraceDAG::BadEdgeScore::compareFinal(const BadEdgeScore &op2) const
{
if (siblingedge != op2.siblingedge)
return (op2.siblingedge < siblingedge); if (terminal !=op2.terminal)
return (terminal < op2.terminal);
if (distance != op2.distance)
return (distance < op2.distance); return (trace->top->depth < op2.trace->top->depth); }
bool TraceDAG::BadEdgeScore::operator<(const BadEdgeScore &op2) const
{
int4 thisind = exitproto->getIndex();
int4 op2ind = op2.exitproto->getIndex();
if (thisind != op2ind) return (thisind < op2ind);
FlowBlock *tmpbl = trace->top->top;
thisind = (tmpbl != (FlowBlock *)0) ? tmpbl->getIndex() : -1;
tmpbl = op2.trace->top->top;
op2ind = (tmpbl != (FlowBlock *)0) ? tmpbl->getIndex() : -1;
if (thisind != op2ind) return (thisind < op2ind);
thisind = trace->pathout;
op2ind = op2.trace->pathout; return (thisind < op2ind);
}
void TraceDAG::removeTrace(BlockTrace *trace)
{
likelygoto.push_back(FloatingEdge(trace->bottom,trace->destnode)); trace->destnode->setVisitCount( trace->destnode->getVisitCount() + trace->edgelump );
BranchPoint *parentbp = trace->top;
if (trace->bottom != parentbp->top) { trace->flags |= BlockTrace::f_terminal;
trace->bottom = (FlowBlock *)0;
trace->destnode = (FlowBlock *)0;
trace->edgelump = 0;
return;
}
removeActive(trace); int4 size = parentbp->paths.size();
for(int4 i=trace->pathout+1;i<size;++i) { BlockTrace *movedtrace = parentbp->paths[i];
movedtrace->pathout -= 1; BranchPoint *derivedbp = movedtrace->derivedbp;
if (derivedbp != (BranchPoint *)0)
derivedbp->pathout -= 1; parentbp->paths[i-1] = movedtrace;
}
parentbp->paths.pop_back();
delete trace; }
void TraceDAG::processExitConflict(list<BadEdgeScore>::iterator start,list<BadEdgeScore>::iterator end)
{
list<BadEdgeScore>::iterator iter;
BranchPoint *startbp;
while(start != end) {
iter = start;
++iter;
startbp = (*start).trace->top;
if (iter != end) {
startbp->markPath(); do {
if (startbp == (*iter).trace->top) { (*start).siblingedge += 1;
(*iter).siblingedge += 1;
}
int4 dist = startbp->distance( (*iter).trace->top );
if (((*start).distance == -1)||((*start).distance > dist))
(*start).distance = dist;
if (((*iter).distance == -1)||((*iter).distance > dist))
(*iter).distance = dist;
++iter;
} while(iter != end);
startbp->markPath(); }
++start;
}
}
TraceDAG::BlockTrace *TraceDAG::selectBadEdge(void)
{
list<BadEdgeScore> badedgelist;
list<BlockTrace *>::const_iterator aiter;
for(aiter=activetrace.begin();aiter!=activetrace.end();++aiter) {
if ((*aiter)->isTerminal()) continue;
if (((*aiter)->top->top == (FlowBlock *)0)&&((*aiter)->bottom==(FlowBlock *)0))
continue; badedgelist.emplace_back();
BadEdgeScore &score( badedgelist.back() );
score.trace = *aiter;
score.exitproto = score.trace->destnode;
score.distance = -1;
score.siblingedge = 0;
score.terminal = (score.trace->destnode->sizeOut()==0) ? 1 : 0;
}
badedgelist.sort();
list<BadEdgeScore>::iterator iter=badedgelist.begin();
list<BadEdgeScore>::iterator startiter = iter;
FlowBlock *curbl = (*iter).exitproto;
int4 samenodecount = 1;
++iter;
while(iter != badedgelist.end()) { BadEdgeScore &score( *iter );
if (curbl == score.exitproto) {
samenodecount += 1; ++iter;
}
else { if (samenodecount > 1)
processExitConflict(startiter,iter);
curbl = score.exitproto;
startiter = iter;
samenodecount = 1;
++iter;
}
}
if (samenodecount > 1) processExitConflict(startiter,iter);
iter = badedgelist.begin();
list<BadEdgeScore>::iterator maxiter = iter;
++iter;
while(iter != badedgelist.end()) {
if ((*maxiter).compareFinal( *iter )) {
maxiter = iter;
}
++iter;
}
return (*maxiter).trace;
}
void TraceDAG::insertActive(BlockTrace *trace)
{
activetrace.push_back(trace);
list<BlockTrace *>::iterator iter = activetrace.end();
--iter;
trace->activeiter = iter;
trace->flags |= BlockTrace::f_active;
activecount += 1;
}
void TraceDAG::removeActive(BlockTrace *trace)
{
activetrace.erase(trace->activeiter);
trace->flags &= ~((uint4)BlockTrace::f_active);
activecount -= 1;
}
bool TraceDAG::checkOpen(BlockTrace *trace)
{
if (trace->isTerminal()) return false; bool isroot = false;
if (trace->top->depth == 0) {
if (trace->bottom == (FlowBlock *)0)
return true; isroot = true;
}
FlowBlock *bl = trace->destnode;
if ((bl == finishblock)&&(!isroot))
return false; int4 ignore = trace->edgelump + bl->getVisitCount();
int4 count = 0;
for(int4 i=0;i<bl->sizeIn();++i) {
if (bl->isLoopDAGIn(i)) {
count += 1;
if (count > ignore) return false;
}
}
return true;
}
list<TraceDAG::BlockTrace *>::iterator TraceDAG::openBranch(BlockTrace *parent)
{
BranchPoint *newbranch = new BranchPoint( parent );
parent->derivedbp = newbranch;
if (newbranch->paths.size() == 0) { delete newbranch;
parent->derivedbp = (BranchPoint *)0;
parent->flags |= BlockTrace::f_terminal; parent->bottom = (FlowBlock *)0;
parent->destnode = (FlowBlock *)0;
parent->edgelump = 0;
return parent->activeiter;
}
removeActive(parent);
branchlist.push_back( newbranch );
for(int4 i=0;i<newbranch->paths.size();++i)
insertActive(newbranch->paths[i]);
return newbranch->paths[0]->activeiter;
}
bool TraceDAG::checkRetirement(BlockTrace *trace,FlowBlock *&exitblock)
{
if (trace->pathout != 0) return false; BranchPoint *bp = trace->top;
if (bp->depth == 0) { for(int4 i=0;i<bp->paths.size();++i) {
BlockTrace *curtrace = bp->paths[i];
if (!curtrace->isActive()) return false;
if (!curtrace->isTerminal()) return false; }
return true;
}
FlowBlock *outblock = (FlowBlock *)0;
for(int4 i=0;i<bp->paths.size();++i) {
BlockTrace *curtrace = bp->paths[i];
if (!curtrace->isActive()) return false;
if (curtrace->isTerminal()) continue;
if (outblock == curtrace->destnode) continue;
if (outblock != (FlowBlock *)0) return false;
outblock = curtrace->destnode;
}
exitblock = outblock;
return true;
}
list<TraceDAG::BlockTrace *>::iterator TraceDAG::retireBranch(BranchPoint *bp,FlowBlock *exitblock)
{
FlowBlock *edgeout_bl = (FlowBlock *)0;
int4 edgelump_sum = 0;
for(int4 i=0;i<bp->paths.size();++i) {
BlockTrace *curtrace = bp->paths[i];
if (!curtrace->isTerminal()) {
edgelump_sum += curtrace->edgelump;
if (edgeout_bl == (FlowBlock *)0)
edgeout_bl = curtrace->bottom;
}
removeActive(curtrace); }
if (bp->depth == 0) return activetrace.begin();
if (bp->parent != (BranchPoint *)0) {
BlockTrace *parenttrace = bp->parent->paths[bp->pathout];
parenttrace->derivedbp = (BranchPoint *)0; if (edgeout_bl == (FlowBlock *)0) { parenttrace->flags |= BlockTrace::f_terminal;
parenttrace->bottom = (FlowBlock *)0;
parenttrace->destnode = (FlowBlock *)0;
parenttrace->edgelump = 0;
}
else {
parenttrace->bottom = edgeout_bl;
parenttrace->destnode = exitblock;
parenttrace->edgelump = edgelump_sum;
}
insertActive(parenttrace); return parenttrace->activeiter;
}
return activetrace.begin();
}
void TraceDAG::clearVisitCount(void)
{
list<FloatingEdge>::const_iterator iter;
for(iter=likelygoto.begin();iter!=likelygoto.end();++iter)
(*iter).getBottom()->setVisitCount(0);
}
TraceDAG::TraceDAG(list<FloatingEdge> &lg)
: likelygoto(lg)
{
activecount = 0;
finishblock = (FlowBlock *)0;
}
TraceDAG::~TraceDAG(void)
{
for(int4 i=0;i<branchlist.size();++i)
delete branchlist[i];
}
void TraceDAG::initialize(void)
{
BranchPoint *rootBranch = new BranchPoint(); branchlist.push_back(rootBranch);
for(uint4 i=0;i<rootlist.size();++i) { BlockTrace *newtrace = new BlockTrace(rootBranch,rootBranch->paths.size(),rootlist[i]);
rootBranch->paths.push_back(newtrace);
insertActive(newtrace);
}
}
void TraceDAG::pushBranches(void)
{
FlowBlock *exitblock;
current_activeiter = activetrace.begin();
missedactivecount = 0;
while(activecount > 0) {
if (current_activeiter == activetrace.end())
current_activeiter = activetrace.begin();
BlockTrace *curtrace = *current_activeiter;
if (missedactivecount >= activecount) { BlockTrace *badtrace = selectBadEdge(); removeTrace(badtrace); current_activeiter = activetrace.begin();
missedactivecount = 0;
}
else if (checkRetirement(curtrace,exitblock)) {
current_activeiter = retireBranch(curtrace->top,exitblock);
missedactivecount = 0;
}
else if (checkOpen(curtrace)) {
current_activeiter = openBranch(curtrace);
missedactivecount = 0;
}
else {
missedactivecount += 1;
current_activeiter++;
}
}
clearVisitCount();
}
LoopBody *LoopBody::find(FlowBlock *looptop,const vector<LoopBody *> &looporder)
{
int4 min=0;
int4 max=looporder.size()-1;
while(min<=max) {
int4 mid = (min + max)/2;
int4 comp = compare_head(looporder[mid],looptop);
if (comp == 0) return looporder[mid];
if (comp < 0)
min = mid + 1;
else
max = mid - 1;
}
return (LoopBody *)0;
}
void LoopBody::clearMarks(vector<FlowBlock *> &body)
{
for(int4 i=0;i<body.size();++i)
body[i]->clearMark();
}
void CollapseStructure::onlyReachableFromRoot(FlowBlock *root,vector<FlowBlock *> &body)
{
vector<FlowBlock *> trial;
int4 i=0;
root->setMark();
body.push_back(root);
while(i<body.size()) {
FlowBlock *bl = body[i++];
int4 sizeout = bl->sizeOut();
for(int4 j=0;j<sizeout;++j) {
FlowBlock *curbl = bl->getOut(j);
if (curbl->isMark()) continue;
int4 count = curbl->getVisitCount();
if (count == 0)
trial.push_back(curbl); count += 1;
curbl->setVisitCount(count);
if (count == curbl->sizeIn()) {
curbl->setMark();
body.push_back(curbl);
}
}
}
for(i=0;i<trial.size();++i)
trial[i]->setVisitCount(0); }
int4 CollapseStructure::markExitsAsGotos(vector<FlowBlock *> &body)
{
int4 changecount = 0;
for(int4 i=0;i<body.size();++i) {
FlowBlock *bl = body[i];
int4 sizeout = bl->sizeOut();
for(int4 j=0;j<sizeout;++j) {
FlowBlock *curbl = bl->getOut(j);
if (!curbl->isMark()) {
bl->setGotoBranch(j); changecount += 1;
}
}
}
return changecount;
}
bool CollapseStructure::clipExtraRoots(void)
{
for(int4 i=1;i<graph.getSize();++i) { FlowBlock *bl = graph.getBlock(i);
if (bl->sizeIn() != 0) continue;
vector<FlowBlock *> body;
onlyReachableFromRoot(bl,body);
int4 count = markExitsAsGotos(body);
LoopBody::clearMarks(body);
if (count != 0)
return true;
}
return false;
}
void CollapseStructure::labelLoops(vector<LoopBody *> &looporder)
{
for(int4 i=0;i<graph.getSize();++i) {
FlowBlock *bl = graph.getBlock(i);
int4 sizein = bl->sizeIn();
for(int4 j=0;j<sizein;++j) {
if (bl->isBackEdgeIn(j)) { FlowBlock *loopbottom = bl->getIn(j);
loopbody.emplace_back(bl);
LoopBody &curbody( loopbody.back() );
curbody.addTail(loopbottom);
looporder.push_back( & curbody );
}
}
}
sort(looporder.begin(),looporder.end(),LoopBody::compare_ends);
}
void CollapseStructure::orderLoopBodies(void)
{
vector<LoopBody *> looporder;
labelLoops(looporder);
if (!loopbody.empty()) {
int4 oldsize = looporder.size();
LoopBody::mergeIdenticalHeads(looporder);
list<LoopBody>::iterator iter;
if (oldsize != looporder.size()) { iter = loopbody.begin();
while(iter != loopbody.end()) {
if ((*iter).getHead() == (FlowBlock *)0) {
list<LoopBody>::iterator deliter = iter;
++iter;
loopbody.erase(deliter); }
else
++iter;
}
}
for(iter=loopbody.begin();iter!=loopbody.end();++iter) {
vector<FlowBlock *> body;
(*iter).findBase(body);
(*iter).labelContainments(body,looporder);
LoopBody::clearMarks(body);
}
loopbody.sort(); for(iter=loopbody.begin();iter!=loopbody.end();++iter) {
vector<FlowBlock *> body;
(*iter).findBase(body);
(*iter).findExit(body);
(*iter).orderTails();
(*iter).extend(body);
(*iter).labelExitEdges(body);
LoopBody::clearMarks(body);
}
}
likelylistfull = false;
loopbodyiter = loopbody.begin();
}
bool CollapseStructure::updateLoopBody(void)
{
FlowBlock *loopbottom = (FlowBlock *)0;
FlowBlock *looptop = (FlowBlock *)0;
if (finaltrace) { if (likelyiter == likelygoto.end())
return false; return true;
}
while (loopbodyiter != loopbody.end()) { loopbottom = (*loopbodyiter).getCurrentBounds(&looptop,&graph);
if (loopbottom != (FlowBlock *)0) {
if ((!likelylistfull) ||
(likelyiter != likelygoto.end())) break; }
++loopbodyiter;
likelylistfull = false; loopbottom = (FlowBlock *)0;
}
if (likelylistfull) return true;
likelygoto.clear(); TraceDAG tracer(likelygoto);
if (loopbottom != (FlowBlock *)0) {
tracer.addRoot( looptop ); tracer.setFinishBlock(loopbottom);
(*loopbodyiter).setExitMarks(&graph); }
else {
finaltrace = true;
for(uint4 i=0;i<graph.getSize();++i) {
FlowBlock *bl = graph.getBlock(i);
if (bl->sizeIn() == 0)
tracer.addRoot(bl);
}
}
tracer.initialize();
tracer.pushBranches();
if (loopbottom != (FlowBlock *)0) {
(*loopbodyiter).emitLikelyEdges(likelygoto,&graph);
(*loopbodyiter).clearExitMarks(&graph);
}
likelylistfull = true;
likelyiter = likelygoto.begin();
return true;
}
FlowBlock *CollapseStructure::selectGoto(void)
{
while(updateLoopBody()) {
while(likelyiter != likelygoto.end()) {
int4 outedge;
FlowBlock *startbl = (*likelyiter).getCurrentEdge(outedge,&graph);
++likelyiter;
if (startbl != (FlowBlock *)0) {
startbl->setGotoBranch(outedge); return startbl;
}
}
}
if (!clipExtraRoots())
throw LowlevelError("Could not finish collapsing block structure");
return (FlowBlock *)0;
}
bool CollapseStructure::ruleBlockCat(FlowBlock *bl)
{
FlowBlock *outblock,*outbl2;
if (bl->sizeOut() != 1) return false;
if (bl->isSwitchOut()) return false;
if ((bl->sizeIn()==1)&&(bl->getIn(0)->sizeOut()==1)) return false; outblock = bl->getOut(0);
if (outblock == bl) return false; if (outblock->sizeIn() != 1) return false; if (!bl->isDecisionOut(0)) return false; if (outblock->isSwitchOut()) return false;
vector<FlowBlock *> nodes;
nodes.push_back(bl); nodes.push_back(outblock);
while(outblock->sizeOut()==1) {
outbl2 = outblock->getOut(0);
if (outbl2 == bl) break; if (outbl2->sizeIn() != 1) break; if (!outblock->isDecisionOut(0)) break; if (outbl2->isSwitchOut()) break; outblock = outbl2;
nodes.push_back(outblock); }
graph.newBlockList(nodes); return true;
}
bool CollapseStructure::ruleBlockOr(FlowBlock *bl)
{
FlowBlock *orblock,*clauseblock;
int4 i,j;
if (bl->sizeOut() != 2) return false;
if (bl->isGotoOut(0)) return false;
if (bl->isGotoOut(1)) return false;
if (bl->isSwitchOut()) return false;
for(i=0;i<2;++i) {
orblock = bl->getOut(i); if (orblock==bl) continue; if (orblock->sizeIn()!=1) continue; if (orblock->sizeOut()!=2) continue; if (orblock->isInteriorGotoTarget()) continue; if (orblock->isSwitchOut()) continue;
if (bl->isBackEdgeOut(i)) continue; if (orblock->isComplex()) continue;
clauseblock = bl->getOut(1-i);
if (clauseblock == bl) continue; if (clauseblock == orblock) continue;
for(j=0;j<2;++j) {
if (clauseblock != orblock->getOut(j)) continue; break;
}
if (j==2) continue;
if (orblock->getOut(1-j) == bl) continue;
if (i==1) { if (bl->negateCondition(true))
dataflow_changecount += 1;
}
if (j==0) { if (orblock->negateCondition(true))
dataflow_changecount += 1;
}
graph.newBlockCondition(bl,orblock);
return true;
}
return false;
}
bool CollapseStructure::ruleBlockProperIf(FlowBlock *bl)
{
FlowBlock *clauseblock,*outblock;
int4 i;
if (bl->sizeOut() != 2) return false; if (bl->isSwitchOut()) return false;
if (bl->getOut(0) == bl) return false; if (bl->getOut(1) == bl) return false;
if (bl->isGotoOut(0)) return false; if (bl->isGotoOut(1)) return false;
for(i=0;i<2;++i) {
clauseblock = bl->getOut(i);
if (clauseblock->sizeIn() != 1) continue; if (clauseblock->sizeOut() != 1) continue; if (clauseblock->isSwitchOut()) continue; if (!bl->isDecisionOut(i)) continue; if (clauseblock->isGotoOut(0)) continue; outblock = clauseblock->getOut(0);
if (outblock != bl->getOut(1-i)) continue;
if (i==0) { if (bl->negateCondition(true))
dataflow_changecount += 1;
}
graph.newBlockIf(bl,clauseblock);
return true;
}
return false;
}
bool CollapseStructure::ruleBlockIfElse(FlowBlock *bl)
{
FlowBlock *tc,*fc,*outblock;
if (bl->sizeOut() != 2) return false; if (bl->isSwitchOut()) return false;
if (!bl->isDecisionOut(0)) return false;
if (!bl->isDecisionOut(1)) return false;
tc = bl->getTrueOut();
fc = bl->getFalseOut();
if (tc->sizeIn() != 1) return false; if (fc->sizeIn() != 1) return false;
if (tc->sizeOut() != 1) return false; if (fc->sizeOut() != 1) return false; outblock = tc->getOut(0);
if (outblock == bl) return false; if (outblock != fc->getOut(0)) return false;
if (tc->isSwitchOut()) return false;
if (fc->isSwitchOut()) return false;
if (tc->isGotoOut(0)) return false;
if (fc->isGotoOut(0)) return false;
graph.newBlockIfElse(bl,tc,fc);
return true;
}
bool CollapseStructure::ruleBlockGoto(FlowBlock *bl)
{
int4 sizeout = bl->sizeOut();
for(int4 i=0;i<sizeout;++i) {
if (bl->isGotoOut(i)) {
if (bl->isSwitchOut()) {
graph.newBlockMultiGoto(bl,i);
return true;
}
if (sizeout == 2) {
if (!bl->isGotoOut(1)) { if (bl->negateCondition(true))
dataflow_changecount += 1;
}
graph.newBlockIfGoto(bl);
return true;
}
if (sizeout == 1) {
graph.newBlockGoto(bl);
return true;
}
}
}
return false;
}
bool CollapseStructure::ruleBlockIfNoExit(FlowBlock *bl)
{
FlowBlock *clauseblock;
int4 i;
if (bl->sizeOut() != 2) return false; if (bl->isSwitchOut()) return false;
if (bl->getOut(0) == bl) return false; if (bl->getOut(1) == bl) return false;
if (bl->isGotoOut(0)) return false;
if (bl->isGotoOut(1)) return false;
for(i=0;i<2;++i) {
clauseblock = bl->getOut(i);
if (clauseblock->sizeIn() != 1) continue; if (clauseblock->sizeOut() != 0) continue; if (clauseblock->isSwitchOut()) continue;
if (!bl->isDecisionOut(i)) continue;
if (i==0) { if (bl->negateCondition(true))
dataflow_changecount += 1;
}
graph.newBlockIf(bl,clauseblock);
return true;
}
return false;
}
bool CollapseStructure::ruleBlockWhileDo(FlowBlock *bl)
{
FlowBlock *clauseblock;
int4 i;
if (bl->sizeOut() != 2) return false; if (bl->isSwitchOut()) return false;
if (bl->getOut(0) == bl) return false; if (bl->getOut(1) == bl) return false;
if (bl->isInteriorGotoTarget()) return false;
if (bl->isGotoOut(0)) return false;
if (bl->isGotoOut(1)) return false;
for(i=0;i<2;++i) {
clauseblock = bl->getOut(i);
if (clauseblock->sizeIn() != 1) continue; if (clauseblock->sizeOut() != 1) continue; if (clauseblock->isSwitchOut()) continue;
if (clauseblock->getOut(0) != bl) continue;
bool overflow = bl->isComplex(); if ((i==0)!=overflow) { if (bl->negateCondition(true))
dataflow_changecount += 1;
}
BlockWhileDo *newbl = graph.newBlockWhileDo(bl,clauseblock);
if (overflow)
newbl->setOverflowSyntax();
return true;
}
return false;
}
bool CollapseStructure::ruleBlockDoWhile(FlowBlock *bl)
{
int4 i;
if (bl->sizeOut() != 2) return false; if (bl->isSwitchOut()) return false;
if (bl->isGotoOut(0)) return false;
if (bl->isGotoOut(1)) return false;
for(i=0;i<2;++i) {
if (bl->getOut(i) != bl) continue; if (i==0) { if (bl->negateCondition(true))
dataflow_changecount += 1;
}
graph.newBlockDoWhile(bl);
return true;
}
return false;
}
bool CollapseStructure::ruleBlockInfLoop(FlowBlock *bl)
{
if (bl->sizeOut() != 1) return false;
if (bl->isGotoOut(0)) return false;
if (bl->getOut(0) != bl) return false; graph.newBlockInfLoop(bl);
return true;
}
bool CollapseStructure::checkSwitchSkips(FlowBlock *switchbl,FlowBlock *exitblock)
{
if (exitblock == (FlowBlock *)0) return true;
int4 sizeout,edgenum;
sizeout = switchbl->sizeOut();
bool defaultnottoexit = false;
bool anyskiptoexit = false;
for(edgenum=0;edgenum<sizeout;++edgenum) {
if (switchbl->getOut(edgenum) == exitblock) {
if (!switchbl->isDefaultBranch(edgenum))
anyskiptoexit = true;
}
else {
if (switchbl->isDefaultBranch(edgenum))
defaultnottoexit = true;
}
}
if (!anyskiptoexit) return true;
if ((!defaultnottoexit)&&(switchbl->getType() == FlowBlock::t_multigoto)) {
BlockMultiGoto *multibl = (BlockMultiGoto *)switchbl;
if (multibl->hasDefaultGoto())
defaultnottoexit = true;
}
if (!defaultnottoexit) return true;
for(edgenum=0;edgenum<sizeout;++edgenum) {
if (switchbl->getOut(edgenum) == exitblock) {
if (!switchbl->isDefaultBranch(edgenum))
switchbl->setGotoBranch(edgenum);
}
}
return false;
}
bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl)
{
if (!bl->isSwitchOut()) return false;
FlowBlock *exitblock = (FlowBlock *)0;
int4 sizeout = bl->sizeOut();
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl == bl) {
exitblock = curbl; break;
}
if (curbl->sizeOut() > 1) {
exitblock = curbl;
break;
}
if (curbl->sizeIn() > 1) {
exitblock = curbl;
break;
}
}
if (exitblock == (FlowBlock *)0) {
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl->isGotoIn(0)) return false; if (curbl->isSwitchOut()) return false; if (curbl->sizeOut() == 1) {
if (curbl->isGotoOut(0)) return false; if (exitblock != (FlowBlock *)0) {
if (exitblock != curbl->getOut(0)) return false;
}
else {
exitblock = curbl->getOut(0);
}
}
}
}
else { for(int4 i=0;i<exitblock->sizeIn();++i) if (exitblock->isGotoIn(i)) return false;
for(int4 i=0;i<exitblock->sizeOut();++i) if (exitblock->isGotoOut(i)) return false;
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl == exitblock) continue; if (curbl->sizeIn() > 1) return false; if (curbl->isGotoIn(0)) return false; if (curbl->sizeOut() > 1) return false; if (curbl->sizeOut() == 1) {
if (curbl->isGotoOut(0)) return false; if (curbl->getOut(0) != exitblock) return false; }
if (curbl->isSwitchOut()) return false; }
}
if (!checkSwitchSkips(bl,exitblock))
return true;
vector<FlowBlock *> cases;
cases.push_back(bl);
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl == exitblock) continue; cases.push_back(curbl);
}
graph.newBlockSwitch(cases,(exitblock != (FlowBlock *)0));
return true;
}
bool CollapseStructure::ruleCaseFallthru(FlowBlock *bl)
{
if (!bl->isSwitchOut()) return false;
int4 sizeout = bl->sizeOut();
int4 nonfallthru = 0; vector<FlowBlock *> fallthru;
for(int4 i=0;i<sizeout;++i) {
FlowBlock *curbl = bl->getOut(i);
if (curbl == bl) return false; if ((curbl->sizeIn() > 2)||(curbl->sizeOut() > 1))
nonfallthru += 1;
else if (curbl->sizeOut()==1) {
FlowBlock *target = curbl->getOut(0);
if ((target->sizeIn()==2)&&(target->sizeOut()<=1)) {
int4 inslot = curbl->getOutRevIndex(0);
if (target->getIn(1-inslot)==bl)
fallthru.push_back(curbl);
}
}
if (nonfallthru > 1) return false; }
if (fallthru.empty()) return false;
for(int4 i=0;i<fallthru.size();++i) {
FlowBlock *curbl = fallthru[i];
curbl->setGotoBranch(0);
}
return true;
}
int4 CollapseStructure::collapseInternal(FlowBlock *targetbl)
{
int4 index;
bool change,fullchange;
int4 isolated_count;
FlowBlock *bl;
do {
do {
change = false;
index = 0;
isolated_count = 0;
while(index < graph.getSize()) {
if (targetbl == (FlowBlock *)0) {
bl = graph.getBlock(index);
index += 1;
}
else {
bl = targetbl; change = true; targetbl = (FlowBlock *)0; index = graph.getSize();
}
if ((bl->sizeIn()==0)&&(bl->sizeOut()==0)) { isolated_count += 1;
continue; }
if (ruleBlockGoto(bl)) {
change = true;
continue;
}
if (ruleBlockCat(bl)) {
change = true;
continue;
}
if (ruleBlockProperIf(bl)) {
change = true;
continue;
}
if (ruleBlockIfElse(bl)) {
change = true;
continue;
}
if (ruleBlockWhileDo(bl)) {
change = true;
continue;
}
if (ruleBlockDoWhile(bl)) {
change = true;
continue;
}
if (ruleBlockInfLoop(bl)) {
change = true;
continue;
}
if (ruleBlockSwitch(bl)) {
change = true;
continue;
}
}
} while(change);
fullchange = false;
for(index=0;index<graph.getSize();++index) {
bl = graph.getBlock(index);
if (ruleBlockIfNoExit(bl)) { fullchange = true;
break;
}
if (ruleCaseFallthru(bl)) { fullchange = true;
break;
}
}
} while(fullchange);
return isolated_count;
}
void CollapseStructure::collapseConditions(void)
{
bool change;
do {
change = false;
for(int4 i=0;i<graph.getSize();++i) {
if (ruleBlockOr(graph.getBlock(i)))
change = true;
}
} while(change);
}
CollapseStructure::CollapseStructure(BlockGraph &g)
: graph(g)
{
dataflow_changecount = 0;
}
void CollapseStructure::collapseAll(void)
{
int4 isolated_count;
finaltrace = false;
graph.clearVisitCount();
orderLoopBodies();
collapseConditions();
isolated_count = collapseInternal((FlowBlock *)0);
while(isolated_count < graph.getSize()) {
FlowBlock *targetbl = selectGoto();
isolated_count = collapseInternal(targetbl);
}
}
bool ConditionalJoin::MergePair::operator<(const MergePair &op2) const
{
uint4 s1 = side1->getCreateIndex();
uint4 s2 = op2.side1->getCreateIndex();
if (s1 != s2)
return (s1 < s2);
return (side2->getCreateIndex() < op2.side2->getCreateIndex());
}
bool ConditionalJoin::findDups(void)
{
cbranch1 = block1->lastOp();
if (cbranch1->code() != CPUI_CBRANCH) return false;
cbranch2 = block2->lastOp();
if (cbranch2->code() != CPUI_CBRANCH) return false;
if (cbranch1->isBooleanFlip()) return false; if (cbranch2->isBooleanFlip()) return false;
Varnode *vn1 = cbranch1->getIn(1);
Varnode *vn2 = cbranch2->getIn(1);
if (vn1 == vn2)
return true;
if (!vn1->isWritten()) return false;
if (!vn2->isWritten()) return false;
if (vn1->isSpacebase()) return false;
if (vn2->isSpacebase()) return false;
Varnode *buf1[2];
Varnode *buf2[2];
int4 res = functionalEqualityLevel(vn1,vn2,buf1,buf2);
if (res < 0) return false;
if (res > 1) return false;
PcodeOp *op1 = vn1->getDef();
if (op1->code() == CPUI_SUBPIECE) return false;
if (op1->code() == CPUI_COPY) return false;
mergeneed[ MergePair(vn1,vn2) ] = (Varnode *)0;
return true;
}
void ConditionalJoin::checkExitBlock(BlockBasic *exit,int4 in1,int4 in2)
{
list<PcodeOp *>::const_iterator iter,enditer;
iter = exit->beginOp();
enditer = exit->endOp();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->code() == CPUI_MULTIEQUAL) { Varnode *vn1 = op->getIn(in1);
Varnode *vn2 = op->getIn(in2);
if (vn1 != vn2)
mergeneed[ MergePair(vn1,vn2) ] = (Varnode *)0;
}
else if (op->code() != CPUI_COPY) break;
}
}
void ConditionalJoin::cutDownMultiequals(BlockBasic *exit,int4 in1,int4 in2)
{
list<PcodeOp *>::const_iterator iter,enditer;
int4 lo,hi;
if (in1 > in2) {
hi = in1;
lo = in2;
}
else {
hi = in2;
lo = in1;
}
iter = exit->beginOp();
enditer = exit->endOp();
while(iter != enditer) {
PcodeOp *op = *iter;
++iter; if (op->code() == CPUI_MULTIEQUAL) {
Varnode *vn1 = op->getIn(in1);
Varnode *vn2 = op->getIn(in2);
if (vn1 == vn2) {
data.opRemoveInput(op,hi);
}
else {
Varnode *subvn = mergeneed[ MergePair(vn1,vn2) ];
data.opRemoveInput(op,hi);
data.opSetInput(op,subvn,lo);
}
if (op->numInput() == 1) {
data.opUninsert(op);
data.opSetOpcode(op,CPUI_COPY);
data.opInsertBegin(op,exit);
}
}
else if (op->code() != CPUI_COPY) break;
}
}
void ConditionalJoin::setupMultiequals(void)
{
map<MergePair,Varnode *>::iterator iter;
for(iter=mergeneed.begin();iter!=mergeneed.end();++iter) {
if ((*iter).second != (Varnode *)0) continue;
Varnode *vn1 = (*iter).first.side1;
Varnode *vn2 = (*iter).first.side2;
PcodeOp *multi = data.newOp(2,cbranch1->getAddr());
data.opSetOpcode(multi,CPUI_MULTIEQUAL);
Varnode *outvn = data.newUniqueOut(vn1->getSize(),multi);
data.opSetInput(multi,vn1,0);
data.opSetInput(multi,vn2,1);
(*iter).second = outvn;
data.opInsertEnd(multi,joinblock);
}
}
void ConditionalJoin::moveCbranch(void)
{
Varnode *vn1 = cbranch1->getIn(1);
Varnode *vn2 = cbranch2->getIn(1);
data.opUninsert(cbranch1);
data.opInsertEnd(cbranch1,joinblock);
Varnode *vn;
if (vn1 != vn2)
vn = mergeneed[ MergePair(vn1,vn2) ];
else
vn = vn1;
data.opSetInput(cbranch1,vn,1);
data.opDestroy(cbranch2);
}
bool ConditionalJoin::match(BlockBasic *b1,BlockBasic *b2)
{
block1 = b1;
block2 = b2;
if (block2 == block1) return false;
if (block1->sizeOut() != 2) return false;
if (block2->sizeOut() != 2) return false;
exita = (BlockBasic *)block1->getOut(0);
exitb = (BlockBasic *)block1->getOut(1);
if (exita == exitb) return false;
if (block2->getOut(0) == exita) {
if (block2->getOut(1) != exitb) return false;
a_in2 = block2->getOutRevIndex(0);
b_in2 = block2->getOutRevIndex(1);
}
else if (block2->getOut(0) == exitb) {
if (block2->getOut(1) != exita) return false;
a_in2 = block2->getOutRevIndex(1);
b_in2 = block2->getOutRevIndex(0);
}
else
return false;
a_in1 = block1->getOutRevIndex(0);
b_in1 = block1->getOutRevIndex(1);
if (!findDups()) {
clear();
return false;
}
checkExitBlock(exita,a_in1,a_in2);
checkExitBlock(exitb,b_in1,b_in2);
return true;
}
void ConditionalJoin::execute(void)
{
joinblock = data.nodeJoinCreateBlock(block1,block2,exita,exitb,(a_in1 > a_in2),(b_in1 > b_in2),cbranch1->getAddr());
setupMultiequals();
moveCbranch();
cutDownMultiequals(exita,a_in1,a_in2);
cutDownMultiequals(exitb,b_in1,b_in2);
}
void ConditionalJoin::clear(void)
{ mergeneed.clear();
}
int4 ActionStructureTransform::apply(Funcdata &data)
{
data.getStructure().finalTransform(data);
return 0;
}
int4 ActionNormalizeBranches::apply(Funcdata &data)
{
const BlockGraph &graph(data.getBasicBlocks());
vector<PcodeOp *> fliplist;
for(int4 i=0;i<graph.getSize();++i) {
BlockBasic *bb = (BlockBasic *)graph.getBlock(i);
if (bb->sizeOut() != 2) continue;
PcodeOp *cbranch = bb->lastOp();
if (cbranch == (PcodeOp *)0) continue;
if (cbranch->code() != CPUI_CBRANCH) continue;
fliplist.clear();
if (opFlipInPlaceTest(cbranch,fliplist) != 0)
continue;
opFlipInPlaceExecute(data,fliplist);
bb->flipInPlaceExecute();
count += 1; }
data.clearDeadOps(); return 0;
}
int4 ActionPreferComplement::apply(Funcdata &data)
{
BlockGraph &graph(data.getStructure());
if (graph.getSize() == 0) return 0;
vector<BlockGraph *> vec;
vec.push_back(&graph);
int4 pos = 0;
while(pos < vec.size()) {
BlockGraph *curbl = vec[pos];
FlowBlock::block_type bt;
pos += 1;
int4 sz = curbl->getSize();
for(int4 i=0;i<sz;++i) {
FlowBlock *childbl = curbl->getBlock(i);
bt = childbl->getType();
if ((bt == FlowBlock::t_copy)||(bt == FlowBlock::t_basic))
continue;
vec.push_back((BlockGraph *)childbl);
}
if (curbl->preferComplement(data))
count += 1;
}
data.clearDeadOps(); return 0;
}
int4 ActionBlockStructure::apply(Funcdata &data)
{
BlockGraph &graph(data.getStructure());
if (graph.getSize() != 0) return 0;
data.installSwitchDefaults();
graph.buildCopy(data.getBasicBlocks());
CollapseStructure collapse(graph);
collapse.collapseAll();
count += collapse.getChangeCount();
return 0;
}
int4 ActionFinalStructure::apply(Funcdata &data)
{
BlockGraph &graph(data.getStructure());
graph.orderBlocks();
graph.finalizePrinting(data);
graph.scopeBreak(-1,-1); graph.markUnstructured(); graph.markLabelBumpUp(false); return 0;
}
void ActionReturnSplit::gatherReturnGotos(FlowBlock *parent,vector<FlowBlock *> &vec)
{
FlowBlock *bl,*ret;
for(int4 i=0;i<parent->sizeIn();++i) {
bl = parent->getIn(i)->getCopyMap();
while(bl != (FlowBlock *)0) {
if (!bl->isMark()) {
ret = (FlowBlock *)0;
if (bl->getType() == FlowBlock::t_goto) {
if (((BlockGoto *)bl)->gotoPrints())
ret = ((BlockGoto *)bl)->getGotoTarget();
}
else if (bl->getType() == FlowBlock::t_if)
ret = ((BlockIf *)bl)->getGotoTarget();
if (ret != (FlowBlock *)0) {
while(ret->getType() != FlowBlock::t_basic)
ret = ret->subBlock(0);
if (ret == parent) {
bl->setMark();
vec.push_back(bl);
}
}
}
bl = bl->getParent();
}
}
}
bool ActionReturnSplit::isSplittable(BlockBasic *b)
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *op;
for(iter=b->beginOp();iter!=b->endOp();++iter) {
op = *iter;
OpCode opc = op->code();
if (opc == CPUI_MULTIEQUAL) continue;
if ((opc == CPUI_COPY)||(opc == CPUI_RETURN)) {
for(int4 i=0;i<op->numInput();++i) {
if (op->getIn(i)->isConstant()) continue;
if (op->getIn(i)->isAnnotation()) continue;
if (op->getIn(i)->isFree()) return false;
}
continue;
}
return false;
}
return true;
}
int4 ActionReturnSplit::apply(Funcdata &data)
{
PcodeOp *op;
BlockBasic *parent;
FlowBlock *bl;
list<PcodeOp *>::const_iterator iter,iterend;
vector<int4> splitedge;
vector<BlockBasic *> retnode;
if (data.getStructure().getSize() == 0)
return 0; iterend = data.endOp(CPUI_RETURN);
for(iter=data.beginOp(CPUI_RETURN);iter!=iterend;++iter) {
op = *iter;
if (op->isDead()) continue;
parent = op->getParent();
if (parent->sizeIn() <= 1) continue;
if (!isSplittable(parent)) continue;
vector<FlowBlock *> gotoblocks;
gatherReturnGotos(parent,gotoblocks);
if (gotoblocks.empty()) continue;
int4 splitcount = 0;
for(int4 i=parent->sizeIn()-1;i>=0;--i) {
bl = parent->getIn(i)->getCopyMap();
while(bl != (FlowBlock *)0) {
if (bl->isMark()) {
splitedge.push_back(i);
retnode.push_back(parent);
bl = (FlowBlock *)0;
splitcount += 1;
}
else
bl = bl->getParent();
}
}
for(int4 i=0;i<gotoblocks.size();++i) gotoblocks[i]->clearMark();
if (parent->sizeIn() == splitcount) {
splitedge.pop_back();
retnode.pop_back();
}
}
for(int4 i=0;i<splitedge.size();++i) {
data.nodeSplit(retnode[i],splitedge[i]);
count += 1;
#ifdef BLOCKCONSISTENT_DEBUG
if (!data.getBasicBlocks().isConsistent())
data.getArch()->printMessage("Block structure is not consistent");
#endif
}
return 0;
}
int4 ActionNodeJoin::apply(Funcdata &data)
{
const BlockGraph &graph(data.getBasicBlocks());
if (graph.getSize()==0) return 0;
ConditionalJoin condjoin(data);
for(int4 i=0;i<graph.getSize();++i) {
BlockBasic *bb = (BlockBasic *) graph.getBlock(i);
if (bb->sizeOut() != 2) continue;
BlockBasic *out1 = (BlockBasic *) bb->getOut(0);
BlockBasic *out2 = (BlockBasic *) bb->getOut(1);
int4 inslot;
BlockBasic *leastout;
if (out1->sizeIn() < out2->sizeIn()) {
leastout = out1;
inslot = bb->getOutRevIndex(0);
}
else {
leastout = out2;
inslot = bb->getOutRevIndex(1);
}
if (leastout->sizeIn()==1) continue;
for(int4 j=0;j<leastout->sizeIn();++j) {
if (j == inslot) continue;
BlockBasic *bb2 = (BlockBasic *)leastout->getIn(j);
if (condjoin.match(bb,bb2)) {
count += 1; condjoin.execute();
condjoin.clear();
break;
}
}
}
return 0;
}