blob: c3193a95b6cd769079c89637bbd3f7b23b781679 [file] [log] [blame] [edit]
#include "LiveValues.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
using namespace llvm;
static void applyMapping(InstructionSetVector& iset, llvm::DenseMap<llvm::Instruction *, llvm::Instruction *>& imap)
{
// There will be probably be few entries in the imap, so apply them one at a time to the iset.
for (auto& kv : imap)
{
if (iset.count(kv.first) != 0)
{
iset.remove(kv.first);
iset.insert(kv.second);
}
}
}
// Compute liveness of a value at basic blocks. Roughly based on
// Algorithm 6 & 7 from the paper "Computing Liveness Sets for SSA-
// Form Programs" by Brander et al., 2011.
LiveValues::LiveValues(ArrayRef<Instruction*> computeLiveAt)
{
m_liveSets.resize(computeLiveAt.size());
// Build index and set of active blocks
for (unsigned int i = 0; i < computeLiveAt.size(); i++)
{
Instruction* v = computeLiveAt[i];
m_computeLiveAtIndex.insert(std::make_pair(v, i));
m_activeBlocks.insert(v->getParent());
}
if (computeLiveAt.size() > 0)
{
m_function = computeLiveAt[0]->getParent()->getParent();
}
}
// Go over all the instructions between begin (included) and end (excluded) and mark the given value
// live for code locations contained in the given range.
void LiveValues::markLiveRange(Instruction* value, BasicBlock::iterator begin, BasicBlock::iterator end)
{
BasicBlock* B = begin->getParent();
if (m_activeBlocks.count(B) == 0)
return; // Nothing to mark in this block
for (BasicBlock::iterator I = begin; I != end; ++I)
{
if (m_computeLiveAtIndex.count(I))
{
// Mark this value
unsigned int index = m_computeLiveAtIndex[I];
m_liveSets[index].insert(value);
m_allLiveSet.insert(value);
// Also store for each value where it is live.
m_liveAtIndices[value].insert(index);
}
}
}
void LiveValues::upAndMark(Instruction* def, Use& use, BlockSet& scanned)
{
// Determine the starting point for the backwards search.
// (Remember that Use represents an edge between the definition of a value and its use)
// In the case in which the user of the use is a phi node we start the search from the terminator
// of the preceding block.
// This allows to avoid going through loop back-edges in cases like these:
// |
// | (y)
// v
// -----------------
// (x) | z = phi(x, y) |
// ----> | ... |
// | | x = z + 1 |
// | -----------------
// | |
// | |
// | |
// | v
// | -----------------
// | | |
// ------| INDIRECT CALL |
// | |
// -----------------
// | (Start the search for the definition of x (backwards) from here!)
// v
//
// Notice that here x is live across the call. This case is tricky because the def comes 'after'
// the use. The def still dominates the use because phi nodes logically use their input values on the
// edges, i.e. on the terminator of the preceding blocks.
//
// This has the advantage of being able to traverse edges strictly backwards.
Instruction* startingPoint = dyn_cast<Instruction>(use.getUser());
if (PHINode* usePHI = dyn_cast<PHINode>(startingPoint))
{
BasicBlock* predecessor = usePHI->getIncomingBlock(use);
startingPoint = predecessor->getTerminator();
}
BasicBlock* startingPointBB = startingPoint->getParent();
BasicBlock* defBB = def->getParent();
// Start a bottom-up recursive search from startingPoint to the definition of the current value.
// Mark all the code ranges that we encounter on the way a having the current value 'live'.
// 'scanned' contains the blocks that we have scanned to the bottom of the block and the we know
// already having the current value 'live'.
SmallVector<BasicBlock*, 16> worklist;
worklist.push_back(startingPointBB);
BlockSet visited;
while (!worklist.empty())
{
BasicBlock* B = worklist.pop_back_val();
if (scanned.count(B) != 0)
continue;
// We have reached the block that contains the definition of the value. We are done for this
// branch of the search.
if (B == defBB)
{
if (defBB == startingPointBB)
{
// If the first block that we visit is also the last mark only the range of instructions
// between the def and the starting point.
// -----------------
// | |
// | x = // def | <--
// | | !
// | | ! This is the range in which x is live.
// | | !
// | = x // use | <--
// | |
// -----------------
markLiveRange(def, ++BasicBlock::iterator(def), BasicBlock::iterator(startingPoint));
}
else
{
markLiveRange(def, ++BasicBlock::iterator(def), defBB->end());
scanned.insert(B);
}
}
else
{
if (B == startingPointBB)
{
// We are in the starting-point block.
// This can mean two things:
// 1. We are in the first iteration, mark the range between begin and starting point as
// live.
if (visited.count(B) == 0)
{
markLiveRange(def, B->begin(), BasicBlock::iterator(startingPoint));
}
// 2. We came back here because the starting point is in a loop.
// In this case mark the whole block as live range and don't come back anymore.
else
{
markLiveRange(def, B->begin(), B->end());
scanned.insert(B);
}
// The if statement above allows to manage situations like this:
// BB0
// -----------------
// | x = ... |
// -----------------
// |
// |
// |
// BB1 v
// -----------------<-- <--
// | | ! !
// ----->| | ! First range marked !
// | | | ! !
// | | ... = x |<-- ! Second and final range marked
// | | | !
// | | INDIRECT CALL | !
// | | | !
// | ----------------- <--
// | |
// ---------------
// x is defined outside a loop and used inside a loop. This means that it is live inside the
// whole loop.
// So, we first mark the range from the use of x to the top of BB1 and, when we visit BB1
// again (because BB1 is a predecessor of BB1) we mark the whole block as live range.
// <rant>
// This case could have been managed much more easily and efficiently if we had access to
// LLVM LoopInfo analysis pass.
// We could have done the following: x is uses in a loop and defined outside of it => mark
// the whole loop body as live range.
// </rant>
}
else
{
// We are in an intermediate block on the way to the definition mark it, all as live range.
markLiveRange(def, B->begin(), B->end());
scanned.insert(B);
}
visited.insert(B);
for (pred_iterator P = pred_begin(B), PE = pred_end(B); P != PE; ++P)
{
worklist.push_back(*P);
}
}
}
}
void LiveValues::run()
{
if (m_computeLiveAtIndex.empty())
return;
// for each variable v do
for (inst_iterator I = inst_begin(m_function), E = inst_end(m_function); I != E; ++I)
{
Instruction* v = &*I;
assert(v->getParent()->getParent() == m_function);
// for each block B where v is used do
BlockSet scanned;
for (Value::use_iterator U = v->use_begin(), UE = v->use_end(); U != UE; ++U)
{
Instruction* user = cast<Instruction>(U->getUser());
assert(user->getParent()->getParent() == m_function);
(void)user;
upAndMark(v, *U, scanned);
}
}
}
void LiveValues::remapLiveValues(llvm::DenseMap<llvm::Instruction*, llvm::Instruction*>& imap)
{
applyMapping(m_allLiveSet, imap);
for (auto& liveSet : m_liveSets)
applyMapping(liveSet, imap);
}
const LiveValues::Indices* LiveValues::getIndicesWhereLive(const Value* value) const
{
const auto& iter = m_liveAtIndices.find(value);
if (iter == m_liveAtIndices.end())
return nullptr;
return &iter->second;
}
void LiveValues::setIndicesWhereLive(Value* value, const Indices* indices)
{
for (unsigned int idx : *indices)
setLiveAtIndex(value, idx, true);
}
bool LiveValues::liveInDisjointRegions(const Value* valueA, const Value* valueB) const
{
const Indices* indicesA = getIndicesWhereLive(valueA);
if (!indicesA)
return true;
const Indices* indicesB = getIndicesWhereLive(valueB);
if (!indicesB)
return true;
for (const unsigned int index : *indicesA)
{
if (indicesB->count(index))
return false;
}
return true;
}
void LiveValues::setLiveAtIndex(Value* value, unsigned int index, bool live)
{
assert(index <= m_computeLiveAtIndex.size());
if (live)
{
m_liveAtIndices[value].insert(index);
Instruction* inst = cast<Instruction>(value);
m_liveSets[index].insert(inst);
m_allLiveSet.insert(inst);
}
else
{
m_liveAtIndices[value].remove(index);
Instruction* inst = cast<Instruction>(value);
m_liveSets[index].remove(inst);
if (m_liveAtIndices[value].empty())
m_allLiveSet.remove(inst);
}
}
void LiveValues::setLiveAtAllIndices(llvm::Value* value, bool live)
{
Instruction* inst = cast<Instruction>(value);
if (live)
{
for (unsigned int index = 0; index < m_computeLiveAtIndex.size(); ++index)
{
m_liveAtIndices[value].insert(index);
m_liveSets[index].insert(inst);
}
m_allLiveSet.insert(inst);
}
else
{
for (unsigned int index = 0; index < m_computeLiveAtIndex.size(); ++index)
{
m_liveAtIndices[value].remove(index);
m_liveSets[index].remove(inst);
}
if (m_liveAtIndices[value].empty())
m_allLiveSet.remove(inst);
}
}
bool LiveValues::getLiveAtIndex(const Value* value, unsigned int index) const
{
assert(index <= m_computeLiveAtIndex.size());
const auto& it = m_liveAtIndices.find(value);
if (it == m_liveAtIndices.end())
return false;
return (it->second.count(index) != 0);
}