Skip to content

Commit 307256e

Browse files
authored
[GVNSink] Do not sink lifetimes of different allocas (#149818)
This was always undesirable, and after #149310 it is illegal and will result in a verifier error. Fix this by moving SimplifyCFG's check for this into canReplaceOperandWithVariable(), so it's shared with GVNSink.
1 parent 314ce69 commit 307256e

File tree

3 files changed

+81
-10
lines changed

3 files changed

+81
-10
lines changed

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3857,6 +3857,10 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) {
38573857
if (Op->isSwiftError())
38583858
return false;
38593859

3860+
// Cannot replace alloca argument with phi/select.
3861+
if (I->isLifetimeStartOrEnd())
3862+
return false;
3863+
38603864
// Early exit.
38613865
if (!isa<Constant, InlineAsm>(Op))
38623866
return true;

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,16 +2227,6 @@ static bool canSinkInstructions(
22272227
return I->getOperand(OI) == I0->getOperand(OI);
22282228
};
22292229
if (!all_of(Insts, SameAsI0)) {
2230-
// SROA can't speculate lifetime markers of selects/phis, and the
2231-
// backend may handle such lifetimes incorrectly as well (#104776).
2232-
// Don't sink lifetimes if it would introduce a phi on the pointer
2233-
// argument.
2234-
if (isa<LifetimeIntrinsic>(I0) && OI == 1 &&
2235-
any_of(Insts, [](const Instruction *I) {
2236-
return isa<AllocaInst>(I->getOperand(1)->stripPointerCasts());
2237-
}))
2238-
return false;
2239-
22402230
if ((isa<Constant>(Op) && !replacingOperandWithVariableIsCheap(I0, OI)) ||
22412231
!canReplaceOperandWithVariable(I0, OI))
22422232
// We can't create a PHI from this GEP.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -S -passes=gvn-sink < %s | FileCheck %s
3+
4+
; Make sure we do not sink lifetime markers if this would introduce a
5+
; lifetime with non-alloca operand.
6+
7+
define void @test_cant_sink(i1 %c) {
8+
; CHECK-LABEL: define void @test_cant_sink(
9+
; CHECK-SAME: i1 [[C:%.*]]) {
10+
; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1
11+
; CHECK-NEXT: [[B:%.*]] = alloca i8, align 1
12+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[A]])
13+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[B]])
14+
; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[ELSE:.*]]
15+
; CHECK: [[IF]]:
16+
; CHECK-NEXT: store i64 1, ptr [[A]], align 4
17+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[A]])
18+
; CHECK-NEXT: br label %[[JOIN:.*]]
19+
; CHECK: [[ELSE]]:
20+
; CHECK-NEXT: store i64 1, ptr [[B]], align 4
21+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[B]])
22+
; CHECK-NEXT: br label %[[JOIN]]
23+
; CHECK: [[JOIN]]:
24+
; CHECK-NEXT: ret void
25+
;
26+
%a = alloca i8
27+
%b = alloca i8
28+
call void @llvm.lifetime.start(i64 1, ptr %a)
29+
call void @llvm.lifetime.start(i64 1, ptr %b)
30+
br i1 %c, label %if, label %else
31+
32+
if:
33+
store i64 1, ptr %a
34+
call void @llvm.lifetime.end(i64 1, ptr %a)
35+
br label %join
36+
37+
else:
38+
store i64 1, ptr %b
39+
call void @llvm.lifetime.end(i64 1, ptr %b)
40+
br label %join
41+
42+
join:
43+
ret void
44+
}
45+
46+
define void @test_can_sink(i1 %c) {
47+
; CHECK-LABEL: define void @test_can_sink(
48+
; CHECK-SAME: i1 [[C:%.*]]) {
49+
; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1
50+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[A]])
51+
; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[ELSE:.*]]
52+
; CHECK: [[IF]]:
53+
; CHECK-NEXT: br label %[[JOIN:.*]]
54+
; CHECK: [[ELSE]]:
55+
; CHECK-NEXT: br label %[[JOIN]]
56+
; CHECK: [[JOIN]]:
57+
; CHECK-NEXT: store i64 1, ptr [[A]], align 4
58+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[A]])
59+
; CHECK-NEXT: ret void
60+
;
61+
%a = alloca i8
62+
call void @llvm.lifetime.start(i64 1, ptr %a)
63+
br i1 %c, label %if, label %else
64+
65+
if:
66+
store i64 1, ptr %a
67+
call void @llvm.lifetime.end(i64 1, ptr %a)
68+
br label %join
69+
70+
else:
71+
store i64 1, ptr %a
72+
call void @llvm.lifetime.end(i64 1, ptr %a)
73+
br label %join
74+
75+
join:
76+
ret void
77+
}

0 commit comments

Comments
 (0)