summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Transforms/InstCombine/InstCombine.h5
-rw-r--r--lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp86
-rw-r--r--test/Transforms/InstCombine/2010-11-01-lshr-mask.ll4
-rw-r--r--test/Transforms/InstCombine/shift.ll76
-rw-r--r--test/Transforms/InstCombine/signext.ll4
5 files changed, 170 insertions, 5 deletions
diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h
index 90637a9d7b..ff5eeb6192 100644
--- a/lib/Transforms/InstCombine/InstCombine.h
+++ b/lib/Transforms/InstCombine/InstCombine.h
@@ -327,6 +327,11 @@ private:
bool SimplifyDemandedBits(Use &U, APInt DemandedMask,
APInt& KnownZero, APInt& KnownOne,
unsigned Depth=0);
+ /// Helper routine of SimplifyDemandedUseBits. It tries to simplify demanded
+ /// bit for "r1 = shr x, c1; r2 = shl r1, c2" instruction sequence.
+ Value *SimplifyShrShlDemandedBits(Instruction *Lsr, Instruction *Sftl,
+ APInt DemandedMask, APInt &KnownZero,
+ APInt &KnownOne);
/// SimplifyDemandedInstructionBits - Inst is an integer instruction that
/// SimplifyDemandedBits knows about. See if the instruction has any
diff --git a/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 602b203371..c65076e883 100644
--- a/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -16,9 +16,10 @@
#include "InstCombine.h"
#include "llvm/DataLayout.h"
#include "llvm/IntrinsicInst.h"
+#include "llvm/Support/PatternMatch.h"
using namespace llvm;
-
+using namespace llvm::PatternMatch;
/// ShrinkDemandedConstant - Check to see if the specified operand of the
/// specified instruction is a constant integer. If so, check to see if there
@@ -580,6 +581,17 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
break;
case Instruction::Shl:
if (ConstantInt *SA = dyn_cast<ConstantInt>(I->getOperand(1))) {
+ {
+ Value *VarX; ConstantInt *C1;
+ if (match(I->getOperand(0), m_Shr(m_Value(VarX), m_ConstantInt(C1)))) {
+ Instruction *Shr = cast<Instruction>(I->getOperand(0));
+ Value *R = SimplifyShrShlDemandedBits(Shr, I, DemandedMask,
+ KnownZero, KnownOne);
+ if (R)
+ return R;
+ }
+ }
+
uint64_t ShiftAmt = SA->getLimitedValue(BitWidth-1);
APInt DemandedMaskIn(DemandedMask.lshr(ShiftAmt));
@@ -800,6 +812,78 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
return 0;
}
+/// Helper routine of SimplifyDemandedUseBits. It tries to simplify
+/// "E1 = (X lsr C1) << C2", where the C1 and C2 are constant, into
+/// "E2 = X << (C2 - C1)" or "E2 = X >> (C1 - C2)", depending on the sign
+/// of "C2-C1".
+///
+/// Suppose E1 and E2 are generally different in bits S={bm, bm+1,
+/// ..., bn}, without considering the specific value X is holding.
+/// This transformation is legal iff one of following conditions is hold:
+/// 1) All the bit in S are 0, in this case E1 == E2.
+/// 2) We don't care those bits in S, per the input DemandedMask.
+/// 3) Combination of 1) and 2). Some bits in S are 0, and we don't care the
+/// rest bits.
+///
+/// Currently we only test condition 2).
+///
+/// As with SimplifyDemandedUseBits, it returns NULL if the simplification was
+/// not successful.
+Value *InstCombiner::SimplifyShrShlDemandedBits(Instruction *Shr,
+ Instruction *Shl, APInt DemandedMask, APInt &KnownZero, APInt &KnownOne) {
+
+ unsigned ShlAmt = cast<ConstantInt>(Shl->getOperand(1))->getZExtValue();
+ unsigned ShrAmt = cast<ConstantInt>(Shr->getOperand(1))->getZExtValue();
+
+ KnownOne.clearAllBits();
+ KnownZero = APInt::getBitsSet(KnownZero.getBitWidth(), 0, ShlAmt-1);
+ KnownZero &= DemandedMask;
+
+ if (ShlAmt == 0 || ShrAmt == 0)
+ return 0;
+
+ Value *VarX = Shr->getOperand(0);
+ Type *Ty = VarX->getType();
+
+ APInt BitMask1(Ty->getIntegerBitWidth(), (uint64_t)-1);
+ APInt BitMask2(Ty->getIntegerBitWidth(), (uint64_t)-1);
+
+ bool isLshr = (Shr->getOpcode() == Instruction::LShr);
+ BitMask1 = isLshr ? (BitMask1.lshr(ShrAmt) << ShlAmt) :
+ (BitMask1.ashr(ShrAmt) << ShlAmt);
+
+ if (ShrAmt <= ShlAmt) {
+ BitMask2 <<= (ShlAmt - ShrAmt);
+ } else {
+ BitMask2 = isLshr ? BitMask2.lshr(ShrAmt - ShlAmt):
+ BitMask2.ashr(ShrAmt - ShlAmt);
+ }
+
+ // Check if condition-2 (see the comment to this function) is satified.
+ if ((BitMask1 & DemandedMask) == (BitMask2 & DemandedMask)) {
+ if (ShrAmt == ShlAmt)
+ return VarX;
+
+ if (!Shr->hasOneUse())
+ return 0;
+
+ BinaryOperator *New;
+ if (ShrAmt < ShlAmt) {
+ Constant *Amt = ConstantInt::get(VarX->getType(), ShlAmt - ShrAmt);
+ New = BinaryOperator::CreateShl(VarX, Amt);
+ BinaryOperator *Orig = cast<BinaryOperator>(Shl);
+ New->setHasNoSignedWrap(Orig->hasNoSignedWrap());
+ New->setHasNoUnsignedWrap(Orig->hasNoUnsignedWrap());
+ } else {
+ Constant *Amt = ConstantInt::get(VarX->getType(), ShrAmt - ShlAmt);
+ New = BinaryOperator::CreateLShr(VarX, Amt);
+ }
+
+ return InsertNewInstWith(New, *Shl);
+ }
+
+ return 0;
+}
/// SimplifyDemandedVectorElts - The specified value produces a vector with
/// any number of elements. DemandedElts contains the set of elements that are
diff --git a/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll b/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll
index eb28994756..5efad8a789 100644
--- a/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll
+++ b/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll
@@ -5,8 +5,8 @@
define i32 @main(i32 %argc) nounwind ssp {
entry:
%tmp3151 = trunc i32 %argc to i8
-; CHECK: %tmp3163 = shl i8 %tmp3162, 6
-; CHECK: and i8 %tmp3163, 64
+; CHECK: %tmp3162 = shl i8 %tmp3151, 5
+; CHECK: and i8 %tmp3162, 64
; CHECK-NOT: shl
; CHECK-NOT: shr
%tmp3161 = or i8 %tmp3151, -17
diff --git a/test/Transforms/InstCombine/shift.ll b/test/Transforms/InstCombine/shift.ll
index 25e708b7f5..b152816d2b 100644
--- a/test/Transforms/InstCombine/shift.ll
+++ b/test/Transforms/InstCombine/shift.ll
@@ -659,3 +659,79 @@ define i32 @test53(i32 %x) {
; CHECK-NEXT: %B = shl nuw i32 %x, 2
; CHECK-NEXT: ret i32 %B
}
+
+define i32 @test54(i32 %x) {
+ %shr2 = lshr i32 %x, 1
+ %shl = shl i32 %shr2, 4
+ %and = and i32 %shl, 16
+ ret i32 %and
+; CHECK: @test54
+; CHECK: shl i32 %x, 3
+}
+
+
+define i32 @test55(i32 %x) {
+ %shr2 = lshr i32 %x, 1
+ %shl = shl i32 %shr2, 4
+ %or = or i32 %shl, 8
+ ret i32 %or
+; CHECK: @test55
+; CHECK: shl i32 %x, 3
+}
+
+define i32 @test56(i32 %x) {
+ %shr2 = lshr i32 %x, 1
+ %shl = shl i32 %shr2, 4
+ %or = or i32 %shl, 7
+ ret i32 %or
+; CHECK: @test56
+; CHECK: shl i32 %shr2, 4
+}
+
+
+define i32 @test57(i32 %x) {
+ %shr = lshr i32 %x, 1
+ %shl = shl i32 %shr, 4
+ %and = and i32 %shl, 16
+ ret i32 %and
+; CHECK: @test57
+; CHECK: shl i32 %x, 3
+}
+
+define i32 @test58(i32 %x) {
+ %shr = lshr i32 %x, 1
+ %shl = shl i32 %shr, 4
+ %or = or i32 %shl, 8
+ ret i32 %or
+; CHECK: @test58
+; CHECK: shl i32 %x, 3
+}
+
+define i32 @test59(i32 %x) {
+ %shr = ashr i32 %x, 1
+ %shl = shl i32 %shr, 4
+ %or = or i32 %shl, 7
+ ret i32 %or
+; CHECK: @test59
+; CHECK: %shl = shl i32 %shr1, 4
+}
+
+
+define i32 @test60(i32 %x) {
+ %shr = ashr i32 %x, 4
+ %shl = shl i32 %shr, 1
+ %or = or i32 %shl, 1
+ ret i32 %or
+; CHECK: @test60
+; CHECK: lshr i32 %x, 3
+}
+
+
+define i32 @test61(i32 %x) {
+ %shr = ashr i32 %x, 4
+ %shl = shl i32 %shr, 1
+ %or = or i32 %shl, 2
+ ret i32 %or
+; CHECK: @test61
+; CHECK: ashr i32 %x, 4
+}
diff --git a/test/Transforms/InstCombine/signext.ll b/test/Transforms/InstCombine/signext.ll
index ecee9830cd..5ed1cd5590 100644
--- a/test/Transforms/InstCombine/signext.ll
+++ b/test/Transforms/InstCombine/signext.ll
@@ -82,6 +82,6 @@ entry:
%sub = add i32 %xor, -67108864 ; <i32> [#uses=1]
ret i32 %sub
; CHECK: @test8
-; CHECK: %shr = ashr i32 %x, 5
-; CHECK: ret i32 %shr
+; CHECK: %sub = ashr i32 %x, 5
+; CHECK: ret i32 %sub
}