InstCombine: Try to turn is.fpclass sign checks to fcmp with 0
Try to use gt/lt compares with 0 instead of class.
This commit is contained in:
parent
e03200164b
commit
e09115bcfd
@ -837,6 +837,17 @@ public:
|
||||
return getOrderedPredicate(getPredicate());
|
||||
}
|
||||
|
||||
/// Returns the unordered variant of a floating point compare.
|
||||
///
|
||||
/// For example, OEQ -> UEQ, OLT -> ULT, OEQ -> UEQ
|
||||
static Predicate getUnorderedPredicate(Predicate Pred) {
|
||||
return static_cast<Predicate>(Pred | FCMP_UNO);
|
||||
}
|
||||
|
||||
Predicate getUnorderedPredicate() const {
|
||||
return getUnorderedPredicate(getPredicate());
|
||||
}
|
||||
|
||||
/// For example, EQ -> NE, UGT -> ULE, SLT -> SGE,
|
||||
/// OEQ -> UNE, UGT -> OLE, OLT -> UGE, etc.
|
||||
/// @returns the inverse predicate for predicate provided in \p pred.
|
||||
|
||||
@ -813,22 +813,75 @@ InstCombinerImpl::foldIntrinsicWithOverflowCommon(IntrinsicInst *II) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// \returns true if the test performed by llvm.is.fpclass(x, \p Mask) is
|
||||
/// equivalent to fcmp oeq x, 0.0 with the floating-point environment assumed
|
||||
/// for \p F for type \p Ty
|
||||
static bool fpclassTestIsFCmp0(FPClassTest Mask, const Function &F, Type *Ty) {
|
||||
if (Mask == fcZero)
|
||||
return F.getDenormalMode(Ty->getScalarType()->getFltSemantics()).Input ==
|
||||
DenormalMode::IEEE;
|
||||
static bool inputDenormalIsIEEE(const Function &F, const Type *Ty) {
|
||||
Ty = Ty->getScalarType();
|
||||
return F.getDenormalMode(Ty->getFltSemantics()).Input == DenormalMode::IEEE;
|
||||
}
|
||||
|
||||
if (Mask == (fcZero | fcSubnormal)) {
|
||||
DenormalMode::DenormalModeKind InputMode =
|
||||
F.getDenormalMode(Ty->getScalarType()->getFltSemantics()).Input;
|
||||
return InputMode == DenormalMode::PreserveSign ||
|
||||
InputMode == DenormalMode::PositiveZero;
|
||||
static bool inputDenormalIsDAZ(const Function &F, const Type *Ty) {
|
||||
Ty = Ty->getScalarType();
|
||||
return F.getDenormalMode(Ty->getFltSemantics()).inputsAreZero();
|
||||
}
|
||||
|
||||
/// \returns the compare predicate type if the test performed by
|
||||
/// llvm.is.fpclass(x, \p Mask) is equivalent to fcmp o__ x, 0.0 with the
|
||||
/// floating-point environment assumed for \p F for type \p Ty
|
||||
static FCmpInst::Predicate fpclassTestIsFCmp0(FPClassTest Mask,
|
||||
const Function &F, Type *Ty) {
|
||||
switch (static_cast<unsigned>(Mask)) {
|
||||
case fcZero:
|
||||
if (inputDenormalIsIEEE(F, Ty))
|
||||
return FCmpInst::FCMP_OEQ;
|
||||
break;
|
||||
case fcZero | fcSubnormal:
|
||||
if (inputDenormalIsDAZ(F, Ty))
|
||||
return FCmpInst::FCMP_OEQ;
|
||||
break;
|
||||
case fcPositive | fcNegZero:
|
||||
if (inputDenormalIsIEEE(F, Ty))
|
||||
return FCmpInst::FCMP_OGE;
|
||||
break;
|
||||
case fcPositive | fcNegZero | fcNegSubnormal:
|
||||
if (inputDenormalIsDAZ(F, Ty))
|
||||
return FCmpInst::FCMP_OGE;
|
||||
break;
|
||||
case fcPosSubnormal | fcPosNormal | fcPosInf:
|
||||
if (inputDenormalIsIEEE(F, Ty))
|
||||
return FCmpInst::FCMP_OGT;
|
||||
break;
|
||||
case fcNegative | fcPosZero:
|
||||
if (inputDenormalIsIEEE(F, Ty))
|
||||
return FCmpInst::FCMP_OLE;
|
||||
break;
|
||||
case fcNegative | fcPosZero | fcPosSubnormal:
|
||||
if (inputDenormalIsDAZ(F, Ty))
|
||||
return FCmpInst::FCMP_OLE;
|
||||
break;
|
||||
case fcNegSubnormal | fcNegNormal | fcNegInf:
|
||||
if (inputDenormalIsIEEE(F, Ty))
|
||||
return FCmpInst::FCMP_OLT;
|
||||
break;
|
||||
case fcPosNormal | fcPosInf:
|
||||
if (inputDenormalIsDAZ(F, Ty))
|
||||
return FCmpInst::FCMP_OGT;
|
||||
break;
|
||||
case fcNegNormal | fcNegInf:
|
||||
if (inputDenormalIsDAZ(F, Ty))
|
||||
return FCmpInst::FCMP_OLT;
|
||||
break;
|
||||
case ~fcZero & ~fcNan:
|
||||
if (inputDenormalIsIEEE(F, Ty))
|
||||
return FCmpInst::FCMP_ONE;
|
||||
break;
|
||||
case ~(fcZero | fcSubnormal) & ~fcNan:
|
||||
if (inputDenormalIsDAZ(F, Ty))
|
||||
return FCmpInst::FCMP_ONE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return FCmpInst::BAD_FCMP_PREDICATE;
|
||||
}
|
||||
|
||||
Instruction *InstCombinerImpl::foldIntrinsicIsFPClass(IntrinsicInst &II) {
|
||||
@ -905,24 +958,30 @@ Instruction *InstCombinerImpl::foldIntrinsicIsFPClass(IntrinsicInst &II) {
|
||||
return replaceInstUsesWith(II, FCmp);
|
||||
}
|
||||
|
||||
FCmpInst::Predicate PredType = FCmpInst::BAD_FCMP_PREDICATE;
|
||||
|
||||
// Try to replace with an fcmp with 0
|
||||
//
|
||||
// is.fpclass(x, fcZero) -> fcmp oeq x, 0.0
|
||||
// is.fpclass(x, fcZero | fcNan) -> fcmp ueq x, 0.0
|
||||
// is.fpclass(x, ~fcZero & ~fcNan) -> fcmp one x, 0.0
|
||||
// is.fpclass(x, ~fcZero) -> fcmp une x, 0.0
|
||||
//
|
||||
// is.fpclass(x, fcPosSubnormal | fcPosNormal | fcPosInf) -> fcmp ogt x, 0.0
|
||||
// is.fpclass(x, fcPositive | fcNegZero) -> fcmp oge x, 0.0
|
||||
//
|
||||
// is.fpclass(x, fcNegSubnormal | fcNegNormal | fcNegInf) -> fcmp olt x, 0.0
|
||||
// is.fpclass(x, fcNegative | fcPosZero) -> fcmp ole x, 0.0
|
||||
//
|
||||
if (!IsStrict && (IsOrdered || IsUnordered) &&
|
||||
fpclassTestIsFCmp0(OrderedMask, *II.getFunction(), Src0->getType())) {
|
||||
(PredType = fpclassTestIsFCmp0(OrderedMask, *II.getFunction(),
|
||||
Src0->getType())) !=
|
||||
FCmpInst::BAD_FCMP_PREDICATE) {
|
||||
Constant *Zero = ConstantFP::getZero(Src0->getType());
|
||||
// Equivalent of == 0.
|
||||
Value *FCmp = IsUnordered ? Builder.CreateFCmpUEQ(Src0, Zero)
|
||||
: Builder.CreateFCmpOEQ(Src0, Zero);
|
||||
FCmp->takeName(&II);
|
||||
return replaceInstUsesWith(II, FCmp);
|
||||
}
|
||||
|
||||
if (!IsStrict && (IsOrdered || IsUnordered) &&
|
||||
fpclassTestIsFCmp0(OrderedInvertedMask, *II.getFunction(),
|
||||
Src0->getType())) {
|
||||
Constant *Zero = ConstantFP::getZero(Src0->getType());
|
||||
|
||||
// Equivalent of !(x == 0).
|
||||
Value *FCmp = IsUnordered ? Builder.CreateFCmpUNE(Src0, Zero)
|
||||
: Builder.CreateFCmpONE(Src0, Zero);
|
||||
Value *FCmp = Builder.CreateFCmp(
|
||||
IsUnordered ? FCmpInst::getUnorderedPredicate(PredType) : PredType,
|
||||
Src0, Zero);
|
||||
|
||||
FCmp->takeName(&II);
|
||||
return replaceInstUsesWith(II, FCmp);
|
||||
|
||||
@ -2790,7 +2790,7 @@ define i1 @test_class_is_pzero_psub_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
|
||||
define i1 @test_class_is_psub_pnorm_pinf__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_psub_pnorm_pinf__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 896)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ogt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 896)
|
||||
@ -2817,7 +2817,7 @@ define i1 @test_class_is_psub_pnorm_pinf_qnan__ieee(float %arg) #0 {
|
||||
|
||||
define i1 @test_class_is_psub_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_psub_pnorm_pinf_nan__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 899)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ugt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 899)
|
||||
@ -2853,7 +2853,7 @@ define i1 @test_class_is_pzero_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
|
||||
define i1 @test_class_is_nzero_pzero_psub_pnorm_pinf__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_nzero_pzero_psub_pnorm_pinf__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 992)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oge float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 992)
|
||||
@ -2880,7 +2880,7 @@ define i1 @test_class_is_nzero_pzero_psub_pnorm_pinf_qnan__ieee(float %arg) #0 {
|
||||
|
||||
define i1 @test_class_is_nzero_pzero_psub_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_nzero_pzero_psub_pnorm_pinf_nan__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 995)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp uge float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 995)
|
||||
@ -2980,7 +2980,7 @@ define i1 @test_class_is_not_pzero_psub_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
|
||||
define i1 @test_class_is_not_psub_pnorm_pinf__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_not_psub_pnorm_pinf__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 127)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ule float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 127)
|
||||
@ -3007,7 +3007,7 @@ define i1 @test_class_is_not_psub_pnorm_pinf_qnan__ieee(float %arg) #0 {
|
||||
|
||||
define i1 @test_class_is_not_psub_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_not_psub_pnorm_pinf_nan__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 124)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ole float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 124)
|
||||
@ -3070,7 +3070,7 @@ define i1 @test_class_is_not_nzero_pzero_psub_pnorm_pinf_qnan__ieee(float %arg)
|
||||
|
||||
define i1 @test_class_is_not_nzero_pzero_psub_pnorm_pinf_nan__ieee(float %arg) #0 {
|
||||
; CHECK-LABEL: @test_class_is_not_nzero_pzero_psub_pnorm_pinf_nan__ieee(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 28)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp olt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 28)
|
||||
@ -3209,7 +3209,7 @@ define i1 @test_class_is_psub_pnorm_pinf_nan__daz(float %arg) #1 {
|
||||
|
||||
define i1 @test_class_is_pnorm_pinf__daz(float %arg) #1 {
|
||||
; CHECK-LABEL: @test_class_is_pnorm_pinf__daz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 768)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ogt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 768)
|
||||
@ -3299,7 +3299,7 @@ define i1 @test_class_is_nsub_nzero_pzero_psub_pnorm_pinf_qnan__daz(float %arg)
|
||||
|
||||
define i1 @test_class_is_nsub_nzero_pzero_psub_pnorm_pinf_nan__daz(float %arg) #1 {
|
||||
; CHECK-LABEL: @test_class_is_nsub_nzero_pzero_psub_pnorm_pinf_nan__daz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 1011)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp uge float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 1011)
|
||||
@ -3399,7 +3399,7 @@ define i1 @test_class_is_not_psub_pnorm_pinf_nan__daz(float %arg) #1 {
|
||||
|
||||
define i1 @test_class_is_not_pnorm_pinf__daz(float %arg) #1 {
|
||||
; CHECK-LABEL: @test_class_is_not_pnorm_pinf__daz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 255)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ule float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 255)
|
||||
@ -3489,7 +3489,7 @@ define i1 @test_class_is_not_nsub_nzero_pzero_psub_pnorm_pinf_qnan__daz(float %a
|
||||
|
||||
define i1 @test_class_is_not_nsub_nzero_pzero_psub_pnorm_pinf_nan__daz(float %arg) #1 {
|
||||
; CHECK-LABEL: @test_class_is_not_nsub_nzero_pzero_psub_pnorm_pinf_nan__daz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 12)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp olt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 12)
|
||||
@ -3592,7 +3592,7 @@ define i1 @test_class_is_psub_pnorm_pinf_nan__dapz(float %arg) #2 {
|
||||
|
||||
define i1 @test_class_is_pnorm_pinf__dapz(float %arg) #2 {
|
||||
; CHECK-LABEL: @test_class_is_pnorm_pinf__dapz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 768)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ogt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 768)
|
||||
@ -3682,7 +3682,7 @@ define i1 @test_class_is_nsub_nzero_pzero_psub_pnorm_pinf_qnan__dapz(float %arg)
|
||||
|
||||
define i1 @test_class_is_nsub_nzero_pzero_psub_pnorm_pinf_nan__dapz(float %arg) #2 {
|
||||
; CHECK-LABEL: @test_class_is_nsub_nzero_pzero_psub_pnorm_pinf_nan__dapz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 1011)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp uge float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 1011)
|
||||
@ -3782,7 +3782,7 @@ define i1 @test_class_is_not_psub_pnorm_pinf_nan__dapz(float %arg) #2 {
|
||||
|
||||
define i1 @test_class_is_not_pnorm_pinf__dapz(float %arg) #2 {
|
||||
; CHECK-LABEL: @test_class_is_not_pnorm_pinf__dapz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 255)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ule float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 255)
|
||||
@ -3872,7 +3872,7 @@ define i1 @test_class_is_not_nsub_nzero_pzero_psub_pnorm_pinf_qnan__dapz(float %
|
||||
|
||||
define i1 @test_class_is_not_nsub_nzero_pzero_psub_pnorm_pinf_nan__dapz(float %arg) #2 {
|
||||
; CHECK-LABEL: @test_class_is_not_nsub_nzero_pzero_psub_pnorm_pinf_nan__dapz(
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 12)
|
||||
; CHECK-NEXT: [[CLASS:%.*]] = fcmp olt float [[ARG:%.*]], 0.000000e+00
|
||||
; CHECK-NEXT: ret i1 [[CLASS]]
|
||||
;
|
||||
%class = call i1 @llvm.is.fpclass.f32(float %arg, i32 12)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user