Skip to content

Commit 955b133

Browse files
committed
only allow lifetime markers on allocas
1 parent de95956 commit 955b133

File tree

63 files changed

+376
-1085
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+376
-1085
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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,13 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack(
614614
Use &U = *AI->use_begin();
615615
Instruction *User = cast<Instruction>(U.getUser());
616616

617+
// Drop lifetime markers now that this is no longer an alloca.
618+
// SafeStack has already performed its own stack coloring.
619+
if (User->isLifetimeStartOrEnd()) {
620+
User->eraseFromParent();
621+
continue;
622+
}
623+
617624
Instruction *InsertBefore;
618625
if (auto *PHI = dyn_cast<PHINode>(User))
619626
InsertBefore = PHI->getIncomingBlock(U)->getTerminator();

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/Target/SPIRV/SPIRVPrepareFunctions.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
380380
bool Changed = false;
381381
const SPIRVSubtarget &STI = TM.getSubtarget<SPIRVSubtarget>(*F);
382382
for (BasicBlock &BB : *F) {
383-
for (Instruction &I : BB) {
383+
for (Instruction &I : make_early_inc_range(BB)) {
384384
auto Call = dyn_cast<CallInst>(&I);
385385
if (!Call)
386386
continue;
@@ -408,12 +408,16 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
408408
if (!STI.isShader()) {
409409
Changed |= toSpvOverloadedIntrinsic(
410410
II, Intrinsic::SPVIntrinsics::spv_lifetime_start, {1});
411+
} else {
412+
II->eraseFromParent();
411413
}
412414
break;
413415
case Intrinsic::lifetime_end:
414416
if (!STI.isShader()) {
415417
Changed |= toSpvOverloadedIntrinsic(
416418
II, Intrinsic::SPVIntrinsics::spv_lifetime_end, {1});
419+
} else {
420+
II->eraseFromParent();
417421
}
418422
break;
419423
case Intrinsic::ptr_annotation:

llvm/lib/Transforms/Coroutines/CoroEarly.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ 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+
// Remove lifetime markers, as these are only allowed on allocas.
174+
for (User *U : make_early_inc_range(PA->users())) {
175+
auto *I = cast<Instruction>(U);
176+
if (I->isLifetimeStartOrEnd())
177+
I->eraseFromParent();
178+
}
173179
PA->replaceUsesWithIf(PI, [CoroId](Use &U) {
174180
bool IsBitcast = U == U.getUser()->stripPointerCasts();
175181
bool IsCoroId = U.getUser() == CoroId;

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,7 @@ void FunctionStackPoisoner::processStaticAllocas() {
36373637
"Variable descriptions relative to ASan stack base will be dropped");
36383638

36393639
// Replace Alloca instructions with base+offset.
3640+
SmallVector<Value *> NewAllocaPtrs;
36403641
for (const auto &Desc : SVD) {
36413642
AllocaInst *AI = Desc.AI;
36423643
replaceDbgDeclare(AI, LocalStackBaseAllocaPtr, DIB, DIExprFlags,
@@ -3645,6 +3646,7 @@ void FunctionStackPoisoner::processStaticAllocas() {
36453646
IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, Desc.Offset)),
36463647
AI->getType());
36473648
AI->replaceAllUsesWith(NewAllocaPtr);
3649+
NewAllocaPtrs.push_back(NewAllocaPtr);
36483650
}
36493651

36503652
// The left-most redzone has enough space for at least 4 pointers.
@@ -3694,6 +3696,15 @@ void FunctionStackPoisoner::processStaticAllocas() {
36943696
}
36953697
}
36963698

3699+
// Remove lifetime markers now that these are no longer allocas.
3700+
for (Value *NewAllocaPtr : NewAllocaPtrs) {
3701+
for (User *U : make_early_inc_range(NewAllocaPtr->users())) {
3702+
auto *I = cast<Instruction>(U);
3703+
if (I->isLifetimeStartOrEnd())
3704+
I->eraseFromParent();
3705+
}
3706+
}
3707+
36973708
SmallVector<uint8_t, 64> ShadowClean(ShadowAfterScope.size(), 0);
36983709
SmallVector<uint8_t, 64> ShadowAfterReturn;
36993710

@@ -3829,6 +3840,13 @@ void FunctionStackPoisoner::handleDynamicAllocaCall(AllocaInst *AI) {
38293840

38303841
Value *NewAddressPtr = IRB.CreateIntToPtr(NewAddress, AI->getType());
38313842

3843+
// Remove lifetime markers now that this is no longer an alloca.
3844+
for (User *U : make_early_inc_range(AI->users())) {
3845+
auto *I = cast<Instruction>(U);
3846+
if (I->isLifetimeStartOrEnd())
3847+
I->eraseFromParent();
3848+
}
3849+
38323850
// Replace all uses of AddessReturnedByAlloca with NewAddressPtr.
38333851
AI->replaceAllUsesWith(NewAddressPtr);
38343852

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/test/Analysis/BasicAA/modref.ll

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,27 +67,33 @@ define i8 @test2a(ptr %P) {
6767
ret i8 %A
6868
}
6969

70-
define void @test3(ptr %P, i8 %X) {
70+
define void @test3(i8 %X) {
7171
; CHECK-LABEL: @test3(
72-
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 2
72+
; CHECK-NEXT: [[P:%.*]] = alloca i64, align 8
73+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i8, ptr [[P]], i32 2
7374
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[P]])
7475
; CHECK-NEXT: store i8 2, ptr [[P2]], align 1
76+
; CHECK-NEXT: call void @external(ptr [[P]])
7577
; CHECK-NEXT: ret void
7678
;
79+
%P = alloca i64
7780
%Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead.
7881

7982
%P2 = getelementptr i8, ptr %P, i32 2
8083
store i8 %Y, ptr %P2 ;; Not read by lifetime.end, should be removed.
8184
call void @llvm.lifetime.end.p0(i64 1, ptr %P)
8285
store i8 2, ptr %P2
86+
call void @external(ptr %P)
8387
ret void
8488
}
8589

86-
define void @test3a(ptr %P, i8 %X) {
90+
define void @test3a(i8 %X) {
8791
; CHECK-LABEL: @test3a(
88-
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 10, ptr [[P:%.*]])
92+
; CHECK-NEXT: [[P:%.*]] = alloca i64, align 8
93+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 10, ptr [[P]])
8994
; CHECK-NEXT: ret void
9095
;
96+
%P = alloca i64
9197
%Y = add i8 %X, 1 ;; Dead, because the only use (the store) is dead.
9298

9399
%P2 = getelementptr i8, ptr %P, i32 2

0 commit comments

Comments
 (0)