Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -830,11 +830,30 @@ 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; + + if (Mask == (fcZero | fcSubnormal)) { + DenormalMode::DenormalModeKind InputMode = + F.getDenormalMode(Ty->getScalarType()->getFltSemantics()).Input; + return InputMode == DenormalMode::PreserveSign || + InputMode == DenormalMode::PositiveZero; + } + + return false; +} + Instruction *InstCombinerImpl::foldIntrinsicIsFPClass(IntrinsicInst &II) { Value *Src0 = II.getArgOperand(0); Value *Src1 = II.getArgOperand(1); const ConstantInt *CMask = cast(Src1); uint32_t Mask = CMask->getZExtValue(); + uint32_t InvertedMask = ~CMask->getZExtValue() & fcAllFlags; const bool IsStrict = II.isStrictFP(); Value *FNegSrc; @@ -895,6 +914,28 @@ return replaceInstUsesWith(II, FCmp); } + if (!IsStrict && + fpclassTestIsFCmp0(static_cast(Mask), + *II.getParent()->getParent(), Src0->getType())) { + // Equivalent of == 0. + Value *FCmp = + Builder.CreateFCmpOEQ(Src0, ConstantFP::get(Src0->getType(), 0.0)); + + FCmp->takeName(&II); + return replaceInstUsesWith(II, FCmp); + } + + if (!IsStrict && + fpclassTestIsFCmp0(static_cast(InvertedMask), + *II.getParent()->getParent(), Src0->getType())) { + // Equivalent of !(x == 0). + Value *FCmp = + Builder.CreateFCmpUNE(Src0, ConstantFP::get(Src0->getType(), 0.0)); + + FCmp->takeName(&II); + return replaceInstUsesWith(II, FCmp); + } + // fp_class (nnan x), qnan|snan|other -> fp_class (nnan x), other if ((Mask & fcNan) && isKnownNeverNaN(Src0, &getTargetLibraryInfo())) { II.setArgOperand(1, ConstantInt::get(Src1->getType(), Mask & ~fcNan)); Index: llvm/test/Transforms/InstCombine/is_fpclass.ll =================================================================== --- llvm/test/Transforms/InstCombine/is_fpclass.ll +++ llvm/test/Transforms/InstCombine/is_fpclass.ll @@ -116,7 +116,7 @@ define i1 @test_class_is_p0_n0_f32(float %x) { ; CHECK-LABEL: @test_class_is_p0_n0_f32( -; CHECK-NEXT: [[VAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 96) +; CHECK-NEXT: [[VAL:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[VAL]] ; %val = call i1 @llvm.is.fpclass.f32(float %x, i32 96) ; fcZero @@ -125,7 +125,7 @@ define <2 x i1> @test_class_is_p0_n0_v2f32(<2 x float> %x) { ; CHECK-LABEL: @test_class_is_p0_n0_v2f32( -; CHECK-NEXT: [[VAL:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[X:%.*]], i32 96) +; CHECK-NEXT: [[VAL:%.*]] = fcmp oeq <2 x float> [[X:%.*]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[VAL]] ; %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 96) ; fcZero @@ -170,7 +170,7 @@ define i1 @test_class_is_not_p0_n0_f32(float %x) { ; CHECK-LABEL: @test_class_is_not_p0_n0_f32( -; CHECK-NEXT: [[VAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 927) +; CHECK-NEXT: [[VAL:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[VAL]] ; %val = call i1 @llvm.is.fpclass.f32(float %x, i32 927) ; ~fcZero & fcAllFlags @@ -179,7 +179,7 @@ define <2 x i1> @test_class_is_not_p0_n0_v2f32(<2 x float> %x) { ; CHECK-LABEL: @test_class_is_not_p0_n0_v2f32( -; CHECK-NEXT: [[VAL:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[X:%.*]], i32 927) +; CHECK-NEXT: [[VAL:%.*]] = fcmp une <2 x float> [[X:%.*]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[VAL]] ; %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 927) ; ~fcZero & fcAllFlags @@ -215,7 +215,7 @@ define i1 @test_class_is_not_p0_n0_psub_nsub_f32_daz(float %x) "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @test_class_is_not_p0_n0_psub_nsub_f32_daz( -; CHECK-NEXT: [[VAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 783) +; CHECK-NEXT: [[VAL:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[VAL]] ; %val = call i1 @llvm.is.fpclass.f32(float %x, i32 783) ; ~(fcZero|fcSubnormal) & fcAllFlags @@ -224,7 +224,7 @@ define i1 @test_class_is_not_p0_n0_psub_nsub_f32_dapz(float %x) "denormal-fp-math"="ieee,positive-zero" { ; CHECK-LABEL: @test_class_is_not_p0_n0_psub_nsub_f32_dapz( -; CHECK-NEXT: [[VAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 783) +; CHECK-NEXT: [[VAL:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[VAL]] ; %val = call i1 @llvm.is.fpclass.f32(float %x, i32 783) ; ~(fcZero|fcSubnormal) & fcAllFlags @@ -278,7 +278,7 @@ define i1 @test_class_is_p0_n0_psub_nsub_f32_daz(float %x) "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @test_class_is_p0_n0_psub_nsub_f32_daz( -; CHECK-NEXT: [[VAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 240) +; CHECK-NEXT: [[VAL:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[VAL]] ; %val = call i1 @llvm.is.fpclass.f32(float %x, i32 240) ; fcZero | fcSubnormal @@ -287,7 +287,7 @@ define i1 @test_class_is_p0_n0_psub_nsub_f32_dapz(float %x) "denormal-fp-math"="ieee,positive-zero" { ; CHECK-LABEL: @test_class_is_p0_n0_psub_nsub_f32_dapz( -; CHECK-NEXT: [[VAL:%.*]] = call i1 @llvm.is.fpclass.f32(float [[X:%.*]], i32 240) +; CHECK-NEXT: [[VAL:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[VAL]] ; %val = call i1 @llvm.is.fpclass.f32(float %x, i32 240) ; fcZero | fcSubnormal @@ -314,7 +314,7 @@ define <2 x i1> @test_class_is_p0_n0_psub_nsub_v2f32_daz(<2 x float> %x) "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @test_class_is_p0_n0_psub_nsub_v2f32_daz( -; CHECK-NEXT: [[VAL:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[X:%.*]], i32 240) +; CHECK-NEXT: [[VAL:%.*]] = fcmp oeq <2 x float> [[X:%.*]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[VAL]] ; %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 240) ; fcZero | fcSubnormal @@ -323,7 +323,7 @@ define <2 x i1> @test_class_is_p0_n0_psub_nsub_v2f32_dapz(<2 x float> %x) "denormal-fp-math"="ieee,positive-zero" { ; CHECK-LABEL: @test_class_is_p0_n0_psub_nsub_v2f32_dapz( -; CHECK-NEXT: [[VAL:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[X:%.*]], i32 240) +; CHECK-NEXT: [[VAL:%.*]] = fcmp oeq <2 x float> [[X:%.*]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[VAL]] ; %val = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> %x, i32 240) ; fcZero | fcSubnormal @@ -1460,7 +1460,7 @@ define i1 @test_class_fneg_zero(float %arg) { ; ; CHECK-LABEL: @test_class_fneg_zero( -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 96) +; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CLASS]] ; %fneg = fneg float %arg @@ -1715,7 +1715,7 @@ ; -> poszero define i1 @test_class_fabs_poszero(float %arg) { ; CHECK-LABEL: @test_class_fabs_poszero( -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 96) +; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call float @llvm.fabs.f32(float %arg) @@ -1792,7 +1792,7 @@ ; -> poszero define i1 @test_class_fabs_zero(float %arg) { ; CHECK-LABEL: @test_class_fabs_zero( -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 96) +; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call float @llvm.fabs.f32(float %arg) @@ -2038,7 +2038,7 @@ define i1 @test_class_fneg_fabs_negzero(float %arg) { ; CHECK-LABEL: @test_class_fneg_fabs_negzero( -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 96) +; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call float @llvm.fabs.f32(float %arg) @@ -2122,7 +2122,7 @@ define i1 @test_class_fneg_fabs_zero(float %arg) { ; CHECK-LABEL: @test_class_fneg_fabs_zero( -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[ARG:%.*]], i32 96) +; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq float [[ARG:%.*]], 0.000000e+00 ; CHECK-NEXT: ret i1 [[CLASS]] ; %fabs = call float @llvm.fabs.f32(float %arg)