[llvm] 8529470 - [InstCombine] fold fcmp-of-copysign idiom

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 17 07:32:45 PST 2021


Author: Sanjay Patel
Date: 2021-02-17T10:32:33-05:00
New Revision: 85294703a74a532448b3d3801d4e9a5c6024547a

URL: https://github.com/llvm/llvm-project/commit/85294703a74a532448b3d3801d4e9a5c6024547a
DIFF: https://github.com/llvm/llvm-project/commit/85294703a74a532448b3d3801d4e9a5c6024547a.diff

LOG: [InstCombine] fold fcmp-of-copysign idiom

As discussed in:
https://llvm.org/PR49179
...this pattern shows up in library code.
There are several potential generalizations as noted,
but we need to be careful that we get FP special-values
right, and it's not clear how much variation we should
expect to see from this exact idiom.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/fcmp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index cd9a036179b6..30048d1232cb 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<Intrinsic::copysign>(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<VectorType>(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 62e747701152..c9941ec46c99 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> <double 4.200000e+01, double 4.200000e+01>, <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> <double 42.0, double 42.0>, <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 
diff erent 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:%.*]])


        


More information about the llvm-commits mailing list