[llvm] [SPIR-V] Legalize G_PHI of oversized vectors via fewer-elements (PR #203993)

Faijul Amin via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 16 08:37:11 PDT 2026


https://github.com/mdfaijul updated https://github.com/llvm/llvm-project/pull/203993

>From b0ff99d99eb06b019a1bc3b9dd92053911dca612 Mon Sep 17 00:00:00 2001
From: Faijul Amin <md.faijul.amin at intel.com>
Date: Mon, 15 Jun 2026 12:35:04 -0700
Subject: [PATCH 1/2] [SPIRV] Legalize G_PHI of oversized vectors via
 fewer-elements

Without a fewer-elements rule on G_PHI, a phi of a vector wider than
the SPIR-V max vector size (16 for Kernel+Vector16, 4 for Shader) fails
legalization with "unable to legalize instruction: G_PHI". Add a
fewerElementsIf rule that splits oversized vector PHIs to MaxVectorSize,
matching the pattern already used for other vector ops in this file,
and round up to the next power-of-two element count first so odd widths
land on a legal lane count.

Assisted by: Claude Opus 4.7 (1M context)
---
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  |  6 ++-
 .../SPIRV/instructions/phi-large-vector.ll    | 42 +++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 6c9b7eb2ef37e..c229f2e6aeb3b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -355,7 +355,11 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
 
   getActionDefinitionsBuilder(G_PHI)
       .legalFor(allPtrsScalarsAndVectors)
-      .legalIf(extendedPtrsScalarsAndVectors);
+      .legalIf(extendedPtrsScalarsAndVectors)
+      .moreElementsToNextPow2(0)
+      .fewerElementsIf(vectorElementCountIsGreaterThan(0, MaxVectorSize),
+                       LegalizeMutations::changeElementCountTo(
+                           0, ElementCount::getFixed(MaxVectorSize)));
 
   getActionDefinitionsBuilder(G_BITCAST).legalIf(
       all(typeInSet(0, allPtrsScalarsAndVectors),
diff --git a/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll b/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll
new file mode 100644
index 0000000000000..1f6058b0fd7ca
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll
@@ -0,0 +1,42 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; A G_PHI on a vector wider than the SPIR-V max (16) must be split into
+; multiple PHIs of the largest legal width.
+
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#V16:]] = OpTypeVector %[[#I32]] 16
+; CHECK: OpPhi %[[#V16]]
+; CHECK: OpPhi %[[#V16]]
+
+define spir_kernel void @phi_v32(ptr addrspace(1) %out, i1 %cond,
+                                 <16 x i32> %a, <16 x i32> %b) {
+entry:
+  %wide_a = shufflevector <16 x i32> %a, <16 x i32> %b,
+              <32 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7,
+                          i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15,
+                          i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23,
+                          i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31>
+  %wide_b = shufflevector <16 x i32> %b, <16 x i32> %a,
+              <32 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7,
+                          i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15,
+                          i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23,
+                          i32 24, i32 25, i32 26, i32 27, i32 28, i32 29, i32 30, i32 31>
+  br i1 %cond, label %then, label %else
+
+then:
+  br label %merge
+
+else:
+  br label %merge
+
+merge:
+  %p = phi <32 x i32> [ %wide_a, %then ], [ %wide_b, %else ]
+  %sum = call i32 @llvm.vector.reduce.add.v32i32(<32 x i32> %p)
+  store i32 %sum, ptr addrspace(1) %out, align 4
+  ret void
+}
+
+declare i32 @llvm.vector.reduce.add.v32i32(<32 x i32>)

>From 69a34053e8f6313eb0b1bdeac5de307e43f02230 Mon Sep 17 00:00:00 2001
From: Faijul Amin <md.faijul.amin at intel.com>
Date: Tue, 16 Jun 2026 08:31:00 -0700
Subject: [PATCH 2/2] Update test with phi uses

---
 llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll b/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll
index 1f6058b0fd7ca..43ab5b127ad54 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/phi-large-vector.ll
@@ -8,8 +8,10 @@
 
 ; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
 ; CHECK-DAG: %[[#V16:]] = OpTypeVector %[[#I32]] 16
-; CHECK: OpPhi %[[#V16]]
-; CHECK: OpPhi %[[#V16]]
+; CHECK: %[[#PHI_LO:]] = OpPhi %[[#V16]]
+; CHECK: %[[#PHI_HI:]] = OpPhi %[[#V16]]
+; CHECK: OpCompositeExtract %[[#I32]] %[[#PHI_HI]]
+; CHECK: OpIAdd %[[#V16]] %[[#PHI_LO]]
 
 define spir_kernel void @phi_v32(ptr addrspace(1) %out, i1 %cond,
                                  <16 x i32> %a, <16 x i32> %b) {



More information about the llvm-commits mailing list