blob: e98ac6d19207087ae3cf4c0f44ea003601a8d4c9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Intel, Mikhail Y. Fursov
*
*/
#include "ControlFlowGraph.h"
#include "LoopTree.h" //required for edge profile smoothing
#include <algorithm>
namespace Jitrino {
//////////////////////////////////////////////////////////////////////////
// ControlFlowGraphFactory methods
Node* ControlFlowGraphFactory::createNode(MemoryManager& mm, Node::Kind kind) {
return new (mm) Node(mm, kind);
}
Edge* ControlFlowGraphFactory::createEdge(MemoryManager& mm, Node::Kind srcKind, Node::Kind dstKind) {
return new (mm) Edge();
}
//////////////////////////////////////////////////////////////////////////
// Edge methods
Edge::Kind Edge::getKind() const {
Edge::Kind kind = Edge::Kind_Unconditional;
if (source->isBlockNode()) {
if (target->isBlockNode()) {
if (source->getOutDegree() > 1) {
CFGInst* inst = source->getLastInst();
if (inst!=NULL) {
kind = inst->getEdgeKind(this);
} else { //empty node with dispatch and unconditional edges. B->B edge is unconditional
#ifdef _DEBUG //do some checks
assert(source->getOutDegree() == 2);
const Edges& outEdges = source->getOutEdges();
Edge* secondEdge = outEdges.front() == this ? outEdges.back() : outEdges.front();
assert(secondEdge->getTargetNode()->isDispatchNode());
#endif
//edge kind stays unconditional
}
}
} else if (target->isDispatchNode()) {
kind = Edge::Kind_Dispatch;
} else {
assert(target->isExitNode());//kind is unconditional
}
} else {
assert(source->isDispatchNode());
if (target->isDispatchNode() || target->isExitNode()) {
kind = Edge::Kind_Dispatch;
} else {
assert(target->isBlockNode());
kind = Edge::Kind_Catch;
}
}
return kind;
}
//////////////////////////////////////////////////////////////////////////
// Node methods
class HeadInst : public CFGInst {
public:
HeadInst(Node* _node) {node = _node;}
// must never be called on head inst
virtual Edge::Kind getEdgeKind(const Edge* edge) const {assert(false); return Edge::Kind_Unconditional;}
};
Node::Node(MemoryManager& mm, Kind _kind)
: id(MAX_UINT32), dfNumber(0), preNumber(0), postNumber(0), traversalNumber(0),
kind(_kind), inEdges(mm), outEdges(mm), instsHead(NULL), execCount(0)
{
instsHead = new (mm) HeadInst(this);
}
Edge* Node::getOutEdge(Edge::Kind edgeKind) const {
for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
if (edge->getKind() == edgeKind) {
return edge;
}
}
return NULL;
}
Edge* Node::findEdge(bool isForward, const Node* node) const {
const Edges& edges = getEdges(isForward);
for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
if (edge->getNode(isForward) == node) {
return edge;
}
}
return NULL;
}
// appends inst to the end of node list.
void Node::appendInst(CFGInst* newInst, CFGInst* instAfter) {
if (instAfter==NULL) {
newInst->insertBefore(instsHead);
} else {
assert(instAfter->getNode() == this);
newInst->insertAfter(instAfter);
}
}
// appends inst to the beginning of node list. Checks "block header critical inst" property
void Node::prependInst(CFGInst* newInst, CFGInst* instBefore) {
if (instBefore==NULL) {
instBefore = instsHead;
for (CFGInst* inst = getFirstInst(); inst!=NULL; inst = inst->next()) {
if (inst->isLabel()) {
continue;
}
if (newInst->isHeaderCriticalInst() || !inst->isHeaderCriticalInst()) {
instBefore = inst;
break;
}
}
}
assert(instBefore->getNode() == this);
newInst->insertBefore(instBefore);
}
void Node::insertInst(CFGInst* prev, CFGInst* newInst) {
#ifdef _DEBUG
assert(newInst->getNode() == NULL);
if (newInst->isHeaderCriticalInst()) { //check prev inst is also critical
if (prev != instsHead) { //check only if newInst will not be the first
CFGInst* prevInst = (CFGInst*)prev;
assert(prevInst->isHeaderCriticalInst());
assert(!newInst->isLabel()); //label must be the first
}
} else { //check next inst is not critical
Dlink* nextLink = prev->getNext();
if (nextLink!=instsHead) {//check only if newInst will not be the last
CFGInst* nextInst = (CFGInst*)nextLink;
assert(!nextInst->isHeaderCriticalInst());
}
}
#endif
((Dlink*)newInst)->insertAfter(prev);
newInst->node = this;
}
U_32 Node::getInstCount(bool ignoreLabels) const {
U_32 count = 0;
CFGInst* first = getFirstInst();
while (ignoreLabels && first!=NULL && first->isLabel()) {
first = first->next();
}
for (CFGInst* inst = first; inst!=NULL; inst = inst->next()) {
count++;
}
return count;
}
Edge* Node::findEdgeTo(bool isForward, Node* node) const {
const Edges& edges = getEdges(isForward);
for (Edges::const_iterator ite = edges.begin(), ende = edges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
if (edge->getNode(isForward) == node) {
return edge;
}
}
return NULL;
}
uint16 Node::getNodeStartBCOffset() const {
if (!isBlockNode()) {
return ILLEGAL_BC_MAPPING_VALUE;
}
CFGInst* inst = getFirstInst();
while (inst!=NULL && inst->getBCOffset()==ILLEGAL_BC_MAPPING_VALUE) {
inst = inst->next();
}
return inst==NULL ? ILLEGAL_BC_MAPPING_VALUE : inst->getBCOffset();
}
uint16 Node::getNodeEndBCOffset() const {
if (!isBlockNode()) {
return ILLEGAL_BC_MAPPING_VALUE;
}
CFGInst* inst = getLastInst();
while (inst!=NULL && inst->getBCOffset()==ILLEGAL_BC_MAPPING_VALUE) {
inst = inst->prev();
}
return inst==NULL ? ILLEGAL_BC_MAPPING_VALUE : inst->getBCOffset();
}
//////////////////////////////////////////////////////////////////////////
// CFG methods
ControlFlowGraph::ControlFlowGraph(MemoryManager& _mm, ControlFlowGraphFactory* _factory)
: mm (_mm), factory(_factory), entryNode (NULL), returnNode(NULL), exitNode(NULL), unwindNode(NULL),
nodes(_mm), postOrderCache(_mm), nodeIDGenerator(0), edgeIDGenerator(0), nodeCount(0),
traversalNumber(0), lastModifiedTraversalNumber(0), lastOrderingTraversalNumber(0),
lastEdgeRemovalTraversalNumber(0), lastProfileUpdateTraversalNumber(0), currentPreNumber(0), currentPostNumber(0),
annotatedWithEdgeProfile(false), domTree(NULL), postDomTree(NULL), loopTree(NULL)
{
if (factory == NULL) { //use default factory
factory = new (mm) ControlFlowGraphFactory();
}
}
Node* ControlFlowGraph::createNode(Node::Kind kind, CFGInst* inst) {
Node* node = factory->createNode(mm, kind);
addNode(node);
if (inst!=NULL) {
node->appendInst(inst);
}
return node;
}
void ControlFlowGraph::removeNode(Node* node) {
removeNode(std::find(nodes.begin(), nodes.end(), node), true);
}
void ControlFlowGraph::removeNode(Nodes::iterator pos, bool erase) {
Node* node = *pos;
if (node == entryNode) {
entryNode=NULL;
}
if (node == returnNode) {
returnNode = NULL;
} else if(node == unwindNode) {
unwindNode = NULL;
} else if (node == exitNode) {
exitNode = NULL;
}
// Remove incident edges
while (!node->inEdges.empty()) {
Edge* edge = node->inEdges.front();
assert(edge->getTargetNode() == node);
removeEdge(edge);
}
while (!node->outEdges.empty()) {
Edge* edge = node->outEdges.front();
assert(edge->getSourceNode() == node);
removeEdge(edge);
}
// Erase the node itself
if (erase) {
*pos = *nodes.rbegin();
nodes.pop_back();
} else {
*pos = NULL;
}
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
}
Edge* ControlFlowGraph::addEdge(Node* source, Node* target, double edgeProb) {
assert(target!=entryNode);
assert(source!=exitNode);
assert (source->findTargetEdge(target) == NULL);
Edge* edge = factory->createEdge(mm, source->getKind(), target->getKind());
addEdge(source, target, edge, edgeProb);
return edge;
}
void ControlFlowGraph::addEdge(Node* source, Node* target, Edge* edge, double edgeProb) {
// Set ID
edge->setId(edgeIDGenerator);
edgeIDGenerator++;
// Out edge for source node
edge->source = source;
source->outEdges.push_back(edge);
// In edge for target node
edge->target = target;
target->inEdges.push_back(edge);
edge->setEdgeProb(edgeProb);
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
}
void ControlFlowGraph::removeEdge(Edge* edge) {
// Remove out edge from source node
Node* source = edge->getSourceNode();
Edges& outEdges = source->outEdges;
outEdges.erase(std::remove(outEdges.begin(), outEdges.end(), edge));
// Remove in edge from target node
Node* target = edge->getTargetNode();
Edges& inEdges = target->inEdges;
inEdges.erase(std::remove(inEdges.begin(), inEdges.end(), edge));
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
lastEdgeRemovalTraversalNumber = traversalNumber;
}
Edge* ControlFlowGraph::replaceEdgeTarget(Edge* edge, Node* newTarget, bool keepOldBody) {
Node* source = edge->getSourceNode();
Node* oldTarget = edge->getTargetNode();
CFGInst* lastInst = source->getLastInst();
Edge* newEdge = NULL;
if (keepOldBody) {
edge->target = newTarget;
newTarget->inEdges.push_back(edge);
Edges& oldInEdges = oldTarget->inEdges;
oldInEdges.erase(std::remove(oldInEdges.begin(), oldInEdges.end(), edge));
newEdge = edge;
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
} else {
removeEdge(edge);
newEdge = addEdge(source, newTarget);
}
if (lastInst!=NULL) {
lastInst->updateControlTransferInst(oldTarget, newTarget);
}
return newEdge;
}
#define PROFILE_ERROR_ALLOWED 0.000000001
#define ABS(a) (((a) > (0)) ? (a) : -(a))
// Check the profile consistency of the CFG.
// Return true if the profile is consistent. Otherwise, return false.
bool ControlFlowGraph::isEdgeProfileConsistent(bool checkEdgeProbs, bool checkExecCounts, bool doAssertForClient) {
assert(hasEdgeProfile());
bool profileIsUptodate= lastProfileUpdateTraversalNumber > getModificationTraversalNum();
#ifndef _DEBUG
if (profileIsUptodate) {
return true;
}
#else
//do self test in debug version
bool doAssert = profileIsUptodate || doAssertForClient;
#endif
const Nodes& postOrdered = getNodesPostOrder();
for (Nodes::const_iterator it = postOrdered.begin(), end = postOrdered.end(); it!=end; ++it) {
Node* node = *it;
if (checkEdgeProbs) {
const Edges& outEdges = node->getOutEdges();
if (!outEdges.empty()) {
double probSum = 0;
for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
double prob = edge->getEdgeProb();
if (prob <= 0 || prob > 1) {
assert(doAssert?false:true);
return false;
}
probSum+=prob;
}
if (ABS(probSum-1) > PROFILE_ERROR_ALLOWED) {
assert(doAssert?false:true);
return false;
}
}
}
if (checkExecCounts) {
const Edges& inEdges = node->getInEdges();
bool hasInfiniteLoops = false;
if (!inEdges.empty()) {
double freqSum = 0;
for (Edges::const_iterator ite = inEdges.begin(), ende = inEdges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
Node* sourceNode = edge->getSourceNode();
double freq = edge->getEdgeProb() * sourceNode->getExecCount();
if (sourceNode->getTraversalNum()!=node->getTraversalNum()) {
freq = 0;
}
if (freq <=0) {
assert(doAssert?false:true);
return false;
}
freqSum+=freq;
}
if (freqSum <=0 ) {
assert(doAssert?false:true);
return false;
}
double nodeFreq = node->getExecCount();
if (nodeFreq > 1/PROFILE_ERROR_ALLOWED) {
hasInfiniteLoops = true;
} else if (ABS(nodeFreq / freqSum - 1) >= PROFILE_ERROR_ALLOWED) {
assert(doAssert?false:true);
return false;
}
}
if (!hasInfiniteLoops && exitNode!=NULL) {
double exitFreq = exitNode->getExecCount();
double entryFreq = entryNode->getExecCount();
bool ok = ABS(exitFreq - entryFreq) < PROFILE_ERROR_ALLOWED * entryFreq;
if (!ok) {
assert(doAssert ? false : true);
return false;
}
}
}
}
if (!profileIsUptodate && checkEdgeProbs && checkExecCounts) {
lastProfileUpdateTraversalNumber = getTraversalNum();
}
return true;
}
// this utility splits a node at a particular instruction, leaving the instruction in the
// same node and moving all insts (before inst : splitAfter=false/after inst : splitAfter=true
// to the newly created node
// returns the new node created
Node* ControlFlowGraph::splitNodeAtInstruction(CFGInst *inst, bool splitAfter, bool keepDispatch, CFGInst* labelInst) {
Node *node = inst->getNode();
Node* dispatchNode = keepDispatch ? node->getExceptionEdgeTarget() : NULL;
Node* newNode = splitNode(node, true, labelInst);
if (inst == node->getLastInst()) {
assert(!splitAfter || (node->getOutDegree() == 1 && node->getUnconditionalEdge()!=NULL)
|| (node->getOutDegree()==2 && node->getExceptionEdgeTarget()!=NULL));
}
//keeping dispatch node is useful for extended basis blocks
if (keepDispatch && dispatchNode!=NULL) {
assert(node->getExceptionEdgeTarget() == NULL);
addEdge(node, dispatchNode, 0);
}
// now move the instructions
for (CFGInst *ins = splitAfter ? inst->next() : inst; ins != NULL; ) {
CFGInst *nextins = ins->next();
ins->unlink();
newNode->appendInst(ins);
ins = nextins;
}
newNode->setExecCount(node->getExecCount());
node->findTargetEdge(newNode)->setEdgeProb(1.0);
return newNode;
}
// Splice a new empty block on the CFG edge.
Node* ControlFlowGraph::spliceBlockOnEdge(Edge* edge, CFGInst* inst, bool keepOldEdge) {
Node* source = edge->getSourceNode();
double edgeProb = edge->getEdgeProb();
double edgeFreq = source->getExecCount()*edgeProb;
// Split the edge
Node* split = splitEdge(edge, inst, keepOldEdge);
split->setExecCount(edgeFreq);
// Set the incoming edge probability
assert(split->getInDegree() == 1);
split->getInEdges().front()->setEdgeProb(edgeProb);
// Set the outgoing edge probability
assert(split->getOutDegree() == 1);
split->getOutEdges().front()->setEdgeProb(1.0);
return split;
}
void ControlFlowGraph::splitCriticalEdges(bool includeExceptionEdges, Nodes* newNodes) {
// go backwards through collection so appending won't hurt us.
Nodes::reverse_iterator iter = nodes.rbegin(), end = nodes.rend();
for (int idx = (int)nodes.size(); --idx<=0;) {
Node* target = nodes[idx];
// exception edges go to a dispatch node.
// only look at nodes with multiple in edges.
if (target->isDispatchNode() || includeExceptionEdges) {
restart:
if (target->getInDegree() > 1) {
Edges& inEdges = target->inEdges;
Edges::iterator iterEdge = inEdges.begin(), endEdge = inEdges.end();
for (; iterEdge != endEdge; ++iterEdge) {
Edge* thisEdge = *iterEdge;
Node* source = thisEdge->getSourceNode();
if ((source->getOutDegree() > 1) && (includeExceptionEdges || !source->isDispatchNode())) {
// it's a critical edge, split it
Node* newNode = splitEdge(thisEdge, NULL, false); //TODO: keep old edge?
if (newNodes) {
newNodes->push_back(newNode);
}
goto restart;
}
}
}
}
}
}
bool ControlFlowGraph::isBlockMergeAllowed(Node* source, Node* target, bool allowMergeDispatch) const {
assert(source->isBlockNode() && target->isBlockNode());
if (target == returnNode) {
return false;
}
if (source->getUnconditionalEdgeTarget()!=target) {
return false;
}
if (target->getInDegree()!=1 || source->getOutDegree() > 2) {
return false;
}
Node* sourceDispatch = source->getExceptionEdgeTarget();
Node* targetDispatch = target->getExceptionEdgeTarget();
//check if there is no problem with header critical insts
if (source->getLastInst()!=NULL && !source->getLastInst()->isHeaderCriticalInst()) {
//we can't allow target to have critical insts except label
CFGInst* inst = target->getFirstInst();
inst = inst!=NULL?(inst->isLabel() ? inst->next() : inst) : NULL;
if (inst!=NULL && inst->isHeaderCriticalInst()) {
return false;
}
}
if (source->getOutDegree() == 2 && sourceDispatch == 0) {
return false; // 2 uncond edges, e.g. indirect jumps
}
if (!allowMergeDispatch) {
return sourceDispatch==NULL && targetDispatch==NULL;
}
bool allowMergeByDispatch = sourceDispatch == targetDispatch
|| (sourceDispatch == unwindNode && targetDispatch == NULL)
|| (sourceDispatch == NULL && targetDispatch == unwindNode);
return allowMergeByDispatch;
}
void ControlFlowGraph::mergeBlocks(Node* source, Node* target, bool keepFirst) {
assert(isBlockMergeAllowed(source, target, true));
Edge* edge = target->inEdges.front();
assert(edge->getSourceNode() == source);
removeEdge(edge);
if(keepFirst) {
// Merge second block into first
moveInstructions(target, source, false);
moveOutEdges(target, source);
removeNode(target);
} else {
// Merge first block into second
moveInstructions(source, target, true);
moveInEdges(source, target);
removeNode(source);
}
}
void ControlFlowGraph::mergeAdjacentNodes(bool skipEntry, bool mergeByDispatch) {
for(U_32 idx = 0; idx < nodes.size(); idx++) {
Node* node = nodes[idx];
if (node->isBlockNode() && (!skipEntry || node!=entryNode)) {
Node* succ = node->getUnconditionalEdgeTarget();
if (succ!=NULL && succ->getInDegree() == 1 && !succ->isExitNode()) {
if (isBlockMergeAllowed(node, succ, mergeByDispatch)){
mergeBlocks(node, succ);
idx--;
}
}
} else if (node->isDispatchNode()) {
if (node->getOutDegree() == 1 && node->isEmpty()) {
Node* succ = node->getOutEdges().front()->getTargetNode();
if (succ->isDispatchNode()) {
// This dispatch has no handlers.
// Forward edges to this dispatch node to the successor.
moveInstructions(node, succ, true);
moveInEdges(node, succ);
removeNode(nodes.begin() + idx, true);
idx--;
}
}
}
}
}
void ControlFlowGraph::purgeEmptyNodes(bool preserveCriticalEdges, bool removeEmptyCatchBlocks) {
for(Nodes::iterator it = nodes.begin(),end = nodes.end(); it != end; ++it) {
Node* node = *it;
if(node->isBlockNode() && node->isEmpty()) {
// Preserve entry node
if(node == getEntryNode() || node == getReturnNode() || (!removeEmptyCatchBlocks && node->isCatchBlock())) {
continue;
}
// Node must have one unconditional successor if it is empty.
assert(node->getOutDegree() == 1 || (node->getOutDegree()==2 && node->getExceptionEdge()!=NULL));
Node* succ = node->getUnconditionalEdgeTarget();
assert(succ->isBlockNode() || (succ->isExitNode() && getReturnNode() == NULL)); //cfg without special support for return node...
if(succ == node) {
// This is an empty infinite loop.
continue;
}
// Preserve this node if it breaks a critical edge if requested.
bool preserve = false;
if(preserveCriticalEdges && succ->getInDegree() > 1) {
// Preserve this block if any predecessors have multiple out edges.
Edges::const_iterator eiter;
for(eiter = node->getInEdges().begin(); !preserve && eiter != node->getInEdges().end(); ++eiter) {
if((*eiter)->getSourceNode()->getOutDegree() > 1)
// This node breaks a critical edge.
preserve = true;
}
}
if(!preserve) {
moveInEdges(node, succ);
removeNode(it, false);
}
}
}
nodes.erase(std::remove(nodes.begin(), nodes.end(), (Node*)NULL), nodes.end());
}
void ControlFlowGraph::addNode(Node* node) {
// Set ID
node->setId(nodeIDGenerator);
nodeIDGenerator++;
// Add node
nodes.push_back(node);
// Reset node traversal number
node->traversalNumber = 0;
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
}
// Splice inlineFG into this CFG.
void ControlFlowGraph::spliceFlowGraphInline(Edge* edge, ControlFlowGraph& inlineFG) {
assert(!edge->isDispatchEdge() && !edge->isCatchEdge());
Node* nodeBeforeEntry = edge->getSourceNode();
Node* nodeAfterReturn = edge->getTargetNode();
Node* dispatchNode = nodeBeforeEntry->getExceptionEdgeTarget();
Node* inlineEntryNode = inlineFG.getEntryNode();
Node* inlineReturnNode = inlineFG.getReturnNode();
Node* inlineUnwindNode = inlineFG.getUnwindNode();
Node* inlineExitNode = inlineFG.getExitNode();
bool returnSeen = false;
bool unwindSeen = false;
// Add nodes to CFG
assert(&getMemoryManager() == &inlineFG.getMemoryManager());
const Nodes& inlineNodes = inlineFG.getNodes();
for(Nodes::const_iterator i = inlineNodes.begin(), end = inlineNodes.end(); i != end; ++i) {
Node* n = *i;
if (n != inlineExitNode) {
addNode(n);
const Edges& oEdges = n->getOutEdges();
Edges::const_iterator e;
for(e = oEdges.begin(); e != oEdges.end(); ++e) {
setNewEdgeId(*e);
}
if (n == inlineReturnNode) {
returnSeen = true;
} else if (n == inlineUnwindNode) {
unwindSeen = true;
}
}
}
// Connect nodes.
replaceEdgeTarget(edge, inlineEntryNode);
if(returnSeen) {
removeEdge(inlineReturnNode, inlineExitNode);
addEdge(inlineReturnNode, nodeAfterReturn, 1);
}
if(unwindSeen) {
removeEdge(inlineUnwindNode, inlineExitNode);
if (dispatchNode == NULL) {
dispatchNode = getUnwindNode();
}
assert(dispatchNode != NULL);
addEdge(inlineUnwindNode, dispatchNode, 1);
}
}
void ControlFlowGraph::spliceFlowGraphInline(CFGInst* instAfter, ControlFlowGraph& inlineFG) {
Node* node = instAfter->getNode();
Edge* edgeToInlined = NULL;
if (node->getLastInst() == instAfter) {
edgeToInlined = node->getUnconditionalEdge();
} else {//WARN: no label inst created -> possible problems if method is used in HLO
Node* newBlock = splitNodeAtInstruction(instAfter, true, false, NULL);
assert(newBlock->getInDegree() == 1);
edgeToInlined = newBlock->getInEdges().front();
}
assert(edgeToInlined!=NULL);
spliceFlowGraphInline(edgeToInlined, inlineFG);
}
void ControlFlowGraph::moveInEdges(Node* oldNode, Node* newNode) {
assert(oldNode != newNode);
assert(oldNode->getKind() == newNode->getKind() || (getReturnNode()==NULL && newNode->isExitNode()));
Edges& oldIns = oldNode->inEdges;
Edges& newIns = newNode->inEdges;
newIns.insert(newIns.begin(), oldIns.begin(), oldIns.end());
oldIns.clear();
// Reset edge pointers and update branch instructions.
resetInEdges(newNode);
assert(oldNode->getInDegree() == 0);
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
}
void
ControlFlowGraph::moveOutEdges(Node* oldNode, Node* newNode) {
assert(oldNode->getKind() == newNode->getKind());
Edges& oldOuts = oldNode->outEdges;
Edges& newOuts = newNode->outEdges;
newOuts.insert(newOuts.end(), oldOuts.begin(), oldOuts.end());
oldOuts.clear();
resetOutEdges(newNode);
assert(oldNode->getOutDegree() == 0);
// Mark the graph modified.
lastModifiedTraversalNumber = traversalNumber;
}
void ControlFlowGraph::resetInEdges(Node* node) {
Edges& edges = node->inEdges;
for(int i=(int)edges.size(); --i>=0;) {
Edge* edge = edges[i];
// The old successor; node is the new successor
Node* old = edge->getTargetNode();
if(old != node) {
Node* pred = edge->getSourceNode();
// Check if another edge already goes to node. .
bool redundant = (pred->findTargetEdge(node) != NULL);
// Set this edge to point to node. Note, we do this even if the
// edge is to be deleted. removeEdge only works if the edge
// is well-formed.
edge->target = node;
// Update control transfer instruction in source.
CFGInst* lastInst = pred->getLastInst();
if(pred->isBlockNode() && lastInst!=NULL) {
lastInst->updateControlTransferInst(old, node);
}
if(redundant) {
// Edge is redundant - eliminate.
if(pred->getOutDegree() == 2 || (pred->getOutDegree()==3 && pred->getExceptionEdge()!=NULL)) {
// Pred already has edge to node and succ, and no other successors.
// We can eliminate the branch and the edge to succ.
// Another case is branch+exception for extended form
if(pred->isBlockNode()) {
lastInst->removeRedundantBranch();
}
}
removeEdge(edge);
}
}
}
}
void ControlFlowGraph::resetOutEdges(Node* node) {
Edges& edges = node->outEdges;
for(int i=(int)edges.size(); --i>=0;) {
Edge* edge = edges[i];
// The old predecessor; node is the new predecessor
Node* old = edge->getSourceNode();
if(old != node) {
Node* succ = edge->getTargetNode();
// Check if another edge already comes from node.
bool redundant = (succ->findSourceEdge(node) != NULL);
// Set this edge to point to node. Note, we do this even if the
// edge is to be deleted. removeEdge only works if the edge
// is well-formed.
edge->source = node;
if(redundant) {
// Edge is redundant - eliminate.
removeEdge(edge);
}
}
}
}
Node* ControlFlowGraph::splitNode(Node* node, bool newBlockAtEnd, CFGInst* inst) {
assert(node->isBlockNode());
Node* newNode = createBlockNode(inst);
if(newBlockAtEnd) {
// move out edges
moveOutEdges(node, newNode);
addEdge(node, newNode);
} else { // new block at beginning
// move in edges
moveInEdges(node, newNode);
addEdge(newNode, node);
}
return newNode;
}
Node* ControlFlowGraph::splitEdge(Edge *edge, CFGInst* inst, bool keepOldEdge) {
Node* target = edge->getTargetNode();
Node* newNode = createBlockNode(inst);
if (inst!=NULL && target->getFirstInst()!=NULL) {
inst->setBCOffset(target->getFirstInst()->getBCOffset());
}
replaceEdgeTarget(edge, newNode, keepOldEdge);
addEdge(newNode, target);
return newNode;
}
void ControlFlowGraph::moveInstructions(Node* fromNode, Node* toNode, bool prepend) {
CFGInst* to = prepend ? toNode->getFirstInst() : toNode->getLastInst();
CFGInst *inst = fromNode->getFirstInst();
if (inst!=NULL && inst->isLabel()) { //skip block label if exists
inst = inst->next();
}
for (; inst != NULL; ) {
CFGInst *next = inst->next();
inst->unlink();
if (to == NULL) {
if (prepend) {
toNode->prependInst(inst);
} else {
toNode->appendInst(inst);
}
} else {
inst->insertAfter(to);
}
to = inst;
assert(prepend || to == toNode->getLastInst());
inst = next;
}
}
class CountFreqsAlgorithm {
public:
CountFreqsAlgorithm(MemoryManager& _mm, ControlFlowGraph* _fg) :
mm(_mm), fg(_fg), loopTree(fg->getLoopTree()),
useCyclicFreqs(false), cyclicFreqs(NULL), exitEdges(mm)
{
if (!loopTree->isValid()) {
loopTree->rebuild(false);
}
U_32 nNodes = fg->getNodeCount();
cyclicFreqs = new (mm) double[nNodes];
std::fill(cyclicFreqs, cyclicFreqs + nNodes, 1);
}
void estimate() {
smoothLinearFrequencies();
LoopNode* topLevelLoops = (LoopNode*)loopTree->getRoot();
if (topLevelLoops->getChild()!=NULL) { //if there are loops in method
useCyclicFreqs = true;
for (LoopNode* loopHead = topLevelLoops->getChild(); loopHead!=NULL; loopHead = loopHead->getSiblings()) {
estimateCyclicFrequencies(loopHead);
}
smoothLinearFrequencies();
}
}
void smoothLinearFrequencies() {
const Nodes& nodes = fg->getNodesPostOrder();
for (Nodes::const_reverse_iterator it = nodes.rbegin(), end = nodes.rend(); it!=end; ++it) {
Node* node = *it;
const Edges& inEdges = node->getInEdges();
if (inEdges.empty()) {
//node is entry, do nothing
assert (node == fg->getEntryNode());
continue;
}
double freq = 0.0;
for(Edges::const_iterator it = inEdges.begin(), itEnd = inEdges.end(); it!=itEnd; it++) {
Edge* edge = *it;
if (loopTree->isBackEdge(edge)) {
continue; //only linear freq estimation
}
Node* fromNode = edge->getSourceNode();
if (fromNode->getTraversalNum()!=node->getTraversalNum()) {
continue;//unreachable source node
}
double fromFreq = fromNode->getExecCount();
freq += fromFreq * edge->getEdgeProb();
}
if (useCyclicFreqs && loopTree->isLoopHeader(node)) {
freq *= cyclicFreqs[node->getDfNum()];
}
node->setExecCount(freq);
}
}
void estimateCyclicFrequencies(LoopNode* loopHead) {
//process all child loops first
bool hasChildLoop = loopHead->getChild()!=NULL;
if (hasChildLoop) {
for (LoopNode* childHead = loopHead->getChild(); childHead!=NULL; childHead = childHead->getSiblings()) {
estimateCyclicFrequencies(childHead);
}
}
findLoopExits(loopHead);
if (hasChildLoop) {
smoothLinearFrequencies();
}
Node* cfgLoopHead = loopHead->getHeader();
double inFlow = cfgLoopHead->getExecCount(); //node has linear freq here
double exitsFlow = 0;
//sum all exits flow
for (Edges::const_iterator it = exitEdges.begin(), end = exitEdges.end(); it!=end; ++it) {
Edge* edge = *it;
Node* fromNode = edge->getSourceNode();
exitsFlow += edge->getEdgeProb() * fromNode->getExecCount();
}
// if loop will make multiple iteration exitsFlow becomes equals to inFlow
double loopCycles = inFlow / exitsFlow;
if (loopCycles < 1) {
assert(ABS(inFlow-exitsFlow) < PROFILE_ERROR_ALLOWED);
loopCycles = 1;
}
cyclicFreqs[cfgLoopHead->getDfNum()] = loopCycles;
}
void findLoopExits(LoopNode* loop) {
exitEdges.clear();
const Nodes& nodes = loop->getNodesInLoop();
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
const Edges& outEdges = node->getOutEdges();
for(Edges::const_iterator eit = outEdges.begin(), eend = outEdges.end(); eit!=eend; ++eit) {
Edge* edge = *eit;
if (loop->isLoopExit(edge)) {
exitEdges.push_back(edge);
}
}
}
}
private:
MemoryManager& mm;
ControlFlowGraph* fg;
LoopTree* loopTree;
bool useCyclicFreqs;
double* cyclicFreqs;
Edges exitEdges;
};
//count node exec count from probs
void ControlFlowGraph::smoothEdgeProfile() {
assert(isEdgeProfileConsistent(true, false, true));
if (isEdgeProfileConsistent(true, true)) {
return;
}
assert(entryNode->getExecCount()!=0);
CountFreqsAlgorithm c(mm, this);
c.estimate();
lastProfileUpdateTraversalNumber = traversalNumber;
assert(isEdgeProfileConsistent(true, true, true));
}
//////////////////////////////////////////////////////////////////////////
/// CFGInst methods
CFGInst* CFGInst::next() const {
CFGInst* next = (CFGInst*)getNext();
return (node!=NULL && next == node->instsHead) ? NULL : next;
}
CFGInst* CFGInst::prev() const {
CFGInst* prev = (CFGInst*)getPrev();
return (node!=NULL && prev == node->instsHead) ? NULL : prev;
}
void CFGInst::insertBefore(CFGInst* inst) {
assert(node == NULL);
CFGInst* nextInst = next();
unlink();
Node* newNode = inst->getNode();
if (newNode!= NULL) {
newNode->insertInst((CFGInst*)inst->getPrev(), this);
} else {
((Dlink*)this)->insertBefore(inst);
}
if (nextInst!=this) {
nextInst->insertBefore(inst);
}
}
void CFGInst::insertAfter(CFGInst* inst) {
assert(node == NULL);
CFGInst* nextInst = next();
unlink();
Node* newNode = inst->getNode();
if (newNode!=NULL) {
newNode->insertInst(inst, this);
} else {
((Dlink*)this)->insertAfter(inst);
}
if (nextInst!=this) {
nextInst->insertAfter(this);
}
}
} //namespace