[ARM] Adjust how NEON shifts are lowered
[llvm-core.git] / test / Transforms / InstSimplify / fast-math.ll
bloba53d6ff6982c2cb9a29dfb3f1a1faa4d3d46b571
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -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 define float @fold_fadd_cannot_be_neg0_nsz_src_x_0(float %a, float %b) {
297 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_nsz_src_x_0(
298 ; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
299 ; CHECK-NEXT:    ret float [[NSZ]]
301   %nsz = fmul nsz float %a, %b
302   %add = fadd float %nsz, 0.0
303   ret float %add
306 define float @fold_fadd_cannot_be_neg0_fabs_src_x_0(float %a) {
307 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_fabs_src_x_0(
308 ; CHECK-NEXT:    [[FABS:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
309 ; CHECK-NEXT:    ret float [[FABS]]
311   %fabs = call float @llvm.fabs.f32(float %a)
312   %add = fadd float %fabs, 0.0
313   ret float %add
316 define float @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(float %a, float %b) {
317 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(
318 ; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
319 ; CHECK-NEXT:    [[SQRT:%.*]] = call float @llvm.sqrt.f32(float [[NSZ]])
320 ; CHECK-NEXT:    ret float [[SQRT]]
322   %nsz = fmul nsz float %a, %b
323   %sqrt = call float @llvm.sqrt.f32(float %nsz)
324   %add = fadd float %sqrt, 0.0
325   ret float %add
328 define float @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(float %a, float %b) {
329 ; CHECK-LABEL: @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(
330 ; CHECK-NEXT:    [[NSZ:%.*]] = fmul nsz float [[A:%.*]], [[B:%.*]]
331 ; CHECK-NEXT:    [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSZ]])
332 ; CHECK-NEXT:    ret float [[CANON]]
334   %nsz = fmul nsz float %a, %b
335   %canon = call float @llvm.canonicalize.f32(float %nsz)
336   %add = fadd float %canon, 0.0
337   ret float %add
340 ; fdiv nsz nnan 0, X ==> 0
341 ; 0 / X -> 0
343 define double @fdiv_zero_by_x(double %x) {
344 ; CHECK-LABEL: @fdiv_zero_by_x(
345 ; CHECK-NEXT:    ret double 0.000000e+00
347   %r = fdiv nnan nsz double 0.0, %x
348   ret double %r
351 define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) {
352 ; CHECK-LABEL: @fdiv_zero_by_x_vec_undef(
353 ; CHECK-NEXT:    ret <2 x double> zeroinitializer
355   %r = fdiv nnan nsz <2 x double> <double 0.0, double undef>, %x
356   ret <2 x double> %r
359 ; 0 % X -> 0
360 ; nsz is not necessary - frem result always has the sign of the dividend
362 define double @frem_zero_by_x(double %x) {
363 ; CHECK-LABEL: @frem_zero_by_x(
364 ; CHECK-NEXT:    ret double 0.000000e+00
366   %r = frem nnan double 0.0, %x
367   ret double %r
370 define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) {
371 ; CHECK-LABEL: @frem_poszero_by_x_vec_undef(
372 ; CHECK-NEXT:    ret <2 x double> zeroinitializer
374   %r = frem nnan <2 x double> <double 0.0, double undef>, %x
375   ret <2 x double> %r
378 ; -0 % X -> -0
379 ; nsz is not necessary - frem result always has the sign of the dividend
381 define double @frem_negzero_by_x(double %x) {
382 ; CHECK-LABEL: @frem_negzero_by_x(
383 ; CHECK-NEXT:    ret double -0.000000e+00
385   %r = frem nnan double -0.0, %x
386   ret double %r
389 define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) {
390 ; CHECK-LABEL: @frem_negzero_by_x_vec_undef(
391 ; CHECK-NEXT:    ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
393   %r = frem nnan <2 x double> <double undef, double -0.0>, %x
394   ret <2 x double> %r
397 define float @fdiv_self(float %f) {
398 ; CHECK-LABEL: @fdiv_self(
399 ; CHECK-NEXT:    ret float 1.000000e+00
401   %div = fdiv nnan float %f, %f
402   ret float %div
405 define float @fdiv_self_invalid(float %f) {
406 ; CHECK-LABEL: @fdiv_self_invalid(
407 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[F:%.*]], [[F]]
408 ; CHECK-NEXT:    ret float [[DIV]]
410   %div = fdiv float %f, %f
411   ret float %div
414 define float @fdiv_neg1(float %f) {
415 ; CHECK-LABEL: @fdiv_neg1(
416 ; CHECK-NEXT:    ret float -1.000000e+00
418   %neg = fsub fast float -0.000000e+00, %f
419   %div = fdiv nnan float %neg, %f
420   ret float %div
423 define float @fdiv_neg2(float %f) {
424 ; CHECK-LABEL: @fdiv_neg2(
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_neg_invalid(float %f) {
433 ; CHECK-LABEL: @fdiv_neg_invalid(
434 ; CHECK-NEXT:    [[NEG:%.*]] = fsub fast float -0.000000e+00, [[F:%.*]]
435 ; CHECK-NEXT:    [[DIV:%.*]] = fdiv float [[NEG]], [[F]]
436 ; CHECK-NEXT:    ret float [[DIV]]
438   %neg = fsub fast float -0.000000e+00, %f
439   %div = fdiv float %neg, %f
440   ret float %div
443 define float @fdiv_neg_swapped1(float %f) {
444 ; CHECK-LABEL: @fdiv_neg_swapped1(
445 ; CHECK-NEXT:    ret float -1.000000e+00
447   %neg = fsub float -0.000000e+00, %f
448   %div = fdiv nnan float %f, %neg
449   ret float %div
452 define float @fdiv_neg_swapped2(float %f) {
453 ; CHECK-LABEL: @fdiv_neg_swapped2(
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 <2 x float> @fdiv_neg_vec_undef_elt(<2 x float> %f) {
462 ; CHECK-LABEL: @fdiv_neg_vec_undef_elt(
463 ; CHECK-NEXT:    ret <2 x float> <float -1.000000e+00, float -1.000000e+00>
465   %neg = fsub <2 x float> <float 0.0, float undef>, %f
466   %div = fdiv nnan <2 x float> %f, %neg
467   ret <2 x float> %div
470 ; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126
471 ; With loose math, sqrt(X) * sqrt(X) is just X.
473 declare double @llvm.sqrt.f64(double)
475 define double @sqrt_squared(double %f) {
476 ; CHECK-LABEL: @sqrt_squared(
477 ; CHECK-NEXT:    ret double [[F:%.*]]
479   %sqrt = call double @llvm.sqrt.f64(double %f)
480   %mul = fmul reassoc nnan nsz double %sqrt, %sqrt
481   ret double %mul
484 ; Negative tests for the above transform: we need all 3 of those flags.
486 define double @sqrt_squared_not_fast_enough1(double %f) {
487 ; CHECK-LABEL: @sqrt_squared_not_fast_enough1(
488 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
489 ; CHECK-NEXT:    [[MUL:%.*]] = fmul nnan nsz double [[SQRT]], [[SQRT]]
490 ; CHECK-NEXT:    ret double [[MUL]]
492   %sqrt = call double @llvm.sqrt.f64(double %f)
493   %mul = fmul nnan nsz double %sqrt, %sqrt
494   ret double %mul
497 define double @sqrt_squared_not_fast_enough2(double %f) {
498 ; CHECK-LABEL: @sqrt_squared_not_fast_enough2(
499 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
500 ; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nnan double [[SQRT]], [[SQRT]]
501 ; CHECK-NEXT:    ret double [[MUL]]
503   %sqrt = call double @llvm.sqrt.f64(double %f)
504   %mul = fmul reassoc nnan double %sqrt, %sqrt
505   ret double %mul
508 define double @sqrt_squared_not_fast_enough3(double %f) {
509 ; CHECK-LABEL: @sqrt_squared_not_fast_enough3(
510 ; CHECK-NEXT:    [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]])
511 ; CHECK-NEXT:    [[MUL:%.*]] = fmul reassoc nsz double [[SQRT]], [[SQRT]]
512 ; CHECK-NEXT:    ret double [[MUL]]
514   %sqrt = call double @llvm.sqrt.f64(double %f)
515   %mul = fmul reassoc nsz double %sqrt, %sqrt
516   ret double %mul
519 declare float @llvm.fabs.f32(float)
520 declare float @llvm.sqrt.f32(float)
521 declare float @llvm.canonicalize.f32(float)