[llvm] [HLSL][SPIRV] Codegen unbound array as OpTypeRuntimeArray (PR #185551)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 10 18:55:48 PDT 2026
=?utf-8?q?João?= Saffran <joaosaffranllvm at gmail.com>,Joao Saffran
<joaosaffranllvm at gmail.com>,
=?utf-8?q?João?= Saffran <joaosaffranllvm at gmail.com>,Joao Saffran
<joaosaffranllvm at gmail.com>,Joao Saffran <joaosaffranllvm at gmail.com>,
=?utf-8?q?João?= Saffran <joaosaffranllvm at gmail.com>,Joao Saffran
<joaosaffranllvm at gmail.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/185551 at github.com>
https://github.com/joaosaffran updated https://github.com/llvm/llvm-project/pull/185551
>From 3b597e52fe579240687db1aa72920c454bd54131 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Saffran?= <joaosaffranllvm at gmail.com>
Date: Thu, 5 Mar 2026 14:53:16 -0800
Subject: [PATCH 1/9] add 16 bit case
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 21 ++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 7b4c047593a3a..bfaf861747612 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3081,11 +3081,30 @@ bool SPIRVInstructionSelector::selectWaveExclusiveScan(
bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
SPIRVTypeInst ResType,
MachineInstr &I) const {
+ Register OpReg = I.getOperand(1).getReg();
+
+ if (GR.getScalarOrVectorBitWidth(ResType) == 16) {
+ SPIRVTypeInst IntType = GR.getOrCreateSPIRVIntegerType(32, I, TII);
+ unsigned N = GR.getScalarOrVectorComponentCount(ResType);
+ if (N > 1)
+ IntType = GR.getOrCreateSPIRVVectorType(ResType, N, I, TII);
+
+ OpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
+ unsigned ExtendOpcode =
+ sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ResType))
+ ? SPIRV::OpSConvert
+ : SPIRV::OpUConvert;
+ if (!selectOpWithSrcs(OpReg, IntType, I, {I.getOperand(1).getReg()},
+ ExtendOpcode))
+ return false;
+ ResType = IntType;
+ }
+
MachineBasicBlock &BB = *I.getParent();
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
- .addUse(I.getOperand(1).getReg())
+ .addUse(OpReg)
.constrainAllUses(TII, TRI, RBI);
return true;
}
>From edb30c0ad4938969f4f71a48a4374fef622dcbf4 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Thu, 5 Mar 2026 15:22:50 -0800
Subject: [PATCH 2/9] fix incorrect function usage & update test reversebits.ll
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 7 +++----
.../test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll | 11 +++++++++--
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index bfaf861747612..fd53bab28b4d8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3090,10 +3090,9 @@ bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
IntType = GR.getOrCreateSPIRVVectorType(ResType, N, I, TII);
OpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
- unsigned ExtendOpcode =
- sampledTypeIsSignedInteger(GR.getTypeForSPIRVType(ResType))
- ? SPIRV::OpSConvert
- : SPIRV::OpUConvert;
+ unsigned ExtendOpcode = GR.isScalarOrVectorSigned(ResType)
+ ? SPIRV::OpSConvert
+ : SPIRV::OpUConvert;
if (!selectOpWithSrcs(OpReg, IntType, I, {I.getOperand(1).getReg()},
ExtendOpcode))
return false;
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll
index 6571b2992fab3..77f24c72cffc6 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll
@@ -3,16 +3,23 @@
; CHECK: OpMemoryModel Logical GLSL450
+;CHECK-DAG: %[[#int_16:]] = OpTypeInt 16
+;CHECK-DAG: %[[#int_32:]] = OpTypeInt 32
+
define noundef i32 @reversebits_i32(i32 noundef %a) {
entry:
-; CHECK: %[[#]] = OpBitReverse %[[#]] %[[#]]
+; CHECK: %[[#param:]] = OpFunctionParameter %[[#int_32]]
+; CHECK-NOT: OpUConvert
+; CHECK: %[[#]] = OpBitReverse %[[#int_32]] %[[#param]]
%elt.bitreverse = call i32 @llvm.bitreverse.i32(i32 %a)
ret i32 %elt.bitreverse
}
define noundef i16 @reversebits_i16(i16 noundef %a) {
entry:
-; CHECK: %[[#]] = OpBitReverse %[[#]] %[[#]]
+; CHECK: %[[#param:]] = OpFunctionParameter %[[#int_16]]
+; CHECK: %[[#conversion:]] = OpUConvert %[[#int_32]] %[[#param]]
+; CHECK-NEXT: %[[#]] = OpBitReverse %[[#int_32]] %[[#conversion]]
%elt.bitreverse = call i16 @llvm.bitreverse.i16(i16 %a)
ret i16 %elt.bitreverse
}
>From 3c0f0e494ff1fb110df41733414c6a345a3c04cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Saffran?= <joaosaffranllvm at gmail.com>
Date: Thu, 5 Mar 2026 17:14:27 -0800
Subject: [PATCH 3/9] add composite to shift
---
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 68 ++++++++++++++-----
1 file changed, 52 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index fd53bab28b4d8..7b8dec6106142 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -188,6 +188,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
bool selectBitreverse(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I) const;
+ bool selectBitreverse16(Register ResVReg, SPIRVTypeInst ResType,
+ MachineInstr &I) const;
+
bool selectBuildVector(Register ResVReg, SPIRVTypeInst ResType,
MachineInstr &I) const;
bool selectSplatVector(Register ResVReg, SPIRVTypeInst ResType,
@@ -3078,32 +3081,65 @@ bool SPIRVInstructionSelector::selectWaveExclusiveScan(
return true;
}
+bool SPIRVInstructionSelector::selectBitreverse16(Register ResVReg,
+ SPIRVTypeInst ResType,
+ MachineInstr &I) const {
+ SPIRVTypeInst Int32Type = GR.getOrCreateSPIRVIntegerType(32, I, TII);
+
+ unsigned N = GR.getScalarOrVectorComponentCount(ResType);
+ if (N > 1)
+ Int32Type = GR.getOrCreateSPIRVVectorType(Int32Type, N, I, TII);
+
+ Register ExtReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
+ unsigned ExtendOpcode = GR.isScalarOrVectorSigned(ResType)
+ ? SPIRV::OpSConvert
+ : SPIRV::OpUConvert;
+ if (!selectOpWithSrcs(ExtReg, Int32Type, I, {I.getOperand(1).getReg()},
+ ExtendOpcode))
+ return false;
+
+ Register BitrevReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
+ if (!selectOpWithSrcs(BitrevReg, Int32Type, I, {ExtReg}, SPIRV::OpBitReverse))
+ return false;
+
+ Register ScalarShiftAmount = GR.getOrCreateConstInt(16, I, Int32Type, TII);
+
+ Register ShiftConst;
+ if (N > 1) {
+ ShiftConst = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
+ auto MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(SPIRV::OpConstantComposite))
+ .addDef(ShiftConst)
+ .addUse(GR.getSPIRVTypeID(Int32Type));
+ for (unsigned It = I.getNumExplicitDefs(); It < I.getNumExplicitOperands();
+ ++It)
+ MIB.addUse(ScalarShiftAmount);
+ MIB.constrainAllUses(TII, TRI, RBI);
+ } else {
+ ShiftConst = ScalarShiftAmount;
+ }
+
+ Register ShiftReg = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
+ if (!selectOpWithSrcs(ShiftReg, Int32Type, I, {BitrevReg, ShiftConst},
+ N > 1 ? SPIRV::OpShiftRightLogicalV
+ : SPIRV::OpShiftRightLogicalS))
+ return false;
+
+ return selectOpWithSrcs(ResVReg, ResType, I, {ShiftReg}, ExtendOpcode);
+}
+
bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
SPIRVTypeInst ResType,
MachineInstr &I) const {
- Register OpReg = I.getOperand(1).getReg();
-
if (GR.getScalarOrVectorBitWidth(ResType) == 16) {
- SPIRVTypeInst IntType = GR.getOrCreateSPIRVIntegerType(32, I, TII);
- unsigned N = GR.getScalarOrVectorComponentCount(ResType);
- if (N > 1)
- IntType = GR.getOrCreateSPIRVVectorType(ResType, N, I, TII);
-
- OpReg = MRI->createVirtualRegister(GR.getRegClass(ResType));
- unsigned ExtendOpcode = GR.isScalarOrVectorSigned(ResType)
- ? SPIRV::OpSConvert
- : SPIRV::OpUConvert;
- if (!selectOpWithSrcs(OpReg, IntType, I, {I.getOperand(1).getReg()},
- ExtendOpcode))
- return false;
- ResType = IntType;
+ return selectBitreverse16(ResVReg, ResType, I);
}
MachineBasicBlock &BB = *I.getParent();
BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpBitReverse))
.addDef(ResVReg)
.addUse(GR.getSPIRVTypeID(ResType))
- .addUse(OpReg)
+ .addUse(I.getOperand(1).getReg())
.constrainAllUses(TII, TRI, RBI);
return true;
}
>From 1f4c76b49e9a528c02790d84abd9aa9381f2a073 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Thu, 5 Mar 2026 17:36:31 -0800
Subject: [PATCH 4/9] fix composite logic
---
llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 7b8dec6106142..41bbb10da8e74 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3085,6 +3085,7 @@ bool SPIRVInstructionSelector::selectBitreverse16(Register ResVReg,
SPIRVTypeInst ResType,
MachineInstr &I) const {
SPIRVTypeInst Int32Type = GR.getOrCreateSPIRVIntegerType(32, I, TII);
+ Register ScalarShiftAmount = GR.getOrCreateConstInt(16, I, Int32Type, TII);
unsigned N = GR.getScalarOrVectorComponentCount(ResType);
if (N > 1)
@@ -3102,8 +3103,6 @@ bool SPIRVInstructionSelector::selectBitreverse16(Register ResVReg,
if (!selectOpWithSrcs(BitrevReg, Int32Type, I, {ExtReg}, SPIRV::OpBitReverse))
return false;
- Register ScalarShiftAmount = GR.getOrCreateConstInt(16, I, Int32Type, TII);
-
Register ShiftConst;
if (N > 1) {
ShiftConst = MRI->createVirtualRegister(GR.getRegClass(Int32Type));
@@ -3111,8 +3110,7 @@ bool SPIRVInstructionSelector::selectBitreverse16(Register ResVReg,
TII.get(SPIRV::OpConstantComposite))
.addDef(ShiftConst)
.addUse(GR.getSPIRVTypeID(Int32Type));
- for (unsigned It = I.getNumExplicitDefs(); It < I.getNumExplicitOperands();
- ++It)
+ for (unsigned It = 0; It < N; ++It)
MIB.addUse(ScalarShiftAmount);
MIB.constrainAllUses(TII, TRI, RBI);
} else {
>From b63d635555dc90b2e6d8e5eac42c2806bbff07c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Saffran?= <joaosaffranllvm at gmail.com>
Date: Thu, 5 Mar 2026 18:21:45 -0800
Subject: [PATCH 5/9] update test
---
.../SPIRV/hlsl-intrinsics/reversebits.ll | 23 ++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll
index 77f24c72cffc6..c1c7210b90f6a 100644
--- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/reversebits.ll
@@ -5,12 +5,18 @@
;CHECK-DAG: %[[#int_16:]] = OpTypeInt 16
;CHECK-DAG: %[[#int_32:]] = OpTypeInt 32
+;CHECK-DAG: %[[#vec_int_32:]] = OpTypeVector %[[#int_32]] 2
+;CHECK-DAG: %[[#vec_int_16:]] = OpTypeVector %[[#int_16]] 2
+
+;CHECK-DAG: %[[#const_16:]] = OpConstant %[[#int_32]] 16
+;CHECK-DAG: %[[#composite:]] = OpConstantComposite %[[#vec_int_32]] %[[#const_16]] %[[#const_16]]
define noundef i32 @reversebits_i32(i32 noundef %a) {
entry:
; CHECK: %[[#param:]] = OpFunctionParameter %[[#int_32]]
; CHECK-NOT: OpUConvert
; CHECK: %[[#]] = OpBitReverse %[[#int_32]] %[[#param]]
+; CHECK-NOT: OpShiftRightLogical
%elt.bitreverse = call i32 @llvm.bitreverse.i32(i32 %a)
ret i32 %elt.bitreverse
}
@@ -19,10 +25,25 @@ define noundef i16 @reversebits_i16(i16 noundef %a) {
entry:
; CHECK: %[[#param:]] = OpFunctionParameter %[[#int_16]]
; CHECK: %[[#conversion:]] = OpUConvert %[[#int_32]] %[[#param]]
-; CHECK-NEXT: %[[#]] = OpBitReverse %[[#int_32]] %[[#conversion]]
+; CHECK-NEXT: %[[#bitrev:]] = OpBitReverse %[[#int_32]] %[[#conversion]]
+; CHECK-NEXT: %[[#shift:]] = OpShiftRightLogical %[[#int_32]] %[[#bitrev]] %[[#const_16]]
+; CHECK-NEXT: %[[#]] = OpUConvert %[[#int_16]] %[[#shift]]
%elt.bitreverse = call i16 @llvm.bitreverse.i16(i16 %a)
ret i16 %elt.bitreverse
}
+define noundef <2 x i16> @reversebits_veci16(<2 x i16> noundef %a) {
+entry:
+; CHECK: %[[#param:]] = OpFunctionParameter %[[#vec_int_16]]
+; CHECK: %[[#conversion:]] = OpUConvert %[[#vec_int_32]] %[[#param]]
+; CHECK-NEXT: %[[#bitrev:]] = OpBitReverse %[[#vec_int_32]] %[[#conversion]]
+; CHECK-NEXT: %[[#shift:]] = OpShiftRightLogical %[[#vec_int_32]] %[[#bitrev]] %[[#composite]]
+; CHECK-NEXT: %[[#]] = OpUConvert %[[#vec_int_16]] %[[#shift]]
+ %elt.bitreverse = call <2 x i16> @llvm.bitreverse.v2i16(<2 x i16> %a)
+ ret <2 x i16> %elt.bitreverse
+}
+
+
declare i16 @llvm.bitreverse.i16(i16)
declare i32 @llvm.bitreverse.i32(i32)
+declare <2 x i16> @llvm.bitreverse.v2i16(<2 x i16>)
>From d24d74265243710dbfa8a0f30aab8a326145744e Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 9 Mar 2026 17:18:40 -0700
Subject: [PATCH 6/9] modify codegen to account for unbound arrays
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 9a85634c82626..e2a52a2a17665 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -910,7 +910,18 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeArray(uint32_t NumElems,
SPIRVTypeInst ArrayType = nullptr;
const SPIRVSubtarget &ST =
cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
- if (NumElems != 0) {
+
+ // Unbounded arrays (e.g. RWBuffer Buf[]) are represented in LLVM IR
+ // with UINT32_MAX as the element count. Lower these to OpTypeRuntimeArray
+ // instead of OpTypeArray.
+ if (NumElems == std::numeric_limits<uint32_t>::max()) {
+ ArrayType = createConstOrTypeAtFunctionEntry(
+ MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+ return MIRBuilder.buildInstr(SPIRV::OpTypeRuntimeArray)
+ .addDef(createTypeVReg(MIRBuilder))
+ .addUse(getSPIRVTypeID(ElemType));
+ });
+ } else if (NumElems != 0) {
Register NumElementsVReg =
buildConstantInt(NumElems, MIRBuilder, SpvTypeInt32, EmitIR);
ArrayType = createConstOrTypeAtFunctionEntry(
>From af0cc4133f5263d8813d62a903cc8275777dcda2 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Mon, 9 Mar 2026 17:18:40 -0700
Subject: [PATCH 7/9] modify codegen to account for unbound arrays
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 9a85634c82626..e2a52a2a17665 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -910,7 +910,18 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeArray(uint32_t NumElems,
SPIRVTypeInst ArrayType = nullptr;
const SPIRVSubtarget &ST =
cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget());
- if (NumElems != 0) {
+
+ // Unbounded arrays (e.g. RWBuffer Buf[]) are represented in LLVM IR
+ // with UINT32_MAX as the element count. Lower these to OpTypeRuntimeArray
+ // instead of OpTypeArray.
+ if (NumElems == std::numeric_limits<uint32_t>::max()) {
+ ArrayType = createConstOrTypeAtFunctionEntry(
+ MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
+ return MIRBuilder.buildInstr(SPIRV::OpTypeRuntimeArray)
+ .addDef(createTypeVReg(MIRBuilder))
+ .addUse(getSPIRVTypeID(ElemType));
+ });
+ } else if (NumElems != 0) {
Register NumElementsVReg =
buildConstantInt(NumElems, MIRBuilder, SpvTypeInt32, EmitIR);
ArrayType = createConstOrTypeAtFunctionEntry(
>From 39d6b19500a130c59f13e83c56d29f6c0e546cbd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Saffran?= <joaosaffranllvm at gmail.com>
Date: Mon, 9 Mar 2026 18:21:30 -0700
Subject: [PATCH 8/9] add missing capability
---
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index e2a52a2a17665..363c7ba6911f4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -915,6 +915,8 @@ SPIRVTypeInst SPIRVGlobalRegistry::getOpTypeArray(uint32_t NumElems,
// with UINT32_MAX as the element count. Lower these to OpTypeRuntimeArray
// instead of OpTypeArray.
if (NumElems == std::numeric_limits<uint32_t>::max()) {
+ MIRBuilder.buildInstr(SPIRV::OpCapability)
+ .addImm(SPIRV::Capability::RuntimeDescriptorArrayEXT);
ArrayType = createConstOrTypeAtFunctionEntry(
MIRBuilder, [&](MachineIRBuilder &MIRBuilder) {
return MIRBuilder.buildInstr(SPIRV::OpTypeRuntimeArray)
>From 10d29ce336715f9deba1384abab3bbe7dd6b0341 Mon Sep 17 00:00:00 2001
From: Joao Saffran <joaosaffranllvm at gmail.com>
Date: Tue, 10 Mar 2026 18:55:28 -0700
Subject: [PATCH 9/9] add test similar to offload-test failling
---
.../SPIRV/hlsl-resources/RWBuffer-array.ll | 98 +++++++++++++++++++
1 file changed, 98 insertions(+)
create mode 100644 llvm/test/CodeGen/SPIRV/hlsl-resources/RWBuffer-array.ll
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-resources/RWBuffer-array.ll b/llvm/test/CodeGen/SPIRV/hlsl-resources/RWBuffer-array.ll
new file mode 100644
index 0000000000000..3eeef2ec0034f
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-resources/RWBuffer-array.ll
@@ -0,0 +1,98 @@
+; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv1.6-vulkan1.3-library %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv1.6-vulkan1.3-library %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[int32:[0-9]+]] = OpTypeInt 32 0
+; CHECK-DAG: %[[rwbuffer:[0-9]+]] = OpTypeImage %[[int32]] Buffer 2 0 0 2 R32i
+; CHECK-DAG: OpTypeRuntimeArray %[[rwbuffer]]
+
+; This IR was emmited from the following HLSL code:
+; [[vk::binding(0)]]
+; RWBuffer<int> Buf[] : register(u0);
+;
+; [numthreads(4,2,1)]
+; void main(uint GI : SV_GroupIndex) {
+; Buf[0][0] = 0;
+; }
+
+
+%"class.hlsl::RWBuffer" = type { target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) }
+
+ at Buf.str = private unnamed_addr constant [4 x i8] c"Buf\00", align 1
+
+; Function Attrs: convergent noinline norecurse
+define void @main() #0 {
+entry:
+ %this.addr.i8 = alloca ptr, align 8
+ %other.addr.i9 = alloca ptr, align 8
+ %this.addr.i6 = alloca ptr, align 8
+ %this.addr.i4 = alloca ptr, align 8
+ %other.addr.i = alloca ptr, align 8
+ %this.addr.i2 = alloca ptr, align 8
+ %this.addr.i = alloca ptr, align 8
+ %Index.addr.i = alloca i32, align 4
+ %result.ptr.i = alloca ptr, align 8
+ %registerNo.addr.i = alloca i32, align 4
+ %spaceNo.addr.i = alloca i32, align 4
+ %range.addr.i = alloca i32, align 4
+ %index.addr.i = alloca i32, align 4
+ %name.addr.i = alloca ptr, align 8
+ %tmp.i1 = alloca %"class.hlsl::RWBuffer", align 8
+ %GI.addr.i = alloca i32, align 4
+ %tmp.i = alloca %"class.hlsl::RWBuffer", align 8
+ %0 = call token @llvm.experimental.convergence.entry()
+ %1 = call i32 @llvm.spv.flattened.thread.id.in.group()
+ store i32 %1, ptr %GI.addr.i, align 4
+ store ptr %tmp.i, ptr %result.ptr.i, align 8
+ store i32 0, ptr %registerNo.addr.i, align 4
+ store i32 0, ptr %spaceNo.addr.i, align 4
+ store i32 -1, ptr %range.addr.i, align 4
+ store i32 0, ptr %index.addr.i, align 4
+ store ptr @Buf.str, ptr %name.addr.i, align 8
+ store ptr %tmp.i1, ptr %this.addr.i2, align 8
+ %this1.i3 = load ptr, ptr %this.addr.i2, align 8
+ store ptr %this1.i3, ptr %this.addr.i6, align 8
+ %this1.i7 = load ptr, ptr %this.addr.i6, align 8
+ store target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) poison, ptr %this1.i7, align 8
+ %2 = load i32, ptr %registerNo.addr.i, align 4
+ %3 = load i32, ptr %spaceNo.addr.i, align 4
+ %4 = load i32, ptr %range.addr.i, align 4
+ %5 = load i32, ptr %index.addr.i, align 4
+ %6 = load ptr, ptr %name.addr.i, align 8
+ %7 = call target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) @llvm.spv.resource.handlefrombinding.tspirv.SignedImage_i32_5_2_0_0_2_24t(i32 %3, i32 %2, i32 %4, i32 %5, ptr %6)
+ store target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) %7, ptr %tmp.i1, align 8
+ store ptr %tmp.i, ptr %this.addr.i4, align 8
+ store ptr %tmp.i1, ptr %other.addr.i, align 8
+ %this1.i5 = load ptr, ptr %this.addr.i4, align 8
+ %8 = load ptr, ptr %other.addr.i, align 8
+ store ptr %this1.i5, ptr %this.addr.i8, align 8
+ store ptr %8, ptr %other.addr.i9, align 8
+ %this1.i10 = load ptr, ptr %this.addr.i8, align 8
+ %9 = load ptr, ptr %other.addr.i9, align 8
+ %10 = load target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24), ptr %9, align 8
+ store target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) %10, ptr %this1.i10, align 8
+ store ptr %tmp.i, ptr %this.addr.i, align 8
+ store i32 0, ptr %Index.addr.i, align 4
+ %this1.i = load ptr, ptr %this.addr.i, align 8
+ %11 = load target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24), ptr %this1.i, align 8
+ %12 = load i32, ptr %Index.addr.i, align 4
+ %13 = call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.SignedImage_i32_5_2_0_0_2_24t(target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) %11, i32 %12)
+ store i32 0, ptr addrspace(11) %13, align 4
+ ret void
+}
+
+; Function Attrs: nounwind willreturn memory(none)
+declare i32 @llvm.spv.flattened.thread.id.in.group() #2
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24) @llvm.spv.resource.handlefrombinding.tspirv.SignedImage_i32_5_2_0_0_2_24t(i32, i32, i32, i32, ptr) #3
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
+declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.SignedImage_i32_5_2_0_0_2_24t(target("spirv.SignedImage", i32, 5, 2, 0, 0, 2, 24), i32) #3
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite)
+declare void @llvm.experimental.noalias.scope.decl(metadata) #4
+
+attributes #0 = { convergent noinline norecurse "hlsl.numthreads"="4,2,1" "hlsl.shader"="compute" "no-nans-fp-math"="true" "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
+attributes #2 = { nounwind willreturn memory(none) }
+attributes #3 = { nocallback nofree nosync nounwind willreturn memory(none) }
+attributes #4 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) }
More information about the llvm-commits
mailing list