[llvm] [Instcombine] Avoid widening trunc+sext to trunc+shl+ashr when not profitable (PR #160483)

Wenju He via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 30 04:36:14 PDT 2025


https://github.com/wenju-he updated https://github.com/llvm/llvm-project/pull/160483

>From e9d56808d3d686a1bde664353f6784af85c7be06 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Sep 2025 12:09:26 +0200
Subject: [PATCH 1/5] [Instcombine] Avoid widening trunc+sext to trunc+shl+ashr
 when not profitable

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
---
 .../Transforms/InstCombine/InstCombineCasts.cpp   | 15 ++++++++++++---
 llvm/test/Transforms/InstCombine/sext.ll          | 11 +++++++++++
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 9ca8194b44f8f..ea029e47730bf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1528,7 +1528,17 @@ 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 *X = nullptr;
+  // Do not extend expression in the trunc + sext pattern when destination type
+  // is narrower than original (pre-trunc) type: modern architectures typically
+  // provide efficient sign-extend instruction, so preserving the sext is
+  // preferable here.
+  if (match(Src, m_Trunc(m_Value(X))))
+    if (X->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"
@@ -1548,8 +1558,7 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
                                       ShAmt);
   }
 
-  Value *X;
-  if (match(Src, m_Trunc(m_Value(X)))) {
+  if (X) {
     // If the input has more sign bits than bits truncated, then convert
     // directly to final type.
     unsigned XBitSize = X->getType()->getScalarSizeInBits();
diff --git a/llvm/test/Transforms/InstCombine/sext.ll b/llvm/test/Transforms/InstCombine/sext.ll
index c72614d526036..92748034f52ab 100644
--- a/llvm/test/Transforms/InstCombine/sext.ll
+++ b/llvm/test/Transforms/InstCombine/sext.ll
@@ -320,6 +320,17 @@ define i10 @test19(i10 %i) {
   ret i10 %d
 }
 
+define i32 @test20(i64 %i) {
+; CHECK-LABEL: @test20(
+; 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
+}
+
 define i32 @smear_set_bit(i32 %x) {
 ; CHECK-LABEL: @smear_set_bit(
 ; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[X:%.*]], 24

>From 1d0a139be9e9cb47de4ac36cbe0d5a5b9c3d4ee3 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Sep 2025 12:16:06 +0200
Subject: [PATCH 2/5] update per copilot suggestion

---
 llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index ea029e47730bf..b65e4936f9812 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1529,13 +1529,13 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
 
   // Try to extend the entire expression tree to the wide destination type.
   bool shouldExtendExpression = true;
-  Value *X = nullptr;
+  Value *Trunc = nullptr;
   // Do not extend expression in the trunc + sext pattern when destination type
   // is narrower than original (pre-trunc) type: modern architectures typically
   // provide efficient sign-extend instruction, so preserving the sext is
   // preferable here.
-  if (match(Src, m_Trunc(m_Value(X))))
-    if (X->getType()->getScalarSizeInBits() > DestBitSize)
+  if (match(Src, m_Trunc(m_Value(Trunc))))
+    if (Trunc->getType()->getScalarSizeInBits() > DestBitSize)
       shouldExtendExpression = false;
   if (shouldExtendExpression && shouldChangeType(SrcTy, DestTy) &&
       canEvaluateSExtd(Src, DestTy)) {
@@ -1558,6 +1558,7 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
                                       ShAmt);
   }
 
+  Value *X = Trunc;
   if (X) {
     // If the input has more sign bits than bits truncated, then convert
     // directly to final type.

>From 4160bec55d9eecf85184a803dd74f538e6e5e67d Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Wed, 24 Sep 2025 13:50:04 +0200
Subject: [PATCH 3/5] refine comment

---
 llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index b65e4936f9812..5f2b6e1cc61eb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1530,10 +1530,8 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
   // Try to extend the entire expression tree to the wide destination type.
   bool shouldExtendExpression = true;
   Value *Trunc = nullptr;
-  // Do not extend expression in the trunc + sext pattern when destination type
-  // is narrower than original (pre-trunc) type: modern architectures typically
-  // provide efficient sign-extend instruction, so preserving the sext is
-  // preferable here.
+  // 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(Trunc))))
     if (Trunc->getType()->getScalarSizeInBits() > DestBitSize)
       shouldExtendExpression = false;

>From 4b636bf838a81048aa86bded097c7251be11d766 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 30 Sep 2025 13:34:10 +0200
Subject: [PATCH 4/5] move to separate test with native integer widths

---
 llvm/test/Transforms/InstCombine/sext.ll       | 11 -----------
 llvm/test/Transforms/InstCombine/trunc-sext.ll | 16 ++++++++++++++++
 2 files changed, 16 insertions(+), 11 deletions(-)
 create mode 100644 llvm/test/Transforms/InstCombine/trunc-sext.ll

diff --git a/llvm/test/Transforms/InstCombine/sext.ll b/llvm/test/Transforms/InstCombine/sext.ll
index 92748034f52ab..c72614d526036 100644
--- a/llvm/test/Transforms/InstCombine/sext.ll
+++ b/llvm/test/Transforms/InstCombine/sext.ll
@@ -320,17 +320,6 @@ define i10 @test19(i10 %i) {
   ret i10 %d
 }
 
-define i32 @test20(i64 %i) {
-; CHECK-LABEL: @test20(
-; 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
-}
-
 define i32 @smear_set_bit(i32 %x) {
 ; CHECK-LABEL: @smear_set_bit(
 ; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[X:%.*]], 24
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
+}

>From 00d2e6e843ceb807712094c4168762ede7428eea Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Tue, 30 Sep 2025 13:35:34 +0200
Subject: [PATCH 5/5] NFC, rename Trunc to TruncSrc

---
 llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 5f2b6e1cc61eb..3d407464ffec6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1529,11 +1529,11 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
 
   // Try to extend the entire expression tree to the wide destination type.
   bool shouldExtendExpression = true;
-  Value *Trunc = nullptr;
+  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(Trunc))))
-    if (Trunc->getType()->getScalarSizeInBits() > DestBitSize)
+  if (match(Src, m_Trunc(m_Value(TruncSrc))))
+    if (TruncSrc->getType()->getScalarSizeInBits() > DestBitSize)
       shouldExtendExpression = false;
   if (shouldExtendExpression && shouldChangeType(SrcTy, DestTy) &&
       canEvaluateSExtd(Src, DestTy)) {
@@ -1556,7 +1556,7 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
                                       ShAmt);
   }
 
-  Value *X = Trunc;
+  Value *X = TruncSrc;
   if (X) {
     // If the input has more sign bits than bits truncated, then convert
     // directly to final type.



More information about the llvm-commits mailing list