This is mostly NFC but some output does change due to consistently inserting into poison rather than undef and using i64 as the index type for inserts.
1067 lines
37 KiB
LLVM
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_undef_elt(<2 x float> %x) {
|
|
; CHECK-LABEL: @not_exact_inverse_vec_arcp_with_undef_elt(
|
|
; CHECK-NEXT: [[DIV:%.*]] = fdiv arcp <2 x float> [[X:%.*]], <float undef, float 3.000000e+00>
|
|
; CHECK-NEXT: ret <2 x float> [[DIV]]
|
|
;
|
|
%div = fdiv arcp <2 x float> %x, <float undef, 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_undef_elts(<2 x float> %x, <2 x float> %y) {
|
|
; CHECK-LABEL: @fneg_fneg_vec_undef_elts(
|
|
; CHECK-NEXT: [[DIV:%.*]] = fdiv <2 x float> [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret <2 x float> [[DIV]]
|
|
;
|
|
%xneg = fsub <2 x float> <float undef, float -0.0>, %x
|
|
%yneg = fsub <2 x float> <float -0.0, float undef>, %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_undef_elt(<2 x float> %x) {
|
|
; CHECK-LABEL: @fneg_dividend_constant_divisor_vec_undef_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 undef, 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 [[TMP2]], [[Z:%.*]]
|
|
; 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 [[TMP2]], [[Z:%.*]]
|
|
; 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 [[TMP2]], [[Z:%.*]]
|
|
; 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 [[TMP2]], [[Z:%.*]]
|
|
; 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
|
|
}
|