[llvm] [HLSL][SPIRV] Codegen unbound array as OpTypeRuntimeArray (PR #185551)

via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 10 18:57:36 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>
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/6] 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/6] 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/6] 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/6] 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/6] 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/6] 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(



More information about the llvm-commits mailing list