Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / InstSimplify / fast-math.ll
blobd1818e6346d7a37539d6cb970eec349419425d28
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
4 ;; x * 0 ==> 0 when no-nans and no-signed-zero
5 define float @mul_zero_1(float %a) {
6 ; CHECK-LABEL: @mul_zero_1(
7 ; CHECK-NEXT:    ret float 0.000000e+00
9   %b = fmul nsz nnan float %a, 0.0
10   ret float %b
13 define float @mul_zero_2(float %a) {
14 ; CHECK-LABEL: @mul_zero_2(
15 ; CHECK-NEXT:    ret float 0.000000e+00
17   %b = fmul fast float 0.0, %a
18   ret float %b
21 define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) {
22 ; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef(
23 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
25   %b = fmul nsz nnan <2 x float> %a, <float 0.0, float undef>
26   ret <2 x float> %b
29 ;; x * 0 =/=> 0 when there could be nans or -0
30 define float @no_mul_zero_1(float %a) {
31 ; CHECK-LABEL: @no_mul_zero_1(
32 ; CHECK-NEXT:    [[B:%.*]] = fmul nsz float [[A:%.*]], 0.000000e+00
33 ; CHECK-NEXT:    ret float [[B]]
35   %b = fmul nsz float %a, 0.0
36   ret float %b
39 define float @no_mul_zero_2(float %a) {
40 ; CHECK-LABEL: @no_mul_zero_2(
41 ; CHECK-NEXT:    [[B:%.*]] = fmul nnan float [[A:%.*]], 0.000000e+00
42 ; CHECK-NEXT:    ret float [[B]]
44   %b = fmul nnan float %a, 0.0
45   ret float %b
48 define float @no_mul_zero_3(float %a) {
49 ; CHECK-LABEL: @no_mul_zero_3(
50 ; CHECK-NEXT:    [[B:%.*]] = fmul float [[A:%.*]], 0.000000e+00
51 ; CHECK-NEXT:    ret float [[B]]
53   %b = fmul float %a, 0.0
54   ret float %b
57 ; -X + X --> 0.0 (with nnan on the fadd)
59 define float @fadd_binary_fnegx(float %x) {
60 ; CHECK-LABEL: @fadd_binary_fnegx(
61 ; CHECK-NEXT:    ret float 0.000000e+00
63   %negx = fsub float -0.0, %x
64   %r = fadd nnan float %negx, %x
65   ret float %r
68 define float @fadd_unary_fnegx(float %x) {
69 ; CHECK-LABEL: @fadd_unary_fnegx(
70 ; CHECK-NEXT:    ret float 0.000000e+00
72   %negx = fneg float %x
73   %r = fadd nnan float %negx, %x
74   ret float %r
77 ; X + -X --> 0.0 (with nnan on the fadd)
79 define <2 x float> @fadd_binary_fnegx_commute_vec(<2 x float> %x) {
80 ; CHECK-LABEL: @fadd_binary_fnegx_commute_vec(
81 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
83   %negx = fsub <2 x float> <float -0.0, float -0.0>, %x
84   %r = fadd nnan <2 x float> %x, %negx
85   ret <2 x float> %r
88 define <2 x float> @fadd_unary_fnegx_commute_vec(<2 x float> %x) {
89 ; CHECK-LABEL: @fadd_unary_fnegx_commute_vec(
90 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
92   %negx = fneg <2 x float> %x
93   %r = fadd nnan <2 x float> %x, %negx
94   ret <2 x float> %r
97 define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) {
98 ; CHECK-LABEL: @fadd_fnegx_commute_vec_undef(
99 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
101   %negx = fsub <2 x float> <float undef, float -0.0>, %x
102   %r = fadd nnan <2 x float> %x, %negx
103   ret <2 x float> %r
106 ; https://bugs.llvm.org/show_bug.cgi?id=26958
107 ; https://bugs.llvm.org/show_bug.cgi?id=27151
109 define float @fadd_binary_fneg_nan(float %x) {
110 ; CHECK-LABEL: @fadd_binary_fneg_nan(
111 ; CHECK-NEXT:    [[T:%.*]] = fsub nnan float -0.000000e+00, [[X:%.*]]
112 ; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd ninf float [[T]], [[X]]
113 ; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
115   %t = fsub nnan float -0.0, %x
116   %could_be_nan = fadd ninf float %t, %x
117   ret float %could_be_nan
120 define float @fadd_unary_fneg_nan(float %x) {
121 ; CHECK-LABEL: @fadd_unary_fneg_nan(
122 ; CHECK-NEXT:    [[T:%.*]] = fneg nnan float [[X:%.*]]
123 ; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd ninf float [[T]], [[X]]
124 ; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
126   %t = fneg nnan float %x
127   %could_be_nan = fadd ninf float %t, %x
128   ret float %could_be_nan
131 define float @fadd_binary_fneg_nan_commute(float %x) {
132 ; CHECK-LABEL: @fadd_binary_fneg_nan_commute(
133 ; CHECK-NEXT:    [[T:%.*]] = fsub nnan ninf float -0.000000e+00, [[X:%.*]]
134 ; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd float [[X]], [[T]]
135 ; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
137   %t = fsub nnan ninf float -0.0, %x
138   %could_be_nan = fadd float %x, %t
139   ret float %could_be_nan
142 define float @fadd_unary_fneg_nan_commute(float %x) {
143 ; CHECK-LABEL: @fadd_unary_fneg_nan_commute(
144 ; CHECK-NEXT:    [[T:%.*]] = fneg nnan ninf float [[X:%.*]]
145 ; CHECK-NEXT:    [[COULD_BE_NAN:%.*]] = fadd float [[X]], [[T]]
146 ; CHECK-NEXT:    ret float [[COULD_BE_NAN]]
148   %t = fneg nnan ninf float %x
149   %could_be_nan = fadd float %x, %t
150   ret float %could_be_nan
153 ; X + (0.0 - X) --> 0.0 (with nnan on the fadd)
155 define float @fadd_fsub_nnan_ninf(float %x) {
156 ; CHECK-LABEL: @fadd_fsub_nnan_ninf(
157 ; CHECK-NEXT:    ret float 0.000000e+00
159   %sub = fsub float 0.0, %x
160   %zero = fadd nnan ninf float %x, %sub
161   ret float %zero
164 ; (0.0 - X) + X --> 0.0 (with nnan on the fadd)
166 define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) {
167 ; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec(
168 ; CHECK-NEXT:    ret <2 x float> zeroinitializer
170   %sub = fsub <2 x float> zeroinitializer, %x
171   %zero = fadd nnan ninf <2 x float> %sub, %x
172   ret <2 x float> %zero
175 ; 'ninf' is not required because 'nnan' allows us to assume
176 ; that X is not INF or -INF (adding opposite INFs would be NaN).
178 define float @fadd_fsub_nnan(float %x) {
179 ; CHECK-LABEL: @fadd_fsub_nnan(
180 ; CHECK-NEXT:    ret float 0.000000e+00
182   %sub = fsub float 0.0, %x
183   %zero = fadd nnan float %sub, %x
184   ret float %zero
187 ; fsub nnan x, x ==> 0.0
188 define float @fsub_x_x(float %a) {
189 ; CHECK-LABEL: @fsub_x_x(
190 ; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fsub ninf float [[A:%.*]], [[A]]
191 ; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fsub float [[A]], [[A]]
192 ; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
193 ; CHECK-NEXT:    ret float [[NO_ZERO]]
195 ; X - X ==> 0
196   %zero1 = fsub nnan float %a, %a
198 ; Dont fold
199   %no_zero1 = fsub ninf float %a, %a
200   %no_zero2 = fsub float %a, %a
201   %no_zero = fadd float %no_zero1, %no_zero2
203 ; Should get folded
204   %ret = fadd nsz float %no_zero, %zero1
206   ret float %ret
209 ; fsub nsz 0.0, (fsub 0.0, X) ==> X
210 define float @fsub_0_0_x(float %a) {
211 ; CHECK-LABEL: @fsub_0_0_x(
212 ; CHECK-NEXT:    ret float [[A:%.*]]
214   %t1 = fsub float 0.0, %a
215   %ret = fsub nsz float 0.0, %t1
216   ret float %ret
219 ; fsub nsz 0.0, (fneg X) ==> X
220 define float @fneg_x(float %a) {
221 ; CHECK-LABEL: @fneg_x(
222 ; CHECK-NEXT:    ret float [[A:%.*]]
224   %t1 = fneg float %a
225   %ret = fsub nsz float 0.0, %t1
226   ret float %ret
229 define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) {
230 ; CHECK-LABEL: @fsub_0_0_x_vec_undef1(
231 ; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
233   %t1 = fsub <2 x float> <float 0.0, float undef>, %a
234   %ret = fsub nsz <2 x float> zeroinitializer, %t1
235   ret <2 x float> %ret
238 define <2 x float> @fneg_x_vec_undef1(<2 x float> %a) {
239 ; CHECK-LABEL: @fneg_x_vec_undef1(
240 ; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
242   %t1 = fneg <2 x float> %a
243   %ret = fsub nsz <2 x float> <float 0.0, float undef>, %t1
244   ret <2 x float> %ret
247 define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) {
248 ; CHECK-LABEL: @fsub_0_0_x_vec_undef2(
249 ; CHECK-NEXT:    ret <2 x float> [[A:%.*]]
251   %t1 = fsub <2 x float> zeroinitializer, %a
252   %ret = fsub nsz <2 x float> <float undef, float -0.0>, %t1
253   ret <2 x float> %ret
256 ; fadd nsz X, 0 ==> X
258 define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) {
259 ; CHECK-LABEL: @fadd_zero_nsz_vec(
260 ; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
262   %r = fadd nsz <2 x float> %x, zeroinitializer
263   ret <2 x float> %r
266 define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) {
267 ; CHECK-LABEL: @fadd_zero_nsz_vec_undef(
268 ; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
270   %r = fadd nsz <2 x float> %x, <float 0.0, float undef>
271   ret <2 x float> %r
274 define float @nofold_fadd_x_0(float %a) {
275 ; CHECK-LABEL: @nofold_fadd_x_0(
276 ; CHECK-NEXT:    [[NO_ZERO1:%.*]] = fadd ninf float [[A:%.*]], 0.000000e+00
277 ; CHECK-NEXT:    [[NO_ZERO2:%.*]] = fadd nnan float [[A]], 0.000000e+00
278 ; CHECK-NEXT:    [[NO_ZERO:%.*]] = fadd float [[NO_ZERO1]], [[NO_ZERO2]]
279 ; CHECK-NEXT:    ret float [[NO_ZERO]]
281 ; Dont fold
282   %no_zero1 = fadd ninf float %a, 0.0
283   %no_zero2 = fadd nnan float %a, 0.0
284   %no_zero = fadd float %no_zero1, %no_zero2
285   ret float %no_zero
288 define float @fold_fadd_nsz_x_0(float %a) {
289 ; CHECK-LABEL: @fold_fadd_nsz_x_0(
290 ; CHECK-NEXT:    ret float [[A:%.*]]
292   %add = fadd nsz float %a, 0.0
293   ret float %add
296 ; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify.
298 define float @fold_fadd_cannot_be_neg0_nsz_src_x_0(float %a, float %b) {
299 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_nsz_src_x_0(
300 ; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
301 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[NSZ]], 0.000000e+00
302 ; CHECK-NEXT:    ret float [[ADD]]
304   %nsz = fmul nsz float %a, %b
305   %add = fadd float %nsz, 0.0
306   ret float %add
309 define float @fold_fadd_cannot_be_neg0_fabs_src_x_0(float %a) {
310 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_fabs_src_x_0(
311 ; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
312 ; CHECK-NEXT:    ret float [[FABS]]
314   %fabs = call float @llvm.fabs.f32(float %a)
315   %add = fadd float %fabs, 0.0
316   ret float %add
319 ; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify.
321 define float @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(float %a, float %b) {
322 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(
323 ; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
324 ; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[NSZ]])
325 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[SQRT]], 0.000000e+00
326 ; CHECK-NEXT:    ret float [[ADD]]
328   %nsz = fmul nsz float %a, %b
329   %sqrt = call float @llvm.sqrt.f32(float %nsz)
330   %add = fadd float %sqrt, 0.0
331   ret float %add
334 ; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify.
336 define float @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(float %a, float %b) {
337 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(
338 ; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
339 ; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSZ]])
340 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[CANON]], 0.000000e+00
341 ; CHECK-NEXT:    ret float [[ADD]]
343   %nsz = fmul nsz float %a, %b
344   %canon = call float @llvm.canonicalize.f32(float %nsz)
345   %add = fadd float %canon, 0.0
346   ret float %add
349 ; fdiv nsz nnan 0, X ==> 0
350 ; 0 / X -> 0
352 define double @fdiv_zero_by_x(double %x) {
353 ; CHECK-LABEL: @fdiv_zero_by_x(
354 ; CHECK-NEXT:    ret double 0.000000e+00
356   %r = fdiv nnan nsz double 0.0, %x
357   ret double %r
360 define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) {
361 ; CHECK-LABEL: @fdiv_zero_by_x_vec_undef(
362 ; CHECK-NEXT:    ret <2 x double> zeroinitializer
364   %r = fdiv nnan nsz <2 x double> <double 0.0, double undef>, %x
365   ret <2 x double> %r
368 ; 0 % X -> 0
369 ; nsz is not necessary - frem result always has the sign of the dividend
371 define double @frem_zero_by_x(double %x) {
372 ; CHECK-LABEL: @frem_zero_by_x(
373 ; CHECK-NEXT:    ret double 0.000000e+00
375   %r = frem nnan double 0.0, %x
376   ret double %r
379 define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) {
380 ; CHECK-LABEL: @frem_poszero_by_x_vec_undef(
381 ; CHECK-NEXT:    ret <2 x double> zeroinitializer
383   %r = frem nnan <2 x double> <double 0.0, double undef>, %x
384   ret <2 x double> %r
387 ; -0 % X -> -0
388 ; nsz is not necessary - frem result always has the sign of the dividend
390 define double @frem_negzero_by_x(double %x) {
391 ; CHECK-LABEL: @frem_negzero_by_x(
392 ; CHECK-NEXT:    ret double -0.000000e+00
394   %r = frem nnan double -0.0, %x
395   ret double %r
398 define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) {
399 ; CHECK-LABEL: @frem_negzero_by_x_vec_undef(
400 ; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
402   %r = frem nnan <2 x double> <double undef, double -0.0>, %x
403   ret <2 x double> %r
406 define float @fdiv_self(float %f) {
407 ; CHECK-LABEL: @fdiv_self(
408 ; CHECK-NEXT:    ret float 1.000000e+00
410   %div = fdiv nnan float %f, %f
411   ret float %div
414 define float @fdiv_self_invalid(float %f) {
415 ; CHECK-LABEL: @fdiv_self_invalid(
416 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[F:%.*]], [[F]]
417 ; CHECK-NEXT:    ret float [[DIV]]
419   %div = fdiv float %f, %f
420   ret float %div
423 define float @fdiv_neg1(float %f) {
424 ; CHECK-LABEL: @fdiv_neg1(
425 ; CHECK-NEXT:    ret float -1.000000e+00
427   %neg = fsub fast float -0.000000e+00, %f
428   %div = fdiv nnan float %neg, %f
429   ret float %div
432 define float @fdiv_neg2(float %f) {
433 ; CHECK-LABEL: @fdiv_neg2(
434 ; CHECK-NEXT:    ret float -1.000000e+00
436   %neg = fsub fast float 0.000000e+00, %f
437   %div = fdiv nnan float %neg, %f
438   ret float %div
441 define float @fdiv_neg_invalid(float %f) {
442 ; CHECK-LABEL: @fdiv_neg_invalid(
443 ; CHECK-NEXT:    [[NEG:%.*]] = fsub fast float -0.000000e+00, [[F:%.*]]
444 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[F]]
445 ; CHECK-NEXT:    ret float [[DIV]]
447   %neg = fsub fast float -0.000000e+00, %f
448   %div = fdiv float %neg, %f
449   ret float %div
452 define float @fdiv_neg_swapped1(float %f) {
453 ; CHECK-LABEL: @fdiv_neg_swapped1(
454 ; CHECK-NEXT:    ret float -1.000000e+00
456   %neg = fsub float -0.000000e+00, %f
457   %div = fdiv nnan float %f, %neg
458   ret float %div
461 define float @fdiv_neg_swapped2(float %f) {
462 ; CHECK-LABEL: @fdiv_neg_swapped2(
463 ; CHECK-NEXT:    ret float -1.000000e+00
465   %neg = fsub float 0.000000e+00, %f
466   %div = fdiv nnan float %f, %neg
467   ret float %div
470 define <2 x float> @fdiv_neg_vec_undef_elt(<2 x float> %f) {
471 ; CHECK-LABEL: @fdiv_neg_vec_undef_elt(
472 ; CHECK-NEXT:    ret <2 x float> <float -1.000000e+00, float -1.000000e+00>
474   %neg = fsub <2 x float> <float 0.0, float undef>, %f
475   %div = fdiv nnan <2 x float> %f, %neg
476   ret <2 x float> %div
479 ; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126
480 ; With loose math, sqrt(X) * sqrt(X) is just X.
482 declare double @llvm.sqrt.f64(double)
484 define double @sqrt_squared(double %f) {
485 ; CHECK-LABEL: @sqrt_squared(
486 ; CHECK-NEXT:    ret double [[F:%.*]]
488   %sqrt = call double @llvm.sqrt.f64(double %f)
489   %mul = fmul reassoc nnan nsz double %sqrt, %sqrt
490   ret double %mul
493 ; Negative tests for the above transform: we need all 3 of those flags.
495 define double @sqrt_squared_not_fast_enough1(double %f) {
496 ; CHECK-LABEL: @sqrt_squared_not_fast_enough1(
497 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
498 ; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan nsz double [[SQRT]], [[SQRT]]
499 ; CHECK-NEXT:    ret double [[MUL]]
501   %sqrt = call double @llvm.sqrt.f64(double %f)
502   %mul = fmul nnan nsz double %sqrt, %sqrt
503   ret double %mul
506 define double @sqrt_squared_not_fast_enough2(double %f) {
507 ; CHECK-LABEL: @sqrt_squared_not_fast_enough2(
508 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
509 ; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nnan double [[SQRT]], [[SQRT]]
510 ; CHECK-NEXT:    ret double [[MUL]]
512   %sqrt = call double @llvm.sqrt.f64(double %f)
513   %mul = fmul reassoc nnan double %sqrt, %sqrt
514   ret double %mul
517 define double @sqrt_squared_not_fast_enough3(double %f) {
518 ; CHECK-LABEL: @sqrt_squared_not_fast_enough3(
519 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
520 ; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz double [[SQRT]], [[SQRT]]
521 ; CHECK-NEXT:    ret double [[MUL]]
523   %sqrt = call double @llvm.sqrt.f64(double %f)
524   %mul = fmul reassoc nsz double %sqrt, %sqrt
525   ret double %mul
528 declare float @llvm.fabs.f32(float)
529 declare float @llvm.sqrt.f32(float)
530 declare float @llvm.canonicalize.f32(float)