xref: /llvm-project/llvm/test/Transforms/SCCP/with.overflow.ll (revision 106ed59fe962e0443d2f59a81fa6f52875ced5c0)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=sccp < %s | FileCheck %s
3
4declare { i8, i1 } @llvm.uadd.with.overflow.i8(i8, i8)
5declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8)
6declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8)
7declare { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8)
8declare { i8, i1 } @llvm.ssub.with.overflow.i8(i8, i8)
9declare { i8, i1 } @llvm.smul.with.overflow.i8(i8, i8)
10declare { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8>, <2 x i8>)
11declare void @use.i1(i1)
12
13define void @unsigned_overflow(ptr %p) {
14; CHECK-LABEL: @unsigned_overflow(
15; CHECK-NEXT:    [[V0_100:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0:![0-9]+]]
16; CHECK-NEXT:    [[V0_155:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG1:![0-9]+]]
17; CHECK-NEXT:    [[V0_156:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG2:![0-9]+]]
18; CHECK-NEXT:    [[V100_255:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG3:![0-9]+]]
19; CHECK-NEXT:    [[V99_255:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG4:![0-9]+]]
20; CHECK-NEXT:    [[V1_2:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG5:![0-9]+]]
21; CHECK-NEXT:    [[V1_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG6:![0-9]+]]
22; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_155]])
23; CHECK-NEXT:    call void @use.i1(i1 false)
24; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_156]])
25; CHECK-NEXT:    [[OV2:%.*]] = extractvalue { i8, i1 } [[WO2]], 1
26; CHECK-NEXT:    call void @use.i1(i1 [[OV2]])
27; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V100_255]], i8 [[V0_100]])
28; CHECK-NEXT:    call void @use.i1(i1 false)
29; CHECK-NEXT:    [[WO4:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V99_255]], i8 [[V0_100]])
30; CHECK-NEXT:    [[OV4:%.*]] = extractvalue { i8, i1 } [[WO4]], 1
31; CHECK-NEXT:    call void @use.i1(i1 [[OV4]])
32; CHECK-NEXT:    [[WO5:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V0_100]], i8 [[V1_2]])
33; CHECK-NEXT:    call void @use.i1(i1 false)
34; CHECK-NEXT:    [[WO6:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V0_100]], i8 [[V1_3]])
35; CHECK-NEXT:    [[OV6:%.*]] = extractvalue { i8, i1 } [[WO6]], 1
36; CHECK-NEXT:    call void @use.i1(i1 [[OV6]])
37; CHECK-NEXT:    ret void
38;
39  %v0_100 = load i8, ptr %p, !range !{i8 0, i8 101}
40  %v0_155 = load i8, ptr %p, !range !{i8 0, i8 156}
41  %v0_156 = load i8, ptr %p, !range !{i8 0, i8 157}
42  %v100_255 = load i8, ptr %p, !range !{i8 100, i8 0}
43  %v99_255 = load i8, ptr %p, !range !{i8 99, i8 0}
44  %v1_2 = load i8, ptr %p, !range !{i8 1, i8 3}
45  %v1_3 = load i8, ptr %p, !range !{i8 1, i8 4}
46
47  %wo1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_100, i8 %v0_155)
48  %ov1 = extractvalue { i8, i1 } %wo1, 1
49  call void @use.i1(i1 %ov1)
50
51  %wo2 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_100, i8 %v0_156)
52  %ov2 = extractvalue { i8, i1 } %wo2, 1
53  call void @use.i1(i1 %ov2)
54
55  %wo3 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v100_255, i8 %v0_100)
56  %ov3 = extractvalue { i8, i1 } %wo3, 1
57  call void @use.i1(i1 %ov3)
58
59  %wo4 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v99_255, i8 %v0_100)
60  %ov4 = extractvalue { i8, i1 } %wo4, 1
61  call void @use.i1(i1 %ov4)
62
63  %wo5 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v0_100, i8 %v1_2)
64  %ov5 = extractvalue { i8, i1 } %wo5, 1
65  call void @use.i1(i1 %ov5)
66
67  %wo6 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v0_100, i8 %v1_3)
68  %ov6 = extractvalue { i8, i1 } %wo6, 1
69  call void @use.i1(i1 %ov6)
70  ret void
71}
72
73define void @signed_overflow(ptr %p) {
74; CHECK-LABEL: @signed_overflow(
75; CHECK-NEXT:    [[V0_100:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0]]
76; CHECK-NEXT:    [[V0_27:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG7:![0-9]+]]
77; CHECK-NEXT:    [[V0_28:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG8:![0-9]+]]
78; CHECK-NEXT:    [[VM27_0:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG9:![0-9]+]]
79; CHECK-NEXT:    [[VM28_0:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG10:![0-9]+]]
80; CHECK-NEXT:    [[V1_4:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG11:![0-9]+]]
81; CHECK-NEXT:    [[V1_5:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG12:![0-9]+]]
82; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_27]])
83; CHECK-NEXT:    call void @use.i1(i1 false)
84; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_100]], i8 [[V0_28]])
85; CHECK-NEXT:    [[OV2:%.*]] = extractvalue { i8, i1 } [[WO2]], 1
86; CHECK-NEXT:    call void @use.i1(i1 [[OV2]])
87; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_100]], i8 [[VM27_0]])
88; CHECK-NEXT:    call void @use.i1(i1 false)
89; CHECK-NEXT:    [[WO4:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_100]], i8 [[VM28_0]])
90; CHECK-NEXT:    [[OV4:%.*]] = extractvalue { i8, i1 } [[WO4]], 1
91; CHECK-NEXT:    call void @use.i1(i1 [[OV4]])
92; CHECK-NEXT:    [[WO5:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V0_27]], i8 [[V1_4]])
93; CHECK-NEXT:    call void @use.i1(i1 false)
94; CHECK-NEXT:    [[WO6:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V0_27]], i8 [[V1_5]])
95; CHECK-NEXT:    [[OV6:%.*]] = extractvalue { i8, i1 } [[WO6]], 1
96; CHECK-NEXT:    call void @use.i1(i1 [[OV6]])
97; CHECK-NEXT:    ret void
98;
99  %v0_100 = load i8, ptr %p, !range !{i8 0, i8 101}
100  %v0_27 = load i8, ptr %p, !range !{i8 0, i8 28}
101  %v0_28 = load i8, ptr %p, !range !{i8 0, i8 29}
102  %vm27_0 = load i8, ptr %p, !range !{i8 -27, i8 0}
103  %vm28_0 = load i8, ptr %p, !range !{i8 -28, i8 0}
104  %v1_4 = load i8, ptr %p, !range !{i8 1, i8 5}
105  %v1_5 = load i8, ptr %p, !range !{i8 1, i8 6}
106
107  %wo1 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_100, i8 %v0_27)
108  %ov1 = extractvalue { i8, i1 } %wo1, 1
109  call void @use.i1(i1 %ov1)
110
111  %wo2 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_100, i8 %v0_28)
112  %ov2 = extractvalue { i8, i1 } %wo2, 1
113  call void @use.i1(i1 %ov2)
114
115  %wo3 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_100, i8 %vm27_0)
116  %ov3 = extractvalue { i8, i1 } %wo3, 1
117  call void @use.i1(i1 %ov3)
118
119  %wo4 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_100, i8 %vm28_0)
120  %ov4 = extractvalue { i8, i1 } %wo4, 1
121  call void @use.i1(i1 %ov4)
122
123  %wo5 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v0_27, i8 %v1_4)
124  %ov5 = extractvalue { i8, i1 } %wo5, 1
125  call void @use.i1(i1 %ov5)
126
127  %wo6 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v0_27, i8 %v1_5)
128  %ov6 = extractvalue { i8, i1 } %wo6, 1
129  call void @use.i1(i1 %ov6)
130  ret void
131}
132
133define void @unsigned_result(ptr %p) {
134; CHECK-LABEL: @unsigned_result(
135; CHECK-NEXT:    [[V0_20:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG13:![0-9]+]]
136; CHECK-NEXT:    [[V20_40:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG14:![0-9]+]]
137; CHECK-NEXT:    [[V0_10:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG15:![0-9]+]]
138; CHECK-NEXT:    [[V2_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG16:![0-9]+]]
139; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 [[V0_20]], i8 [[V20_40]])
140; CHECK-NEXT:    [[RES1:%.*]] = extractvalue { i8, i1 } [[WO1]], 0
141; CHECK-NEXT:    call void @use.i1(i1 true)
142; CHECK-NEXT:    call void @use.i1(i1 true)
143; CHECK-NEXT:    [[CMP1_3:%.*]] = icmp ugt i8 [[RES1]], 20
144; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_3]])
145; CHECK-NEXT:    [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60
146; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_4]])
147; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[V0_10]], i8 [[V20_40]])
148; CHECK-NEXT:    [[RES2:%.*]] = extractvalue { i8, i1 } [[WO2]], 0
149; CHECK-NEXT:    call void @use.i1(i1 true)
150; CHECK-NEXT:    call void @use.i1(i1 true)
151; CHECK-NEXT:    [[CMP2_3:%.*]] = icmp ugt i8 [[RES2]], -40
152; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_3]])
153; CHECK-NEXT:    [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10
154; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_4]])
155; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[V20_40]], i8 [[V2_3]])
156; CHECK-NEXT:    [[RES3:%.*]] = extractvalue { i8, i1 } [[WO3]], 0
157; CHECK-NEXT:    call void @use.i1(i1 true)
158; CHECK-NEXT:    call void @use.i1(i1 true)
159; CHECK-NEXT:    [[CMP3_3:%.*]] = icmp ugt i8 [[RES3]], 40
160; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_3]])
161; CHECK-NEXT:    [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120
162; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_4]])
163; CHECK-NEXT:    ret void
164;
165  %v0_20 = load i8, ptr %p, !range !{i8 0, i8 21}
166  %v20_40 = load i8, ptr %p, !range !{i8 20, i8 41}
167  %v0_10 = load i8, ptr %p, !range !{i8 0, i8 11}
168  %v2_3 = load i8, ptr %p, !range !{i8 2, i8 4}
169  %wo1 = call { i8, i1 } @llvm.uadd.with.overflow.i8(i8 %v0_20, i8 %v20_40)
170  %res1 = extractvalue { i8, i1 } %wo1, 0
171  %cmp1.1 = icmp uge i8 %res1, 20
172  call void @use.i1(i1 %cmp1.1)
173  %cmp1.2 = icmp ule i8 %res1, 60
174  call void @use.i1(i1 %cmp1.2)
175  %cmp1.3 = icmp ugt i8 %res1, 20
176  call void @use.i1(i1 %cmp1.3)
177  %cmp1.4 = icmp ult i8 %res1, 60
178  call void @use.i1(i1 %cmp1.4)
179
180  ; This case actually does overflow, but we can still determine the range.
181  %wo2 = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %v0_10, i8 %v20_40)
182  %res2 = extractvalue { i8, i1 } %wo2, 0
183  %cmp2.1 = icmp uge i8 %res2, -40
184  call void @use.i1(i1 %cmp2.1)
185  %cmp2.2 = icmp ule i8 %res2, -10
186  call void @use.i1(i1 %cmp2.2)
187  %cmp2.3 = icmp ugt i8 %res2, -40
188  call void @use.i1(i1 %cmp2.3)
189  %cmp2.4 = icmp ult i8 %res2, -10
190  call void @use.i1(i1 %cmp2.4)
191
192  %wo3 = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 %v20_40, i8 %v2_3)
193  %res3 = extractvalue { i8, i1 } %wo3, 0
194  %cmp3.1 = icmp uge i8 %res3, 40
195  call void @use.i1(i1 %cmp3.1)
196  %cmp3.2 = icmp ule i8 %res3, 120
197  call void @use.i1(i1 %cmp3.2)
198  %cmp3.3 = icmp ugt i8 %res3, 40
199  call void @use.i1(i1 %cmp3.3)
200  %cmp3.4 = icmp ult i8 %res3, 120
201  call void @use.i1(i1 %cmp3.4)
202  ret void
203}
204
205define void @signed_result(ptr %p) {
206; CHECK-LABEL: @signed_result(
207; CHECK-NEXT:    [[V0_20:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG13]]
208; CHECK-NEXT:    [[V20_40:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG14]]
209; CHECK-NEXT:    [[V0_10:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG15]]
210; CHECK-NEXT:    [[V2_3:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG16]]
211; CHECK-NEXT:    [[WO1:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[V0_20]], i8 [[V20_40]])
212; CHECK-NEXT:    [[RES1:%.*]] = extractvalue { i8, i1 } [[WO1]], 0
213; CHECK-NEXT:    call void @use.i1(i1 true)
214; CHECK-NEXT:    call void @use.i1(i1 true)
215; CHECK-NEXT:    [[CMP1_3:%.*]] = icmp ugt i8 [[RES1]], 20
216; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_3]])
217; CHECK-NEXT:    [[CMP1_4:%.*]] = icmp ult i8 [[RES1]], 60
218; CHECK-NEXT:    call void @use.i1(i1 [[CMP1_4]])
219; CHECK-NEXT:    [[WO2:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[V0_10]], i8 [[V20_40]])
220; CHECK-NEXT:    [[RES2:%.*]] = extractvalue { i8, i1 } [[WO2]], 0
221; CHECK-NEXT:    call void @use.i1(i1 true)
222; CHECK-NEXT:    call void @use.i1(i1 true)
223; CHECK-NEXT:    [[CMP2_3:%.*]] = icmp ugt i8 [[RES2]], -40
224; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_3]])
225; CHECK-NEXT:    [[CMP2_4:%.*]] = icmp ult i8 [[RES2]], -10
226; CHECK-NEXT:    call void @use.i1(i1 [[CMP2_4]])
227; CHECK-NEXT:    [[WO3:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[V20_40]], i8 [[V2_3]])
228; CHECK-NEXT:    [[RES3:%.*]] = extractvalue { i8, i1 } [[WO3]], 0
229; CHECK-NEXT:    call void @use.i1(i1 true)
230; CHECK-NEXT:    call void @use.i1(i1 true)
231; CHECK-NEXT:    [[CMP3_3:%.*]] = icmp ugt i8 [[RES3]], 40
232; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_3]])
233; CHECK-NEXT:    [[CMP3_4:%.*]] = icmp ult i8 [[RES3]], 120
234; CHECK-NEXT:    call void @use.i1(i1 [[CMP3_4]])
235; CHECK-NEXT:    ret void
236;
237  %v0_20 = load i8, ptr %p, !range !{i8 0, i8 21}
238  %v20_40 = load i8, ptr %p, !range !{i8 20, i8 41}
239  %v0_10 = load i8, ptr %p, !range !{i8 0, i8 11}
240  %v2_3 = load i8, ptr %p, !range !{i8 2, i8 4}
241  %wo1 = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %v0_20, i8 %v20_40)
242  %res1 = extractvalue { i8, i1 } %wo1, 0
243  %cmp1.1 = icmp uge i8 %res1, 20
244  call void @use.i1(i1 %cmp1.1)
245  %cmp1.2 = icmp ule i8 %res1, 60
246  call void @use.i1(i1 %cmp1.2)
247  %cmp1.3 = icmp ugt i8 %res1, 20
248  call void @use.i1(i1 %cmp1.3)
249  %cmp1.4 = icmp ult i8 %res1, 60
250  call void @use.i1(i1 %cmp1.4)
251
252  %wo2 = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %v0_10, i8 %v20_40)
253  %res2 = extractvalue { i8, i1 } %wo2, 0
254  %cmp2.1 = icmp uge i8 %res2, -40
255  call void @use.i1(i1 %cmp2.1)
256  %cmp2.2 = icmp ule i8 %res2, -10
257  call void @use.i1(i1 %cmp2.2)
258  %cmp2.3 = icmp ugt i8 %res2, -40
259  call void @use.i1(i1 %cmp2.3)
260  %cmp2.4 = icmp ult i8 %res2, -10
261  call void @use.i1(i1 %cmp2.4)
262
263  %wo3 = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 %v20_40, i8 %v2_3)
264  %res3 = extractvalue { i8, i1 } %wo3, 0
265  %cmp3.1 = icmp uge i8 %res3, 40
266  call void @use.i1(i1 %cmp3.1)
267  %cmp3.2 = icmp ule i8 %res3, 120
268  call void @use.i1(i1 %cmp3.2)
269  %cmp3.3 = icmp ugt i8 %res3, 40
270  call void @use.i1(i1 %cmp3.3)
271  %cmp3.4 = icmp ult i8 %res3, 120
272  call void @use.i1(i1 %cmp3.4)
273  ret void
274}
275
276; SCCP doesn't really support vector ranges yet, just make sure we don't crash.
277define <2 x i1> @vec(<2 x i8> %v1, <2 x i8> %v2) {
278; CHECK-LABEL: @vec(
279; CHECK-NEXT:    [[WO:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[V1:%.*]], <2 x i8> [[V2:%.*]])
280; CHECK-NEXT:    [[OV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[WO]], 1
281; CHECK-NEXT:    ret <2 x i1> [[OV]]
282;
283  %wo = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> %v1, <2 x i8> %v2)
284  %ov = extractvalue { <2 x i8>, <2 x i1> } %wo, 1
285  ret <2 x i1> %ov
286}
287