Skip to content

Commit

Permalink
[InstCombine] sext(trunc(x)) --> sext(x) iff trunc is NSW (PR49543)
Browse files Browse the repository at this point in the history
If we can tell that trunc only chops off sign bits, and not all of them,
then we can simply sign-extend the trunc's source.
  • Loading branch information
LebedevRI committed Apr 20, 2021
1 parent 4e2c419 commit 1e6ca23
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 11 deletions.
18 changes: 14 additions & 4 deletions llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1493,12 +1493,22 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &CI) {
// If the input is a trunc from the destination type, then turn sext(trunc(x))
// into shifts.
Value *X;
if (match(Src, m_OneUse(m_Trunc(m_Value(X)))) && X->getType() == DestTy) {
// sext(trunc(X)) --> ashr(shl(X, C), C)
if (match(Src, m_Trunc(m_Value(X)))) {
unsigned SrcBitSize = SrcTy->getScalarSizeInBits();
unsigned DestBitSize = DestTy->getScalarSizeInBits();
Constant *ShAmt = ConstantInt::get(DestTy, DestBitSize - SrcBitSize);
return BinaryOperator::CreateAShr(Builder.CreateShl(X, ShAmt), ShAmt);
unsigned XBitSize = X->getType()->getScalarSizeInBits();

// Iff X had more sign bits than the number of bits that were chopped off
// by the truncation, we can directly sign-extend the X.
unsigned XNumSignBits = ComputeNumSignBits(X, 0, &CI);
if (XNumSignBits > (XBitSize - SrcBitSize))
return CastInst::Create(Instruction::SExt, X, DestTy);

if (Src->hasOneUse() && X->getType() == DestTy) {
// sext(trunc(X)) --> ashr(shl(X, C), C)
Constant *ShAmt = ConstantInt::get(DestTy, DestBitSize - SrcBitSize);
return BinaryOperator::CreateAShr(Builder.CreateShl(X, ShAmt), ShAmt);
}
}

if (ICmpInst *ICI = dyn_cast<ICmpInst>(Src))
Expand Down
11 changes: 4 additions & 7 deletions llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ define i16 @t0(i8 %x) {
; CHECK-LABEL: @t0(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 5
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[B:%.*]] = trunc i8 [[A]] to i4
; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16
; CHECK-NEXT: [[C:%.*]] = sext i8 [[A]] to i16
; CHECK-NEXT: ret i16 [[C]]
;
%a = ashr i8 %x, 5
Expand All @@ -28,8 +27,7 @@ define i16 @t1(i8 %x) {
; CHECK-LABEL: @t1(
; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 4
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[B:%.*]] = trunc i8 [[A]] to i4
; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16
; CHECK-NEXT: [[C:%.*]] = sext i8 [[A]] to i16
; CHECK-NEXT: ret i16 [[C]]
;
%a = ashr i8 %x, 4
Expand Down Expand Up @@ -59,8 +57,7 @@ define <2 x i16> @t3_vec(<2 x i8> %x) {
; CHECK-LABEL: @t3_vec(
; CHECK-NEXT: [[A:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 4, i8 4>
; CHECK-NEXT: call void @usevec(<2 x i8> [[A]])
; CHECK-NEXT: [[B:%.*]] = trunc <2 x i8> [[A]] to <2 x i4>
; CHECK-NEXT: [[C:%.*]] = sext <2 x i4> [[B]] to <2 x i16>
; CHECK-NEXT: [[C:%.*]] = sext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT: ret <2 x i16> [[C]]
;
%a = ashr <2 x i8> %x, <i8 4, i8 4>
Expand Down Expand Up @@ -91,7 +88,7 @@ define i16 @t5_extrause(i8 %x) {
; CHECK-NEXT: call void @use8(i8 [[A]])
; CHECK-NEXT: [[B:%.*]] = trunc i8 [[A]] to i4
; CHECK-NEXT: call void @use4(i4 [[B]])
; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16
; CHECK-NEXT: [[C:%.*]] = sext i8 [[A]] to i16
; CHECK-NEXT: ret i16 [[C]]
;
%a = ashr i8 %x, 5
Expand Down

0 comments on commit 1e6ca23

Please sign in to comment.