From 66a7442059bc9e9c6ab22c2bbbde304a07260e68 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Sun, 30 Nov 2008 13:52:49 +0000 Subject: [PATCH] Add instruction combining for ((A&~B)|(~A&B)) -> A^B and all permutations. llvm-svn: 60291 --- lib/Target/README.txt | 6 --- .../Scalar/InstructionCombining.cpp | 23 ++++++++++ test/Transforms/InstCombine/or-to-xor.ll | 42 +++++++++++++++++++ 3 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 test/Transforms/InstCombine/or-to-xor.ll diff --git a/lib/Target/README.txt b/lib/Target/README.txt index bf7c0b14475..17b830d5d4a 100644 --- a/lib/Target/README.txt +++ b/lib/Target/README.txt @@ -1171,12 +1171,6 @@ Should combine to "a | 1". Currently not optimized with "clang //===---------------------------------------------------------------------===// -int a(int a, int b, int c) {return ((a&~b) | (~a&b));} -Should fold to xor. Currently not optimized with "clang -emit-llvm-bc -| opt -std-compile-opts". - -//===---------------------------------------------------------------------===// - int a(int a, int b, int c) {return (~a & c) | ((c|a) & b);} Should fold to "(~a & c) | (a & b)". Currently not optimized with "clang -emit-llvm-bc | opt -std-compile-opts". diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index ace3ff80d4f..c79bf9c7523 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -4638,6 +4638,29 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { return Match; if (Instruction *Match = MatchSelectFromAndOr(D, A, B, C)) return Match; + + V1 = V2 = 0; + + // ((A&~B)|(~A&B)) -> A^B + if ((match(C, m_Not(m_Value(V1))) && + match(B, m_Not(m_Value(V2))))) + if (V1 == D && V2 == A) + return BinaryOperator::CreateXor(V1, V2); + // ((~B&A)|(~A&B)) -> A^B + if ((match(A, m_Not(m_Value(V1))) && + match(B, m_Not(m_Value(V2))))) + if (V1 == D && V2 == C) + return BinaryOperator::CreateXor(V1, V2); + // ((A&~B)|(B&~A)) -> A^B + if ((match(C, m_Not(m_Value(V1))) && + match(D, m_Not(m_Value(V2))))) + if (V1 == B && V2 == A) + return BinaryOperator::CreateXor(V1, V2); + // ((~B&A)|(B&~A)) -> A^B + if ((match(A, m_Not(m_Value(V1))) && + match(D, m_Not(m_Value(V2))))) + if (V1 == B && V2 == C) + return BinaryOperator::CreateXor(V1, V2); } // (X >> Z) | (Y >> Z) -> (X|Y) >> Z for all shifts. diff --git a/test/Transforms/InstCombine/or-to-xor.ll b/test/Transforms/InstCombine/or-to-xor.ll new file mode 100644 index 00000000000..f403412bd5c --- /dev/null +++ b/test/Transforms/InstCombine/or-to-xor.ll @@ -0,0 +1,42 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep {xor i32 %b, %a} | count 4 +; RUN: llvm-as < %s | opt -instcombine | llvm-dis | not grep {and} + +define i32 @func1(i32 %a, i32 %b) nounwind readnone { +entry: + %b_not = xor i32 %b, -1 + %0 = and i32 %a, %b_not + %a_not = xor i32 %a, -1 + %1 = and i32 %a_not, %b + %2 = or i32 %0, %1 + ret i32 %2 +} + +define i32 @func2(i32 %a, i32 %b) nounwind readnone { +entry: + %b_not = xor i32 %b, -1 + %0 = and i32 %b_not, %a + %a_not = xor i32 %a, -1 + %1 = and i32 %a_not, %b + %2 = or i32 %0, %1 + ret i32 %2 +} + +define i32 @func3(i32 %a, i32 %b) nounwind readnone { +entry: + %b_not = xor i32 %b, -1 + %0 = and i32 %a, %b_not + %a_not = xor i32 %a, -1 + %1 = and i32 %b, %a_not + %2 = or i32 %0, %1 + ret i32 %2 +} + +define i32 @func4(i32 %a, i32 %b) nounwind readnone { +entry: + %b_not = xor i32 %b, -1 + %0 = and i32 %b_not, %a + %a_not = xor i32 %a, -1 + %1 = and i32 %b, %a_not + %2 = or i32 %0, %1 + ret i32 %2 +}