diff --git a/llvm/include/llvm/Analysis/StackLifetime.h b/llvm/include/llvm/Analysis/StackLifetime.h index 6622433b4dcd..577d9ba177ea 100644 --- a/llvm/include/llvm/Analysis/StackLifetime.h +++ b/llvm/include/llvm/Analysis/StackLifetime.h @@ -14,6 +14,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PassManager.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -55,6 +56,8 @@ class StackLifetime { }; public: + class LifetimeAnnotationWriter; + /// This class represents a set of interesting instructions where an alloca is /// live. class LiveRange { @@ -71,6 +74,8 @@ public: } void join(const LiveRange &Other) { Bits |= Other.Bits; } + + bool test(unsigned Idx) const { return Bits.test(Idx); } }; private: @@ -135,6 +140,8 @@ public: assert(NumInst >= 0); return LiveRange(NumInst, true); } + + void print(raw_ostream &O); }; static inline raw_ostream &operator<<(raw_ostream &OS, const BitVector &V) { @@ -158,6 +165,16 @@ inline raw_ostream &operator<<(raw_ostream &OS, return OS << R.Bits; } +/// Printer pass for testing. +class StackLifetimePrinterPass + : public PassInfoMixin { + raw_ostream &OS; + +public: + explicit StackLifetimePrinterPass(raw_ostream &OS) : OS(OS) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + } // end namespace llvm #endif // LLVM_ANALYSIS_STACKLIFETIME_H diff --git a/llvm/lib/Analysis/StackLifetime.cpp b/llvm/lib/Analysis/StackLifetime.cpp index 7dde0ec38d57..efdfcf5c6c5c 100644 --- a/llvm/lib/Analysis/StackLifetime.cpp +++ b/llvm/lib/Analysis/StackLifetime.cpp @@ -8,17 +8,26 @@ #include "llvm/Analysis/StackLifetime.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Config/llvm-config.h" +#include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FormattedStream.h" +#include #include using namespace llvm; @@ -284,3 +293,66 @@ void StackLifetime::run() { calculateLiveIntervals(); LLVM_DEBUG(dumpLiveRanges()); } + +class StackLifetime::LifetimeAnnotationWriter + : public AssemblyAnnotationWriter { + const StackLifetime &SL; + SmallVector Names; + + void printInstrAlive(unsigned InstrNo, formatted_raw_ostream &OS) { + Names.clear(); + for (const auto &KV : SL.AllocaNumbering) { + if (SL.LiveRanges[KV.getSecond()].test(InstrNo)) + Names.push_back(KV.getFirst()->getName()); + } + llvm::sort(Names); + OS << " ; Alive: <" << llvm::join(Names, " ") << ">\n"; + } + + void printBBAlive(const BasicBlock *BB, bool Start, + formatted_raw_ostream &OS) { + auto ItBB = SL.BlockInstRange.find(BB); + if (ItBB == SL.BlockInstRange.end()) + return; // Unreachable. + unsigned InstrNo = + Start ? ItBB->getSecond().first : (ItBB->getSecond().second - 1); + printInstrAlive(InstrNo, OS); + } + + void emitBasicBlockStartAnnot(const BasicBlock *BB, + formatted_raw_ostream &OS) override { + printBBAlive(BB, true, OS); + } + void emitBasicBlockEndAnnot(const BasicBlock *BB, + formatted_raw_ostream &OS) override { + printBBAlive(BB, false, OS); + } + + void printInfoComment(const Value &V, formatted_raw_ostream &OS) override { + auto It = SL.InstructionNumbering.find(dyn_cast(&V)); + if (It == SL.InstructionNumbering.end()) + return; // Unintresting. + OS << "\n"; + printInstrAlive(It->getSecond(), OS); + } + +public: + LifetimeAnnotationWriter(const StackLifetime &SL) : SL(SL) {} +}; + +void StackLifetime::print(raw_ostream &OS) { + LifetimeAnnotationWriter AAW(*this); + F.print(OS, &AAW); +} + +PreservedAnalyses StackLifetimePrinterPass::run(Function &F, + FunctionAnalysisManager &AM) { + SmallVector Allocas; + for (auto &I : instructions(F)) + if (const AllocaInst *AI = dyn_cast(&I)) + Allocas.push_back(AI); + StackLifetime SL(F, Allocas); + SL.run(); + SL.print(OS); + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index c145ec42a960..49866f35e7fd 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -52,6 +52,7 @@ #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" #include "llvm/Analysis/ScopedNoAliasAA.h" +#include "llvm/Analysis/StackLifetime.h" #include "llvm/Analysis/StackSafetyAnalysis.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index dc037ff1d3ec..a38c651c673c 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -239,6 +239,7 @@ FUNCTION_PASS("print", PhiValuesPrinterPass(dbgs())) FUNCTION_PASS("print", RegionInfoPrinterPass(dbgs())) FUNCTION_PASS("print", ScalarEvolutionPrinterPass(dbgs())) FUNCTION_PASS("print", StackSafetyPrinterPass(dbgs())) +FUNCTION_PASS("print", StackLifetimePrinterPass(dbgs())) FUNCTION_PASS("reassociate", ReassociatePass()) FUNCTION_PASS("scalarizer", ScalarizerPass()) FUNCTION_PASS("sccp", SCCPPass()) diff --git a/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll b/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll new file mode 100644 index 000000000000..61d0dc2286f6 --- /dev/null +++ b/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll @@ -0,0 +1,766 @@ +; RUN: opt -passes='print' -disable-output %s 2>&1 | FileCheck %s + +define void @f() { +; CHECK-LABEL: define void @f() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + %z0 = bitcast i32* %z to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %z) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %z0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %z0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @no_markers() { +; CHECK-LABEL: define void @no_markers() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: +} + +define void @g() { +; CHECK-LABEL: define void @g() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %z = alloca i64, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + %z0 = bitcast i64* %z to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: <> + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0) +; CHECK-NEXT: Alive: + + call void @capture64(i64* %z) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %z0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %z0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @h() { +; CHECK-LABEL: define void @h() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 16 + %z = alloca i64, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + %z0 = bitcast i64* %z to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %z0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + call void @capture32(i32* %y) + call void @capture64(i64* %z) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %z0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %z0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @i(i1 zeroext %a, i1 zeroext %b) { +; CHECK-LABEL: define void @i(i1 zeroext %a, i1 zeroext %b) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x1 = alloca i64, align 8 + %x2 = alloca i64, align 8 + %y = alloca i64, align 8 + %y1 = alloca i64, align 8 + %y2 = alloca i64, align 8 + %z = alloca i64, align 8 + %z1 = alloca i64, align 8 + %z2 = alloca i64, align 8 + %0 = bitcast i64* %x1 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0) +; CHECK-NEXT: Alive: + + %1 = bitcast i64* %x2 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %1) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %1) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %x1) + call void @capture64(i64* nonnull %x2) + br i1 %a, label %if.then, label %if.else4 +; CHECK: br i1 %a, label %if.then, label %if.else4 +; CHECK-NEXT: Alive: + +if.then: ; preds = %entry +; CHECK: if.then: +; CHECK-NEXT: Alive: + %2 = bitcast i64* %y to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %2) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %2) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %y) + br i1 %b, label %if.then3, label %if.else +; CHECK: br i1 %b, label %if.then3, label %if.else +; CHECK-NEXT: Alive: + +if.then3: ; preds = %if.then +; CHECK: if.then3: +; CHECK-NEXT: Alive: + %3 = bitcast i64* %y1 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %3) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %3) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %y1) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %3) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %3) +; CHECK-NEXT: Alive: + + br label %if.end +; CHECK: br label %if.end +; CHECK-NEXT: Alive: + +if.else: ; preds = %if.then +; CHECK: if.else: +; CHECK-NEXT: Alive: + %4 = bitcast i64* %y2 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %4) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %4) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %y2) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %4) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %4) +; CHECK-NEXT: Alive: + + br label %if.end +; CHECK: br label %if.end +; CHECK-NEXT: Alive: + +if.end: ; preds = %if.else, %if.then3 +; CHECK: if.end: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %2) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %2) +; CHECK-NEXT: Alive: + + br label %if.end9 +; CHECK: br label %if.end9 +; CHECK-NEXT: Alive: + +if.else4: ; preds = %entry +; CHECK: if.else4: +; CHECK-NEXT: Alive: + %5 = bitcast i64* %z to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %5) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %5) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %z) + br i1 %b, label %if.then6, label %if.else7 +; CHECK: br i1 %b, label %if.then6, label %if.else7 +; CHECK-NEXT: Alive: + +if.then6: ; preds = %if.else4 +; CHECK: if.then6: +; CHECK-NEXT: Alive: + %6 = bitcast i64* %z1 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %6) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %z1) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %6) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %6) +; CHECK-NEXT: Alive: + + br label %if.end8 +; CHECK: br label %if.end8 +; CHECK-NEXT: Alive: + +if.else7: ; preds = %if.else4 +; CHECK: if.else7: +; CHECK-NEXT: Alive: + %7 = bitcast i64* %z2 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %7) +; CHECK-NEXT: Alive: + + call void @capture64(i64* nonnull %z2) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %7) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %7) +; CHECK-NEXT: Alive: + + br label %if.end8 +; CHECK: br label %if.end8 +; CHECK-NEXT: Alive: + +if.end8: ; preds = %if.else7, %if.then6 +; CHECK: if.end8: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %5) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %5) +; CHECK-NEXT: Alive: + + br label %if.end9 +; CHECK: br label %if.end9 +; CHECK-NEXT: Alive: + +if.end9: ; preds = %if.end8, %if.end +; CHECK: if.end9: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @no_merge1(i1 %d) { +; CHECK-LABEL: define void @no_merge1(i1 %d) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + br i1 %d, label %bb2, label %bb3 +; CHECK: br i1 %d, label %bb2, label %bb3 +; CHECK-NEXT: Alive: + +bb2: ; preds = %entry +; CHECK: bb2: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> + +bb3: ; preds = %entry +; CHECK: bb3: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @merge1(i1 %d) { +; CHECK-LABEL: define void @merge1(i1 %d) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: <> + + br i1 %d, label %bb2, label %bb3 +; CHECK: br i1 %d, label %bb2, label %bb3 +; CHECK-NEXT: Alive: <> + +bb2: ; preds = %entry +; CHECK: bb2: +; CHECK-NEXT: Alive: <> + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> + +bb3: ; preds = %entry +; CHECK: bb3: +; CHECK-NEXT: Alive: <> + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @merge2_noend(i1 %d) { +; CHECK-LABEL: define void @merge2_noend(i1 %d) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: <> + + br i1 %d, label %bb2, label %bb3 +; CHECK: br i1 %d, label %bb2, label %bb3 +; CHECK-NEXT: Alive: <> + +bb2: ; preds = %entry +; CHECK: bb2: +; CHECK-NEXT: Alive: <> + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: + +bb3: ; preds = %entry +; CHECK: bb3: +; CHECK-NEXT: Alive: <> + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @merge3_noend(i1 %d) { +; CHECK-LABEL: define void @merge3_noend(i1 %d) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %x) + br i1 %d, label %bb2, label %bb3 +; CHECK: br i1 %d, label %bb2, label %bb3 +; CHECK-NEXT: Alive: + +bb2: ; preds = %entry +; CHECK: bb2: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: <> + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: + +bb3: ; preds = %entry +; CHECK: bb3: +; CHECK-NEXT: Alive: + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: +} + +define void @nomerge4_nostart(i1 %d) { +; CHECK-LABEL: define void @nomerge4_nostart(i1 %d) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: + %x = alloca i32, align 4 + %y = alloca i32, align 4 + %x0 = bitcast i32* %x to i8* + %y0 = bitcast i32* %y to i8* + call void @capture32(i32* %x) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %x0) +; CHECK-NEXT: Alive: + + br i1 %d, label %bb2, label %bb3 +; CHECK: br i1 %d, label %bb2, label %bb3 +; CHECK-NEXT: Alive: + +bb2: ; preds = %entry +; CHECK: bb2: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %y0) +; CHECK-NEXT: Alive: + + call void @capture32(i32* %y) + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: + +bb3: ; preds = %entry +; CHECK: bb3: +; CHECK-NEXT: Alive: + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: +} + +define void @array_merge() { +; CHECK-LABEL: define void @array_merge() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %A.i1 = alloca [100 x i32], align 4 + %B.i2 = alloca [100 x i32], align 4 + %A.i = alloca [100 x i32], align 4 + %B.i = alloca [100 x i32], align 4 + %0 = bitcast [100 x i32]* %A.i to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0) +; CHECK-NEXT: Alive: + + %1 = bitcast [100 x i32]* %B.i to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %1) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %1) +; CHECK-NEXT: Alive: + + call void @capture100x32([100 x i32]* %A.i) + call void @capture100x32([100 x i32]* %B.i) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1) +; CHECK-NEXT: Alive: <> + + %2 = bitcast [100 x i32]* %A.i1 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %2) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %2) +; CHECK-NEXT: Alive: + + %3 = bitcast [100 x i32]* %B.i2 to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %3) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %3) +; CHECK-NEXT: Alive: + + call void @capture100x32([100 x i32]* %A.i1) + call void @capture100x32([100 x i32]* %B.i2) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %2) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %2) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %3) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %3) +; CHECK-NEXT: Alive: <> + + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: <> +} + +define void @myCall_pr15707() { +; CHECK-LABEL: define void @myCall_pr15707() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %buf1 = alloca i8, i32 100000, align 16 + %buf2 = alloca i8, i32 100000, align 16 + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf1) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf1) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %buf1) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %buf1) +; CHECK-NEXT: Alive: <> + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf1) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf1) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf2) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %buf2) +; CHECK-NEXT: Alive: + + call void @capture8(i8* %buf1) + call void @capture8(i8* %buf2) + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: +} + +define void @bad_range() { +; CHECK-LABEL: define void @bad_range() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: + %A.i1 = alloca [100 x i32], align 4 + %B.i2 = alloca [100 x i32], align 4 + %A.i = alloca [100 x i32], align 4 + %B.i = alloca [100 x i32], align 4 + %0 = bitcast [100 x i32]* %A.i to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %0) +; CHECK-NEXT: Alive: + + %1 = bitcast [100 x i32]* %B.i to i8* + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %1) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %1) +; CHECK-NEXT: Alive: + + call void @capture100x32([100 x i32]* %A.i) + call void @capture100x32([100 x i32]* %B.i) + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %0) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %1) +; CHECK-NEXT: Alive: + + br label %block2 +; CHECK: br label %block2 +; CHECK-NEXT: Alive: + +block2: ; preds = %entry +; CHECK: block2: +; CHECK-NEXT: Alive: + call void @capture100x32([100 x i32]* %A.i) + call void @capture100x32([100 x i32]* %B.i) + ret void +; CHECK: ret void +; CHECK-NEXT: Alive: +} + +%struct.Klass = type { i32, i32 } + +define i32 @shady_range(i32 %argc, i8** nocapture %argv) { +; CHECK-LABEL: define i32 @shady_range(i32 %argc, i8** nocapture %argv) +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %a.i = alloca [4 x %struct.Klass], align 16 + %b.i = alloca [4 x %struct.Klass], align 16 + %a8 = bitcast [4 x %struct.Klass]* %a.i to i8* + %b8 = bitcast [4 x %struct.Klass]* %b.i to i8* + %z2 = getelementptr inbounds [4 x %struct.Klass], [4 x %struct.Klass]* %a.i, i64 0, i64 0, i32 0 + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a8) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %a8) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 -1, i8* %b8) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* %b8) +; CHECK-NEXT: Alive: + + call void @capture8(i8* %a8) + call void @capture8(i8* %b8) + %z3 = load i32, i32* %z2, align 16 + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %a8) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %a8) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.end.p0i8(i64 -1, i8* %b8) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 -1, i8* %b8) +; CHECK-NEXT: Alive: <> + + ret i32 %z3 +; CHECK: ret i32 %z3 +; CHECK-NEXT: Alive: <> +} + +define void @end_loop() { +; CHECK-LABEL: define void @end_loop() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i8, align 4 + call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) +; CHECK-NEXT: Alive: + + br label %l2 +; CHECK: br label %l2 +; CHECK-NEXT: Alive: + +l2: ; preds = %l2, %entry +; CHECK: l2: +; CHECK-NEXT: Alive: + call void @capture8(i8* %x) + call void @llvm.lifetime.end.p0i8(i64 4, i8* %x) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 4, i8* %x) +; CHECK-NEXT: Alive: <> + + br label %l2 +; CHECK: br label %l2 +; CHECK-NEXT: Alive: <> +} + +define void @start_loop() { +; CHECK-LABEL: define void @start_loop() +entry: +; CHECK: entry: +; CHECK-NEXT: Alive: <> + %x = alloca i8, align 4 + %y = alloca i8, align 4 + call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) +; CHECK-NEXT: Alive: + + br label %l2 +; CHECK: br label %l2 +; CHECK-NEXT: Alive: + +l2: ; preds = %l2, %entry +; CHECK: l2: +; CHECK-NEXT: Alive: + call void @llvm.lifetime.start.p0i8(i64 4, i8* %y) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 4, i8* %y) +; CHECK-NEXT: Alive: + + call void @capture8(i8* %y) + call void @llvm.lifetime.end.p0i8(i64 4, i8* %y) +; CHECK: call void @llvm.lifetime.end.p0i8(i64 4, i8* %y) +; CHECK-NEXT: Alive: + + call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) +; CHECK: call void @llvm.lifetime.start.p0i8(i64 4, i8* %x) +; CHECK-NEXT: Alive: + + call void @capture8(i8* %x) + br label %l2 +; CHECK: br label %l2 +; CHECK-NEXT: Alive: +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) +declare void @capture8(i8*) +declare void @capture32(i32*) +declare void @capture64(i64*) +declare void @capture100x32([100 x i32]*)