forked from OSchip/llvm-project
[InstCombine] canonicalize fcmp+select to fabs
This is complicated by -0.0 and nan. This is based on the DAG patterns as shown in D44091. I'm hoping that we can just remove those DAG folds and always rely on IR canonicalization to handle the matching to fabs. We would still need to delete the broken code from DAGCombiner to fix PR36600: https://bugs.llvm.org/show_bug.cgi?id=36600 Differential Revision: https://reviews.llvm.org/D44550 llvm-svn: 327858
This commit is contained in:
parent
e5340a8ce9
commit
0ce3086777
|
@ -1569,7 +1569,37 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
|
|||
|
||||
// NOTE: if we wanted to, this is where to detect MIN/MAX
|
||||
}
|
||||
// NOTE: if we wanted to, this is where to detect ABS
|
||||
|
||||
// Canonicalize select with fcmp to fabs(). -0.0 makes this tricky. We need
|
||||
// fast-math-flags (nsz) or fsub with +0.0 (not fneg) for this to work. We
|
||||
// also require nnan because we do not want to unintentionally change the
|
||||
// sign of a NaN value.
|
||||
Value *X = FCI->getOperand(0);
|
||||
FCmpInst::Predicate Pred = FCI->getPredicate();
|
||||
if (match(FCI->getOperand(1), m_AnyZeroFP()) && FCI->hasNoNaNs()) {
|
||||
// (X <= +/-0.0) ? (0.0 - X) : X --> fabs(X)
|
||||
// (X > +/-0.0) ? X : (0.0 - X) --> fabs(X)
|
||||
if ((X == FalseVal && match(TrueVal, m_FSub(m_Zero(), m_Specific(X))) &&
|
||||
Pred == FCmpInst::FCMP_OLE) ||
|
||||
(X == TrueVal && match(FalseVal, m_FSub(m_Zero(), m_Specific(X))) &&
|
||||
Pred == FCmpInst::FCMP_OGT)) {
|
||||
Value *Fabs = Builder.CreateIntrinsic(Intrinsic::fabs, { X }, FCI);
|
||||
return replaceInstUsesWith(SI, Fabs);
|
||||
}
|
||||
// With nsz:
|
||||
// (X < +/-0.0) ? -X : X --> fabs(X)
|
||||
// (X <= +/-0.0) ? -X : X --> fabs(X)
|
||||
// (X > +/-0.0) ? X : -X --> fabs(X)
|
||||
// (X >= +/-0.0) ? X : -X --> fabs(X)
|
||||
if (FCI->hasNoSignedZeros() &&
|
||||
((X == FalseVal && match(TrueVal, m_FNeg(m_Specific(X))) &&
|
||||
(Pred == FCmpInst::FCMP_OLT || Pred == FCmpInst::FCMP_OLE)) ||
|
||||
(X == TrueVal && match(FalseVal, m_FNeg(m_Specific(X))) &&
|
||||
(Pred == FCmpInst::FCMP_OGT || Pred == FCmpInst::FCMP_OGE)))) {
|
||||
Value *Fabs = Builder.CreateIntrinsic(Intrinsic::fabs, { X }, FCI);
|
||||
return replaceInstUsesWith(SI, Fabs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See if we are selecting two values based on a comparison of the two values.
|
||||
|
|
|
@ -246,14 +246,28 @@ define double @multi_use_fabs_fpext(float %x) {
|
|||
ret double %fabs
|
||||
}
|
||||
|
||||
; X <= 0.0 ? (0.0 - X) : X --> fabs(X)
|
||||
; Negative test for the fabs folds below: we require nnan, so
|
||||
; we won't always clear the sign bit of a NaN value.
|
||||
|
||||
define double @select_fcmp_ole_zero(double %x) {
|
||||
; CHECK-LABEL: @select_fcmp_ole_zero(
|
||||
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp nnan ole double [[X:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp ole double [[X:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub double 0.000000e+00, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
|
||||
; CHECK-NEXT: ret double [[FABS]]
|
||||
;
|
||||
%lezero = fcmp ole double %x, 0.0
|
||||
%negx = fsub double 0.0, %x
|
||||
%fabs = select i1 %lezero, double %negx, double %x
|
||||
ret double %fabs
|
||||
}
|
||||
|
||||
; X <= 0.0 ? (0.0 - X) : X --> fabs(X)
|
||||
|
||||
define double @select_fcmp_nnan_ole_zero(double %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_ole_zero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan double @llvm.fabs.f64(double [[X:%.*]])
|
||||
; CHECK-NEXT: ret double [[TMP1]]
|
||||
;
|
||||
%lezero = fcmp nnan ole double %x, 0.0
|
||||
%negx = fsub double 0.0, %x
|
||||
|
@ -263,12 +277,10 @@ define double @select_fcmp_ole_zero(double %x) {
|
|||
|
||||
; X <= -0.0 ? (0.0 - X) : X --> fabs(X)
|
||||
|
||||
define float @select_fcmp_ole_negzero(float %x) {
|
||||
; CHECK-LABEL: @select_fcmp_ole_negzero(
|
||||
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp nnan ole float [[X:%.*]], -0.000000e+00
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub float 0.000000e+00, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], float [[NEGX]], float [[X]]
|
||||
; CHECK-NEXT: ret float [[FABS]]
|
||||
define float @select_fcmp_nnan_ole_negzero(float %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_ole_negzero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float [[X:%.*]])
|
||||
; CHECK-NEXT: ret float [[TMP1]]
|
||||
;
|
||||
%lezero = fcmp nnan ole float %x, -0.0
|
||||
%negx = fsub float 0.0, %x
|
||||
|
@ -278,12 +290,10 @@ define float @select_fcmp_ole_negzero(float %x) {
|
|||
|
||||
; X > 0.0 ? X : (0.0 - X) --> fabs(X)
|
||||
|
||||
define fp128 @select_fcmp_ogt_zero(fp128 %x) {
|
||||
; CHECK-LABEL: @select_fcmp_ogt_zero(
|
||||
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp nnan ogt fp128 [[X:%.*]], 0xL00000000000000000000000000000000
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub fp128 0xL00000000000000000000000000000000, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GTZERO]], fp128 [[X]], fp128 [[NEGX]]
|
||||
; CHECK-NEXT: ret fp128 [[FABS]]
|
||||
define fp128 @select_fcmp_nnan_ogt_zero(fp128 %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_ogt_zero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan fp128 @llvm.fabs.f128(fp128 [[X:%.*]])
|
||||
; CHECK-NEXT: ret fp128 [[TMP1]]
|
||||
;
|
||||
%gtzero = fcmp nnan ogt fp128 %x, zeroinitializer
|
||||
%negx = fsub fp128 zeroinitializer, %x
|
||||
|
@ -293,12 +303,10 @@ define fp128 @select_fcmp_ogt_zero(fp128 %x) {
|
|||
|
||||
; X > -0.0 ? X : (0.0 - X) --> fabs(X)
|
||||
|
||||
define half @select_fcmp_ogt_negzero(half %x) {
|
||||
; CHECK-LABEL: @select_fcmp_ogt_negzero(
|
||||
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp nnan ogt half [[X:%.*]], 0xH8000
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub half 0xH0000, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GTZERO]], half [[X]], half [[NEGX]]
|
||||
; CHECK-NEXT: ret half [[FABS]]
|
||||
define half @select_fcmp_nnan_ogt_negzero(half %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_ogt_negzero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan half @llvm.fabs.f16(half [[X:%.*]])
|
||||
; CHECK-NEXT: ret half [[TMP1]]
|
||||
;
|
||||
%gtzero = fcmp nnan ogt half %x, -0.0
|
||||
%negx = fsub half 0.0, %x
|
||||
|
@ -308,12 +316,10 @@ define half @select_fcmp_ogt_negzero(half %x) {
|
|||
|
||||
; X < 0.0 ? -X : X --> fabs(X)
|
||||
|
||||
define double @select_fcmp_nsz_olt_zero(double %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_olt_zero(
|
||||
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp nnan nsz olt double [[X:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub double -0.000000e+00, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LTZERO]], double [[NEGX]], double [[X]]
|
||||
; CHECK-NEXT: ret double [[FABS]]
|
||||
define double @select_fcmp_nnan_nsz_olt_zero(double %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_zero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz double @llvm.fabs.f64(double [[X:%.*]])
|
||||
; CHECK-NEXT: ret double [[TMP1]]
|
||||
;
|
||||
%ltzero = fcmp nnan nsz olt double %x, 0.0
|
||||
%negx = fsub double -0.0, %x
|
||||
|
@ -323,12 +329,10 @@ define double @select_fcmp_nsz_olt_zero(double %x) {
|
|||
|
||||
; X < -0.0 ? -X : X --> fabs(X)
|
||||
|
||||
define float @select_fcmp_nsz_olt_negzero(float %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_olt_negzero(
|
||||
; CHECK-NEXT: [[LTZERO:%.*]] = fcmp nnan ninf nsz olt float [[X:%.*]], -0.000000e+00
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub float -0.000000e+00, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LTZERO]], float [[NEGX]], float [[X]]
|
||||
; CHECK-NEXT: ret float [[FABS]]
|
||||
define float @select_fcmp_nnan_nsz_olt_negzero(float %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_olt_negzero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[X:%.*]])
|
||||
; CHECK-NEXT: ret float [[TMP1]]
|
||||
;
|
||||
%ltzero = fcmp nnan nsz ninf olt float %x, -0.0
|
||||
%negx = fsub float -0.0, %x
|
||||
|
@ -338,12 +342,10 @@ define float @select_fcmp_nsz_olt_negzero(float %x) {
|
|||
|
||||
; X <= 0.0 ? -X : X --> fabs(X)
|
||||
|
||||
define double @select_fcmp_nsz_ole_zero(double %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_ole_zero(
|
||||
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp fast ole double [[X:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub double -0.000000e+00, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], double [[NEGX]], double [[X]]
|
||||
; CHECK-NEXT: ret double [[FABS]]
|
||||
define double @select_fcmp_nnan_nsz_ole_zero(double %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_zero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call fast double @llvm.fabs.f64(double [[X:%.*]])
|
||||
; CHECK-NEXT: ret double [[TMP1]]
|
||||
;
|
||||
%lezero = fcmp fast ole double %x, 0.0
|
||||
%negx = fsub double -0.0, %x
|
||||
|
@ -353,12 +355,10 @@ define double @select_fcmp_nsz_ole_zero(double %x) {
|
|||
|
||||
; X <= -0.0 ? -X : X --> fabs(X)
|
||||
|
||||
define float @select_fcmp_nsz_ole_negzero(float %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_ole_negzero(
|
||||
; CHECK-NEXT: [[LEZERO:%.*]] = fcmp nnan nsz ole float [[X:%.*]], -0.000000e+00
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub float -0.000000e+00, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[LEZERO]], float [[NEGX]], float [[X]]
|
||||
; CHECK-NEXT: ret float [[FABS]]
|
||||
define float @select_fcmp_nnan_nsz_ole_negzero(float %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_ole_negzero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[X:%.*]])
|
||||
; CHECK-NEXT: ret float [[TMP1]]
|
||||
;
|
||||
%lezero = fcmp nnan nsz ole float %x, -0.0
|
||||
%negx = fsub float -0.0, %x
|
||||
|
@ -368,12 +368,10 @@ define float @select_fcmp_nsz_ole_negzero(float %x) {
|
|||
|
||||
; X > 0.0 ? X : (0.0 - X) --> fabs(X)
|
||||
|
||||
define <2 x float> @select_fcmp_nsz_ogt_zero(<2 x float> %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_ogt_zero(
|
||||
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp nnan nsz arcp ogt <2 x float> [[X:%.*]], zeroinitializer
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select <2 x i1> [[GTZERO]], <2 x float> [[X]], <2 x float> [[NEGX]]
|
||||
; CHECK-NEXT: ret <2 x float> [[FABS]]
|
||||
define <2 x float> @select_fcmp_nnan_nsz_ogt_zero(<2 x float> %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_zero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz arcp <2 x float> @llvm.fabs.v2f32(<2 x float> [[X:%.*]])
|
||||
; CHECK-NEXT: ret <2 x float> [[TMP1]]
|
||||
;
|
||||
%gtzero = fcmp nnan nsz arcp ogt <2 x float> %x, zeroinitializer
|
||||
%negx = fsub <2 x float> <float -0.0, float -0.0>, %x
|
||||
|
@ -383,12 +381,10 @@ define <2 x float> @select_fcmp_nsz_ogt_zero(<2 x float> %x) {
|
|||
|
||||
; X > -0.0 ? X : (0.0 - X) --> fabs(X)
|
||||
|
||||
define half @select_fcmp_nsz_ogt_negzero(half %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_ogt_negzero(
|
||||
; CHECK-NEXT: [[GTZERO:%.*]] = fcmp fast ogt half [[X:%.*]], 0xH8000
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub half 0xH0000, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GTZERO]], half [[X]], half [[NEGX]]
|
||||
; CHECK-NEXT: ret half [[FABS]]
|
||||
define half @select_fcmp_nnan_nsz_ogt_negzero(half %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_ogt_negzero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call fast half @llvm.fabs.f16(half [[X:%.*]])
|
||||
; CHECK-NEXT: ret half [[TMP1]]
|
||||
;
|
||||
%gtzero = fcmp fast ogt half %x, -0.0
|
||||
%negx = fsub half 0.0, %x
|
||||
|
@ -398,12 +394,10 @@ define half @select_fcmp_nsz_ogt_negzero(half %x) {
|
|||
|
||||
; X > 0.0 ? X : (0.0 - X) --> fabs(X)
|
||||
|
||||
define <2 x double> @select_fcmp_nsz_oge_zero(<2 x double> %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_oge_zero(
|
||||
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp reassoc nnan nsz oge <2 x double> [[X:%.*]], zeroinitializer
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select <2 x i1> [[GEZERO]], <2 x double> [[X]], <2 x double> [[NEGX]]
|
||||
; CHECK-NEXT: ret <2 x double> [[FABS]]
|
||||
define <2 x double> @select_fcmp_nnan_nsz_oge_zero(<2 x double> %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_zero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan nsz <2 x double> @llvm.fabs.v2f64(<2 x double> [[X:%.*]])
|
||||
; CHECK-NEXT: ret <2 x double> [[TMP1]]
|
||||
;
|
||||
%gezero = fcmp nnan nsz reassoc oge <2 x double> %x, zeroinitializer
|
||||
%negx = fsub <2 x double> <double -0.0, double -0.0>, %x
|
||||
|
@ -413,12 +407,10 @@ define <2 x double> @select_fcmp_nsz_oge_zero(<2 x double> %x) {
|
|||
|
||||
; X > -0.0 ? X : (0.0 - X) --> fabs(X)
|
||||
|
||||
define half @select_fcmp_nsz_oge_negzero(half %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nsz_oge_negzero(
|
||||
; CHECK-NEXT: [[GEZERO:%.*]] = fcmp nnan nsz oge half [[X:%.*]], 0xH8000
|
||||
; CHECK-NEXT: [[NEGX:%.*]] = fsub half 0xH8000, [[X]]
|
||||
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[GEZERO]], half [[X]], half [[NEGX]]
|
||||
; CHECK-NEXT: ret half [[FABS]]
|
||||
define half @select_fcmp_nnan_nsz_oge_negzero(half %x) {
|
||||
; CHECK-LABEL: @select_fcmp_nnan_nsz_oge_negzero(
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz half @llvm.fabs.f16(half [[X:%.*]])
|
||||
; CHECK-NEXT: ret half [[TMP1]]
|
||||
;
|
||||
%gezero = fcmp nnan nsz oge half %x, -0.0
|
||||
%negx = fsub half -0.0, %x
|
||||
|
|
Loading…
Reference in New Issue