Skip to content

Commit 0fa2a96

Browse files
committed
only allow lifetime markers on allocas
1 parent 34c8533 commit 0fa2a96

File tree

15 files changed

+84
-55
lines changed

15 files changed

+84
-55
lines changed

llvm/docs/LangRef.rst

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26634,19 +26634,14 @@ Arguments:
2663426634

2663526635
The first argument is a constant integer representing the size of the
2663626636
object, or -1 if it is variable sized. The second argument is a pointer
26637-
to the object.
26637+
to to an ``alloca`` instruction.
2663826638

2663926639
Semantics:
2664026640
""""""""""
2664126641

26642-
If ``ptr`` is a stack-allocated object and it points to the first byte of
26643-
the object, the object is initially marked as dead.
26644-
``ptr`` is conservatively considered as a non-stack-allocated object if
26645-
the stack coloring algorithm that is used in the optimization pipeline cannot
26646-
conclude that ``ptr`` is a stack-allocated object.
26647-
26648-
After '``llvm.lifetime.start``', the stack object that ``ptr`` points is marked
26649-
as alive and has an uninitialized value.
26642+
The stack-allocated object that ``ptr`` points to is initially marked as dead.
26643+
After '``llvm.lifetime.start``', the stack object is marked as alive and has an
26644+
uninitialized value.
2665026645
The stack object is marked as dead when either
2665126646
:ref:`llvm.lifetime.end <int_lifeend>` to the alloca is executed or the
2665226647
function returns.
@@ -26656,11 +26651,6 @@ After :ref:`llvm.lifetime.end <int_lifeend>` is called,
2665626651
The second '``llvm.lifetime.start``' call marks the object as alive, but it
2665726652
does not change the address of the object.
2665826653

26659-
If ``ptr`` is a non-stack-allocated object, it does not point to the first
26660-
byte of the object or it is a stack object that is already alive, it simply
26661-
fills all bytes of the object with ``poison``.
26662-
26663-
2666426654
.. _int_lifeend:
2666526655

2666626656
'``llvm.lifetime.end``' Intrinsic
@@ -26684,24 +26674,16 @@ Arguments:
2668426674

2668526675
The first argument is a constant integer representing the size of the
2668626676
object, or -1 if it is variable sized. The second argument is a pointer
26687-
to the object.
26677+
to an ``alloca`` instruction.
2668826678

2668926679
Semantics:
2669026680
""""""""""
2669126681

26692-
If ``ptr`` is a stack-allocated object and it points to the first byte of the
26693-
object, the object is dead.
26694-
``ptr`` is conservatively considered as a non-stack-allocated object if
26695-
the stack coloring algorithm that is used in the optimization pipeline cannot
26696-
conclude that ``ptr`` is a stack-allocated object.
26682+
The stack-allocated object that ``ptr`` points becomes dead after the call to
26683+
this intrinsic.
2669726684

2669826685
Calling ``llvm.lifetime.end`` on an already dead alloca is no-op.
2669926686

26700-
If ``ptr`` is a non-stack-allocated object or it does not point to the first
26701-
byte of the object, it is equivalent to simply filling all bytes of the object
26702-
with ``poison``.
26703-
26704-
2670526687
'``llvm.invariant.start``' Intrinsic
2670626688
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2670726689

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7116,9 +7116,11 @@ Error BitcodeReader::materializeModule() {
71167116
if (CallInst *CI = dyn_cast<CallInst>(U))
71177117
UpgradeIntrinsicCall(CI, I.second);
71187118
}
7119-
if (!I.first->use_empty())
7120-
I.first->replaceAllUsesWith(I.second);
7121-
I.first->eraseFromParent();
7119+
if (I.first != I.second) {
7120+
if (!I.first->use_empty())
7121+
I.first->replaceAllUsesWith(I.second);
7122+
I.first->eraseFromParent();
7123+
}
71227124
}
71237125
UpgradedIntrinsics.clear();
71247126

llvm/lib/CodeGen/SafeStack.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,9 +610,12 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack(
610610
// Replace uses of the alloca with the new location.
611611
// Insert address calculation close to each use to work around PR27844.
612612
std::string Name = std::string(AI->getName()) + ".unsafe";
613-
while (!AI->use_empty()) {
614-
Use &U = *AI->use_begin();
613+
for (Use &U : make_early_inc_range(AI->uses())) {
615614
Instruction *User = cast<Instruction>(U.getUser());
615+
if (User->isLifetimeStartOrEnd()) {
616+
User->eraseFromParent();
617+
continue;
618+
}
616619

617620
Instruction *InsertBefore;
618621
if (auto *PHI = dyn_cast<PHINode>(User))

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,6 +1310,18 @@ static bool upgradeIntrinsicFunction1(Function *F, Function *&NewFn,
13101310
return true;
13111311
}
13121312
break;
1313+
case 'l':
1314+
if (Name.starts_with("lifetime.start") ||
1315+
Name.starts_with("lifetime.end")) {
1316+
// Unless remangling is required, do not upgrade the function declaration,
1317+
// but do upgrade the calls.
1318+
if (auto Result = llvm::Intrinsic::remangleIntrinsicFunction(F))
1319+
NewFn = *Result;
1320+
else
1321+
NewFn = F;
1322+
return true;
1323+
}
1324+
break;
13131325
case 'm': {
13141326
// Updating the memory intrinsics (memcpy/memmove/memset) that have an
13151327
// alignment parameter to embedding the alignment as an attribute of
@@ -1629,7 +1641,6 @@ bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn,
16291641
NewFn = nullptr;
16301642
bool Upgraded =
16311643
upgradeIntrinsicFunction1(F, NewFn, CanUpgradeDebugIntrinsicsToRecords);
1632-
assert(F != NewFn && "Intrinsic function upgraded to the same function");
16331644

16341645
// Upgrade intrinsic attributes. This does not change the function.
16351646
if (NewFn)
@@ -4570,6 +4581,9 @@ void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) {
45704581
}
45714582

45724583
const auto &DefaultCase = [&]() -> void {
4584+
if (F == NewFn)
4585+
return;
4586+
45734587
if (CI->getFunctionType() == NewFn->getFunctionType()) {
45744588
// Handle generic mangling change.
45754589
assert(
@@ -5109,6 +5123,31 @@ void llvm::UpgradeIntrinsicCall(CallBase *CI, Function *NewFn) {
51095123
MTI->setSourceAlignment(Align->getMaybeAlignValue());
51105124
break;
51115125
}
5126+
5127+
case Intrinsic::lifetime_start:
5128+
case Intrinsic::lifetime_end: {
5129+
Value *Size = CI->getArgOperand(0);
5130+
Value *Ptr = CI->getArgOperand(1);
5131+
if (isa<AllocaInst>(Ptr)) {
5132+
DefaultCase();
5133+
return;
5134+
}
5135+
5136+
// Try to strip pointer casts, such that the lifetime works on an alloca.
5137+
Ptr = Ptr->stripPointerCasts();
5138+
if (isa<AllocaInst>(Ptr)) {
5139+
// Don't use NewFn, as we might have looked through an addrspacecast.
5140+
if (NewFn->getIntrinsicID() == Intrinsic::lifetime_start)
5141+
NewCall = Builder.CreateLifetimeStart(Ptr, cast<ConstantInt>(Size));
5142+
else
5143+
NewCall = Builder.CreateLifetimeEnd(Ptr, cast<ConstantInt>(Size));
5144+
break;
5145+
}
5146+
5147+
// Otherwise remove the lifetime marker.
5148+
CI->eraseFromParent();
5149+
return;
5150+
}
51125151
}
51135152
assert(NewCall && "Should have either set this variable or returned through "
51145153
"the default case");
@@ -5131,7 +5170,8 @@ void llvm::UpgradeCallsToIntrinsic(Function *F) {
51315170
UpgradeIntrinsicCall(CB, NewFn);
51325171

51335172
// Remove old function, no longer used, from the module.
5134-
F->eraseFromParent();
5173+
if (F != NewFn)
5174+
F->eraseFromParent();
51355175
}
51365176
}
51375177

llvm/lib/IR/Verifier.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6679,6 +6679,11 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
66796679
"llvm.threadlocal.address operand isThreadLocal() must be true");
66806680
break;
66816681
}
6682+
case Intrinsic::lifetime_start:
6683+
case Intrinsic::lifetime_end:
6684+
Check(isa<AllocaInst>(Call.getArgOperand(1)),
6685+
"llvm.lifetime.start/end can only be used on alloca", &Call);
6686+
break;
66826687
};
66836688

66846689
// Verify that there aren't any unmediated control transfers between funclets.

llvm/lib/Transforms/Coroutines/CoroEarly.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,11 @@ void Lowerer::hidePromiseAlloca(CoroIdInst *CoroId, CoroBeginInst *CoroBegin) {
170170
auto *PI = Builder.CreateIntrinsic(
171171
Builder.getPtrTy(), Intrinsic::coro_promise, Arg, {}, "promise.addr");
172172
PI->setCannotDuplicate();
173+
for (User *U : make_early_inc_range(PA->users())) {
174+
auto *I = cast<Instruction>(U);
175+
if (I->isLifetimeStartOrEnd())
176+
I->eraseFromParent();
177+
}
173178
PA->replaceUsesWithIf(PI, [CoroId](Use &U) {
174179
bool IsBitcast = U == U.getUser()->stripPointerCasts();
175180
bool IsCoroId = U.getUser() == CoroId;

llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,8 @@ bool InferAddressSpacesImpl::rewriteIntrinsicOperands(IntrinsicInst *II,
430430
}
431431
case Intrinsic::lifetime_start:
432432
case Intrinsic::lifetime_end: {
433+
// Always force lifetime markers to work directly on the alloca.
434+
NewV = NewV->stripPointerCasts();
433435
Function *NewDecl = Intrinsic::getOrInsertDeclaration(
434436
M, II->getIntrinsicID(), {NewV->getType()});
435437
II->setArgOperand(1, NewV);

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5968,7 +5968,7 @@ void LSRInstance::Rewrite(const LSRUse &LU, const LSRFixup &LF,
59685968
// find the nearest block which dominates all the relevant uses.
59695969
if (PHINode *PN = dyn_cast<PHINode>(LF.UserInst)) {
59705970
RewriteForPHI(PN, LU, LF, F, DeadInsts);
5971-
} else {
5971+
} else if (!LF.UserInst->isLifetimeStartOrEnd()) {
59725972
Value *FullV = Expand(LU, LF, F, LF.UserInst->getIterator(), DeadInsts);
59735973

59745974
// If this is reuse-by-noop-cast, insert the noop cast.

llvm/test/Transforms/CodeExtractor/PartialInlineAlloca5.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ bb:
1818
br i1 %tmp4, label %bb6, label %bb5
1919

2020
bb5: ; preds = %bb
21-
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %tmp1) #2
21+
call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %tmp) #2
2222
store i32 %tmp3, ptr %tmp, align 4, !tbaa !2
2323
store i32 %tmp3, ptr @g, align 4, !tbaa !2
2424
call void @bar(ptr nonnull %tmp) #2
25-
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %tmp1) #2
25+
call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %tmp) #2
2626
br label %bb6
2727

2828
bb6: ; preds = %bb5, %bb

llvm/test/Transforms/InferAddressSpaces/NVPTX/lifetime.ll

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
12
; RUN: opt -S -passes=infer-address-spaces %s | FileCheck %s
23

34
target triple = "nvptx64-nvidia-cuda"
@@ -6,11 +7,13 @@ define i32 @lifetime_flat_pointer() {
67
; CHECK-LABEL: define i32 @lifetime_flat_pointer() {
78
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
89
; CHECK-NEXT: [[TMP1:%.*]] = addrspacecast ptr [[ALLOCA]] to ptr addrspace(5)
9-
; CHECK-NEXT: call void @llvm.lifetime.start.p5(i64 4, ptr addrspace(5) [[TMP1]])
10+
; CHECK-NEXT: [[TMP2:%.*]] = addrspacecast ptr addrspace(5) [[TMP1]] to ptr
11+
; CHECK-NEXT: [[TMP3:%.*]] = addrspacecast ptr addrspace(5) [[TMP1]] to ptr
12+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[ALLOCA]])
1013
; CHECK-NEXT: store i32 1, ptr addrspace(5) [[TMP1]], align 4
11-
; CHECK-NEXT: %ret = load i32, ptr addrspace(5) [[TMP1]], align 4
12-
; CHECK-NEXT: call void @llvm.lifetime.end.p5(i64 4, ptr addrspace(5) [[TMP1]])
13-
; CHECK-NEXT: ret i32 %ret
14+
; CHECK-NEXT: [[RET:%.*]] = load i32, ptr addrspace(5) [[TMP1]], align 4
15+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[ALLOCA]])
16+
; CHECK-NEXT: ret i32 [[RET]]
1417
;
1518
%alloca = alloca i32, align 4
1619
%1 = addrspacecast ptr %alloca to ptr addrspace(5)

0 commit comments

Comments
 (0)