[llvm] 45b1bcf - [Instcombine] Avoid widening trunc+sext to trunc+shl+ashr when not profitable (#160483)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 27 18:01:55 PDT 2025
Author: Wenju He
Date: 2025-10-28T09:01:50+08:00
New Revision: 45b1bcfa26a40b189f34530eb3a2c8490c15965b
URL: https://github.com/llvm/llvm-project/commit/45b1bcfa26a40b189f34530eb3a2c8490c15965b
DIFF: https://github.com/llvm/llvm-project/commit/45b1bcfa26a40b189f34530eb3a2c8490c15965b.diff
LOG: [Instcombine] Avoid widening trunc+sext to trunc+shl+ashr when not profitable (#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 #116019
Also fold sext(trunc nsw) to trunc nsw when narrowing source.
Added:
llvm/test/Transforms/InstCombine/trunc-sext.ll
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 9b9fe265c7bce..f939e7aa78c33 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1525,7 +1525,15 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
}
// Try to extend the entire expression tree to the wide destination type.
- if (shouldChangeType(SrcTy, DestTy) && canEvaluateSExtd(Src, DestTy)) {
+ bool ShouldExtendExpression = true;
+ Value *TruncSrc = nullptr;
+ // It is not desirable to extend expression in the trunc + sext pattern when
+ // destination type is narrower than original (pre-trunc) type.
+ if (match(Src, m_Trunc(m_Value(TruncSrc))))
+ if (TruncSrc->getType()->getScalarSizeInBits() > DestBitSize)
+ ShouldExtendExpression = false;
+ if (ShouldExtendExpression && shouldChangeType(SrcTy, DestTy) &&
+ canEvaluateSExtd(Src, DestTy)) {
// Okay, we can transform this! Insert the new expression now.
LLVM_DEBUG(
dbgs() << "ICE: EvaluateInDifferentType converting expression type"
@@ -1545,13 +1553,18 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
ShAmt);
}
- Value *X;
- if (match(Src, m_Trunc(m_Value(X)))) {
+ Value *X = TruncSrc;
+ if (X) {
// If the input has more sign bits than bits truncated, then convert
// directly to final type.
unsigned XBitSize = X->getType()->getScalarSizeInBits();
- if (ComputeNumSignBits(X, &Sext) > XBitSize - SrcBitSize)
- return CastInst::CreateIntegerCast(X, DestTy, /* isSigned */ true);
+ bool HasNSW = cast<TruncInst>(Src)->hasNoSignedWrap();
+ if (HasNSW || (ComputeNumSignBits(X, &Sext) > XBitSize - SrcBitSize)) {
+ auto *Res = CastInst::CreateIntegerCast(X, DestTy, /* isSigned */ true);
+ if (auto *ResTrunc = dyn_cast<TruncInst>(Res); ResTrunc && HasNSW)
+ ResTrunc->setHasNoSignedWrap(true);
+ return Res;
+ }
// If input is a trunc from the destination type, then convert into shifts.
if (Src->hasOneUse() && X->getType() == DestTy) {
diff --git a/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll b/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll
index 516f1a2bfd5c5..4128a15d8d7ce 100644
--- a/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll
+++ b/llvm/test/Transforms/InstCombine/sext-of-trunc-nsw.ll
@@ -144,6 +144,17 @@ define i24 @wide_source_matching_signbits(i32 %x) {
ret i24 %c
}
+define i32 @wide_source_matching_signbits_has_nsw_flag(i64 %i) {
+; CHECK-LABEL: define i32 @wide_source_matching_signbits_has_nsw_flag(
+; CHECK-SAME: i64 [[I:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = trunc nsw i64 [[I]] to i32
+; CHECK-NEXT: ret i32 [[A]]
+;
+ %a = trunc nsw i64 %i to i16
+ %b = sext i16 %a to i32
+ ret i32 %b
+}
+
; negative test - not enough sign-bits
define i24 @wide_source_not_matching_signbits(i32 %x) {
diff --git a/llvm/test/Transforms/InstCombine/trunc-sext.ll b/llvm/test/Transforms/InstCombine/trunc-sext.ll
new file mode 100644
index 0000000000000..ac1438405e171
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/trunc-sext.ll
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+target datalayout = "i16:16:16-i32:32:32-i64:64:64-n16:32:64"
+
+define i32 @test(i64 %i) {
+; CHECK-LABEL: define i32 @test(
+; CHECK-SAME: i64 [[I:%.*]]) {
+; CHECK-NEXT: [[A:%.*]] = trunc i64 [[I]] to i16
+; CHECK-NEXT: [[B:%.*]] = sext i16 [[A]] to i32
+; CHECK-NEXT: ret i32 [[B]]
+;
+ %a = trunc i64 %i to i16
+ %b = sext i16 %a to i32
+ ret i32 %b
+}
More information about the llvm-commits
mailing list