From 4eb218a6fda4ab0fcbc6f00a1dbe7bd128d7340a Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 26 Jan 2017 22:08:10 +0000 Subject: [PATCH] [InstCombine] fold (X >>u C) << C --> X & (-1 << C) We already have this fold when the lshr has one use, but it doesn't need that restriction. We may be able to remove some code from foldShiftedShift(). Also, move the similar: (X << C) >>u C --> X & (-1 >>u C) ...directly into visitLShr to help clean up foldShiftByConstOfShiftByConst(). That whole function seems questionable since it is called by commonShiftTransforms(), but there's really not much in common if we're checking the shift opcodes for every fold. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293215 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineShifts.cpp | 35 +++++++++---------- test/Transforms/InstCombine/apint-shift.ll | 8 ++--- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp index a4ff5f76da9..6507bb94519 100644 --- a/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -360,21 +360,8 @@ foldShiftByConstOfShiftByConst(BinaryOperator &I, const APInt *COp1, if (ShiftAmt1 == 0) return nullptr; // Will be simplified in the future. - if (ShiftAmt1 == ShiftAmt2) { - // FIXME: This repeats a fold that exists in foldShiftedShift(), but we're - // not handling the related fold here: - // (X >>u C) << C --> X & (-1 << C). - // foldShiftedShift() is always called before this, but it is restricted to - // only handle cases where the ShiftOp has one use. We don't have that - // restriction here. - if (I.getOpcode() != Instruction::LShr || - ShiftOp->getOpcode() != Instruction::Shl) - return nullptr; - - // (X << C) >>u C --> X & (-1 >>u C). - APInt Mask(APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt1)); - return BinaryOperator::CreateAnd(X, ConstantInt::get(I.getType(), Mask)); - } + if (ShiftAmt1 == ShiftAmt2) + return nullptr; // FIXME: Everything under here should be extended to work with vector types. @@ -714,6 +701,7 @@ Instruction *InstCombiner::visitShl(BinaryOperator &I) { const APInt *ShAmtAPInt; if (match(Op1, m_APInt(ShAmtAPInt))) { unsigned ShAmt = ShAmtAPInt->getZExtValue(); + unsigned BitWidth = I.getType()->getScalarSizeInBits(); // shl (zext X), ShAmt --> zext (shl X, ShAmt) // This is only valid if X would have zeros shifted out. @@ -725,11 +713,15 @@ Instruction *InstCombiner::visitShl(BinaryOperator &I) { return new ZExtInst(Builder->CreateShl(X, ShAmt), I.getType()); } + // (X >>u C) << C --> X & (-1 << C) + if (match(Op0, m_LShr(m_Value(X), m_Specific(Op1)))) { + APInt Mask(APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt)); + return BinaryOperator::CreateAnd(X, ConstantInt::get(I.getType(), Mask)); + } + // If the shifted-out value is known-zero, then this is a NUW shift. if (!I.hasNoUnsignedWrap() && - MaskedValueIsZero( - Op0, APInt::getHighBitsSet(ShAmtAPInt->getBitWidth(), ShAmt), 0, - &I)) { + MaskedValueIsZero(Op0, APInt::getHighBitsSet(BitWidth, ShAmt), 0, &I)) { I.setHasNoUnsignedWrap(); return &I; } @@ -780,6 +772,13 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { return new ZExtInst(Cmp, II->getType()); } + // (X << C) >>u C --> X & (-1 >>u C) + Value *X; + if (match(Op0, m_Shl(m_Value(X), m_Specific(Op1)))) { + APInt Mask(APInt::getLowBitsSet(BitWidth, BitWidth - ShAmt)); + return BinaryOperator::CreateAnd(X, ConstantInt::get(I.getType(), Mask)); + } + // If the shifted-out value is known-zero, then this is an exact shift. if (!I.isExact() && MaskedValueIsZero(Op0, APInt::getLowBitsSet(BitWidth, ShAmt), 0, &I)) { diff --git a/test/Transforms/InstCombine/apint-shift.ll b/test/Transforms/InstCombine/apint-shift.ll index 7ddaf154f31..fc1934b576f 100644 --- a/test/Transforms/InstCombine/apint-shift.ll +++ b/test/Transforms/InstCombine/apint-shift.ll @@ -459,12 +459,12 @@ define <2 x i44> @shl_lshr_eq_amt_multi_use_splat_vec(<2 x i44> %A) { ret <2 x i44> %D } -; FIXME: Fold shl (lshr X, C), C -> and X, C' regardless of the number of uses of the lshr. +; Fold shl (lshr X, C), C -> and X, C' regardless of the number of uses of the lshr. define i43 @lshr_shl_eq_amt_multi_use(i43 %A) { ; CHECK-LABEL: @lshr_shl_eq_amt_multi_use( ; CHECK-NEXT: [[B:%.*]] = lshr i43 %A, 23 -; CHECK-NEXT: [[C:%.*]] = shl nuw i43 [[B]], 23 +; CHECK-NEXT: [[C:%.*]] = and i43 %A, -8388608 ; CHECK-NEXT: [[D:%.*]] = mul i43 [[B]], [[C]] ; CHECK-NEXT: ret i43 [[D]] ; @@ -474,12 +474,12 @@ define i43 @lshr_shl_eq_amt_multi_use(i43 %A) { ret i43 %D } -; FIXME: Fold vector shl (lshr X, C), C -> and X, C' regardless of the number of uses of the lshr. +; Fold vector shl (lshr X, C), C -> and X, C' regardless of the number of uses of the lshr. define <2 x i43> @lshr_shl_eq_amt_multi_use_splat_vec(<2 x i43> %A) { ; CHECK-LABEL: @lshr_shl_eq_amt_multi_use_splat_vec( ; CHECK-NEXT: [[B:%.*]] = lshr <2 x i43> %A, -; CHECK-NEXT: [[C:%.*]] = shl nuw <2 x i43> [[B]], +; CHECK-NEXT: [[C:%.*]] = and <2 x i43> %A, ; CHECK-NEXT: [[D:%.*]] = mul <2 x i43> [[B]], [[C]] ; CHECK-NEXT: ret <2 x i43> [[D]] ; -- 2.40.0