From e9d56808d3d686a1bde664353f6784af85c7be06 Mon Sep 17 00:00:00 2001 From: Wenju He 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 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 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 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 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.