#include "block.hh"
#include "funcdata.hh"
void BlockEdge::saveXml(ostream &s) const
{
s << "<edge";
a_v_i(s,"end",point->getIndex()); a_v_i(s,"rev",reverse_index); s << "/>\n";
}
void BlockEdge::restoreXml(const Element *el,BlockMap &resolver)
{
label = 0; int4 endIndex;
istringstream s(el->getAttributeValue("end"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> endIndex;
point = resolver.findLevelBlock(endIndex);
if (point == (FlowBlock *)0)
throw LowlevelError("Bad serialized edge in block graph");
istringstream s2(el->getAttributeValue("rev"));
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> reverse_index;
}
FlowBlock::FlowBlock(void)
{
flags = 0;
index = 0;
visitcount = 0;
parent = (FlowBlock *)0;
immed_dom = (FlowBlock *)0;
}
void FlowBlock::addInEdge(FlowBlock *b,uint4 lab)
{
int4 ourrev = b->outofthis.size();
int4 brev = intothis.size();
intothis.push_back(BlockEdge(b,lab,ourrev));
b->outofthis.push_back(BlockEdge(this,lab,brev));
}
void FlowBlock::restoreNextInEdge(const Element *el,BlockMap &resolver)
{
intothis.emplace_back();
BlockEdge &inedge(intothis.back());
inedge.restoreXml(el,resolver);
while(inedge.point->outofthis.size() <= inedge.reverse_index)
inedge.point->outofthis.emplace_back();
BlockEdge &outedge(inedge.point->outofthis[inedge.reverse_index]);
outedge.label = 0;
outedge.point = this;
outedge.reverse_index = intothis.size()-1;
}
void FlowBlock::halfDeleteInEdge(int4 slot)
{
while(slot < intothis.size()-1) {
BlockEdge &edge( intothis[slot] );
edge = intothis[slot+1]; BlockEdge &edger( edge.point->outofthis[edge.reverse_index] );
edger.reverse_index -= 1;
slot += 1;
}
intothis.pop_back();
}
void FlowBlock::halfDeleteOutEdge(int4 slot)
{
while(slot < outofthis.size()-1) {
BlockEdge &edge( outofthis[slot] );
edge = outofthis[slot+1]; BlockEdge &edger( edge.point->intothis[edge.reverse_index] );
edger.reverse_index -= 1;
slot += 1;
}
outofthis.pop_back();
}
void FlowBlock::removeInEdge(int4 slot)
{
FlowBlock *b = intothis[slot].point;
int4 rev = intothis[slot].reverse_index;
halfDeleteInEdge(slot);
b->halfDeleteOutEdge(rev);
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
b->checkEdges();
#endif
}
void FlowBlock::removeOutEdge(int4 slot)
{
FlowBlock *b = outofthis[slot].point;
int4 rev = outofthis[slot].reverse_index;
halfDeleteOutEdge(slot);
b->halfDeleteInEdge(rev);
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
b->checkEdges();
#endif
}
void FlowBlock::replaceInEdge(int4 num,FlowBlock *b)
{
FlowBlock *oldb = intothis[num].point;
oldb->halfDeleteOutEdge(intothis[num].reverse_index);
intothis[num].point = b;
intothis[num].reverse_index = b->outofthis.size();
b->outofthis.push_back(BlockEdge(this,intothis[num].label,num));
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
b->checkEdges();
oldb->checkEdges();
#endif
}
void FlowBlock::replaceOutEdge(int4 num,FlowBlock *b)
{
FlowBlock *oldb = outofthis[num].point;
oldb->halfDeleteInEdge(outofthis[num].reverse_index);
outofthis[num].point = b;
outofthis[num].reverse_index = b->intothis.size();
b->intothis.push_back(BlockEdge(this,outofthis[num].label,num));
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
b->checkEdges();
oldb->checkEdges();
#endif
}
void FlowBlock::replaceEdgesThru(int4 in,int4 out)
{
FlowBlock *inb = intothis[in].point;
int4 inblock_outslot = intothis[in].reverse_index;
FlowBlock *outb = outofthis[out].point;
int4 outblock_inslot = outofthis[out].reverse_index;
inb->outofthis[inblock_outslot].point = outb;
inb->outofthis[inblock_outslot].reverse_index = outblock_inslot;
outb->intothis[outblock_inslot].point = inb;
outb->intothis[outblock_inslot].reverse_index = inblock_outslot;
halfDeleteInEdge(in);
halfDeleteOutEdge(out);
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
inb->checkEdges();
outb->checkEdges();
#endif
}
void FlowBlock::swapEdges(void)
{
#ifdef BLOCKCONSISTENT_DEBUG
if (outofthis.size() != 2)
throw LowlevelError("Swapping edges for block that doesn't have two edges");
#endif
BlockEdge tmp = outofthis[0];
outofthis[0] = outofthis[1];
outofthis[1] = tmp;
FlowBlock *bl = outofthis[0].point;
bl->intothis[ outofthis[0].reverse_index ].reverse_index = 0;
bl = outofthis[1].point;
bl->intothis[ outofthis[1].reverse_index ].reverse_index = 1;
flags ^= f_flip_path;
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
#endif
}
void FlowBlock::setOutEdgeFlag(int4 i,uint4 lab)
{
FlowBlock *bbout = outofthis[i].point;
outofthis[i].label |= lab;
bbout->intothis[ outofthis[i].reverse_index ].label |= lab;
}
void FlowBlock::clearOutEdgeFlag(int4 i,uint4 lab)
{
FlowBlock *bbout = outofthis[i].point;
outofthis[i].label &= ~lab;
bbout->intothis[ outofthis[i].reverse_index ].label &= ~lab;
}
void FlowBlock::markLabelBumpUp(bool bump)
{
if (bump)
flags |= f_label_bumpup;
}
void FlowBlock::replaceEdgeMap(vector<BlockEdge> &vec)
{
vector<BlockEdge>::iterator iter;
for(iter=vec.begin();iter!=vec.end();++iter)
(*iter).point = (*iter).point->getCopyMap();
}
void FlowBlock::replaceUsingMap(void)
{
replaceEdgeMap(intothis);
replaceEdgeMap(outofthis);
if (immed_dom != (FlowBlock *)0)
immed_dom = immed_dom->getCopyMap();
}
bool FlowBlock::negateCondition(bool toporbottom)
{
if (!toporbottom) return false; swapEdges();
return false;
}
void FlowBlock::setGotoBranch(int4 i)
{ if ((i>=0)&&(i < outofthis.size()))
setOutEdgeFlag(i,f_goto_edge);
else
throw LowlevelError("Could not find block edge to mark unstructured");
flags |= f_interior_gotoout;
outofthis[i].point->flags |= f_interior_gotoin;
}
bool FlowBlock::isJumpTarget(void) const
{
for(int4 i=0;i<intothis.size();++i)
if (intothis[i].point->index != index-1) return true;
return false;
}
const FlowBlock *FlowBlock::getFrontLeaf(void) const
{
const FlowBlock *bl = this;
while(bl->getType() != t_copy) {
bl = bl->subBlock(0);
if (bl == (const FlowBlock *)0) return bl;
}
return bl;
}
FlowBlock *FlowBlock::getFrontLeaf(void)
{
FlowBlock *bl = this;
while(bl->getType() != t_copy) {
bl = bl->subBlock(0);
if (bl == (FlowBlock *)0) return bl;
}
return bl;
}
int4 FlowBlock::calcDepth(const FlowBlock *leaf) const
{
int4 depth = 0;
while(leaf != this) {
if (leaf == (const FlowBlock *)0)
return -1;
leaf = leaf->getParent();
depth += 1;
}
return depth;
}
bool FlowBlock::dominates(const FlowBlock *subBlock) const
{
while(subBlock != (const FlowBlock *)0 && index <= subBlock->index) {
if (subBlock == this) return true;
subBlock = subBlock->getImmedDom();
}
return false;
}
bool FlowBlock::restrictedByConditional(const FlowBlock *cond) const
{
if (sizeIn() == 1) return true; if (getImmedDom() != cond) return false; for(int4 i=0;i<sizeIn();++i) {
const FlowBlock *inBlock = getIn(i);
if (inBlock == cond) continue; while(inBlock != this) {
if (inBlock == cond) return false; inBlock = inBlock->getImmedDom();
}
}
return true;
}
bool FlowBlock::hasLoopIn(void) const
{
for(int4 i=0;i<intothis.size();++i)
if ((intothis[i].label & f_loop_edge)!=0) return true;
return false;
}
bool FlowBlock::hasLoopOut(void) const
{
for(int4 i=0;i<outofthis.size();++i)
if ((outofthis[i].label & f_loop_edge)!=0) return true;
return false;
}
void FlowBlock::eliminateInDups(FlowBlock *bl)
{
int4 indval = -1;
int4 i=0;
while(i < intothis.size()) {
if (intothis[i].point == bl) {
if (indval == -1) { indval = i; i += 1;
}
else {
intothis[indval].label |= intothis[i].label;
int4 rev = intothis[i].reverse_index;
halfDeleteInEdge(i);
bl->halfDeleteOutEdge(rev);
}
}
else
i += 1;
}
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
bl->checkEdges();
#endif
}
void FlowBlock::eliminateOutDups(FlowBlock *bl)
{
int4 indval = -1;
int4 i=0;
while(i < outofthis.size()) {
if (outofthis[i].point == bl) {
if (indval == -1) { indval = i; i += 1;
}
else {
outofthis[indval].label |= outofthis[i].label;
int4 rev = outofthis[i].reverse_index;
halfDeleteOutEdge(i);
bl->halfDeleteInEdge(rev);
}
}
else
i += 1;
}
#ifdef BLOCKCONSISTENT_DEBUG
checkEdges();
bl->checkEdges();
#endif
}
void FlowBlock::findDups(const vector<BlockEdge> &ref,vector<FlowBlock *> &duplist)
{
vector<BlockEdge>::const_iterator iter;
for(iter=ref.begin();iter!=ref.end();++iter) {
if (((*iter).point->flags&f_mark2)!=0) continue; if (((*iter).point->flags&f_mark)!=0) { duplist.push_back((*iter).point);
(*iter).point->flags |= f_mark2;
}
else
(*iter).point->flags |= f_mark;
}
for(iter=ref.begin();iter!=ref.end();++iter) (*iter).point->flags &= ~(f_mark | f_mark2);
}
void FlowBlock::dedup(void)
{
vector<FlowBlock *> duplist;
vector<FlowBlock *>::iterator iter;
findDups(intothis,duplist);
for(iter=duplist.begin();iter!=duplist.end();++iter)
eliminateInDups(*iter);
duplist.clear();
findDups(outofthis,duplist);
for(iter=duplist.begin();iter!=duplist.end();++iter)
eliminateOutDups(*iter);
}
#ifdef BLOCKCONSISTENT_DEBUG
void FlowBlock::checkEdges(void)
{
for(int4 i=0;i<intothis.size();++i) {
BlockEdge &edge( intothis[i] );
int4 rev = edge.reverse_index;
FlowBlock *bl = edge.point;
if (bl->outofthis.size() <= rev)
throw LowlevelError("Not enough outofthis blocks");
BlockEdge &edger( bl->outofthis[rev] );
if (edger.point != this)
throw LowlevelError("Intothis edge mismatch");
if (edger.reverse_index != i)
throw LowlevelError("Intothis index mismatch");
}
for(int4 i=0;i<outofthis.size();++i) {
BlockEdge &edge( outofthis[i] );
int4 rev = edge.reverse_index;
FlowBlock *bl = edge.point;
if (bl->intothis.size() <= rev)
throw LowlevelError("Not enough intothis blocks");
BlockEdge &edger( bl->intothis[rev] );
if (edger.point != this)
throw LowlevelError("Outofthis edge mismatch");
if (edger.reverse_index != i)
throw LowlevelError("Outofthis index mismatch");
}
}
#endif
int4 FlowBlock::getInIndex(const FlowBlock *bl) const
{
int4 blocknum;
for(blocknum=0;blocknum<intothis.size();++blocknum)
if (intothis[blocknum].point==bl) return blocknum;
return -1; }
int4 FlowBlock::getOutIndex(const FlowBlock *bl) const
{
int4 blocknum;
for(blocknum=0;blocknum<outofthis.size();++blocknum)
if (outofthis[blocknum].point==bl) return blocknum;
return -1;
}
void FlowBlock::printHeader(ostream &s) const
{
s << dec << index;
if (!getStart().isInvalid() && !getStop().isInvalid()) {
s << ' ' << getStart() << '-' << getStop();
}
}
void FlowBlock::printTree(ostream &s,int4 level) const
{
int4 i;
for(i=0;i<level;++i)
s << " ";
printHeader(s);
s << endl;
}
JumpTable *FlowBlock::getJumptable(void) const
{
JumpTable *jt = (JumpTable *)0;
if (!isSwitchOut()) return jt;
PcodeOp *indop = lastOp();
if (indop != (PcodeOp *)0)
jt = indop->getParent()->getFuncdata()->findJumpTable(indop);
return jt;
}
FlowBlock::block_type FlowBlock::nameToType(const string &nm)
{
FlowBlock::block_type bt = FlowBlock::t_plain;
if (nm == "graph")
bt = FlowBlock::t_graph;
else if (nm == "copy")
bt = FlowBlock::t_copy;
return bt;
}
string FlowBlock::typeToName(FlowBlock::block_type bt)
{
switch(bt) {
case t_plain:
return "plain";
case t_basic:
return "basic";
case t_graph:
return "graph";
case t_copy:
return "copy";
case t_goto:
return "goto";
case t_multigoto:
return "multigoto";
case t_ls:
return "list";
case t_condition:
return "condition";
case t_if:
return "properif";
case t_whiledo:
return "whiledo";
case t_dowhile:
return "dowhile";
case t_switch:
return "switch";
case t_infloop:
return "infloop";
}
return "";
}
bool FlowBlock::compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2)
{
if (bl1->getIndex() == 0) return true; if (bl2->getIndex() == 0) return false;
PcodeOp *op1 = bl1->lastOp();
PcodeOp *op2 = bl2->lastOp();
if (op1 != (PcodeOp *)0) { if (op2 != (PcodeOp *)0) {
if ((op1->code() == CPUI_RETURN)&&(op2->code() != CPUI_RETURN))
return false;
else if ((op1->code() != CPUI_RETURN)&&(op2->code() == CPUI_RETURN))
return true;
}
if (op1->code() == CPUI_RETURN) return false;
}
else if (op2 != (PcodeOp *)0) {
if (op2->code() == CPUI_RETURN) return true;
}
return (bl1->getIndex() < bl2->getIndex()); }
FlowBlock *FlowBlock::findCommonBlock(FlowBlock *bl1,FlowBlock *bl2)
{
FlowBlock *b1,*b2,*common;
common = (FlowBlock *)0;
b1 = bl1;
b2 = bl2;
for(;;) {
if (b2 == (FlowBlock *)0) {
while(b1 != (FlowBlock *)0) {
if (b1->isMark()) {
common = b1;
break;
}
b1 = b1->getImmedDom();
}
break;
}
if (b1 == (FlowBlock *)0) {
while(b2 != (FlowBlock *)0) {
if (b2->isMark()) {
common = b2;
break;
}
b2 = b2->getImmedDom();
}
break;
}
if (b1->isMark()) {
common = b1;
break;
}
b1->setMark();
if (b2->isMark()) {
common = b2;
break;
}
b2->setMark();
b1 = b1->getImmedDom();
b2 = b2->getImmedDom();
}
while(bl1!=(FlowBlock *)0) {
if (!bl1->isMark()) break;
bl1->clearMark();
bl1 = bl1->getImmedDom();
}
while(bl2!=(FlowBlock *)0) {
if (!bl2->isMark()) break;
bl2->clearMark();
bl2 = bl2->getImmedDom();
}
return common;
}
FlowBlock *FlowBlock::findCommonBlock(const vector<FlowBlock *> &blockSet)
{
vector<FlowBlock *> markedSet;
FlowBlock *bl;
FlowBlock *res = blockSet[0];
int4 bestIndex = res->getIndex();
bl = res;
do {
bl->setMark();
markedSet.push_back(bl);
bl = bl->getImmedDom();
} while (bl != (FlowBlock *)0);
for(int4 i=1;i<blockSet.size();++i) {
if (bestIndex == 0)
break;
bl = blockSet[i];
while(!bl->isMark()) {
bl->setMark();
markedSet.push_back(bl);
bl = bl->getImmedDom();
}
if (bl->getIndex() < bestIndex) { res = bl; bestIndex = res->getIndex();
}
}
for(int4 i=0;i<markedSet.size();++i)
markedSet[i]->clearMark();
return res;
}
void BlockGraph::addBlock(FlowBlock *bl)
{
int4 min = bl->index;
if (list.empty()) {
index = min;
}
else {
if (min < index) index = min;
}
bl->parent = this;
list.push_back(bl);
}
void BlockGraph::forceOutputNum(int4 i)
{
#ifdef BLOCKCONSISTENT_DEBUG
if (sizeOut() > i)
throw LowlevelError("Bad block output force");
#endif
while(sizeOut() < i)
addInEdge(this,f_loop_edge|f_back_edge);
}
void BlockGraph::selfIdentify(void)
{
vector<FlowBlock *>::iterator iter;
FlowBlock *mybl,*otherbl;
if (list.empty()) return;
for(iter=list.begin();iter!=list.end();++iter) {
mybl = *iter;
int4 i = 0;
while(i<mybl->intothis.size()) {
otherbl = mybl->intothis[i].point;
if (otherbl->parent == this)
i += 1;
else {
for(int4 j=0;j<otherbl->outofthis.size();++j)
if (otherbl->outofthis[j].point == mybl)
otherbl->replaceOutEdge(j,this);
}
}
i = 0;
while(i<mybl->outofthis.size()) {
otherbl = mybl->outofthis[i].point;
if (otherbl->parent == this)
i += 1;
else {
for(int4 j=0;j<otherbl->intothis.size();++j)
if (otherbl->intothis[j].point == mybl)
otherbl->replaceInEdge(j,this);
if (mybl->isSwitchOut()) setFlag(f_switch_out);
}
}
}
dedup();
}
void BlockGraph::identifyInternal(BlockGraph *ident,const vector<FlowBlock *> &nodes)
{
vector<FlowBlock *>::const_iterator iter;
for(iter=nodes.begin();iter!=nodes.end();++iter) {
#ifdef BLOCKCONSISTENT_DEBUG
if ((*iter)->parent != this)
throw LowlevelError("Bad block identify");
#endif
(*iter)->setMark();
ident->addBlock(*iter); ident->flags |= ((*iter)->flags & (f_interior_gotoout | f_interior_gotoin));
}
vector<FlowBlock *> newlist;
for(iter=list.begin();iter!=list.end();++iter) { if (!(*iter)->isMark())
newlist.push_back(*iter);
else
(*iter)->clearMark();
}
list = newlist;
ident->selfIdentify();
}
void BlockGraph::clearEdgeFlags(uint4 fl)
{
fl = ~fl;
int4 size = list.size();
for(int4 j=0;j<size;++j) {
FlowBlock *bl = list[j];
for(int4 i=0;i<bl->intothis.size();++i)
bl->intothis[i].label &= fl;
for(int4 i=0;i<bl->outofthis.size();++i)
bl->outofthis[i].label &= fl;
}
}
FlowBlock *BlockGraph::createVirtualRoot(const vector<FlowBlock *> &rootlist)
{
FlowBlock *newroot = new FlowBlock();
for(int4 i=0;i<rootlist.size();++i)
rootlist[i]->addInEdge(newroot,0);
return newroot;
}
void BlockGraph::findSpanningTree(vector<FlowBlock *> &preorder,vector<FlowBlock *> &rootlist)
{
if (list.size()==0) return;
vector<FlowBlock *> rpostorder;
vector<FlowBlock *> state;
vector<int4> istate;
FlowBlock *tmpbl;
int4 origrootpos;
preorder.reserve(list.size());
rpostorder.resize(list.size());
state.reserve(list.size());
istate.reserve(list.size());
for(int4 i=0;i<list.size();++i) {
tmpbl = list[i];
tmpbl->index = -1; tmpbl->visitcount = -1;
tmpbl->copymap = tmpbl;
if (tmpbl->sizeIn()==0) rootlist.push_back(tmpbl);
}
if (rootlist.size() > 1) { tmpbl = rootlist[rootlist.size()-1];
rootlist[rootlist.size()-1] = rootlist[0];
rootlist[0] = tmpbl;
}
else if (rootlist.size() == 0) { rootlist.push_back(list[0]); }
origrootpos = rootlist.size()-1;
for(int4 repeat=0;repeat<2;++repeat) {
bool extraroots = false;
int4 rpostcount = list.size();
int4 rootindex = 0;
clearEdgeFlags(~((uint4)0)); while(preorder.size() < list.size()) {
FlowBlock *startbl = (FlowBlock *)0;
while(rootindex<rootlist.size()) { startbl = rootlist[rootindex];
rootindex += 1;
if (startbl->visitcount == -1) break;
for(int4 i=rootindex;i<rootlist.size();++i)
rootlist[i-1] = rootlist[i];
rootlist.pop_back(); rootindex -= 1;
startbl = (FlowBlock *)0;
}
if (startbl == (FlowBlock *)0) { extraroots = true;
for(int4 i=0;i<list.size();++i) {
startbl = list[i];
if (startbl->visitcount == -1) break;
}
rootlist.push_back(startbl); rootindex += 1; }
state.push_back(startbl);
istate.push_back(0);
startbl->visitcount = preorder.size();
preorder.push_back(startbl);
startbl->numdesc = 1;
while(!state.empty()) {
FlowBlock *curbl = state.back();
if (curbl->sizeOut() <= istate.back()) { state.pop_back();
istate.pop_back();
rpostcount -= 1;
curbl->index = rpostcount;
rpostorder[rpostcount] = curbl;
if (!state.empty())
state.back()->numdesc += curbl->numdesc;
}
else {
int4 edgenum = istate.back();
istate.back() += 1; if (curbl->isIrreducibleOut(edgenum)) continue; FlowBlock *childbl = curbl->getOut(edgenum);
if (childbl->visitcount == -1) { curbl->setOutEdgeFlag(edgenum,f_tree_edge);
state.push_back(childbl);
istate.push_back(0);
childbl->visitcount = preorder.size();
preorder.push_back(childbl);
childbl->numdesc = 1;
}
else if (childbl->index == -1) curbl->setOutEdgeFlag(edgenum,f_back_edge|f_loop_edge);
else if (curbl->visitcount < childbl->visitcount) curbl->setOutEdgeFlag(edgenum,f_forward_edge);
else
curbl->setOutEdgeFlag(edgenum,f_cross_edge);
}
}
}
if (!extraroots) break;
if (repeat==1)
throw LowlevelError("Could not generate spanning tree");
tmpbl = rootlist[rootlist.size()-1];
rootlist[rootlist.size()-1] = rootlist[origrootpos]; rootlist[origrootpos] = tmpbl;
for(int4 i=0;i<list.size();++i) {
tmpbl = list[i];
tmpbl->index = -1; tmpbl->visitcount = -1;
tmpbl->copymap = tmpbl;
}
preorder.clear();
state.clear();
istate.clear();
}
if (rootlist.size() > 1) { tmpbl = rootlist[rootlist.size()-1];
rootlist[rootlist.size()-1] = rootlist[0];
rootlist[0] = tmpbl;
}
list = rpostorder;
}
bool BlockGraph::findIrreducible(const vector<FlowBlock *> &preorder,int4 &irreduciblecount)
{
vector<FlowBlock *> reachunder; bool needrebuild = false;
int4 xi = preorder.size()-1;
while(xi >= 0) { FlowBlock *x = preorder[xi];
xi -= 1;
int4 sizein = x->sizeIn();
for(int4 i=0;i<sizein;++i) {
if (!x->isBackEdgeIn(i)) continue; FlowBlock *y = x->getIn(i);
if (y==x) continue; reachunder.push_back(y->copymap); y->copymap->setMark();
}
int4 q = 0;
while(q < reachunder.size()) {
FlowBlock *t = reachunder[q];
q += 1;
int4 sizein_t = t->sizeIn();
for(int4 i=0;i<sizein_t;++i) {
if (t->isIrreducibleIn(i)) continue; FlowBlock *y = t->getIn(i); FlowBlock *yprime = y->copymap; if ((x->visitcount > yprime->visitcount)||( x->visitcount + x->numdesc <= yprime->visitcount)) {
irreduciblecount += 1;
int4 edgeout = t->getInRevIndex(i);
y->setOutEdgeFlag(edgeout,f_irreducible);
if (t->isTreeEdgeIn(i))
needrebuild = true; else y->clearOutEdgeFlag(edgeout,f_cross_edge|f_forward_edge);
}
else if ((!yprime->isMark())&&(yprime != x)) { reachunder.push_back(yprime);
yprime->setMark();
}
}
}
for(int4 i=0;i<reachunder.size();++i) {
FlowBlock *s = reachunder[i];
s->clearMark();
s->copymap = x;
}
reachunder.clear();
}
return needrebuild;
}
void BlockGraph::forceFalseEdge(const FlowBlock *out0)
{
if (sizeOut() != 2)
throw LowlevelError("Can only preserve binary condition");
if (out0->getParent() == this) out0 = this;
if (outofthis[0].point != out0)
swapEdges();
if (outofthis[0].point != out0)
throw LowlevelError("Unable to preserve condition");
}
void BlockGraph::swapBlocks(int4 i,int4 j)
{
FlowBlock *bl = list[i];
list[i] = list[j];
list[j] = bl;
}
void BlockGraph::markCopyBlock(FlowBlock *bl,uint4 fl)
{
bl->getFrontLeaf()->flags |= fl;
}
void BlockGraph::clear(void)
{
vector<FlowBlock *>::iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
delete *iter;
list.clear();
}
void BlockGraph::markUnstructured(void)
{
vector<FlowBlock *>::iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->markUnstructured(); }
void BlockGraph::markLabelBumpUp(bool bump)
{
FlowBlock::markLabelBumpUp(bump); if (list.empty()) return;
vector<FlowBlock *>::iterator iter = list.begin();
(*iter)->markLabelBumpUp(bump); ++iter;
for(;iter!=list.end();++iter)
(*iter)->markLabelBumpUp(false);
}
void BlockGraph::scopeBreak(int4 curexit,int4 curloopexit)
{
vector<FlowBlock *>::iterator iter;
FlowBlock *curbl;
int4 ind;
iter = list.begin();
while(iter != list.end()) {
curbl = *iter;
++iter;
if (iter == list.end())
ind = curexit;
else
ind = (*iter)->getIndex();
curbl->scopeBreak(ind,curloopexit);
}
}
void BlockGraph::printTree(ostream &s,int4 level) const
{
vector<FlowBlock *>::const_iterator iter;
FlowBlock::printTree(s,level);
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->printTree(s,level+1);
}
void BlockGraph::printRaw(ostream &s) const
{
vector<FlowBlock *>::const_iterator iter;
printHeader(s);
s << endl;
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->printRaw(s);
}
FlowBlock *BlockGraph::nextFlowAfter(const FlowBlock *bl) const
{
FlowBlock *nextbl;
vector<FlowBlock *>::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
if ((*iter)==bl)
break;
++iter; if (iter == list.end()) {
if (getParent() == (FlowBlock *)0)
return (FlowBlock *)0;
return getParent()->nextFlowAfter(this);
}
nextbl = *iter; if (nextbl != (FlowBlock *)0)
nextbl = nextbl->getFrontLeaf();
return nextbl;
}
void BlockGraph::finalTransform(Funcdata &data)
{
vector<FlowBlock *>::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->finalTransform(data);
}
void BlockGraph::finalizePrinting(Funcdata &data) const
{
vector<FlowBlock *>::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->finalizePrinting(data);
}
void BlockGraph::saveXmlBody(ostream &s) const
{
FlowBlock::saveXmlBody(s);
for(int4 i=0;i<list.size();++i) {
FlowBlock *bl = list[i];
s << "<bhead";
a_v_i(s,"index",bl->getIndex());
FlowBlock::block_type bt = bl->getType();
string nm;
if (bt == FlowBlock::t_if) {
int4 sz = ((BlockGraph *)bl)->getSize();
if (sz == 1)
nm = "ifgoto";
else if (sz == 2)
nm = "properif";
else
nm = "ifelse";
}
else
nm = FlowBlock::typeToName(bt);
a_v(s,"type",nm);
s << "/>\n";
}
for(int4 i=0;i<list.size();++i)
list[i]->saveXml(s);
}
void BlockGraph::restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver)
{
BlockMap newresolver(resolver);
FlowBlock::restoreXmlBody(iter,enditer,newresolver);
vector<FlowBlock *> tmplist;
while(iter != enditer) {
const Element *el = *iter;
if (el->getName() != "bhead") break;
++iter;
int4 newindex;
istringstream s(el->getAttributeValue("index"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> newindex;
const string &nm( el->getAttributeValue("type") );
FlowBlock *bl = newresolver.createBlock(nm);
bl->index = newindex; tmplist.push_back(bl);
}
newresolver.sortList();
for(int4 i=0;i<tmplist.size();++i) {
if (iter == enditer)
throw LowlevelError("Bad BlockGraph xml");
FlowBlock *bl = tmplist[i];
bl->restoreXml(*iter,newresolver);
addBlock(bl);
++iter;
}
}
void BlockGraph::restoreXml(const Element *el,const AddrSpaceManager *m)
{
BlockMap resolver(m);
FlowBlock::restoreXml(el,resolver);
}
void BlockGraph::addEdge(FlowBlock *begin,FlowBlock *end)
{
#ifdef BLOCKCONSISTENT_DEBUG
if ((begin->parent != this)||(end->parent != this))
throw LowlevelError("Bad edge create");
#endif
end->addInEdge(begin,0);
}
void BlockGraph::addLoopEdge(FlowBlock *begin,int4 outindex)
{
#ifdef BLOCKCONSISTENT_DEBUG
if ((begin->parent != this))
throw LowlevelError("Bad loopedge create");
#endif
begin->setOutEdgeFlag(outindex,f_loop_edge);
}
void BlockGraph::removeEdge(FlowBlock *begin,FlowBlock *end)
{
#ifdef BLOCKCONSISTENT_DEBUG
if ((begin->parent != this)||(end->parent != this))
throw LowlevelError("Bad edge remove");
#endif
int4 i;
for(i=0;i<end->intothis.size();++i)
if (end->intothis[i].point == begin)
break;
end->removeInEdge(i);
}
void BlockGraph::switchEdge(FlowBlock *in,FlowBlock *outbefore,FlowBlock *outafter)
{
for(int4 i=0;i<in->outofthis.size();++i)
if (in->outofthis[i].point == outbefore)
in->replaceOutEdge(i,outafter);
}
void BlockGraph::moveOutEdge(FlowBlock *blold,int4 slot,FlowBlock *blnew)
{
#ifdef BLOCKCONSISTENT_DEBUG
if ((blold->parent != this)||(blnew->parent != this))
throw LowlevelError("Bad edge move");
#endif
FlowBlock *outbl = blold->getOut(slot);
int4 i = blold->getOutRevIndex(slot);
outbl->replaceInEdge(i,blnew);
}
void BlockGraph::removeBlock(FlowBlock *bl)
{
#ifdef BLOCKCONSISTENT_DEBUG
if (bl->parent != this)
throw LowlevelError("Bad block remove");
#endif
vector<FlowBlock *>::iterator iter;
while(bl->sizeIn()>0) removeEdge(bl->getIn(0),bl);
while(bl->sizeOut()>0)
removeEdge(bl,bl->getOut(0));
for(iter=list.begin();iter!=list.end();++iter)
if (*iter == bl) {
list.erase(iter);
break;
}
delete bl; }
void BlockGraph::removeFromFlow(FlowBlock *bl)
{
#ifdef BLOCKCONSISTENT_DEBUG
if (bl->parent != this)
throw LowlevelError("Bad remove from flow");
if ((bl->sizeIn()>0)&&(bl->sizeOut()>1))
throw LowlevelError("Illegal remove from flow");
#endif
FlowBlock *bbout,*bbin;
while(bl->sizeOut()>0) {
bbout = bl->getOut(bl->sizeOut()-1);
bl->removeOutEdge(bl->sizeOut()-1);
while(bl->sizeIn()>0) {
bbin = bl->getIn(0);
bbin->replaceOutEdge(bl->intothis[0].reverse_index,bbout);
}
}
}
void BlockGraph::removeFromFlowSplit(FlowBlock *bl,bool flipflow)
{
#ifdef BLOCKCONSISTENT_DEBUG
if (bl->parent != this)
throw LowlevelError("Bad remove from flow split");
if ((bl->sizeIn()!=2)&&(bl->sizeOut()!=2))
throw LowlevelError("Illegal remove from flow split");
#endif
if (flipflow)
bl->replaceEdgesThru(0,1); else
bl->replaceEdgesThru(1,1); bl->replaceEdgesThru(0,0); }
void BlockGraph::spliceBlock(FlowBlock *bl)
{
FlowBlock *outbl = (FlowBlock *)0;
if (bl->sizeOut() == 1) {
outbl = bl->getOut(0);
if (outbl->sizeIn() != 1)
outbl = (FlowBlock *)0;
}
if (outbl == (FlowBlock *)0)
throw LowlevelError("Can only splice a block with 1 output to a block with 1 input");
uint4 fl1 = bl->flags & (f_unstructured_targ|f_entry_point);
uint4 fl2 = outbl->flags & f_switch_out;
bl->removeOutEdge(0);
int4 szout = outbl->sizeOut();
for(int4 i=0;i<szout;++i)
moveOutEdge(outbl,0,bl);
removeBlock(outbl);
bl->flags = fl1 | fl2;
}
void BlockGraph::setStartBlock(FlowBlock *bl)
{
#ifdef BLOCKCONSISTENT_DEBUG
if (bl->parent != this)
throw LowlevelError("Bad set start");
#endif
if ((list[0]->flags&f_entry_point)!=0) {
if (bl == list[0]) return; list[0]->flags &= ~f_entry_point; }
int4 i;
for(i=0;i<list.size();++i)
if (list[i] == bl) break;
for(int4 j=i;j>0;--j) list[j] = list[j-1];
list[0] = bl;
bl->flags |= f_entry_point;
}
FlowBlock *BlockGraph::getStartBlock(void) const
{
if (list.empty() || ((list[0]->flags&f_entry_point)==0))
throw LowlevelError("No start block registered");
return list[0];
}
FlowBlock *BlockGraph::newBlock(void)
{
FlowBlock *ret = new FlowBlock();
addBlock(ret);
return ret;
}
BlockBasic *BlockGraph::newBlockBasic(Funcdata *fd)
{
BlockBasic *ret = new BlockBasic(fd);
addBlock(ret);
return ret;
}
BlockCopy *BlockGraph::newBlockCopy(FlowBlock *bl)
{
BlockCopy *ret = new BlockCopy(bl);
ret->intothis = bl->intothis;
ret->outofthis = bl->outofthis;
ret->immed_dom = bl->immed_dom;
ret->index = bl->index;
ret->numdesc = bl->numdesc;
ret->flags |= bl->flags;
if (ret->outofthis.size() > 2)
ret->flags |= f_switch_out; addBlock(ret);
return ret;
}
BlockGoto *BlockGraph::newBlockGoto(FlowBlock *bl)
{
BlockGoto *ret = new BlockGoto(bl->getOut(0));
vector<FlowBlock *> nodes;
nodes.push_back(bl);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(1);
removeEdge(ret,ret->getOut(0)); return ret;
}
BlockMultiGoto *BlockGraph::newBlockMultiGoto(FlowBlock *bl,int4 outedge)
{
BlockMultiGoto *ret;
FlowBlock *targetbl = bl->getOut(outedge);
bool isdefaultedge = bl->isDefaultBranch(outedge);
if (bl->getType() == t_multigoto) { ret = (BlockMultiGoto *)bl;
ret->addEdge(targetbl);
removeEdge(ret,targetbl);
if (isdefaultedge)
ret->setDefaultGoto();
}
else {
ret = new BlockMultiGoto(bl);
vector<FlowBlock *> nodes;
nodes.push_back(bl);
identifyInternal(ret,nodes);
addBlock(ret);
ret->addEdge(targetbl);
if (targetbl != bl) removeEdge(ret,targetbl);
if (isdefaultedge)
ret->setDefaultGoto();
}
return ret;
}
BlockList *BlockGraph::newBlockList(const vector<FlowBlock *> &nodes)
{
const FlowBlock *out0 = (const FlowBlock *)0;
int4 outforce = nodes.back()->sizeOut();
if (outforce==2)
out0 = nodes.back()->getOut(0);
BlockList *ret = new BlockList();
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(outforce);
if (ret->sizeOut()==2)
ret->forceFalseEdge(out0); return ret;
}
BlockCondition *BlockGraph::newBlockCondition(FlowBlock *b1,FlowBlock *b2)
{
const FlowBlock *out0 = b2->getOut(0);
vector<FlowBlock *> nodes;
OpCode opc = (b1->getFalseOut() == b2) ? CPUI_INT_OR : CPUI_INT_AND;
BlockCondition *ret = new BlockCondition(opc);
nodes.push_back(b1);
nodes.push_back(b2);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(2); ret->forceFalseEdge(out0); return ret;
}
BlockIf *BlockGraph::newBlockIfGoto(FlowBlock *cond)
{
if (!cond->isGotoOut(1)) throw LowlevelError("Building ifgoto where true branch is not the goto");
const FlowBlock *out0 = cond->getOut(0);
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
ret->setGotoTarget(cond->getOut(1)); nodes.push_back(cond);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(2);
ret->forceFalseEdge(out0); removeEdge(ret,ret->getTrueOut()); return ret;
}
BlockIf *BlockGraph::newBlockIf(FlowBlock *cond,FlowBlock *tc)
{
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
nodes.push_back(cond);
nodes.push_back(tc);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(1);
return ret;
}
BlockIf *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
{
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
nodes.push_back(cond);
nodes.push_back(tc);
nodes.push_back(fc);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(1);
return ret;
}
BlockWhileDo *BlockGraph::newBlockWhileDo(FlowBlock *cond,FlowBlock *cl)
{
vector<FlowBlock *> nodes;
BlockWhileDo *ret = new BlockWhileDo();
nodes.push_back(cond);
nodes.push_back(cl);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(1);
return ret;
}
BlockDoWhile *BlockGraph::newBlockDoWhile(FlowBlock *condcl)
{
vector<FlowBlock *> nodes;
BlockDoWhile *ret = new BlockDoWhile();
nodes.push_back(condcl);
identifyInternal(ret,nodes);
addBlock(ret);
ret->forceOutputNum(1);
return ret;
}
BlockInfLoop *BlockGraph::newBlockInfLoop(FlowBlock *body)
{
vector<FlowBlock *> nodes;
BlockInfLoop *ret = new BlockInfLoop();
nodes.push_back(body);
identifyInternal(ret,nodes);
addBlock(ret);
return ret;
}
BlockSwitch *BlockGraph::newBlockSwitch(const vector<FlowBlock *> &cs,bool hasExit)
{
FlowBlock *rootbl = cs[0];
BlockSwitch *ret = new BlockSwitch(rootbl);
const FlowBlock *leafbl = rootbl->getExitLeaf();
if ((leafbl == (const FlowBlock *)0)||(leafbl->getType() != FlowBlock::t_copy))
throw LowlevelError("Could not get switch leaf");
ret->grabCaseBasic(leafbl->subBlock(0),cs); identifyInternal(ret,cs);
addBlock(ret);
if (hasExit)
ret->forceOutputNum(1); ret->clearFlag(f_switch_out); return ret;
}
void BlockGraph::buildCopy(const BlockGraph &graph)
{
BlockCopy *copyblock;
int4 startsize = list.size();
vector<FlowBlock *>::const_iterator iter;
for(iter=graph.list.begin();iter!=graph.list.end();++iter) {
copyblock = newBlockCopy(*iter);
(*iter)->copymap = copyblock; }
for(iter=list.begin()+startsize;iter!=list.end();++iter)
(*iter)->replaceUsingMap();
}
void BlockGraph::clearVisitCount(void)
{
for(int4 i=0;i<list.size();++i)
list[i]->visitcount = 0;
}
void BlockGraph::calcForwardDominator(const vector<FlowBlock *> &rootlist)
{
vector<FlowBlock *> postorder;
FlowBlock *virtualroot;
FlowBlock *b,*new_idom,*rho;
bool changed;
int4 i,j,finger1,finger2;
if (list.empty()) return;
int4 numnodes = list.size()-1;
postorder.resize(list.size());
for(i=0;i<list.size();++i) {
list[i]->immed_dom = (FlowBlock *)0; postorder[ numnodes-i ] = list[i]; }
if (rootlist.size() > 1) {
virtualroot = createVirtualRoot(rootlist);
postorder.push_back(virtualroot);
}
else
virtualroot = (FlowBlock *)0;
b = postorder.back(); if (b->sizeIn() != 0) { if ((rootlist.size() != 1)||(rootlist[0] != b))
throw LowlevelError("Problems finding root node of graph");
virtualroot = createVirtualRoot(rootlist); postorder.push_back(virtualroot);
b = virtualroot;
}
b->immed_dom = b;
for(i=0;i<b->sizeOut();++i) b->getOut(i)->immed_dom = b; changed = true;
new_idom = (FlowBlock *)0;
while(changed) {
changed = false;
for(i=postorder.size()-2;i>=0;--i) { b = postorder[i];
if (b->immed_dom != postorder.back()) {
for(j=0;j<b->sizeIn();++j) { new_idom = b->getIn(j);
if (new_idom->immed_dom != (FlowBlock *)0)
break;
}
j += 1;
for(;j<b->sizeIn();++j) {
rho = b->getIn(j);
if (rho->immed_dom != (FlowBlock *)0) { finger1 = numnodes - rho->index;
finger2 = numnodes - new_idom->index;
while(finger1 != finger2) {
while(finger1 < finger2)
finger1 = numnodes - postorder[finger1]->immed_dom->index;
while(finger2 < finger1)
finger2 = numnodes - postorder[finger2]->immed_dom->index;
}
new_idom = postorder[finger1];
}
}
if (b->immed_dom != new_idom) {
b->immed_dom = new_idom;
changed = true;
}
}
}
}
if (virtualroot != (FlowBlock *)0) { for(i=0;i<list.size();++i)
if (postorder[i]->immed_dom == virtualroot)
postorder[i]->immed_dom = (FlowBlock *)0; while(virtualroot->sizeOut() > 0)
virtualroot->removeOutEdge(virtualroot->sizeOut()-1); delete virtualroot;
}
else
postorder.back()->immed_dom = (FlowBlock *)0;
}
void BlockGraph::buildDomTree(vector<vector<FlowBlock *> > &child) const
{
FlowBlock *bl;
child.clear();
child.resize(list.size()+1);
for(int4 i=0;i<list.size();++i) {
bl = list[i];
if (bl->immed_dom != (FlowBlock *)0)
child[bl->immed_dom->index].push_back(bl);
else
child[list.size()].push_back(bl);
}
}
int4 BlockGraph::buildDomDepth(vector<int4> &depth) const
{
FlowBlock *bl;
int4 max = 0;
depth.resize(list.size()+1);
for(int4 i=0;i<list.size();++i) {
bl = list[i]->immed_dom;
if (bl != (FlowBlock *)0)
depth[i] = depth[bl->getIndex()] + 1;
else
depth[i] = 1;
if (max<depth[i])
max = depth[i];
}
depth[list.size()] = 0;
return max;
}
void BlockGraph::buildDomSubTree(vector<FlowBlock *> &res,FlowBlock *root) const
{
FlowBlock *bl,*dombl;
int4 rootindex = root->getIndex();
res.push_back(root);
for(int4 i=rootindex+1;i<list.size();++i) {
bl = list[i];
dombl = bl->getImmedDom();
if (dombl == (FlowBlock *)0) break;
if (dombl->getIndex() > rootindex) break;
res.push_back(bl);
}
}
void BlockGraph::calcLoop(void)
{ vector<FlowBlock *>::iterator iter;
FlowBlock *bl,*nextbl;
int4 i;
if (list.empty()) return;
vector<FlowBlock *> path; vector<int4> state;
path.push_back(list.front());
state.push_back(0); list.front()->setFlag(f_mark|f_mark2); while(!path.empty()) {
bl = path.back();
i = state.back();
if (i >= bl->sizeOut()) { bl->clearFlag(f_mark2); path.pop_back();
state.pop_back();
}
else {
state.back() += 1;
if (bl->isLoopOut(i)) continue; nextbl = bl->getOut(i);
if ((nextbl->flags&f_mark2) != 0) { addLoopEdge(bl,i);
}
else if ((nextbl->flags&f_mark)==0) { nextbl->setFlag(f_mark|f_mark2);
path.push_back(nextbl);
state.push_back(0);
}
}
}
for(iter=list.begin();iter!=list.end();++iter)
(*iter)->clearFlag(f_mark|f_mark2); }
void BlockGraph::collectReachable(vector<FlowBlock *> &res,FlowBlock *bl,bool un) const
{
FlowBlock *blk,*blk2;
bl->setMark();
res.push_back(bl);
int4 total = 0;
while(total < res.size()) {
blk = res[total++];
for(int4 j=0;j<blk->sizeOut();++j) {
blk2 = blk->getOut(j);
if (blk2->isMark()) continue;
blk2->setMark();
res.push_back(blk2);
}
}
if (un) {
res.clear(); for(int4 i=0;i<list.size();++i) {
blk = list[i];
if (blk->isMark())
blk->clearMark();
else
res.push_back(blk);
}
}
else {
for(int4 i=0;i<res.size();++i)
res[i]->clearMark();
}
}
void BlockGraph::structureLoops(vector<FlowBlock *> &rootlist)
{
vector<FlowBlock *> preorder;
bool needrebuild;
int4 irreduciblecount = 0;
do {
needrebuild = false;
findSpanningTree(preorder,rootlist);
needrebuild = findIrreducible(preorder,irreduciblecount);
if (needrebuild) {
clearEdgeFlags(f_tree_edge|f_forward_edge|f_cross_edge|f_back_edge|f_loop_edge); preorder.clear();
rootlist.clear();
}
} while(needrebuild);
if (irreduciblecount > 0) {
calcLoop();
}
}
#ifdef BLOCKCONSISTENT_DEBUG
bool BlockGraph::isConsistent(void) const
{
FlowBlock *bl1,*bl2;
int4 i,j,k;
int4 count1,count2;
for(i=0;i<list.size();++i) {
bl1 = list[i];
for(j=0;j<bl1->sizeIn();++j) {
bl2 = bl1->getIn(j); count1 = 0;
for(k=0;k<bl1->sizeIn();++k)
if (bl1->getIn(k)==bl2) count1 += 1;
count2 = 0;
for(k=0;k<bl2->sizeOut();++k)
if (bl2->getOut(k)==bl1) count2 += 1;
if (count1 != count2)
return false;
}
for(j=0;j<bl1->sizeOut();++j) {
bl2 = bl1->getOut(j); count1 = 0;
for(k=0;k<bl1->sizeOut();++k)
if (bl1->getOut(k)==bl2) count1 += 1;
count2 = 0;
for(k=0;k<bl2->sizeIn();++k)
if (bl2->getIn(k)==bl1) count2 += 1;
if (count1 != count2)
return false;
}
}
return true;
}
#endif
void BlockBasic::insert(list<PcodeOp *>::iterator iter,PcodeOp *inst)
{
uintm ordbefore,ordafter;
list<PcodeOp *>::iterator newiter;
inst->setParent( this );
newiter = op.insert(iter,inst);
inst->setBasicIter(newiter);
if (newiter == op.begin())
ordbefore = 2; else {
--newiter;
ordbefore = (*newiter)->getSeqNum().getOrder();
}
if (iter==op.end()) {
ordafter = ordbefore+0x1000000;
if (ordafter <= ordbefore)
ordafter = ~((uintm)0);
}
else
ordafter = (*iter)->getSeqNum().getOrder();
if (ordafter-ordbefore<=1)
setOrder();
else
inst->setOrder( ordafter/2 + ordbefore/2 );
if (inst->isBranch()) {
if (inst->code()==CPUI_BRANCHIND)
setFlag(f_switch_out);
}
}
void BlockBasic::removeOp(PcodeOp *inst)
{
inst->setParent( (BlockBasic *)0 );
op.erase(inst->basiciter);
}
Address BlockBasic::getEntryAddr(void) const
{
const Range *range;
if (cover.numRanges() == 1) range = cover.getFirstRange(); else {
if (op.empty())
return Address();
const Address &addr(op.front()->getAddr()); range = cover.getRange(addr.getSpace(),addr.getOffset());
if (range == (const Range *)0)
return op.front()->getAddr();
}
return range->getFirstAddr();
}
Address BlockBasic::getStart(void) const
{
const Range *range = cover.getFirstRange();
if (range == (const Range *)0)
return Address();
return range->getFirstAddr();
}
Address BlockBasic::getStop(void) const
{
const Range *range = cover.getLastRange();
if (range == (const Range *)0)
return Address();
return range->getLastAddr();
}
PcodeOp *BlockBasic::lastOp(void) const
{
if (op.empty()) return (PcodeOp *)0;
return (PcodeOp *) op.back();
}
bool BlockBasic::negateCondition(bool toporbottom)
{
PcodeOp *lastop = op.back();
lastop->flipFlag(PcodeOp::boolean_flip); lastop->flipFlag(PcodeOp::fallthru_true); FlowBlock::negateCondition(true); return true; }
FlowBlock *BlockBasic::getSplitPoint(void)
{
if (sizeOut() != 2) return (FlowBlock *)0;
return this;
}
int4 BlockBasic::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
{
if (op.empty()) return 2;
PcodeOp *lastop = op.back();
if (lastop->code() != CPUI_CBRANCH)
return 2;
return opFlipInPlaceTest(lastop,fliplist);
}
void BlockBasic::flipInPlaceExecute(void)
{
PcodeOp *lastop = op.back();
lastop->flipFlag(PcodeOp::fallthru_true); FlowBlock::negateCondition(true); }
bool BlockBasic::isComplex(void) const
{
list<PcodeOp *>::const_iterator iter,iter2;
PcodeOp *inst,*d_op;
Varnode *vn;
int4 statement,maxref;
statement = 0;
if (sizeOut()>=2)
statement = 1; maxref = data->getArch()->max_implied_ref; for(iter=op.begin();iter!=op.end();++iter) {
inst = *iter;
if (inst->isMarker()) continue;
vn = inst->getOut();
if (inst->isCall())
statement += 1;
else if (vn==(Varnode *)0) {
if (inst->isFlowBreak()) continue;
statement += 1;
}
else { bool yesstatement = false;
if (vn->hasNoDescend())
yesstatement = true;
else if (vn->isAddrTied()) yesstatement = true;
else {
int4 totalref = 0;
for(iter2=vn->beginDescend();iter2!=vn->endDescend();++iter2) {
d_op = *iter2;
if (d_op->isMarker()||(d_op->getParent() != this)) { yesstatement = true;
break;
}
totalref += 1;
if (totalref > maxref) { yesstatement = true; break;
}
}
}
if (yesstatement)
statement += 1;
}
if (statement >2) return true;
}
return false;
}
void FlowBlock::saveXmlHeader(ostream &s) const
{
a_v_i(s,"index",index);
}
void FlowBlock::restoreXmlHeader(const Element *el)
{
istringstream s(el->getAttributeValue("index"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> index;
}
void FlowBlock::saveXmlEdges(ostream &s) const
{
for(int4 i=0;i<intothis.size();++i) {
intothis[i].saveXml(s);
}
}
void FlowBlock::restoreXmlEdges(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver)
{
while(iter != enditer) {
const Element *el = *iter;
if (el->getName() != "edge")
return;
++iter;
restoreNextInEdge(el,resolver);
}
}
void FlowBlock::saveXml(ostream &s) const
{
s << "<block";
saveXmlHeader(s);
s << ">\n";
saveXmlBody(s);
saveXmlEdges(s);
s << "</block>\n";
}
void FlowBlock::restoreXml(const Element *el,BlockMap &resolver)
{
restoreXmlHeader(el);
const List &list(el->getChildren());
List::const_iterator iter;
iter = list.begin();
restoreXmlBody(iter,list.end(),resolver);
restoreXmlEdges(iter,list.end(),resolver);
}
const FlowBlock *FlowBlock::nextInFlow(void) const
{
const PcodeOp *op;
if (sizeOut()==1) return getOut(0);
if (sizeOut()==2) {
op = lastOp();
if (op == (const PcodeOp *)0) return (const FlowBlock *)0;
if (op->code() != CPUI_CBRANCH) return (const FlowBlock *)0;
return op->isFallthruTrue() ? getOut(1) : getOut(0);
}
return (const FlowBlock *)0;
}
bool BlockBasic::unblockedMulti(int4 outslot) const
{
const BlockBasic *blout = (const BlockBasic *)getOut(outslot);
const FlowBlock *bl;
PcodeOp *multiop,*othermulti;
list<PcodeOp *>::const_iterator iter;
Varnode *vnremove,*vnredund;
vector<const FlowBlock *> redundlist;
for(int4 i=0;i<sizeIn();++i) {
bl = getIn(i);
for(int4 j=0;j<bl->sizeOut();++j)
if (bl->getOut(j)==blout)
redundlist.push_back(bl);
}
if (redundlist.empty()) return true;
for(iter=blout->op.begin();iter!=blout->op.end();++iter) {
multiop = *iter;
if (multiop->code() != CPUI_MULTIEQUAL) continue;
for(vector<const FlowBlock *>::iterator biter=redundlist.begin();biter!=redundlist.end();++biter) {
bl = *biter;
vnredund = multiop->getIn(blout->getInIndex(bl)); vnremove = multiop->getIn(blout->getInIndex(this));
if (vnremove->isWritten()) {
othermulti = vnremove->getDef();
if ((othermulti->code()==CPUI_MULTIEQUAL)&&(othermulti->getParent()==this))
vnremove = othermulti->getIn(getInIndex(bl));
}
if (vnremove != vnredund) return false; }
}
return true;
}
bool BlockBasic::hasOnlyMarkers(void) const
{
list<PcodeOp *>::const_iterator iter;
const PcodeOp *bop;
for(iter=op.begin();iter!=op.end();++iter) {
bop = *iter;
if (bop->isMarker()) continue;
if (bop->isBranch()) continue;
return false;
}
return true;
}
bool BlockBasic::isDoNothing(void) const
{
if (sizeOut() != 1) return false; if (sizeIn() == 0) return false; if ((sizeIn()==1)&&(getIn(0)->isSwitchOut())) {
if (getOut(0)->sizeIn() > 1)
return false; }
PcodeOp *lastop = lastOp();
if ((lastop != (PcodeOp *)0)&&(lastop->code()==CPUI_BRANCHIND))
return false; return hasOnlyMarkers();
}
void BlockBasic::setInitialRange(const Address &beg,const Address &end)
{
cover.clear();
cover.insertRange(beg.getSpace(),beg.getOffset(),end.getOffset());
}
void BlockBasic::setOrder(void)
{
list<PcodeOp *>::iterator iter;
uintm count,step;
step = ~((uintm)0);
step = ( step / op.size() ) -1;
count = 0;
for(iter=op.begin();iter!=op.end();++iter) {
count += step;
(*iter)->setOrder(count);
}
}
void BlockBasic::saveXmlBody(ostream &s) const
{
cover.saveXml(s);
}
void BlockBasic::restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver)
{
cover.restoreXml(*iter, resolver.getAddressManager());
++iter;
}
void BlockBasic::printHeader(ostream &s) const
{
s << "Basic Block ";
FlowBlock::printHeader(s);
}
void BlockBasic::printRaw(ostream &s) const
{
list<PcodeOp *>::const_iterator iter;
PcodeOp *inst;
printHeader(s);
s << endl;
for(iter=op.begin();iter!=op.end();++iter) {
inst = *iter;
s << inst->getSeqNum() << ":\t";
inst->printRaw(s);
s << endl;
}
}
bool BlockBasic::noInterveningStatement(PcodeOp *first,int4 path,PcodeOp *last)
{
BlockBasic *curbl = (BlockBasic *)first->getParent()->getOut(path);
for(int4 i=0;i<2;++i) {
if (!curbl->hasOnlyMarkers()) return false;
if (curbl != last->getParent()) {
if (curbl->sizeOut() != 1) return false; }
else
return true;
curbl = (BlockBasic *)curbl->getOut(0);
}
return false;
}
void BlockCopy::printHeader(ostream &s) const
{
s << "Basic(copy) block ";
FlowBlock::printHeader(s);
}
void BlockCopy::printTree(ostream &s,int4 level) const
{
copy->printTree(s,level);
}
void BlockCopy::saveXmlHeader(ostream &s) const
{
FlowBlock::saveXmlHeader(s);
int4 altindex = copy->getIndex();
a_v_i(s,"altindex",altindex);
}
void BlockGoto::markUnstructured(void)
{
BlockGraph::markUnstructured(); if (gototype == f_goto_goto) {
if (gotoPrints())
markCopyBlock(gototarget,f_unstructured_targ);
}
}
void BlockGoto::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(gototarget->getIndex(),curloopexit);
if (curloopexit == gototarget->getIndex())
gototype = f_break_goto; }
bool BlockGoto::gotoPrints(void) const
{
if (getParent() != (FlowBlock *)0) {
FlowBlock *nextbl = getParent()->nextFlowAfter(this);
FlowBlock *gotobl = getGotoTarget()->getFrontLeaf();
return (gotobl != nextbl);
}
return false;
}
void BlockGoto::printHeader(ostream &s) const
{
s << "Plain goto block ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockGoto::nextFlowAfter(const FlowBlock *bl) const
{ return getGotoTarget()->getFrontLeaf();
}
void BlockGoto::saveXmlBody(ostream &s) const
{
BlockGraph::saveXmlBody(s);
s << "<target";
const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
a_v_i(s,"index",leaf->getIndex());
a_v_i(s,"depth",depth);
a_v_u(s,"type",gototype);
s << "/>\n";
}
void BlockMultiGoto::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); }
void BlockMultiGoto::printHeader(ostream &s) const
{
s << "Multi goto block ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockMultiGoto::nextFlowAfter(const FlowBlock *bl) const
{
return (FlowBlock *)0;
}
void BlockMultiGoto::saveXmlBody(ostream &s) const
{
BlockGraph::saveXmlBody(s);
for(int4 i=0;i<gotoedges.size();++i) {
FlowBlock *gototarget = gotoedges[i];
const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
s << "<target";
a_v_i(s,"index",leaf->getIndex());
a_v_i(s,"depth",depth);
s << "/>\n";
}
}
const FlowBlock *BlockList::getExitLeaf(void) const
{
if (getSize()==0) return (FlowBlock *)0;
return getBlock(getSize()-1)->getExitLeaf();
}
PcodeOp *BlockList::lastOp(void) const
{
if (getSize()==0) return (PcodeOp *)0;
return getBlock(getSize()-1)->lastOp(); }
bool BlockList::negateCondition(bool toporbottom)
{
FlowBlock *bl = getBlock(getSize()-1);
bool res = bl->negateCondition(false); FlowBlock::negateCondition(toporbottom); return res;
}
FlowBlock *BlockList::getSplitPoint(void)
{
if (getSize()==0) return (FlowBlock *)0;
return getBlock(getSize()-1)->getSplitPoint();
}
void BlockList::printHeader(ostream &s) const
{
s << "List block ";
FlowBlock::printHeader(s);
}
int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
{
FlowBlock *split1 = getBlock(0)->getSplitPoint();
if (split1 == (FlowBlock *)0)
return 2;
FlowBlock *split2 = getBlock(1)->getSplitPoint();
if (split2 == (FlowBlock *)0)
return 2;
int4 subtest1 = split1->flipInPlaceTest(fliplist);
if (subtest1 == 2)
return 2;
int4 subtest2 = split2->flipInPlaceTest(fliplist);
if (subtest2 == 2)
return 2;
return subtest1;
}
void BlockCondition::flipInPlaceExecute(void)
{
opc = (opc==CPUI_BOOL_AND) ? CPUI_BOOL_OR : CPUI_BOOL_AND;
getBlock(0)->getSplitPoint()->flipInPlaceExecute();
getBlock(1)->getSplitPoint()->flipInPlaceExecute();
}
PcodeOp *BlockCondition::lastOp(void) const
{ return getBlock(1)->lastOp();
}
bool BlockCondition::negateCondition(bool toporbottom)
{
bool res1,res2;
res1 = getBlock(0)->negateCondition(false); res2 = getBlock(1)->negateCondition(false); opc = (opc==CPUI_BOOL_AND) ? CPUI_BOOL_OR : CPUI_BOOL_AND;
FlowBlock::negateCondition(toporbottom); return (res1 || res2);
}
void BlockCondition::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); getBlock(1)->scopeBreak(-1,curloopexit);
}
void BlockCondition::printHeader(ostream &s) const
{
s << "Condition block(";
if (opc==CPUI_BOOL_AND)
s << "&&";
else
s << "||";
s << ") ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockCondition::nextFlowAfter(const FlowBlock *bl) const
{
return (FlowBlock *)0; }
void BlockCondition::saveXmlHeader(ostream &s) const
{
BlockGraph::saveXmlHeader(s);
string nm(get_opname(opc));
a_v(s,"opcode",nm);
}
void BlockIf::markUnstructured(void)
{
BlockGraph::markUnstructured(); if ((gototarget != (FlowBlock *)0)&&(gototype==f_goto_goto))
markCopyBlock(gototarget,f_unstructured_targ);
}
void BlockIf::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); for(int4 i=1;i<getSize();++i)
getBlock(i)->scopeBreak(curexit,curloopexit);
if ((gototarget != (FlowBlock *)0)&&(gototarget->getIndex() == curloopexit))
gototype = f_break_goto;
}
void BlockIf::printHeader(ostream &s) const
{
s << "If block ";
FlowBlock::printHeader(s);
}
bool BlockIf::preferComplement(Funcdata &data)
{
if (getSize()!=3) return false;
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
if (0 != split->flipInPlaceTest(fliplist))
return false;
split->flipInPlaceExecute();
opFlipInPlaceExecute(data,fliplist);
swapBlocks(1,2);
return true;
}
const FlowBlock *BlockIf::getExitLeaf(void) const
{ if (getSize() == 1)
return getBlock(0)->getExitLeaf();
return (FlowBlock *)0;
}
PcodeOp *BlockIf::lastOp(void) const
{ if (getSize() == 1)
return getBlock(0)->lastOp();
return (PcodeOp *)0;
}
FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const
{
if (getBlock(0)==bl)
return (FlowBlock *)0; if (getParent() == (FlowBlock *)0)
return (FlowBlock *)0;
return getParent()->nextFlowAfter(this);
}
void BlockIf::saveXmlBody(ostream &s) const
{
BlockGraph::saveXmlBody(s);
if (getSize() == 1) { const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
s << "<target";
a_v_i(s,"index",leaf->getIndex());
a_v_i(s,"depth",depth);
a_v_u(s,"type",gototype);
s << "/>\n";
}
}
void BlockWhileDo::findLoopVariable(PcodeOp *cbranch,BlockBasic *head,BlockBasic *tail,PcodeOp *lastOp)
{
Varnode *vn = cbranch->getIn(1);
if (!vn->isWritten()) return; PcodeOp *op = vn->getDef();
int4 slot = tail->getOutRevIndex(0);
PcodeOpNode path[4];
int4 count = 0;
if (op->isCall() || op->isMarker()) {
return;
}
path[0].op = op;
path[0].slot = 0;
while(count>=0) {
PcodeOp *curOp = path[count].op;
int4 ind = path[count].slot++;
if (ind >= curOp->numInput()) {
count -= 1;
continue;
}
Varnode *nextVn = curOp->getIn(ind);
if (!nextVn->isWritten()) continue;
PcodeOp *defOp = nextVn->getDef();
if (defOp->code() == CPUI_MULTIEQUAL) {
if (defOp->getParent() != head) continue;
Varnode *itvn = defOp->getIn(slot);
if (!itvn->isWritten()) continue;
PcodeOp *possibleIterate = itvn->getDef();
if (possibleIterate->getParent() == tail) { if (possibleIterate->isMarker())
continue; if (!possibleIterate->isMoveable(lastOp))
continue; loopDef = defOp;
iterateOp = possibleIterate;
return; }
}
else {
if (count == 3) continue;
if (defOp->isCall() || defOp->isMarker()) continue;
count += 1;
path[count].op = defOp;
path[count].slot = 0;
}
}
return; }
PcodeOp *BlockWhileDo::findInitializer(BlockBasic *head,int4 slot) const
{
if (head->sizeIn() != 2) return (PcodeOp *)0;
slot = 1 - slot;
Varnode *initVn = loopDef->getIn(slot);
if (!initVn->isWritten()) return (PcodeOp *)0;
PcodeOp *res = initVn->getDef();
if (res->isMarker()) return (PcodeOp *)0;
FlowBlock *initialBlock = res->getParent();
if (initialBlock != head->getIn(slot))
return (PcodeOp *)0; PcodeOp *lastOp = initialBlock->lastOp();
if (lastOp == (PcodeOp *)0) return (PcodeOp *)0;
if (initialBlock->sizeOut() != 1) return (PcodeOp *)0; if (lastOp->isBranch()) {
lastOp = lastOp->previousOp();
if (lastOp == (PcodeOp *)0) return (PcodeOp *)0;
}
initializeOp = res;
return lastOp;
}
PcodeOp *BlockWhileDo::testTerminal(Funcdata &data,int4 slot) const
{
Varnode *vn = loopDef->getIn(slot);
if (!vn->isWritten()) return (PcodeOp *)0;
PcodeOp *finalOp = vn->getDef();
BlockBasic *parentBlock = (BlockBasic *)loopDef->getParent()->getIn(slot);
PcodeOp *resOp = finalOp;
if (finalOp->code() == CPUI_COPY && finalOp->notPrinted()) {
vn = finalOp->getIn(0);
if (!vn->isWritten()) return (PcodeOp *)0;
resOp = vn->getDef();
if (resOp->getParent() != parentBlock) return (PcodeOp *)0;
}
if (!vn->isExplicit()) return (PcodeOp *)0;
if (resOp->notPrinted())
return (PcodeOp *)0;
PcodeOp *lastOp = finalOp->getParent()->lastOp();
if (lastOp->isBranch())
lastOp = lastOp->previousOp();
if (!data.moveRespectingCover(finalOp, lastOp))
return (PcodeOp *)0;
return resOp;
}
bool BlockWhileDo::testIterateForm(void) const
{
Varnode *targetVn = loopDef->getOut();
HighVariable *high = targetVn->getHigh();
vector<PcodeOpNode> path;
PcodeOp *op = iterateOp;
path.push_back(PcodeOpNode(op,0));
while(!path.empty()) {
PcodeOpNode &node(path.back());
if (node.op->numInput() <= node.slot) {
path.pop_back();
continue;
}
Varnode *vn = node.op->getIn(node.slot);
node.slot += 1;
if (vn->isAnnotation()) continue;
if (vn->getHigh() == high) {
return true;
}
if (vn->isExplicit()) continue; if (!vn->isWritten()) continue;
op = vn->getDef();
path.push_back(PcodeOpNode(vn->getDef(),0));
}
return false;
}
void BlockWhileDo::markLabelBumpUp(bool bump)
{
BlockGraph::markLabelBumpUp(true); if (!bump)
clearFlag(f_label_bumpup);
}
void BlockWhileDo::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curexit); getBlock(1)->scopeBreak(getBlock(0)->getIndex(),curexit); }
void BlockWhileDo::printHeader(ostream &s) const
{
s << "Whiledo block ";
if (hasOverflowSyntax())
s << "(overflow) ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockWhileDo::nextFlowAfter(const FlowBlock *bl) const
{
if (getBlock(0) == bl)
return (FlowBlock *)0;
FlowBlock *nextbl = getBlock(0); if (nextbl != (FlowBlock *)0)
nextbl = nextbl->getFrontLeaf();
return nextbl;
}
void BlockWhileDo::finalTransform(Funcdata &data)
{
BlockGraph::finalTransform(data);
if (!data.getArch()->analyze_for_loops) return;
if (hasOverflowSyntax()) return;
FlowBlock *copyBl = getFrontLeaf();
if (copyBl == (FlowBlock *)0) return;
BlockBasic *head = (BlockBasic *)copyBl->subBlock(0);
if (head->getType() != t_basic) return;
PcodeOp *lastOp = getBlock(1)->lastOp(); if (lastOp == (PcodeOp *)0) return;
BlockBasic *tail = lastOp->getParent();
if (tail->sizeOut() != 1) return;
if (tail->getOut(0) != head) return;
PcodeOp *cbranch = getBlock(0)->lastOp();
if (cbranch == (PcodeOp *)0 || cbranch->code() != CPUI_CBRANCH) return;
if (lastOp->isBranch()) { lastOp = lastOp->previousOp();
if (lastOp == (PcodeOp *)0) return;
}
findLoopVariable(cbranch, head, tail, lastOp);
if (iterateOp == (PcodeOp *)0) return;
if (iterateOp != lastOp) {
data.opUninsert(iterateOp);
data.opInsertAfter(iterateOp, lastOp);
}
lastOp = findInitializer(head, tail->getOutRevIndex(0));
if (lastOp == (PcodeOp *)0) return;
if (!initializeOp->isMoveable(lastOp)) {
initializeOp = (PcodeOp *)0; return;
}
if (initializeOp != lastOp) {
data.opUninsert(initializeOp);
data.opInsertAfter(initializeOp, lastOp);
}
}
void BlockWhileDo::finalizePrinting(Funcdata &data) const
{
BlockGraph::finalizePrinting(data); if (iterateOp == (PcodeOp *)0) return; int4 slot = iterateOp->getParent()->getOutRevIndex(0);
iterateOp = testTerminal(data,slot); if (iterateOp == (PcodeOp *)0) return;
if (!testIterateForm()) {
iterateOp = (PcodeOp *)0;
return;
}
if (initializeOp == (PcodeOp *)0)
findInitializer(loopDef->getParent(), slot); if (initializeOp != (PcodeOp *)0)
initializeOp = testTerminal(data,1-slot);
data.opMarkNonPrinting(iterateOp);
if (initializeOp != (PcodeOp *)0)
data.opMarkNonPrinting(initializeOp);
}
void BlockDoWhile::markLabelBumpUp(bool bump)
{
BlockGraph::markLabelBumpUp(true); if (!bump)
clearFlag(f_label_bumpup);
}
void BlockDoWhile::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curexit); }
void BlockDoWhile::printHeader(ostream &s) const
{
s << "Dowhile block ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockDoWhile::nextFlowAfter(const FlowBlock *bl) const
{
return (FlowBlock *)0; }
void BlockInfLoop::markLabelBumpUp(bool bump)
{
BlockGraph::markLabelBumpUp(true); if (!bump)
clearFlag(f_label_bumpup);
}
void BlockInfLoop::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(getBlock(0)->getIndex(),curexit); }
void BlockInfLoop::printHeader(ostream &s) const
{
s << "Infinite loop block ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockInfLoop::nextFlowAfter(const FlowBlock *bl) const
{
FlowBlock *nextbl = getBlock(0); if (nextbl != (FlowBlock *)0)
nextbl = nextbl->getFrontLeaf();
return nextbl;
}
BlockSwitch::BlockSwitch(FlowBlock *ind)
{
jump = ind->getJumptable();
}
void BlockSwitch::addCase(FlowBlock *switchbl,FlowBlock *bl,uint4 gt)
{
caseblocks.emplace_back();
CaseOrder &curcase( caseblocks.back() );
const FlowBlock *basicbl = bl->getFrontLeaf()->subBlock(0);
curcase.block = bl;
curcase.basicblock = basicbl;
curcase.label = 0;
curcase.depth = 0;
curcase.chain = -1;
int4 inindex = basicbl->getInIndex(switchbl);
if (inindex==-1)
throw LowlevelError("Case block has become detached from switch");
curcase.outindex = basicbl->getInRevIndex(inindex);
curcase.gototype = gt;
if (gt != 0)
curcase.isexit = false;
else
curcase.isexit = (bl->sizeOut() == 1);
curcase.isdefault = switchbl->isDefaultBranch( curcase.outindex );
}
void BlockSwitch::grabCaseBasic(FlowBlock *switchbl,const vector<FlowBlock *> &cs)
{
vector<int4> casemap(switchbl->sizeOut(),-1); caseblocks.clear();
for(int4 i=1;i<cs.size();++i) {
FlowBlock *casebl = cs[i];
addCase(switchbl,casebl,0);
casemap[caseblocks[i-1].outindex] = i-1;
}
for(int4 i=0;i<caseblocks.size();++i) {
CaseOrder &curcase( caseblocks[i] );
FlowBlock *casebl = curcase.block;
if (casebl->getType() == t_goto) { FlowBlock *targetbl = ((BlockGoto *)casebl)->getGotoTarget();
const FlowBlock *basicbl = targetbl->getFrontLeaf()->subBlock(0);
int4 inindex = basicbl->getInIndex(switchbl);
if (inindex == -1) continue; curcase.chain = casemap[ basicbl->getInRevIndex(inindex) ];
}
}
if (cs[0]->getType() == t_multigoto) { BlockMultiGoto *gotoedgeblock = (BlockMultiGoto *)cs[0];
int4 numgoto = gotoedgeblock->numGotos();
for(int4 i=0;i<numgoto;++i)
addCase(switchbl,gotoedgeblock->getGoto(i),f_goto_goto);
}
}
void BlockSwitch::finalizePrinting(Funcdata &data) const
{
BlockGraph::finalizePrinting(data); for(int4 i=0;i<caseblocks.size();++i) { CaseOrder &curcase( caseblocks[i] );
int4 j = curcase.chain;
while(j != -1) { if (caseblocks[j].depth != 0) break; caseblocks[j].depth = -1; j = caseblocks[j].chain;
}
}
for(int4 i=0;i<caseblocks.size();++i) {
CaseOrder &curcase( caseblocks[i] );
if (jump->numIndicesByBlock(curcase.basicblock) > 0) {
if (curcase.depth == 0) { int4 ind = jump->getIndexByBlock(curcase.basicblock,0);
curcase.label = jump->getLabelByIndex(ind);
int4 j = curcase.chain;
int4 depthcount = 1;
while(j != -1) {
if (caseblocks[j].depth > 0) break; caseblocks[j].depth = depthcount++;
caseblocks[j].label = curcase.label;
j = caseblocks[j].chain;
}
}
}
else
curcase.label = 0; }
stable_sort(caseblocks.begin(),caseblocks.end(),CaseOrder::compare);
}
const Datatype *BlockSwitch::getSwitchType(void) const
{
PcodeOp *op = jump->getIndirectOp();
return op->getIn(0)->getHigh()->getType();
}
void BlockSwitch::markUnstructured(void)
{
BlockGraph::markUnstructured(); for(int4 i=0;i<caseblocks.size();++i) {
if (caseblocks[i].gototype == f_goto_goto)
markCopyBlock(caseblocks[i].block,f_unstructured_targ);
}
}
void BlockSwitch::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curexit); for(int4 i=0;i<caseblocks.size();++i) {
FlowBlock *bl = caseblocks[i].block;
if (caseblocks[i].gototype != 0) {
if (bl->getIndex() == curexit) caseblocks[i].gototype = f_break_goto;
}
else {
bl->scopeBreak(curexit,curexit);
}
}
}
void BlockSwitch::printHeader(ostream &s) const
{
s << "Switch block ";
FlowBlock::printHeader(s);
}
FlowBlock *BlockSwitch::nextFlowAfter(const FlowBlock *bl) const
{
if (getBlock(0) == bl)
return (FlowBlock *)0; int4 i;
for(i=0;i<caseblocks.size();++i)
if (caseblocks[i].block == bl) break;
if (i==caseblocks.size()) return (FlowBlock *)0;
i = i + 1; if (i < caseblocks.size())
return caseblocks[i].block->getFrontLeaf();
if (getParent() == (const FlowBlock *)0) return (FlowBlock *)0;
return getParent()->nextFlowAfter(this);
}
BlockMap::BlockMap(const BlockMap &op2)
{
manage = op2.manage;
}
FlowBlock *BlockMap::resolveBlock(FlowBlock::block_type bt)
{
switch(bt) {
case FlowBlock::t_plain:
return new FlowBlock();
case FlowBlock::t_copy:
return new BlockCopy((FlowBlock *)0);
case FlowBlock::t_graph:
return new BlockGraph();
default:
break;
}
return (FlowBlock *)0;
}
FlowBlock *BlockMap::findBlock(const vector<FlowBlock *> &list,int4 ind)
{
int4 min = 0;
int4 max = list.size();
max -= 1;
while(min <= max) {
int4 mid = (min + max)/2;
FlowBlock *block = list[mid];
if (block->getIndex() == ind)
return block;
if (block->getIndex() < ind)
min = mid + 1;
else
max = mid -1;
}
return (FlowBlock *)0;
}
void BlockMap::sortList(void)
{
sort(sortlist.begin(),sortlist.end(),FlowBlock::compareBlockIndex);
}
FlowBlock *BlockMap::createBlock(const string &name)
{
FlowBlock::block_type bt = FlowBlock::nameToType(name);
FlowBlock *bl = resolveBlock(bt);
sortlist.push_back(bl);
return bl;
}