aboutsummaryrefslogtreecommitdiffstats
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)
downloadexternal_llvm-e4412c1f0b636980d77a518b76e94559830eeaed.zip
external_llvm-e4412c1f0b636980d77a518b76e94559830eeaed.tar.gz
external_llvm-e4412c1f0b636980d77a518b76e94559830eeaed.tar.bz2
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 a6e05fa..22dadfe 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 363d879..03885a5 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 44228ba..822dfb3 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
+}