[llvm] [DirectX] Implement Max64UAVs shader flag analysis (PR #136229)

Deric C. via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 17 17:15:27 PDT 2025


https://github.com/Icohedron created https://github.com/llvm/llvm-project/pull/136229

Fixes [#114553](https://github.com/llvm/llvm-project/issues/114553)

This implementation replicates the behavior of DXC in setting the `m_b64UAVs` flag: the `Max64UAVs` DXIL module flag is set in the presence of more than 8 UAVs in a DXIL module.

The behavior of how UAV (resource) arrays are counted differs based on Shader Model version:
- If Shader Model < 6.6, then a UAV array counts as a single UAV regardless of its range size
- if Shader Model >= 6.6, then a UAV array contributes its range size to the total number of UAVs

I initially thought the complete implementation of this analysis may be blocked by the resource arrays implementation, but it seems that it is not the case, as the `@llvm.dx.resource.handle*` already includes a range size argument.

>From b8ef7b390a923400bac9a68e0c603cedc513a4af Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Fri, 18 Apr 2025 00:01:14 +0000
Subject: [PATCH] Implement Max64UAVs shader flag analysis

---
 llvm/lib/Target/DirectX/DXILShaderFlags.cpp   | 10 ++++
 .../ShaderFlags/max-64-uavs-array-sm6_5.ll    | 33 ++++++++++
 .../ShaderFlags/max-64-uavs-array-sm6_6.ll    | 33 ++++++++++
 .../DirectX/ShaderFlags/max-64-uavs.ll        | 60 +++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_5.ll
 create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_6.ll
 create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll

diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 1331b0d1d852b..282b9dcf6de2b 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -255,6 +255,16 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
         EntryFunProps.Entry->getContext().diagnose(DiagnosticInfoUnsupported(
             *(EntryFunProps.Entry), "Inconsistent optnone attribute "));
   }
+
+  // Set the Max64UAVs flag if the number of UAVs is > 8
+  uint32_t NumUAVs = 0;
+  for (auto &UAV : DRM.uavs())
+    if (MMDI.DXILVersion < VersionTuple(1, 6))
+      NumUAVs++;
+    else // MMDI.DXILVersion >= VersionTuple(1, 6)
+      NumUAVs += UAV.getBinding().Size;
+  if (NumUAVs > 8)
+    CombinedSFMask.Max64UAVs = true;
 }
 
 void ComputedShaderFlags::print(raw_ostream &OS) const {
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_5.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_5.ll
new file mode 100644
index 0000000000000..5b978d67866be
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_5.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+; This test makes sure that resource arrays only add 1 to the count of the
+; number of UAVs for setting the shader flag '64 UAV slots' when the shader
+; model version is < 6.6
+
+; Note: there is no feature flag here (only a module flag), so we don't have an
+; object test.
+
+target triple = "dxil-pc-shadermodel6.5-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00000000
+
+; CHECK-NOT: Note: shader requires additional functionality:
+; CHECK-NOT:    64 UAV slots
+
+; CHECK: Function test : 0x00000000
+define void @test() "hlsl.export" {
+  ; RWBuffer<float> Buf : register(u0, space0)
+  %buf0 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 0, i32 1, i32 0, i1 false)
+
+  ; RWBuffer<float> Buf[8] : register(u1, space0)
+  %buf1 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 1, i32 8, i32 0, i1 false)
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_6.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_6.ll
new file mode 100644
index 0000000000000..4b901a78e6ea4
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs-array-sm6_6.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+; This test makes sure that resource arrays sizes are accounted for when
+; counting the number of UAVs for setting the shader flag '64 UAV slots' when
+; the shader model version is >= 6.6
+
+; Note: there is no feature flag here (only a module flag), so we don't have an
+; object test.
+
+target triple = "dxil-pc-shadermodel6.6-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00008000
+
+; CHECK: Note: shader requires additional functionality:
+; CHECK:        64 UAV slots
+
+; CHECK: Function test : 0x00000000
+define void @test() "hlsl.export" {
+  ; RWBuffer<float> Buf : register(u0, space0)
+  %buf0 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 0, i32 1, i32 0, i1 false)
+
+  ; RWBuffer<float> Buf[8] : register(u1, space0)
+  %buf1 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 1, i32 8, i32 0, i1 false)
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll
new file mode 100644
index 0000000000000..c002ff2851452
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll
@@ -0,0 +1,60 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+; This test makes sure that the shader flag '64 UAV slots' is set when there are
+; more than 8 UAVs in the module.
+
+; Note: there is no feature flag here (only a module flag), so we don't have an
+; object test.
+
+target triple = "dxil-pc-shadermodel6.7-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00008000
+
+; CHECK: Note: shader requires additional functionality:
+; CHECK:       64 UAV slots
+
+; Note: 64 UAV slots does not get set per-function
+; CHECK: Function test : 0x00000000
+define void @test() "hlsl.export" {
+  ; RWBuffer<float> Buf : register(u0, space0)
+  %buf0 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 0, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u1, space0)
+  %buf1 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 1, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u2, space0)
+  %buf2 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 2, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u3, space0)
+  %buf3 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 3, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u4, space0)
+  %buf4 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 4, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u5, space0)
+  %buf5 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 5, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u6, space0)
+  %buf6 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 6, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u7, space0)
+  %buf7 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 7, i32 1, i32 0, i1 false)
+  ; RWBuffer<float> Buf : register(u8, space0)
+  %buf8 = call target("dx.TypedBuffer", float, 1, 0, 1)
+       @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(
+           i32 0, i32 8, i32 1, i32 0, i1 false)
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.resmayalias", i32 1}



More information about the llvm-commits mailing list