From d85505a9323aadcfd3a34e9ba2e088a0d670b6bd Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 13 Oct 2022 15:37:28 -0400 Subject: [PATCH] [InstCombine] fold logical and/or to xor (A | B) & ~(A & B) --> A ^ B https://alive2.llvm.org/ce/z/qpFMns We already have the equivalent fold for real logic instructions, but this pattern may occur with selects too. This is part of solving issue #58313. --- .../Transforms/InstCombine/InstCombineSelect.cpp | 5 +++++ .../test/Transforms/InstCombine/logical-select.ll | 15 ++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 58c628abecd6..6ade18f898a7 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2774,6 +2774,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { match(TrueVal, m_Specific(B)) && match(FalseVal, m_Zero())) return replaceOperand(SI, 0, A); + // ~(A & B) & (A | B) --> A ^ B + if (match(&SI, m_c_LogicalAnd(m_Not(m_LogicalAnd(m_Value(A), m_Value(B))), + m_c_LogicalOr(m_Deferred(A), m_Deferred(B))))) + return BinaryOperator::CreateXor(A, B); + Value *C; // select (~a | c), a, b -> and a, (or c, freeze(b)) if (match(CondVal, m_c_Or(m_Not(m_Specific(TrueVal)), m_Value(C))) && diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll index 1276501f59d9..8fe517ad4145 100644 --- a/llvm/test/Transforms/InstCombine/logical-select.ll +++ b/llvm/test/Transforms/InstCombine/logical-select.ll @@ -932,10 +932,7 @@ define i8 @sext_cond_extra_uses(i1 %cmp, i8 %a, i8 %b) { define i1 @xor_commute0(i1 %x, i1 %y) { ; CHECK-LABEL: @xor_commute0( -; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false -; CHECK-NEXT: [[OR:%.*]] = select i1 [[X]], i1 true, i1 [[Y]] -; CHECK-NEXT: [[NAND:%.*]] = xor i1 [[AND]], true -; CHECK-NEXT: [[AND2:%.*]] = select i1 [[NAND]], i1 [[OR]], i1 false +; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[AND2]] ; %and = select i1 %x, i1 %y, i1 false @@ -948,10 +945,9 @@ define i1 @xor_commute0(i1 %x, i1 %y) { define i1 @xor_commute1(i1 %x, i1 %y) { ; CHECK-LABEL: @xor_commute1( ; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[Y:%.*]], i1 false -; CHECK-NEXT: [[OR:%.*]] = select i1 [[Y]], i1 true, i1 [[X]] ; CHECK-NEXT: [[NAND:%.*]] = xor i1 [[AND]], true ; CHECK-NEXT: call void @use1(i1 [[NAND]]) -; CHECK-NEXT: [[AND2:%.*]] = select i1 [[NAND]], i1 [[OR]], i1 false +; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[AND2]] ; %and = select i1 %x, i1 %y, i1 false @@ -970,7 +966,7 @@ define i1 @xor_commute2(i1 %x, i1 %y) { ; CHECK-NEXT: call void @use1(i1 [[OR]]) ; CHECK-NEXT: [[NAND:%.*]] = xor i1 [[AND]], true ; CHECK-NEXT: call void @use1(i1 [[NAND]]) -; CHECK-NEXT: [[AND2:%.*]] = select i1 [[OR]], i1 [[NAND]], i1 false +; CHECK-NEXT: [[AND2:%.*]] = xor i1 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[AND2]] ; %and = select i1 %x, i1 %y, i1 false @@ -985,10 +981,7 @@ define i1 @xor_commute2(i1 %x, i1 %y) { define <2 x i1> @xor_commute3(<2 x i1> %x, <2 x i1> %y) { ; CHECK-LABEL: @xor_commute3( -; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[X:%.*]], <2 x i1> [[Y:%.*]], <2 x i1> zeroinitializer -; CHECK-NEXT: [[OR:%.*]] = select <2 x i1> [[Y]], <2 x i1> , <2 x i1> [[X]] -; CHECK-NEXT: [[NAND:%.*]] = xor <2 x i1> [[AND]], -; CHECK-NEXT: [[AND2:%.*]] = select <2 x i1> [[OR]], <2 x i1> [[NAND]], <2 x i1> zeroinitializer +; CHECK-NEXT: [[AND2:%.*]] = xor <2 x i1> [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: ret <2 x i1> [[AND2]] ; %and = select <2 x i1> %x, <2 x i1> %y, <2 x i1>