diff options
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp | 14 | ||||
-rw-r--r-- | llvm/test/Transforms/InstCombine/lshr.ll | 19 |
2 files changed, 24 insertions, 9 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 3f2ddcacce2..8cec865c642 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -682,11 +682,11 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, Mask)); } - if (match(Op0, m_SExt(m_Value(X)))) { + if (match(Op0, m_SExt(m_Value(X))) && + (!Ty->isIntegerTy() || shouldChangeType(Ty, X->getType()))) { // Are we moving the sign bit to the low bit and widening with high zeros? unsigned SrcTyBitWidth = X->getType()->getScalarSizeInBits(); - if (ShAmt == BitWidth - 1 && - (!Ty->isIntegerTy() || shouldChangeType(Ty, X->getType()))) { + if (ShAmt == BitWidth - 1) { // lshr (sext i1 X to iN), N-1 --> zext X to iN if (SrcTyBitWidth == 1) return new ZExtInst(X, Ty); @@ -698,7 +698,13 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { } } - // TODO: Convert to ashr+zext if the shift equals the extension amount. + // lshr (sext iM X to iN), N-M --> zext (ashr X, min(N-M, M-1)) to iN + if (ShAmt == BitWidth - SrcTyBitWidth && Op0->hasOneUse()) { + // The new shift amount can't be more than the narrow source type. + unsigned NewShAmt = std::min(ShAmt, SrcTyBitWidth - 1); + Value *AShr = Builder->CreateAShr(X, NewShAmt); + return new ZExtInst(AShr, Ty); + } } if (match(Op0, m_LShr(m_Value(X), m_APInt(ShOp1)))) { diff --git a/llvm/test/Transforms/InstCombine/lshr.ll b/llvm/test/Transforms/InstCombine/lshr.ll index 71b25177162..4cdcb98f730 100644 --- a/llvm/test/Transforms/InstCombine/lshr.ll +++ b/llvm/test/Transforms/InstCombine/lshr.ll @@ -122,10 +122,19 @@ define <2 x i8> @bool_zext_splat(<2 x i1> %x) { ret <2 x i8> %hibit } -; FIXME: The replicated sign bits are all that's left. This could be ashr+zext. - -define i16 @smear_sign_and_widen(i4 %x) { +define i32 @smear_sign_and_widen(i8 %x) { ; CHECK-LABEL: @smear_sign_and_widen( +; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 %x, 7 +; CHECK-NEXT: [[HIBIT:%.*]] = zext i8 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[HIBIT]] +; + %sext = sext i8 %x to i32 + %hibit = lshr i32 %sext, 24 + ret i32 %hibit +} + +define i16 @smear_sign_and_widen_should_not_change_type(i4 %x) { +; CHECK-LABEL: @smear_sign_and_widen_should_not_change_type( ; CHECK-NEXT: [[SEXT:%.*]] = sext i4 %x to i16 ; CHECK-NEXT: [[HIBIT:%.*]] = lshr i16 [[SEXT]], 12 ; CHECK-NEXT: ret i16 [[HIBIT]] @@ -137,8 +146,8 @@ define i16 @smear_sign_and_widen(i4 %x) { define <2 x i8> @smear_sign_and_widen_splat(<2 x i6> %x) { ; CHECK-LABEL: @smear_sign_and_widen_splat( -; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i6> %x to <2 x i8> -; CHECK-NEXT: [[HIBIT:%.*]] = lshr <2 x i8> [[SEXT]], <i8 2, i8 2> +; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i6> %x, <i6 2, i6 2> +; CHECK-NEXT: [[HIBIT:%.*]] = zext <2 x i6> [[TMP1]] to <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[HIBIT]] ; %sext = sext <2 x i6> %x to <2 x i8> |