Files
clang-p2996/llvm/test/Transforms/InstCombine/fdiv.ll
Nikita Popov a105877646 [InstCombine] Remove some of the complexity-based canonicalization (#91185)
The idea behind this canonicalization is that it allows us to handle less
patterns, because we know that some will be canonicalized away. This is
indeed very useful to e.g. know that constants are always on the right.

However, this is only useful if the canonicalization is actually
reliable. This is the case for constants, but not for arguments: Moving
these to the right makes it look like the "more complex" expression is
guaranteed to be on the left, but this is not actually the case in
practice. It fails as soon as you replace the argument with another
instruction.

The end result is that it looks like things correctly work in tests,
while they actually don't. We use the "thwart complexity-based
canonicalization" trick to handle this in tests, but it's often a
challenge for new contributors to get this right, and based on the
regressions this PR originally exposed, we clearly don't get this right
in many cases.

For this reason, I think that it's better to remove this complexity
canonicalization. It will make it much easier to write tests for
commuted cases and make sure that they are handled.
2024-08-21 12:02:54 +02:00

1067 lines
37 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
declare float @llvm.fabs.f32(float) nounwind readnone
declare float @llvm.pow.f32(float, float) nounwind readnone
declare <2 x half> @llvm.pow.v2f16(<2 x half>, <2 x half>) nounwind readnone
declare float @llvm.exp.f32(float) nounwind readnone
declare <2 x half> @llvm.exp.v2f16(<2 x half>) nounwind readnone
declare float @llvm.exp2.f32(float) nounwind readnone
declare <2 x half> @llvm.exp2.v2f16(<2 x half>) nounwind readnone
declare float @llvm.powi.f32.i32(float, i32) nounwind readnone
declare <2 x half> @llvm.powi.v2f16.i32(<2 x half>, i32) nounwind readnone
define float @exact_inverse(float %x) {
; CHECK-LABEL: @exact_inverse(
; CHECK-NEXT: [[DIV:%.*]] = fmul float [[X:%.*]], 1.250000e-01
; CHECK-NEXT: ret float [[DIV]]
;
%div = fdiv float %x, 8.0
ret float %div
}
; Min normal float = 1.17549435E-38
define float @exact_inverse2(float %x) {
; CHECK-LABEL: @exact_inverse2(
; CHECK-NEXT: [[DIV:%.*]] = fmul float [[X:%.*]], 0x47D0000000000000
; CHECK-NEXT: ret float [[DIV]]
;
%div = fdiv float %x, 0x3810000000000000
ret float %div
}
; Max exponent = 1.70141183E+38; don't transform to multiply with denormal.
define float @exact_inverse_but_denorm(float %x) {
; CHECK-LABEL: @exact_inverse_but_denorm(
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[X:%.*]], 0x47E0000000000000
; CHECK-NEXT: ret float [[DIV]]
;
%div = fdiv float %x, 0x47E0000000000000
ret float %div
}
; Denormal = float 1.40129846E-45; inverse can't be represented.
define float @not_exact_inverse2(float %x) {
; CHECK-LABEL: @not_exact_inverse2(
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[X:%.*]], 0x36A0000000000000
; CHECK-NEXT: ret float [[DIV]]
;
%div = fdiv float %x, 0x36A0000000000000
ret float %div
}
; Fast math allows us to replace this fdiv.
define float @not_exact_but_allow_recip(float %x) {
; CHECK-LABEL: @not_exact_but_allow_recip(
; CHECK-NEXT: [[DIV:%.*]] = fmul arcp float [[X:%.*]], 0x3FD5555560000000
; CHECK-NEXT: ret float [[DIV]]
;
%div = fdiv arcp float %x, 3.0
ret float %div
}
; Fast math allows us to replace this fdiv, but we don't to avoid a denormal.
; TODO: What if the function attributes tell us that denormals are flushed?
define float @not_exact_but_allow_recip_but_denorm(float %x) {
; CHECK-LABEL: @not_exact_but_allow_recip_but_denorm(
; CHECK-NEXT: [[DIV:%.*]] = fdiv arcp float [[X:%.*]], 0x47E0000100000000
; CHECK-NEXT: ret float [[DIV]]
;
%div = fdiv arcp float %x, 0x47E0000100000000
ret float %div
}
define <2 x float> @exact_inverse_splat(<2 x float> %x) {
; CHECK-LABEL: @exact_inverse_splat(
; CHECK-NEXT: [[DIV:%.*]] = fmul <2 x float> [[X:%.*]], <float 2.500000e-01, float 2.500000e-01>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv <2 x float> %x, <float 4.0, float 4.0>
ret <2 x float> %div
}
define <vscale x 2 x float> @exact_inverse_scalable_splat(<vscale x 2 x float> %x) {
; CHECK-LABEL: @exact_inverse_scalable_splat(
; CHECK-NEXT: [[DIV:%.*]] = fmul <vscale x 2 x float> [[X:%.*]], shufflevector (<vscale x 2 x float> insertelement (<vscale x 2 x float> poison, float 2.500000e-01, i64 0), <vscale x 2 x float> poison, <vscale x 2 x i32> zeroinitializer)
; CHECK-NEXT: ret <vscale x 2 x float> [[DIV]]
;
%div = fdiv <vscale x 2 x float> %x, splat (float 4.0)
ret <vscale x 2 x float> %div
}
; Fast math allows us to replace this fdiv.
define <2 x float> @not_exact_but_allow_recip_splat(<2 x float> %x) {
; CHECK-LABEL: @not_exact_but_allow_recip_splat(
; CHECK-NEXT: [[DIV:%.*]] = fmul arcp <2 x float> [[X:%.*]], <float 0x3FD5555560000000, float 0x3FD5555560000000>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv arcp <2 x float> %x, <float 3.0, float 3.0>
ret <2 x float> %div
}
define <2 x float> @exact_inverse_vec(<2 x float> %x) {
; CHECK-LABEL: @exact_inverse_vec(
; CHECK-NEXT: [[DIV:%.*]] = fmul <2 x float> [[X:%.*]], <float 2.500000e-01, float 1.250000e-01>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv <2 x float> %x, <float 4.0, float 8.0>
ret <2 x float> %div
}
define <2 x float> @not_exact_inverse_splat(<2 x float> %x) {
; CHECK-LABEL: @not_exact_inverse_splat(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], <float 3.000000e+00, float 3.000000e+00>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv <2 x float> %x, <float 3.0, float 3.0>
ret <2 x float> %div
}
define <2 x float> @not_exact_inverse_vec(<2 x float> %x) {
; CHECK-LABEL: @not_exact_inverse_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], <float 4.000000e+00, float 3.000000e+00>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv <2 x float> %x, <float 4.0, float 3.0>
ret <2 x float> %div
}
define <2 x float> @not_exact_inverse_vec_arcp(<2 x float> %x) {
; CHECK-LABEL: @not_exact_inverse_vec_arcp(
; CHECK-NEXT: [[DIV:%.*]] = fmul arcp <2 x float> [[X:%.*]], <float 2.500000e-01, float 0x3FD5555560000000>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv arcp <2 x float> %x, <float 4.0, float 3.0>
ret <2 x float> %div
}
define <2 x float> @not_exact_inverse_vec_arcp_with_poison_elt(<2 x float> %x) {
; CHECK-LABEL: @not_exact_inverse_vec_arcp_with_poison_elt(
; CHECK-NEXT: [[DIV:%.*]] = fdiv arcp <2 x float> [[X:%.*]], <float poison, float 3.000000e+00>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%div = fdiv arcp <2 x float> %x, <float poison, float 3.0>
ret <2 x float> %div
}
; (X / Y) / Z --> X / (Y * Z)
define float @div_with_div_numerator(float %x, float %y, float %z) {
; CHECK-LABEL: @div_with_div_numerator(
; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc arcp float [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[DIV2:%.*]] = fdiv reassoc arcp float [[X:%.*]], [[TMP1]]
; CHECK-NEXT: ret float [[DIV2]]
;
%div1 = fdiv ninf float %x, %y
%div2 = fdiv arcp reassoc float %div1, %z
ret float %div2
}
; Z / (X / Y) --> (Z * Y) / X
define <2 x float> @div_with_div_denominator(<2 x float> %x, <2 x float> %y, <2 x float> %z) {
; CHECK-LABEL: @div_with_div_denominator(
; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc arcp <2 x float> [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[DIV2:%.*]] = fdiv reassoc arcp <2 x float> [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV2]]
;
%div1 = fdiv nnan <2 x float> %x, %y
%div2 = fdiv arcp reassoc <2 x float> %z, %div1
ret <2 x float> %div2
}
; Don't create an extra multiply if we can't eliminate the first div.
declare void @use_f32(float)
define float @div_with_div_numerator_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @div_with_div_numerator_extra_use(
; CHECK-NEXT: [[DIV1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[DIV2:%.*]] = fdiv fast float [[DIV1]], [[Z:%.*]]
; CHECK-NEXT: call void @use_f32(float [[DIV1]])
; CHECK-NEXT: ret float [[DIV2]]
;
%div1 = fdiv float %x, %y
%div2 = fdiv fast float %div1, %z
call void @use_f32(float %div1)
ret float %div2
}
define float @div_with_div_denominator_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @div_with_div_denominator_extra_use(
; CHECK-NEXT: [[DIV1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[DIV2:%.*]] = fdiv fast float [[Z:%.*]], [[DIV1]]
; CHECK-NEXT: call void @use_f32(float [[DIV1]])
; CHECK-NEXT: ret float [[DIV2]]
;
%div1 = fdiv float %x, %y
%div2 = fdiv fast float %z, %div1
call void @use_f32(float %div1)
ret float %div2
}
; Z / (1.0 / Y) ==> Y * Z
define float @div_with_div_denominator_with_one_as_numerator_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @div_with_div_denominator_with_one_as_numerator_extra_use(
; CHECK-NEXT: [[DIV1:%.*]] = fdiv float 1.000000e+00, [[Y:%.*]]
; CHECK-NEXT: [[DIV2:%.*]] = fmul reassoc arcp float [[Y]], [[Z:%.*]]
; CHECK-NEXT: call void @use_f32(float [[DIV1]])
; CHECK-NEXT: ret float [[DIV2]]
;
%div1 = fdiv float 1.0, %y
%div2 = fdiv reassoc arcp float %z, %div1
call void @use_f32(float %div1)
ret float %div2
}
define float @fneg_fneg(float %x, float %y) {
; CHECK-LABEL: @fneg_fneg(
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%x.fneg = fsub float -0.0, %x
%y.fneg = fsub float -0.0, %y
%div = fdiv float %x.fneg, %y.fneg
ret float %div
}
define float @unary_fneg_unary_fneg(float %x, float %y) {
; CHECK-LABEL: @unary_fneg_unary_fneg(
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%x.fneg = fneg float %x
%y.fneg = fneg float %y
%div = fdiv float %x.fneg, %y.fneg
ret float %div
}
define float @unary_fneg_fneg(float %x, float %y) {
; CHECK-LABEL: @unary_fneg_fneg(
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%x.fneg = fneg float %x
%y.fneg = fsub float -0.0, %y
%div = fdiv float %x.fneg, %y.fneg
ret float %div
}
define float @fneg_unary_fneg(float %x, float %y) {
; CHECK-LABEL: @fneg_unary_fneg(
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%x.fneg = fsub float -0.0, %x
%y.fneg = fneg float %y
%div = fdiv float %x.fneg, %y.fneg
ret float %div
}
; The test above shows that no FMF are needed, but show that we are not dropping FMF.
define float @fneg_fneg_fast(float %x, float %y) {
; CHECK-LABEL: @fneg_fneg_fast(
; CHECK-NEXT: [[DIV:%.*]] = fdiv fast float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%x.fneg = fsub float -0.0, %x
%y.fneg = fsub float -0.0, %y
%div = fdiv fast float %x.fneg, %y.fneg
ret float %div
}
define float @unary_fneg_unary_fneg_fast(float %x, float %y) {
; CHECK-LABEL: @unary_fneg_unary_fneg_fast(
; CHECK-NEXT: [[DIV:%.*]] = fdiv fast float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%x.fneg = fneg float %x
%y.fneg = fneg float %y
%div = fdiv fast float %x.fneg, %y.fneg
ret float %div
}
define <2 x float> @fneg_fneg_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fneg_fneg_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%xneg = fsub <2 x float> <float -0.0, float -0.0>, %x
%yneg = fsub <2 x float> <float -0.0, float -0.0>, %y
%div = fdiv <2 x float> %xneg, %yneg
ret <2 x float> %div
}
define <2 x float> @unary_fneg_unary_fneg_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @unary_fneg_unary_fneg_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%xneg = fneg <2 x float> %x
%yneg = fneg <2 x float> %y
%div = fdiv <2 x float> %xneg, %yneg
ret <2 x float> %div
}
define <2 x float> @fneg_unary_fneg_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fneg_unary_fneg_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%xneg = fsub <2 x float> <float -0.0, float -0.0>, %x
%yneg = fneg <2 x float> %y
%div = fdiv <2 x float> %xneg, %yneg
ret <2 x float> %div
}
define <2 x float> @unary_fneg_fneg_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @unary_fneg_fneg_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%xneg = fneg <2 x float> %x
%yneg = fsub <2 x float> <float -0.0, float -0.0>, %y
%div = fdiv <2 x float> %xneg, %yneg
ret <2 x float> %div
}
define <2 x float> @fneg_fneg_vec_poison_elts(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fneg_fneg_vec_poison_elts(
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%xneg = fsub <2 x float> <float poison, float -0.0>, %x
%yneg = fsub <2 x float> <float -0.0, float poison>, %y
%div = fdiv <2 x float> %xneg, %yneg
ret <2 x float> %div
}
define float @fneg_dividend_constant_divisor(float %x) {
; CHECK-LABEL: @fneg_dividend_constant_divisor(
; CHECK-NEXT: [[DIV:%.*]] = fdiv nsz float [[X:%.*]], -3.000000e+00
; CHECK-NEXT: ret float [[DIV]]
;
%neg = fsub float -0.0, %x
%div = fdiv nsz float %neg, 3.0
ret float %div
}
define float @unary_fneg_dividend_constant_divisor(float %x) {
; CHECK-LABEL: @unary_fneg_dividend_constant_divisor(
; CHECK-NEXT: [[DIV:%.*]] = fdiv nsz float [[X:%.*]], -3.000000e+00
; CHECK-NEXT: ret float [[DIV]]
;
%neg = fneg float %x
%div = fdiv nsz float %neg, 3.0
ret float %div
}
define float @fneg_divisor_constant_dividend(float %x) {
; CHECK-LABEL: @fneg_divisor_constant_dividend(
; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan float 3.000000e+00, [[X:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%neg = fsub float -0.0, %x
%div = fdiv nnan float -3.0, %neg
ret float %div
}
define float @unary_fneg_divisor_constant_dividend(float %x) {
; CHECK-LABEL: @unary_fneg_divisor_constant_dividend(
; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan float 3.000000e+00, [[X:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%neg = fneg float %x
%div = fdiv nnan float -3.0, %neg
ret float %div
}
define <2 x float> @fneg_dividend_constant_divisor_vec(<2 x float> %x) {
; CHECK-LABEL: @fneg_dividend_constant_divisor_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf <2 x float> [[X:%.*]], <float -3.000000e+00, float 8.000000e+00>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fsub <2 x float> <float -0.0, float -0.0>, %x
%div = fdiv ninf <2 x float> %neg, <float 3.0, float -8.0>
ret <2 x float> %div
}
define <2 x float> @unary_fneg_dividend_constant_divisor_vec(<2 x float> %x) {
; CHECK-LABEL: @unary_fneg_dividend_constant_divisor_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf <2 x float> [[X:%.*]], <float -3.000000e+00, float 8.000000e+00>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fneg <2 x float> %x
%div = fdiv ninf <2 x float> %neg, <float 3.0, float -8.0>
ret <2 x float> %div
}
define <2 x float> @fneg_dividend_constant_divisor_vec_poison_elt(<2 x float> %x) {
; CHECK-LABEL: @fneg_dividend_constant_divisor_vec_poison_elt(
; CHECK-NEXT: [[DIV:%.*]] = fdiv ninf <2 x float> [[X:%.*]], <float -3.000000e+00, float 8.000000e+00>
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fsub <2 x float> <float poison, float -0.0>, %x
%div = fdiv ninf <2 x float> %neg, <float 3.0, float -8.0>
ret <2 x float> %div
}
define <2 x float> @fneg_divisor_constant_dividend_vec(<2 x float> %x) {
; CHECK-LABEL: @fneg_divisor_constant_dividend_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv afn <2 x float> <float 3.000000e+00, float -5.000000e+00>, [[X:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fsub <2 x float> <float -0.0, float -0.0>, %x
%div = fdiv afn <2 x float> <float -3.0, float 5.0>, %neg
ret <2 x float> %div
}
define <2 x float> @unary_fneg_divisor_constant_dividend_vec(<2 x float> %x) {
; CHECK-LABEL: @unary_fneg_divisor_constant_dividend_vec(
; CHECK-NEXT: [[DIV:%.*]] = fdiv afn <2 x float> <float 3.000000e+00, float -5.000000e+00>, [[X:%.*]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fneg <2 x float> %x
%div = fdiv afn <2 x float> <float -3.0, float 5.0>, %neg
ret <2 x float> %div
}
; X / (X * Y) --> 1.0 / Y
define float @div_factor(float %x, float %y) {
; CHECK-LABEL: @div_factor(
; CHECK-NEXT: [[D:%.*]] = fdiv reassoc nnan float 1.000000e+00, [[Y:%.*]]
; CHECK-NEXT: ret float [[D]]
;
%m = fmul float %x, %y
%d = fdiv nnan reassoc float %x, %m
ret float %d;
}
; We can't do the transform without 'nnan' because if x is NAN and y is a number, this should return NAN.
define float @div_factor_too_strict(float %x, float %y) {
; CHECK-LABEL: @div_factor_too_strict(
; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[D:%.*]] = fdiv reassoc float [[X]], [[M]]
; CHECK-NEXT: ret float [[D]]
;
%m = fmul float %x, %y
%d = fdiv reassoc float %x, %m
ret float %d
}
; Commute, verify vector types, and show that we are not dropping extra FMF.
; X / (Y * X) --> 1.0 / Y
define <2 x float> @div_factor_commute(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @div_factor_commute(
; CHECK-NEXT: [[D:%.*]] = fdiv reassoc nnan ninf nsz <2 x float> <float 1.000000e+00, float 1.000000e+00>, [[Y:%.*]]
; CHECK-NEXT: ret <2 x float> [[D]]
;
%m = fmul <2 x float> %y, %x
%d = fdiv nnan ninf nsz reassoc <2 x float> %x, %m
ret <2 x float> %d
}
; C1/(X*C2) => (C1/C2) / X
define <2 x float> @div_constant_dividend1(<2 x float> %x) {
; CHECK-LABEL: @div_constant_dividend1(
; CHECK-NEXT: [[T2:%.*]] = fdiv reassoc arcp <2 x float> <float 5.000000e+00, float 1.000000e+00>, [[X:%.*]]
; CHECK-NEXT: ret <2 x float> [[T2]]
;
%t1 = fmul <2 x float> %x, <float 3.0e0, float 7.0e0>
%t2 = fdiv arcp reassoc <2 x float> <float 15.0e0, float 7.0e0>, %t1
ret <2 x float> %t2
}
define <2 x float> @div_constant_dividend1_arcp_only(<2 x float> %x) {
; CHECK-LABEL: @div_constant_dividend1_arcp_only(
; CHECK-NEXT: [[T1:%.*]] = fmul <2 x float> [[X:%.*]], <float 3.000000e+00, float 7.000000e+00>
; CHECK-NEXT: [[T2:%.*]] = fdiv arcp <2 x float> <float 1.500000e+01, float 7.000000e+00>, [[T1]]
; CHECK-NEXT: ret <2 x float> [[T2]]
;
%t1 = fmul <2 x float> %x, <float 3.0e0, float 7.0e0>
%t2 = fdiv arcp <2 x float> <float 15.0e0, float 7.0e0>, %t1
ret <2 x float> %t2
}
; C1/(X/C2) => (C1*C2) / X
define <2 x float> @div_constant_dividend2(<2 x float> %x) {
; CHECK-LABEL: @div_constant_dividend2(
; CHECK-NEXT: [[T2:%.*]] = fdiv reassoc arcp <2 x float> <float 4.500000e+01, float 4.900000e+01>, [[X:%.*]]
; CHECK-NEXT: ret <2 x float> [[T2]]
;
%t1 = fdiv <2 x float> %x, <float 3.0e0, float -7.0e0>
%t2 = fdiv arcp reassoc <2 x float> <float 15.0e0, float -7.0e0>, %t1
ret <2 x float> %t2
}
define <2 x float> @div_constant_dividend2_reassoc_only(<2 x float> %x) {
; CHECK-LABEL: @div_constant_dividend2_reassoc_only(
; CHECK-NEXT: [[T1:%.*]] = fdiv <2 x float> [[X:%.*]], <float 3.000000e+00, float -7.000000e+00>
; CHECK-NEXT: [[T2:%.*]] = fdiv reassoc <2 x float> <float 1.500000e+01, float -7.000000e+00>, [[T1]]
; CHECK-NEXT: ret <2 x float> [[T2]]
;
%t1 = fdiv <2 x float> %x, <float 3.0e0, float -7.0e0>
%t2 = fdiv reassoc <2 x float> <float 15.0e0, float -7.0e0>, %t1
ret <2 x float> %t2
}
; C1/(C2/X) => (C1/C2) * X
; This tests the combination of 2 folds: (C1 * X) / C2 --> (C1 / C2) * X
define <2 x float> @div_constant_dividend3(<2 x float> %x) {
; CHECK-LABEL: @div_constant_dividend3(
; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc arcp <2 x float> [[X:%.*]], <float 1.500000e+01, float -7.000000e+00>
; CHECK-NEXT: [[T2:%.*]] = fmul reassoc arcp <2 x float> [[TMP1]], <float 0x3FD5555560000000, float 0x3FC24924A0000000>
; CHECK-NEXT: ret <2 x float> [[T2]]
;
%t1 = fdiv <2 x float> <float 3.0e0, float 7.0e0>, %x
%t2 = fdiv arcp reassoc <2 x float> <float 15.0e0, float -7.0e0>, %t1
ret <2 x float> %t2
}
define double @fdiv_fneg1(double %x, double %y) {
; CHECK-LABEL: @fdiv_fneg1(
; CHECK-NEXT: [[NEG:%.*]] = fneg double [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[NEG]], [[Y:%.*]]
; CHECK-NEXT: ret double [[DIV]]
;
%neg = fsub double -0.0, %x
%div = fdiv double %neg, %y
ret double %div
}
define double @fdiv_unary_fneg1(double %x, double %y) {
; CHECK-LABEL: @fdiv_unary_fneg1(
; CHECK-NEXT: [[NEG:%.*]] = fneg double [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[NEG]], [[Y:%.*]]
; CHECK-NEXT: ret double [[DIV]]
;
%neg = fneg double %x
%div = fdiv double %neg, %y
ret double %div
}
define <2 x float> @fdiv_fneg2(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fdiv_fneg2(
; CHECK-NEXT: [[NEG:%.*]] = fneg <2 x float> [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[Y:%.*]], [[NEG]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fsub <2 x float> <float -0.0, float -0.0>, %x
%div = fdiv <2 x float> %y, %neg
ret <2 x float> %div
}
define <2 x float> @fdiv_unary_fneg2(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @fdiv_unary_fneg2(
; CHECK-NEXT: [[NEG:%.*]] = fneg <2 x float> [[X:%.*]]
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[Y:%.*]], [[NEG]]
; CHECK-NEXT: ret <2 x float> [[DIV]]
;
%neg = fneg <2 x float> %x
%div = fdiv <2 x float> %y, %neg
ret <2 x float> %div
}
define float @fdiv_fneg1_extra_use(float %x, float %y) {
; CHECK-LABEL: @fdiv_fneg1_extra_use(
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: call void @use_f32(float [[NEG]])
; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]]
; CHECK-NEXT: ret float [[DIV]]
;
%neg = fsub float -0.0, %x
call void @use_f32(float %neg)
%div = fdiv float %neg, %y
ret float %div
}
define float @fabs_same_op(float %x) {
; CHECK-LABEL: @fabs_same_op(
; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], [[X]]
; CHECK-NEXT: ret float [[R]]
;
%a = call float @llvm.fabs.f32(float %x)
%r = fdiv float %a, %a
ret float %r
}
define float @fabs_same_op_extra_use(float %x) {
; CHECK-LABEL: @fabs_same_op_extra_use(
; CHECK-NEXT: [[A:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: call void @use_f32(float [[A]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc ninf float [[X]], [[X]]
; CHECK-NEXT: ret float [[R]]
;
%a = call float @llvm.fabs.f32(float %x)
call void @use_f32(float %a)
%r = fdiv ninf reassoc float %a, %a
ret float %r
}
define float @fabs_fabs(float %x, float %y) {
; CHECK-LABEL: @fabs_fabs(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = call float @llvm.fabs.f32(float [[TMP1]])
; CHECK-NEXT: ret float [[R]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
%y.fabs = call float @llvm.fabs.f32(float %y)
%r = fdiv float %x.fabs, %y.fabs
ret float %r
}
define float @fabs_fabs_extra_use1(float %x, float %y) {
; CHECK-LABEL: @fabs_fabs_extra_use1(
; CHECK-NEXT: [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: call void @use_f32(float [[X_FABS]])
; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf float [[X]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = call ninf float @llvm.fabs.f32(float [[TMP1]])
; CHECK-NEXT: ret float [[R]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
call void @use_f32(float %x.fabs)
%y.fabs = call float @llvm.fabs.f32(float %y)
%r = fdiv ninf float %x.fabs, %y.fabs
ret float %r
}
define float @fabs_fabs_extra_use2(float %x, float %y) {
; CHECK-LABEL: @fabs_fabs_extra_use2(
; CHECK-NEXT: [[Y_FABS:%.*]] = call fast float @llvm.fabs.f32(float [[Y:%.*]])
; CHECK-NEXT: call void @use_f32(float [[Y_FABS]])
; CHECK-NEXT: [[TMP1:%.*]] = fdiv reassoc ninf float [[X:%.*]], [[Y]]
; CHECK-NEXT: [[R:%.*]] = call reassoc ninf float @llvm.fabs.f32(float [[TMP1]])
; CHECK-NEXT: ret float [[R]]
;
%x.fabs = call fast float @llvm.fabs.f32(float %x)
%y.fabs = call fast float @llvm.fabs.f32(float %y)
call void @use_f32(float %y.fabs)
%r = fdiv reassoc ninf float %x.fabs, %y.fabs
ret float %r
}
; negative test - don't create an extra instruction
define float @fabs_fabs_extra_use3(float %x, float %y) {
; CHECK-LABEL: @fabs_fabs_extra_use3(
; CHECK-NEXT: [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: call void @use_f32(float [[X_FABS]])
; CHECK-NEXT: [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]])
; CHECK-NEXT: call void @use_f32(float [[Y_FABS]])
; CHECK-NEXT: [[R:%.*]] = fdiv float [[X_FABS]], [[Y_FABS]]
; CHECK-NEXT: ret float [[R]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
call void @use_f32(float %x.fabs)
%y.fabs = call float @llvm.fabs.f32(float %y)
call void @use_f32(float %y.fabs)
%r = fdiv float %x.fabs, %y.fabs
ret float %r
}
define float @pow_divisor(float %x, float %y, float %z) {
; CHECK-LABEL: @pow_divisor(
; CHECK-NEXT: [[TMP1:%.*]] = fneg reassoc arcp float [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc arcp float @llvm.pow.f32(float [[X:%.*]], float [[TMP1]])
; CHECK-NEXT: [[R:%.*]] = fmul reassoc arcp float [[Z:%.*]], [[TMP2]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.pow.f32(float %x, float %y)
%r = fdiv reassoc arcp float %z, %p
ret float %r
}
; Negative test - don't create an extra pow
define float @pow_divisor_extra_use(float %x, float %y, float %z) {
; CHECK-LABEL: @pow_divisor_extra_use(
; CHECK-NEXT: [[P:%.*]] = call float @llvm.pow.f32(float [[X:%.*]], float [[Y:%.*]])
; CHECK-NEXT: call void @use_f32(float [[P]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.pow.f32(float %x, float %y)
call void @use_f32(float %p)
%r = fdiv reassoc arcp float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp
define float @pow_divisor_not_enough_fmf(float %x, float %y, float %z) {
; CHECK-LABEL: @pow_divisor_not_enough_fmf(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.pow.f32(float [[X:%.*]], float [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.pow.f32(float %x, float %y)
%r = fdiv reassoc float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp
define float @pow_divisor_not_enough_fmf2(float %x, float %y, float %z) {
; CHECK-LABEL: @pow_divisor_not_enough_fmf2(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.pow.f32(float [[X:%.*]], float [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.pow.f32(float %x, float %y)
%r = fdiv arcp float %z, %p
ret float %r
}
; Special-case - reciprocal does not require extra fmul
define <2 x half> @pow_recip(<2 x half> %x, <2 x half> %y) {
; CHECK-LABEL: @pow_recip(
; CHECK-NEXT: [[TMP1:%.*]] = fneg reassoc ninf arcp <2 x half> [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc ninf arcp <2 x half> @llvm.pow.v2f16(<2 x half> [[X:%.*]], <2 x half> [[TMP1]])
; CHECK-NEXT: ret <2 x half> [[TMP2]]
;
%p = call <2 x half> @llvm.pow.v2f16(<2 x half> %x, <2 x half> %y)
%r = fdiv reassoc arcp ninf <2 x half> <half 1.0, half 1.0>, %p
ret <2 x half> %r
}
define float @exp_divisor(float %y, float %z) {
; CHECK-LABEL: @exp_divisor(
; CHECK-NEXT: [[TMP1:%.*]] = fneg reassoc arcp float [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc arcp float @llvm.exp.f32(float [[TMP1]])
; CHECK-NEXT: [[R:%.*]] = fmul reassoc arcp float [[Z:%.*]], [[TMP2]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.exp.f32(float %y)
%r = fdiv reassoc arcp float %z, %p
ret float %r
}
; Negative test - don't create an extra exp
define float @exp_divisor_extra_use(float %y, float %z) {
; CHECK-LABEL: @exp_divisor_extra_use(
; CHECK-NEXT: [[P:%.*]] = call float @llvm.exp.f32(float [[Y:%.*]])
; CHECK-NEXT: call void @use_f32(float [[P]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.exp.f32(float %y)
call void @use_f32(float %p)
%r = fdiv reassoc arcp float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp
define float @exp_divisor_not_enough_fmf(float %y, float %z) {
; CHECK-LABEL: @exp_divisor_not_enough_fmf(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.exp.f32(float [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.exp.f32(float %y)
%r = fdiv reassoc float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp
define float @exp_divisor_not_enough_fmf2(float %y, float %z) {
; CHECK-LABEL: @exp_divisor_not_enough_fmf2(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.exp.f32(float [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.exp.f32(float %y)
%r = fdiv arcp float %z, %p
ret float %r
}
; Special-case - reciprocal does not require extra fmul
define <2 x half> @exp_recip(<2 x half> %x, <2 x half> %y) {
; CHECK-LABEL: @exp_recip(
; CHECK-NEXT: [[TMP1:%.*]] = fneg reassoc ninf arcp <2 x half> [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc ninf arcp <2 x half> @llvm.exp.v2f16(<2 x half> [[TMP1]])
; CHECK-NEXT: ret <2 x half> [[TMP2]]
;
%p = call <2 x half> @llvm.exp.v2f16(<2 x half> %y)
%r = fdiv reassoc arcp ninf <2 x half> <half 1.0, half 1.0>, %p
ret <2 x half> %r
}
define float @exp2_divisor(float %y, float %z) {
; CHECK-LABEL: @exp2_divisor(
; CHECK-NEXT: [[TMP1:%.*]] = fneg reassoc arcp float [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc arcp float @llvm.exp2.f32(float [[TMP1]])
; CHECK-NEXT: [[R:%.*]] = fmul reassoc arcp float [[Z:%.*]], [[TMP2]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.exp2.f32(float %y)
%r = fdiv reassoc arcp float %z, %p
ret float %r
}
; Negative test - don't create an extra exp
define float @exp2_divisor_extra_use(float %y, float %z) {
; CHECK-LABEL: @exp2_divisor_extra_use(
; CHECK-NEXT: [[P:%.*]] = call float @llvm.exp2.f32(float [[Y:%.*]])
; CHECK-NEXT: call void @use_f32(float [[P]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.exp2.f32(float %y)
call void @use_f32(float %p)
%r = fdiv reassoc arcp float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp
define float @exp2_divisor_not_enough_fmf(float %y, float %z) {
; CHECK-LABEL: @exp2_divisor_not_enough_fmf(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.exp2.f32(float [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.exp2.f32(float %y)
%r = fdiv reassoc float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp
define float @exp2_divisor_not_enough_fmf2(float %y, float %z) {
; CHECK-LABEL: @exp2_divisor_not_enough_fmf2(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.exp2.f32(float [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.exp2.f32(float %y)
%r = fdiv arcp float %z, %p
ret float %r
}
; Special-case - reciprocal does not require extra fmul
define <2 x half> @exp2_recip(<2 x half> %x, <2 x half> %y) {
; CHECK-LABEL: @exp2_recip(
; CHECK-NEXT: [[TMP1:%.*]] = fneg reassoc ninf arcp <2 x half> [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc ninf arcp <2 x half> @llvm.exp2.v2f16(<2 x half> [[TMP1]])
; CHECK-NEXT: ret <2 x half> [[TMP2]]
;
%p = call <2 x half> @llvm.exp2.v2f16(<2 x half> %y)
%r = fdiv reassoc arcp ninf <2 x half> <half 1.0, half 1.0>, %p
ret <2 x half> %r
}
define float @powi_divisor(float %x, i32 %y, float %z) {
; CHECK-LABEL: @powi_divisor(
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc ninf arcp float @llvm.powi.f32.i32(float [[X:%.*]], i32 [[TMP1]])
; CHECK-NEXT: [[R:%.*]] = fmul reassoc ninf arcp float [[Z:%.*]], [[TMP2]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.powi.f32.i32(float %x, i32 %y)
%r = fdiv reassoc arcp ninf float %z, %p
ret float %r
}
; Negative test - don't create an extra pow
define float @powi_divisor_extra_use(float %x, i32 %y, float %z) {
; CHECK-LABEL: @powi_divisor_extra_use(
; CHECK-NEXT: [[P:%.*]] = call float @llvm.powi.f32.i32(float [[X:%.*]], i32 [[Y:%.*]])
; CHECK-NEXT: call void @use_f32(float [[P]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc ninf arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call float @llvm.powi.f32.i32(float %x, i32 %y)
call void @use_f32(float %p)
%r = fdiv reassoc arcp ninf float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp+ninf
define float @powi_divisor_not_enough_fmf(float %x, i32 %y, float %z) {
; CHECK-LABEL: @powi_divisor_not_enough_fmf(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.powi.f32.i32(float [[X:%.*]], i32 [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv reassoc ninf float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.powi.f32.i32(float %x, i32 %y)
%r = fdiv reassoc ninf float %z, %p
ret float %r
}
; Negative test - must have reassoc+arcp+ninf
define float @powi_divisor_not_enough_fmf2(float %x, i32 %y, float %z) {
; CHECK-LABEL: @powi_divisor_not_enough_fmf2(
; CHECK-NEXT: [[P:%.*]] = call fast float @llvm.powi.f32.i32(float [[X:%.*]], i32 [[Y:%.*]])
; CHECK-NEXT: [[R:%.*]] = fdiv ninf arcp float [[Z:%.*]], [[P]]
; CHECK-NEXT: ret float [[R]]
;
%p = call fast float @llvm.powi.f32.i32(float %x, i32 %y)
%r = fdiv arcp ninf float %z, %p
ret float %r
}
; Special-case - reciprocal does not require extra fmul
define <2 x half> @powi_recip(<2 x half> %x, i32 %y) {
; CHECK-LABEL: @powi_recip(
; CHECK-NEXT: [[TMP1:%.*]] = sub i32 0, [[Y:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call reassoc nnan ninf arcp <2 x half> @llvm.powi.v2f16.i32(<2 x half> [[X:%.*]], i32 [[TMP1]])
; CHECK-NEXT: ret <2 x half> [[TMP2]]
;
%p = call <2 x half> @llvm.powi.v2f16.i32(<2 x half> %x, i32 %y)
%r = fdiv reassoc arcp nnan ninf <2 x half> <half 1.0, half 1.0>, %p
ret <2 x half> %r
}
define float @fdiv_zero_f32(float %x) {
; CHECK-LABEL: @fdiv_zero_f32(
; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret float [[FDIV]]
;
%fdiv = fdiv float %x, 0.0
ret float %fdiv
}
; https://alive2.llvm.org/ce/z/gLBFKB
define float @fdiv_nnan_zero_f32(float %x) {
; CHECK-LABEL: @fdiv_nnan_zero_f32(
; CHECK-NEXT: [[FDIV:%.*]] = call nnan float @llvm.copysign.f32(float 0x7FF0000000000000, float [[X:%.*]])
; CHECK-NEXT: ret float [[FDIV]]
;
%fdiv = fdiv nnan float %x, 0.0
ret float %fdiv
}
define <2 x float> @fdiv_nnan_zero_v2f32(<2 x float> %x) {
; CHECK-LABEL: @fdiv_nnan_zero_v2f32(
; CHECK-NEXT: [[FDIV:%.*]] = call nnan <2 x float> @llvm.copysign.v2f32(<2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, <2 x float> [[X:%.*]])
; CHECK-NEXT: ret <2 x float> [[FDIV]]
;
%fdiv = fdiv nnan <2 x float> %x, zeroinitializer
ret <2 x float> %fdiv
}
define float @fdiv_nnan_zero_f32_fmf(float %x) {
; CHECK-LABEL: @fdiv_nnan_zero_f32_fmf(
; CHECK-NEXT: [[FDIV:%.*]] = call nnan nsz float @llvm.copysign.f32(float 0x7FF0000000000000, float [[X:%.*]])
; CHECK-NEXT: ret float [[FDIV]]
;
%fdiv = fdiv nnan nsz float %x, 0.0
ret float %fdiv
}
define <2 x float> @fdiv_nnan_zero_v2f32_fmf(<2 x float> %x) {
; CHECK-LABEL: @fdiv_nnan_zero_v2f32_fmf(
; CHECK-NEXT: [[FDIV:%.*]] = call nnan nsz <2 x float> @llvm.copysign.v2f32(<2 x float> <float 0x7FF0000000000000, float 0x7FF0000000000000>, <2 x float> [[X:%.*]])
; CHECK-NEXT: ret <2 x float> [[FDIV]]
;
%fdiv = fdiv nnan nsz <2 x float> %x, zeroinitializer
ret <2 x float> %fdiv
}
define float @fdiv_nnan_neg_zero_f32(float %x) {
; CHECK-LABEL: @fdiv_nnan_neg_zero_f32(
; CHECK-NEXT: [[FDIV:%.*]] = fdiv nnan float [[X:%.*]], -0.000000e+00
; CHECK-NEXT: ret float [[FDIV]]
;
%fdiv = fdiv nnan float %x, -0.0
ret float %fdiv
}
define double @test_positive_zero_nsz(double %X) {
; CHECK-LABEL: @test_positive_zero_nsz(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz double @llvm.copysign.f64(double 0x7FF0000000000000, double [[X:%.*]])
; CHECK-NEXT: ret double [[TMP1]]
;
%1 = fdiv nnan nsz double %X, 0.0
ret double %1
}
define double @test_negative_zero_nsz(double %X) {
; CHECK-LABEL: @test_negative_zero_nsz(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz double @llvm.copysign.f64(double 0x7FF0000000000000, double [[X:%.*]])
; CHECK-NEXT: ret double [[TMP1]]
;
%1 = fdiv nnan nsz double %X, -0.0
ret double %1
}
define double @test_positive_zero(double %X) {
; CHECK-LABEL: @test_positive_zero(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan double @llvm.copysign.f64(double 0x7FF0000000000000, double [[X:%.*]])
; CHECK-NEXT: ret double [[TMP1]]
;
%1 = fdiv nnan double %X, 0.0
ret double %1
}
define double @test_negative_zero(double %X) {
; CHECK-LABEL: @test_negative_zero(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv nnan double [[X:%.*]], -0.000000e+00
; CHECK-NEXT: ret double [[TMP1]]
;
%1 = fdiv nnan double %X, -0.0
ret double %1
}
define <2 x double> @test_positive_zero_vector_nsz(<2 x double> %X) {
; CHECK-LABEL: @test_positive_zero_vector_nsz(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz <2 x double> @llvm.copysign.v2f64(<2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[X:%.*]])
; CHECK-NEXT: ret <2 x double> [[TMP1]]
;
%1 = fdiv nnan nsz <2 x double> %X, <double 0.0, double 0.0>
ret <2 x double> %1
}
define <2 x double> @test_negative_zero_vector_nsz(<2 x double> %X) {
; CHECK-LABEL: @test_negative_zero_vector_nsz(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz <2 x double> @llvm.copysign.v2f64(<2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[X:%.*]])
; CHECK-NEXT: ret <2 x double> [[TMP1]]
;
%1 = fdiv nnan nsz <2 x double> %X, <double -0.0, double 0.0>
ret <2 x double> %1
}
define <2 x double> @test_positive_zero_vector(<2 x double> %X) {
; CHECK-LABEL: @test_positive_zero_vector(
; CHECK-NEXT: [[TMP1:%.*]] = call nnan <2 x double> @llvm.copysign.v2f64(<2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[X:%.*]])
; CHECK-NEXT: ret <2 x double> [[TMP1]]
;
%1 = fdiv nnan <2 x double> %X, <double 0.0, double 0.0>
ret <2 x double> %1
}
define <2 x double> @test_negative_zero_vector(<2 x double> %X) {
; CHECK-LABEL: @test_negative_zero_vector(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv nnan <2 x double> [[X:%.*]], <double -0.000000e+00, double 0.000000e+00>
; CHECK-NEXT: ret <2 x double> [[TMP1]]
;
%1 = fdiv nnan <2 x double> %X, <double -0.0, double 0.0>
ret <2 x double> %1
}