xref: /llvm-project/llvm/test/Transforms/AggressiveInstCombine/patterned-load.ll (revision 39a0677784d1b53f2d6e33af2a53e915f3f62c86)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=aggressive-instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=CHECK,LE
3; RUN: opt < %s -passes=aggressive-instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=CHECK,BE
4
5
6@constarray1 = internal constant [8 x i8]  c"\01\00\01\00\01\00\01\00", align 4
7@constarray2 = internal constant [8 x i8]  c"\FF\FF\01\00\01\00\01\00", align 4
8
9@g = internal constant i32 42
10@constptrarray = internal constant [4 x ptr]  [ptr @g, ptr @g, ptr @g, ptr @g], align 4
11
12@constpackedstruct = internal constant <{[8 x i8]}>  <{[8 x i8] c"\01\00\01\00\01\00\01\00"}>, align 4
13@conststruct = internal constant {i16, [8 x i8]}  {i16 1, [8 x i8] c"\01\00\01\00\01\00\01\00"}, align 4
14
15%struct = type { i128 }
16@global = internal constant %struct { i128 1 }
17; TODO: this should be folded, but currently i128 is not folded.
18define i32 @no-gep-128-struct(i64 %idx){
19; CHECK-LABEL: @no-gep-128-struct(
20; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr @global, align 4
21; CHECK-NEXT:    ret i32 [[TMP1]]
22;
23  %1 = load i32, ptr @global, align 4
24  ret i32 %1
25}
26
27define i8 @inbounds_gep_load_i8_align2(i64 %idx){
28; CHECK-LABEL: @inbounds_gep_load_i8_align2(
29; CHECK-NEXT:    ret i8 1
30;
31  %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx
32  %2 = load i8, ptr %1, align 2
33  ret i8 %2
34}
35
36; can't be folded because access with i8 strides is not patterned.
37define i8 @inbounds_gep_load_i8_align1(i64 %idx){
38; CHECK-LABEL: @inbounds_gep_load_i8_align1(
39; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constarray1, i64 [[IDX:%.*]]
40; CHECK-NEXT:    [[TMP2:%.*]] = load i8, ptr [[TMP1]], align 1
41; CHECK-NEXT:    ret i8 [[TMP2]]
42;
43  %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx
44  %2 = load i8, ptr %1, align 1
45  ret i8 %2
46}
47
48; can't be folded because volatile load cannot assure same results.
49define i8 @inbounds_gep_load_i8_align2_volatile(i64 %idx){
50; CHECK-LABEL: @inbounds_gep_load_i8_align2_volatile(
51; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constarray1, i64 [[IDX:%.*]]
52; CHECK-NEXT:    [[TMP2:%.*]] = load volatile i8, ptr [[TMP1]], align 2
53; CHECK-NEXT:    ret i8 [[TMP2]]
54;
55  %1 = getelementptr inbounds i8, ptr @constarray1, i64 %idx
56  %2 = load volatile i8, ptr %1, align 2
57  ret i8 %2
58}
59
60declare ptr @llvm.ptrmask.p0.i64(ptr , i64)
61
62; can't be folded because ptrmask can change ptr, while preserving provenance
63; This invalidates GEP indices analysis
64define i8 @inbounds_gep_load_i16_align1_ptrmasked(i64 %idx, i64 %mask){
65; CHECK-LABEL: @inbounds_gep_load_i16_align1_ptrmasked(
66; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr @constarray1, i64 [[MASK:%.*]])
67; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i16, ptr [[TMP1]], i64 [[IDX:%.*]]
68; CHECK-NEXT:    [[TMP3:%.*]] = load i8, ptr [[TMP2]], align 1
69; CHECK-NEXT:    ret i8 [[TMP3]]
70;
71  %1 = call ptr @llvm.ptrmask.p0.i64(ptr @constarray1, i64 %mask)
72  %2 = getelementptr inbounds i16, ptr %1, i64 %idx
73  %3 = load i8, ptr %2, align 1
74  ret i8 %3
75}
76
77define i32 @inbounds_gep_i16_load_i32_align1(i64 %idx){
78; LE-LABEL: @inbounds_gep_i16_load_i32_align1(
79; LE-NEXT:    ret i32 65537
80;
81; BE-LABEL: @inbounds_gep_i16_load_i32_align1(
82; BE-NEXT:    ret i32 16777472
83;
84  %1 = getelementptr inbounds i16, ptr @constarray1, i64 %idx
85  %2 = load i32, ptr %1, align 1
86  ret i32 %2
87}
88
89define i32 @inbounds_gep_i32_load_i32_align8(i64 %idx){
90; LE-LABEL: @inbounds_gep_i32_load_i32_align8(
91; LE-NEXT:    ret i32 65537
92;
93; BE-LABEL: @inbounds_gep_i32_load_i32_align8(
94; BE-NEXT:    ret i32 16777472
95;
96  %1 = getelementptr inbounds i32, ptr @constarray1, i64 %idx
97  %2 = load i32, ptr %1, align 8
98  ret i32 %2
99}
100
101define i32 @inbounds_gep_i32_load_i32_const_offset(i64 %idx){
102; LE-LABEL: @inbounds_gep_i32_load_i32_const_offset(
103; LE-NEXT:    ret i32 65537
104;
105; BE-LABEL: @inbounds_gep_i32_load_i32_const_offset(
106; BE-NEXT:    ret i32 16777472
107;
108  %1 = getelementptr inbounds i16, ptr @constarray2, i64 1
109  %2 = getelementptr inbounds i32, ptr %1, i64 %idx
110  %3 = load i32, ptr %2, align 4
111  ret i32 %3
112}
113
114define i32 @gep_load_i32_align2_const_offset(i64 %idx){
115; LE-LABEL: @gep_load_i32_align2_const_offset(
116; LE-NEXT:    ret i32 65537
117;
118; BE-LABEL: @gep_load_i32_align2_const_offset(
119; BE-NEXT:    ret i32 16777472
120;
121  %1 = getelementptr i16, ptr @constarray1, i64 -2
122  %2 = getelementptr [3 x i16], ptr %1, i64 %idx
123  %3 = load i32, ptr %2, align 2
124  ret i32 %3
125}
126
127; can't be folded because if gep is non-inbounds,
128; the offsets are silently-wrapped with two’s complement arithmetic(mod 2**64).
129; So the load operand can be a base pointer of constarray2.
130define i32 @gep_load_i32_align2_const_offset_wrap(i64 %idx){
131; CHECK-LABEL: @gep_load_i32_align2_const_offset_wrap(
132; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i16, ptr @constarray2, i64 -2
133; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr [3 x i16], ptr [[TMP1]], i64 [[IDX:%.*]]
134; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 2
135; CHECK-NEXT:    ret i32 [[TMP3]]
136;
137  %1 = getelementptr i16, ptr @constarray2, i64 -2
138  %2 = getelementptr [3 x i16], ptr %1, i64 %idx
139  %3 = load i32, ptr %2, align 2
140  ret i32 %3
141}
142
143define i32 @inbounds_gep_i32_load_i32_const_ptr_array(i64 %idx){
144; CHECK-LABEL: @inbounds_gep_i32_load_i32_const_ptr_array(
145; CHECK-NEXT:    ret i32 42
146;
147  %1 = getelementptr inbounds ptr, ptr @constptrarray, i64 %idx
148  %2 = load ptr, ptr %1, align 4
149  %3 = load i32, ptr %2, align 4
150  ret i32 %3
151}
152
153define i32 @inbounds_gep_i32_load_i32_align4_packedstruct(i64 %idx){
154; LE-LABEL: @inbounds_gep_i32_load_i32_align4_packedstruct(
155; LE-NEXT:    ret i32 65537
156;
157; BE-LABEL: @inbounds_gep_i32_load_i32_align4_packedstruct(
158; BE-NEXT:    ret i32 16777472
159;
160  %1 = getelementptr inbounds i32, ptr @constpackedstruct, i64 %idx
161  %2 = load i32, ptr %1, align 4
162  ret i32 %2
163}
164
165; can't be folded because results are not equal
166define i32 @inbounds_gep_i8_load_i32_align1_packedstruct(i64 %idx){
167; CHECK-LABEL: @inbounds_gep_i8_load_i32_align1_packedstruct(
168; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr @constpackedstruct, i64 [[IDX:%.*]]
169; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[TMP1]], align 1
170; CHECK-NEXT:    ret i32 [[TMP2]]
171;
172  %1 = getelementptr inbounds i8, ptr @constpackedstruct, i64 %idx
173  %2 = load i32, ptr %1, align 1
174  ret i32 %2
175}
176
177define i32 @inbounds_gep_i32_load_i32_align4_struct_with_const_offset(i64 %idx){
178; LE-LABEL: @inbounds_gep_i32_load_i32_align4_struct_with_const_offset(
179; LE-NEXT:    ret i32 65537
180;
181; BE-LABEL: @inbounds_gep_i32_load_i32_align4_struct_with_const_offset(
182; BE-NEXT:    ret i32 16777472
183;
184  %1 = getelementptr inbounds i16, ptr @conststruct, i64 1
185  %2 = getelementptr inbounds i32, ptr %1, i64 %idx
186  %3 = load i32, ptr %2, align 4
187  ret i32 %3
188}
189
190