Skip to content

Commit 155359c

Browse files
authored
[llvm][sroa] Disable support for invariant.group (#151743)
Resolves #151574. > SROA pass does not perform aggregate load/store rewriting on a pointer whose source is a `launder.invariant.group`. > > This causes failed assertion in `AllocaSlices`. > > ``` > void (anonymous namespace)::AllocaSlices::SliceBuilder::visitStoreInst(StoreInst &): > Assertion `(!SI.isSimple() || ValOp->getType()->isSingleValueType()) && > "All simple FCA stores should have been pre-split"' failed. > ``` Disables support for `{launder,strip}.invariant.group` intrinsics in SROA. Updates SROA test for `invariant.group` support.
1 parent 00a648a commit 155359c

File tree

2 files changed

+84
-20
lines changed

2 files changed

+84
-20
lines changed

llvm/lib/Transforms/Scalar/SROA.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,8 +1247,7 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
12471247
"Map index doesn't point back to a slice with this user.");
12481248
}
12491249

1250-
// Disable SRoA for any intrinsics except for lifetime invariants and
1251-
// invariant group.
1250+
// Disable SRoA for any intrinsics except for lifetime invariants.
12521251
// FIXME: What about debug intrinsics? This matches old behavior, but
12531252
// doesn't make sense.
12541253
void visitIntrinsicInst(IntrinsicInst &II) {
@@ -1268,12 +1267,6 @@ class AllocaSlices::SliceBuilder : public PtrUseVisitor<SliceBuilder> {
12681267
return;
12691268
}
12701269

1271-
if (II.isLaunderOrStripInvariantGroup()) {
1272-
insertUse(II, Offset, AllocSize, true);
1273-
enqueueUsers(II);
1274-
return;
1275-
}
1276-
12771270
Base::visitIntrinsicInst(II);
12781271
}
12791272

@@ -3607,8 +3600,7 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
36073600
}
36083601

36093602
bool visitIntrinsicInst(IntrinsicInst &II) {
3610-
assert((II.isLifetimeStartOrEnd() || II.isLaunderOrStripInvariantGroup() ||
3611-
II.isDroppable()) &&
3603+
assert((II.isLifetimeStartOrEnd() || II.isDroppable()) &&
36123604
"Unexpected intrinsic!");
36133605
LLVM_DEBUG(dbgs() << " original: " << II << "\n");
36143606

@@ -3622,9 +3614,6 @@ class AllocaSliceRewriter : public InstVisitor<AllocaSliceRewriter, bool> {
36223614
return true;
36233615
}
36243616

3625-
if (II.isLaunderOrStripInvariantGroup())
3626-
return true;
3627-
36283617
assert(II.getArgOperand(1) == OldPtr);
36293618
// Lifetime intrinsics are only promotable if they cover the whole alloca.
36303619
// Therefore, we drop lifetime intrinsics which don't cover the whole

llvm/test/Transforms/SROA/invariant-group.ll

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,17 @@ declare i32 @somevalue()
1111

1212
define void @f() {
1313
; CHECK-LABEL: @f(
14+
; CHECK-NEXT: [[A:%.*]] = alloca [[T:%.*]], align 8
15+
; CHECK-NEXT: [[A1_I8_INV:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[A]])
16+
; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i32 0, i32 1
1417
; CHECK-NEXT: [[SV1:%.*]] = call i32 @somevalue()
1518
; CHECK-NEXT: [[SV2:%.*]] = call i32 @somevalue()
16-
; CHECK-NEXT: call void @h(i32 [[SV1]])
17-
; CHECK-NEXT: call void @h(i32 [[SV2]])
19+
; CHECK-NEXT: store i32 [[SV1]], ptr [[A1_I8_INV]], align 4, !invariant.group [[META0:![0-9]+]]
20+
; CHECK-NEXT: store i32 [[SV2]], ptr [[A2]], align 4
21+
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]]
22+
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[A2]], align 4
23+
; CHECK-NEXT: call void @h(i32 [[V1]])
24+
; CHECK-NEXT: call void @h(i32 [[V2]])
1825
; CHECK-NEXT: ret void
1926
;
2027
%a = alloca %t
@@ -44,7 +51,7 @@ define void @g() {
4451
; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds [[T]], ptr [[A]], i32 0, i32 1
4552
; CHECK-NEXT: [[SV1:%.*]] = call i32 @somevalue()
4653
; CHECK-NEXT: [[SV2:%.*]] = call i32 @somevalue()
47-
; CHECK-NEXT: store i32 [[SV1]], ptr [[A1_I8_INV]], align 4, !invariant.group [[META0:![0-9]+]]
54+
; CHECK-NEXT: store i32 [[SV1]], ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]]
4855
; CHECK-NEXT: store i32 [[SV2]], ptr [[A2]], align 4
4956
; CHECK-NEXT: [[V1:%.*]] = load i32, ptr [[A1_I8_INV]], align 4, !invariant.group [[META0]]
5057
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[A2]], align 4
@@ -81,6 +88,9 @@ define void @g() {
8188

8289
define void @store_and_launder() {
8390
; CHECK-LABEL: @store_and_launder(
91+
; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4
92+
; CHECK-NEXT: store i32 0, ptr [[VALPTR]], align 4
93+
; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])
8494
; CHECK-NEXT: ret void
8595
;
8696
%valptr = alloca i32, align 4
@@ -91,7 +101,10 @@ define void @store_and_launder() {
91101

92102
define i32 @launder_and_load() {
93103
; CHECK-LABEL: @launder_and_load(
94-
; CHECK-NEXT: ret i32 undef
104+
; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4
105+
; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])
106+
; CHECK-NEXT: [[V2:%.*]] = load i32, ptr [[VALPTR]], align 4
107+
; CHECK-NEXT: ret i32 [[V2]]
95108
;
96109
%valptr = alloca i32, align 4
97110
%barr = call ptr @llvm.launder.invariant.group.p0(ptr %valptr)
@@ -101,6 +114,9 @@ define i32 @launder_and_load() {
101114

102115
define void @launder_and_ptr_arith() {
103116
; CHECK-LABEL: @launder_and_ptr_arith(
117+
; CHECK-NEXT: [[VALPTR:%.*]] = alloca i32, align 4
118+
; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[VALPTR]])
119+
; CHECK-NEXT: [[A2:%.*]] = getelementptr inbounds i32, ptr [[VALPTR]], i32 0
104120
; CHECK-NEXT: ret void
105121
;
106122
%valptr = alloca i32, align 4
@@ -140,9 +156,13 @@ end:
140156

141157
define void @partial_promotion_of_alloca() {
142158
; CHECK-LABEL: @partial_promotion_of_alloca(
143-
; CHECK-NEXT: [[STRUCT_PTR_SROA_2:%.*]] = alloca i32, align 4
144-
; CHECK-NEXT: store volatile i32 0, ptr [[STRUCT_PTR_SROA_2]], align 4
145-
; CHECK-NEXT: [[STRUCT_PTR_SROA_2_0_STRUCT_PTR_SROA_2_4_LOAD_VAL:%.*]] = load volatile i32, ptr [[STRUCT_PTR_SROA_2]], align 4
159+
; CHECK-NEXT: [[STRUCT_PTR:%.*]] = alloca [[T:%.*]], align 4
160+
; CHECK-NEXT: [[FIELD_PTR:%.*]] = getelementptr inbounds [[T]], ptr [[STRUCT_PTR]], i32 0, i32 0
161+
; CHECK-NEXT: store i32 0, ptr [[FIELD_PTR]], align 4
162+
; CHECK-NEXT: [[VOLATILE_FIELD_PTR:%.*]] = getelementptr inbounds [[T]], ptr [[STRUCT_PTR]], i32 0, i32 1
163+
; CHECK-NEXT: store volatile i32 0, ptr [[VOLATILE_FIELD_PTR]], align 4, !invariant.group [[META0]]
164+
; CHECK-NEXT: [[BARR:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[STRUCT_PTR]])
165+
; CHECK-NEXT: [[LOAD_VAL:%.*]] = load volatile i32, ptr [[VOLATILE_FIELD_PTR]], align 4, !invariant.group [[META0]]
146166
; CHECK-NEXT: ret void
147167
;
148168
%struct_ptr = alloca %t, align 4
@@ -155,6 +175,61 @@ define void @partial_promotion_of_alloca() {
155175
ret void
156176
}
157177

178+
define void @memcpy_after_laundering_alloca(ptr %ptr) {
179+
; CHECK-LABEL: @memcpy_after_laundering_alloca(
180+
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca { i64, i64 }, align 8
181+
; CHECK-NEXT: [[LAUNDER:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[ALLOCA]])
182+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[LAUNDER]], ptr [[PTR:%.*]], i64 16, i1 false)
183+
; CHECK-NEXT: ret void
184+
;
185+
%alloca = alloca { i64, i64 }, align 8
186+
%launder = call ptr @llvm.launder.invariant.group.p0(ptr %alloca)
187+
call void @llvm.memcpy.p0.p0.i64(ptr %launder, ptr %ptr, i64 16, i1 false)
188+
ret void
189+
}
190+
191+
define void @memcpy_after_laundering_alloca_slices(ptr %ptr) {
192+
; CHECK-LABEL: @memcpy_after_laundering_alloca_slices(
193+
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca { [16 x i8], i64, [16 x i8] }, align 8
194+
; CHECK-NEXT: [[LAUNDER:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[ALLOCA]])
195+
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i8, ptr [[LAUNDER]], i64 16
196+
; CHECK-NEXT: store i64 0, ptr [[GEP]], align 4
197+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr [[LAUNDER]], ptr [[PTR:%.*]], i64 40, i1 false)
198+
; CHECK-NEXT: ret void
199+
;
200+
%alloca = alloca { [16 x i8], i64, [16 x i8] }, align 8
201+
%launder = call ptr @llvm.launder.invariant.group.p0(ptr %alloca)
202+
%gep = getelementptr i8, ptr %launder, i64 16
203+
store i64 0, ptr %gep
204+
call void @llvm.memcpy.p0.p0.i64(ptr %launder, ptr %ptr, i64 40, i1 false)
205+
ret void
206+
}
207+
208+
define void @test_agg_store() {
209+
; CHECK-LABEL: @test_agg_store(
210+
; CHECK-NEXT: [[STRUCT_PTR:%.*]] = alloca [[T:%.*]], i64 1, align 4
211+
; CHECK-NEXT: [[STRUCT_PTR_FRESH:%.*]] = call ptr @llvm.launder.invariant.group.p0(ptr [[STRUCT_PTR]])
212+
; CHECK-NEXT: [[STRUCT:%.*]] = call [[T]] @[[MAKE_T:[a-zA-Z0-9_$\"\\.-]*[a-zA-Z_$\"\\.-][a-zA-Z0-9_$\"\\.-]*]]()
213+
; CHECK-NEXT: store [[T]] [[STRUCT]], ptr [[STRUCT_PTR_FRESH]], align 4, !invariant.group [[META0]]
214+
; CHECK-NEXT: [[FIRST_PTR:%.*]] = getelementptr [[T]], ptr [[STRUCT_PTR_FRESH]], i32 0, i32 0
215+
; CHECK-NEXT: [[FIRST:%.*]] = load i32, ptr [[FIRST_PTR]], align 4
216+
; CHECK-NEXT: [[SECOND_PTR:%.*]] = getelementptr [[T]], ptr [[STRUCT_PTR_FRESH]], i32 0, i32 1
217+
; CHECK-NEXT: [[SECOND:%.*]] = load i32, ptr [[SECOND_PTR]], align 4
218+
; CHECK-NEXT: ret void
219+
;
220+
%struct_ptr = alloca %t, i64 1, align 4
221+
%struct_ptr_fresh = call ptr @llvm.launder.invariant.group.p0(ptr %struct_ptr)
222+
%struct = call %t @make_t()
223+
store %t %struct, ptr %struct_ptr_fresh, align 4, !invariant.group !0
224+
%first_ptr = getelementptr %t, ptr %struct_ptr_fresh, i32 0, i32 0
225+
%first = load i32, ptr %first_ptr, align 4
226+
%second_ptr = getelementptr %t, ptr %struct_ptr_fresh, i32 0, i32 1
227+
%second = load i32, ptr %second_ptr, align 4
228+
ret void
229+
}
230+
231+
declare %t @make_t()
232+
158233
declare void @use(ptr)
159234

160235
!0 = !{}

0 commit comments

Comments
 (0)