[llvm] [DirectX] Implement Shader Flag Analysis for `UAVsAtEveryStage` (PR #137085)

Deric C. via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 24 08:50:32 PDT 2025


https://github.com/Icohedron updated https://github.com/llvm/llvm-project/pull/137085

>From 8342b32585317036bf075bf884dd6b813eddd029 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Wed, 23 Apr 2025 21:06:22 +0000
Subject: [PATCH 1/2] Implement UAVsAtEveryStage shader flag

---
 llvm/lib/Target/DirectX/DXILShaderFlags.cpp   | 20 ++++++++++
 .../ShaderFlags/max-64-uavs-array-sm6_5.ll    |  5 +++
 .../ShaderFlags/max-64-uavs-array-sm6_6.ll    |  5 +++
 .../DirectX/ShaderFlags/max-64-uavs.ll        |  5 +++
 .../DirectX/ShaderFlags/res-may-alias-0.ll    |  5 +++
 .../DirectX/ShaderFlags/res-may-alias-1.ll    |  6 ++-
 .../res-may-not-alias-shadermodel6.6.ll       |  5 +++
 .../res-may-not-alias-shadermodel6.7.ll       |  5 +++
 .../res-may-not-alias-shadermodel6.8.ll       |  5 +++
 .../typed-uav-load-additional-formats.ll      |  5 +++
 .../uavs-at-every-stage-lib-valver1.7.ll      | 39 ++++++++++++++++++
 .../uavs-at-every-stage-lib-valver1.8.ll      | 29 ++++++++++++++
 .../ShaderFlags/uavs-at-every-stage-vs.ll     | 40 +++++++++++++++++++
 13 files changed, 173 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.7.ll
 create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.8.ll
 create mode 100644 llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll

diff --git a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
index 282b9dcf6de2b..aa140330c61bb 100644
--- a/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
+++ b/llvm/lib/Target/DirectX/DXILShaderFlags.cpp
@@ -265,6 +265,26 @@ void ModuleShaderFlags::initialize(Module &M, DXILResourceTypeMap &DRTM,
       NumUAVs += UAV.getBinding().Size;
   if (NumUAVs > 8)
     CombinedSFMask.Max64UAVs = true;
+
+  // Set UAVsAtEveryStage flag based on the presence of UAVs, the shader
+  // model version, and the shader environment
+  if (!DRM.uavs().empty()) {
+    if (MMDI.ValidatorVersion < VersionTuple(1, 8))
+      CombinedSFMask.UAVsAtEveryStage =
+          MMDI.ShaderProfile != Triple::EnvironmentType::Compute &&
+          MMDI.ShaderProfile != Triple::EnvironmentType::Pixel;
+    else // MMDI.ValidatorVersion >= VersionTuple(1, 8)
+      switch (MMDI.ShaderProfile) {
+      default:
+        break;
+      case Triple::EnvironmentType::Vertex:
+      case Triple::EnvironmentType::Hull:
+      case Triple::EnvironmentType::Domain:
+      case Triple::EnvironmentType::Geometry:
+        CombinedSFMask.UAVsAtEveryStage = true;
+        break;
+      }
+  }
 }
 
 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
index 5b978d67866be..b476cab236cb3 100644
--- 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
@@ -29,5 +29,10 @@ define void @test() "hlsl.export" {
   ret void
 }
 
+; Set dx.valver and dx.resmayalias to prevent flags ResMayNotAlias and
+; UAVsAtEveryStage from being set, as to not distract from the flag that is
+; actually being tested
 !llvm.module.flags = !{!0}
+!dx.valver = !{!1}
 !0 = !{i32 1, !"dx.resmayalias", i32 1}
+!1 = !{i32 1, i32 8}
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
index 4b901a78e6ea4..6c2b82a85188e 100644
--- 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
@@ -29,5 +29,10 @@ define void @test() "hlsl.export" {
   ret void
 }
 
+; Set dx.valver and dx.resmayalias to prevent flags ResMayNotAlias and
+; UAVsAtEveryStage from being set, as to not distract from the flag that is
+; actually being tested
 !llvm.module.flags = !{!0}
+!dx.valver = !{!1}
 !0 = !{i32 1, !"dx.resmayalias", i32 1}
+!1 = !{i32 1, i32 8}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll
index c002ff2851452..9045f75ef33c1 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/max-64-uavs.ll
@@ -56,5 +56,10 @@ define void @test() "hlsl.export" {
   ret void
 }
 
+; Set dx.valver and dx.resmayalias to prevent flags ResMayNotAlias and
+; UAVsAtEveryStage from being set, as to not distract from the flag that is
+; actually being tested
 !llvm.module.flags = !{!0}
+!dx.valver = !{!1}
 !0 = !{i32 1, !"dx.resmayalias", i32 1}
+!1 = !{i32 1, i32 8}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
index d15b5c7b61984..6996ccc59c204 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-0.ll
@@ -40,4 +40,9 @@ define float @loadSRV() #0 {
 ; But if it does, ensure that it has no effect.
 !0 = !{i32 1, !"dx.resmayalias", i32 0}
 
+; Set dx.valver to prevent the flag UAVsAtEveryStage from being set, as to not
+; distract from the flag that is actually being tested
+!dx.valver = !{!1}
+!1 = !{i32 1, i32 8}
+
 attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
index edd3250a2db0d..c4f9ab498bddf 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-alias-1.ll
@@ -35,7 +35,11 @@ define float @loadSRV() #0 {
 }
 
 !llvm.module.flags = !{!0}
-
 !0 = !{i32 1, !"dx.resmayalias", i32 1}
 
+; Set dx.valver to prevent the flag UAVsAtEveryStage from being set, as to not
+; distract from the flag that is actually being tested
+!dx.valver = !{!1}
+!1 = !{i32 1, i32 8}
+
 attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.6.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.6.ll
index da7c4c619790c..e2f1155b26063 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.6.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.6.ll
@@ -34,4 +34,9 @@ define float @loadSRV() #0 {
   ret float %val
 }
 
+; Set dx.valver to prevent the flag UAVsAtEveryStage from being set, as to not
+; distract from the flag that is actually being tested
+!dx.valver = !{!0}
+!0 = !{i32 1, i32 8}
+
 attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
index 87a76162f734e..c6358473ff2e4 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.7.ll
@@ -35,4 +35,9 @@ define float @loadSRV() #0 {
   ret float %val
 }
 
+; Set dx.valver to prevent the flag UAVsAtEveryStage from being set, as to not
+; distract from the flag that is actually being tested
+!dx.valver = !{!0}
+!0 = !{i32 1, i32 8}
+
 attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
index a309d8ecea56c..10eb7a878e5c4 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/res-may-not-alias-shadermodel6.8.ll
@@ -35,4 +35,9 @@ define float @loadSRV() #0 {
   ret float %val
 }
 
+; Set dx.valver to prevent the flag UAVsAtEveryStage from being set, as to not
+; distract from the flag that is actually being tested
+!dx.valver = !{!0}
+!0 = !{i32 1, i32 8}
+
 attributes #0 = { convergent norecurse nounwind "hlsl.export"}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
index 1bb8a4d78eb16..dd42bb73e9bdd 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/typed-uav-load-additional-formats.ll
@@ -43,8 +43,13 @@ define void @noload(<4 x float> %val) #0 {
   ret void
 }
 
+; Set dx.valver and dx.resmayalias to prevent flags ResMayNotAlias and
+; UAVsAtEveryStage from being set, as to not distract from the flag that is
+; actually being tested
 !llvm.module.flags = !{!0}
+!dx.valver = !{!1}
 !0 = !{i32 1, !"dx.resmayalias", i32 1}
+!1 = !{i32 1, i32 8}
 
 attributes #0 = { convergent norecurse nounwind "hlsl.export"}
 
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.7.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.7.ll
new file mode 100644
index 0000000000000..5db3b32deee62
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.7.ll
@@ -0,0 +1,39 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+
+; This test ensures that a library shader with a UAV gets the module and
+; shader feature flag UAVsAtEveryStage when the DXIL validator version is < 1.8
+
+target triple = "dxil-pc-shadermodel6.5-library"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00010000
+
+; CHECK: Note: shader requires additional functionality:
+; CHECK:        UAVs at every shader stage
+
+; 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)
+  ret void
+}
+
+!dx.valver = !{!1}
+!1 = !{i32 1, i32 7}
+
+; Set dx.resmayalias to prevent the shader flag ResMayNotAlias from being set,
+; as to not distract from the shader flag that is actually being tested
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
+
+; DXC: - Name:            SFI0
+; DXC-NEXT:     Size:            8
+; DXC-NEXT:     Flags:
+; DXC-NOT:   {{[A-Za-z]+: +true}}
+; DXC:              UAVsAtEveryStage:         true
+; DXC-NOT:   {{[A-Za-z]+: +true}}
+; DXC:       NextUnusedBit:   false
+; DXC: ...
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.8.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.8.ll
new file mode 100644
index 0000000000000..98c2e833f4aee
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-lib-valver1.8.ll
@@ -0,0 +1,29 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+
+; This test ensures that a library shader with a UAV does not get the module and
+; shader feature flag UAVsAtEveryStage when the DXIL validator version is >= 1.8
+
+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:        UAVs at every shader stage
+
+; 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)
+  ret void
+}
+
+!dx.valver = !{!1}
+!1 = !{i32 1, i32 8}
+
+; Set dx.resmayalias to prevent the shader flag ResMayNotAlias from being set,
+; as to not distract from the shader flag that is actually being tested
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll
new file mode 100644
index 0000000000000..4aeddf08f6a8b
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll
@@ -0,0 +1,40 @@
+; RUN: opt -S --passes="print-dx-shader-flags" 2>&1 %s | FileCheck %s
+; TODO: Remove this comment and add 'RUN' to the line below once vertex shaders are supported by llc
+; llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC
+
+; This test ensures that a Vertex shader with a UAV gets the module and
+; shader feature flag UAVsAtEveryStage
+
+target triple = "dxil-pc-shadermodel6.5-vertex"
+
+; CHECK:      Combined Shader Flags for Module
+; CHECK-NEXT: Shader Flags Value: 0x00010000
+
+; CHECK: Note: shader requires additional functionality:
+; CHECK:        UAVs at every shader stage
+
+; 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)
+  ret void
+}
+
+!dx.valver = !{!1}
+!1 = !{i32 1, i32 8}
+
+; Set dx.resmayalias to prevent the shader flag ResMayNotAlias from being set,
+; as to not distract from the shader flag that is actually being tested
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"dx.resmayalias", i32 1}
+
+; DXC: - Name:            SFI0
+; DXC-NEXT:     Size:            8
+; DXC-NEXT:     Flags:
+; DXC-NOT:   {{[A-Za-z]+: +true}}
+; DXC-NEXT:       UAVsAtEveryStage:         true
+; DXC-NOT:   {{[A-Za-z]+: +true}}
+; DXC:       NextUnusedBit:   false
+; DXC: ...

>From 1f11675d444e81e4d7d3e194a2d6259dbc516341 Mon Sep 17 00:00:00 2001
From: Icohedron <cheung.deric at gmail.com>
Date: Thu, 24 Apr 2025 15:45:10 +0000
Subject: [PATCH 2/2] Change vertex shader test function name and remove
 hlsl.export from it

---
 .../CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll
index 4aeddf08f6a8b..f0a9d0762d999 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/uavs-at-every-stage-vs.ll
@@ -13,8 +13,8 @@ target triple = "dxil-pc-shadermodel6.5-vertex"
 ; CHECK: Note: shader requires additional functionality:
 ; CHECK:        UAVs at every shader stage
 
-; CHECK: Function test : 0x00000000
-define void @test() "hlsl.export" {
+; CHECK: Function VSMain : 0x00000000
+define void @VSMain() {
   ; RWBuffer<float> Buf : register(u0, space0)
   %buf0 = call target("dx.TypedBuffer", float, 1, 0, 1)
        @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0t(



More information about the llvm-commits mailing list