[llvm] [InstCombine] Simplify (A >= 0) & ((A & INT_MAX) != 0) to A > 0 (PR #207209)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 2 08:42:52 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: AZero13 (AZero13)

<details>
<summary>Changes</summary>

This patch implements simplifications for bitwise and logical AND/OR combinations of sign-bit checks and lower-bits checks.

---
Full diff: https://github.com/llvm/llvm-project/pull/207209.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+28) 
- (added) llvm/test/Transforms/InstCombine/sign-bitwise-check.ll (+75) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index b6f4a55c07e8a..591802b77178c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3533,6 +3533,34 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
     }
   }
 
+  // (icmp sge X, 0) & (icmp ne (X & INT_MAX), 0) -> (icmp sgt X, 0)
+  // (icmp slt X, 0) | (icmp eq (X & INT_MAX), 0) -> (icmp sle X, 0)
+  {
+    bool TrueIfSigned;
+    if (isSignBitCheck(PredL, *LHSC, TrueIfSigned) &&
+        PredR == (IsAnd ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ) &&
+        match(RHS1, m_Zero()) &&
+        match(RHS0, m_And(m_Specific(LHS0), m_MaxSignedValue()))) {
+      if (IsAnd && !TrueIfSigned)
+        return Builder.CreateICmpSGT(
+            LHS0, ConstantInt::getNullValue(LHS0->getType()));
+      if (!IsAnd && TrueIfSigned)
+        return Builder.CreateICmpSLE(
+            LHS0, ConstantInt::getNullValue(LHS0->getType()));
+    }
+    if (isSignBitCheck(PredR, *RHSC, TrueIfSigned) &&
+        PredL == (IsAnd ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ) &&
+        match(LHS1, m_Zero()) &&
+        match(LHS0, m_And(m_Specific(RHS0), m_MaxSignedValue()))) {
+      if (IsAnd && !TrueIfSigned)
+        return Builder.CreateICmpSGT(
+            RHS0, ConstantInt::getNullValue(RHS0->getType()));
+      if (!IsAnd && TrueIfSigned)
+        return Builder.CreateICmpSLE(
+            RHS0, ConstantInt::getNullValue(RHS0->getType()));
+    }
+  }
+
   // Match naive pattern (and its inverted form) for checking if two values
   // share same sign. An example of the pattern:
   // (icmp slt (X & Y), 0) | (icmp sgt (X | Y), -1) -> (icmp sgt (X ^ Y), -1)
diff --git a/llvm/test/Transforms/InstCombine/sign-bitwise-check.ll b/llvm/test/Transforms/InstCombine/sign-bitwise-check.ll
new file mode 100644
index 0000000000000..2b404e56c58fc
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/sign-bitwise-check.ll
@@ -0,0 +1,75 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+define i1 @test_and(i32 %A) {
+; CHECK-LABEL: @test_and(
+; CHECK-NEXT:    [[RES:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cmp1 = icmp sge i32 %A, 0
+  %and = and i32 %A, 2147483647
+  %cmp2 = icmp ne i32 %and, 0
+  %res = and i1 %cmp1, %cmp2
+  ret i1 %res
+}
+
+define i1 @test_or(i32 %A) {
+; CHECK-LABEL: @test_or(
+; CHECK-NEXT:    [[RES:%.*]] = icmp slt i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cmp1 = icmp slt i32 %A, 0
+  %and = and i32 %A, 2147483647
+  %cmp2 = icmp eq i32 %and, 0
+  %res = or i1 %cmp1, %cmp2
+  ret i1 %res
+}
+
+define i1 @test_and_logical(i32 %A) {
+; CHECK-LABEL: @test_and_logical(
+; CHECK-NEXT:    [[RES:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cmp1 = icmp sge i32 %A, 0
+  %and = and i32 %A, 2147483647
+  %cmp2 = icmp ne i32 %and, 0
+  %res = select i1 %cmp1, i1 %cmp2, i1 false
+  ret i1 %res
+}
+
+define i1 @test_or_logical(i32 %A) {
+; CHECK-LABEL: @test_or_logical(
+; CHECK-NEXT:    [[RES:%.*]] = icmp slt i32 [[A:%.*]], 1
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cmp1 = icmp slt i32 %A, 0
+  %and = and i32 %A, 2147483647
+  %cmp2 = icmp eq i32 %and, 0
+  %res = select i1 %cmp1, i1 true, i1 %cmp2
+  ret i1 %res
+}
+
+define <2 x i1> @test_and_vec(<2 x i32> %A) {
+; CHECK-LABEL: @test_and_vec(
+; CHECK-NEXT:    [[RES:%.*]] = icmp sgt <2 x i32> [[A:%.*]], zeroinitializer
+; CHECK-NEXT:    ret <2 x i1> [[RES]]
+;
+  %cmp1 = icmp sge <2 x i32> %A, zeroinitializer
+  %and = and <2 x i32> %A, <i32 2147483647, i32 2147483647>
+  %cmp2 = icmp ne <2 x i32> %and, zeroinitializer
+  %res = and <2 x i1> %cmp1, %cmp2
+  ret <2 x i1> %res
+}
+
+define i1 @test_and_commuted(i32 %A) {
+; CHECK-LABEL: @test_and_commuted(
+; CHECK-NEXT:    [[RES:%.*]] = icmp sgt i32 [[A:%.*]], 0
+; CHECK-NEXT:    ret i1 [[RES]]
+;
+  %cmp1 = icmp sge i32 %A, 0
+  %and = and i32 %A, 2147483647
+  %cmp2 = icmp ne i32 %and, 0
+  %res = and i1 %cmp2, %cmp1
+  ret i1 %res
+}
+

``````````

</details>


https://github.com/llvm/llvm-project/pull/207209


More information about the llvm-commits mailing list