From 92c55a315eab455d5fed2625fe0f61f88cb25499 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 21 Jul 2025 15:04:50 +0200 Subject: [PATCH] [IR] Only allow lifetime.start/end on allocas (#149310) lifetime.start and lifetime.end are primarily intended for use on allocas, to enable stack coloring and other liveness optimizations. This is necessary because all (static) allocas are hoisted into the entry block, so lifetime markers are the only way to convey the actual lifetimes. However, lifetime.start and lifetime.end are currently *allowed* to be used on non-alloca pointers. We don't actually do this in practice, but just the mere fact that this is possible breaks the core purpose of the lifetime markers, which is stack coloring of allocas. Stack coloring can only work correctly if all lifetime markers for an alloca are analyzable. * If a lifetime marker may operate on multiple allocas via a select/phi, we don't know which lifetime actually starts/ends and handle it incorrectly (https://github.com/llvm/llvm-project/issues/104776). * Stack coloring operates on the assumption that all lifetime markers are visible, and not, for example, hidden behind a function call or escaped pointer. It's not possible to change this, as part of the purpose of lifetime markers is that they work even in the presence of escaped pointers, where simple use analysis is insufficient. I don't think there is any way to have coherent semantics for lifetime markers on allocas, while also permitting them on arbitrary pointer values. This PR restricts lifetimes to operate on allocas only. As a followup, I will also drop the size argument, which is superfluous if we always operate on an alloca. (This change also renders various code handling lifetime markers on non-alloca dead. I plan to clean up that kind of code after dropping the size argument as well.) In practice, I've only found a few places that currently produce lifetimes on non-allocas: * CoroEarly replaces the promise alloca with the result of an intrinsic, which will later be replaced back with an alloca. I think this is the only place where there is some legitimate loss of functionality, but I don't think this is particularly important (I don't think we'd expect the promise in a coroutine to admit useful lifetime optimization.) * SafeStack moves unsafe allocas onto a separate frame. We can safely drop lifetimes here, as SafeStack performs its own stack coloring. * Similar for AddressSanitizer, it also moves allocas into separate memory. * LSR sometimes replaces the lifetime argument with a GEP chain of the alloca (where the offsets ultimately cancel out). This is just unnecessary. (Fixed separately in https://github.com/llvm/llvm-project/pull/149492.) * InferAddrSpaces sometimes makes lifetimes operate on an addrspacecast of an alloca. I don't think this is necessary. --- llvm/docs/LangRef.rst | 32 +- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 8 +- llvm/lib/CodeGen/SafeStack.cpp | 7 + llvm/lib/IR/AutoUpgrade.cpp | 44 ++- llvm/lib/IR/Verifier.cpp | 5 + .../Target/SPIRV/SPIRVPrepareFunctions.cpp | 6 +- llvm/lib/Transforms/Coroutines/CoroEarly.cpp | 6 + .../Instrumentation/AddressSanitizer.cpp | 18 + .../Transforms/Scalar/InferAddressSpaces.cpp | 2 + llvm/test/Analysis/BasicAA/modref.ll | 14 +- .../CallGraph/ignore-assumelike-calls.ll | 13 +- .../Analysis/CostModel/X86/free-intrinsics.ll | 15 +- .../CostModel/free-intrinsics-datalayout.ll | 15 +- .../CostModel/free-intrinsics-no_info.ll | 15 +- .../Analysis/MemorySSA/lifetime-simple.ll | 6 +- llvm/test/Analysis/MemorySSA/pr43427.ll | 7 +- llvm/test/Analysis/MemorySSA/pr43438.ll | 5 +- .../Analysis/StackSafetyAnalysis/lifetime.ll | 77 ----- .../autoupgrade-lifetime-intrinsics.ll | 57 ++++ .../GlobalISel/irtranslator-switch-split.ll | 10 +- llvm/test/CodeGen/AArch64/stack-tagging.ll | 50 --- .../Thumb2/ifcvt-rescan-bug-2016-08-22.ll | 3 +- llvm/test/CodeGen/X86/select-optimize.ll | 6 +- llvm/test/CodeGen/X86/swap.ll | 9 +- .../AddressSanitizer/asan-funclet.ll | 26 +- .../AddressSanitizer/lifetime-throw.ll | 8 +- .../AddressSanitizer/lifetime.ll | 174 ---------- .../stack-poisoning-and-lifetime-be.ll | 12 - .../stack-poisoning-and-lifetime.ll | 46 --- .../Instrumentation/MemorySanitizer/alloca.ll | 73 ----- .../Transforms/Attributor/heap_to_stack.ll | 20 -- .../Attributor/heap_to_stack_gpu.ll | 21 -- .../CodeExtractor/PartialInlineAlloca5.ll | 4 +- .../CodeExtractor/live_shrink_gep.ll | 7 +- .../AArch64/const-hoist-intrinsics.ll | 6 +- llvm/test/Transforms/DCE/basic.ll | 42 --- .../DeadStoreElimination/libcalls.ll | 13 - .../DeadStoreElimination/lifetime.ll | 12 +- .../multiblock-multipath.ll | 7 +- llvm/test/Transforms/EarlyCSE/memoryssa.ll | 25 +- llvm/test/Transforms/GVN/opt-remarks.ll | 3 +- .../lifetime-markers-on-inputs-1.ll | 5 +- .../InferAddressSpaces/NVPTX/lifetime.ll | 11 +- llvm/test/Transforms/Inline/alloca-bonus.ll | 5 - .../test/Transforms/Inline/redundant-loads.ll | 3 - llvm/test/Transforms/InstCombine/deadcode.ll | 5 +- .../Transforms/InstCombine/malloc-free.ll | 2 - .../InstCombine/scalable-vector-struct.ll | 4 - .../multiply-fused-lifetime-ends.ll | 307 ++---------------- llvm/test/Transforms/MemCpyOpt/lifetime.ll | 19 -- .../test/Transforms/MemCpyOpt/memcpy-undef.ll | 18 +- .../MemCpyOpt/memset-memcpy-oversized.ll | 23 +- .../Transforms/MemCpyOpt/preserve-memssa.ll | 15 - llvm/test/Transforms/MoveAutoInit/clobber.ll | 22 +- .../test/Transforms/NewGVN/lifetime-simple.ll | 6 +- .../inlined-autorelease-return-value.ll | 8 +- .../Transforms/SafeStack/X86/coloring2.ll | 37 --- llvm/test/Verifier/intrinsic-immarg.ll | 6 +- llvm/test/Verifier/opaque-ptr.ll | 6 +- .../Import/intrinsic-prefer-unregistered.ll | 11 +- mlir/test/Target/LLVMIR/Import/intrinsic.ll | 7 +- .../test/Target/LLVMIR/llvmir-intrinsics.mlir | 8 +- .../invariant_load_in_non_affine_subregion.ll | 4 +- 63 files changed, 376 insertions(+), 1085 deletions(-) create mode 100644 llvm/test/Assembler/autoupgrade-lifetime-intrinsics.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 9a32f0cd15dd..8a8a6505d902 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -26639,19 +26639,14 @@ Arguments: The first argument is a constant integer representing the size of the object, or -1 if it is variable sized. The second argument is a pointer -to the object. +to an ``alloca`` instruction. Semantics: """""""""" -If ``ptr`` is a stack-allocated object and it points to the first byte of -the object, the object is initially marked as dead. -``ptr`` is conservatively considered as a non-stack-allocated object if -the stack coloring algorithm that is used in the optimization pipeline cannot -conclude that ``ptr`` is a stack-allocated object. - -After '``llvm.lifetime.start``', the stack object that ``ptr`` points is marked -as alive and has an uninitialized value. +The stack-allocated object that ``ptr`` points to is initially marked as dead. +After '``llvm.lifetime.start``', the stack object is marked as alive and has an +uninitialized value. The stack object is marked as dead when either :ref:`llvm.lifetime.end ` to the alloca is executed or the function returns. @@ -26661,11 +26656,6 @@ After :ref:`llvm.lifetime.end ` is called, The second '``llvm.lifetime.start``' call marks the object as alive, but it does not change the address of the object. -If ``ptr`` is a non-stack-allocated object, it does not point to the first -byte of the object or it is a stack object that is already alive, it simply -fills all bytes of the object with ``poison``. - - .. _int_lifeend: '``llvm.lifetime.end``' Intrinsic @@ -26689,24 +26679,16 @@ Arguments: The first argument is a constant integer representing the size of the object, or -1 if it is variable sized. The second argument is a pointer -to the object. +to an ``alloca`` instruction. Semantics: """""""""" -If ``ptr`` is a stack-allocated object and it points to the first byte of the -object, the object is dead. -``ptr`` is conservatively considered as a non-stack-allocated object if -the stack coloring algorithm that is used in the optimization pipeline cannot -conclude that ``ptr`` is a stack-allocated object. +The stack-allocated object that ``ptr`` points to becomes dead after the call +to this intrinsic. Calling ``llvm.lifetime.end`` on an already dead alloca is no-op. -If ``ptr`` is a non-stack-allocated object or it does not point to the first -byte of the object, it is equivalent to simply filling all bytes of the object -with ``poison``. - - '``llvm.invariant.start``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 6e938723c3c1..f76368357a9c 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -7124,9 +7124,11 @@ Error BitcodeReader::materializeModule() { if (CallInst *CI = dyn_cast(U)) UpgradeIntrinsicCall(CI, I.second); } - if (!I.first->use_empty()) - I.first->replaceAllUsesWith(I.second); - I.first->eraseFromParent(); + if (I.first != I.second) { + if (!I.first->use_empty()) + I.first->replaceAllUsesWith(I.second); + I.first->eraseFromParent(); + } } UpgradedIntrinsics.clear(); diff --git a/llvm/lib/CodeGen/SafeStack.cpp b/llvm/lib/CodeGen/SafeStack.cpp index 996207034d07..908ed9617261 100644 --- a/llvm/lib/CodeGen/SafeStack.cpp +++ b/llvm/lib/CodeGen/SafeStack.cpp @@ -614,6 +614,13 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack( Use &U = *AI->use_begin(); Instruction *User = cast(U.getUser()); + // Drop lifetime markers now that this is no longer an alloca. + // SafeStack has already performed its own stack coloring. + if (User->isLifetimeStartOrEnd()) { + User->eraseFromParent(); + continue; + } + Instruction *InsertBefore; if (auto *PHI = dyn_cast(User)) InsertBefore = PHI->getIncomingBlock(U)->getTerminator(); diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 86285a03c66b..28ed1e520ce5 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -1310,6 +1310,18 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn, return true; } break; + case 'l': + if (Name.starts_with("lifetime.start") || + Name.starts_with("lifetime.end")) { + // Unless remangling is required, do not upgrade the function declaration, + // but do upgrade the calls. + if (auto Result = llvm::Intrinsic::remangleIntrinsicFunction(F)) + NewFn = *Result; + else + NewFn = F; + return true; + } + break; case 'm': { // Updating the memory intrinsics (memcpy/memmove/memset) that have an // alignment parameter to embedding the alignment as an attribute of @@ -1629,7 +1641,6 @@ bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn, NewFn = nullptr; bool Upgraded = upgradeIntrinsicFunction1(F, NewFn, CanUpgradeDebugIntrinsicsToRecords); - assert(F != NewFn && "Intrinsic function upgraded to the same function"); // Upgrade intrinsic attributes. This does not change the function. if (NewFn) @@ -4570,6 +4581,9 @@ void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) { } const auto &DefaultCase = [&]() -> void { + if (F == NewFn) + return; + if (CI->getFunctionType() == NewFn->getFunctionType()) { // Handle generic mangling change. assert( @@ -5109,6 +5123,31 @@ void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) { MTI->setSourceAlignment(Align->getMaybeAlignValue()); break; } + + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: { + Value *Size = CI->getArgOperand(0); + Value *Ptr = CI->getArgOperand(1); + if (isa(Ptr)) { + DefaultCase(); + return; + } + + // Try to strip pointer casts, such that the lifetime works on an alloca. + Ptr = Ptr->stripPointerCasts(); + if (isa(Ptr)) { + // Don't use NewFn, as we might have looked through an addrspacecast. + if (NewFn->getIntrinsicID() == Intrinsic::lifetime_start) + NewCall = Builder.CreateLifetimeStart(Ptr, cast(Size)); + else + NewCall = Builder.CreateLifetimeEnd(Ptr, cast(Size)); + break; + } + + // Otherwise remove the lifetime marker. + CI->eraseFromParent(); + return; + } } assert(NewCall && "Should have either set this variable or returned through " "the default case"); @@ -5131,7 +5170,8 @@ void llvm::UpgradeCallsToIntrinsic(Function *F) { UpgradeIntrinsicCall(CB, NewFn); // Remove old function, no longer used, from the module. - F->eraseFromParent(); + if (F != NewFn) + F->eraseFromParent(); } } diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index e7b491e76724..ef37f70bf8ae 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -6720,6 +6720,11 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) { "llvm.threadlocal.address operand isThreadLocal() must be true"); break; } + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: + Check(isa(Call.getArgOperand(1)), + "llvm.lifetime.start/end can only be used on alloca", &Call); + break; }; // Verify that there aren't any unmediated control transfers between funclets. diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp index 2bffbf73b574..6766bd866cd2 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp @@ -380,7 +380,7 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { bool Changed = false; const SPIRVSubtarget &STI = TM.getSubtarget(*F); for (BasicBlock &BB : *F) { - for (Instruction &I : BB) { + for (Instruction &I : make_early_inc_range(BB)) { auto Call = dyn_cast(&I); if (!Call) continue; @@ -408,12 +408,16 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) { if (!STI.isShader()) { Changed |= toSpvOverloadedIntrinsic( II, Intrinsic::SPVIntrinsics::spv_lifetime_start, {1}); + } else { + II->eraseFromParent(); } break; case Intrinsic::lifetime_end: if (!STI.isShader()) { Changed |= toSpvOverloadedIntrinsic( II, Intrinsic::SPVIntrinsics::spv_lifetime_end, {1}); + } else { + II->eraseFromParent(); } break; case Intrinsic::ptr_annotation: diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp index e279fec18bdb..6561b1cd4ade 100644 --- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp @@ -170,6 +170,12 @@ void Lowerer::hidePromiseAlloca(CoroIdInst *CoroId, CoroBeginInst *CoroBegin) { auto *PI = Builder.CreateIntrinsic( Builder.getPtrTy(), Intrinsic::coro_promise, Arg, {}, "promise.addr"); PI->setCannotDuplicate(); + // Remove lifetime markers, as these are only allowed on allocas. + for (User *U : make_early_inc_range(PA->users())) { + auto *I = cast(U); + if (I->isLifetimeStartOrEnd()) + I->eraseFromParent(); + } PA->replaceUsesWithIf(PI, [CoroId](Use &U) { bool IsBitcast = U == U.getUser()->stripPointerCasts(); bool IsCoroId = U.getUser() == CoroId; diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 5957940add57..fbaa65164156 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -3637,6 +3637,7 @@ void FunctionStackPoisoner::processStaticAllocas() { "Variable descriptions relative to ASan stack base will be dropped"); // Replace Alloca instructions with base+offset. + SmallVector NewAllocaPtrs; for (const auto &Desc : SVD) { AllocaInst *AI = Desc.AI; replaceDbgDeclare(AI, LocalStackBaseAllocaPtr, DIB, DIExprFlags, @@ -3645,6 +3646,7 @@ void FunctionStackPoisoner::processStaticAllocas() { IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, Desc.Offset)), AI->getType()); AI->replaceAllUsesWith(NewAllocaPtr); + NewAllocaPtrs.push_back(NewAllocaPtr); } // The left-most redzone has enough space for at least 4 pointers. @@ -3694,6 +3696,15 @@ void FunctionStackPoisoner::processStaticAllocas() { } } + // Remove lifetime markers now that these are no longer allocas. + for (Value *NewAllocaPtr : NewAllocaPtrs) { + for (User *U : make_early_inc_range(NewAllocaPtr->users())) { + auto *I = cast(U); + if (I->isLifetimeStartOrEnd()) + I->eraseFromParent(); + } + } + SmallVector ShadowClean(ShadowAfterScope.size(), 0); SmallVector ShadowAfterReturn; @@ -3829,6 +3840,13 @@ void FunctionStackPoisoner::handleDynamicAllocaCall(AllocaInst *AI) { Value *NewAddressPtr = IRB.CreateIntToPtr(NewAddress, AI->getType()); + // Remove lifetime markers now that this is no longer an alloca. + for (User *U : make_early_inc_range(AI->users())) { + auto *I = cast(U); + if (I->isLifetimeStartOrEnd()) + I->eraseFromParent(); + } + // Replace all uses of AddessReturnedByAlloca with NewAddressPtr. AI->replaceAllUsesWith(NewAddressPtr); diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp index 66836ef05d5d..85ee824b6712 100644 --- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp +++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp @@ -430,6 +430,8 @@ bool InferAddressSpacesImpl::rewriteIntrinsicOperands(IntrinsicInst *II, } case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: { + // Always force lifetime markers to work directly on the alloca. + NewV = NewV->stripPointerCasts(); Function *NewDecl = Intrinsic::getOrInsertDeclaration( M, II->getIntrinsicID(), {NewV->getType()}); II->setArgOperand(1, NewV); diff --git a/llvm/test/Analysis/BasicAA/modref.ll b/llvm/test/Analysis/BasicAA/modref.ll index 0619f8e615b8..1aab28f3f187 100644 --- a/llvm/test/Analysis/BasicAA/modref.ll +++ b/llvm/test/Analysis/BasicAA/modref.ll @@ -67,27 +67,33 @@ define i8 @test2a(ptr %P) { ret i8 %A } -define void @test3(ptr %P, i8 %X) { +define void @test3(i8 %X) { ; CHECK-LABEL: @test3( -; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 2 +; CHECK-NEXT: [[P:%.*]] = alloca i64, align 8 +; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i32 2 ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[P]]) ; CHECK-NEXT: store i8 2, ptr [[P2]], align 1 +; CHECK-NEXT: call void @external(ptr [[P]]) ; CHECK-NEXT: ret void ; + %P = alloca i64 %Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead. %P2 = getelementptr i8, ptr %P, i32 2 store i8 %Y, ptr %P2 ;; Not read by lifetime.end, should be removed. call void @llvm.lifetime.end.p0(i64 1, ptr %P) store i8 2, ptr %P2 + call void @external(ptr %P) ret void } -define void @test3a(ptr %P, i8 %X) { +define void @test3a(i8 %X) { ; CHECK-LABEL: @test3a( -; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 10, ptr [[P:%.*]]) +; CHECK-NEXT: [[P:%.*]] = alloca i64, align 8 +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 10, ptr [[P]]) ; CHECK-NEXT: ret void ; + %P = alloca i64 %Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead. %P2 = getelementptr i8, ptr %P, i32 2 diff --git a/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll b/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll index 658d73804c17..1c9d20193869 100644 --- a/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll +++ b/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll @@ -10,7 +10,7 @@ ; CHECK-EMPTY: ; CHECK-NEXT: Call graph node for function: 'bitcast_only'<<{{.*}}>> #uses=0 ; CHECK-EMPTY: -; CHECK-NEXT: Call graph node for function: 'llvm.lifetime.start.p0'<<{{.*}}>> #uses=3 +; CHECK-NEXT: Call graph node for function: 'llvm.lifetime.start.p0'<<{{.*}}>> #uses=2 ; CHECK-EMPTY: ; CHECK-NEXT: Call graph node for function: 'llvm.memset.p0.i64'<<{{.*}}>> #uses=2 ; CHECK-EMPTY: @@ -25,18 +25,11 @@ ; CHECK-NEXT: Call graph node for function: 'used_by_lifetime'<<{{.*}}>> #uses=0 ; CHECK-NEXT: CS<{{.*}}> calls function 'llvm.lifetime.start.p0' ; CHECK-EMPTY: -; CHECK-NEXT: Call graph node for function: 'used_by_lifetime_cast'<<{{.*}}>> #uses=0 -; CHECK-NEXT: CS<{{.*}}> calls function 'llvm.lifetime.start.p0' -; CHECK-EMPTY: define internal void @used_by_lifetime() { entry: - call void @llvm.lifetime.start.p0(i64 4, ptr @used_by_lifetime) - ret void -} - -define internal void @used_by_lifetime_cast() addrspace(1) { - call void @llvm.lifetime.start.p0(i64 4, ptr addrspacecast (ptr addrspace(1) @used_by_lifetime_cast to ptr)) + %a = alloca i8 + call void @llvm.lifetime.start.p0(i64 4, ptr %a) ret void } diff --git a/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll b/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll index a8c5c43c3a9f..3a54428bd829 100644 --- a/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll +++ b/llvm/test/Analysis/CostModel/X86/free-intrinsics.ll @@ -4,6 +4,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-LABEL: 'trivially_free' +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %alloca = alloca i8, align 1 ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32.p0(i32 undef, ptr undef, ptr undef, i32 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !3) @@ -13,14 +14,15 @@ define i32 @trivially_free() { ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a4 = call i1 @llvm.is.constant.i32(i32 undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 true, i1 true, i1 true) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call ptr @llvm.ptr.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; ; CHECK-THROUGHPUT-LABEL: 'trivially_free' +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %alloca = alloca i8, align 1 ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32.p0(i32 undef, ptr undef, ptr undef, i32 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !3) @@ -30,13 +32,14 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a4 = call i1 @llvm.is.constant.i32(i32 undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 true, i1 true, i1 true) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call ptr @llvm.ptr.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret i32 undef ; + %alloca = alloca i8 %a0 = call i32 @llvm.annotation.i32(i32 undef, ptr undef, ptr undef, i32 undef) call void @llvm.assume(i1 undef) call void @llvm.experimental.noalias.scope.decl(metadata !4) @@ -46,8 +49,8 @@ define i32 @trivially_free() { %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) %a4 = call i1 @llvm.is.constant.i32(i32 undef) - call void @llvm.lifetime.start.p0(i64 1, ptr undef) - call void @llvm.lifetime.end.p0(i64 1, ptr undef) + call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) + call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 1, i1 1, i1 1) %a6 = call ptr @llvm.ptr.annotation.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) call void @llvm.var.annotation(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) diff --git a/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll b/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll index 560af3d2b48f..96064dc3af60 100644 --- a/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll +++ b/llvm/test/Analysis/CostModel/free-intrinsics-datalayout.ll @@ -6,6 +6,7 @@ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" define i32 @trivially_free() { ; CHECK-SIZE-LABEL: 'trivially_free' +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %alloca = alloca i8, align 4 ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32.p0(i32 undef, ptr undef, ptr undef, i32 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !3) @@ -15,8 +16,8 @@ define i32 @trivially_free() { ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a4 = call i1 @llvm.is.constant.i32(i32 undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 true, i1 true, i1 true) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call ptr @llvm.ptr.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a7 = call i1 @llvm.allow.ubsan.check(i8 123) @@ -25,6 +26,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; ; CHECK-THROUGHPUT-LABEL: 'trivially_free' +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %alloca = alloca i8, align 4 ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32.p0(i32 undef, ptr undef, ptr undef, i32 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !3) @@ -34,8 +36,8 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a4 = call i1 @llvm.is.constant.i32(i32 undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 true, i1 true, i1 true) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call ptr @llvm.ptr.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a7 = call i1 @llvm.allow.ubsan.check(i8 123) @@ -43,6 +45,7 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; + %alloca = alloca i8 %a0 = call i32 @llvm.annotation.i32(i32 undef, ptr undef, ptr undef, i32 undef) call void @llvm.assume(i1 undef) call void @llvm.experimental.noalias.scope.decl(metadata !4) @@ -52,8 +55,8 @@ define i32 @trivially_free() { %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) %a4 = call i1 @llvm.is.constant.i32(i32 undef) - call void @llvm.lifetime.start.p0(i64 1, ptr undef) - call void @llvm.lifetime.end.p0(i64 1, ptr undef) + call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) + call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 1, i1 1, i1 1) %a6 = call ptr @llvm.ptr.annotation.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) %a7 = call i1 @llvm.allow.ubsan.check(i8 123) diff --git a/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll b/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll index 53828f2f0727..f989ebe592a1 100644 --- a/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll +++ b/llvm/test/Analysis/CostModel/free-intrinsics-no_info.ll @@ -4,6 +4,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-LABEL: 'trivially_free' +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %alloca = alloca i8, align 1 ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32.p0(i32 undef, ptr undef, ptr undef, i32 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !3) @@ -13,8 +14,8 @@ define i32 @trivially_free() { ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a4 = call i1 @llvm.is.constant.i32(i32 undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr undef) -; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr undef) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) +; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 true, i1 true, i1 true) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call ptr @llvm.ptr.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) @@ -23,6 +24,7 @@ define i32 @trivially_free() { ; CHECK-SIZE-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; ; CHECK-THROUGHPUT-LABEL: 'trivially_free' +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %alloca = alloca i8, align 1 ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a0 = call i32 @llvm.annotation.i32.p0(i32 undef, ptr undef, ptr undef, i32 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.assume(i1 undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.experimental.noalias.scope.decl(metadata !3) @@ -32,8 +34,8 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a4 = call i1 @llvm.is.constant.i32(i32 undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr undef) -; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr undef) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) +; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 true, i1 true, i1 true) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a6 = call ptr @llvm.ptr.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: call void @llvm.var.annotation.p0.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) @@ -41,6 +43,7 @@ define i32 @trivially_free() { ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 0 for instruction: %a8 = call i1 @llvm.allow.runtime.check(metadata !"test_check") ; CHECK-THROUGHPUT-NEXT: Cost Model: Found an estimated cost of 1 for instruction: ret i32 undef ; + %alloca = alloca i8 %a0 = call i32 @llvm.annotation.i32(i32 undef, ptr undef, ptr undef, i32 undef) call void @llvm.assume(i1 undef) call void @llvm.experimental.noalias.scope.decl(metadata !4) @@ -50,8 +53,8 @@ define i32 @trivially_free() { %a2 = call ptr @llvm.launder.invariant.group.p0(ptr undef) %a3 = call ptr @llvm.strip.invariant.group.p0(ptr undef) %a4 = call i1 @llvm.is.constant.i32(i32 undef) - call void @llvm.lifetime.start.p0(i64 1, ptr undef) - call void @llvm.lifetime.end.p0(i64 1, ptr undef) + call void @llvm.lifetime.start.p0(i64 1, ptr %alloca) + call void @llvm.lifetime.end.p0(i64 1, ptr %alloca) %a5 = call i64 @llvm.objectsize.i64.p0(ptr undef, i1 1, i1 1, i1 1) %a6 = call ptr @llvm.ptr.annotation.p0(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) call void @llvm.var.annotation(ptr undef, ptr undef, ptr undef, i32 undef, ptr undef) diff --git a/llvm/test/Analysis/MemorySSA/lifetime-simple.ll b/llvm/test/Analysis/MemorySSA/lifetime-simple.ll index d409c140dc7b..18d2459b42c4 100644 --- a/llvm/test/Analysis/MemorySSA/lifetime-simple.ll +++ b/llvm/test/Analysis/MemorySSA/lifetime-simple.ll @@ -2,8 +2,12 @@ ; This test checks that lifetime markers are considered clobbers of %P, ; and due to lack of noalias information, of %Q as well. -define i8 @test(ptr %P, ptr %Q) { +declare ptr @obscure(ptr) memory(none) + +define i8 @test() { entry: + %P = alloca [32 x i8] + %Q = call ptr @obscure(ptr %P) ; CHECK: 1 = MemoryDef(liveOnEntry) ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 32, ptr %P) call void @llvm.lifetime.start.p0(i64 32, ptr %P) diff --git a/llvm/test/Analysis/MemorySSA/pr43427.ll b/llvm/test/Analysis/MemorySSA/pr43427.ll index a9b442c735b6..254fb1104c59 100644 --- a/llvm/test/Analysis/MemorySSA/pr43427.ll +++ b/llvm/test/Analysis/MemorySSA/pr43427.ll @@ -30,7 +30,7 @@ ; CHECK-NEXT: ; [[NO6:.*]] = MemoryDef([[NO7]]) ; CHECK-NEXT: store i16 undef, ptr %e, align 1 ; CHECK-NEXT: 3 = MemoryDef([[NO6]]) -; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr null) +; CHECK-NEXT: call void @g() define void @f(i1 %arg) { entry: @@ -57,7 +57,7 @@ cleanup: ; preds = %lbl3 br i1 %switch, label %cleanup.cont, label %lbl1 cleanup.cont: ; preds = %cleanup - call void @llvm.lifetime.end.p0(i64 1, ptr null) + call void @g() ret void if.else: ; preds = %lbl1 @@ -65,6 +65,3 @@ if.else: ; preds = %lbl1 } declare void @g() - -; Function Attrs: argmemonly nounwind willreturn -declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) diff --git a/llvm/test/Analysis/MemorySSA/pr43438.ll b/llvm/test/Analysis/MemorySSA/pr43438.ll index d137c52e3e0f..0e09137c1cf9 100644 --- a/llvm/test/Analysis/MemorySSA/pr43438.ll +++ b/llvm/test/Analysis/MemorySSA/pr43438.ll @@ -87,7 +87,7 @@ if.else: ; preds = %lbl1 ] if.end12: ; preds = %cleanup.cont11s, %cleanup.cont - call void @llvm.lifetime.end.p0(i64 1, ptr undef) + call i16 @g(i16 1) ret void unreachable: ; preds = %if.else, %for.end5 @@ -95,6 +95,3 @@ unreachable: ; preds = %if.else, %for.end5 } declare i16 @g(i16) - -; Function Attrs: argmemonly nounwind willreturn -declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) diff --git a/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll b/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll index 37fa7d3e84ea..7fa1cf47f06b 100644 --- a/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll +++ b/llvm/test/Analysis/StackSafetyAnalysis/lifetime.ll @@ -786,83 +786,6 @@ end: ret void } -define void @non_alloca(ptr %p) { -; CHECK-LABEL: define void @non_alloca -entry: -; CHECK: entry: -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - %x = alloca i8, align 4 - %y = alloca i8, align 4 - - call void @llvm.lifetime.start.p0(i64 4, ptr %p) -; CHECK: call void @llvm.lifetime.start.p0(i64 4, ptr %p) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - call void @llvm.lifetime.start.p0(i64 4, ptr %x) -; CHECK: call void @llvm.lifetime.start.p0(i64 4, ptr %x) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - call void @llvm.lifetime.end.p0(i64 4, ptr %p) -; CHECK: call void @llvm.lifetime.end.p0(i64 4, ptr %p) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - ret void -} - -define void @select_alloca(i1 %v) { -; CHECK-LABEL: define void @select_alloca -entry: -; CHECK: entry: -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - %x = alloca i8, align 4 - %y = alloca i8, align 4 - %cxcy = select i1 %v, ptr %x, ptr %y - - call void @llvm.lifetime.start.p0(i64 1, ptr %cxcy) -; CHECK: call void @llvm.lifetime.start.p0(i64 1, ptr %cxcy) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - call void @llvm.lifetime.start.p0(i64 1, ptr %x) -; CHECK: call void @llvm.lifetime.start.p0(i64 1, ptr %x) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - call void @llvm.lifetime.end.p0(i64 1, ptr %x) -; CHECK: call void @llvm.lifetime.end.p0(i64 1, ptr %x) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - ret void -} - -define void @alloca_offset() { -; CHECK-LABEL: define void @alloca_offset -entry: -; CHECK: entry: -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - %x = alloca [5 x i32], align 4 - %x2 = getelementptr [5 x i32], ptr %x, i64 0, i64 1 - - call void @llvm.lifetime.start.p0(i64 20, ptr %x2) -; CHECK: call void @llvm.lifetime.start.p0(i64 20, ptr %x2) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - call void @llvm.lifetime.end.p0(i64 20, ptr %x2) -; CHECK: call void @llvm.lifetime.end.p0(i64 20, ptr %x2) -; MAY-NEXT: Alive: -; MUST-NEXT: Alive: <> - - ret void -} - define void @alloca_size() { ; CHECK-LABEL: define void @alloca_size entry: diff --git a/llvm/test/Assembler/autoupgrade-lifetime-intrinsics.ll b/llvm/test/Assembler/autoupgrade-lifetime-intrinsics.ll new file mode 100644 index 000000000000..00ab93470c19 --- /dev/null +++ b/llvm/test/Assembler/autoupgrade-lifetime-intrinsics.ll @@ -0,0 +1,57 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -S < %s | FileCheck %s + +define void @strip_bitcast() { +; CHECK-LABEL: define void @strip_bitcast() { +; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 +; CHECK-NEXT: [[B:%.*]] = bitcast ptr [[A]] to ptr +; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[A]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[A]]) +; CHECK-NEXT: ret void +; + %a = alloca i8 + %b = bitcast ptr %a to ptr + call void @llvm.lifetime.start.p0(i64 1, ptr %b) + call void @llvm.lifetime.end.p0(i64 1, ptr %b) + ret void +} + +define void @strip_addrspacecast() { +; CHECK-LABEL: define void @strip_addrspacecast() { +; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 +; CHECK-NEXT: [[B:%.*]] = addrspacecast ptr [[A]] to ptr addrspace(1) +; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[A]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[A]]) +; CHECK-NEXT: ret void +; + %a = alloca i8 + %b = addrspacecast ptr %a to ptr addrspace(1) + call void @llvm.lifetime.start.p1(i64 1, ptr addrspace(1) %b) + call void @llvm.lifetime.end.p1(i64 1, ptr addrspace(1) %b) + ret void +} + +define void @strip_gep() { +; CHECK-LABEL: define void @strip_gep() { +; CHECK-NEXT: [[A:%.*]] = alloca [2 x i8], align 1 +; CHECK-NEXT: [[B:%.*]] = getelementptr [2 x i8], ptr [[A]], i64 0, i64 0 +; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[A]]) +; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[A]]) +; CHECK-NEXT: ret void +; + %a = alloca [2 x i8] + %b = getelementptr [2 x i8], ptr %a, i64 0, i64 0 + call void @llvm.lifetime.start.p0(i64 1, ptr %b) + call void @llvm.lifetime.end.p0(i64 1, ptr %b) + ret void +} + +define void @remove_unanalyzable(ptr %p) { +; CHECK-LABEL: define void @remove_unanalyzable( +; CHECK-SAME: ptr [[P:%.*]]) { +; CHECK-NEXT: ret void +; + call void @llvm.lifetime.start.p0(i64 1, ptr %p) + call void @llvm.lifetime.end.p0(i64 1, ptr %p) + ret void +} diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-switch-split.ll b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-switch-split.ll index 55cf48ed2245..d1a6584a331c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-switch-split.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/irtranslator-switch-split.ll @@ -9,7 +9,7 @@ declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #0 declare i32 @logg(...) -define i32 @scanfile(i32 %call148) { +define i32 @scanfile(i32 %call148, ptr %p) { ; CHECK-LABEL: scanfile: ; CHECK: ; %bb.0: ; %entry ; CHECK-NEXT: stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill @@ -26,7 +26,7 @@ define i32 @scanfile(i32 %call148) { ; CHECK-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: LBB0_3: ; %entry -; CHECK-NEXT: b.eq LBB0_2 +; CHECK-NEXT: b.eq LBB0_10 ; CHECK-NEXT: ; %bb.4: ; %entry ; CHECK-NEXT: cmp w8, #2 ; CHECK-NEXT: b.eq LBB0_6 @@ -46,6 +46,10 @@ define i32 @scanfile(i32 %call148) { ; CHECK-NEXT: LBB0_9: ; %sw.bb150 ; CHECK-NEXT: bl _logg ; CHECK-NEXT: brk #0x1 +; CHECK-NEXT: LBB0_10: ; %sw.bb178 +; CHECK-NEXT: str wzr, [x1] +; CHECK-NEXT: ldp x29, x30, [sp], #16 ; 16-byte Folded Reload +; CHECK-NEXT: ret entry: switch i32 %call148, label %common.ret [ i32 -1, label %sw.bb @@ -80,7 +84,7 @@ sw.bb152: ; preds = %entry br label %common.ret sw.bb178: ; preds = %entry - call void @llvm.lifetime.start.p0(i64 0, ptr null) + store i32 0, ptr %p br label %common.ret } diff --git a/llvm/test/CodeGen/AArch64/stack-tagging.ll b/llvm/test/CodeGen/AArch64/stack-tagging.ll index 8759fb12bea7..5d73c7ba968a 100644 --- a/llvm/test/CodeGen/AArch64/stack-tagging.ll +++ b/llvm/test/CodeGen/AArch64/stack-tagging.ll @@ -143,54 +143,4 @@ l: ; CHECK-NOT: @llvm.aarch64.irg.sp ; CHECK: ret void -; If we can't trace one of the lifetime markers to a single alloca, fall back -; to poisoning all allocas at the beginning of the function. -; Each alloca must be poisoned only once. -define void @UnrecognizedLifetime(i8 %v) sanitize_memtag { -entry: - %x = alloca i32, align 4 - %y = alloca i32, align 4 - %z = alloca i32, align 4 - %tobool = icmp eq i8 %v, 0 - %xy = select i1 %tobool, ptr %x, ptr %y - %cxcy = select i1 %tobool, ptr %x, ptr %y - br label %another_bb - -another_bb: - call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %z) - store i32 7, ptr %z - call void @noUse32(ptr %z) - call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %z) - call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %z) - store i32 7, ptr %z - call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %z) - call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %cxcy) - store i32 8, ptr %xy - call void @noUse32(ptr %x) - call void @noUse32(ptr %y) - call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %cxcy) - ret void -} - -; CHECK-LABEL: define void @UnrecognizedLifetime( -; CHECK: call ptr @llvm.aarch64.irg.sp(i64 0) -; CHECK: alloca { i32, [12 x i8] }, align 16 -; CHECK: call ptr @llvm.aarch64.tagp -; CHECK: call void @llvm.aarch64.settag( -; CHECK: alloca { i32, [12 x i8] }, align 16 -; CHECK: call ptr @llvm.aarch64.tagp -; CHECK: call void @llvm.aarch64.settag( -; CHECK: alloca { i32, [12 x i8] }, align 16 -; CHECK: call ptr @llvm.aarch64.tagp -; CHECK: call void @llvm.aarch64.settag( -; CHECK: store i32 -; CHECK: call void @noUse32(ptr -; CHECK: store i32 -; CHECK: store i32 -; CHECK: call void @noUse32(ptr -; CHECK: call void @llvm.aarch64.settag( -; CHECK: call void @llvm.aarch64.settag( -; CHECK: call void @llvm.aarch64.settag( -; CHECK: ret void - !0 = !{} diff --git a/llvm/test/CodeGen/Thumb2/ifcvt-rescan-bug-2016-08-22.ll b/llvm/test/CodeGen/Thumb2/ifcvt-rescan-bug-2016-08-22.ll index 9acdd7e4a8ad..b70505cad471 100644 --- a/llvm/test/CodeGen/Thumb2/ifcvt-rescan-bug-2016-08-22.ll +++ b/llvm/test/CodeGen/Thumb2/ifcvt-rescan-bug-2016-08-22.ll @@ -17,6 +17,7 @@ declare void @_ZNSsC1EPKcRKSaIcE() unnamed_addr #0 ; CHECK: .LBB0_2 ; Function Attrs: nounwind define hidden void @_ZN4llvm14DOTGraphTraitsIPNS_13ScheduleDAGMIEE17getEdgeAttributesEPKNS_5SUnitENS_13SUnitIteratorEPKNS_11ScheduleDAGE() #0 align 2 { + %a = alloca i8 br i1 undef, label %1, label %2 ;