[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