[llvm] [ConstraintElimination] Decompose bitwise and or (PR #126158)

Lee Wei via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 6 15:50:47 PST 2025


https://github.com/leewei05 created https://github.com/llvm/llvm-project/pull/126158

Alive2: https://alive2.llvm.org/ce/z/XUp6KG
Fixes #118114

@regehr 

>From f000937d1610bf5ab697ddcbfaba918f28540675 Mon Sep 17 00:00:00 2001
From: Lee <lee10202013 at gmail.com>
Date: Tue, 4 Feb 2025 15:18:07 -0700
Subject: [PATCH 1/2] Add bitwise or and bitwise and decomposition tests

---
 .../Transforms/ConstraintElimination/and.ll   | 88 +++++++++++++++++++
 .../Transforms/ConstraintElimination/or.ll    | 88 +++++++++++++++++++
 2 files changed, 176 insertions(+)

diff --git a/llvm/test/Transforms/ConstraintElimination/and.ll b/llvm/test/Transforms/ConstraintElimination/and.ll
index f9824df3975e97a..350d75160d4de77 100644
--- a/llvm/test/Transforms/ConstraintElimination/and.ll
+++ b/llvm/test/Transforms/ConstraintElimination/and.ll
@@ -603,3 +603,91 @@ exit:
 
   ret i1 %r.10
 }
+
+define void @test_decompose_bitwise_and(i4 %x, i4 %y) {
+; CHECK-LABEL: @test_decompose_bitwise_and(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = and i4 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = icmp slt i4 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[AND]], label [[BB1:%.*]], label [[EXIT:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[F_1:%.*]] = icmp sge i4 [[X]], 0
+; CHECK-NEXT:    [[F_2:%.*]] = icmp sge i4 [[Y]], 0
+; CHECK-NEXT:    [[F_AND:%.*]] = and i1 [[F_1]], [[F_2]]
+; CHECK-NEXT:    call void @use(i1 [[F_AND]])
+; CHECK-NEXT:    ret void
+; CHECK:       exit:
+; CHECK-NEXT:    [[F_3:%.*]] = icmp slt i4 [[X]], 0
+; CHECK-NEXT:    [[F_4:%.*]] = icmp slt i4 [[Y]], 0
+; CHECK-NEXT:    [[F_AND_2:%.*]] = and i1 [[F_3]], [[F_4]]
+; CHECK-NEXT:    call void @use(i1 [[F_AND_2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %1 = and i4 %y, %x
+  %and = icmp slt i4 %1, 0
+  br i1 %and, label %bb1, label %exit
+
+bb1:
+  %f.1 = icmp sge i4 %x, 0
+  %f.2 = icmp sge i4 %y, 0
+  %f.and = and i1 %f.1, %f.2
+  call void @use(i1 %f.and)
+  ret void
+
+exit:
+  %f.3 = icmp slt i4 %x, 0
+  %f.4 = icmp slt i4 %y, 0
+  %f.and.2 = and i1 %f.3, %f.4
+  call void @use(i1 %f.and.2)
+  ret void
+}
+
+define void @test_decompose_nested_bitwise_and(i4 %x, i4 %y, i4 %z) {
+; CHECK-LABEL: @test_decompose_nested_bitwise_and(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = and i4 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i4 [[TMP0]], [[Z:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = icmp slt i4 [[TMP1]], 0
+; CHECK-NEXT:    br i1 [[AND]], label [[BB1:%.*]], label [[EXIT:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[F_1:%.*]] = icmp sge i4 [[X]], 0
+; CHECK-NEXT:    [[F_2:%.*]] = icmp sge i4 [[Y]], 0
+; CHECK-NEXT:    [[F_3:%.*]] = icmp sge i4 [[Z]], 0
+; CHECK-NEXT:    [[F_AND:%.*]] = and i1 [[F_1]], [[F_2]]
+; CHECK-NEXT:    [[F_AND_2:%.*]] = and i1 [[F_AND]], [[F_3]]
+; CHECK-NEXT:    call void @use(i1 [[F_AND]])
+; CHECK-NEXT:    ret void
+; CHECK:       exit:
+; CHECK-NEXT:    [[F_4:%.*]] = icmp slt i4 [[X]], 0
+; CHECK-NEXT:    [[F_5:%.*]] = icmp slt i4 [[Y]], 0
+; CHECK-NEXT:    [[F_6:%.*]] = icmp slt i4 [[Z]], 0
+; CHECK-NEXT:    [[F_AND_3:%.*]] = and i1 [[F_4]], [[F_5]]
+; CHECK-NEXT:    [[F_AND_4:%.*]] = and i1 [[F_AND_3]], [[F_6]]
+; CHECK-NEXT:    call void @use(i1 [[F_AND_4]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %1 = and i4 %y, %x
+  %2 = and i4 %1, %z
+  %and = icmp slt i4 %2, 0
+  br i1 %and, label %bb1, label %exit
+
+bb1:
+  %f.1 = icmp sge i4 %x, 0
+  %f.2 = icmp sge i4 %y, 0
+  %f.3 = icmp sge i4 %z, 0
+  %f.and = and i1 %f.1, %f.2
+  %f.and.2 = and i1 %f.and, %f.3
+  call void @use(i1 %f.and)
+  ret void
+
+exit:
+  %f.4 = icmp slt i4 %x, 0
+  %f.5 = icmp slt i4 %y, 0
+  %f.6 = icmp slt i4 %z, 0
+  %f.and.3 = and i1 %f.4, %f.5
+  %f.and.4 = and i1 %f.and.3, %f.6
+  call void @use(i1 %f.and.4)
+  ret void
+}
diff --git a/llvm/test/Transforms/ConstraintElimination/or.ll b/llvm/test/Transforms/ConstraintElimination/or.ll
index b401d6f18136958..ac0c02e2807f7ca 100644
--- a/llvm/test/Transforms/ConstraintElimination/or.ll
+++ b/llvm/test/Transforms/ConstraintElimination/or.ll
@@ -808,3 +808,91 @@ end:                                           ; preds = %entry
 
   ret void
 }
+
+define void @test_decompose_bitwise_or(i4 %x, i4 %y) {
+; CHECK-LABEL: @test_decompose_bitwise_or(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = or i4 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = icmp slt i4 [[TMP0]], 0
+; CHECK-NEXT:    br i1 [[OR]], label [[BB1:%.*]], label [[EXIT:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[F_1:%.*]] = icmp slt i4 [[X]], 0
+; CHECK-NEXT:    [[F_2:%.*]] = icmp slt i4 [[Y]], 0
+; CHECK-NEXT:    [[F_OR:%.*]] = or i1 [[F_1]], [[F_2]]
+; CHECK-NEXT:    call void @use(i1 [[F_OR]])
+; CHECK-NEXT:    ret void
+; CHECK:       exit:
+; CHECK-NEXT:    [[F_3:%.*]] = icmp sge i4 [[X]], 0
+; CHECK-NEXT:    [[F_4:%.*]] = icmp sge i4 [[Y]], 0
+; CHECK-NEXT:    [[F_OR_2:%.*]] = or i1 [[F_3]], [[F_4]]
+; CHECK-NEXT:    call void @use(i1 [[F_OR_2]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %1 = or i4 %y, %x
+  %or = icmp slt i4 %1, 0
+  br i1 %or, label %bb1, label %exit
+
+bb1:
+  %f.1 = icmp slt i4 %x, 0
+  %f.2 = icmp slt i4 %y, 0
+  %f.or = or i1 %f.1, %f.2
+  call void @use(i1 %f.or)
+  ret void
+
+exit:
+  %f.3 = icmp sge i4 %x, 0
+  %f.4 = icmp sge i4 %y, 0
+  %f.or.2 = or i1 %f.3, %f.4
+  call void @use(i1 %f.or.2)
+  ret void
+}
+
+define void @test_decompose_nested_bitwise_or(i4 %x, i4 %y, i4 %z) {
+; CHECK-LABEL: @test_decompose_nested_bitwise_or(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = or i4 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i4 [[TMP0]], [[Z:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = icmp slt i4 [[TMP1]], 0
+; CHECK-NEXT:    br i1 [[OR]], label [[BB1:%.*]], label [[EXIT:%.*]]
+; CHECK:       bb1:
+; CHECK-NEXT:    [[F_1:%.*]] = icmp slt i4 [[X]], 0
+; CHECK-NEXT:    [[F_2:%.*]] = icmp slt i4 [[Y]], 0
+; CHECK-NEXT:    [[F_3:%.*]] = icmp slt i4 [[Z]], 0
+; CHECK-NEXT:    [[F_OR:%.*]] = or i1 [[F_1]], [[F_2]]
+; CHECK-NEXT:    [[F_OR_2:%.*]] = or i1 [[F_OR]], [[F_3]]
+; CHECK-NEXT:    call void @use(i1 [[F_OR_2]])
+; CHECK-NEXT:    ret void
+; CHECK:       exit:
+; CHECK-NEXT:    [[F_4:%.*]] = icmp sge i4 [[X]], 0
+; CHECK-NEXT:    [[F_5:%.*]] = icmp sge i4 [[Y]], 0
+; CHECK-NEXT:    [[F_6:%.*]] = icmp sge i4 [[Z]], 0
+; CHECK-NEXT:    [[F_OR_3:%.*]] = or i1 [[F_4]], [[F_5]]
+; CHECK-NEXT:    [[F_OR_4:%.*]] = or i1 [[F_OR_3]], [[F_6]]
+; CHECK-NEXT:    call void @use(i1 [[F_OR_4]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %1 = or i4 %y, %x
+  %2 = or i4 %1, %z
+  %or = icmp slt i4 %2, 0
+  br i1 %or, label %bb1, label %exit
+
+bb1:
+  %f.1 = icmp slt i4 %x, 0
+  %f.2 = icmp slt i4 %y, 0
+  %f.3 = icmp slt i4 %z, 0
+  %f.or = or i1 %f.1, %f.2
+  %f.or.2 = or i1 %f.or, %f.3
+  call void @use(i1 %f.or.2)
+  ret void
+
+exit:
+  %f.4 = icmp sge i4 %x, 0
+  %f.5 = icmp sge i4 %y, 0
+  %f.6 = icmp sge i4 %z, 0
+  %f.or.3 = or i1 %f.4, %f.5
+  %f.or.4 = or i1 %f.or.3, %f.6
+  call void @use(i1 %f.or.4)
+  ret void
+}

>From 4cf9610f0bf04583db84dc690ab864736a0cc2d4 Mon Sep 17 00:00:00 2001
From: Lee <lee10202013 at gmail.com>
Date: Thu, 6 Feb 2025 13:31:07 -0700
Subject: [PATCH 2/2] Apply constraints

---
 llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 12 ++++++++++++
 llvm/test/Transforms/ConstraintElimination/and.ll    |  8 ++++----
 llvm/test/Transforms/ConstraintElimination/or.ll     |  8 ++++----
 3 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index e0861fbedc560aa..78252ffa7ec785d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -562,6 +562,18 @@ static Decomposition decompose(Value *V,
       }
     }
 
+    // (x | y) < 0 => (x < 0) || (y < 0)
+    if (match(V, m_Or(m_Value(Op0), m_Value(Op1)))) {
+      if (!isKnownNonNegative(Op0, DL) || !isKnownNonNegative(Op1, DL))
+        return MergeResults(Op0, Op1, IsSigned);
+    }
+
+    // (x & y) < 0 => (x < 0) && (y < 0)
+    if (match(V, m_And(m_Value(Op0), m_Value(Op1)))) {
+      if (!isKnownNonNegative(Op0, DL) && !isKnownNonNegative(Op1, DL))
+        return MergeResults(Op0, Op1, IsSigned);
+    }
+
     return {V, IsKnownNonNegative};
   }
 
diff --git a/llvm/test/Transforms/ConstraintElimination/and.ll b/llvm/test/Transforms/ConstraintElimination/and.ll
index 350d75160d4de77..9d89f8e5d372150 100644
--- a/llvm/test/Transforms/ConstraintElimination/and.ll
+++ b/llvm/test/Transforms/ConstraintElimination/and.ll
@@ -613,13 +613,13 @@ define void @test_decompose_bitwise_and(i4 %x, i4 %y) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp sge i4 [[X]], 0
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp sge i4 [[Y]], 0
-; CHECK-NEXT:    [[F_AND:%.*]] = and i1 [[F_1]], [[F_2]]
+; CHECK-NEXT:    [[F_AND:%.*]] = and i1 false, [[F_2]]
 ; CHECK-NEXT:    call void @use(i1 [[F_AND]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       exit:
 ; CHECK-NEXT:    [[F_3:%.*]] = icmp slt i4 [[X]], 0
 ; CHECK-NEXT:    [[F_4:%.*]] = icmp slt i4 [[Y]], 0
-; CHECK-NEXT:    [[F_AND_2:%.*]] = and i1 [[F_3]], [[F_4]]
+; CHECK-NEXT:    [[F_AND_2:%.*]] = and i1 false, [[F_4]]
 ; CHECK-NEXT:    call void @use(i1 [[F_AND_2]])
 ; CHECK-NEXT:    ret void
 ;
@@ -655,7 +655,7 @@ define void @test_decompose_nested_bitwise_and(i4 %x, i4 %y, i4 %z) {
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp sge i4 [[Y]], 0
 ; CHECK-NEXT:    [[F_3:%.*]] = icmp sge i4 [[Z]], 0
 ; CHECK-NEXT:    [[F_AND:%.*]] = and i1 [[F_1]], [[F_2]]
-; CHECK-NEXT:    [[F_AND_2:%.*]] = and i1 [[F_AND]], [[F_3]]
+; CHECK-NEXT:    [[F_AND_2:%.*]] = and i1 [[F_AND]], false
 ; CHECK-NEXT:    call void @use(i1 [[F_AND]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       exit:
@@ -663,7 +663,7 @@ define void @test_decompose_nested_bitwise_and(i4 %x, i4 %y, i4 %z) {
 ; CHECK-NEXT:    [[F_5:%.*]] = icmp slt i4 [[Y]], 0
 ; CHECK-NEXT:    [[F_6:%.*]] = icmp slt i4 [[Z]], 0
 ; CHECK-NEXT:    [[F_AND_3:%.*]] = and i1 [[F_4]], [[F_5]]
-; CHECK-NEXT:    [[F_AND_4:%.*]] = and i1 [[F_AND_3]], [[F_6]]
+; CHECK-NEXT:    [[F_AND_4:%.*]] = and i1 [[F_AND_3]], false
 ; CHECK-NEXT:    call void @use(i1 [[F_AND_4]])
 ; CHECK-NEXT:    ret void
 ;
diff --git a/llvm/test/Transforms/ConstraintElimination/or.ll b/llvm/test/Transforms/ConstraintElimination/or.ll
index ac0c02e2807f7ca..37fecb0348b3b1c 100644
--- a/llvm/test/Transforms/ConstraintElimination/or.ll
+++ b/llvm/test/Transforms/ConstraintElimination/or.ll
@@ -818,13 +818,13 @@ define void @test_decompose_bitwise_or(i4 %x, i4 %y) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp slt i4 [[X]], 0
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp slt i4 [[Y]], 0
-; CHECK-NEXT:    [[F_OR:%.*]] = or i1 [[F_1]], [[F_2]]
+; CHECK-NEXT:    [[F_OR:%.*]] = or i1 true, [[F_2]]
 ; CHECK-NEXT:    call void @use(i1 [[F_OR]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       exit:
 ; CHECK-NEXT:    [[F_3:%.*]] = icmp sge i4 [[X]], 0
 ; CHECK-NEXT:    [[F_4:%.*]] = icmp sge i4 [[Y]], 0
-; CHECK-NEXT:    [[F_OR_2:%.*]] = or i1 [[F_3]], [[F_4]]
+; CHECK-NEXT:    [[F_OR_2:%.*]] = or i1 true, [[F_4]]
 ; CHECK-NEXT:    call void @use(i1 [[F_OR_2]])
 ; CHECK-NEXT:    ret void
 ;
@@ -860,7 +860,7 @@ define void @test_decompose_nested_bitwise_or(i4 %x, i4 %y, i4 %z) {
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp slt i4 [[Y]], 0
 ; CHECK-NEXT:    [[F_3:%.*]] = icmp slt i4 [[Z]], 0
 ; CHECK-NEXT:    [[F_OR:%.*]] = or i1 [[F_1]], [[F_2]]
-; CHECK-NEXT:    [[F_OR_2:%.*]] = or i1 [[F_OR]], [[F_3]]
+; CHECK-NEXT:    [[F_OR_2:%.*]] = or i1 [[F_OR]], true
 ; CHECK-NEXT:    call void @use(i1 [[F_OR_2]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       exit:
@@ -868,7 +868,7 @@ define void @test_decompose_nested_bitwise_or(i4 %x, i4 %y, i4 %z) {
 ; CHECK-NEXT:    [[F_5:%.*]] = icmp sge i4 [[Y]], 0
 ; CHECK-NEXT:    [[F_6:%.*]] = icmp sge i4 [[Z]], 0
 ; CHECK-NEXT:    [[F_OR_3:%.*]] = or i1 [[F_4]], [[F_5]]
-; CHECK-NEXT:    [[F_OR_4:%.*]] = or i1 [[F_OR_3]], [[F_6]]
+; CHECK-NEXT:    [[F_OR_4:%.*]] = or i1 [[F_OR_3]], true
 ; CHECK-NEXT:    call void @use(i1 [[F_OR_4]])
 ; CHECK-NEXT:    ret void
 ;



More information about the llvm-commits mailing list