blob: d1bfe21ff399de62bf69c5b44245a3b7d59766f8 [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 "Ia32CodeLayoutBottomUp.h"
#include "Ia32IRManager.h"
#include "Log.h"
namespace Jitrino
{
namespace Ia32 {
/**
* Class to perform bottom-up block layout.
* The layout algorithm is similar to the one described in the paper
* "Profile Guided Code Positioning" by Hansen & Pettis.
*/
BottomUpLayout::BottomUpLayout(IRManager* irm) :
Linearizer(irm),
mm("Ia32::bottomUpLayout"),
firstInChain(mm, irm->getFlowGraph()->getNodeCount(), false),
lastInChain(mm, irm->getFlowGraph()->getNodeCount(), false),
prevInLayoutBySuccessorId(mm, irm->getFlowGraph()->getNodeCount(), NULL)
{
}
struct edge_comparator {
bool operator() (const Edge* e1, const Edge* e2) const { //true -> e1 is first
double v1 = getEdgeExecCount(e1);
double v2 = getEdgeExecCount(e2);
return v1 > v2;
}
static double getEdgeExecCount(const Edge* e) {
return e->getSourceNode()->getExecCount() * e->getEdgeProb();
}
};
void BottomUpLayout::linearizeCfgImpl() {
assert(irManager->getFlowGraph()->isEdgeProfileConsistent());
StlVector<Edge*> sortedEdges(mm);
const Nodes& nodes = irManager->getFlowGraph()->getNodes();
sortedEdges.reserve(nodes.size() * 3);
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
const Edges& edges = node->getOutEdges();
sortedEdges.insert(sortedEdges.end(), edges.begin(), edges.end());
}
//GCC 3.4 passes NULLs to comparator if usual std::sort is used here..
std::stable_sort(sortedEdges.begin(), sortedEdges.end(), edge_comparator());
for(StlVector<Edge*>::const_iterator it = sortedEdges.begin(), itEnd = sortedEdges.end(); it!=itEnd; it++) {
Edge* edge = *it;
layoutEdge(edge);
}
//create one-block-chains from blocks that was not laid out
//these blocks are dispatch successors or are blocks connected by in/out edges to already laid out chains
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
if (node->isBlockNode()) {
BasicBlock* block = (BasicBlock*)node;
if (block->getLayoutSucc() == NULL && !lastInChain[block->getDfNum()]) {
firstInChain[block->getDfNum()] = true;
lastInChain[block->getDfNum()] = true;
}
}
}
combineChains();
}
void BottomUpLayout::layoutEdge(Edge *edge) {
Node* tailNode = edge->getSourceNode();
Node* headNode = edge->getTargetNode();
if (!headNode->isBlockNode() || !tailNode->isBlockNode()) {
return;
}
if (headNode == irManager->getFlowGraph()->getEntryNode()) { //prolog node should be first in layout
return;
}
if (tailNode == headNode) {
return; //backedge to self
}
BasicBlock* tailBlock = (BasicBlock*)tailNode;
if (tailBlock->getLayoutSucc()!=NULL) {
return; //tailBlock is layout predecessor for another successor
}
BasicBlock* headBlock = (BasicBlock*)headNode;
if (prevInLayoutBySuccessorId[headBlock->getDfNum()]!=NULL) {
return; // head was already laid out (in other chain)
}
if (lastInChain[tailBlock->getDfNum()] && firstInChain[headBlock->getDfNum()]) {
BasicBlock* tailOfHeadChain = headBlock;
while (tailOfHeadChain->getLayoutSucc()!=NULL) {
tailOfHeadChain = tailOfHeadChain->getLayoutSucc();
}
if (tailOfHeadChain == tailBlock) {
return; // layout must be acyclic
}
}
tailBlock->setLayoutSucc(headBlock);
prevInLayoutBySuccessorId[headBlock->getDfNum()] = tailBlock;
BasicBlock* tailPred = prevInLayoutBySuccessorId[tailBlock->getDfNum()];
if (tailPred) {
assert(lastInChain[tailBlock->getDfNum()]);
lastInChain[tailBlock->getDfNum()] = false;
} else {
firstInChain[tailBlock->getDfNum()] = true;
}// here we have valid first
firstInChain[headBlock->getDfNum()] = false;
BasicBlock* newLast = headBlock;
while (newLast->getLayoutSucc()!=NULL) {
newLast = newLast->getLayoutSucc();
}
lastInChain[newLast->getDfNum()] = true;
}
struct chains_comparator{
const StlVector<BasicBlock*>& prevInLayoutBySuccessorId;
const BasicBlock* prolog;
chains_comparator(const StlVector<BasicBlock*>& _prevInLayoutBySuccessorId, BasicBlock* _prolog)
: prevInLayoutBySuccessorId(_prevInLayoutBySuccessorId), prolog(_prolog)
{};
bool operator() (const BasicBlock* c1, const BasicBlock* c2) const {
if (c1 == prolog) {
return true;
}
if (c2 == prolog) {
return false;
}
double fromC1ToC2 = calcEdgesWeight(c1, c2);
double fromC2ToC1 = calcEdgesWeight(c2, c1);
if (fromC1ToC2 > fromC2ToC1) {
return true; //c1 is first in topological order
} else if (fromC1ToC2 < fromC2ToC1) {
return false; //c2 is first in topological order
}
return c1 > c2; //any stable order..
}
double calcEdgesWeight(const BasicBlock* c1, const BasicBlock* c2) const {
double d = 0.0;
//distance is sum of exec count of c1 blocks out edges c1 to c2;
for (const BasicBlock* b = c1; b!=NULL; b = b->getLayoutSucc()) {
const Edges& outEdges = b->getOutEdges();
for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) {
Edge* e= *ite;
Node* node = e->getTargetNode();
if (node != b->getLayoutSucc() && node->isBlockNode()) {
const BasicBlock* targetBlock = (BasicBlock*)node;
//look if node is in c2 chain
const BasicBlock* targetChain = findChain(targetBlock);
if (targetChain == c2) {
double dd = b->getExecCount() * e->getEdgeProb();
d+=dd;
}
}
}
}
return d;
}
const BasicBlock* findChain(const BasicBlock* bb) const {
const BasicBlock* prev = bb;
while ((prev = prevInLayoutBySuccessorId[bb->getDfNum()])!=NULL) {
bb = prev;
}
return bb;
}
};
void BottomUpLayout::combineChains() {
StlVector<BasicBlock*> chains(mm);
const Nodes& nodes = irManager->getFlowGraph()->getNodes();
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node* node = *it;
if (firstInChain[node->getDfNum()]) {
assert(node->isBlockNode());
chains.push_back((BasicBlock*)node);
}
}
std::sort(chains.begin(), chains.end(),
chains_comparator(prevInLayoutBySuccessorId, (BasicBlock*)irManager->getFlowGraph()->getEntryNode()));
assert(*chains.begin() ==irManager->getFlowGraph()->getEntryNode());
assert(*chains.begin() == irManager->getFlowGraph()->getEntryNode());
for (U_32 i = 0, n = (U_32)chains.size()-1; i<n;i++) {
BasicBlock* firstChain = chains[i];
BasicBlock* secondChain= chains[i+1];
BasicBlock* lastInFirst = firstChain;
while (lastInFirst->getLayoutSucc()!=NULL) {
lastInFirst = lastInFirst->getLayoutSucc();
}
lastInFirst->setLayoutSucc(secondChain);
}
}
}} //namespace