[llvm-branch-commits] [llvm] [InstCombine] Move sext(trunc(lshr(...))) combine before same type combine (PR #227322)

Luke Lau via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Oct 7 14:55:47 PDT 2026


https://github.com/lukel97 updated https://github.com/llvm/llvm-project/pull/227322

>From 1302f02d355d7a990d29f9ad218b4695a4acd9ce Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 29 Sep 2026 14:16:08 +0100
Subject: [PATCH] [InstCombine] Move sext(trunc(lshr(...))) combine before same
 type combine

The same type sext(trunc(...)) combine will fire on the lshr case, but the lshr produces one less shift. Move it afterwards to give the lshr combine a chance to fire first. Fixes the motivating x264 case
---
 .../Transforms/InstCombine/InstCombineCasts.cpp    | 14 +++++++-------
 .../AArch64/lshr-trunc-sext-to-ashr-sext.ll        |  5 ++---
 .../RISCV/lshr-trunc-sext-to-ashr-sext.ll          |  5 ++---
 .../X86/lshr-trunc-sext-to-ashr-sext.ll            |  5 ++---
 4 files changed, 13 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index f3741e9b16b94e..c8614cede3b3f9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1959,13 +1959,6 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
       return Res;
     }
 
-    // If input is a trunc from the destination type, then convert into shifts.
-    if (Src->hasOneUse() && X->getType() == DestTy) {
-      // sext (trunc X) --> ashr (shl X, C), C
-      Constant *ShAmt = ConstantInt::get(DestTy, DestBitSize - SrcBitSize);
-      return BinaryOperator::CreateAShr(Builder.CreateShl(X, ShAmt), ShAmt);
-    }
-
     // If we are replacing shifted-in high zero bits with sign bits, convert
     // the logic shift to arithmetic shift and eliminate the cast to
     // intermediate type:
@@ -1981,6 +1974,13 @@ Instruction *InstCombinerImpl::visitSExt(SExtInst &Sext) {
       Value *Ashr = Builder.CreateAShr(Y, C->getZExtValue());
       return CastInst::CreateIntegerCast(Ashr, DestTy, /* isSigned */ true);
     }
+
+    // If input is a trunc from the destination type, then convert into shifts.
+    if (Src->hasOneUse() && X->getType() == DestTy) {
+      // sext (trunc X) --> ashr (shl X, C), C
+      Constant *ShAmt = ConstantInt::get(DestTy, DestBitSize - SrcBitSize);
+      return BinaryOperator::CreateAShr(Builder.CreateShl(X, ShAmt), ShAmt);
+    }
   }
 
   // Try to extend the entire expression tree to the wide destination type.
diff --git a/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll
index 6451486688a123..01f0d9c7ec5489 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/lshr-trunc-sext-to-ashr-sext.ll
@@ -18,9 +18,8 @@ define i32 @t1(i16 %x) {
 ; CHECK-LABEL: define i32 @t1(
 ; CHECK-SAME: i16 [[X:%.*]]) {
 ; CHECK-NEXT:    [[S:%.*]] = sext i16 [[X]] to i32
-; CHECK-NEXT:    [[Y:%.*]] = shl nsw i32 [[S]], 10
-; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[Y]], 32768
-; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[TMP1]], 16
+; CHECK-NEXT:    [[Y:%.*]] = add nsw i32 [[S]], 32
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[Y]], 6
 ; CHECK-NEXT:    ret i32 [[C]]
 ;
   %s = sext i16 %x to i32
diff --git a/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll
index 09d35c2cfa2c3b..66f0e93b89992a 100644
--- a/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll
+++ b/llvm/test/Transforms/InstCombine/RISCV/lshr-trunc-sext-to-ashr-sext.ll
@@ -18,9 +18,8 @@ define i32 @t1(i16 %x) {
 ; CHECK-LABEL: define i32 @t1(
 ; CHECK-SAME: i16 [[X:%.*]]) {
 ; CHECK-NEXT:    [[S:%.*]] = sext i16 [[X]] to i32
-; CHECK-NEXT:    [[Y:%.*]] = shl nsw i32 [[S]], 10
-; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[Y]], 32768
-; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[TMP1]], 16
+; CHECK-NEXT:    [[Y:%.*]] = add nsw i32 [[S]], 32
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[Y]], 6
 ; CHECK-NEXT:    ret i32 [[C]]
 ;
   %s = sext i16 %x to i32
diff --git a/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll b/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll
index 852b6bc0daefea..c08fa0944487ca 100644
--- a/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll
+++ b/llvm/test/Transforms/InstCombine/X86/lshr-trunc-sext-to-ashr-sext.ll
@@ -18,9 +18,8 @@ define i32 @t1(i16 %x) {
 ; CHECK-LABEL: define i32 @t1(
 ; CHECK-SAME: i16 [[X:%.*]]) {
 ; CHECK-NEXT:    [[S:%.*]] = sext i16 [[X]] to i32
-; CHECK-NEXT:    [[Y:%.*]] = shl nsw i32 [[S]], 10
-; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[Y]], 32768
-; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[TMP1]], 16
+; CHECK-NEXT:    [[Y:%.*]] = add nsw i32 [[S]], 32
+; CHECK-NEXT:    [[C:%.*]] = ashr i32 [[Y]], 6
 ; CHECK-NEXT:    ret i32 [[C]]
 ;
   %s = sext i16 %x to i32



More information about the llvm-branch-commits mailing list