return CastInst::CreateIntegerCast(Shift, DestTy, false);
}
- // FIXME: We should canonicalize to zext/trunc and remove this transform.
+ const APInt *C;
+ if (match(Src, m_LShr(m_SExt(m_Value(A)), m_APInt(C))) &&
+ A->getType() == DestTy) {
+ // If the shift is small enough, all zero bits created by the shift are
+ // removed by the trunc:
+ // trunc (lshr (sext A), C) --> ashr A, C
+ if (C->getZExtValue() <= SrcWidth - DestWidth) {
+ unsigned ShAmt = std::min((unsigned)C->getZExtValue(), DestWidth - 1);
+ return BinaryOperator::CreateAShr(A, ConstantInt::get(DestTy, ShAmt));
+ }
+ // TODO: Mask high bits with 'and'.
+ }
+
+ // More complicated: deal with mismatched sizes.
+ // FIXME: This is too restrictive for uses and doesn't work with vectors.
// Transform trunc(lshr (sext A), Cst) to ashr A, Cst to eliminate type
// conversion.
// It works because bits coming from sign extension have the same value as
// FIXME: Instead of bailing when the shift is too large, use and to clear
// the extra bits.
if (ShiftAmt <= MaxAmt) {
- if (DestWidth == ASize)
- return BinaryOperator::CreateAShr(
- A, ConstantInt::get(DestTy, std::min(ShiftAmt, ASize - 1)));
if (SExt->hasOneUse()) {
Value *Shift = Builder.CreateAShr(A, std::min(ShiftAmt, ASize - 1));
Shift->takeName(Src);
; ALL-LABEL: @trunc_lshr_sext_uses1(
; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[B]])
-; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 6, i32 6>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = ashr <2 x i8> [[A]], <i8 6, i8 6>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
; ALL-NEXT: [[B:%.*]] = sext i8 [[A:%.*]] to i32
; ALL-NEXT: [[C:%.*]] = lshr i32 [[B]], 6
; ALL-NEXT: call void @use_i32(i32 [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = ashr i8 [[A]], 6
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i8 %A to i32
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[B]])
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 6, i32 6>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = ashr <2 x i8> [[A]], <i8 6, i8 6>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8 >%A to <2 x i32>
define <2 x i8> @trunc_lshr_overshift_sext(<2 x i8> %A) {
; ALL-LABEL: @trunc_lshr_overshift_sext(
-; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
-; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 8, i32 8>
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = ashr <2 x i8> [[A:%.*]], <i8 7, i8 7>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
; ALL-NEXT: [[B:%.*]] = sext <2 x i8> [[A:%.*]] to <2 x i32>
; ALL-NEXT: [[C:%.*]] = lshr <2 x i32> [[B]], <i32 8, i32 8>
; ALL-NEXT: call void @use_v2i32(<2 x i32> [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc <2 x i32> [[C]] to <2 x i8>
+; ALL-NEXT: [[D:%.*]] = ashr <2 x i8> [[A]], <i8 7, i8 7>
; ALL-NEXT: ret <2 x i8> [[D]]
;
%B = sext <2 x i8> %A to <2 x i32>
; ALL-NEXT: call void @use_i32(i32 [[B]])
; ALL-NEXT: [[C:%.*]] = lshr i32 [[B]], 8
; ALL-NEXT: call void @use_i32(i32 [[C]])
-; ALL-NEXT: [[D:%.*]] = trunc i32 [[C]] to i8
+; ALL-NEXT: [[D:%.*]] = ashr i8 [[A]], 7
; ALL-NEXT: ret i8 [[D]]
;
%B = sext i8 %A to i32