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
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_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>
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_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
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_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
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
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
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_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>
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 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
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
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
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
340 ; fdiv nsz nnan 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
519 declare float @llvm.fabs.f32(float)
520 declare float @llvm.sqrt.f32(float)
521 declare float @llvm.canonicalize.f32(float)