15#include "llvm/Config/llvm-config.h"
32#define DEBUG_TYPE "stack-lifetime"
36 const auto IT = AllocaNumbering.find(AI);
38 return LiveRanges[
IT->second];
42 return BlockInstRange.contains(
I->getParent());
48 auto ItBB = BlockInstRange.find(BB);
49 assert(ItBB != BlockInstRange.end() &&
"Unreachable is not expected");
52 auto It = std::upper_bound(Instructions.begin() + ItBB->getSecond().first + 1,
53 Instructions.begin() + ItBB->getSecond().second,
I,
55 return L->comesBefore(R);
58 unsigned InstNum = It - Instructions.begin();
77 int64_t LifetimeSize =
Size->getSExtValue();
79 if (LifetimeSize != -1 &&
uint64_t(LifetimeSize) != *AllocaSize)
85void StackLifetime::collectMarkers() {
86 InterestingAllocas.
resize(NumAllocas);
100 HasUnknownLifetimeStartOrEnd =
true;
103 auto It = AllocaNumbering.find(AI);
104 if (It == AllocaNumbering.end())
106 auto AllocaNo = It->second;
109 InterestingAllocas.
set(AllocaNo);
110 BBMarkerSet[BB][II] = {AllocaNo, IsStart};
123 LLVM_DEBUG(
dbgs() <<
" " << Instructions.size() <<
": BB " << BB->getName()
125 auto BBStart = Instructions.size();
126 Instructions.push_back(
nullptr);
128 BlockLifetimeInfo &BlockInfo =
129 BlockLiveness.
try_emplace(BB, NumAllocas).first->getSecond();
131 auto &BlockMarkerSet = BBMarkerSet[BB];
132 if (BlockMarkerSet.empty()) {
133 BlockInstRange[BB] = std::make_pair(BBStart, Instructions.size());
139 << (
M.IsStart ?
"start " :
"end ") <<
M.AllocaNo
140 <<
", " << *
I <<
"\n");
142 BBMarkers[BB].push_back({Instructions.size(), M});
143 Instructions.push_back(
I);
146 BlockInfo.End.reset(
M.AllocaNo);
147 BlockInfo.Begin.set(
M.AllocaNo);
149 BlockInfo.Begin.reset(
M.AllocaNo);
150 BlockInfo.End.set(
M.AllocaNo);
154 if (BlockMarkerSet.size() == 1) {
155 ProcessMarker(BlockMarkerSet.begin()->getFirst(),
156 BlockMarkerSet.begin()->getSecond());
163 auto It = BlockMarkerSet.find(II);
164 if (It == BlockMarkerSet.end())
166 ProcessMarker(II, It->getSecond());
170 BlockInstRange[BB] = std::make_pair(BBStart, Instructions.size());
174void StackLifetime::calculateLocalLiveness() {
186 BlockLifetimeInfo &BlockInfo = BlockLiveness.
find(BB)->getSecond();
193 if (
I == BlockLiveness.
end())
195 BitsIn |=
I->second.LiveOut;
200 BitsIn.
resize(NumAllocas,
true);
203 if (BitsIn.
test(BlockInfo.LiveIn)) {
204 BlockInfo.LiveIn |= BitsIn;
216 BitsIn.
reset(BlockInfo.End);
218 BitsIn |= BlockInfo.Begin;
221 BitsIn.
reset(BlockInfo.Begin);
223 BitsIn |= BlockInfo.End;
228 if (BitsIn.
test(BlockInfo.LiveOut)) {
230 BlockInfo.LiveOut |= BitsIn;
237 for (
auto &[BB, BlockInfo] : BlockLiveness) {
238 BlockInfo.LiveIn.
flip();
239 BlockInfo.LiveOut.
flip();
244void StackLifetime::calculateLiveIntervals() {
245 for (
auto IT : BlockLiveness) {
247 BlockLifetimeInfo &BlockInfo =
IT.getSecond();
248 unsigned BBStart, BBEnd;
249 std::tie(BBStart, BBEnd) = BlockInstRange[BB];
252 Started.
resize(NumAllocas);
255 Start.resize(NumAllocas);
258 for (
unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo) {
259 if (BlockInfo.LiveIn.test(AllocaNo)) {
260 Started.
set(AllocaNo);
261 Start[AllocaNo] = BBStart;
265 for (
auto &It : BBMarkers[BB]) {
266 unsigned InstNo = It.first;
267 bool IsStart = It.second.IsStart;
268 unsigned AllocaNo = It.second.AllocaNo;
271 if (!Started.
test(AllocaNo)) {
272 Started.
set(AllocaNo);
273 Ended.
reset(AllocaNo);
274 Start[AllocaNo] = InstNo;
277 if (Started.
test(AllocaNo)) {
278 LiveRanges[AllocaNo].addRange(Start[AllocaNo], InstNo);
279 Started.
reset(AllocaNo);
285 for (
unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
286 if (Started.
test(AllocaNo))
287 LiveRanges[AllocaNo].addRange(Start[AllocaNo], BBEnd);
291#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
293 dbgs() <<
"Allocas:\n";
294 for (
unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
295 dbgs() <<
" " << AllocaNo <<
": " << *Allocas[AllocaNo] <<
"\n";
299 dbgs() <<
"Block liveness:\n";
300 for (
auto IT : BlockLiveness) {
302 const BlockLifetimeInfo &BlockInfo = BlockLiveness.find(BB)->getSecond();
303 auto BlockRange = BlockInstRange.find(BB)->getSecond();
304 dbgs() <<
" BB (" << BB->
getName() <<
") [" << BlockRange.first <<
", " << BlockRange.second
305 <<
"): begin " << BlockInfo.Begin <<
", end " << BlockInfo.End
306 <<
", livein " << BlockInfo.LiveIn <<
", liveout "
307 << BlockInfo.LiveOut <<
"\n";
312 dbgs() <<
"Alloca liveness:\n";
313 for (
unsigned AllocaNo = 0; AllocaNo < NumAllocas; ++AllocaNo)
314 dbgs() <<
" " << AllocaNo <<
": " << LiveRanges[AllocaNo] <<
"\n";
321 :
F(
F),
Type(
Type), Allocas(Allocas), NumAllocas(Allocas.
size()) {
324 for (
unsigned I = 0;
I < NumAllocas; ++
I)
325 AllocaNumbering[Allocas[
I]] =
I;
331 if (HasUnknownLifetimeStartOrEnd) {
339 LiveRanges.resize(NumAllocas,
LiveRange(Instructions.size()));
345 LiveRanges.resize(NumAllocas,
LiveRange(Instructions.size()));
346 for (
unsigned I = 0;
I < NumAllocas; ++
I)
347 if (!InterestingAllocas.
test(
I))
350 calculateLocalLiveness();
352 calculateLiveIntervals();
362 for (
const auto &KV : SL.AllocaNumbering) {
363 if (SL.LiveRanges[KV.getSecond()].test(InstrNo))
364 Names.
push_back(KV.getFirst()->getName());
367 OS <<
" ; Alive: <" << llvm::join(Names,
" ") <<
">\n";
370 void emitBasicBlockStartAnnot(
const BasicBlock *BB,
372 auto ItBB = SL.BlockInstRange.find(BB);
373 if (ItBB == SL.BlockInstRange.end())
375 printInstrAlive(ItBB->getSecond().first,
OS);
379 const Instruction *Instr = dyn_cast<Instruction>(&V);
384 for (
const auto &KV : SL.AllocaNumbering) {
386 Names.
push_back(KV.getFirst()->getName());
389 OS <<
"\n ; Alive: <" << llvm::join(Names,
" ") <<
">\n";
405 if (
const AllocaInst *AI = dyn_cast<AllocaInst>(&
I))
416 OS, MapClassName2PassName);
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate any type of IT block"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow complex IT blocks")))
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
Select target instructions out of generic instructions
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
static const AllocaInst * findMatchingAlloca(const IntrinsicInst &II, const DataLayout &DL)
LifetimeAnnotationWriter(const StackLifetime &SL)
an instruction to allocate memory on the stack
std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const
Get allocation size in bytes.
A container for analyses that lazily runs them and caches their results.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
bool test(unsigned Idx) const
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
bool empty() const
empty - Tests whether there are no bits in this bitvector.
Value * getArgOperand(unsigned i) const
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&... Args)
DenseMapIterator< KeyT, ValueT, KeyInfoT, BucketT, true > const_iterator
void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW=nullptr, bool ShouldPreserveUseListOrder=false, bool IsForDebug=false) const
Print the function to an output stream with an optional AssemblyAnnotationWriter.
Module * getParent()
Get the module that this global value is contained inside of...
bool isLifetimeStartOrEnd() const LLVM_READONLY
Return true if the instruction is a llvm.lifetime.start or llvm.lifetime.end marker.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
This class represents a set of interesting instructions where an alloca is live.
bool test(unsigned Idx) const
Compute live ranges of allocas.
void print(raw_ostream &O)
StackLifetime(const Function &F, ArrayRef< const AllocaInst * > Allocas, LivenessType Type)
bool isReachable(const Instruction *I) const
Returns true if instruction is reachable from entry.
LiveRange getFullLiveRange() const
Returns a live range that represents an alloca that is live throughout the entire function.
const LiveRange & getLiveRange(const AllocaInst *AI) const
Returns a set of "interesting" instructions where the given alloca is live.
bool isAliveAfter(const AllocaInst *AI, const Instruction *I) const
Returns true if the alloca is alive after the instruction.
StringRef - Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
StringRef getName() const
Return a constant reference to the value's name.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
AllocaInst * findAllocaForValue(Value *V, bool OffsetZero=false)
Returns unique alloca where the value comes from, or nullptr.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto predecessors(const MachineBasicBlock *BB)
iterator_range< df_iterator< T > > depth_first(const T &G)
A CRTP mix-in to automatically provide informational APIs needed for passes.