1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s
4 ; This is the canonical form for a type-changing min/max.
5 define double @t1(float %a) {
7 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 5.000000e+00
8 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], float 5.000000e+00, float [[A]]
9 ; CHECK-NEXT: [[TMP2:%.*]] = fpext float [[TMP1]] to double
10 ; CHECK-NEXT: ret double [[TMP2]]
12 %1 = fcmp ult float %a, 5.0
13 %2 = select i1 %1, float %a, float 5.0
14 %3 = fpext float %2 to double
18 ; Check this is converted into canonical form, as above.
19 define double @t2(float %a) {
21 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 5.000000e+00
22 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], float 5.000000e+00, float [[A]]
23 ; CHECK-NEXT: [[TMP2:%.*]] = fpext float [[TMP1]] to double
24 ; CHECK-NEXT: ret double [[TMP2]]
26 %1 = fcmp ult float %a, 5.0
27 %2 = fpext float %a to double
28 %3 = select i1 %1, double %2, double 5.0
32 ; Same again, with trunc.
33 define float @t4(double %a) {
35 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge double [[A:%.*]], 5.000000e+00
36 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], double 5.000000e+00, double [[A]]
37 ; CHECK-NEXT: [[TMP2:%.*]] = fptrunc double [[TMP1]] to float
38 ; CHECK-NEXT: ret float [[TMP2]]
40 %1 = fcmp ult double %a, 5.0
41 %2 = fptrunc double %a to float
42 %3 = select i1 %1, float %2, float 5.0
46 ; different values, should not be converted.
47 define double @t5(float %a) {
49 ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult float [[A:%.*]], 5.000000e+00
50 ; CHECK-NEXT: [[TMP2:%.*]] = fpext float [[A]] to double
51 ; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], double [[TMP2]], double 5.001000e+00
52 ; CHECK-NEXT: ret double [[TMP3]]
54 %1 = fcmp ult float %a, 5.0
55 %2 = fpext float %a to double
56 %3 = select i1 %1, double %2, double 5.001
62 define float @not_maxnum(float %x) {
63 ; CHECK-LABEL: @not_maxnum(
64 ; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
65 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], float -0.000000e+00, float [[X]]
66 ; CHECK-NEXT: ret float [[SEL]]
68 %cmp = fcmp olt float %x, 0.0
69 %sel = select i1 %cmp, float -0.0, float %x
73 ; From IEEE754: "Comparisons shall ignore the sign of zero (so +0 = -0)."
74 ; So the compare constant may be treated as +0.0, and we sink the fpext.
76 define double @t6(float %a) {
78 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
79 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
80 ; CHECK-NEXT: [[TMP2:%.*]] = fpext float [[TMP1]] to double
81 ; CHECK-NEXT: ret double [[TMP2]]
83 %1 = fcmp ult float %a, -0.0
84 %2 = fpext float %a to double
85 %3 = select i1 %1, double %2, double 0.0
89 ; TODO: Move the select ahead of the fpext because it's a narrower op.
90 ; This works as long as the wide constant can be represented exactly in the narrow type.
92 define double @t7(float %a) {
94 ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult float [[A:%.*]], 0.000000e+00
95 ; CHECK-NEXT: [[TMP2:%.*]] = fpext float [[A]] to double
96 ; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], double [[TMP2]], double -0.000000e+00
97 ; CHECK-NEXT: ret double [[TMP3]]
99 %1 = fcmp ult float %a, 0.0
100 %2 = fpext float %a to double
101 %3 = select i1 %1, double %2, double -0.0
105 ; min(min(x, 0.0), 0.0) --> min(x, 0.0)
107 define float @fmin_fmin_zero_mismatch(float %x) {
108 ; CHECK-LABEL: @fmin_fmin_zero_mismatch(
109 ; CHECK-NEXT: [[CMP1:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
110 ; CHECK-NEXT: [[MIN2:%.*]] = select i1 [[CMP1]], float [[X]], float 0.000000e+00
111 ; CHECK-NEXT: ret float [[MIN2]]
113 %cmp1 = fcmp olt float %x, -0.0
114 %min1 = select i1 %cmp1, float %x, float 0.0
115 %cmp2 = fcmp olt float %min1, 0.0
116 %min2 = select i1 %cmp2, float %min1, float 0.0
120 ; max(max(x, -0.0), -0.0) --> max(x, -0.0)
121 define float @fmax_fmax_zero_mismatch(float %x) {
122 ; CHECK-LABEL: @fmax_fmax_zero_mismatch(
123 ; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt float [[X:%.*]], 0.000000e+00
124 ; CHECK-NEXT: [[MAX1:%.*]] = select i1 [[CMP1]], float [[X]], float -0.000000e+00
125 ; CHECK-NEXT: ret float [[MAX1]]
127 %cmp1 = fcmp ogt float %x, 0.0
128 %max1 = select i1 %cmp1, float %x, float -0.0
129 %cmp2 = fcmp ogt float 0.0, %max1
130 %max2 = select i1 %cmp2, float -0.0, float %max1
134 define i64 @t8(float %a) {
136 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 5.000000e+00
137 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], float 5.000000e+00, float [[A]]
138 ; CHECK-NEXT: [[TMP2:%.*]] = fptoui float [[TMP1]] to i64
139 ; CHECK-NEXT: ret i64 [[TMP2]]
141 %1 = fcmp ult float %a, 5.0
142 %2 = fptoui float %a to i64
143 %3 = select i1 %1, i64 %2, i64 5
147 define i8 @t9(float %a) {
149 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
150 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
151 ; CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i8
152 ; CHECK-NEXT: ret i8 [[TMP2]]
154 %1 = fcmp ult float %a, 0.0
155 %2 = fptosi float %a to i8
156 %3 = select i1 %1, i8 %2, i8 0
160 ; Either operand could be NaN, but fast modifier applied.
161 define i8 @t11(float %a, float %b) {
163 ; CHECK-NEXT: [[DOTV:%.*]] = call fast float @llvm.minnum.f32(float [[B:%.*]], float [[A:%.*]])
164 ; CHECK-NEXT: [[TMP1:%.*]] = fptosi float [[DOTV]] to i8
165 ; CHECK-NEXT: ret i8 [[TMP1]]
167 %1 = fcmp fast ult float %b, %a
168 %2 = fptosi float %a to i8
169 %3 = fptosi float %b to i8
170 %4 = select i1 %1, i8 %3, i8 %2
174 ; Either operand could be NaN, but nnan modifier applied.
175 define i8 @t12(float %a, float %b) {
177 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp nnan oge float [[B:%.*]], [[A:%.*]]
178 ; CHECK-NEXT: [[DOTV:%.*]] = select nnan i1 [[DOTINV]], float [[A]], float [[B]]
179 ; CHECK-NEXT: [[TMP1:%.*]] = fptosi float [[DOTV]] to i8
180 ; CHECK-NEXT: ret i8 [[TMP1]]
182 %1 = fcmp nnan ult float %b, %a
183 %2 = fptosi float %a to i8
184 %3 = fptosi float %b to i8
185 %4 = select i1 %1, i8 %3, i8 %2
189 ; Float and int values do not match.
190 define i8 @t13(float %a) {
192 ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ult float [[A:%.*]], 1.500000e+00
193 ; CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[A]] to i8
194 ; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP1]], i8 [[TMP2]], i8 1
195 ; CHECK-NEXT: ret i8 [[TMP3]]
197 %1 = fcmp ult float %a, 1.5
198 %2 = fptosi float %a to i8
199 %3 = select i1 %1, i8 %2, i8 1
203 ; %a could be -0.0, but it doesn't matter because the conversion to int is the same for 0.0 or -0.0.
204 define i8 @t14(float %a) {
206 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp oge float [[A:%.*]], 0.000000e+00
207 ; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], float 0.000000e+00, float [[A]]
208 ; CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i8
209 ; CHECK-NEXT: ret i8 [[TMP2]]
211 %1 = fcmp ule float %a, 0.0
212 %2 = fptosi float %a to i8
213 %3 = select i1 %1, i8 %2, i8 0
217 define i8 @t14_commute(float %a) {
218 ; CHECK-LABEL: @t14_commute(
219 ; CHECK-NEXT: [[TMP1:%.*]] = fcmp ogt float [[A:%.*]], 0.000000e+00
220 ; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float 0.000000e+00
221 ; CHECK-NEXT: [[TMP3:%.*]] = fptosi float [[TMP2]] to i8
222 ; CHECK-NEXT: ret i8 [[TMP3]]
224 %1 = fcmp ule float %a, 0.0
225 %2 = fptosi float %a to i8
226 %3 = select i1 %1, i8 0, i8 %2
230 define i8 @t15(float %a) {
232 ; CHECK-NEXT: [[DOTINV:%.*]] = fcmp nsz oge float [[A:%.*]], 0.000000e+00
233 ; CHECK-NEXT: [[TMP1:%.*]] = select nsz i1 [[DOTINV]], float 0.000000e+00, float [[A]]
234 ; CHECK-NEXT: [[TMP2:%.*]] = fptosi float [[TMP1]] to i8
235 ; CHECK-NEXT: ret i8 [[TMP2]]
237 %1 = fcmp nsz ule float %a, 0.0
238 %2 = fptosi float %a to i8
239 %3 = select i1 %1, i8 %2, i8 0
243 define double @t16(i32 %x) {
245 ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], 0
246 ; CHECK-NEXT: [[CST:%.*]] = sitofp i32 [[X]] to double
247 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], double [[CST]], double 5.000000e-01
248 ; CHECK-NEXT: ret double [[SEL]]
250 %cmp = icmp sgt i32 %x, 0
251 %cst = sitofp i32 %x to double
252 %sel = select i1 %cmp, double %cst, double 5.000000e-01
256 define double @t17(i32 %x) {
258 ; CHECK-NEXT: [[SEL1:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 2)
259 ; CHECK-NEXT: [[SEL:%.*]] = uitofp nneg i32 [[SEL1]] to double
260 ; CHECK-NEXT: ret double [[SEL]]
262 %cmp = icmp sgt i32 %x, 2
263 %cst = sitofp i32 %x to double
264 %sel = select i1 %cmp, double %cst, double 2.0
268 define float @fneg_fmax(float %x, float %y) {
269 ; CHECK-LABEL: @fneg_fmax(
270 ; CHECK-NEXT: [[COND:%.*]] = fcmp nnan olt float [[X:%.*]], [[Y:%.*]]
271 ; CHECK-NEXT: [[MAX_V:%.*]] = select i1 [[COND]], float [[X]], float [[Y]]
272 ; CHECK-NEXT: [[MAX:%.*]] = fneg float [[MAX_V]]
273 ; CHECK-NEXT: ret float [[MAX]]
277 %cond = fcmp nnan ogt float %n1, %n2
278 %max = select i1 %cond, float %n1, float %n2
282 define <2 x float> @fsub_fmax(<2 x float> %x, <2 x float> %y) {
283 ; CHECK-LABEL: @fsub_fmax(
284 ; CHECK-NEXT: [[MAX_V:%.*]] = call nnan nsz <2 x float> @llvm.minnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]])
285 ; CHECK-NEXT: [[MAX:%.*]] = fneg <2 x float> [[MAX_V]]
286 ; CHECK-NEXT: ret <2 x float> [[MAX]]
288 %n1 = fsub <2 x float> <float -0.0, float -0.0>, %x
289 %n2 = fsub <2 x float> <float -0.0, float -0.0>, %y
290 %cond = fcmp nsz nnan uge <2 x float> %n1, %n2
291 %max = select <2 x i1> %cond, <2 x float> %n1, <2 x float> %n2
295 define <2 x double> @fsub_fmin(<2 x double> %x, <2 x double> %y) {
296 ; CHECK-LABEL: @fsub_fmin(
297 ; CHECK-NEXT: [[COND:%.*]] = fcmp nnan ogt <2 x double> [[X:%.*]], [[Y:%.*]]
298 ; CHECK-NEXT: [[MAX_V:%.*]] = select <2 x i1> [[COND]], <2 x double> [[X]], <2 x double> [[Y]]
299 ; CHECK-NEXT: [[MAX:%.*]] = fneg <2 x double> [[MAX_V]]
300 ; CHECK-NEXT: ret <2 x double> [[MAX]]
302 %n1 = fsub <2 x double> <double -0.0, double -0.0>, %x
303 %n2 = fsub <2 x double> <double -0.0, double -0.0>, %y
304 %cond = fcmp nnan olt <2 x double> %n1, %n2
305 %max = select <2 x i1> %cond, <2 x double> %n1, <2 x double> %n2
306 ret <2 x double> %max
309 define double @fneg_fmin(double %x, double %y) {
310 ; CHECK-LABEL: @fneg_fmin(
311 ; CHECK-NEXT: [[MAX_V:%.*]] = call nnan nsz double @llvm.maxnum.f64(double [[X:%.*]], double [[Y:%.*]])
312 ; CHECK-NEXT: [[MAX:%.*]] = fneg double [[MAX_V]]
313 ; CHECK-NEXT: ret double [[MAX]]
317 %cond = fcmp nsz nnan ule double %n1, %n2
318 %max = select i1 %cond, double %n1, double %n2
322 define float @maxnum_ogt_fmf_on_select(float %a, float %b) {
323 ; CHECK-LABEL: @maxnum_ogt_fmf_on_select(
324 ; CHECK-NEXT: [[F:%.*]] = call nsz float @llvm.maxnum.f32(float [[A:%.*]], float [[B:%.*]])
325 ; CHECK-NEXT: ret float [[F]]
327 %cond = fcmp ogt float %a, %b
328 %f = select nnan nsz i1 %cond, float %a, float %b
332 define <2 x float> @maxnum_oge_fmf_on_select(<2 x float> %a, <2 x float> %b) {
333 ; CHECK-LABEL: @maxnum_oge_fmf_on_select(
334 ; CHECK-NEXT: [[F:%.*]] = call ninf nsz <2 x float> @llvm.maxnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])
335 ; CHECK-NEXT: ret <2 x float> [[F]]
337 %cond = fcmp oge <2 x float> %a, %b
338 %f = select ninf nnan nsz <2 x i1> %cond, <2 x float> %a, <2 x float> %b
342 define float @maxnum_ogt_fmf_on_fcmp(float %a, float %b) {
343 ; CHECK-LABEL: @maxnum_ogt_fmf_on_fcmp(
344 ; CHECK-NEXT: [[COND:%.*]] = fcmp nnan nsz ogt float [[A:%.*]], [[B:%.*]]
345 ; CHECK-NEXT: [[F:%.*]] = select i1 [[COND]], float [[A]], float [[B]]
346 ; CHECK-NEXT: ret float [[F]]
348 %cond = fcmp nnan nsz ogt float %a, %b
349 %f = select i1 %cond, float %a, float %b
353 define <2 x float> @maxnum_oge_fmf_on_fcmp(<2 x float> %a, <2 x float> %b) {
354 ; CHECK-LABEL: @maxnum_oge_fmf_on_fcmp(
355 ; CHECK-NEXT: [[COND:%.*]] = fcmp nnan ninf nsz oge <2 x float> [[A:%.*]], [[B:%.*]]
356 ; CHECK-NEXT: [[F:%.*]] = select <2 x i1> [[COND]], <2 x float> [[A]], <2 x float> [[B]]
357 ; CHECK-NEXT: ret <2 x float> [[F]]
359 %cond = fcmp ninf nnan nsz oge <2 x float> %a, %b
360 %f = select <2 x i1> %cond, <2 x float> %a, <2 x float> %b
364 define float @maxnum_no_nsz(float %a, float %b) {
365 ; CHECK-LABEL: @maxnum_no_nsz(
366 ; CHECK-NEXT: [[COND:%.*]] = fcmp ogt float [[A:%.*]], [[B:%.*]]
367 ; CHECK-NEXT: [[F:%.*]] = select nnan i1 [[COND]], float [[A]], float [[B]]
368 ; CHECK-NEXT: ret float [[F]]
370 %cond = fcmp ogt float %a, %b
371 %f = select nnan i1 %cond, float %a, float %b
375 define float @maxnum_no_nnan(float %a, float %b) {
376 ; CHECK-LABEL: @maxnum_no_nnan(
377 ; CHECK-NEXT: [[COND:%.*]] = fcmp oge float [[A:%.*]], [[B:%.*]]
378 ; CHECK-NEXT: [[F:%.*]] = select nsz i1 [[COND]], float [[A]], float [[B]]
379 ; CHECK-NEXT: ret float [[F]]
381 %cond = fcmp oge float %a, %b
382 %f = select nsz i1 %cond, float %a, float %b
386 define float @minnum_olt_fmf_on_select(float %a, float %b) {
387 ; CHECK-LABEL: @minnum_olt_fmf_on_select(
388 ; CHECK-NEXT: [[F:%.*]] = call nsz float @llvm.minnum.f32(float [[A:%.*]], float [[B:%.*]])
389 ; CHECK-NEXT: ret float [[F]]
391 %cond = fcmp olt float %a, %b
392 %f = select nnan nsz i1 %cond, float %a, float %b
396 define <2 x float> @minnum_ole_fmf_on_select(<2 x float> %a, <2 x float> %b) {
397 ; CHECK-LABEL: @minnum_ole_fmf_on_select(
398 ; CHECK-NEXT: [[F:%.*]] = call ninf nsz <2 x float> @llvm.minnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])
399 ; CHECK-NEXT: ret <2 x float> [[F]]
401 %cond = fcmp ole <2 x float> %a, %b
402 %f = select ninf nnan nsz <2 x i1> %cond, <2 x float> %a, <2 x float> %b
406 define float @minnum_olt_fmf_on_fcmp(float %a, float %b) {
407 ; CHECK-LABEL: @minnum_olt_fmf_on_fcmp(
408 ; CHECK-NEXT: [[COND:%.*]] = fcmp nnan nsz olt float [[A:%.*]], [[B:%.*]]
409 ; CHECK-NEXT: [[F:%.*]] = select i1 [[COND]], float [[A]], float [[B]]
410 ; CHECK-NEXT: ret float [[F]]
412 %cond = fcmp nnan nsz olt float %a, %b
413 %f = select i1 %cond, float %a, float %b
417 define <2 x float> @minnum_ole_fmf_on_fcmp(<2 x float> %a, <2 x float> %b) {
418 ; CHECK-LABEL: @minnum_ole_fmf_on_fcmp(
419 ; CHECK-NEXT: [[COND:%.*]] = fcmp nnan ninf nsz ole <2 x float> [[A:%.*]], [[B:%.*]]
420 ; CHECK-NEXT: [[F:%.*]] = select <2 x i1> [[COND]], <2 x float> [[A]], <2 x float> [[B]]
421 ; CHECK-NEXT: ret <2 x float> [[F]]
423 %cond = fcmp ninf nnan nsz ole <2 x float> %a, %b
424 %f = select <2 x i1> %cond, <2 x float> %a, <2 x float> %b
428 define float @minnum_no_nsz(float %a, float %b) {
429 ; CHECK-LABEL: @minnum_no_nsz(
430 ; CHECK-NEXT: [[COND:%.*]] = fcmp olt float [[A:%.*]], [[B:%.*]]
431 ; CHECK-NEXT: [[F:%.*]] = select nnan i1 [[COND]], float [[A]], float [[B]]
432 ; CHECK-NEXT: ret float [[F]]
434 %cond = fcmp olt float %a, %b
435 %f = select nnan i1 %cond, float %a, float %b
439 define float @minnum_no_nnan(float %a, float %b) {
440 ; CHECK-LABEL: @minnum_no_nnan(
441 ; CHECK-NEXT: [[COND:%.*]] = fcmp ole float [[A:%.*]], [[B:%.*]]
442 ; CHECK-NEXT: [[F:%.*]] = select nsz i1 [[COND]], float [[A]], float [[B]]
443 ; CHECK-NEXT: ret float [[F]]
445 %cond = fcmp ole float %a, %b
446 %f = select nsz i1 %cond, float %a, float %b
450 define float @pr64937_preserve_min_idiom(float %a) {
451 ; CHECK-LABEL: @pr64937_preserve_min_idiom(
452 ; CHECK-NEXT: [[CMP:%.*]] = fcmp nnan olt float [[A:%.*]], 3.276700e+04
453 ; CHECK-NEXT: [[SEL:%.*]] = select nnan i1 [[CMP]], float [[A]], float 3.276700e+04
454 ; CHECK-NEXT: [[RES:%.*]] = fmul nnan float [[SEL]], 6.553600e+04
455 ; CHECK-NEXT: ret float [[RES]]
457 %cmp = fcmp nnan olt float %a, 3.276700e+04
458 %sel = select nnan i1 %cmp, float %a, float 3.276700e+04
459 %res = fmul nnan float %sel, 6.553600e+04