Thanks to @lab313ru : fix bad iterator usage

Trying to increment past the end in graph.cpp

Also removed a goto by extracting a common function.
This commit is contained in:
nemerle
2016-04-24 12:22:15 +02:00
parent 12ee08f87e
commit 5963f5fd4d

View File

@@ -1,389 +1,396 @@
/***************************************************************************** /*****************************************************************************
* dcc project CFG related functions * dcc project CFG related functions
* (C) Cristina Cifuentes * (C) Cristina Cifuentes
****************************************************************************/ ****************************************************************************/
#include <string.h> #include <string.h>
#include <boost/range/rbegin.hpp> #include <boost/range/rbegin.hpp>
#include <boost/range/rend.hpp> #include <boost/range/rend.hpp>
#include <boost/range/adaptors.hpp> #include <boost/range/adaptors.hpp>
#include "dcc.h" #include "dcc.h"
#include "graph.h" #include "graph.h"
#include "project.h" #include "project.h"
using namespace std; using namespace std;
using namespace boost; using namespace boost;
extern Project g_proj; extern Project g_proj;
//static BB * rmJMP(Function * pProc, int marker, BB * pBB); //static BB * rmJMP(Function * pProc, int marker, BB * pBB);
//static void mergeFallThrough(Function * pProc, BB * pBB); //static void mergeFallThrough(Function * pProc, BB * pBB);
//static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last); //static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last);
/***************************************************************************** void Function::addOutEdgesForConditionalJump(BB * pBB,int next_ip, LLInst *ll)
* createCFG - Create the basic control flow graph {
****************************************************************************/ pBB->addOutEdge(next_ip);
void Function::createCFG() /* This is checking for jumps off into nowhere */
{ if ( not ll->testFlags(NO_LABEL) )
/* Splits Icode associated with the procedure into Basic Blocks. pBB->addOutEdge(ll->src().getImm2());
* The links between BBs represent the control flow graph of the }
* procedure.
* A Basic Block is defined to end on one of the following instructions: /*****************************************************************************
* 1) Conditional and unconditional jumps * createCFG - Create the basic control flow graph
* 2) CALL(F) ****************************************************************************/
* 3) RET(F) void Function::createCFG()
* 4) On the instruction before a join (a flagged TARGET) {
* 5) Repeated string instructions /* Splits Icode associated with the procedure into Basic Blocks.
* 6) End of procedure * The links between BBs represent the control flow graph of the
*/ * procedure.
* A Basic Block is defined to end on one of the following instructions:
BB * psBB; * 1) Conditional and unconditional jumps
BB * pBB; * 2) CALL(F)
iICODE pIcode = Icode.begin(); * 3) RET(F)
* 4) On the instruction before a join (a flagged TARGET)
stats.numBBbef = stats.numBBaft = 0; * 5) Repeated string instructions
rICODE current_range=make_iterator_range(pIcode,++iICODE(pIcode)); * 6) End of procedure
for (; pIcode!=Icode.end(); ++pIcode,current_range.advance_end(1)) */
{
iICODE nextIcode = ++iICODE(pIcode); BB * psBB;
pBB = nullptr; BB * pBB;
iICODE pIcode = Icode.begin();
LLInst *ll = pIcode->ll();
/* Only process icodes that have valid instructions */ stats.numBBbef = stats.numBBaft = 0;
if(ll->testFlags(NO_CODE)) rICODE current_range=make_iterator_range(pIcode,++iICODE(pIcode));
continue; for (; pIcode!=Icode.end(); ++pIcode,current_range.advance_end(1))
/* Stick a NOWHERE_NODE on the end if we terminate {
* with anything other than a ret, jump or terminate */ iICODE nextIcode = ++iICODE(pIcode);
if (nextIcode == Icode.end() and pBB = nullptr;
(not ll->testFlags(TERMINATES)) and
(not ll->match(iJMP)) and (not ll->match(iJMPF)) and LLInst *ll = pIcode->ll();
(not ll->match(iRET)) and (not ll->match(iRETF))) /* Only process icodes that have valid instructions */
{ if(ll->testFlags(NO_CODE))
pBB=BB::Create(current_range, NOWHERE_NODE, this); continue;
} /* Stick a NOWHERE_NODE on the end if we terminate
else * with anything other than a ret, jump or terminate */
switch (ll->getOpcode()) { if (nextIcode == Icode.end() and
case iJB: case iJBE: case iJAE: case iJA: (not ll->testFlags(TERMINATES)) and
case iJL: case iJLE: case iJGE: case iJG: (not ll->match(iJMP)) and (not ll->match(iJMPF)) and
case iJE: case iJNE: case iJS: case iJNS: (not ll->match(iRET)) and (not ll->match(iRETF)))
case iJO: case iJNO: case iJP: case iJNP: {
case iJCXZ: pBB=BB::Create(current_range, NOWHERE_NODE, this);
pBB = BB::Create(current_range, TWO_BRANCH, this); }
CondJumps: else
pBB->addOutEdge(nextIcode->loc_ip); switch (ll->getOpcode()) {
/* This is checking for jumps off into nowhere */ case iJB: case iJBE: case iJAE: case iJA:
if ( not ll->testFlags(NO_LABEL) ) case iJL: case iJLE: case iJGE: case iJG:
pBB->addOutEdge(ll->src().getImm2()); case iJE: case iJNE: case iJS: case iJNS:
break; case iJO: case iJNO: case iJP: case iJNP:
case iJCXZ:
case iLOOP: case iLOOPE: case iLOOPNE: pBB = BB::Create(current_range, TWO_BRANCH, this);
pBB = BB::Create(current_range, LOOP_NODE, this); addOutEdgesForConditionalJump(pBB,nextIcode->loc_ip, ll);
goto CondJumps; break;
case iJMPF: case iJMP: case iLOOP: case iLOOPE: case iLOOPNE:
if (ll->testFlags(SWITCH)) pBB = BB::Create(current_range, LOOP_NODE, this);
{ addOutEdgesForConditionalJump(pBB,nextIcode->loc_ip, ll);
pBB = BB::Create(current_range, MULTI_BRANCH, this); break;
for (auto & elem : ll->caseTbl2)
pBB->addOutEdge(elem); case iJMPF: case iJMP:
hasCase = true; if (ll->testFlags(SWITCH))
} {
else if ((ll->getFlag() & (I | NO_LABEL)) == I) //TODO: WHY NO_LABEL TESTIT pBB = BB::Create(current_range, MULTI_BRANCH, this);
{ for (auto & elem : ll->caseTbl2)
pBB = BB::Create(current_range, ONE_BRANCH, this); pBB->addOutEdge(elem);
pBB->addOutEdge(ll->src().getImm2()); hasCase = true;
} }
else else if ((ll->getFlag() & (I | NO_LABEL)) == I) //TODO: WHY NO_LABEL TESTIT
pBB = BB::Create(current_range, NOWHERE_NODE, this); {
break; pBB = BB::Create(current_range, ONE_BRANCH, this);
pBB->addOutEdge(ll->src().getImm2());
case iCALLF: case iCALL: }
{ else
Function * p = ll->src().proc.proc; pBB = BB::Create(current_range, NOWHERE_NODE, this);
pBB = BB::Create(current_range, CALL_NODE, this); break;
if (p && not ((p->flg) & TERMINATES) )
pBB->addOutEdge(nextIcode->loc_ip); case iCALLF: case iCALL:
break; {
} Function * p = ll->src().proc.proc;
pBB = BB::Create(current_range, CALL_NODE, this);
case iRET: case iRETF: if (p && not ((p->flg) & TERMINATES) )
pBB = BB::Create(current_range, RETURN_NODE, this); pBB->addOutEdge(nextIcode->loc_ip);
break; break;
}
default:
/* Check for exit to DOS */ case iRET: case iRETF:
if ( ll->testFlags(TERMINATES) ) pBB = BB::Create(current_range, RETURN_NODE, this);
{ break;
pBB = BB::Create(current_range, TERMINATE_NODE, this);
} default:
/* Check for a fall through */ /* Check for exit to DOS */
else if (nextIcode != Icode.end()) if ( ll->testFlags(TERMINATES) )
{ {
if (nextIcode->ll()->testFlags(TARGET | CASE)) pBB = BB::Create(current_range, TERMINATE_NODE, this);
{ }
pBB = BB::Create(current_range, FALL_NODE, this); /* Check for a fall through */
pBB->addOutEdge(nextIcode->loc_ip); else if (nextIcode != Icode.end())
} {
} if (nextIcode->ll()->testFlags(TARGET | CASE))
break; {
} pBB = BB::Create(current_range, FALL_NODE, this);
if(pBB!=nullptr) // created a new Basic block pBB->addOutEdge(nextIcode->loc_ip);
{ }
// restart the range }
// end iterator will be updated by expression in for statement break;
current_range=make_iterator_range(nextIcode,nextIcode); }
} if(pBB!=nullptr) // created a new Basic block
} {
for (auto pr : m_ip_to_bb) // restart the range
{ // end iterator will be updated by expression in for statement
BB* pBB=pr.second; current_range=make_iterator_range(nextIcode,nextIcode);
for (auto & elem : pBB->edges) }
{ if (nextIcode == Icode.end())
int32_t ip = elem.ip; break;
if (ip >= SYNTHESIZED_MIN) }
{ for (auto pr : m_ip_to_bb)
fatalError (INVALID_SYNTHETIC_BB); {
return; BB* pBB=pr.second;
} for (auto & elem : pBB->edges)
auto iter2=m_ip_to_bb.find(ip); {
if(iter2==m_ip_to_bb.end()) int32_t ip = elem.ip;
fatalError(NO_BB, ip, name.c_str()); if (ip >= SYNTHESIZED_MIN)
psBB = iter2->second; {
elem.BBptr = psBB; fatalError (INVALID_SYNTHETIC_BB);
psBB->inEdges.push_back((BB *)nullptr); return;
} }
} auto iter2=m_ip_to_bb.find(ip);
} if(iter2==m_ip_to_bb.end())
fatalError(NO_BB, ip, name.c_str());
void Function::markImpure() psBB = iter2->second;
{ elem.BBptr = psBB;
PROG &prog(Project::get()->prog); psBB->inEdges.push_back((BB *)nullptr);
for(ICODE &icod : Icode) }
{ }
if ( not icod.ll()->testFlags(SYM_USE | SYM_DEF)) }
continue;
//assert that case tbl has less entries then symbol table ???? void Function::markImpure()
//WARNING: Case entries are held in symbol table ! {
assert(Project::get()->validSymIdx(icod.ll()->caseEntry)); PROG &prog(Project::get()->prog);
const SYM &psym(Project::get()->getSymByIdx(icod.ll()->caseEntry)); for(ICODE &icod : Icode)
for (int c = (int)psym.label; c < (int)psym.label+psym.size; c++) {
{ if ( not icod.ll()->testFlags(SYM_USE | SYM_DEF))
if (BITMAP(c, BM_CODE)) continue;
{ //assert that case tbl has less entries then symbol table ????
icod.ll()->setFlags(IMPURE); //WARNING: Case entries are held in symbol table !
flg |= IMPURE; assert(Project::get()->validSymIdx(icod.ll()->caseEntry));
break; const SYM &psym(Project::get()->getSymByIdx(icod.ll()->caseEntry));
} for (int c = (int)psym.label; c < (int)psym.label+psym.size; c++)
} {
} if (BITMAP(c, BM_CODE))
{
} icod.ll()->setFlags(IMPURE);
flg |= IMPURE;
/***************************************************************************** break;
* freeCFG - Deallocates a cfg }
****************************************************************************/ }
void Function::freeCFG() }
{
for(auto p : m_ip_to_bb) }
{
delete p.second; /*****************************************************************************
} * freeCFG - Deallocates a cfg
m_ip_to_bb.clear(); ****************************************************************************/
} void Function::freeCFG()
{
for(auto p : m_ip_to_bb)
/***************************************************************************** {
* compressCFG - Remove redundancies and add in-edge information delete p.second;
****************************************************************************/ }
void Function::compressCFG() m_ip_to_bb.clear();
{ }
BB *pNxt;
int ip, first=0, last;
/*****************************************************************************
/* First pass over BB list removes redundant jumps of the form * compressCFG - Remove redundancies and add in-edge information
* (Un)Conditional -> Unconditional jump */ ****************************************************************************/
for (BB *pBB : m_actual_cfg) //m_cfg void Function::compressCFG()
{ {
if(pBB->inEdges.empty() || (pBB->nodeType != ONE_BRANCH && pBB->nodeType != TWO_BRANCH)) BB *pNxt;
continue; int ip, first=0, last;
for (TYPEADR_TYPE &edgeRef : pBB->edges)
{ /* First pass over BB list removes redundant jumps of the form
ip = pBB->rbegin()->loc_ip; * (Un)Conditional -> Unconditional jump */
pNxt = edgeRef.BBptr->rmJMP(ip, edgeRef.BBptr); for (BB *pBB : m_actual_cfg) //m_cfg
{
if (not pBB->edges.empty()) /* Might have been clobbered */ if(pBB->inEdges.empty() || (pBB->nodeType != ONE_BRANCH && pBB->nodeType != TWO_BRANCH))
{ continue;
edgeRef.BBptr = pNxt; for (TYPEADR_TYPE &edgeRef : pBB->edges)
assert(pBB->back().loc_ip==ip); {
pBB->back().ll()->SetImmediateOp((uint32_t)pNxt->begin()->loc_ip); ip = pBB->rbegin()->loc_ip;
//Icode[ip].SetImmediateOp((uint32_t)pNxt->begin()); pNxt = edgeRef.BBptr->rmJMP(ip, edgeRef.BBptr);
}
} if (not pBB->edges.empty()) /* Might have been clobbered */
} {
edgeRef.BBptr = pNxt;
/* Next is a depth-first traversal merging any FALL_NODE or assert(pBB->back().loc_ip==ip);
* ONE_BRANCH that fall through to a node with that as their only pBB->back().ll()->SetImmediateOp((uint32_t)pNxt->begin()->loc_ip);
* in-edge. */ //Icode[ip].SetImmediateOp((uint32_t)pNxt->begin());
m_actual_cfg.front()->mergeFallThrough(Icode); }
}
/* Remove redundant BBs created by the above compressions }
* and allocate in-edge arrays as required. */
stats.numBBaft = stats.numBBbef; /* Next is a depth-first traversal merging any FALL_NODE or
bool entry_node=true; * ONE_BRANCH that fall through to a node with that as their only
for(BB *pBB : m_actual_cfg) * in-edge. */
{ m_actual_cfg.front()->mergeFallThrough(Icode);
if (pBB->inEdges.empty())
{ /* Remove redundant BBs created by the above compressions
if (entry_node) /* Init it misses out on */ * and allocate in-edge arrays as required. */
pBB->index = UN_INIT; stats.numBBaft = stats.numBBbef;
else bool entry_node=true;
{ for(BB *pBB : m_actual_cfg)
delete pBB; {
stats.numBBaft--; if (pBB->inEdges.empty())
} {
} if (entry_node) /* Init it misses out on */
else pBB->index = UN_INIT;
{ else
pBB->inEdgeCount = pBB->inEdges.size(); {
} delete pBB;
entry_node=false; stats.numBBaft--;
} }
}
/* Allocate storage for dfsLast[] array */ else
numBBs = stats.numBBaft; {
m_dfsLast.resize(numBBs,nullptr); // = (BB **)allocMem(numBBs * sizeof(BB *)) pBB->inEdgeCount = pBB->inEdges.size();
}
/* Now do a dfs numbering traversal and fill in the inEdges[] array */ entry_node=false;
last = numBBs - 1; }
m_actual_cfg.front()->dfsNumbering(m_dfsLast, &first, &last);
} /* Allocate storage for dfsLast[] array */
numBBs = stats.numBBaft;
m_dfsLast.resize(numBBs,nullptr); // = (BB **)allocMem(numBBs * sizeof(BB *))
/****************************************************************************
* rmJMP - If BB addressed is just a JMP it is replaced with its target /* Now do a dfs numbering traversal and fill in the inEdges[] array */
***************************************************************************/ last = numBBs - 1;
BB *BB::rmJMP(int marker, BB * pBB) m_actual_cfg.front()->dfsNumbering(m_dfsLast, &first, &last);
{ }
marker += (int)DFS_JMP;
while (pBB->nodeType == ONE_BRANCH && pBB->size() == 1) /****************************************************************************
{ * rmJMP - If BB addressed is just a JMP it is replaced with its target
if (pBB->traversed != marker) ***************************************************************************/
{ BB *BB::rmJMP(int marker, BB * pBB)
pBB->traversed = (eDFS)marker; {
pBB->inEdges.pop_back(); marker += (int)DFS_JMP;
if (not pBB->inEdges.empty())
{ while (pBB->nodeType == ONE_BRANCH && pBB->size() == 1)
pBB->edges[0].BBptr->inEdges.push_back((BB *)nullptr); {
} if (pBB->traversed != marker)
else {
{ pBB->traversed = (eDFS)marker;
pBB->front().ll()->setFlags(NO_CODE); pBB->inEdges.pop_back();
pBB->front().invalidate(); //pProc->Icode.SetLlInvalid(pBB->begin(), true); if (not pBB->inEdges.empty())
} {
pBB->edges[0].BBptr->inEdges.push_back((BB *)nullptr);
pBB = pBB->edges[0].BBptr; }
} else
else {
{ pBB->front().ll()->setFlags(NO_CODE);
/* We are going around in circles */ pBB->front().invalidate(); //pProc->Icode.SetLlInvalid(pBB->begin(), true);
pBB->nodeType = NOWHERE_NODE; }
pBB->front().ll()->replaceSrc(LLOperand::CreateImm2(pBB->front().loc_ip));
//pBB->front().ll()->src.immed.op = pBB->front().loc_ip; pBB = pBB->edges[0].BBptr;
do { }
pBB = pBB->edges[0].BBptr; else
pBB->inEdges.pop_back(); // was --numInedges {
if (! pBB->inEdges.empty()) /* We are going around in circles */
{ pBB->nodeType = NOWHERE_NODE;
pBB->front().ll()->setFlags(NO_CODE); pBB->front().ll()->replaceSrc(LLOperand::CreateImm2(pBB->front().loc_ip));
pBB->front().invalidate(); //pBB->front().ll()->src.immed.op = pBB->front().loc_ip;
// pProc->Icode.setFlags(pBB->start, NO_CODE); do {
// pProc->Icode.SetLlInvalid(pBB->start, true); pBB = pBB->edges[0].BBptr;
} pBB->inEdges.pop_back(); // was --numInedges
} while (pBB->nodeType != NOWHERE_NODE); if (! pBB->inEdges.empty())
{
pBB->edges.clear(); pBB->front().ll()->setFlags(NO_CODE);
} pBB->front().invalidate();
} // pProc->Icode.setFlags(pBB->start, NO_CODE);
return pBB; // pProc->Icode.SetLlInvalid(pBB->start, true);
} }
} while (pBB->nodeType != NOWHERE_NODE);
/***************************************************************************** pBB->edges.clear();
* mergeFallThrough }
****************************************************************************/ }
void BB::mergeFallThrough( CIcodeRec &Icode) return pBB;
{ }
BB * pChild;
if (!this)
{ /*****************************************************************************
printf("mergeFallThrough on empty BB!\n"); * mergeFallThrough
} ****************************************************************************/
while (nodeType == FALL_NODE || nodeType == ONE_BRANCH) void BB::mergeFallThrough( CIcodeRec &Icode)
{ {
pChild = edges[0].BBptr; BB * pChild;
/* Jump to next instruction can always be removed */ if (!this)
if (nodeType == ONE_BRANCH) {
{ printf("mergeFallThrough on empty BB!\n");
assert(Parent==pChild->Parent); }
if(back().loc_ip>pChild->front().loc_ip) // back edege while (nodeType == FALL_NODE || nodeType == ONE_BRANCH)
break; {
auto iter=std::find_if(this->end(),pChild->begin(),[](ICODE &c) pChild = edges[0].BBptr;
{return not c.ll()->testFlags(NO_CODE);}); /* Jump to next instruction can always be removed */
if (nodeType == ONE_BRANCH)
if (iter != pChild->begin()) {
break; assert(Parent==pChild->Parent);
back().ll()->setFlags(NO_CODE); if(back().loc_ip>pChild->front().loc_ip) // back edege
back().invalidate(); break;
nodeType = FALL_NODE; auto iter=std::find_if(this->end(),pChild->begin(),[](ICODE &c)
//instructions.advance_end(-1); //TODO: causes creation of empty BB {return not c.ll()->testFlags(NO_CODE);});
}
/* If there's no other edges into child can merge */ if (iter != pChild->begin())
if (pChild->inEdges.size() != 1) break;
break; back().ll()->setFlags(NO_CODE);
back().invalidate();
nodeType = pChild->nodeType; nodeType = FALL_NODE;
instructions = boost::make_iterator_range(begin(),pChild->end()); //instructions.advance_end(-1); //TODO: causes creation of empty BB
pChild->front().ll()->clrFlags(TARGET); }
edges.swap(pChild->edges); /* If there's no other edges into child can merge */
if (pChild->inEdges.size() != 1)
pChild->inEdges.clear(); break;
pChild->edges.clear();
} nodeType = pChild->nodeType;
traversed = DFS_MERGE; instructions = boost::make_iterator_range(begin(),pChild->end());
pChild->front().ll()->clrFlags(TARGET);
/* Process all out edges recursively */ edges.swap(pChild->edges);
for (auto & elem : edges)
{ pChild->inEdges.clear();
if (elem.BBptr->traversed != DFS_MERGE) pChild->edges.clear();
elem.BBptr->mergeFallThrough(Icode); }
} traversed = DFS_MERGE;
}
/* Process all out edges recursively */
for (auto & elem : edges)
/***************************************************************************** {
* dfsNumbering - Numbers nodes during first and last visits and determine if (elem.BBptr->traversed != DFS_MERGE)
* in-edges elem.BBptr->mergeFallThrough(Icode);
****************************************************************************/ }
void BB::dfsNumbering(std::vector<BB *> &dfsLast, int *first, int *last) }
{
BB * pChild;
traversed = DFS_NUM; /*****************************************************************************
dfsFirstNum = (*first)++; * dfsNumbering - Numbers nodes during first and last visits and determine
* in-edges
/* index is being used as an index to inEdges[]. */ ****************************************************************************/
// for (i = 0; i < edges.size(); i++) void BB::dfsNumbering(std::vector<BB *> &dfsLast, int *first, int *last)
for(auto edge : edges) {
{ BB * pChild;
pChild = edge.BBptr; traversed = DFS_NUM;
pChild->inEdges[pChild->index++] = this; dfsFirstNum = (*first)++;
/* Is this the last visit? */ /* index is being used as an index to inEdges[]. */
if (pChild->index == int(pChild->inEdges.size())) // for (i = 0; i < edges.size(); i++)
pChild->index = UN_INIT; for(auto edge : edges)
{
if (pChild->traversed != DFS_NUM) pChild = edge.BBptr;
pChild->dfsNumbering(dfsLast, first, last); pChild->inEdges[pChild->index++] = this;
}
dfsLastNum = *last; /* Is this the last visit? */
dfsLast[(*last)--] = this; if (pChild->index == int(pChild->inEdges.size()))
} pChild->index = UN_INIT;
if (pChild->traversed != DFS_NUM)
pChild->dfsNumbering(dfsLast, first, last);
}
dfsLastNum = *last;
dfsLast[(*last)--] = this;
}