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]] ;