[llvm] goldsteinn/select and eq 0 (PR #121841)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 6 13:31:19 PST 2025


https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/121841

- **[InstCombine] Add tests for folding `(select (icmp eq (and x, y), 0), (add/xor x, y), F)`; NFC**
- **[InstCombine] Fold `(select (icmp eq (and x, y), 0), (add/xor x, y), F)`**


>From 9423bd0aa1db7af813eae1edb7a8c9b5ac1fd931 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Mon, 6 Jan 2025 14:52:15 -0600
Subject: [PATCH 1/2] [InstCombine] Add tests for folding `(select (icmp eq
 (and x, y), 0), (add/xor x, y), F)`; NFC

---
 llvm/test/Transforms/InstCombine/select.ll | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 9de3c2483ba49c..48824d6b38bf24 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -5,6 +5,9 @@
 
 target datalayout = "e-p:64:64-p1:16:16-p2:32:32:32-p3:64:64:64"
 
+declare void @use.i1(i1)
+declare void @use.i32(i32)
+
 define i1 @test5(i1 %C) {
 ; CHECK-LABEL: @test5(
 ; CHECK-NEXT:    [[NOT_C:%.*]] = xor i1 [[C:%.*]], true
@@ -4436,6 +4439,40 @@ define i32 @src_no_trans_select_and_eq0_xor_and(i32 %x, i32 %y) {
   ret i32 %cond
 }
 
+define i32 @src_no_trans_select_and_eq0_xor_and_fail_multiuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_no_trans_select_and_eq0_xor_and_fail_multiuse(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[AND0:%.*]] = icmp eq i32 [[AND]], 0
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT:    call void @use.i32(i32 [[XOR]])
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[AND0]], i32 [[XOR]], i32 [[AND]]
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %and = and i32 %x, %y
+  %and0 = icmp eq i32 %and, 0
+  %xor = xor i32 %x, %y
+  call void @use.i32(i32 %xor)
+  %cond = select i1 %and0, i32 %xor, i32 %and
+  ret i32 %cond
+}
+
+define i32 @src_no_trans_select_and_eq0_add(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @src_no_trans_select_and_eq0_add(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[AND0:%.*]] = icmp ne i32 [[AND]], 0
+; CHECK-NEXT:    call void @use.i1(i1 [[AND0]])
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[AND0]], i32 [[Z:%.*]], i32 [[ADD]]
+; CHECK-NEXT:    ret i32 [[COND]]
+;
+  %and = and i32 %x, %y
+  %and0 = icmp ne i32 %and, 0
+  call void @use.i1(i1 %and0)
+  %add = add i32 %x, %y
+  %cond = select i1 %and0, i32 %z, i32 %add
+  ret i32 %cond
+}
+
 define i32 @src_no_trans_select_or_eq0_or_and(i32 %x, i32 %y) {
 ; CHECK-LABEL: @src_no_trans_select_or_eq0_or_and(
 ; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]

>From ed6e432d6ffc6cd3876be9cebbab2fff61a209f3 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Mon, 6 Jan 2025 14:49:53 -0600
Subject: [PATCH 2/2] [InstCombine] Fold `(select (icmp eq (and x, y), 0),
 (add/xor x, y), F)`

In the context of `(icmp eq (and x, y), 0)` we can replace `add`/`xor`
with `or`:
https://alive2.llvm.org/ce/z/R7CQp3
---
 .../InstCombine/InstCombineSelect.cpp         | 26 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/select.ll    | 12 +++------
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7fd91c72a2fb0e..5ec98d937327d3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -4395,5 +4395,31 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
       return replaceOperand(SI, 2, ConstantInt::get(FalseVal->getType(), 0));
   }
 
+  {
+    // (select (icmp eq (and X, Y), 0), (add/xor X, Y), F)
+    //	-> (select (icmp eq (and X, Y), 0), (or X, Y), F)
+    // And vice versa for `ne` pred.
+    CmpPredicate Pred;
+    Value *X, *Y;
+    if (match(CondVal, m_ICmp(Pred, m_And(m_Value(X), m_Value(Y)), m_Zero())) &&
+        ICmpInst::isEquality(Pred)) {
+      unsigned RepIdx;
+      Value *RepArm;
+      if (Pred == CmpInst::ICMP_EQ) {
+        RepIdx = 1;
+        RepArm = TrueVal;
+      } else {
+        RepIdx = 2;
+        RepArm = FalseVal;
+      }
+      auto ReduceToOrNoCommonBits =
+          m_CombineOr(m_c_Xor(m_Specific(X), m_Specific(Y)),
+                      m_c_Add(m_Specific(X), m_Specific(Y)));
+
+      if (RepArm->hasOneUse() && match(RepArm, ReduceToOrNoCommonBits))
+        return replaceOperand(SI, RepIdx, Builder.CreateOr(X, Y));
+    }
+  }
+
   return nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 48824d6b38bf24..267306de1f791c 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3787,12 +3787,8 @@ entry:
 define i32 @src_and_eq_0_xor_or(i32 %x, i32 %y) {
 ; CHECK-LABEL: @src_and_eq_0_xor_or(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT:    [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT:    ret i32 [[COND]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
 ;
 entry:
   %and = and i32 %y, %x
@@ -4428,7 +4424,7 @@ define i32 @src_no_trans_select_and_eq0_xor_and(i32 %x, i32 %y) {
 ; CHECK-LABEL: @src_no_trans_select_and_eq0_xor_and(
 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    [[AND0:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[XOR:%.*]] = or i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[COND:%.*]] = select i1 [[AND0]], i32 [[XOR]], i32 [[AND]]
 ; CHECK-NEXT:    ret i32 [[COND]]
 ;
@@ -4461,7 +4457,7 @@ define i32 @src_no_trans_select_and_eq0_add(i32 %x, i32 %y, i32 %z) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    [[AND0:%.*]] = icmp ne i32 [[AND]], 0
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND0]])
-; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[X]], [[Y]]
+; CHECK-NEXT:    [[ADD:%.*]] = or i32 [[X]], [[Y]]
 ; CHECK-NEXT:    [[COND:%.*]] = select i1 [[AND0]], i32 [[Z:%.*]], i32 [[ADD]]
 ; CHECK-NEXT:    ret i32 [[COND]]
 ;



More information about the llvm-commits mailing list