From 2265d01f2a5bd153959701e22f5be2a40e1674a3 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Mon, 3 Aug 2020 08:11:06 -0400 Subject: [PATCH] [InstCombine] reduce xor-of-or's bitwise logic (PR46955) I tried to use m_Deferred() on this, but didn't find a clean way to do that. http://bugs.llvm.org/PR46955 https://alive2.llvm.org/ce/z/2h6QTq --- .../Transforms/InstCombine/InstCombineAndOrXor.cpp | 14 +++++++++++++ llvm/test/Transforms/InstCombine/xor.ll | 24 +++++++++++----------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 030d2f2..ef1e8db 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3351,6 +3351,20 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { match(Op1, m_Not(m_Specific(A)))) return BinaryOperator::CreateNot(Builder.CreateAnd(A, B)); + // (A | B) ^ (A | C) --> (B ^ C) & ~A -- There are 4 commuted variants. + // TODO: Loosen one-use restriction if common operand is a constant. + Value *D; + if (match(Op0, m_OneUse(m_Or(m_Value(A), m_Value(B)))) && + match(Op1, m_OneUse(m_Or(m_Value(C), m_Value(D))))) { + if (B == C || B == D) + std::swap(A, B); + if (A == C) + std::swap(C, D); + if (A == D) + return BinaryOperator::CreateAnd(Builder.CreateXor(B, C), + Builder.CreateNot(A)); + } + if (auto *LHS = dyn_cast(I.getOperand(0))) if (auto *RHS = dyn_cast(I.getOperand(1))) if (Value *V = foldXorOfICmps(LHS, RHS, I)) diff --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll index a133f2a..2bdb837 100644 --- a/llvm/test/Transforms/InstCombine/xor.ll +++ b/llvm/test/Transforms/InstCombine/xor.ll @@ -915,9 +915,9 @@ define <2 x i32> @test51vec(<2 x i32> %x, <2 x i32> %y) { define i4 @or_or_xor(i4 %x, i4 %y, i4 %z) { ; CHECK-LABEL: @or_or_xor( -; CHECK-NEXT: [[O1:%.*]] = or i4 [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[O2:%.*]] = or i4 [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = xor i4 [[O1]], [[O2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i4 [[Z:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = and i4 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i4 [[R]] ; %o1 = or i4 %z, %x @@ -928,9 +928,9 @@ define i4 @or_or_xor(i4 %x, i4 %y, i4 %z) { define i4 @or_or_xor_commute1(i4 %x, i4 %y, i4 %z) { ; CHECK-LABEL: @or_or_xor_commute1( -; CHECK-NEXT: [[O1:%.*]] = or i4 [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[O2:%.*]] = or i4 [[Z]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = xor i4 [[O1]], [[O2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i4 [[Z:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = and i4 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i4 [[R]] ; %o1 = or i4 %x, %z @@ -941,9 +941,9 @@ define i4 @or_or_xor_commute1(i4 %x, i4 %y, i4 %z) { define i4 @or_or_xor_commute2(i4 %x, i4 %y, i4 %z) { ; CHECK-LABEL: @or_or_xor_commute2( -; CHECK-NEXT: [[O1:%.*]] = or i4 [[Z:%.*]], [[X:%.*]] -; CHECK-NEXT: [[O2:%.*]] = or i4 [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[R:%.*]] = xor i4 [[O1]], [[O2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor i4 [[Z:%.*]], -1 +; CHECK-NEXT: [[R:%.*]] = and i4 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i4 [[R]] ; %o1 = or i4 %z, %x @@ -954,9 +954,9 @@ define i4 @or_or_xor_commute2(i4 %x, i4 %y, i4 %z) { define <2 x i4> @or_or_xor_commute3(<2 x i4> %x, <2 x i4> %y, <2 x i4> %z) { ; CHECK-LABEL: @or_or_xor_commute3( -; CHECK-NEXT: [[O1:%.*]] = or <2 x i4> [[X:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[O2:%.*]] = or <2 x i4> [[Y:%.*]], [[Z]] -; CHECK-NEXT: [[R:%.*]] = xor <2 x i4> [[O1]], [[O2]] +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i4> [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i4> [[Z:%.*]], +; CHECK-NEXT: [[R:%.*]] = and <2 x i4> [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret <2 x i4> [[R]] ; %o1 = or <2 x i4> %x, %z -- 2.7.4