Skip to content

Commit b32ed5a

Browse files
wenju-heLukacma
authored andcommitted
[Instcombine] Avoid widening trunc+sext to trunc+shl+ashr when not profitable (llvm#160483)
Skip the transform that replaces: %a = trunc i64 %x to i16 %b = sext i16 %a to i32 with %a = trunc i64 %x to i32 %b = shl i32 %a, 16 %c = ashr exact i32 %b, 16 when (pre-trunc) source type is wider than the final destination type. Modern architectures typically have efficient sign-extend instruction. It is preferable to preserve the sext for this case. Resolves llvm#116019 Also fold sext(trunc nsw) to trunc nsw when narrowing source.
1 parent 64490e1 commit b32ed5a

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,7 +1525,15 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
15251525
}
15261526

15271527
// Try to extend the entire expression tree to the wide destination type.
1528-
if (shouldChangeType(SrcTy, DestTy) && canEvaluateSExtd(Src, DestTy)) {
1528+
bool ShouldExtendExpression = true;
1529+
Value *TruncSrc = nullptr;
1530+
// It is not desirable to extend expression in the trunc + sext pattern when
1531+
// destination type is narrower than original (pre-trunc) type.
1532+
if (match(Src, m_Trunc(m_Value(TruncSrc))))
1533+
if (TruncSrc->getType()->getScalarSizeInBits() > DestBitSize)
1534+
ShouldExtendExpression = false;
1535+
if (ShouldExtendExpression && shouldChangeType(SrcTy, DestTy) &&
1536+
canEvaluateSExtd(Src, DestTy)) {
15291537
// Okay, we can transform this! Insert the new expression now.
15301538
LLVM_DEBUG(
15311539
dbgs() << "ICE: EvaluateInDifferentType converting expression type"
@@ -1545,13 +1553,18 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
15451553
ShAmt);
15461554
}
15471555

1548-
Value *X;
1549-
if (match(Src, m_Trunc(m_Value(X)))) {
1556+
Value *X = TruncSrc;
1557+
if (X) {
15501558
// If the input has more sign bits than bits truncated, then convert
15511559
// directly to final type.
15521560
unsigned XBitSize = X->getType()->getScalarSizeInBits();
1553-
if (ComputeNumSignBits(X, &Sext) > XBitSize - SrcBitSize)
1554-
return CastInst::CreateIntegerCast(X, DestTy, /* isSigned */ true);
1561+
bool HasNSW = cast<TruncInst>(Src)->hasNoSignedWrap();
1562+
if (HasNSW || (ComputeNumSignBits(X, &Sext) > XBitSize - SrcBitSize)) {
1563+
auto *Res = CastInst::CreateIntegerCast(X, DestTy, /* isSigned */ true);
1564+
if (auto *ResTrunc = dyn_cast<TruncInst>(Res); ResTrunc && HasNSW)
1565+
ResTrunc->setHasNoSignedWrap(true);
1566+
return Res;
1567+
}
15551568

15561569
// If input is a trunc from the destination type, then convert into shifts.
15571570
if (Src->hasOneUse() && X->getType() == DestTy) {

llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,17 @@ define i24 @wide_source_matching_signbits(i32 %x) {
144144
ret i24 %c
145145
}
146146

147+
define i32 @wide_source_matching_signbits_has_nsw_flag(i64 %i) {
148+
; CHECK-LABEL: define i32 @wide_source_matching_signbits_has_nsw_flag(
149+
; CHECK-SAME: i64 [[I:%.*]]) {
150+
; CHECK-NEXT: [[A:%.*]] = trunc nsw i64 [[I]] to i32
151+
; CHECK-NEXT: ret i32 [[A]]
152+
;
153+
%a = trunc nsw i64 %i to i16
154+
%b = sext i16 %a to i32
155+
ret i32 %b
156+
}
157+
147158
; negative test - not enough sign-bits
148159

149160
define i24 @wide_source_not_matching_signbits(i32 %x) {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
target datalayout = "i16:16:16-i32:32:32-i64:64:64-n16:32:64"
5+
6+
define i32 @test(i64 %i) {
7+
; CHECK-LABEL: define i32 @test(
8+
; CHECK-SAME: i64 [[I:%.*]]) {
9+
; CHECK-NEXT: [[A:%.*]] = trunc i64 [[I]] to i16
10+
; CHECK-NEXT: [[B:%.*]] = sext i16 [[A]] to i32
11+
; CHECK-NEXT: ret i32 [[B]]
12+
;
13+
%a = trunc i64 %i to i16
14+
%b = sext i16 %a to i32
15+
ret i32 %b
16+
}

0 commit comments

Comments
 (0)