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
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
21 define <2 x float> @mul_zero_nsz_nnan_vec_poison(<2 x float> %a) {
22 ; CHECK-LABEL: @mul_zero_nsz_nnan_vec_poison(
23 ; CHECK-NEXT: ret <2 x float> zeroinitializer
25 %b = fmul nsz nnan <2 x float> %a, <float 0.0, float poison>
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
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
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
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
68 define float @fadd_unary_fnegx(float %x) {
69 ; CHECK-LABEL: @fadd_unary_fnegx(
70 ; CHECK-NEXT: ret float 0.000000e+00
73 %r = fadd nnan float %negx, %x
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
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
97 define <2 x float> @fadd_fnegx_commute_vec_poison(<2 x float> %x) {
98 ; CHECK-LABEL: @fadd_fnegx_commute_vec_poison(
99 ; CHECK-NEXT: ret <2 x float> zeroinitializer
101 %negx = fsub <2 x float> <float poison, float -0.0>, %x
102 %r = fadd nnan <2 x float> %x, %negx
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
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
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]]
196 %zero1 = fsub nnan float %a, %a
199 %no_zero1 = fsub ninf float %a, %a
200 %no_zero2 = fsub float %a, %a
201 %no_zero = fadd float %no_zero1, %no_zero2
204 %ret = fadd nsz float %no_zero, %zero1
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
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:%.*]]
225 %ret = fsub nsz float 0.0, %t1
229 define <2 x float> @fsub_0_0_x_vec_poison1(<2 x float> %a) {
230 ; CHECK-LABEL: @fsub_0_0_x_vec_poison1(
231 ; CHECK-NEXT: ret <2 x float> [[A:%.*]]
233 %t1 = fsub <2 x float> <float 0.0, float poison>, %a
234 %ret = fsub nsz <2 x float> zeroinitializer, %t1
238 define <2 x float> @fneg_x_vec_poison1(<2 x float> %a) {
239 ; CHECK-LABEL: @fneg_x_vec_poison1(
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 poison>, %t1
247 define <2 x float> @fsub_0_0_x_vec_poison2(<2 x float> %a) {
248 ; CHECK-LABEL: @fsub_0_0_x_vec_poison2(
249 ; CHECK-NEXT: ret <2 x float> [[A:%.*]]
251 %t1 = fsub <2 x float> zeroinitializer, %a
252 %ret = fsub nsz <2 x float> <float poison, float -0.0>, %t1
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
266 define <2 x float> @fadd_zero_nsz_vec_poison(<2 x float> %x) {
267 ; CHECK-LABEL: @fadd_zero_nsz_vec_poison(
268 ; CHECK-NEXT: ret <2 x float> [[X:%.*]]
270 %r = fadd nsz <2 x float> %x, <float 0.0, float poison>
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]]
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
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
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
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
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
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
349 ; fdiv nsz nnan 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
360 define <2 x double> @fdiv_zero_by_x_vec_poison(<2 x double> %x) {
361 ; CHECK-LABEL: @fdiv_zero_by_x_vec_poison(
362 ; CHECK-NEXT: ret <2 x double> zeroinitializer
364 %r = fdiv nnan nsz <2 x double> <double 0.0, double poison>, %x
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
379 define <2 x double> @frem_poszero_by_x_vec_poison(<2 x double> %x) {
380 ; CHECK-LABEL: @frem_poszero_by_x_vec_poison(
381 ; CHECK-NEXT: ret <2 x double> zeroinitializer
383 %r = frem nnan <2 x double> <double 0.0, double poison>, %x
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
398 define <2 x double> @frem_negzero_by_x_vec_poison(<2 x double> %x) {
399 ; CHECK-LABEL: @frem_negzero_by_x_vec_poison(
400 ; CHECK-NEXT: ret <2 x double> splat (double -0.000000e+00)
402 %r = frem nnan <2 x double> <double poison, double -0.0>, %x
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
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
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
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
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
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
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
470 define <2 x float> @fdiv_neg_vec_poison_elt(<2 x float> %f) {
471 ; CHECK-LABEL: @fdiv_neg_vec_poison_elt(
472 ; CHECK-NEXT: ret <2 x float> splat (float -1.000000e+00)
474 %neg = fsub <2 x float> <float 0.0, float poison>, %f
475 %div = fdiv nnan <2 x float> %f, %neg
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
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
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
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
528 declare float @llvm.fabs.f32(float)
529 declare float @llvm.sqrt.f32(float)
530 declare float @llvm.canonicalize.f32(float)