Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -834,6 +834,13 @@ return replaceInstUsesWith(II, FCmp); } + if (Mask == (~fcNan & fcAllFlags) && !IsStrict) { + // Equivalent of !isnan. Replace with standard fcmp. + Value *FCmp = Builder.CreateFCmpORD(Src0, Src0); + FCmp->takeName(&II); + return replaceInstUsesWith(II, FCmp); + } + if (Mask == fcZero && !IsStrict) { // Equivalent of == 0. Value *FCmp = @@ -843,14 +850,26 @@ return replaceInstUsesWith(II, FCmp); } + if (Mask == (~fcZero & fcAllFlags) && !IsStrict) { + // 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())) { return replaceOperand(II, 1, ConstantInt::get(Src1->getType(), Mask & ~fcNan)); } - // TODO: Handle inverted mask cases, e.g. // fp_class (nnan x), ~(qnan|snan) -> true + if (Mask == (~fcNan & fcAllFlags) && + isKnownNeverNaN(Src0, &getTargetLibraryInfo())) { + return replaceInstUsesWith(II, ConstantInt::get(II.getType(), true)); + } // fp_class (ninf x), ninf|pinf|other -> fp_class (ninf x), other if ((Mask & fcInf) && isKnownNeverInfinity(Src0, &getTargetLibraryInfo())) { @@ -858,6 +877,12 @@ ConstantInt::get(Src1->getType(), Mask & ~fcInf)); } + // fp_class (ninf x), ~(ninf|pinf) -> true + if (Mask == (~fcInf & fcAllFlags) && + isKnownNeverInfinity(Src0, &getTargetLibraryInfo())) { + return replaceInstUsesWith(II, ConstantInt::get(II.getType(), true)); + } + // Clamp mask to used bits if ((Mask & fcAllFlags) != Mask) { CallInst *NewCall = Builder.CreateCall( Index: llvm/test/Transforms/InstCombine/is_fpclass.ll =================================================================== --- llvm/test/Transforms/InstCombine/is_fpclass.ll +++ llvm/test/Transforms/InstCombine/is_fpclass.ll @@ -125,7 +125,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 @@ -143,7 +143,7 @@ define i1 @test_class_is_not_p0_n0_f32_daz(float %x) "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @test_class_is_not_p0_n0_f32_daz( -; 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 @@ -447,9 +447,7 @@ ; Fold test of is not nan define i1 @test_class_is_not_nan_nnan_src(float %x) { ; CHECK-LABEL: @test_class_is_not_nan_nnan_src( -; CHECK-NEXT: [[NNAN:%.*]] = fadd nnan float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NNAN]], i32 1020) -; CHECK-NEXT: ret i1 [[CLASS]] +; CHECK-NEXT: ret i1 true ; %nnan = fadd nnan float %x, 1.0 %class = call i1 @llvm.is.fpclass.f32(float %nnan, i32 1020) ; ~fcNan & fcAllFlags @@ -458,9 +456,7 @@ define i1 @test_class_is_not_nan_nnan_src_strict(float %x) { ; CHECK-LABEL: @test_class_is_not_nan_nnan_src_strict( -; CHECK-NEXT: [[NNAN:%.*]] = fadd nnan float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NNAN]], i32 1020) #[[ATTR3]] -; CHECK-NEXT: ret i1 [[CLASS]] +; CHECK-NEXT: ret i1 true ; %nnan = fadd nnan float %x, 1.0 %class = call i1 @llvm.is.fpclass.f32(float %nnan, i32 1020) strictfp ; ~fcNan & fcAllFlags @@ -511,9 +507,7 @@ define i1 @test_class_is_not_inf_ninf_src(float %x) { ; CHECK-LABEL: @test_class_is_not_inf_ninf_src( -; CHECK-NEXT: [[NINF:%.*]] = fadd ninf float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NINF]], i32 507) -; CHECK-NEXT: ret i1 [[CLASS]] +; CHECK-NEXT: ret i1 true ; %ninf = fadd ninf float %x, 1.0 %class = call i1 @llvm.is.fpclass.f32(float %ninf, i32 507) ; ~fcInf & fcAllFlags @@ -522,9 +516,7 @@ define i1 @test_class_is_not_inf_ninf_src_strict(float %x) { ; CHECK-LABEL: @test_class_is_not_inf_ninf_src_strict( -; CHECK-NEXT: [[NINF:%.*]] = fadd ninf float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NINF]], i32 507) #[[ATTR3]] -; CHECK-NEXT: ret i1 [[CLASS]] +; CHECK-NEXT: ret i1 true ; %ninf = fadd ninf float %x, 1.0 %class = call i1 @llvm.is.fpclass.f32(float %ninf, i32 507) strictfp ; ~fcInf & fcAllFlags