[llvm] [InstCombine] Bail out on inner disjoint or in `foldSelectICmpEq` (PR #121635)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 4 02:20:24 PST 2025
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/121635
It is tricky to remove the disjoint flag in the inner instruction. I believe these patterns with inner disjoint or are unlikely to exist in real-world cases.
Alive2: https://alive2.llvm.org/ce/z/hjyRk-
Closes https://github.com/llvm/llvm-project/issues/121583.
>From ee736a811a004c077b02aa94fe0092495f2c7f9c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 4 Jan 2025 17:50:36 +0800
Subject: [PATCH 1/4] [InstCombine] Add pre-commit tests. NFC.
---
llvm/test/Transforms/InstCombine/select.ll | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 0168a804239a89..55cf414cd1514f 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -4564,6 +4564,25 @@ define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
ret i32 %cond
}
+define i32 @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(i32 noundef %x, i32 noundef %y, i32 %c) {
+; CHECK-LABEL: @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[OR]], [[NOT]]
+; CHECK-NEXT: ret i32 [[AND1]]
+;
+entry:
+ %xor = xor i32 %y, %x
+ %cmp = icmp eq i32 %xor, %c
+ %and = and i32 %x, %y
+ %or = or disjoint i32 %y, %x
+ %not = xor i32 %c, -1
+ %and1 = and i32 %or, %not
+ %cond = select i1 %cmp, i32 %and, i32 %and1
+ ret i32 %cond
+}
+
; (X == C) ? X : Y -> (X == C) ? C : Y
; Fixed #77553
define i32 @src_select_xxory_eq0_xorxy_y(i32 %x, i32 %y) {
>From 3a704b6d5329a31a5288ea59b51de477af3aa949 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 4 Jan 2025 18:04:33 +0800
Subject: [PATCH 2/4] [InstCombine] Bail out on inner disjoint or in
`foldSelectICmpEq`
---
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 9 +++++----
llvm/test/Transforms/InstCombine/select.ll | 10 +++++++---
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index e7a8e947705f8d..cce353040b8009 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1853,12 +1853,13 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
XorOps = Instruction::Xor, NoOps = 0;
enum NotMask { None = 0, NotInner, NotRHS };
+ // We cannot refine TrueVal to FalseVal when the inner instruction contains
+ // disjoint or.
auto matchFalseVal = [&](unsigned OuterOpc, unsigned InnerOpc,
unsigned NotMask) {
- auto matchInner = m_c_BinOp(InnerOpc, m_Specific(X), m_Specific(Y));
- if (OuterOpc == NoOps)
- return match(CmpRHS, m_Zero()) && match(FalseVal, matchInner);
-
+ auto matchInner =
+ m_CombineAnd(m_c_BinOp(InnerOpc, m_Specific(X), m_Specific(Y)),
+ m_Unless(m_DisjointOr(m_Value(), m_Value())));
if (NotMask == NotInner) {
return match(FalseVal, m_c_BinOp(OuterOpc, m_NotForbidPoison(matchInner),
m_Specific(CmpRHS)));
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 55cf414cd1514f..c4e7e09b7e1f32 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -4567,10 +4567,14 @@ define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
define i32 @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(i32 noundef %x, i32 noundef %y, i32 %c) {
; CHECK-LABEL: @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[Y]], [[X]]
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C]], -1
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[OR]], [[NOT]]
-; CHECK-NEXT: ret i32 [[AND1]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[AND1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%xor = xor i32 %y, %x
>From 38c15e048429b7e94a35d4761a2aa381412a6e36 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 4 Jan 2025 18:08:02 +0800
Subject: [PATCH 3/4] cleanup
---
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index cce353040b8009..471ffa33bdfc02 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1850,7 +1850,7 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
return nullptr;
const unsigned AndOps = Instruction::And, OrOps = Instruction::Or,
- XorOps = Instruction::Xor, NoOps = 0;
+ XorOps = Instruction::Xor;
enum NotMask { None = 0, NotInner, NotRHS };
// We cannot refine TrueVal to FalseVal when the inner instruction contains
@@ -1860,16 +1860,13 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
auto matchInner =
m_CombineAnd(m_c_BinOp(InnerOpc, m_Specific(X), m_Specific(Y)),
m_Unless(m_DisjointOr(m_Value(), m_Value())));
- if (NotMask == NotInner) {
+ if (NotMask == NotInner)
return match(FalseVal, m_c_BinOp(OuterOpc, m_NotForbidPoison(matchInner),
m_Specific(CmpRHS)));
- } else if (NotMask == NotRHS) {
+ if (NotMask == NotRHS)
return match(FalseVal, m_c_BinOp(OuterOpc, matchInner,
m_NotForbidPoison(m_Specific(CmpRHS))));
- } else {
- return match(FalseVal,
- m_c_BinOp(OuterOpc, matchInner, m_Specific(CmpRHS)));
- }
+ return match(FalseVal, m_c_BinOp(OuterOpc, matchInner, m_Specific(CmpRHS)));
};
// (X&Y)==C ? X|Y : X^Y -> (X^Y)|C : X^Y or (X^Y)^ C : X^Y
>From 4e1b6db688d530a979d531f0cd046ee125e19e6e Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 4 Jan 2025 18:19:48 +0800
Subject: [PATCH 4/4] [InstCombine] Add more tests. NFC.
---
llvm/test/Transforms/InstCombine/select.ll | 57 +++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index c4e7e09b7e1f32..2ad67c80513a2d 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -4564,7 +4564,7 @@ define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
ret i32 %cond
}
-define i32 @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(i32 noundef %x, i32 noundef %y, i32 %c) {
+define i32 @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_no_trans_select_xor_eqc_and_disjoint_or_and_notc(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
@@ -4587,6 +4587,61 @@ entry:
ret i32 %cond
}
+define i32 @negative_inner_disjoint_or2(i32 %x, i32 %y, i32 %c) {
+; CHECK-LABEL: @negative_inner_disjoint_or2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND1:%.*]] = xor i32 [[OR]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[AND1]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+entry:
+ %xor = xor i32 %y, %x
+ %cmp = icmp eq i32 %xor, %c
+ %and = and i32 %x, %y
+ %or = or disjoint i32 %y, %x
+ %and1 = xor i32 %or, %c
+ %cond = select i1 %cmp, i32 %and, i32 %and1
+ ret i32 %cond
+}
+
+define i32 @positive_outer_disjoint_or1(i32 %x, i32 %y, i32 %c) {
+; CHECK-LABEL: @positive_outer_disjoint_or1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[AND:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[OR1:%.*]] = or disjoint i32 [[AND]], [[C:%.*]]
+; CHECK-NEXT: ret i32 [[OR1]]
+;
+entry:
+ %xor = and i32 %y, %x
+ %cmp = icmp eq i32 %xor, %c
+ %or = or i32 %y, %x
+ %and = xor i32 %y, %x
+ %or1 = or disjoint i32 %and, %c
+ %cond = select i1 %cmp, i32 %or, i32 %or1
+ ret i32 %cond
+}
+
+define i32 @positive_outer_disjoint_or2(i32 %x, i32 %y, i32 %c) {
+; CHECK-LABEL: @positive_outer_disjoint_or2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[OR1:%.*]] = or disjoint i32 [[AND]], [[C:%.*]]
+; CHECK-NEXT: ret i32 [[OR1]]
+;
+entry:
+ %xor = xor i32 %y, %x
+ %cmp = icmp eq i32 %xor, %c
+ %or = or i32 %y, %x
+ %and = and i32 %y, %x
+ %or1 = or disjoint i32 %and, %c
+ %cond = select i1 %cmp, i32 %or, i32 %or1
+ ret i32 %cond
+}
+
; (X == C) ? X : Y -> (X == C) ? C : Y
; Fixed #77553
define i32 @src_select_xxory_eq0_xorxy_y(i32 %x, i32 %y) {
More information about the llvm-commits
mailing list