diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -6749,7 +6749,6 @@ // 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)))) && @@ -6758,10 +6757,28 @@ 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, + // copysign(non-zero constant, X) < 0.0 --> (bitcast X) < 0 + // copysign(non-zero constant, X) > 0.0 --> (bitcast X) > 0 + // copysign(non-zero constant, X) <= 0.0 --> (bitcast X) <= 0 + // copysign(non-zero constant, X) >= 0.0 --> (bitcast X) >= 0 + switch (Pred) { + default: + break; + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_ULT: + return new ICmpInst(ICmpInst::ICMP_SLT, Builder.CreateBitCast(X, IntType), + ConstantInt::getNullValue(IntType)); + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_UGT: + return new ICmpInst(ICmpInst::ICMP_SGT, Builder.CreateBitCast(X, IntType), + ConstantInt::getNullValue(IntType)); + case FCmpInst::FCMP_OLE: + case FCmpInst::FCMP_ULE: + return new ICmpInst(ICmpInst::ICMP_SLE, Builder.CreateBitCast(X, IntType), + ConstantInt::getNullValue(IntType)); + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_UGE: + return new ICmpInst(ICmpInst::ICMP_SGE, Builder.CreateBitCast(X, IntType), ConstantInt::getNullValue(IntType)); } } diff --git a/llvm/test/Transforms/InstCombine/fcmp.ll b/llvm/test/Transforms/InstCombine/fcmp.ll --- a/llvm/test/Transforms/InstCombine/fcmp.ll +++ b/llvm/test/Transforms/InstCombine/fcmp.ll @@ -605,12 +605,10 @@ 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:%.*]]) -; CHECK-NEXT: [[R:%.*]] = fcmp ogt double [[S]], 0.000000e+00 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64 +; CHECK-NEXT: [[R:%.*]] = icmp sgt i64 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %s = call double @llvm.copysign.f64(double -42.0, double %x) @@ -618,6 +616,28 @@ ret i1 %r } +define i1 @is_signbit_clear_1(double %x) { +; CHECK-LABEL: @is_signbit_clear_1( +; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64 +; CHECK-NEXT: [[R:%.*]] = icmp slt i64 [[TMP1]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %s = call double @llvm.copysign.f64(double -42.0, double %x) + %r = fcmp ule double %s, 0.0 + ret i1 %r +} + +define i1 @is_signbit_clear_2(double %x) { +; CHECK-LABEL: @is_signbit_clear_2( +; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[X:%.*]] to i64 +; CHECK-NEXT: [[R:%.*]] = icmp sgt i64 [[TMP1]], -1 +; CHECK-NEXT: ret i1 [[R]] +; + %s = call double @llvm.copysign.f64(double -42.0, double %x) + %r = fcmp uge double %s, 0.0 + ret i1 %r +} + ; Negative test - uses define i1 @is_signbit_set_extra_use(double %x, double* %p) {