From ee736a811a004c077b02aa94fe0092495f2c7f9c Mon Sep 17 00:00:00 2001 From: Yingwei Zheng 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 0168a804239a8..55cf414cd1514 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 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 e7a8e947705f8..cce353040b800 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 55cf414cd1514..c4e7e09b7e1f3 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 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 cce353040b800..471ffa33bdfc0 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 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 c4e7e09b7e1f3..2ad67c80513a2 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) {