xref: /llvm-project/llvm/test/Transforms/InstCombine/loadstore-metadata.ll (revision edd1360208b2c4dc60d81b525d6e59d9fb491c05)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals smart
2; RUN: opt -passes=instcombine -S < %s | FileCheck %s
3
4target datalayout = "e-m:e-p:64:64:64-i64:64-f80:128-n8:16:32:64-S128"
5
6define i32 @test_load_cast_combine_tbaa(ptr %ptr) {
7; Ensure (cast (load (...))) -> (load (cast (...))) preserves TBAA.
8; CHECK-LABEL: @test_load_cast_combine_tbaa(
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !tbaa [[TBAA0:![0-9]+]]
11; CHECK-NEXT:    ret i32 [[L1]]
12;
13entry:
14  %l = load float, ptr %ptr, !tbaa !0
15  %c = bitcast float %l to i32
16  ret i32 %c
17}
18
19define i32 @test_load_cast_combine_noalias(ptr %ptr) {
20; Ensure (cast (load (...))) -> (load (cast (...))) preserves no-alias metadata.
21; CHECK-LABEL: @test_load_cast_combine_noalias(
22; CHECK-NEXT:  entry:
23; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !alias.scope [[META3:![0-9]+]], !noalias [[META3]]
24; CHECK-NEXT:    ret i32 [[L1]]
25;
26entry:
27  %l = load float, ptr %ptr, !alias.scope !3, !noalias !3
28  %c = bitcast float %l to i32
29  ret i32 %c
30}
31
32define float @test_load_cast_combine_range(ptr %ptr) {
33; Ensure (cast (load (...))) -> (load (cast (...))) drops range metadata. It
34; would be nice to preserve or update it somehow but this is hard when moving
35; between types.
36; CHECK-LABEL: @test_load_cast_combine_range(
37; CHECK-NEXT:  entry:
38; CHECK-NEXT:    [[L1:%.*]] = load float, ptr [[PTR:%.*]], align 4
39; CHECK-NEXT:    ret float [[L1]]
40;
41entry:
42  %l = load i32, ptr %ptr, !range !6
43  %c = bitcast i32 %l to float
44  ret float %c
45}
46
47define i32 @test_load_cast_combine_invariant(ptr %ptr) {
48; Ensure (cast (load (...))) -> (load (cast (...))) preserves invariant metadata.
49; CHECK-LABEL: @test_load_cast_combine_invariant(
50; CHECK-NEXT:  entry:
51; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !invariant.load [[META6:![0-9]+]]
52; CHECK-NEXT:    ret i32 [[L1]]
53;
54entry:
55  %l = load float, ptr %ptr, !invariant.load !7
56  %c = bitcast float %l to i32
57  ret i32 %c
58}
59
60define i32 @test_load_cast_combine_nontemporal(ptr %ptr) {
61; Ensure (cast (load (...))) -> (load (cast (...))) preserves nontemporal
62; metadata.
63; CHECK-LABEL: @test_load_cast_combine_nontemporal(
64; CHECK-NEXT:  entry:
65; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !nontemporal [[META7:![0-9]+]]
66; CHECK-NEXT:    ret i32 [[L1]]
67;
68entry:
69  %l = load float, ptr %ptr, !nontemporal !8
70  %c = bitcast float %l to i32
71  ret i32 %c
72}
73
74define ptr @test_load_cast_combine_align(ptr %ptr) {
75; Ensure (cast (load (...))) -> (load (cast (...))) preserves align
76; metadata.
77; CHECK-LABEL: @test_load_cast_combine_align(
78; CHECK-NEXT:  entry:
79; CHECK-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !align [[META8:![0-9]+]]
80; CHECK-NEXT:    ret ptr [[L]]
81;
82entry:
83  %l = load ptr, ptr %ptr, !align !9
84  ret ptr %l
85}
86
87define ptr @test_load_cast_combine_deref(ptr %ptr) {
88; Ensure (cast (load (...))) -> (load (cast (...))) preserves dereferenceable
89; metadata.
90; CHECK-LABEL: @test_load_cast_combine_deref(
91; CHECK-NEXT:  entry:
92; CHECK-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable [[META8]]
93; CHECK-NEXT:    ret ptr [[L]]
94;
95entry:
96  %l = load ptr, ptr %ptr, !dereferenceable !9
97  ret ptr %l
98}
99
100define ptr @test_load_cast_combine_deref_or_null(ptr %ptr) {
101; Ensure (cast (load (...))) -> (load (cast (...))) preserves
102; dereferenceable_or_null metadata.
103; CHECK-LABEL: @test_load_cast_combine_deref_or_null(
104; CHECK-NEXT:  entry:
105; CHECK-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !dereferenceable_or_null [[META8]]
106; CHECK-NEXT:    ret ptr [[L]]
107;
108entry:
109  %l = load ptr, ptr %ptr, !dereferenceable_or_null !9
110  ret ptr %l
111}
112
113define void @test_load_cast_combine_loop(ptr %src, ptr %dst, i32 %n) {
114; Ensure (cast (load (...))) -> (load (cast (...))) preserves loop access
115; metadata.
116; CHECK-LABEL: @test_load_cast_combine_loop(
117; CHECK-NEXT:  entry:
118; CHECK-NEXT:    br label [[LOOP:%.*]]
119; CHECK:       loop:
120; CHECK-NEXT:    [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
121; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
122; CHECK-NEXT:    [[SRC_GEP:%.*]] = getelementptr inbounds float, ptr [[SRC:%.*]], i64 [[TMP0]]
123; CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[I]] to i64
124; CHECK-NEXT:    [[DST_GEP:%.*]] = getelementptr inbounds i32, ptr [[DST:%.*]], i64 [[TMP1]]
125; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[SRC_GEP]], align 4, !llvm.access.group [[ACC_GRP9:![0-9]+]]
126; CHECK-NEXT:    store i32 [[L1]], ptr [[DST_GEP]], align 4
127; CHECK-NEXT:    [[I_NEXT]] = add i32 [[I]], 1
128; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I_NEXT]], [[N:%.*]]
129; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]], !llvm.loop [[LOOP1:![0-9]+]]
130; CHECK:       exit:
131; CHECK-NEXT:    ret void
132;
133entry:
134  br label %loop
135
136loop:
137  %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
138  %src.gep = getelementptr inbounds float, ptr %src, i32 %i
139  %dst.gep = getelementptr inbounds i32, ptr %dst, i32 %i
140  %l = load float, ptr %src.gep, !llvm.access.group !10
141  %c = bitcast float %l to i32
142  store i32 %c, ptr %dst.gep
143  %i.next = add i32 %i, 1
144  %cmp = icmp slt i32 %i.next, %n
145  br i1 %cmp, label %loop, label %exit, !llvm.loop !1
146
147exit:
148  ret void
149}
150
151define void @test_load_cast_combine_nonnull(ptr %ptr) {
152; CHECK-LABEL: @test_load_cast_combine_nonnull(
153; CHECK-NEXT:  entry:
154; CHECK-NEXT:    [[P:%.*]] = load ptr, ptr [[PTR:%.*]], align 8, !nonnull [[META6]]
155; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 336
156; CHECK-NEXT:    store ptr [[P]], ptr [[GEP]], align 8
157; CHECK-NEXT:    ret void
158;
159entry:
160  %p = load ptr, ptr %ptr, !nonnull !{}
161  %gep = getelementptr ptr, ptr %ptr, i32 42
162  store ptr %p, ptr %gep
163  ret void
164}
165
166define i32 @test_load_cast_combine_noundef(ptr %ptr) {
167; CHECK-LABEL: @test_load_cast_combine_noundef(
168; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[PTR:%.*]], align 4, !noundef [[META6]]
169; CHECK-NEXT:    ret i32 [[L1]]
170;
171  %l = load float, ptr %ptr, !noundef !{}
172  %c = bitcast float %l to i32
173  ret i32 %c
174}
175
176define i32 @test_load_cast_combine_noalias_addrspace(ptr %ptr) {
177; Ensure (cast (load (...))) -> (load (cast (...))) preserves TBAA.
178; CHECK-LABEL: @test_load_cast_combine_noalias_addrspace(
179; CHECK-NEXT:  entry:
180; CHECK-NEXT:    [[L1:%.*]] = load i32, ptr [[PTR:%.*]], align 4
181; CHECK-NEXT:    ret i32 [[L1]]
182;
183entry:
184  %l = load float, ptr %ptr, align 4, !noalias.addrspace !11
185  %c = bitcast float %l to i32
186  ret i32 %c
187}
188
189; Preserve none-UB metadata on loads.
190define ptr @preserve_load_metadata_after_select_transform1(i1 %c, ptr dereferenceable(8) %a, ptr dereferenceable(8) %b) {
191; CHECK-LABEL: @preserve_load_metadata_after_select_transform1(
192; CHECK-NEXT:  entry:
193; CHECK-NEXT:    [[B_VAL:%.*]] = load ptr, ptr [[B:%.*]], align 1, !nonnull [[META6]], !align [[META8]]
194; CHECK-NEXT:    [[A_VAL:%.*]] = load ptr, ptr [[A:%.*]], align 1, !nonnull [[META6]], !align [[META8]]
195; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[C:%.*]], ptr [[B_VAL]], ptr [[A_VAL]]
196; CHECK-NEXT:    ret ptr [[L_SEL]]
197;
198entry:
199  %ptr.sel = select i1 %c, ptr %b, ptr %a
200  %l.sel = load ptr, ptr %ptr.sel, align 1, !tbaa !0, !llvm.access.group !7, !dereferenceable !9, !noundef !{}, !invariant.load !7, !align !9, !nonnull !{}
201  ret ptr %l.sel
202}
203
204; Preserve none-UB metadata on loads.
205define i32 @preserve_load_metadata_after_select_transform_range(i1 %c, ptr dereferenceable(8) %a, ptr dereferenceable(8) %b) {
206; CHECK-LABEL: @preserve_load_metadata_after_select_transform_range(
207; CHECK-NEXT:  entry:
208; CHECK-NEXT:    [[B_VAL:%.*]] = load i32, ptr [[B:%.*]], align 1, !range [[RNG10:![0-9]+]]
209; CHECK-NEXT:    [[A_VAL:%.*]] = load i32, ptr [[A:%.*]], align 1, !range [[RNG10]]
210; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[C:%.*]], i32 [[B_VAL]], i32 [[A_VAL]]
211; CHECK-NEXT:    ret i32 [[L_SEL]]
212;
213entry:
214  %ptr.sel = select i1 %c, ptr %b, ptr %a
215  %l.sel = load i32, ptr %ptr.sel, align 1, !tbaa !0, !llvm.access.group !7, !invariant.load !7, !noundef !{}, !range !6
216  ret i32 %l.sel
217}
218
219define double @preserve_load_metadata_after_select_transform2(ptr %a, ptr %b) {
220; CHECK-LABEL: @preserve_load_metadata_after_select_transform2(
221; CHECK-NEXT:  entry:
222; CHECK-NEXT:    [[L_A:%.*]] = load double, ptr [[A:%.*]], align 8, !tbaa [[TBAA0]], !llvm.access.group [[META6]]
223; CHECK-NEXT:    [[L_B:%.*]] = load double, ptr [[B:%.*]], align 8, !tbaa [[TBAA0]], !llvm.access.group [[META6]]
224; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp fast olt double [[L_A]], [[L_B]]
225; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[CMP_I]], double [[L_B]], double [[L_A]]
226; CHECK-NEXT:    ret double [[L_SEL]]
227;
228entry:
229  %l.a = load double, ptr %a, align 8, !tbaa !0, !llvm.access.group !7
230  %l.b = load double, ptr %b, align 8, !tbaa !0, !llvm.access.group !7
231  %cmp.i = fcmp fast olt double %l.a, %l.b
232  %ptr.sel = select i1 %cmp.i, ptr %b, ptr %a
233  %l.sel = load double, ptr %ptr.sel, align 8, !tbaa !0, !llvm.access.group !7
234  ret double %l.sel
235}
236
237define double @preserve_load_metadata_after_select_transform_metadata_missing_1(ptr %a, ptr %b) {
238; CHECK-LABEL: @preserve_load_metadata_after_select_transform_metadata_missing_1(
239; CHECK-NEXT:  entry:
240; CHECK-NEXT:    [[L_A:%.*]] = load double, ptr [[A:%.*]], align 8, !llvm.access.group [[META6]]
241; CHECK-NEXT:    [[L_B:%.*]] = load double, ptr [[B:%.*]], align 8, !tbaa [[TBAA0]], !llvm.access.group [[META6]]
242; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp fast olt double [[L_A]], [[L_B]]
243; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[CMP_I]], double [[L_B]], double [[L_A]]
244; CHECK-NEXT:    ret double [[L_SEL]]
245;
246entry:
247  %l.a = load double, ptr %a, align 8, !llvm.access.group !7
248  %l.b = load double, ptr %b, align 8, !tbaa !0, !llvm.access.group !7
249  %cmp.i = fcmp fast olt double %l.a, %l.b
250  %ptr.sel = select i1 %cmp.i, ptr %b, ptr %a
251  %l.sel = load double, ptr %ptr.sel, align 8, !tbaa !0, !llvm.access.group !7
252  ret double %l.sel
253}
254
255define double @preserve_load_metadata_after_select_transform_metadata_missing_2(ptr %a, ptr %b) {
256; CHECK-LABEL: @preserve_load_metadata_after_select_transform_metadata_missing_2(
257; CHECK-NEXT:  entry:
258; CHECK-NEXT:    [[L_A:%.*]] = load double, ptr [[A:%.*]], align 8, !llvm.access.group [[META6]]
259; CHECK-NEXT:    [[L_B:%.*]] = load double, ptr [[B:%.*]], align 8, !llvm.access.group [[META6]]
260; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp fast olt double [[L_A]], [[L_B]]
261; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[CMP_I]], double [[L_B]], double [[L_A]]
262; CHECK-NEXT:    ret double [[L_SEL]]
263;
264entry:
265  %l.a = load double, ptr %a, align 8, !llvm.access.group !7
266  %l.b = load double, ptr %b, align 8, !llvm.access.group !7
267  %cmp.i = fcmp fast olt double %l.a, %l.b
268  %ptr.sel = select i1 %cmp.i, ptr %b, ptr %a
269  %l.sel = load double, ptr %ptr.sel, align 8, !tbaa !0, !llvm.access.group !12
270  ret double %l.sel
271}
272
273define double @preserve_load_metadata_after_select_transform_metadata_missing_3(ptr %a, ptr %b) {
274; CHECK-LABEL: @preserve_load_metadata_after_select_transform_metadata_missing_3(
275; CHECK-NEXT:  entry:
276; CHECK-NEXT:    [[L_A:%.*]] = load double, ptr [[A:%.*]], align 8, !tbaa [[TBAA0]], !llvm.access.group [[META6]]
277; CHECK-NEXT:    [[L_B:%.*]] = load double, ptr [[B:%.*]], align 8, !tbaa [[TBAA0]], !llvm.access.group [[META6]]
278; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp fast olt double [[L_A]], [[L_B]]
279; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[CMP_I]], double [[L_B]], double [[L_A]]
280; CHECK-NEXT:    ret double [[L_SEL]]
281;
282entry:
283  %l.a = load double, ptr %a, align 8, !tbaa !0, !llvm.access.group !7
284  %l.b = load double, ptr %b, align 8, !tbaa !0, !llvm.access.group !7
285  %cmp.i = fcmp fast olt double %l.a, %l.b
286  %ptr.sel = select i1 %cmp.i, ptr %b, ptr %a
287  %l.sel = load double, ptr %ptr.sel, align 8, !tbaa !0, !llvm.access.group !13
288  ret double %l.sel
289}
290
291; Like preserve_load_metadata_after_select_transform_metadata_missing_3, but
292; with different access groups on all loads.
293define double @preserve_load_metadata_after_select_transform_metadata_missing_4(ptr %a, ptr %b) {
294; CHECK-LABEL: @preserve_load_metadata_after_select_transform_metadata_missing_4(
295; CHECK-NEXT:  entry:
296; CHECK-NEXT:    [[L_A:%.*]] = load double, ptr [[A:%.*]], align 8, !tbaa [[TBAA0]], !alias.scope [[META3]], !noalias [[META3]], !llvm.access.group [[META6]]
297; CHECK-NEXT:    [[L_B:%.*]] = load double, ptr [[B:%.*]], align 8, !tbaa [[TBAA0]], !alias.scope [[META11:![0-9]+]], !noalias [[META11]], !llvm.access.group [[ACC_GRP14:![0-9]+]]
298; CHECK-NEXT:    [[CMP_I:%.*]] = fcmp fast olt double [[L_A]], [[L_B]]
299; CHECK-NEXT:    [[L_SEL:%.*]] = select i1 [[CMP_I]], double [[L_B]], double [[L_A]]
300; CHECK-NEXT:    ret double [[L_SEL]]
301;
302entry:
303  %l.a = load double, ptr %a, align 8, !tbaa !0, !llvm.access.group !7, !alias.scope !3, !noalias !3
304  %l.b = load double, ptr %b, align 8, !tbaa !0, !llvm.access.group !12, !alias.scope !14, !noalias !14
305  %cmp.i = fcmp fast olt double %l.a, %l.b
306  %ptr.sel = select i1 %cmp.i, ptr %b, ptr %a
307  %l.sel = load double, ptr %ptr.sel, align 8, !tbaa !0, !llvm.access.group !13
308  ret double %l.sel
309}
310
311!0 = !{!1, !1, i64 0}
312!1 = !{!"scalar type", !2}
313!2 = !{!"root"}
314!3 = !{!4}
315!4 = distinct !{!4, !5}
316!5 = distinct !{!5}
317!6 = !{i32 0, i32 42}
318!7 = !{}
319!8 = !{i32 1}
320!9 = !{i64 8}
321!10 = distinct !{}
322!11 = !{i32 5, i32 6}
323!12 = distinct !{}
324!13 = distinct !{}
325!14 = !{!15}
326!15 = distinct !{!15, !16}
327!16 = distinct !{!16}
328
329;.
330; CHECK: [[TBAA0]] = !{[[LOOP1]], [[LOOP1]], i64 0}
331; CHECK: [[LOOP1]] = !{!"scalar type", [[META2:![0-9]+]]}
332; CHECK: [[META2]] = !{!"root"}
333; CHECK: [[META3]] = !{[[META4:![0-9]+]]}
334; CHECK: [[META4]] = distinct !{[[META4]], [[META5:![0-9]+]]}
335; CHECK: [[META5]] = distinct !{[[META5]]}
336; CHECK: [[META6]] = !{}
337; CHECK: [[META7]] = !{i32 1}
338; CHECK: [[META8]] = !{i64 8}
339; CHECK: [[ACC_GRP9]] = distinct !{}
340; CHECK: [[RNG10]] = !{i32 0, i32 42}
341; CHECK: [[META11]] = !{[[META12:![0-9]+]]}
342; CHECK: [[META12]] = distinct !{[[META12]], [[META13:![0-9]+]]}
343; CHECK: [[META13]] = distinct !{[[META13]]}
344; CHECK: [[ACC_GRP14]] = distinct !{}
345;.
346