Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Unified Diff: lib/Target/JSBackend/AllocaManager.cpp

Issue 1692803002: Remove Emscripten support (Closed) Base URL: https://chromium.googlesource.com/a/native_client/pnacl-llvm.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Target/JSBackend/AllocaManager.h ('k') | lib/Target/JSBackend/CMakeLists.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Target/JSBackend/AllocaManager.cpp
diff --git a/lib/Target/JSBackend/AllocaManager.cpp b/lib/Target/JSBackend/AllocaManager.cpp
deleted file mode 100644
index 8e6ece7b15dbe96633d94af5a92eb1c686fbc561..0000000000000000000000000000000000000000
--- a/lib/Target/JSBackend/AllocaManager.cpp
+++ /dev/null
@@ -1,588 +0,0 @@
-//===-- AllocaManager.cpp -------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the AllocaManager class.
-//
-// The AllocaManager computes a frame layout, assigning every static alloca an
-// offset. It does alloca liveness analysis in order to reuse stack memory,
-// using lifetime intrinsics.
-//
-//===----------------------------------------------------------------------===//
-
-#define DEBUG_TYPE "allocamanager"
-#include "AllocaManager.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IR/CFG.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/ADT/Statistic.h"
-using namespace llvm;
-
-STATISTIC(NumAllocas, "Number of allocas eliminated");
-
-// Return the size of the given alloca.
-uint64_t AllocaManager::getSize(const AllocaInst *AI) {
- assert(AI->isStaticAlloca());
- return DL->getTypeAllocSize(AI->getAllocatedType()) *
- cast<ConstantInt>(AI->getArraySize())->getValue().getZExtValue();
-}
-
-// Return the alignment of the given alloca.
-unsigned AllocaManager::getAlignment(const AllocaInst *AI) {
- assert(AI->isStaticAlloca());
- unsigned Alignment = std::max(AI->getAlignment(),
- DL->getABITypeAlignment(AI->getAllocatedType()));
- MaxAlignment = std::max(Alignment, MaxAlignment);
- return Alignment;
-}
-
-AllocaManager::AllocaInfo AllocaManager::getInfo(const AllocaInst *AI) {
- assert(AI->isStaticAlloca());
- return AllocaInfo(AI, getSize(AI), getAlignment(AI));
-}
-
-// Given a lifetime_start or lifetime_end intrinsic, determine if it's
-// describing a single pointer suitable for our analysis. If so,
-// return the pointer, otherwise return NULL.
-const Value *
-AllocaManager::getPointerFromIntrinsic(const CallInst *CI) {
- const IntrinsicInst *II = cast<IntrinsicInst>(CI);
- assert(II->getIntrinsicID() == Intrinsic::lifetime_start ||
- II->getIntrinsicID() == Intrinsic::lifetime_end);
-
- // Lifetime intrinsics have a size as their first argument and a pointer as
- // their second argument.
- const Value *Size = II->getArgOperand(0);
- const Value *Ptr = II->getArgOperand(1);
-
- // Check to see if we can convert the size to a host integer. If we can't,
- // it's probably not worth worrying about.
- const ConstantInt *SizeCon = dyn_cast<ConstantInt>(Size);
- if (!SizeCon) return NULL;
- const APInt &SizeAP = SizeCon->getValue();
- if (SizeAP.getActiveBits() > 64) return NULL;
- uint64_t MarkedSize = SizeAP.getZExtValue();
-
- // Test whether the pointer operand is an alloca. This ought to be pretty
- // simple, but e.g. PRE can decide to PRE bitcasts and no-op geps and
- // split critical edges and insert phis for them, even though it's all
- // just no-ops, so we have to dig through phis to see whether all the
- // inputs are in fact the same pointer after stripping away casts.
- const Value *Result = NULL;
- SmallPtrSet<const PHINode *, 8> VisitedPhis;
- SmallVector<const Value *, 8> Worklist;
- Worklist.push_back(Ptr);
- do {
- const Value *P = Worklist.pop_back_val()->stripPointerCasts();
-
- if (const PHINode *Phi = dyn_cast<PHINode>(P)) {
- if (!VisitedPhis.insert(Phi).second)
- continue;
- for (unsigned i = 0, e = Phi->getNumOperands(); i < e; ++i)
- Worklist.push_back(Phi->getOperand(i));
- continue;
- }
- if (const SelectInst *Select = dyn_cast<SelectInst>(P)) {
- Worklist.push_back(Select->getTrueValue());
- Worklist.push_back(Select->getFalseValue());
- continue;
- }
-
- if (Result == NULL)
- Result = P;
- else if (Result != P)
- return NULL;
- } while (!Worklist.empty());
-
- // If it's a static Alloca, make sure the size is suitable. We test this here
- // because if this fails, we need to be as conservative as if we don't know
- // what the pointer is.
- if (const AllocaInst *AI = dyn_cast<AllocaInst>(Result)) {
- if (AI->isStaticAlloca() && MarkedSize < getSize(AI))
- return NULL;
- } else if (isa<Instruction>(Result)) {
- // And if it's any other kind of non-object/argument, we have to be
- // similarly conservative, because we may be dealing with an escaped alloca
- // that we can't see.
- return NULL;
- }
-
- // Yay, it's all just one Value!
- return Result;
-}
-
-// Test whether the given value is an alloca which we have a hope of
-const AllocaInst *AllocaManager::isFavorableAlloca(const Value *V) {
- const AllocaInst *AI = dyn_cast<AllocaInst>(V);
- if (!AI) return NULL;
-
- if (!AI->isStaticAlloca()) return NULL;
-
- return AI;
-}
-
-int AllocaManager::AllocaSort(const AllocaInfo *li, const AllocaInfo *ri) {
- // Sort by alignment to minimize padding.
- if (li->getAlignment() > ri->getAlignment()) return -1;
- if (li->getAlignment() < ri->getAlignment()) return 1;
-
- // Ensure a stable sort. We can do this because the pointers are
- // pointing into the same array.
- if (li > ri) return -1;
- if (li < ri) return 1;
-
- return 0;
-}
-
-// Collect allocas
-void AllocaManager::collectMarkedAllocas() {
- NamedRegionTimer Timer("Collect Marked Allocas", "AllocaManager",
- TimePassesIsEnabled);
-
- // Weird semantics: If an alloca *ever* appears in a lifetime start or end
- // within the same function, its lifetime begins only at the explicit lifetime
- // starts and ends only at the explicit lifetime ends and function exit
- // points. Otherwise, its lifetime begins in the entry block and it is live
- // everywhere.
- //
- // And so, instead of just walking the entry block to find all the static
- // allocas, we walk the whole body to find the intrinsics so we can find the
- // set of static allocas referenced in the intrinsics.
- for (Function::const_iterator FI = F->begin(), FE = F->end();
- FI != FE; ++FI) {
- for (BasicBlock::const_iterator BI = FI->begin(), BE = FI->end();
- BI != BE; ++BI) {
- const CallInst *CI = dyn_cast<CallInst>(BI);
- if (!CI) continue;
-
- const Value *Callee = CI->getCalledValue();
- if (Callee == LifetimeStart || Callee == LifetimeEnd) {
- if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
- if (const AllocaInst *AI = isFavorableAlloca(Ptr))
- Allocas.insert(std::make_pair(AI, 0));
- } else if (isa<Instruction>(CI->getArgOperand(1)->stripPointerCasts())) {
- // Oh noes, There's a lifetime intrinsics with something that
- // doesn't appear to resolve to an alloca. This means that it's
- // possible that it may be declaring a lifetime for some escaping
- // alloca. Look out!
- Allocas.clear();
- assert(AllocasByIndex.empty());
- return;
- }
- }
- }
- }
-
- // All that said, we still want the intrinsics in the order they appear in the
- // block, so that we can represent later ones with earlier ones and skip
- // worrying about dominance, so run through the entry block and index those
- // allocas which we identified above.
- AllocasByIndex.reserve(Allocas.size());
- const BasicBlock *EntryBB = &F->getEntryBlock();
- for (BasicBlock::const_iterator BI = EntryBB->begin(), BE = EntryBB->end();
- BI != BE; ++BI) {
- const AllocaInst *AI = dyn_cast<AllocaInst>(BI);
- if (!AI || !AI->isStaticAlloca()) continue;
-
- AllocaMap::iterator I = Allocas.find(AI);
- if (I != Allocas.end()) {
- I->second = AllocasByIndex.size();
- AllocasByIndex.push_back(getInfo(AI));
- }
- }
- assert(AllocasByIndex.size() == Allocas.size());
-}
-
-// Calculate the starting point from which inter-block liveness will be
-// computed.
-void AllocaManager::collectBlocks() {
- NamedRegionTimer Timer("Collect Blocks", "AllocaManager",
- TimePassesIsEnabled);
-
- size_t AllocaCount = AllocasByIndex.size();
-
- BitVector Seen(AllocaCount);
-
- for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I) {
- const BasicBlock *BB = I;
-
- BlockLifetimeInfo &BLI = BlockLiveness[BB];
- BLI.Start.resize(AllocaCount);
- BLI.End.resize(AllocaCount);
-
- // Track which allocas we've seen. This is used because if a lifetime start
- // is the first lifetime marker for an alloca in a block, the alloca is
- // live-in.
- Seen.reset();
-
- // Walk the instructions and compute the Start and End sets.
- for (BasicBlock::const_iterator BI = BB->begin(), BE = BB->end();
- BI != BE; ++BI) {
- const CallInst *CI = dyn_cast<CallInst>(BI);
- if (!CI) continue;
-
- const Value *Callee = CI->getCalledValue();
- if (Callee == LifetimeStart) {
- if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
- if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
- AllocaMap::const_iterator MI = Allocas.find(AI);
- if (MI != Allocas.end()) {
- size_t AllocaIndex = MI->second;
- if (!Seen.test(AllocaIndex)) {
- BLI.Start.set(AllocaIndex);
- }
- BLI.End.reset(AllocaIndex);
- Seen.set(AllocaIndex);
- }
- }
- }
- } else if (Callee == LifetimeEnd) {
- if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
- if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
- AllocaMap::const_iterator MI = Allocas.find(AI);
- if (MI != Allocas.end()) {
- size_t AllocaIndex = MI->second;
- BLI.End.set(AllocaIndex);
- Seen.set(AllocaIndex);
- }
- }
- }
- }
- }
-
- // Lifetimes that start in this block and do not end here are live-out.
- BLI.LiveOut = BLI.Start;
- BLI.LiveOut.reset(BLI.End);
- if (BLI.LiveOut.any()) {
- for (succ_const_iterator SI = succ_begin(BB), SE = succ_end(BB);
- SI != SE; ++SI) {
- InterBlockTopDownWorklist.insert(*SI);
- }
- }
-
- // Lifetimes that end in this block and do not start here are live-in.
- // TODO: Is this actually true? What are the semantics of a standalone
- // lifetime end? See also the code in computeInterBlockLiveness.
- BLI.LiveIn = BLI.End;
- BLI.LiveIn.reset(BLI.Start);
- if (BLI.LiveIn.any()) {
- for (const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
- PI != PE; ++PI) {
- InterBlockBottomUpWorklist.insert(*PI);
- }
- }
- }
-}
-
-// Compute the LiveIn and LiveOut sets for each block in F.
-void AllocaManager::computeInterBlockLiveness() {
- NamedRegionTimer Timer("Compute inter-block liveness", "AllocaManager",
- TimePassesIsEnabled);
-
- size_t AllocaCount = AllocasByIndex.size();
-
- BitVector Temp(AllocaCount);
-
- // Proporgate liveness backwards.
- while (!InterBlockBottomUpWorklist.empty()) {
- const BasicBlock *BB = InterBlockBottomUpWorklist.pop_back_val();
- BlockLifetimeInfo &BLI = BlockLiveness[BB];
-
- // Compute the new live-out set.
- for (succ_const_iterator SI = succ_begin(BB), SE = succ_end(BB);
- SI != SE; ++SI) {
- Temp |= BlockLiveness[*SI].LiveIn;
- }
-
- // If it contains new live blocks, prepare to propagate them.
- // TODO: As above, what are the semantics of a standalone lifetime end?
- Temp.reset(BLI.Start);
- if (Temp.test(BLI.LiveIn)) {
- BLI.LiveIn |= Temp;
- for (const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
- PI != PE; ++PI) {
- InterBlockBottomUpWorklist.insert(*PI);
- }
- }
- Temp.reset();
- }
-
- // Proporgate liveness forwards.
- while (!InterBlockTopDownWorklist.empty()) {
- const BasicBlock *BB = InterBlockTopDownWorklist.pop_back_val();
- BlockLifetimeInfo &BLI = BlockLiveness[BB];
-
- // Compute the new live-in set.
- for (const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
- PI != PE; ++PI) {
- Temp |= BlockLiveness[*PI].LiveOut;
- }
-
- // Also record the live-in values.
- BLI.LiveIn |= Temp;
-
- // If it contains new live blocks, prepare to propagate them.
- Temp.reset(BLI.End);
- if (Temp.test(BLI.LiveOut)) {
- BLI.LiveOut |= Temp;
- for (succ_const_iterator SI = succ_begin(BB), SE = succ_end(BB);
- SI != SE; ++SI) {
- InterBlockTopDownWorklist.insert(*SI);
- }
- }
- Temp.reset();
- }
-}
-
-// Determine overlapping liveranges within blocks.
-void AllocaManager::computeIntraBlockLiveness() {
- NamedRegionTimer Timer("Compute intra-block liveness", "AllocaManager",
- TimePassesIsEnabled);
-
- size_t AllocaCount = AllocasByIndex.size();
-
- BitVector Current(AllocaCount);
-
- AllocaCompatibility.resize(AllocaCount, BitVector(AllocaCount, true));
-
- for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I) {
- const BasicBlock *BB = I;
- const BlockLifetimeInfo &BLI = BlockLiveness[BB];
-
- Current = BLI.LiveIn;
-
- for (int i = Current.find_first(); i >= 0; i = Current.find_next(i)) {
- AllocaCompatibility[i].reset(Current);
- }
-
- for (BasicBlock::const_iterator BI = BB->begin(), BE = BB->end();
- BI != BE; ++BI) {
- const CallInst *CI = dyn_cast<CallInst>(BI);
- if (!CI) continue;
-
- const Value *Callee = CI->getCalledValue();
- if (Callee == LifetimeStart) {
- if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
- if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
- size_t AIndex = Allocas[AI];
- // We conflict with everything else that's currently live.
- AllocaCompatibility[AIndex].reset(Current);
- // Everything else that's currently live conflicts with us.
- for (int i = Current.find_first(); i >= 0; i = Current.find_next(i)) {
- AllocaCompatibility[i].reset(AIndex);
- }
- // We're now live.
- Current.set(AIndex);
- }
- }
- } else if (Callee == LifetimeEnd) {
- if (const Value *Ptr = getPointerFromIntrinsic(CI)) {
- if (const AllocaInst *AI = isFavorableAlloca(Ptr)) {
- size_t AIndex = Allocas[AI];
- // We're no longer live.
- Current.reset(AIndex);
- }
- }
- }
- }
- }
-}
-
-// Decide which allocas will represent which other allocas, and if so what their
-// size and alignment will need to be.
-void AllocaManager::computeRepresentatives() {
- NamedRegionTimer Timer("Compute Representatives", "AllocaManager",
- TimePassesIsEnabled);
-
- for (size_t i = 0, e = AllocasByIndex.size(); i != e; ++i) {
- // If we've already represented this alloca with another, don't visit it.
- if (AllocasByIndex[i].isForwarded()) continue;
- if (i > size_t(INT_MAX)) continue;
-
- // Find compatible allocas. This is a simple greedy algorithm.
- for (int j = int(i); ; ) {
- assert(j >= int(i));
- j = AllocaCompatibility[i].find_next(j);
- assert(j != int(i));
- if (j < 0) break;
- if (!AllocaCompatibility[j][i]) continue;
-
- DEBUG(dbgs() << "Allocas: "
- "Representing "
- << AllocasByIndex[j].getInst()->getName() << " "
- "with "
- << AllocasByIndex[i].getInst()->getName() << "\n");
- ++NumAllocas;
-
- assert(!AllocasByIndex[j].isForwarded());
-
- AllocasByIndex[i].mergeSize(AllocasByIndex[j].getSize());
- AllocasByIndex[i].mergeAlignment(AllocasByIndex[j].getAlignment());
- AllocasByIndex[j].forward(i);
-
- AllocaCompatibility[i] &= AllocaCompatibility[j];
- AllocaCompatibility[j].reset();
- }
- }
-}
-
-void AllocaManager::computeFrameOffsets() {
- NamedRegionTimer Timer("Compute Frame Offsets", "AllocaManager",
- TimePassesIsEnabled);
-
- // Walk through the entry block and collect all the allocas, including the
- // ones with no lifetime markers that we haven't looked at yet. We walk in
- // reverse order so that we can set the representative allocas as those that
- // dominate the others as we go.
- const BasicBlock *EntryBB = &F->getEntryBlock();
- for (BasicBlock::const_iterator BI = EntryBB->begin(), BE = EntryBB->end();
- BI != BE; ++BI) {
- const AllocaInst *AI = dyn_cast<AllocaInst>(BI);
- if (!AI || !AI->isStaticAlloca()) continue;
-
- AllocaMap::const_iterator I = Allocas.find(AI);
- if (I != Allocas.end()) {
- // An alloca with lifetime markers. Emit the record we've crafted for it,
- // if we've chosen to keep it as a representative.
- const AllocaInfo &Info = AllocasByIndex[I->second];
- if (!Info.isForwarded()) {
- SortedAllocas.push_back(Info);
- }
- } else {
- // An alloca with no lifetime markers.
- SortedAllocas.push_back(getInfo(AI));
- }
- }
-
- // Sort the allocas to hopefully reduce padding.
- array_pod_sort(SortedAllocas.begin(), SortedAllocas.end(), AllocaSort);
-
- // Assign stack offsets.
- uint64_t CurrentOffset = 0;
- for (SmallVectorImpl<AllocaInfo>::const_iterator I = SortedAllocas.begin(),
- E = SortedAllocas.end(); I != E; ++I) {
- const AllocaInfo &Info = *I;
- uint64_t NewOffset = RoundUpToAlignment(CurrentOffset, Info.getAlignment());
-
- // For backwards compatibility, align every power-of-two multiple alloca to
- // its greatest power-of-two factor, up to 8 bytes. In particular, cube2hash
- // is known to depend on this.
- // TODO: Consider disabling this and making people fix their code.
- if (uint64_t Size = Info.getSize()) {
- uint64_t P2 = uint64_t(1) << countTrailingZeros(Size);
- unsigned CompatAlign = unsigned(std::min(P2, uint64_t(8)));
- NewOffset = RoundUpToAlignment(NewOffset, CompatAlign);
- }
-
- const AllocaInst *AI = Info.getInst();
- StaticAllocas[AI] = StaticAllocation(AI, NewOffset);
-
- CurrentOffset = NewOffset + Info.getSize();
- }
-
- // Add allocas that were represented by other allocas to the StaticAllocas map
- // so that our clients can look them up.
- for (unsigned i = 0, e = AllocasByIndex.size(); i != e; ++i) {
- const AllocaInfo &Info = AllocasByIndex[i];
- if (!Info.isForwarded()) continue;
- size_t j = Info.getForwardedID();
- assert(!AllocasByIndex[j].isForwarded());
-
- StaticAllocaMap::const_iterator I =
- StaticAllocas.find(AllocasByIndex[j].getInst());
- assert(I != StaticAllocas.end());
-
- std::pair<StaticAllocaMap::const_iterator, bool> Pair =
- StaticAllocas.insert(std::make_pair(AllocasByIndex[i].getInst(),
- I->second));
- assert(Pair.second); (void)Pair;
- }
-
- // Record the final frame size. Keep the stack pointer 16-byte aligned.
- FrameSize = CurrentOffset;
- FrameSize = RoundUpToAlignment(FrameSize, 16);
-
- DEBUG(dbgs() << "Allocas: "
- "Statically allocated frame size is " << FrameSize << "\n");
-}
-
-AllocaManager::AllocaManager() : MaxAlignment(0) {
-}
-
-void AllocaManager::analyze(const Function &Func, const DataLayout &Layout,
- bool PerformColoring) {
- NamedRegionTimer Timer("AllocaManager", TimePassesIsEnabled);
- assert(Allocas.empty());
- assert(AllocasByIndex.empty());
- assert(AllocaCompatibility.empty());
- assert(BlockLiveness.empty());
- assert(StaticAllocas.empty());
- assert(SortedAllocas.empty());
-
- DL = &Layout;
- F = &Func;
-
- // Get the declarations for the lifetime intrinsics so we can quickly test to
- // see if they are used at all, and for use later if they are.
- const Module *M = F->getParent();
- LifetimeStart = M->getFunction(Intrinsic::getName(Intrinsic::lifetime_start));
- LifetimeEnd = M->getFunction(Intrinsic::getName(Intrinsic::lifetime_end));
-
- // If we are optimizing and the module contains any lifetime intrinsics, run
- // the alloca coloring algorithm.
- if (PerformColoring &&
- ((LifetimeStart && !LifetimeStart->use_empty()) ||
- (LifetimeEnd && !LifetimeEnd->use_empty()))) {
-
- collectMarkedAllocas();
-
- if (!AllocasByIndex.empty()) {
- DEBUG(dbgs() << "Allocas: "
- << AllocasByIndex.size() << " marked allocas found\n");
-
- collectBlocks();
- computeInterBlockLiveness();
- computeIntraBlockLiveness();
- BlockLiveness.clear();
-
- computeRepresentatives();
- AllocaCompatibility.clear();
- }
- }
-
- computeFrameOffsets();
- SortedAllocas.clear();
- Allocas.clear();
- AllocasByIndex.clear();
-}
-
-void AllocaManager::clear() {
- StaticAllocas.clear();
-}
-
-bool
-AllocaManager::getFrameOffset(const AllocaInst *AI, uint64_t *Offset) const {
- assert(AI->isStaticAlloca());
- StaticAllocaMap::const_iterator I = StaticAllocas.find(AI);
- assert(I != StaticAllocas.end());
- *Offset = I->second.Offset;
- return AI == I->second.Representative;
-}
-
-const AllocaInst *
-AllocaManager::getRepresentative(const AllocaInst *AI) const {
- assert(AI->isStaticAlloca());
- StaticAllocaMap::const_iterator I = StaticAllocas.find(AI);
- assert(I != StaticAllocas.end());
- return I->second.Representative;
-}
« no previous file with comments | « lib/Target/JSBackend/AllocaManager.h ('k') | lib/Target/JSBackend/CMakeLists.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698