blob: 6317986bf840e369296c0f49dda89c1a836fafb5 [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 "Ia32CodeLayoutTopDown.h"
#include "Ia32IRManager.h"
#include "Log.h"
#include "Ia32Printer.h"
namespace Jitrino
{
namespace Ia32 {
/**
* Class to perform top-down block layout.
* The layout algorithm is similar to the one described in the paper
* "Profile Guided Code Positioning" by Hansen & Pettis.
*/
TopDownLayout::TopDownLayout(IRManager* irm)
: Linearizer(irm),
memManager("ia32::topdown_layout"),
lastBlk(NULL),
neighboursBlocks(memManager),
blockInfos(memManager, irm->getFlowGraph()->getMaxNodeId(), NULL)
{
const Nodes& nodes = irManager->getFlowGraph()->getNodes();
for (Nodes::const_iterator it = nodes.begin(), end = nodes.end(); it!=end; ++it) {
Node * node=*it;
if (node->isBlockNode()){
TopDownLayoutBlockInfo* info = new (memManager) TopDownLayoutBlockInfo();
info->block = (BasicBlock*)node;
blockInfos[node->getId()]= info;
}
}
}
// Do complete top down code layout
void TopDownLayout::linearizeCfgImpl() {
assert(irManager->getFlowGraph()->isEdgeProfileConsistent());
BasicBlock * blk;
lastBlk = NULL;
// Check that nodes have no layout successors set
#ifdef _DEBUG
const Nodes& postOrderNodes = irManager->getFlowGraph()->getNodesPostOrder();
for (Nodes::const_iterator it = postOrderNodes.begin(), end = postOrderNodes.end(); it!=end; ++it) {
Node* node = *it;
if (node->isBlockNode()){
assert(((BasicBlock *)node)->getLayoutSucc()==NULL);
}
}
#endif
while ((blk = pickLayoutCandidate()) != NULL) {
layoutBlock(blk);
}
}
// Layout "blk" after "lastBlk". Do all bookkeeping and branch updates as needed
void TopDownLayout::layoutBlock(BasicBlock *blk) {
TopDownLayoutBlockInfo* bInfo = blockInfos[blk->getId()];
assert(!bInfo->isLayouted());
if (Log::isEnabled()) {
Log::out() << "layoutBlock(";
IRPrinter::printNodeName(Log::out(), blk);
Log::out() << ")" << std::endl;
}
// Remove the block from the localityMap if it is there
if (bInfo->isLayoutNeighbour()) {
neighboursBlocks.erase(bInfo);
}
bInfo->state = TopDownLayoutBlockInfo::LAYOUTED;
if (lastBlk) {
lastBlk->setLayoutSucc(blk);
} else {
// Check our assumption that the first block laid-out is the entry block.
assert(blk== irManager->getFlowGraph()->getEntryNode());
}
lastBlk = blk;
}
// Pick and return the next block to be laid-out
#define PROB_SIMILAR_FACTOR 0.9
BasicBlock * TopDownLayout::pickLayoutCandidate() {
if (lastBlk == NULL) {
// Layout the entry block
return (BasicBlock*)irManager->getFlowGraph()->getEntryNode();
}
// Return most likely successor of lastBlk if it has not already been placed
// and if branch inversion is either not needed or is possible
// (i.e. predicate is available). Given two almost equally likely
// successors, pick the one that is not a Join block. This will help
// reduce taken branches.
Edge *bestEdge = NULL;
const Edges& outEdges=lastBlk->getOutEdges();
for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
Node *succ = edge->getTargetNode();
if (!succ->isBlockNode()) {
continue;
}
TopDownLayoutBlockInfo* info = blockInfos[succ->getId()];
if (info->isLayouted() ) {
continue;
}
if (!edge->isFalseEdge() && !canEdgeBeMadeToFallThrough(edge)) {
continue;
}
if (bestEdge == NULL) {
bestEdge = edge;
}
double bestEdgeWeight = bestEdge->getEdgeProb();
double edgeWeight = edge->getEdgeProb();
if ( edgeWeight > bestEdgeWeight || (edgeWeight >= bestEdgeWeight * PROB_SIMILAR_FACTOR
&& edge->getTargetNode()->getInDegree() == 1 && bestEdge->getTargetNode()->getInDegree() > 1))
{
bestEdge = edge;
}
}
// Before returning or choosing a block from the connectivity map, update
// the layoutValue information to successors not chosen or already laid out.
if (bestEdge) {
BasicBlock* headBlock = (BasicBlock*)bestEdge->getTargetNode();
processSuccLayoutValue(lastBlk, headBlock);
return headBlock;
}
processSuccLayoutValue(lastBlk, NULL);
#if _DEBUG
// Find node with the greatest layoutValue in the connectedBlkMap
// Check assumption that the iterator accesses map elements in ordered fashion
const TopDownLayoutBlockInfo* prevInfo = NULL;
for (SortedBlockInfoSet::iterator it = neighboursBlocks.begin(), end = neighboursBlocks.end(); it!=end; ++it) {
TopDownLayoutBlockInfo *bInfo = *it;
assert(prevInfo == NULL || TopDownLayoutBlockInfo::less(bInfo, prevInfo));
prevInfo = bInfo;
}
#endif
if (Log::isEnabled()) {
printConnectedBlkMap(Log::out());
}
if (neighboursBlocks.empty()) {
return NULL;
}
TopDownLayoutBlockInfo* info = *neighboursBlocks.begin();
BasicBlock * locBlk = info->block;
if (Log::isEnabled()) {
Log::out() << "Picking ";
IRPrinter::printNodeName(Log::out(), locBlk);
Log::out() << " " << info->layoutValue<< ::std::endl;
}
assert(info->isLayoutNeighbour());
return locBlk;
}
// Update layoutValue information for all successors of node that have not yet been laid out.
// If a successor is a dispatch node, recursively process its successors, since
// dispatch nodes are not being laid out.
void TopDownLayout::processSuccLayoutValue(Node *node, BasicBlock * layoutSucc) {
const Edges& outEdges = node->getOutEdges();
for (Edges::const_iterator ite = outEdges.begin(), ende = outEdges.end(); ite!=ende; ++ite) {
Edge* edge = *ite;
Node *succ = edge->getTargetNode();
if (succ->isDispatchNode()) {
processSuccLayoutValue(succ, layoutSucc);
} else if (succ->isBlockNode()) {
TopDownLayoutBlockInfo* succInfo = blockInfos[succ->getId()];
if (succ != layoutSucc && !succInfo->isLayouted()) {
if (succInfo->isLayoutNeighbour()) { //remove from sorted map and insert latter to sort again.
neighboursBlocks.erase(succInfo);
}
succInfo->layoutValue+=node->getExecCount() * edge->getEdgeProb();
succInfo->state = TopDownLayoutBlockInfo::LAYOUT_NEIGHBOUR;
neighboursBlocks.insert(succInfo);
if (Log::isEnabled()) {
Log::out() << "Block ";
IRPrinter::printNodeName(Log::out(), succInfo->block);
Log::out() << " is in neighbors set." << std::endl;
}
}
}
}
}
//
// Print the contents of the connectivity map
//
void TopDownLayout::printConnectedBlkMap(::std::ostream & os) {
os << "Neighbors set contents: ";
for (SortedBlockInfoSet::iterator it = neighboursBlocks.begin(), end = neighboursBlocks.end(); it != end; ++it) {
TopDownLayoutBlockInfo* info= *it;
IRPrinter::printNodeName(os, info->block);
os << " " << info->layoutValue << ::std::endl;
}
}
}
}