diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index cd9a036179b6aa..30048d1232cbf8 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -6267,6 +6267,26 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) { } } + // Convert a sign-bit test of an FP value into a cast and integer compare. + // TODO: Simplify if the copysign constant is 0.0 or NaN. + // TODO: Handle non-zero compare constants. + // TODO: Handle other predicates. + const APFloat *C; + if (match(Op0, m_OneUse(m_Intrinsic(m_APFloat(C), + m_Value(X)))) && + match(Op1, m_AnyZeroFP()) && !C->isZero() && !C->isNaN()) { + Type *IntType = Builder.getIntNTy(X->getType()->getScalarSizeInBits()); + if (auto *VecTy = dyn_cast(OpType)) + IntType = VectorType::get(IntType, VecTy->getElementCount()); + + // copysign(non-zero constant, X) < 0.0 --> (bitcast X) < 0 + if (Pred == FCmpInst::FCMP_OLT) { + Value *IntX = Builder.CreateBitCast(X, IntType); + return new ICmpInst(ICmpInst::ICMP_SLT, IntX, + ConstantInt::getNullValue(IntType)); + } + } + if (I.getType()->isVectorTy()) if (Instruction *Res = foldVectorCmp(I, Builder)) return Res; diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll index 62e747701152b8..c9941ec46c993b 100644 --- a/llvm/test/Transforms/InstCombine/fcmp.ll +++ b/llvm/test/Transforms/InstCombine/fcmp.ll @@ -583,8 +583,8 @@ define <2 x i1> @test27_recipX_gt_vecsplat(<2 x float> %X) { define i1 @is_signbit_set(double %x) { ; CHECK-LABEL: @is_signbit_set( -; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 1.000000e+00, double [[X:%.*]]) -; CHECK-NEXT: [[R:%.*]] = fcmp olt double [[S]], 0.000000e+00 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64 +; CHECK-NEXT: [[R:%.*]] = icmp slt i64 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %s = call double @llvm.copysign.f64(double 1.0, double %x) @@ -592,10 +592,12 @@ define i1 @is_signbit_set(double %x) { ret i1 %r } +; Vectors are ok; the sign of zero in the compare doesn't matter; the copysign constant can be any non-zero number. + define <2 x i1> @is_signbit_set_anyzero(<2 x double> %x) { ; CHECK-LABEL: @is_signbit_set_anyzero( -; CHECK-NEXT: [[S:%.*]] = call <2 x double> @llvm.copysign.v2f64(<2 x double> , <2 x double> [[X:%.*]]) -; CHECK-NEXT: [[R:%.*]] = fcmp olt <2 x double> [[S]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = bitcast <2 x double> [[X:%.*]] to <2 x i64> +; CHECK-NEXT: [[R:%.*]] = icmp slt <2 x i64> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[R]] ; %s = call <2 x double> @llvm.copysign.v2f64(<2 x double> , <2 x double> %x) @@ -603,6 +605,8 @@ define <2 x i1> @is_signbit_set_anyzero(<2 x double> %x) { ret <2 x i1> %r } +; TODO: Handle different predicates. + define i1 @is_signbit_clear(double %x) { ; CHECK-LABEL: @is_signbit_clear( ; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]]) @@ -614,6 +618,8 @@ define i1 @is_signbit_clear(double %x) { ret i1 %r } +; Negative test - uses + define i1 @is_signbit_set_extra_use(double %x, double* %p) { ; CHECK-LABEL: @is_signbit_set_extra_use( ; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 1.000000e+00, double [[X:%.*]]) @@ -627,6 +633,8 @@ define i1 @is_signbit_set_extra_use(double %x, double* %p) { ret i1 %r } +; TODO: Handle non-zero compare constant. + define i1 @is_signbit_clear_nonzero(double %x) { ; CHECK-LABEL: @is_signbit_clear_nonzero( ; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double -4.200000e+01, double [[X:%.*]]) @@ -638,6 +646,8 @@ define i1 @is_signbit_clear_nonzero(double %x) { ret i1 %r } +; TODO: Handle zero copysign constant. + define i1 @is_signbit_set_simplify_zero(double %x) { ; CHECK-LABEL: @is_signbit_set_simplify_zero( ; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0.000000e+00, double [[X:%.*]]) @@ -649,6 +659,8 @@ define i1 @is_signbit_set_simplify_zero(double %x) { ret i1 %r } +; TODO: Handle NaN copysign constant. + define i1 @is_signbit_set_simplify_nan(double %x) { ; CHECK-LABEL: @is_signbit_set_simplify_nan( ; CHECK-NEXT: [[S:%.*]] = call double @llvm.copysign.f64(double 0xFFFFFFFFFFFFFFFF, double [[X:%.*]])