[llvm] [SPIRV] Evaluate G_ZEXT fewerElementsIf before vector size legality rules (PR #219017)
Farzon Lotfi via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 12:01:08 PDT 2026
https://github.com/farzonl created https://github.com/llvm/llvm-project/pull/219017
fixes #218444 for power of 2 vectors
So what is going on here is after we legalized the FCMP and ICMP instructions the SPIRV legalizer has two legalization paths. One path for power of 2 based vectors and one for non power of 2 based vectors. The previous fix only exercised the non power of 2 based vectors which is why we saw 3x3 and 4x3 based matrix types light up.
The power of 2 based case needs to know through the whole data flow that their vector is to large if we hit an instruction that says it isn't then the merge/unmerge artifacts can't combine away.
So these 4x4 and 4x2 cases did not light up because the legalizer assumes we don't need to split these cases. it hit Zext since HLSL bools are converted from i1s to i32s. the Zext instruction needs to legalize the size before looking at legal vector sizes because those legal vector sizes include opencl vector sizes. The fix was to change the legal rule ordering.
>From 4307ca5d2cc32cc1e3fbc71c92cb7a6cf42742c6 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzon at farzon.org>
Date: Wed, 26 Aug 2026 14:44:15 -0400
Subject: [PATCH] [SPIRV] Evaluate G_ZEXT fewerElementsIf before vector size
legality rules
fixes #218444 for power of 2 vectors
So what is going on here is after we legalized the FCMP and ICMP
instructions the SPIRV legalizer has two legalization paths. One path
for power of 2 based vectors and one for non power of 2 based vectors.
The previous fix only exercised the non power of 2 based vectors
which is why we saw 3x3 and 4x3 based matrix types light up. The
power of 2 based case did not light up because it hit Zext since
HLSL bools are converted from i1s to i32s. the Zext instruction
needs to legalize the size befor looking at legal vector sizes because
those legal vector sizes include opencl vector sizes. The fix was
to change the ordering.
---
llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 6 +--
.../legalization/matrix-wide-vector-shader.ll | 48 +++++++++++++++++++
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index e32d720aed8f7..fde1cc02900d1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -360,12 +360,12 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
.legalIf(ExtendedScalarsAndVectorsProduct);
getActionDefinitionsBuilder({G_TRUNC, G_ZEXT, G_SEXT, G_ANYEXT})
- .legalForCartesianProduct(allScalarsAndVectors)
- .legalIf(ExtendedScalarsAndVectorsProduct)
.moreElementsToNextPow2(0)
.fewerElementsIf(vectorElementCountIsGreaterThan(0, MaxVectorSize),
LegalizeMutations::changeElementCountTo(
- 0, ElementCount::getFixed(MaxVectorSize)));
+ 0, ElementCount::getFixed(MaxVectorSize)))
+ .legalForCartesianProduct(allScalarsAndVectors)
+ .legalIf(ExtendedScalarsAndVectorsProduct);
getActionDefinitionsBuilder(G_SEXT_INREG)
.moreElementsToNextPow2(0)
diff --git a/llvm/test/CodeGen/SPIRV/legalization/matrix-wide-vector-shader.ll b/llvm/test/CodeGen/SPIRV/legalization/matrix-wide-vector-shader.ll
index 0d054b6ef3338..8ffc963e77238 100644
--- a/llvm/test/CodeGen/SPIRV/legalization/matrix-wide-vector-shader.ll
+++ b/llvm/test/CodeGen/SPIRV/legalization/matrix-wide-vector-shader.ll
@@ -4,6 +4,9 @@
@Ints9 = internal addrspace(10) global [9 x i32] poison
@Ints9B = internal addrspace(10) global [9 x i32] poison
@Bools9 = internal addrspace(10) global [9 x i32] poison
+ at Ints8 = internal addrspace(10) global [8 x i32] poison
+ at Ints8B = internal addrspace(10) global [8 x i32] poison
+ at Bools8 = internal addrspace(10) global [8 x i32] poison
@Floats9 = internal addrspace(10) global [9 x float] poison
@Floats9B = internal addrspace(10) global [9 x float] poison
@Ints12 = internal addrspace(10) global [12 x i32] poison
@@ -12,7 +15,11 @@
@Floats12 = internal addrspace(10) global [12 x float] poison
@Floats12B = internal addrspace(10) global [12 x float] poison
@Ints16 = internal addrspace(10) global [16 x i32] poison
+ at Ints16B = internal addrspace(10) global [16 x i32] poison
@Bools16 = internal addrspace(10) global [16 x i32] poison
+ at Floats16 = internal addrspace(10) global [16 x float] poison
+ at Floats16B = internal addrspace(10) global [16 x float] poison
+ at BoolBits16 = internal addrspace(10) global [16 x i1] poison
; CHECK-DAG: %[[Bool:[0-9]+]] = OpTypeBool
; CHECK-DAG: %[[Int32:[0-9]+]] = OpTypeInt 32 0
@@ -196,6 +203,18 @@ define internal void @narrow_12elem_zext() {
ret void
}
+; Standalone G_ZEXT regression: the wide result must be split before the
+; Cartesian-product legality rule accepts it.
+; CHECK-LABEL: ; -- Begin function zext_16elem
+; CHECK-COUNT-16: OpSelect %[[Int32]]
+; CHECK-NOT: OpSelect %[[Int32]]
+define internal void @zext_16elem() {
+ %bits = load <16 x i1>, ptr addrspace(10) @BoolBits16
+ %ext = zext <16 x i1> %bits to <16 x i32>
+ store <16 x i32> %ext, ptr addrspace(10) @Bools16
+ ret void
+}
+
; CHECK-LABEL: ; -- Begin function narrow_16elem_sext
; CHECK: %[[Shl0:[0-9]+]] = OpShiftLeftLogical %[[Vec4Int32]]
; CHECK-NEXT: %{{[0-9]+}} = OpShiftRightArithmetic %[[Vec4Int32]] %[[Shl0]]
@@ -216,6 +235,32 @@ define internal void @narrow_16elem_sext() {
;--- G_ICMP/G_FCMP: split the flattened matrix into 4-lane comparisons ---
+; CHECK-LABEL: ; -- Begin function icmp_8elem
+; CHECK-COUNT-2: OpIEqual %[[Vec4Bool]]
+; CHECK-COUNT-2: OpSelect %[[Vec4Int32]]
+; CHECK-NOT: OpIEqual
+define internal void @icmp_8elem() {
+ %a = load <8 x i32>, ptr addrspace(10) @Ints8
+ %b = load <8 x i32>, ptr addrspace(10) @Ints8B
+ %cmp = icmp eq <8 x i32> %a, %b
+ %ext = zext <8 x i1> %cmp to <8 x i32>
+ store <8 x i32> %ext, ptr addrspace(10) @Bools8
+ ret void
+}
+
+; CHECK-LABEL: ; -- Begin function fcmp_16elem
+; CHECK-COUNT-4: OpFOrdEqual %[[Vec4Bool]]
+; CHECK-COUNT-4: OpSelect %[[Vec4Int32]]
+; CHECK-NOT: OpFOrdEqual
+define internal void @fcmp_16elem() {
+ %a = load <16 x float>, ptr addrspace(10) @Floats16
+ %b = load <16 x float>, ptr addrspace(10) @Floats16B
+ %cmp = fcmp oeq <16 x float> %a, %b
+ %ext = zext <16 x i1> %cmp to <16 x i32>
+ store <16 x i32> %ext, ptr addrspace(10) @Bools16
+ ret void
+}
+
; CHECK-LABEL: ; -- Begin function icmp_3x3
; CHECK-COUNT-8: OpLoad %[[Int32]]
; CHECK: %[[ICMP_AS:[0-9]+]] = OpLoad %[[Int32]]
@@ -312,6 +357,9 @@ define void @main() #0 {
call void @bool4x4_sext()
call void @narrow_12elem_zext()
call void @narrow_16elem_sext()
+ call void @zext_16elem()
+ call void @icmp_8elem()
+ call void @fcmp_16elem()
call void @icmp_3x3()
call void @icmp_12elem()
call void @fcmp_3x3()
More information about the llvm-commits
mailing list