[llvm] [ValueTracking] Compute known FPClass from signbit idiom (PR #80740)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 14 03:20:49 PST 2024


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/80740

>From 6a53e1b1724f44da57cff8f0d13889427b40ef74 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 13 Feb 2024 20:58:41 +0800
Subject: [PATCH 1/4] [ValueTracking] Add pre-commit tests. NFC.

---
 .../InstCombine/fpclass-from-dom-cond.ll      | 116 ++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
index 5d4840159dc9a0..6f4cf092cfbc6f 100644
--- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
+++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
@@ -320,3 +320,119 @@ if.else:
   %ret = call i1 @llvm.is.fpclass.f32(float %x, i32 783)
   ret i1 %ret
 }
+
+define float @test_signbit_check(float %x, i1 %cond) {
+; CHECK-LABEL: define float @test_signbit_check(
+; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[I32:%.*]] = bitcast float [[X]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I32]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then1:
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
+; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
+; CHECK-NEXT:    ret float [[RET]]
+;
+  %i32 = bitcast float %x to i32
+  %cmp = icmp slt i32 %i32, 0
+  br i1 %cmp, label %if.then1, label %if.else
+
+if.then1:
+  %fneg = fneg float %x
+  br label %if.end
+
+if.else:
+  br i1 %cond, label %if.then2, label %if.end
+
+if.then2:
+  br label %if.end
+
+if.end:
+  %value = phi float [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
+  %ret = call float @llvm.fabs.f32(float %value)
+  ret float %ret
+}
+
+define float @test_signbit_check_fail(float %x, i1 %cond) {
+; CHECK-LABEL: define float @test_signbit_check_fail(
+; CHECK-SAME: float [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[I32:%.*]] = bitcast float [[X]] to i32
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[I32]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then1:
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg float [[X]]
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    [[FNEG2:%.*]] = fneg float [[X]]
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[FNEG2]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
+; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
+; CHECK-NEXT:    ret float [[RET]]
+;
+  %i32 = bitcast float %x to i32
+  %cmp = icmp slt i32 %i32, 0
+  br i1 %cmp, label %if.then1, label %if.else
+
+if.then1:
+  %fneg = fneg float %x
+  br label %if.end
+
+if.else:
+  br i1 %cond, label %if.then2, label %if.end
+
+if.then2:
+  %fneg2 = fneg float %x
+  br label %if.end
+
+if.end:
+  %value = phi float [ %fneg, %if.then1 ], [ %fneg2, %if.then2 ], [ %x, %if.else ]
+  %ret = call float @llvm.fabs.f32(float %value)
+  ret float %ret
+}
+
+define <2 x float> @test_signbit_check_wrong_type(<2 x float> %x, i1 %cond) {
+; CHECK-LABEL: define <2 x float> @test_signbit_check_wrong_type(
+; CHECK-SAME: <2 x float> [[X:%.*]], i1 [[COND:%.*]]) {
+; CHECK-NEXT:    [[I32:%.*]] = bitcast <2 x float> [[X]] to i64
+; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i64 [[I32]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_ELSE:%.*]]
+; CHECK:       if.then1:
+; CHECK-NEXT:    [[FNEG:%.*]] = fneg <2 x float> [[X]]
+; CHECK-NEXT:    br label [[IF_END:%.*]]
+; CHECK:       if.else:
+; CHECK-NEXT:    br i1 [[COND]], label [[IF_THEN2:%.*]], label [[IF_END]]
+; CHECK:       if.then2:
+; CHECK-NEXT:    br label [[IF_END]]
+; CHECK:       if.end:
+; CHECK-NEXT:    [[VALUE:%.*]] = phi <2 x float> [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
+; CHECK-NEXT:    [[RET:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[VALUE]])
+; CHECK-NEXT:    ret <2 x float> [[RET]]
+;
+  %i32 = bitcast <2 x float> %x to i64
+  %cmp = icmp slt i64 %i32, 0
+  br i1 %cmp, label %if.then1, label %if.else
+
+if.then1:
+  %fneg = fneg <2 x float> %x
+  br label %if.end
+
+if.else:
+  br i1 %cond, label %if.then2, label %if.end
+
+if.then2:
+  br label %if.end
+
+if.end:
+  %value = phi <2 x float> [ %fneg, %if.then1 ], [ %x, %if.then2 ], [ %x, %if.else ]
+  %ret = call <2 x float> @llvm.fabs.v2f32(<2 x float> %value)
+  ret <2 x float> %ret
+}

>From e4e88ce4492996446d7701efff204ce36565b900 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Tue, 13 Feb 2024 21:18:20 +0800
Subject: [PATCH 2/4] [ValueTracking] Handle signbit idiom in
 `computeKnownFPClassFromCond`

---
 llvm/lib/Analysis/DomConditionCache.cpp           |  4 ++++
 llvm/lib/Analysis/ValueTracking.cpp               | 15 ++++++++++++++-
 .../InstCombine/fpclass-from-dom-cond.ll          |  3 +--
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp
index c07a8a76f111df..66ad2b8d86dc39 100644
--- a/llvm/lib/Analysis/DomConditionCache.cpp
+++ b/llvm/lib/Analysis/DomConditionCache.cpp
@@ -66,6 +66,10 @@ static void findAffectedValues(Value *Cond,
         // A > C3 && A < C4.
         if (match(A, m_Add(m_Value(X), m_ConstantInt())))
           AddAffected(X);
+        // Handle icmp slt/sgt (bitcast X to int), 0/-1
+        if (match(A, m_ElementWiseBitCast(m_Value(X))) &&
+            (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGT))
+          Affected.push_back(X);
       }
     } else if (match(Cond, m_CombineOr(m_FCmp(Pred, m_Value(A), m_Constant()),
                                        m_Intrinsic<Intrinsic::is_fpclass>(
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 6c42facea3b2b3..9ed204f7b2c5db 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4272,7 +4272,7 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond,
   Value *LHS;
   uint64_t ClassVal = 0;
   const APFloat *CRHS;
-  // TODO: handle sign-bit check idiom
+  const APInt *RHS;
   if (match(Cond, m_FCmp(Pred, m_Value(LHS), m_APFloat(CRHS)))) {
     auto [CmpVal, MaskIfTrue, MaskIfFalse] = fcmpImpliesClass(
         Pred, *CxtI->getParent()->getParent(), LHS, *CRHS, LHS != V);
@@ -4282,6 +4282,19 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond,
                              m_Value(LHS), m_ConstantInt(ClassVal)))) {
     FPClassTest Mask = static_cast<FPClassTest>(ClassVal);
     KnownFromContext.knownNot(CondIsTrue ? ~Mask : Mask);
+  } else if (match(Cond, m_ICmp(Pred, m_ElementWiseBitCast(m_Value(LHS)),
+                                m_APInt(RHS)))) {
+    bool TrueIfSigned;
+    if (Pred == ICmpInst::ICMP_SLT && RHS->isZero())
+      TrueIfSigned = true;
+    else if (Pred == ICmpInst::ICMP_SGT && RHS->isAllOnes())
+      TrueIfSigned = false;
+    else
+      return;
+    if (TrueIfSigned == CondIsTrue)
+      KnownFromContext.signBitMustBeOne();
+    else
+      KnownFromContext.signBitMustBeZero();
   }
 }
 
diff --git a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
index 6f4cf092cfbc6f..d40cd7fd503ecc 100644
--- a/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
+++ b/llvm/test/Transforms/InstCombine/fpclass-from-dom-cond.ll
@@ -336,8 +336,7 @@ define float @test_signbit_check(float %x, i1 %cond) {
 ; CHECK-NEXT:    br label [[IF_END]]
 ; CHECK:       if.end:
 ; CHECK-NEXT:    [[VALUE:%.*]] = phi float [ [[FNEG]], [[IF_THEN1]] ], [ [[X]], [[IF_THEN2]] ], [ [[X]], [[IF_ELSE]] ]
-; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fabs.f32(float [[VALUE]])
-; CHECK-NEXT:    ret float [[RET]]
+; CHECK-NEXT:    ret float [[VALUE]]
 ;
   %i32 = bitcast float %x to i32
   %cmp = icmp slt i32 %i32, 0

>From 57ec61d6eeda08bbddae395530fad88ee9c8074d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 14 Feb 2024 09:20:48 +0800
Subject: [PATCH 3/4] fixup! [ValueTracking] Handle signbit idiom in
 `computeKnownFPClassFromCond`

---
 llvm/lib/Analysis/DomConditionCache.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/DomConditionCache.cpp b/llvm/lib/Analysis/DomConditionCache.cpp
index 66ad2b8d86dc39..274f3ff44b2a6f 100644
--- a/llvm/lib/Analysis/DomConditionCache.cpp
+++ b/llvm/lib/Analysis/DomConditionCache.cpp
@@ -66,9 +66,10 @@ static void findAffectedValues(Value *Cond,
         // A > C3 && A < C4.
         if (match(A, m_Add(m_Value(X), m_ConstantInt())))
           AddAffected(X);
-        // Handle icmp slt/sgt (bitcast X to int), 0/-1
-        if (match(A, m_ElementWiseBitCast(m_Value(X))) &&
-            (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGT))
+        // Handle icmp slt/sgt (bitcast X to int), 0/-1, which is supported by
+        // computeKnownFPClass().
+        if ((Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGT) &&
+            match(A, m_ElementWiseBitCast(m_Value(X))))
           Affected.push_back(X);
       }
     } else if (match(Cond, m_CombineOr(m_FCmp(Pred, m_Value(A), m_Constant()),

>From 041218bf5491996edd828cc15b3aec5a59ddc636 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 14 Feb 2024 19:20:13 +0800
Subject: [PATCH 4/4] [ValueTracking] Use the `isSignBitCheck` helper.

---
 llvm/lib/Analysis/ValueTracking.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 9ed204f7b2c5db..cc1d5b74dcfc53 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -4285,11 +4285,7 @@ static void computeKnownFPClassFromCond(const Value *V, Value *Cond,
   } else if (match(Cond, m_ICmp(Pred, m_ElementWiseBitCast(m_Value(LHS)),
                                 m_APInt(RHS)))) {
     bool TrueIfSigned;
-    if (Pred == ICmpInst::ICMP_SLT && RHS->isZero())
-      TrueIfSigned = true;
-    else if (Pred == ICmpInst::ICMP_SGT && RHS->isAllOnes())
-      TrueIfSigned = false;
-    else
+    if (!isSignBitCheck(Pred, *RHS, TrueIfSigned))
       return;
     if (TrueIfSigned == CondIsTrue)
       KnownFromContext.signBitMustBeOne();



More information about the llvm-commits mailing list