Invert and-of-or into or-of-and when doing so would allow us to clear bits of the and's mask.

This can result in increased opportunities for store narrowing in code generation.  Update a number of
tests for this change.  This fixes <rdar://problem/8285027>.

Additionally, because this inverts the order of ors and ands, some patterns for optimizing or-of-and-of-or
no longer fire in instances where they did originally.  Add a simple transform which recaptures most of these
opportunities: if we have an or-of-constant-or and have failed to fold away the inner or, commute the order 
of the two ors, to give the non-constant or a chance for simplification instead.

llvm-svn: 113679
This commit is contained in:
Owen Anderson 2010-09-11 05:48:06 +00:00
parent bcf2cfbdc5
commit 70f4524427
5 changed files with 69 additions and 22 deletions

View File

@ -207,12 +207,26 @@ Instruction *InstCombiner::OptAndOp(Instruction *Op,
}
break;
case Instruction::Or:
if (Op->hasOneUse() && Together != OpRHS) {
// (X | C1) & C2 --> (X | (C1&C2)) & C2
Value *Or = Builder->CreateOr(X, Together);
Or->takeName(Op);
return BinaryOperator::CreateAnd(Or, AndRHS);
if (Op->hasOneUse()){
if (Together != OpRHS) {
// (X | C1) & C2 --> (X | (C1&C2)) & C2
Value *Or = Builder->CreateOr(X, Together);
Or->takeName(Op);
return BinaryOperator::CreateAnd(Or, AndRHS);
}
ConstantInt *TogetherCI = dyn_cast<ConstantInt>(Together);
if (TogetherCI && !TogetherCI->isZero()){
// (X | C1) & C2 --> (X & (C2^(C1&C2))) | C1
// NOTE: This reduces the number of bits set in the & mask, which
// can expose opportunities for store narrowing.
Together = ConstantExpr::getXor(AndRHS, Together);
Value *And = Builder->CreateAnd(X, Together);
And->takeName(Op);
return BinaryOperator::CreateOr(And, OpRHS);
}
}
break;
case Instruction::Add:
if (Op->hasOneUse()) {
@ -1943,6 +1957,17 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) {
}
}
// Note: If we've gotten to the point of visiting the outer OR, then the
// inner one couldn't be simplified. If it was a constant, then it won't
// be simplified by a later pass either, so we try swapping the inner/outer
// ORs in the hopes that we'll be able to simplify it this way.
// (X|C) | V --> (X|V) | C
if (Op0->hasOneUse() && match(Op0, m_Or(m_Value(A), m_ConstantInt(C1)))) {
Value *Inner = Builder->CreateOr(Op0, Op1);
Inner->takeName(Op0);
return BinaryOperator::CreateOr(Inner, C1);
}
return Changed ? &I : 0;
}

View File

@ -0,0 +1,13 @@
; RUN: opt -S -instcombine < %s | FileCheck %s
; <rdar://problem/8285027>
; CHECK: @func
define i32 @func(i32 %a) nounwind ssp align 2 {
entry:
; CHECK: and i32 %a, -256
%0 = or i32 %a, 8
; CHECK: or i32 %0, 8
%1 = and i32 %0, -248
ret i32 %1
; CHECK: }
}

View File

@ -437,8 +437,8 @@ define i64 @test47(i8 %A) {
ret i64 %E
; CHECK: @test47
; CHECK-NEXT: %B = sext i8 %A to i64
; CHECK-NEXT: %C = or i64 %B, 42
; CHECK-NEXT: %E = and i64 %C, 4294967295
; CHECK-NEXT: %C = and i64 %B, 4294967253
; CHECK-NEXT: %E = or i64 %C, 42
; CHECK-NEXT: ret i64 %E
}
@ -508,8 +508,8 @@ define i32 @test52(i64 %A) {
ret i32 %E
; CHECK: @test52
; CHECK-NEXT: %B = trunc i64 %A to i32
; CHECK-NEXT: %C = or i32 %B, 32962
; CHECK-NEXT: %D = and i32 %C, 40186
; CHECK-NEXT: %C = and i32 %B, 7224
; CHECK-NEXT: %D = or i32 %C, 32962
; CHECK-NEXT: ret i32 %D
}
@ -521,8 +521,8 @@ define i64 @test53(i32 %A) {
ret i64 %E
; CHECK: @test53
; CHECK-NEXT: %B = zext i32 %A to i64
; CHECK-NEXT: %C = or i64 %B, 32962
; CHECK-NEXT: %D = and i64 %C, 40186
; CHECK-NEXT: %C = and i64 %B, 7224
; CHECK-NEXT: %D = or i64 %C, 32962
; CHECK-NEXT: ret i64 %D
}
@ -534,8 +534,8 @@ define i32 @test54(i64 %A) {
ret i32 %E
; CHECK: @test54
; CHECK-NEXT: %B = trunc i64 %A to i32
; CHECK-NEXT: %C = or i32 %B, -32574
; CHECK-NEXT: %D = and i32 %C, -25350
; CHECK-NEXT: %C = and i32 %B, 7224
; CHECK-NEXT: %D = or i32 %C, -32574
; CHECK-NEXT: ret i32 %D
}
@ -547,8 +547,8 @@ define i64 @test55(i32 %A) {
ret i64 %E
; CHECK: @test55
; CHECK-NEXT: %B = zext i32 %A to i64
; CHECK-NEXT: %C = or i64 %B, -32574
; CHECK-NEXT: %D = and i64 %C, -25350
; CHECK-NEXT: %C = and i64 %B, 7224
; CHECK-NEXT: %D = or i64 %C, -32574
; CHECK-NEXT: ret i64 %D
}
@ -584,8 +584,8 @@ define i64 @test58(i64 %A) nounwind {
; CHECK: @test58
; CHECK-NEXT: %C = lshr i64 %A, 8
; CHECK-NEXT: %D = or i64 %C, 128
; CHECK-NEXT: %E = and i64 %D, 16777215
; CHECK-NEXT: %D = and i64 %C, 16777087
; CHECK-NEXT: %E = or i64 %D, 128
; CHECK-NEXT: ret i64 %E
}

View File

@ -316,8 +316,8 @@ entry:
%E = or i32 %D, %C
ret i32 %E
; CHECK: @test30
; CHECK: %B = or i32 %A, 32962
; CHECK: %E = and i32 %B, -25350
; CHECK: %D = and i32 %A, -58312
; CHECK: %E = or i32 %D, 32962
; CHECK: ret i32 %E
}
@ -332,8 +332,8 @@ define i64 @test31(i64 %A) nounwind readnone ssp noredzone {
%F = or i64 %D, %E
ret i64 %F
; CHECK: @test31
; CHECK-NEXT: %bitfield = or i64 %A, 32962
; CHECK-NEXT: %F = and i64 %bitfield, 4294941946
; CHECK-NEXT: %E1 = and i64 %A, 4294908984
; CHECK-NEXT: %F = or i64 %E1, 32962
; CHECK-NEXT: ret i64 %F
}
@ -367,3 +367,12 @@ define i32 @test34(i32 %X, i32 %Y) {
; CHECK-NEXT: or i32 %X, %Y
; CHECK-NEXT: ret
}
define i32 @test35(i32 %a, i32 %b) {
%1 = or i32 %a, 1135
%2 = or i32 %1, %b
ret i32 %2
; CHECK: @test35
; CHECK-NEXT: or i32 %a, %b
; CHECK-NEXT: or i32 %1, 1135
}

View File

@ -34,7 +34,7 @@ define i32 @test2(i32 %tmp1) {
define i32 @test3(i32 %tmp1) {
; CHECK: @test3
; CHECK-NEXT: and i32 %tmp1, 32
; CHECK-NEXT: or i32 %tmp, 8
; CHECK-NEXT: or i32 %ovm, 8
; CHECK-NEXT: ret i32
%ovm = or i32 %tmp1, 145
%ov31 = and i32 %ovm, 177