blob: 164aa2a30789c504c6f269d7cc9c94d260e28965 [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, Pavel A. Ozhdikhin
*
*/
#include "Log.h"
#include "tailduplicator.h"
#include "irmanager.h"
#include "Dominator.h"
#include "Loop.h"
#include "escapeanalyzer.h"
#include "FlowGraph.h"
namespace Jitrino {
DEFINE_SESSION_ACTION(RedundantBranchMergingPass, taildup, "Redundant Branch Merging/Factoring")
void
RedundantBranchMergingPass::_run(IRManager& irm) {
computeDominators(irm);
DominatorTree* dominatorTree = irm.getDominatorTree();
assert(dominatorTree->isValid());
TailDuplicator tm(irm, dominatorTree);
tm.doTailDuplication();
}
DEFINE_SESSION_ACTION(HotPathSplittingPass, hotpath, "Profile Guided Hot Path Splitting")
void
HotPathSplittingPass::_run(IRManager& irm) {
computeDominatorsAndLoops(irm);
DominatorTree* dominatorTree = irm.getDominatorTree();
LoopTree* loopTree = irm.getLoopTree();
assert(dominatorTree->isValid() && loopTree->isValid());
TailDuplicator tm(irm, dominatorTree);
tm.doProfileGuidedTailDuplication(loopTree);
}
bool
TailDuplicator::isMatchingBranch(BranchInst* br1, BranchInst* br2) {
if(br1->getComparisonModifier() != br2->getComparisonModifier())
return false;
if(br1->getNumSrcOperands() == 2 && br2->getNumSrcOperands() == 2) {
if(br1->getSrc(0) == br2->getSrc(0) && br1->getSrc(1) == br2->getSrc(1))
return true;
}
return false;
}
void
TailDuplicator::process(DefUseBuilder& defUses, DominatorNode* dnode) {
// Process children.
DominatorNode* child;
for(child = dnode->getChild(); child != NULL; child = child->getSiblings()) {
process(defUses, child);
}
Node* node = dnode->getNode();
BranchInst* branch = ((Inst*)node->getLastInst())->asBranchInst();
if(branch == NULL)
return;
// Tail duplicate redundant branches in dominated nodes.
for(child = dnode->getChild(); child != NULL; child = child->getSiblings()) {
Node* cnode = child->getNode();
BranchInst* branch2 = ((Inst*)cnode->getLastInst())->asBranchInst();
if(branch2 != NULL && node->findTargetEdge(cnode) == NULL && isMatchingBranch(branch, branch2))
tailDuplicate(defUses, node, cnode);
}
}
void
TailDuplicator::tailDuplicate(DefUseBuilder& defUses, Node* idom, Node* tail)
{
if(tail->getInDegree() != 2)
return;
Node* t1 = idom->getTrueEdge()->getTargetNode();
Node* f1 = idom->getFalseEdge()->getTargetNode();
Node* p1 = tail->getInEdges().front()->getSourceNode();
Node* p2 = tail->getInEdges().back()->getSourceNode();
Node* t2;
if(_dtree->dominates(t1, p1) && _dtree->dominates(f1, p2)) {
t2 = p1;
} else if(_dtree->dominates(t1, p2) && _dtree->dominates(f1, p1)) {
t2 = p2;
} else {
return;
}
if(Log::isEnabled()) {
Log::out() << "Tail duplicate ";
FlowGraph::printLabel(Log::out(), tail);
Log::out() << ::std::endl;
}
ControlFlowGraph& fg = _irm.getFlowGraph();
Node* copy = FlowGraph::tailDuplicate(_irm, t2, tail, defUses);
FlowGraph::foldBranch(fg, ((Inst*)copy->getLastInst())->asBranchInst(), true);
FlowGraph::foldBranch(fg, ((Inst*)tail->getLastInst())->asBranchInst(), false);
}
void
TailDuplicator::doTailDuplication() {
MemoryManager mm("TailDuplicator::doTailDuplication.mm");
ControlFlowGraph& fg = _irm.getFlowGraph();
DefUseBuilder defUses(mm);
defUses.initialize(fg);
DominatorNode* dnode = _dtree->getDominatorRoot();
process(defUses, dnode);
}
void
TailDuplicator::profileGuidedTailDuplicate(LoopTree* ltree, DefUseBuilder& defUses, Node* node) {
ControlFlowGraph& fg = _irm.getFlowGraph();
if(node->getInDegree() < 2)
// Nothing to duplicate
return;
double heatThreshold = _irm.getHeatThreshold();
double nodeCount = node->getExecCount();
Log::out() << "Try nodeCount = " << nodeCount << ::std::endl;
if(nodeCount < 0.90 * heatThreshold)
return;
const Edges& inEdges = node->getInEdges();
Node* hotPred = NULL;
Edge* hotEdge = NULL;
Edges::const_iterator j;
for(j = inEdges.begin(); j != inEdges.end(); ++j) {
Edge* edge = *j;
Node* pred = edge->getSourceNode();
if(!pred->isBlockNode()) {
hotPred = NULL;
break;
}
if(pred->getExecCount() > 0.90 * nodeCount) {
hotPred = pred;
hotEdge = edge;
}
}
if(hotPred != NULL) {
Log::out() << "Duplicate " << ::std::endl;
double hotProb = hotEdge->getEdgeProb();
double hotFreq = hotPred->getExecCount() * hotProb;
if(Log::isEnabled()) {
Log::out() << "Hot Pred = ";
FlowGraph::printLabel(Log::out(), hotPred);
Log::out() << ::std::endl;
Log::out() << "HotPredProb = " << hotProb << ::std::endl;
Log::out() << "HotPredFreq = " << hotPred->getExecCount() << ::std::endl;
Log::out() << "HotFreq = " << hotFreq << ::std::endl;
}
if(hotFreq > 1.10 * nodeCount)
assert(0);
if(hotFreq > nodeCount)
hotFreq = nodeCount;
else if(hotFreq < 0.75 * nodeCount)
return;
Node* newNode = FlowGraph::tailDuplicate(_irm, hotPred, node, defUses);
if(Log::isEnabled()) {
Log::out() << "New node = ";
FlowGraph::printLabel(Log::out(), newNode);
Log::out() << ::std::endl;
}
newNode->setExecCount(hotFreq);
Edge* stBlockEdge = newNode->getUnconditionalEdge();
if(stBlockEdge != NULL) {
Node* stBlock = stBlockEdge->getTargetNode();
if(stBlock->getId() > newNode->getId())
stBlock->setExecCount(newNode->getExecCount());
}
node->setExecCount(nodeCount-hotFreq);
hotPred->findTargetEdge(newNode)->setEdgeProb(hotProb);
// Test if node is source of back edge.
Node* loopHeader = NULL;
const Edges& outEdges = node->getOutEdges();
for(j = outEdges.begin(); j != outEdges.end(); ++j) {
Edge* edge = *j;
Node* succ = edge->getTargetNode();
if(succ->getDfNum() != MAX_UINT32 && ltree->isLoopHeader(succ) && succ->getDfNum() < node->getDfNum()) {
loopHeader = succ;
}
}
if(loopHeader != NULL) {
// Create new loop header:
Node* newHeader = fg.createBlockNode(_irm.getInstFactory().makeLabel());
const Edges& loopInEdges = loopHeader->getInEdges();
for(j = loopInEdges.begin(); j != loopInEdges.end();) {
Edge* edge = *j;
++j;
Node* pred = edge->getSourceNode();
if(pred != newNode) {
fg.replaceEdgeTarget(edge, newHeader);
newHeader->setExecCount(newHeader->getExecCount()+pred->getExecCount()*edge->getEdgeProb());
}
}
fg.addEdge(newHeader, loopHeader);
}
}
}
void
TailDuplicator::doProfileGuidedTailDuplication(LoopTree* ltree) {
MemoryManager mm("TailDuplicator::doProfileGuidedTailDuplication.mm");
ControlFlowGraph& fg = _irm.getFlowGraph();
if(!fg.hasEdgeProfile())
return;
DefUseBuilder defUses(mm);
defUses.initialize(fg);
Nodes nodes(mm);
fg.getNodesPostOrder(nodes);
Nodes::reverse_iterator i;
for(i = nodes.rbegin(); i != nodes.rend(); ++i) {
Node* node = *i;
if(Log::isEnabled()) {
Log::out() << "Consider ";
FlowGraph::printLabel(Log::out(), node);
Log::out() << ::std::endl;
}
if(!node->isBlockNode() || node == fg.getReturnNode())
continue;
if(ltree->isLoopHeader(node))
continue;
profileGuidedTailDuplicate(ltree, defUses, node);
}
}
} //namespace Jitrino