Index: lib/Transforms/InstCombine/InstCombineShifts.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineShifts.cpp +++ lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -680,6 +680,24 @@ return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, Mask)); } + if (match(Op0, m_SExt(m_Value(X)))) { + // Are we moving the sign bit to the low bit and widening with high zeros? + unsigned SrcTyBitWidth = X->getType()->getScalarSizeInBits(); + if (ShAmt == BitWidth - 1) { + // lshr (sext i1 X to iN), N-1 --> zext X to iN + if (SrcTyBitWidth == 1) + return new ZExtInst(X, Ty); + + // lshr (sext iM X to iN), N-1 --> zext (lshr X, M-1) to iN + if (Op0->hasOneUse()) { + Value *NewLShr = Builder->CreateLShr(X, SrcTyBitWidth - 1); + return new ZExtInst(NewLShr, Ty); + } + } + + // TODO: Convert to ashr+zext if the shift equals the extension amount. + } + if (match(Op0, m_LShr(m_Value(X), m_APInt(ShOp1)))) { unsigned AmtSum = ShAmt + ShOp1->getZExtValue(); // Oversized shifts are simplified to zero in InstSimplify. Index: test/Transforms/InstCombine/lshr.ll =================================================================== --- test/Transforms/InstCombine/lshr.ll +++ test/Transforms/InstCombine/lshr.ll @@ -100,12 +100,9 @@ ret <2 x i8> %lshr } -; FIXME: The bool bit got smeared across a wide val, but then we zero'd out those bits. This is just a zext. - define i16 @bool_zext(i1 %x) { ; CHECK-LABEL: @bool_zext( -; CHECK-NEXT: [[SEXT:%.*]] = sext i1 %x to i16 -; CHECK-NEXT: [[HIBIT:%.*]] = lshr i16 [[SEXT]], 15 +; CHECK-NEXT: [[HIBIT:%.*]] = zext i1 %x to i16 ; CHECK-NEXT: ret i16 [[HIBIT]] ; %sext = sext i1 %x to i16 @@ -115,8 +112,7 @@ define <2 x i8> @bool_zext_splat(<2 x i1> %x) { ; CHECK-LABEL: @bool_zext_splat( -; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i1> %x to <2 x i8> -; CHECK-NEXT: [[HIBIT:%.*]] = lshr <2 x i8> [[SEXT]], +; CHECK-NEXT: [[HIBIT:%.*]] = zext <2 x i1> %x to <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[HIBIT]] ; %sext = sext <2 x i1> %x to <2 x i8> @@ -148,12 +144,10 @@ ret <2 x i8> %hibit } -; FIXME: All of the replicated sign bits are wiped out by the lshr. This could be lshr+zext. - define i16 @fake_sext(i3 %x) { ; CHECK-LABEL: @fake_sext( -; CHECK-NEXT: [[SEXT:%.*]] = sext i3 %x to i16 -; CHECK-NEXT: [[SH:%.*]] = lshr i16 [[SEXT]], 15 +; CHECK-NEXT: [[TMP1:%.*]] = lshr i3 %x, 2 +; CHECK-NEXT: [[SH:%.*]] = zext i3 [[TMP1]] to i16 ; CHECK-NEXT: ret i16 [[SH]] ; %sext = sext i3 %x to i16 @@ -163,8 +157,8 @@ define <2 x i8> @fake_sext_splat(<2 x i3> %x) { ; CHECK-LABEL: @fake_sext_splat( -; CHECK-NEXT: [[SEXT:%.*]] = sext <2 x i3> %x to <2 x i8> -; CHECK-NEXT: [[SH:%.*]] = lshr <2 x i8> [[SEXT]], +; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i3> %x, +; CHECK-NEXT: [[SH:%.*]] = zext <2 x i3> [[TMP1]] to <2 x i8> ; CHECK-NEXT: ret <2 x i8> [[SH]] ; %sext = sext <2 x i3> %x to <2 x i8>