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; |
-} |