Skip to content

Conversation

@topperc
Copy link
Collaborator

@topperc topperc commented Nov 19, 2025

We can constant fold interleave of identical splat vectors to a larger splat vector.

@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Nov 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 19, 2025

@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: Craig Topper (topperc)

Changes

We can constant fold interleave of identical splat vectors to a larger splat vector.


Full diff: https://github.com/llvm/llvm-project/pull/168668.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ConstantFolding.cpp (+16)
  • (modified) llvm/test/Transforms/InstSimplify/ConstProp/vector-calls.ll (+112)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
old mode 100755
new mode 100644
index a13df6c5bf552..e1bbcec306edc
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -4307,6 +4307,22 @@ static Constant *ConstantFoldScalableVectorCall(
       return ConstantVector::getNullValue(SVTy);
     break;
   }
+  case Intrinsic::vector_interleave2:
+  case Intrinsic::vector_interleave3:
+  case Intrinsic::vector_interleave4:
+  case Intrinsic::vector_interleave5:
+  case Intrinsic::vector_interleave6:
+  case Intrinsic::vector_interleave7:
+  case Intrinsic::vector_interleave8: {
+    Constant *SplatVal = Operands[0]->getSplatValue();
+    if (!SplatVal)
+      return nullptr;
+
+    if (!llvm::all_equal(Operands))
+      return nullptr;
+
+    return ConstantVector::getSplat(SVTy->getElementCount(), SplatVal);
+  }
   default:
     break;
   }
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/vector-calls.ll b/llvm/test/Transforms/InstSimplify/ConstProp/vector-calls.ll
index 848f0d17ff373..2d8a444141a2b 100644
--- a/llvm/test/Transforms/InstSimplify/ConstProp/vector-calls.ll
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/vector-calls.ll
@@ -51,6 +51,22 @@ define <8 x i32> @fold_vector_interleave2() {
   ret <8 x i32> %1
 }
 
+define <vscale x 8 x i32> @fold_scalable_vector_interleave2() {
+; CHECK-LABEL: define <vscale x 8 x i32> @fold_scalable_vector_interleave2() {
+; CHECK-NEXT:    ret <vscale x 8 x i32> zeroinitializer
+;
+  %1 = call <vscale x 8 x i32> @llvm.vector.interleave2.nxv8i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 8 x i32> %1
+}
+
+define <vscale x 8 x i32> @fold_scalable_vector_interleave2_splat() {
+; CHECK-LABEL: define <vscale x 8 x i32> @fold_scalable_vector_interleave2_splat() {
+; CHECK-NEXT:    ret <vscale x 8 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 8 x i32> @llvm.vector.interleave2.nxv8i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 8 x i32> %1
+}
+
 define <12 x i32> @fold_vector_interleave3() {
 ; CHECK-LABEL: define <12 x i32> @fold_vector_interleave3() {
 ; CHECK-NEXT:    ret <12 x i32> <i32 1, i32 5, i32 9, i32 2, i32 6, i32 10, i32 3, i32 7, i32 11, i32 4, i32 8, i32 12>
@@ -59,6 +75,22 @@ define <12 x i32> @fold_vector_interleave3() {
   ret <12 x i32> %1
 }
 
+define <vscale x 12 x i32> @fold_scalable_vector_interleave3() {
+; CHECK-LABEL: define <vscale x 12 x i32> @fold_scalable_vector_interleave3() {
+; CHECK-NEXT:    ret <vscale x 12 x i32> zeroinitializer
+;
+  %1 = call <vscale x 12 x i32> @llvm.vector.interleave3.nxv8i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 12 x i32> %1
+}
+
+define <vscale x 12 x i32> @fold_scalable_vector_interleave3_splat() {
+; CHECK-LABEL: define <vscale x 12 x i32> @fold_scalable_vector_interleave3_splat() {
+; CHECK-NEXT:    ret <vscale x 12 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 12 x i32> @llvm.vector.interleave3.nxv8i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 12 x i32> %1
+}
+
 define <16 x i32> @fold_vector_interleave4() {
 ; CHECK-LABEL: define <16 x i32> @fold_vector_interleave4() {
 ; CHECK-NEXT:    ret <16 x i32> <i32 1, i32 5, i32 9, i32 13, i32 2, i32 6, i32 10, i32 14, i32 3, i32 7, i32 11, i32 15, i32 4, i32 8, i32 12, i32 16>
@@ -67,6 +99,22 @@ define <16 x i32> @fold_vector_interleave4() {
   ret <16 x i32> %1
 }
 
+define <vscale x 16 x i32> @fold_scalable_vector_interleave4() {
+; CHECK-LABEL: define <vscale x 16 x i32> @fold_scalable_vector_interleave4() {
+; CHECK-NEXT:    ret <vscale x 16 x i32> zeroinitializer
+;
+  %1 = call <vscale x 16 x i32> @llvm.vector.interleave4.nxv16i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 16 x i32> %1
+}
+
+define <vscale x 16 x i32> @fold_scalable_vector_interleave4_splat() {
+; CHECK-LABEL: define <vscale x 16 x i32> @fold_scalable_vector_interleave4_splat() {
+; CHECK-NEXT:    ret <vscale x 16 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 16 x i32> @llvm.vector.interleave4.nxv16i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 16 x i32> %1
+}
+
 define <20 x i32> @fold_vector_interleave5() {
 ; CHECK-LABEL: define <20 x i32> @fold_vector_interleave5() {
 ; CHECK-NEXT:    ret <20 x i32> <i32 1, i32 5, i32 9, i32 13, i32 17, i32 2, i32 6, i32 10, i32 14, i32 18, i32 3, i32 7, i32 11, i32 15, i32 19, i32 4, i32 8, i32 12, i32 16, i32 20>
@@ -75,6 +123,22 @@ define <20 x i32> @fold_vector_interleave5() {
   ret <20 x i32> %1
 }
 
+define <vscale x 20 x i32> @fold_scalable_vector_interleave5() {
+; CHECK-LABEL: define <vscale x 20 x i32> @fold_scalable_vector_interleave5() {
+; CHECK-NEXT:    ret <vscale x 20 x i32> zeroinitializer
+;
+  %1 = call <vscale x 20 x i32> @llvm.vector.interleave5.nxv20i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 20 x i32> %1
+}
+
+define <vscale x 20 x i32> @fold_scalable_vector_interleave5_splat() {
+; CHECK-LABEL: define <vscale x 20 x i32> @fold_scalable_vector_interleave5_splat() {
+; CHECK-NEXT:    ret <vscale x 20 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 20 x i32> @llvm.vector.interleave5.nxv20i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 20 x i32> %1
+}
+
 define <24 x i32> @fold_vector_interleave6() {
 ; CHECK-LABEL: define <24 x i32> @fold_vector_interleave6() {
 ; CHECK-NEXT:    ret <24 x i32> <i32 1, i32 5, i32 9, i32 13, i32 17, i32 21, i32 2, i32 6, i32 10, i32 14, i32 18, i32 22, i32 3, i32 7, i32 11, i32 15, i32 19, i32 23, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24>
@@ -83,6 +147,22 @@ define <24 x i32> @fold_vector_interleave6() {
   ret <24 x i32> %1
 }
 
+define <vscale x 24 x i32> @fold_scalable_vector_interleave6() {
+; CHECK-LABEL: define <vscale x 24 x i32> @fold_scalable_vector_interleave6() {
+; CHECK-NEXT:    ret <vscale x 24 x i32> zeroinitializer
+;
+  %1 = call <vscale x 24 x i32> @llvm.vector.interleave6.nxv24i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 24 x i32> %1
+}
+
+define <vscale x 24 x i32> @fold_scalable_vector_interleave6_splat() {
+; CHECK-LABEL: define <vscale x 24 x i32> @fold_scalable_vector_interleave6_splat() {
+; CHECK-NEXT:    ret <vscale x 24 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 24 x i32> @llvm.vector.interleave6.nxv24i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 24 x i32> %1
+}
+
 define <28 x i32> @fold_vector_interleave7() {
 ; CHECK-LABEL: define <28 x i32> @fold_vector_interleave7() {
 ; CHECK-NEXT:    ret <28 x i32> <i32 1, i32 5, i32 9, i32 13, i32 17, i32 21, i32 25, i32 2, i32 6, i32 10, i32 14, i32 18, i32 22, i32 26, i32 3, i32 7, i32 11, i32 15, i32 19, i32 23, i32 27, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24, i32 28>
@@ -91,6 +171,22 @@ define <28 x i32> @fold_vector_interleave7() {
   ret <28 x i32> %1
 }
 
+define <vscale x 28 x i32> @fold_scalable_vector_interleave7() {
+; CHECK-LABEL: define <vscale x 28 x i32> @fold_scalable_vector_interleave7() {
+; CHECK-NEXT:    ret <vscale x 28 x i32> zeroinitializer
+;
+  %1 = call <vscale x 28 x i32> @llvm.vector.interleave7.nxv28i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 28 x i32> %1
+}
+
+define <vscale x 28 x i32> @fold_scalable_vector_interleave7_splat() {
+; CHECK-LABEL: define <vscale x 28 x i32> @fold_scalable_vector_interleave7_splat() {
+; CHECK-NEXT:    ret <vscale x 28 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 28 x i32> @llvm.vector.interleave7.nxv28i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 28 x i32> %1
+}
+
 define <32 x i32> @fold_vector_interleave8() {
 ; CHECK-LABEL: define <32 x i32> @fold_vector_interleave8() {
 ; CHECK-NEXT:    ret <32 x i32> <i32 1, i32 5, i32 9, i32 13, i32 17, i32 21, i32 25, i32 29, i32 2, i32 6, i32 10, i32 14, i32 18, i32 22, i32 26, i32 30, i32 3, i32 7, i32 11, i32 15, i32 19, i32 23, i32 27, i32 31, i32 4, i32 8, i32 12, i32 16, i32 20, i32 24, i32 28, i32 32>
@@ -99,6 +195,22 @@ define <32 x i32> @fold_vector_interleave8() {
   ret <32 x i32> %1
 }
 
+define <vscale x 32 x i32> @fold_scalable_vector_interleave8() {
+; CHECK-LABEL: define <vscale x 32 x i32> @fold_scalable_vector_interleave8() {
+; CHECK-NEXT:    ret <vscale x 32 x i32> zeroinitializer
+;
+  %1 = call <vscale x 32 x i32> @llvm.vector.interleave8.nxv32i32(<vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> zeroinitializer)
+  ret <vscale x 32 x i32> %1
+}
+
+define <vscale x 32 x i32> @fold_scalable_vector_interleave8_splat() {
+; CHECK-LABEL: define <vscale x 32 x i32> @fold_scalable_vector_interleave8_splat() {
+; CHECK-NEXT:    ret <vscale x 32 x i32> splat (i32 1)
+;
+  %1 = call <vscale x 32 x i32> @llvm.vector.interleave8.nxv32i32(<vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1), <vscale x 4 x i32> splat (i32 1))
+  ret <vscale x 32 x i32> %1
+}
+
 define {<4 x i32>, <4 x i32>} @fold_vector_deinterleave2() {
 ; CHECK-LABEL: define { <4 x i32>, <4 x i32> } @fold_vector_deinterleave2() {
 ; CHECK-NEXT:    ret { <4 x i32>, <4 x i32> } { <4 x i32> <i32 1, i32 2, i32 3, i32 4>, <4 x i32> <i32 5, i32 6, i32 7, i32 8> }

@github-actions
Copy link

github-actions bot commented Nov 19, 2025

🐧 Linux x64 Test Results

  • 186403 tests passed
  • 4864 tests skipped

Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG

Copy link
Collaborator

@preames preames left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM w/additional tests added.

@topperc topperc force-pushed the pr/constant-fold-scalable-interleave branch from d49c0db to 44f277a Compare November 19, 2025 17:59
@topperc topperc force-pushed the pr/constant-fold-scalable-interleave branch from 44f277a to d7c17ce Compare November 19, 2025 19:26
@topperc topperc merged commit 8830525 into llvm:main Nov 19, 2025
8 of 9 checks passed
@topperc topperc deleted the pr/constant-fold-scalable-interleave branch November 19, 2025 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants