summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCraig Topper <craig.topper@gmail.com>2017-04-25 17:01:32 +0000
committerCraig Topper <craig.topper@gmail.com>2017-04-25 17:01:32 +0000
commit0b650d35698d7a80352f3f4a67289b8b47df4726 (patch)
treeb456b2b1ec7a19b3de4feb063bd72c38977be156
parent3c0ede7f7aa201a1f4910f097682a796451d344b (diff)
downloadbcm5719-llvm-0b650d35698d7a80352f3f4a67289b8b47df4726.tar.gz
bcm5719-llvm-0b650d35698d7a80352f3f4a67289b8b47df4726.zip
[InstSimplify] Handle (~A & ~B) | (~A ^ B) -> ~A ^ B
The code Sanjay Patel moved over from InstCombine doesn't work properly if the 'and' has both inputs as nots because we used a commuted op matcher on the 'and' first. But this will bind to the first 'not' on 'and' when there could be two 'not's. InstCombine could rely on DeMorgan to ensure the 'and' wouldn't have two 'not's eventually, but InstSimplify can't rely on that. This patch matches the xor first then checks for the ands and allows a not of either operand of the xor. Differential Revision: https://reviews.llvm.org/D32458 llvm-svn: 301329
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp14
-rw-r--r--llvm/test/Transforms/InstSimplify/AndOrXor.ll62
2 files changed, 72 insertions, 4 deletions
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index be9beebe189..febaf302ef3 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -1886,15 +1886,21 @@ static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
// (A & ~B) | (A ^ B) -> (A ^ B)
// (~B & A) | (A ^ B) -> (A ^ B)
- if (match(Op0, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
- match(Op1, m_Xor(m_Specific(A), m_Specific(B))))
+ // (A & ~B) | (B ^ A) -> (B ^ A)
+ // (~B & A) | (B ^ A) -> (B ^ A)
+ if (match(Op1, m_Xor(m_Value(A), m_Value(B))) &&
+ (match(Op0, m_c_And(m_Specific(A), m_Not(m_Specific(B)))) ||
+ match(Op0, m_c_And(m_Not(m_Specific(A)), m_Specific(B)))))
return Op1;
// Commute the 'or' operands.
// (A ^ B) | (A & ~B) -> (A ^ B)
// (A ^ B) | (~B & A) -> (A ^ B)
- if (match(Op1, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
- match(Op0, m_Xor(m_Specific(A), m_Specific(B))))
+ // (B ^ A) | (A & ~B) -> (B ^ A)
+ // (B ^ A) | (~B & A) -> (B ^ A)
+ if (match(Op0, m_Xor(m_Value(A), m_Value(B))) &&
+ (match(Op1, m_c_And(m_Specific(A), m_Not(m_Specific(B)))) ||
+ match(Op1, m_c_And(m_Not(m_Specific(A)), m_Specific(B)))))
return Op0;
if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {
diff --git a/llvm/test/Transforms/InstSimplify/AndOrXor.ll b/llvm/test/Transforms/InstSimplify/AndOrXor.ll
index 5292732842b..c5108217056 100644
--- a/llvm/test/Transforms/InstSimplify/AndOrXor.ll
+++ b/llvm/test/Transforms/InstSimplify/AndOrXor.ll
@@ -521,3 +521,65 @@ define i32 @test44_commuted_and(i32 %a, i32 %b) {
ret i32 %or
}
+; (~A & ~B) | (~A ^ B) -> ~A ^ B
+
+define i32 @test45(i32 %a, i32 %b) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT: ret i32 [[XOR]]
+;
+ %nega = xor i32 %a, -1
+ %negb = xor i32 %b, -1
+ %and = and i32 %nega, %negb
+ %xor = xor i32 %a, %negb
+ %or = or i32 %and, %xor
+ ret i32 %or
+}
+
+define i32 @test45_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT: ret i32 [[XOR]]
+;
+ %nega = xor i32 %a, -1
+ %negb = xor i32 %b, -1
+ %and = and i32 %negb, %nega
+ %xor = xor i32 %a, %negb
+ %or = or i32 %and, %xor
+ ret i32 %or
+}
+
+; Commute operands of the 'or'.
+; (~A ^ B) | (~A & ~B) -> ~A ^ B
+
+define i32 @test46(i32 %a, i32 %b) {
+; CHECK-LABEL: @test46(
+; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT: ret i32 [[XOR]]
+;
+ %nega = xor i32 %a, -1
+ %negb = xor i32 %b, -1
+ %and = and i32 %nega, %negb
+ %xor = xor i32 %a, %negb
+ %or = or i32 %xor, %and
+ ret i32 %or
+}
+
+; (~A & ~B) | (~A ^ B) -> ~A ^ B
+
+define i32 @test46_commuted_and(i32 %a, i32 %b) {
+; CHECK-LABEL: @test45(
+; CHECK-NEXT: [[NEGB:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[A:%.*]], [[NEGB]]
+; CHECK-NEXT: ret i32 [[XOR]]
+;
+ %nega = xor i32 %a, -1
+ %negb = xor i32 %b, -1
+ %and = and i32 %negb, %nega
+ %xor = xor i32 %a, %negb
+ %or = or i32 %xor, %and
+ ret i32 %or
+}
OpenPOWER on IntegriCloud