[llvm] [AggressiveInstCombine] Add shufflevector support to TruncInstCombine (PR #220218)

Laxman Gupta via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 06:55:31 PDT 2026


https://github.com/laxman-gupta1006 updated https://github.com/llvm/llvm-project/pull/220218

>From a2b40c90982b5b5d16b275d8c4cf87531d51a8a7 Mon Sep 17 00:00:00 2001
From: laxman-gupta1006 <laxman.gupta1006 at gmail.com>
Date: Tue, 1 Sep 2026 16:39:01 +0530
Subject: [PATCH 1/2] [test] Update TruncInstCombine tests to show
 shufflevector optimization

Update test expectations for shufflevector patterns in TruncInstCombine.
Tests now show optimized behavior with reduced bitwidth operations.
---
 .../AggressiveInstCombine/trunc_vector_instrs.ll | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/llvm/test/Transforms/AggressiveInstCombine/trunc_vector_instrs.ll b/llvm/test/Transforms/AggressiveInstCombine/trunc_vector_instrs.ll
index fd84dce33c092..5099c07bf37a6 100644
--- a/llvm/test/Transforms/AggressiveInstCombine/trunc_vector_instrs.ll
+++ b/llvm/test/Transforms/AggressiveInstCombine/trunc_vector_instrs.ll
@@ -3,10 +3,9 @@
 
 define <4 x i16> @shuffle(<2 x i8> %a, <2 x i8> %b) {
 ; CHECK-LABEL: @shuffle(
-; CHECK-NEXT:    [[ZEXTA:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[ZEXTB:%.*]] = zext <2 x i8> [[B:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i32> [[ZEXTA]], <2 x i32> [[ZEXTB]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <4 x i32> [[SHUF]] to <4 x i16>
+; CHECK-NEXT:    [[ZEXTA:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[ZEXTB:%.*]] = zext <2 x i8> [[B:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[TRUNC:%.*]] = shufflevector <2 x i16> [[ZEXTA]], <2 x i16> [[ZEXTB]], <4 x i32> <i32 3, i32 2, i32 1, i32 0>
 ; CHECK-NEXT:    ret <4 x i16> [[TRUNC]]
 ;
   %zexta = zext <2 x i8> %a to <2 x i32>
@@ -18,9 +17,8 @@ define <4 x i16> @shuffle(<2 x i8> %a, <2 x i8> %b) {
 
 define <2 x i16> @unary_shuffle(<2 x i8> %a) {
 ; CHECK-LABEL: @unary_shuffle(
-; CHECK-NEXT:    [[ZEXTA:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i32> [[ZEXTA]], <2 x i32> poison, <2 x i32> <i32 1, i32 0>
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i32> [[SHUF]] to <2 x i16>
+; CHECK-NEXT:    [[ZEXTA:%.*]] = zext <2 x i8> [[A:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[TRUNC:%.*]] = shufflevector <2 x i16> [[ZEXTA]], <2 x i16> poison, <2 x i32> <i32 1, i32 0>
 ; CHECK-NEXT:    ret <2 x i16> [[TRUNC]]
 ;
   %zexta = zext <2 x i8> %a to <2 x i32>
@@ -31,9 +29,7 @@ define <2 x i16> @unary_shuffle(<2 x i8> %a) {
 
 define <4 x i16> @const_shuffle() {
 ; CHECK-LABEL: @const_shuffle(
-; CHECK-NEXT:    [[SHUF:%.*]] = shufflevector <2 x i32> <i32 1, i32 2>, <2 x i32> <i32 3, i32 7>, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <4 x i32> [[SHUF]] to <4 x i16>
-; CHECK-NEXT:    ret <4 x i16> [[TRUNC]]
+; CHECK-NEXT:    ret <4 x i16> <i16 7, i16 3, i16 2, i16 1>
 ;
   %shuf = shufflevector <2 x i32> <i32 1, i32 2>, <2 x i32> <i32 3, i32 7>, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
   %trunc = trunc <4 x i32> %shuf to <4 x i16>

>From d728aa0729a675381ca14b23e1ccd1583b3a6dd7 Mon Sep 17 00:00:00 2001
From: laxman-gupta1006 <laxman.gupta1006 at gmail.com>
Date: Tue, 1 Sep 2026 16:39:37 +0530
Subject: [PATCH 2/2] [AggressiveInstCombine] Add shufflevector support to
 TruncInstCombine

This patch extends TruncInstCombine to handle shufflevector operations,
enabling expression graphs containing shuffle operations to be reduced to
smaller bit-widths.

Changes:
1. isRelevantOperand() - Mark shufflevector operands as relevant to the
   optimization graph (line ~76)
2. buildTruncExpressionGraph() - Add shufflevector to expression DAG
   traversal and remove from TODO list (line ~152)
3. ReduceExpressionGraph() - Implement shufflevector IR generation for
   reduced-bitwidth operations, preserving the original shuffle mask
   (line ~470)

Example optimization:
Before: zext to i32 -> shuffle i32 -> trunc to i16
After:  zext to i16 -> shuffle i16 (no trunc needed)

This closes the shufflevector TODO in the pass and improves optimization
for vectorized code patterns.
---
 .../AggressiveInstCombine/TruncInstCombine.cpp   | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp
index e07012938e09c..4b29e33c2e7f7 100644
--- a/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp
+++ b/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp
@@ -73,6 +73,8 @@ static bool isRelevantOperand(const Instruction *I, unsigned OpNo) {
     return OpNo != 0;
   case Instruction::PHI:
     return true;
+  case Instruction::ShuffleVector:
+    return true;
   default:
     llvm_unreachable("Unreachable!");
   }
@@ -147,7 +149,8 @@ bool TruncInstCombine::buildTruncExpressionGraph() {
     case Instruction::URem:
     case Instruction::InsertElement:
     case Instruction::ExtractElement:
-    case Instruction::Select: {
+    case Instruction::Select:
+    case Instruction::ShuffleVector: {
       SmallVector<Value *, 2> Operands;
       getRelevantOperands(I, Operands);
       append_range(Worklist, Operands);
@@ -164,8 +167,7 @@ bool TruncInstCombine::buildTruncExpressionGraph() {
     }
     default:
       // TODO: Can handle more cases here:
-      // 1. shufflevector
-      // 2. sdiv, srem
+      // 1. sdiv, srem
       // ...
       return false;
     }
@@ -352,7 +354,6 @@ Type *TruncInstCombine::getBestTruncatedType() {
   if (MinBitWidth >= OrigBitWidth ||
       (DesiredBitWidth && DesiredBitWidth != MinBitWidth))
     return nullptr;
-
   return IntegerType::get(CurrentTruncInst->getContext(), MinBitWidth);
 }
 
@@ -466,6 +467,13 @@ void TruncInstCombine::ReduceExpressionGraph(Type *SclTy) {
       Res = Builder.CreateSelect(Op0, LHS, RHS, "", I);
       break;
     }
+    case Instruction::ShuffleVector: {
+      Value *LHS = getReducedOperand(I->getOperand(0), SclTy);
+      Value *RHS = getReducedOperand(I->getOperand(1), SclTy);
+      auto *SI = cast<ShuffleVectorInst>(I);
+      Res = Builder.CreateShuffleVector(LHS, RHS, SI->getShuffleMask());
+      break;
+    }
     case Instruction::PHI: {
       Res = Builder.CreatePHI(getReducedType(I, SclTy), I->getNumOperands());
       OldNewPHINodes.push_back(



More information about the llvm-commits mailing list