summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-01-04 06:03:59 +0000
committerChris Lattner <sabre@nondot.org>2010-01-04 06:03:59 +0000
commite4412c1f0b636980d77a518b76e94559830eeaed (patch)
treec9a87c184827577f46b5ab6a46bea23b70ee068b
parentd0592d3be68e60a77c0bb98ad4861648e16e467c (diff)
downloadllvm-e4412c1f0b636980d77a518b76e94559830eeaed.tar.gz
llvm-e4412c1f0b636980d77a518b76e94559830eeaed.tar.bz2
llvm-e4412c1f0b636980d77a518b76e94559830eeaed.tar.xz
implement an instcombine xform needed by clang's codegen
on the example in PR4216. This doesn't trigger in the testsuite, so I'd really appreciate someone scrutinizing the logic for correctness. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@92458 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Target/README.txt13
-rw-r--r--lib/Transforms/Scalar/InstructionCombining.cpp20
-rw-r--r--test/Transforms/InstCombine/or.ll13
3 files changed, 32 insertions, 14 deletions
diff --git a/lib/Target/README.txt b/lib/Target/README.txt
index a6e05fadef..22dadfeb3d 100644
--- a/lib/Target/README.txt
+++ b/lib/Target/README.txt
@@ -282,19 +282,6 @@ this requires TBAA.
//===---------------------------------------------------------------------===//
-This should be optimized to one 'and' and one 'or', from PR4216:
-
-define i32 @test_bitfield(i32 %bf.prev.low) nounwind ssp {
-entry:
- %bf.prev.lo.cleared10 = or i32 %bf.prev.low, 32962 ; <i32> [#uses=1]
- %0 = and i32 %bf.prev.low, -65536 ; <i32> [#uses=1]
- %1 = and i32 %bf.prev.lo.cleared10, 40186 ; <i32> [#uses=1]
- %2 = or i32 %1, %0 ; <i32> [#uses=1]
- ret i32 %2
-}
-
-//===---------------------------------------------------------------------===//
-
This isn't recognized as bswap by instcombine (yes, it really is bswap):
unsigned long reverse(unsigned v) {
diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp
index 363d8798f3..03885a5e05 100644
--- a/lib/Transforms/Scalar/InstructionCombining.cpp
+++ b/lib/Transforms/Scalar/InstructionCombining.cpp
@@ -5213,12 +5213,30 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
return ReplaceInstUsesWith(I, B);
}
}
- V1 = 0; V2 = 0; V3 = 0;
+
+ // ((V | N) & C1) | (V & C2) --> (V|N) & (C1|C2)
+ // iff (C1&C2) == 0 and (N&~C1) == 0
+ if ((C1->getValue() & C2->getValue()) == 0) {
+ if (match(A, m_Or(m_Value(V1), m_Value(V2))) &&
+ ((V1 == B && MaskedValueIsZero(V2, ~C1->getValue())) || // (V|N)
+ (V2 == B && MaskedValueIsZero(V1, ~C1->getValue())))) // (N|V)
+ return BinaryOperator::CreateAnd(A,
+ ConstantInt::get(A->getContext(),
+ C1->getValue()|C2->getValue()));
+ // Or commutes, try both ways.
+ if (match(B, m_Or(m_Value(V1), m_Value(V2))) &&
+ ((V1 == A && MaskedValueIsZero(V2, ~C2->getValue())) || // (V|N)
+ (V2 == A && MaskedValueIsZero(V1, ~C2->getValue())))) // (N|V)
+ return BinaryOperator::CreateAnd(B,
+ ConstantInt::get(B->getContext(),
+ C1->getValue()|C2->getValue()));
+ }
}
// Check to see if we have any common things being and'ed. If so, find the
// terms for V1 & (V2|V3).
if (isOnlyUse(Op0) || isOnlyUse(Op1)) {
+ V1 = 0;
if (A == B) // (A & C)|(A & D) == A & (C|D)
V1 = A, V2 = C, V3 = D;
else if (A == D) // (A & C)|(B & A) == A & (B|C)
diff --git a/test/Transforms/InstCombine/or.ll b/test/Transforms/InstCombine/or.ll
index 44228ba357..822dfb3d55 100644
--- a/test/Transforms/InstCombine/or.ll
+++ b/test/Transforms/InstCombine/or.ll
@@ -307,3 +307,16 @@ define i1 @test29(i32* %A, i32* %B) {
; CHECK: ret i1
}
+; PR4216
+define i32 @test30(i32 %A) {
+entry:
+ %B = or i32 %A, 32962
+ %C = and i32 %A, -65536
+ %D = and i32 %B, 40186
+ %E = or i32 %D, %C
+ ret i32 %E
+; CHECK: @test30
+; CHECK: %B = or i32 %A, 32962
+; CHECK: %E = and i32 %B, -25350
+; CHECK: ret i32 %E
+}