dcc/src/control.cpp
2016-05-06 15:57:15 +02:00

667 lines
22 KiB
C++

/*********************************************************************
* Description : Performs control flow analysis on the CFG
* (C) Cristina Cifuentes
********************************************************************/
#include "dcc.h"
#include "msvc_fixes.h"
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <list>
#include <cassert>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
typedef std::list<int> nodeList; /* dfsLast index to the node */
#define ancestor(a,b) ((a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum))
/* there is a path on the DFST from a to b if the a was first visited in a
* dfs, and a was later visited than b when doing the last visit of each
* node. */
/* Checks if the edge (p,s) is a back edge. If node s was visited first
* during the dfs traversal (ie. s has a smaller dfsFirst number) or s == p,
* then it is a backedge.
* Also incrementes the number of backedges entries to the header node. */
static bool isBackEdge (BB * p,BB * s)
{
if (p->dfsFirstNum >= s->dfsFirstNum)
{
s->numBackEdges++;
return true;
}
return false;
}
/* Finds the common dominator of the current immediate dominator
* currImmDom and its predecessor's immediate dominator predImmDom */
static int commonDom (int currImmDom, int predImmDom, Function * pProc)
{
if (currImmDom == NO_DOM)
return (predImmDom);
if (predImmDom == NO_DOM) /* predecessor is the root */
return (currImmDom);
while ((currImmDom != NO_DOM) and (predImmDom != NO_DOM) and
(currImmDom != predImmDom))
{
if (currImmDom < predImmDom)
predImmDom = pProc->m_dfsLast[predImmDom]->immedDom;
else
currImmDom = pProc->m_dfsLast[currImmDom]->immedDom;
}
return (currImmDom);
}
/* Finds the immediate dominator of each node in the graph pProc->cfg.
* Adapted version of the dominators algorithm by Hecht and Ullman; finds
* immediate dominators only.
* Note: graph should be reducible */
void Function::findImmedDom ()
{
BB * currNode;
for (size_t currIdx = 0; currIdx < numBBs; currIdx++)
{
currNode = m_dfsLast[currIdx];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue;
for (BB * inedge : currNode->inEdges)
{
size_t predIdx = inedge->dfsLastNum;
if (predIdx < currIdx)
currNode->immedDom = commonDom (currNode->immedDom, predIdx, this);
}
}
}
/* Inserts the node n to the list l. */
static void insertList (nodeList &l, int n)
{
l.push_back(n);
}
/* Returns whether or not the node n (dfsLast numbering of a basic block)
* is on the list l. */
static bool inList (const nodeList &l, int n)
{
return std::find(l.begin(),l.end(),n)!=l.end();
}
/* Frees space allocated by the list l. */
static void freeList (nodeList &l)
{
l.clear();
}
/* Returns whether the node n belongs to the queue list q. */
static bool inInt(BB * n, queue &q)
{
return std::find(q.begin(),q.end(),n)!=q.end();
}
/* Finds the follow of the endless loop headed at node head (if any).
* The follow node is the closest node to the loop. */
static void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
{
head->loopFollow = MAX;
for( int loop_node : loopNodes)
{
for (TYPEADR_TYPE &typeaddr: pProc->m_dfsLast[loop_node]->edges)
{
int succ = typeaddr.BBptr->dfsLastNum;
if ((not inList(loopNodes, succ)) and (succ < head->loopFollow))
head->loopFollow = succ;
}
}
}
//static void findNodesInLoop(BB * latchNode,BB * head,PPROC pProc,queue *intNodes)
/* Flags nodes that belong to the loop determined by (latchNode, head) and
* determines the type of loop. */
static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &intNodes)
{
int i, headDfsNum, intNodeType;
nodeList loopNodes;
int immedDom, /* dfsLast index to immediate dominator */
thenDfs, elseDfs; /* dsfLast index for THEN and ELSE nodes */
BB * pbb;
/* Flag nodes in loop headed by head (except header node) */
headDfsNum = head->dfsLastNum;
head->loopHead = headDfsNum;
insertList (loopNodes, headDfsNum);
for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++)
{
if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */
continue;
immedDom = pProc->m_dfsLast[i]->immedDom;
if (inList (loopNodes, immedDom) and inInt(pProc->m_dfsLast[i], intNodes))
{
insertList (loopNodes, i);
if (pProc->m_dfsLast[i]->loopHead == NO_NODE)/*not in other loop*/
pProc->m_dfsLast[i]->loopHead = headDfsNum;
}
}
latchNode->loopHead = headDfsNum;
if (latchNode != head)
insertList (loopNodes, latchNode->dfsLastNum);
/* Determine type of loop and follow node */
intNodeType = head->nodeType;
if (latchNode->nodeType == TWO_BRANCH)
if ((intNodeType == TWO_BRANCH) or (latchNode == head))
if ((latchNode == head) or
(inList (loopNodes, head->edges[THEN].BBptr->dfsLastNum) and
inList (loopNodes, head->edges[ELSE].BBptr->dfsLastNum)))
{
head->loopType = eNodeHeaderType::REPEAT_TYPE;
if (latchNode->edges[0].BBptr == head)
head->loopFollow = latchNode->edges[ELSE].BBptr->dfsLastNum;
else
head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum;
latchNode->back().ll()->setFlags(JX_LOOP);
}
else
{
head->loopType = eNodeHeaderType::WHILE_TYPE;
if (inList (loopNodes, head->edges[THEN].BBptr->dfsLastNum))
head->loopFollow = head->edges[ELSE].BBptr->dfsLastNum;
else
head->loopFollow = head->edges[THEN].BBptr->dfsLastNum;
head->back().ll()->setFlags(JX_LOOP);
}
else /* head = anything besides 2-way, latch = 2-way */
{
head->loopType = eNodeHeaderType::REPEAT_TYPE;
if (latchNode->edges[THEN].BBptr == head)
head->loopFollow = latchNode->edges[ELSE].BBptr->dfsLastNum;
else
head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum;
latchNode->back().ll()->setFlags(JX_LOOP);
}
else /* latch = 1-way */
if (latchNode->nodeType == LOOP_NODE)
{
head->loopType = eNodeHeaderType::REPEAT_TYPE;
head->loopFollow = latchNode->edges[0].BBptr->dfsLastNum;
}
else if (intNodeType == TWO_BRANCH)
{
head->loopType = eNodeHeaderType::WHILE_TYPE;
pbb = latchNode;
thenDfs = head->edges[THEN].BBptr->dfsLastNum;
elseDfs = head->edges[ELSE].BBptr->dfsLastNum;
while (1)
{
if (pbb->dfsLastNum == thenDfs)
{
head->loopFollow = elseDfs;
break;
}
else if (pbb->dfsLastNum == elseDfs)
{
head->loopFollow = thenDfs;
break;
}
/* Check if couldn't find it, then it is a strangely formed
* loop, so it is safer to consider it an endless loop */
if (pbb->dfsLastNum <= head->dfsLastNum)
{
head->loopType = eNodeHeaderType::ENDLESS_TYPE;
findEndlessFollow (pProc, loopNodes, head);
break;
}
pbb = pProc->m_dfsLast[pbb->immedDom];
}
if (pbb->dfsLastNum > head->dfsLastNum)
pProc->m_dfsLast[head->loopFollow]->loopHead = NO_NODE; /*****/
head->back().ll()->setFlags(JX_LOOP);
}
else
{
head->loopType = eNodeHeaderType::ENDLESS_TYPE;
findEndlessFollow (pProc, loopNodes, head);
}
freeList(loopNodes);
}
//static void findNodesInInt (queue **intNodes, int level, interval *Ii)
/* Recursive procedure to find nodes that belong to the interval (ie. nodes
* from G1). */
static void findNodesInInt (queue &intNodes, int level, interval *Ii)
{
if (level == 1)
{
for(BB *en : Ii->nodes)
{
appendQueue(intNodes,en);
}
}
else
{
for(BB *en : Ii->nodes)
{
findNodesInInt(intNodes,level-1,en->correspInt);
}
}
}
/* Algorithm for structuring loops */
void Function::structLoops(derSeq *derivedG)
{
interval *Ii;
BB * intHead, /* interval header node */
* pred, /* predecessor node */
* latchNode;/* latching node (in case of loops) */
size_t level = 0; /* derived sequence level */
interval *initInt; /* initial interval */
queue intNodes; /* list of interval nodes */
/* Structure loops */
/* for all derived sequences Gi */
for(auto & elem : *derivedG)
{
level++;
Ii = elem.Ii;
while (Ii) /* for all intervals Ii of Gi */
{
latchNode = nullptr;
intNodes.clear();
/* Find interval head (original BB node in G1) and create
* list of nodes of interval Ii. */
initInt = Ii;
for (size_t i = 1; i < level; i++)
initInt = (*initInt->nodes.begin())->correspInt;
intHead = *initInt->nodes.begin();
/* Find nodes that belong to the interval (nodes from G1) */
findNodesInInt (intNodes, level, Ii);
/* Find greatest enclosing back edge (if any) */
for (size_t i = 0; i < intHead->inEdges.size(); i++)
{
pred = intHead->inEdges[i];
if (inInt(pred, intNodes) and isBackEdge(pred, intHead))
{
if (nullptr == latchNode)
latchNode = pred;
else if (pred->dfsLastNum > latchNode->dfsLastNum)
latchNode = pred;
}
}
/* Find nodes in the loop and the type of loop */
if (latchNode)
{
/* Check latching node is at the same nesting level of case
* statements (if any) and that the node doesn't belong to
* another loop. */
if ((latchNode->caseHead == intHead->caseHead) and
(latchNode->loopHead == NO_NODE))
{
intHead->latchNode = latchNode->dfsLastNum;
findNodesInLoop(latchNode, intHead, this, intNodes);
latchNode->flg |= IS_LATCH_NODE;
}
}
/* Next interval */
Ii = Ii->next;
}
/* Next derived sequence */
}
}
/* Returns whether the BB indexed by s is a successor of the BB indexed by
* h. Note that h is a case node. */
static bool successor (int s, int h, Function * pProc)
{
BB * header = pProc->m_dfsLast[h];
auto iter = std::find_if(header->edges.begin(),
header->edges.end(),
[s](const TYPEADR_TYPE &te)->bool{ return te.BBptr->dfsLastNum == s;});
return iter!=header->edges.end();
}
/* Recursive procedure to tag nodes that belong to the case described by
* the list l, head and tail (dfsLast index to first and exit node of the
* case). */
static void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
{
int current; /* index to current node */
pBB->traversed = DFS_CASE;
current = pBB->dfsLastNum;
if ((current != tail) and (pBB->nodeType != MULTI_BRANCH) and (inList (l, pBB->immedDom)))
{
insertList (l, current);
pBB->caseHead = head;
for(TYPEADR_TYPE &edge : pBB->edges)
{
if (edge.BBptr->traversed != DFS_CASE)
tagNodesInCase (edge.BBptr, l, head, tail);
}
}
}
/* Structures case statements. This procedure is invoked only when pProc
* has a case node. */
void Function::structCases()
{
int exitNode = NO_NODE; /* case exit node */
nodeList caseNodes; /* temporary: list of nodes in case */
/* Linear scan of the nodes in reverse dfsLast order, searching for
* case nodes */
for (int i = numBBs - 1; i >= 0; i--)
{
if ((m_dfsLast[i]->nodeType != MULTI_BRANCH))
continue;
BB * caseHeader = m_dfsLast[i];; /* case header node */
/* Find descendant node which has as immediate predecessor
* the current header node, and is not a successor. */
for (size_t j = i + 2; j < numBBs; j++)
{
if ((not successor(j, i, this)) and (m_dfsLast[j]->immedDom == i))
{
if (exitNode == NO_NODE)
{
exitNode = j;
}
else if (m_dfsLast[exitNode]->inEdges.size() < m_dfsLast[j]->inEdges.size())
exitNode = j;
}
}
m_dfsLast[i]->caseTail = exitNode;
/* Tag nodes that belong to the case by recording the
* header field with caseHeader. */
insertList (caseNodes, i);
m_dfsLast[i]->caseHead = i;
for(TYPEADR_TYPE &pb : caseHeader->edges)
{
tagNodesInCase(pb.BBptr, caseNodes, i, exitNode);
}
//for (j = 0; j < caseHeader->edges[j]; j++)
// tagNodesInCase (caseHeader->edges[j].BBptr, caseNodes, i, exitNode);
if (exitNode != NO_NODE)
m_dfsLast[exitNode]->caseHead = i;
}
}
/* Flags all nodes in the list l as having follow node f, and deletes all
* nodes from the list. */
static void flagNodes (nodeList &l, int f, Function * pProc)
{
nodeList::iterator p;
for(int idx : l)
{
pProc->m_dfsLast[idx]->ifFollow = f;
}
l.clear();
}
/* Structures if statements */
void Function::structIfs ()
{
size_t followInEdges; /* Largest # in-edges so far */
int curr, /* Index for linear scan of nodes */
/*desc,*/ /* Index for descendant */
follow; /* Possible follow node */
nodeList domDesc, /* List of nodes dominated by curr */
unresolved /* List of unresolved if nodes */
;
BB * currNode, /* Pointer to current node */
* pbb;
/* Linear scan of nodes in reverse dfsLast order */
for (curr = numBBs - 1; curr >= 0; curr--)
{
currNode = m_dfsLast[curr];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue;
if ((currNode->nodeType == TWO_BRANCH) and (not currNode->back().ll()->testFlags(JX_LOOP)))
{
followInEdges = 0;
follow = 0;
/* Find all nodes that have this node as immediate dominator */
for (size_t desc = curr+1; desc < numBBs; desc++)
{
if (m_dfsLast[desc]->immedDom == curr)
{
insertList (domDesc, desc);
pbb = m_dfsLast[desc];
if ((pbb->inEdges.size() - pbb->numBackEdges) >= followInEdges)
{
follow = desc;
followInEdges = pbb->inEdges.size() - pbb->numBackEdges;
}
}
}
/* Determine follow according to number of descendants
* immediately dominated by this node */
if ((follow != 0) and (followInEdges > 1))
{
currNode->ifFollow = follow;
if (not unresolved.empty())
flagNodes (unresolved, follow, this);
}
else
insertList (unresolved, curr);
}
freeList (domDesc);
}
}
bool Function::removeInEdge_Flag_and_ProcessLatch(BB *pbb,BB *a,BB *b)
{
/* Remove in-edge e to t */
auto iter = std::find(b->inEdges.begin(),b->inEdges.end(),a);
assert(iter!=b->inEdges.end());
b->inEdges.erase(iter); /* looses 1 arc */
a->flg |= INVALID_BB;
if (pbb->flg & IS_LATCH_NODE)
this->m_dfsLast[a->dfsLastNum] = pbb;
else
return true; /* to repeat this analysis */
return false;
}
void Function::replaceInEdge(BB* where, BB* which,BB* with)
{
auto iter=std::find(where->inEdges.begin(),where->inEdges.end(),which);
assert(iter!=where->inEdges.end());
*iter=with;
}
bool Function::Case_notX_or_Y(BB* pbb, BB* thenBB, BB* elseBB)
{
HLTYPE &hl1(*pbb->back().hlU());
HLTYPE &hl2(*thenBB->back().hlU());
BB* obb = elseBB->edges[THEN].BBptr;
/* Construct compound DBL_OR expression */
hl1.replaceExpr(hl1.expr()->inverse());
hl1.expr(BinaryOperator::Create(DBL_OR,hl1.expr(), hl2.expr()));
/* Replace in-edge to obb from e to pbb */
replaceInEdge(obb,elseBB,pbb);
/* New THEN and ELSE out-edges of pbb */
pbb->edges[THEN].BBptr = obb;
pbb->edges[ELSE].BBptr = thenBB;
/* Remove in-edge e to t */
return removeInEdge_Flag_and_ProcessLatch(pbb,elseBB,thenBB);
}
bool Function::Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB)
{
HLTYPE &hl1(*pbb->back().hlU());
HLTYPE &hl2(*thenBB->back().hlU());
BB* obb = elseBB->edges[ELSE].BBptr;
Expr * hl2_expr = hl2.getMyExpr();
/* Construct compound DBL_AND expression */
assert(hl1.expr());
assert(hl2_expr);
hl1.expr(BinaryOperator::Create(DBL_AND,hl1.expr(),hl2_expr));
/* Replace in-edge to obb from e to pbb */
replaceInEdge(obb,elseBB,pbb);
/* New ELSE out-edge of pbb */
pbb->edges[ELSE].BBptr = obb;
/* Remove in-edge e to t */
return removeInEdge_Flag_and_ProcessLatch(pbb,elseBB,thenBB);
}
bool Function::Case_notX_and_Y(BB* pbb, BB* thenBB, BB* elseBB)
{
HLTYPE &hl1(*pbb->back().hlU());
HLTYPE &hl2(*thenBB->back().hlU());
BB* obb = thenBB->edges[ELSE].BBptr;
/* Construct compound DBL_AND expression */
hl1.replaceExpr(hl1.expr()->inverse());
hl1.expr(BinaryOperator::LogicAnd(hl1.expr(), hl2.expr()));
/* Replace in-edge to obb from t to pbb */
replaceInEdge(obb,thenBB,pbb);
/* New THEN and ELSE out-edges of pbb */
pbb->edges[THEN].BBptr = elseBB;
pbb->edges[ELSE].BBptr = obb;
/* Remove in-edge t to e */
return removeInEdge_Flag_and_ProcessLatch(pbb,thenBB,elseBB);
}
bool Function::Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB)
{
HLTYPE &hl1(*pbb->back().hlU());
HLTYPE &hl2(*thenBB->back().hlU());
BB * obb = thenBB->edges[THEN].BBptr;
/* Construct compound DBL_OR expression */
hl1.expr(BinaryOperator::LogicOr(hl1.expr(), hl2.expr()));
/* Replace in-edge to obb from t to pbb */
auto iter=find(obb->inEdges.begin(),obb->inEdges.end(),thenBB);
if(iter!=obb->inEdges.end())
*iter = pbb;
/* New THEN out-edge of pbb */
pbb->edges[THEN].BBptr = obb;
/* Remove in-edge t to e */
return removeInEdge_Flag_and_ProcessLatch(pbb,thenBB,elseBB);
}
/** \brief Checks for compound conditions of basic blocks that have only 1 high
* level instruction. Whenever these blocks are found, they are merged
* into one block with the appropriate condition */
void Function::compoundCond()
{
BB * pbb, * thenBB, * elseBB;
bool change = true;
while (change)
{
change = false;
/* Traverse nodes in postorder, this way, the header node of a
* compound condition is analysed first */
for (size_t i = 0; i < this->numBBs; i++)
{
pbb = this->m_dfsLast[i];
if (pbb->flg & INVALID_BB)
continue;
if (pbb->nodeType != TWO_BRANCH)
continue;
thenBB = pbb->edges[THEN].BBptr;
elseBB = pbb->edges[ELSE].BBptr;
change = true; //assume change
/* Check (X or Y) case */
if ((thenBB->nodeType == TWO_BRANCH) and (thenBB->numHlIcodes == 1) and
(thenBB->inEdges.size() == 1) and (thenBB->edges[ELSE].BBptr == elseBB))
{
if(Case_X_or_Y(pbb, thenBB, elseBB))
--i;
}
/* Check (not X and Y) case */
else if ((thenBB->nodeType == TWO_BRANCH) and (thenBB->numHlIcodes == 1) and
(thenBB->inEdges.size() == 1) and (thenBB->edges[THEN].BBptr == elseBB))
{
if(Case_notX_and_Y(pbb, thenBB, elseBB))
--i;
}
/* Check (X and Y) case */
else if ((elseBB->nodeType == TWO_BRANCH) and (elseBB->numHlIcodes == 1) and
(elseBB->inEdges.size()==1) and (elseBB->edges[THEN].BBptr == thenBB))
{
if(Case_X_and_Y(pbb, thenBB, elseBB ))
--i;
}
/* Check (not X or Y) case */
else if ((elseBB->nodeType == TWO_BRANCH) and (elseBB->numHlIcodes == 1) and
(elseBB->inEdges.size() == 1) and (elseBB->edges[ELSE].BBptr == thenBB))
{
if(Case_notX_or_Y(pbb, thenBB, elseBB ))
--i;
}
else
change = false; // otherwise we changed nothing
}
}
}
/* Structuring algorithm to find the structures of the graph pProc->cfg */
void Function::structure(derSeq *derivedG)
{
/* Find immediate dominators of the graph */
findImmedDom();
if (hasCase)
structCases();
structLoops(derivedG);
structIfs();
}