Skip to content

[DirectX] Implement metadata lowering for resources #104447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

bogner
Copy link
Contributor

@bogner bogner commented Aug 15, 2024

Generate metadata from target extension type based resources.

Part of #91366

bogner added 2 commits August 15, 2024 16:51
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
@llvmbot
Copy link
Member

llvmbot commented Aug 15, 2024

@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-backend-directx

Author: Justin Bogner (bogner)

Changes

Generate metadata from target extension type based resources.

Part of #91366


Full diff: https://github.com/llvm/llvm-project/pull/104447.diff

3 Files Affected:

  • (modified) llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp (+39-8)
  • (modified) llvm/test/CodeGen/DirectX/CreateHandle.ll (+9-1)
  • (modified) llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll (+9-1)
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 007af0b46b9f3..f8621eea23448 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -13,27 +13,52 @@
 #include "DXILShaderFlags.h"
 #include "DirectX.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
+#include "llvm/InitializePasses.h"
 #include "llvm/Pass.h"
 #include "llvm/TargetParser/Triple.h"
 
 using namespace llvm;
 using namespace llvm::dxil;
 
-static void emitResourceMetadata(Module &M,
+static void emitResourceMetadata(Module &M, const DXILResourceMap &DRM,
                                  const dxil::Resources &MDResources) {
-  Metadata *SRVMD = nullptr, *UAVMD = nullptr, *CBufMD = nullptr,
-           *SmpMD = nullptr;
-  bool HasResources = false;
+  LLVMContext &Context = M.getContext();
+
+  SmallVector<Metadata *> SRVs, UAVs, CBufs, Smps;
+  for (auto [_, RI] : DRM) {
+    switch (RI.getResourceClass()) {
+    case dxil::ResourceClass::SRV:
+      SRVs.push_back(RI.getAsMetadata(Context));
+      break;
+    case dxil::ResourceClass::UAV:
+      UAVs.push_back(RI.getAsMetadata(Context));
+      break;
+    case dxil::ResourceClass::CBuffer:
+      CBufs.push_back(RI.getAsMetadata(Context));
+      break;
+    case dxil::ResourceClass::Sampler:
+      Smps.push_back(RI.getAsMetadata(Context));
+      break;
+    }
+  }
+  Metadata *SRVMD = SRVs.empty() ? nullptr : MDNode::get(Context, SRVs);
+  Metadata *UAVMD = UAVs.empty() ? nullptr : MDNode::get(Context, UAVs);
+  Metadata *CBufMD = CBufs.empty() ? nullptr : MDNode::get(Context, CBufs);
+  Metadata *SmpMD = Smps.empty() ? nullptr : MDNode::get(Context, Smps);
+  bool HasResources = !DRM.empty();
 
   if (MDResources.hasUAVs()) {
+    assert(!UAVMD && "Old and new UAV representations can't coexist");
     UAVMD = MDResources.writeUAVs(M);
     HasResources = true;
   }
 
   if (MDResources.hasCBuffers()) {
+    assert(!CBufMD && "Old and new cbuffer representations can't coexist");
     CBufMD = MDResources.writeCBuffers(M);
     HasResources = true;
   }
@@ -46,7 +71,8 @@ static void emitResourceMetadata(Module &M,
       MDNode::get(M.getContext(), {SRVMD, UAVMD, CBufMD, SmpMD}));
 }
 
-static void translateMetadata(Module &M, const dxil::Resources &MDResources,
+static void translateMetadata(Module &M, const DXILResourceMap &DRM,
+                              const dxil::Resources &MDResources,
                               const ComputedShaderFlags &ShaderFlags) {
   dxil::ValidatorVersionMD ValVerMD(M);
   if (ValVerMD.isEmpty())
@@ -54,18 +80,19 @@ static void translateMetadata(Module &M, const dxil::Resources &MDResources,
   dxil::createShaderModelMD(M);
   dxil::createDXILVersionMD(M);
 
-  emitResourceMetadata(M, MDResources);
+  emitResourceMetadata(M, DRM, MDResources);
 
   dxil::createEntryMD(M, static_cast<uint64_t>(ShaderFlags));
 }
 
 PreservedAnalyses DXILTranslateMetadata::run(Module &M,
                                              ModuleAnalysisManager &MAM) {
+  const DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
   const dxil::Resources &MDResources = MAM.getResult<DXILResourceMDAnalysis>(M);
   const ComputedShaderFlags &ShaderFlags =
       MAM.getResult<ShaderFlagsAnalysis>(M);
 
-  translateMetadata(M, MDResources, ShaderFlags);
+  translateMetadata(M, DRM, MDResources, ShaderFlags);
 
   return PreservedAnalyses::all();
 }
@@ -80,17 +107,20 @@ class DXILTranslateMetadataLegacy : public ModulePass {
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.setPreservesAll();
+    AU.addRequired<DXILResourceWrapperPass>();
     AU.addRequired<DXILResourceMDWrapper>();
     AU.addRequired<ShaderFlagsAnalysisWrapper>();
   }
 
   bool runOnModule(Module &M) override {
+    const DXILResourceMap &DRM =
+        getAnalysis<DXILResourceWrapperPass>().getResourceMap();
     const dxil::Resources &MDResources =
         getAnalysis<DXILResourceMDWrapper>().getDXILResource();
     const ComputedShaderFlags &ShaderFlags =
         getAnalysis<ShaderFlagsAnalysisWrapper>().getShaderFlags();
 
-    translateMetadata(M, MDResources, ShaderFlags);
+    translateMetadata(M, DRM, MDResources, ShaderFlags);
     return true;
   }
 };
@@ -105,6 +135,7 @@ ModulePass *llvm::createDXILTranslateMetadataLegacyPass() {
 
 INITIALIZE_PASS_BEGIN(DXILTranslateMetadataLegacy, "dxil-translate-metadata",
                       "DXIL Translate Metadata", false, false)
+INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
 INITIALIZE_PASS_DEPENDENCY(DXILResourceMDWrapper)
 INITIALIZE_PASS_DEPENDENCY(ShaderFlagsAnalysisWrapper)
 INITIALIZE_PASS_END(DXILTranslateMetadataLegacy, "dxil-translate-metadata",
diff --git a/llvm/test/CodeGen/DirectX/CreateHandle.ll b/llvm/test/CodeGen/DirectX/CreateHandle.ll
index 1fad869ab4305..f0d1c8da5a425 100644
--- a/llvm/test/CodeGen/DirectX/CreateHandle.ll
+++ b/llvm/test/CodeGen/DirectX/CreateHandle.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -dxil-op-lower %s | FileCheck %s
+; RUN: opt -S -passes=dxil-op-lower,dxil-translate-metadata %s | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.0-compute"
 
@@ -40,6 +40,14 @@ define void @test_buffers() {
   ret void
 }
 
+; Just check that we have the right types and number of metadata nodes, the
+; contents of the metadata are tested elsewhere.
+;
+; CHECK: !dx.resources = !{[[RESMD:![0-9]+]]}
+; CHECK: [[RESMD]] = !{[[SRVMD:![0-9]+]], [[UAVMD:![0-9]+]], null, null}
+; CHECK-DAG: [[SRVMD]] = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+; CHECK-DAG: [[UAVMD]] = !{!{{[0-9]+}}, !{{[0-9]+}}}
+
 ; Note: We need declarations for each handle.fromBinding in the same order as
 ; they appear in source to force a deterministic ordering of record IDs.
 declare target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
diff --git a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
index e8bd8fe89132d..345459a60c5ab 100644
--- a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
+++ b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
@@ -1,4 +1,4 @@
-; RUN: opt -S -dxil-op-lower %s | FileCheck %s
+; RUN: opt -S -passes=dxil-op-lower,dxil-translate-metadata %s | FileCheck %s
 
 target triple = "dxil-pc-shadermodel6.6-compute"
 
@@ -44,6 +44,14 @@ define void @test_bindings() {
   ret void
 }
 
+; Just check that we have the right types and number of metadata nodes, the
+; contents of the metadata are tested elsewhere.
+;
+; CHECK: !dx.resources = !{[[RESMD:![0-9]+]]}
+; CHECK: [[RESMD]] = !{[[SRVMD:![0-9]+]], [[UAVMD:![0-9]+]], null, null}
+; CHECK-DAG: [[SRVMD]] = !{!{{[0-9]+}}, !{{[0-9]+}}, !{{[0-9]+}}}
+; CHECK-DAG: [[UAVMD]] = !{!{{[0-9]+}}, !{{[0-9]+}}}
+
 ; Note: We need declarations for each handle.fromBinding in the same order as
 ; they appear in source to force a deterministic ordering of record IDs.
 declare target("dx.TypedBuffer", <4 x float>, 1, 0, 0)

@bogner
Copy link
Contributor Author

bogner commented Aug 15, 2024

Depends on #104251 and #104446

Copy link
Contributor

@coopp coopp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Copy link
Member

@hekota hekota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!


SmallVector<Metadata *> SRVs, UAVs, CBufs, Smps;
for (auto [_, RI] : DRM) {
switch (RI.getResourceClass()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a resource array like Buffer<float4> B[10] which used B[2] and B[5]. Will B[2] and B[5] both in DRM and get same RI?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the API in #105602 - you can now iterate over the unique resources, and there are helpers to just iterate .srvs(), .uavs(), etc.

bogner added 2 commits August 21, 2024 18:09
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
bogner added a commit that referenced this pull request Aug 23, 2024
If a resources is used multiple times, we should only have one resource record
for it. This comes up most prominantly with arrays of resources like so:

```hlsl
RWBuffer<float4> BufferArray[10] : register(u0, space4);
RWBuffer<float4> B1 = BufferArray[0];
RWBuffer<float4> B2 = BufferArray[SomeIndex];
RWBuffer<float4> B3 = BufferArray[3];
```

In this case, there's only one resource, but we'll generate 3 different
`dx.handle.fromBinding` calls to access different slices.

Note that this adds some API that won't be used until #104447 later in the
stack. Trying to avoid that results in unnecessary churn.

Fixes #105143

Pull Request: #105602
bogner added 2 commits August 26, 2024 16:48
Created using spr 1.3.5-bogner

[skip ci]
Created using spr 1.3.5-bogner
@llvmbot llvmbot added the llvm:analysis Includes value tracking, cost tables and constant folding label Aug 26, 2024
@bogner bogner changed the base branch from users/bogner/sprmain.directx-implement-metadata-lowering-for-resources to main August 27, 2024 00:19
@bogner bogner merged commit daa7923 into main Aug 27, 2024
9 of 11 checks passed
@bogner bogner deleted the users/bogner/sprdirectx-implement-metadata-lowering-for-resources branch August 27, 2024 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:DirectX llvm:analysis Includes value tracking, cost tables and constant folding
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

6 participants