[llvm] [HLSL] Add support to lookup a ResourceBindingInfo from its use (PR #126556)

Ashley Coleman via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 10 10:05:35 PST 2025


https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/126556

>From ab1e78dd414c3d2c816451f2310082c1a1827e2f Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Fri, 7 Feb 2025 16:30:44 -0700
Subject: [PATCH 1/3] Implement trivial resource lookup with test

---
 llvm/include/llvm/Analysis/DXILResource.h     |  4 +
 llvm/lib/Analysis/DXILResource.cpp            | 20 ++++-
 llvm/unittests/Target/DirectX/CMakeLists.txt  |  1 +
 .../DirectX/UniqueResourceFromUseTests.cpp    | 87 +++++++++++++++++++
 4 files changed, 111 insertions(+), 1 deletion(-)
 create mode 100644 llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 87c5615c28ee0c5..8a861c510c0011b 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -446,6 +446,10 @@ class DXILBindingMap {
     return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
   }
 
+  // Resoloves the use of a resource handle into the unique description of that
+  // resource by deduping calls to create.
+  const_iterator findByUse(const Value *Key) const;
+
   const_iterator find(const CallInst *Key) const {
     auto Pos = CallMap.find(Key);
     return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 7f28e63cc117d4c..56957a7ea09b60f 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -770,6 +770,23 @@ void DXILBindingMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
   }
 }
 
+SmallVector<dxil::ResourceBindingInfo>::const_iterator DXILBindingMap::findByUse(const Value *Key) const {
+    const CallInst *CI = dyn_cast<CallInst>(Key);
+    if (!CI) {
+      // TODO: Any other cases to follow up the tree?
+      return Infos.end();
+    }
+
+    switch (CI->getIntrinsicID()) {
+      case Intrinsic::not_intrinsic:
+        return Infos.end();
+      case Intrinsic::dx_resource_handlefrombinding:
+        return find(CI);
+    }
+
+    return Infos.end();
+}
+
 //===----------------------------------------------------------------------===//
 
 AnalysisKey DXILResourceTypeAnalysis::Key;
@@ -828,7 +845,8 @@ bool DXILResourceBindingWrapperPass::runOnModule(Module &M) {
   return false;
 }
 
-void DXILResourceBindingWrapperPass::releaseMemory() { Map.reset(); }
+void DXILResourceBindingWrapperPass::releaseMemory() { 
+  /*Map.reset();*/ }
 
 void DXILResourceBindingWrapperPass::print(raw_ostream &OS,
                                            const Module *M) const {
diff --git a/llvm/unittests/Target/DirectX/CMakeLists.txt b/llvm/unittests/Target/DirectX/CMakeLists.txt
index 626c0d6384268da..4aed48c0b9a2ac5 100644
--- a/llvm/unittests/Target/DirectX/CMakeLists.txt
+++ b/llvm/unittests/Target/DirectX/CMakeLists.txt
@@ -14,4 +14,5 @@ set(LLVM_LINK_COMPONENTS
 add_llvm_target_unittest(DirectXTests
   CBufferDataLayoutTests.cpp
   PointerTypeAnalysisTests.cpp
+  UniqueResourceFromUseTests.cpp
   )
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
new file mode 100644
index 000000000000000..08e9cc77d166aba
--- /dev/null
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -0,0 +1,87 @@
+//===- llvm/unittests/Target/DirectX/PointerTypeAnalysisTests.cpp ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DirectXIRPasses/PointerTypeAnalysis.h"
+#include "llvm/Analysis/DXILResource.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/TypedPointerType.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Transforms/Utils/Debugify.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using ::testing::Contains;
+using ::testing::Pair;
+
+using namespace llvm;
+using namespace llvm::dxil;
+
+template <typename T> struct IsA {
+  friend bool operator==(const Value *V, const IsA &) { return isa<T>(V); }
+};
+
+TEST(UniqueResourceFromUse, TestTrivialUse) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  ret void
+}
+
+declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
+
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  )";
+
+  LLVMContext Context;
+  SMDiagnostic Error;
+  auto M = parseAssemblyString(Assembly, Error, Context);
+  ASSERT_TRUE(M) << "Bad assembly?";
+  DebugifyCustomPassManager Passes;
+  Passes.add(createDXILResourceTypeWrapperPassPass());
+  DXILResourceBindingWrapperPass* RBPass = new DXILResourceBindingWrapperPass();
+  Passes.add(RBPass);
+  Passes.run(*M);
+
+  const DXILBindingMap &DBM = RBPass->getBindingMap();
+  for (const Function& F : M->functions()) {
+    if (F.getName() != "a.func") {
+      continue;
+    }
+
+    unsigned CalledResources = 0;
+
+    for (const User* U : F.users()) {
+      const CallInst* CI = dyn_cast<CallInst>(U);
+      ASSERT_TRUE(CI) << "All users of @a.func must be CallInst";
+
+      const Value* Handle = CI->getArgOperand(0);
+
+      const auto* It = DBM.findByUse(Handle);
+      ASSERT_TRUE(It != DBM.end()) << "Handle should resolve into resource";
+
+      const llvm::dxil::ResourceBindingInfo::ResourceBinding& Binding = It->getBinding();
+      EXPECT_EQ(0u, Binding.RecordID);
+      EXPECT_EQ(1u, Binding.Space);
+      EXPECT_EQ(2u, Binding.LowerBound);
+      EXPECT_EQ(3u, Binding.Size);
+
+      CalledResources++;
+    }
+
+    EXPECT_EQ(1u, CalledResources) << "Expected exactly 1 resolved call to create resource";
+  }
+
+}

>From e7d1042457256b5580125f6a72789ad191f05b3f Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 10 Feb 2025 10:39:36 -0700
Subject: [PATCH 2/3] format

---
 llvm/lib/Analysis/DXILResource.cpp            | 29 ++++++++++---------
 .../DirectX/UniqueResourceFromUseTests.cpp    | 19 ++++++------
 2 files changed, 25 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 56957a7ea09b60f..bcf8fed90bcad3e 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -770,21 +770,22 @@ void DXILBindingMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
   }
 }
 
-SmallVector<dxil::ResourceBindingInfo>::const_iterator DXILBindingMap::findByUse(const Value *Key) const {
-    const CallInst *CI = dyn_cast<CallInst>(Key);
-    if (!CI) {
-      // TODO: Any other cases to follow up the tree?
-      return Infos.end();
-    }
-
-    switch (CI->getIntrinsicID()) {
-      case Intrinsic::not_intrinsic:
-        return Infos.end();
-      case Intrinsic::dx_resource_handlefrombinding:
-        return find(CI);
-    }
+SmallVector<dxil::ResourceBindingInfo>::const_iterator
+DXILBindingMap::findByUse(const Value *Key) const {
+  const CallInst *CI = dyn_cast<CallInst>(Key);
+  if (!CI) {
+    // TODO: Any other cases to follow up the tree?
+    return Infos.end();
+  }
 
+  switch (CI->getIntrinsicID()) {
+  case Intrinsic::not_intrinsic:
     return Infos.end();
+  case Intrinsic::dx_resource_handlefrombinding:
+    return find(CI);
+  }
+
+  return Infos.end();
 }
 
 //===----------------------------------------------------------------------===//
@@ -845,7 +846,7 @@ bool DXILResourceBindingWrapperPass::runOnModule(Module &M) {
   return false;
 }
 
-void DXILResourceBindingWrapperPass::releaseMemory() { 
+void DXILResourceBindingWrapperPass::releaseMemory() {
   /*Map.reset();*/ }
 
 void DXILResourceBindingWrapperPass::print(raw_ostream &OS,
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index 08e9cc77d166aba..1f40ccebd4a3ca3 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -51,28 +51,29 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ASSERT_TRUE(M) << "Bad assembly?";
   DebugifyCustomPassManager Passes;
   Passes.add(createDXILResourceTypeWrapperPassPass());
-  DXILResourceBindingWrapperPass* RBPass = new DXILResourceBindingWrapperPass();
+  DXILResourceBindingWrapperPass *RBPass = new DXILResourceBindingWrapperPass();
   Passes.add(RBPass);
   Passes.run(*M);
 
   const DXILBindingMap &DBM = RBPass->getBindingMap();
-  for (const Function& F : M->functions()) {
+  for (const Function &F : M->functions()) {
     if (F.getName() != "a.func") {
       continue;
     }
 
     unsigned CalledResources = 0;
 
-    for (const User* U : F.users()) {
-      const CallInst* CI = dyn_cast<CallInst>(U);
+    for (const User *U : F.users()) {
+      const CallInst *CI = dyn_cast<CallInst>(U);
       ASSERT_TRUE(CI) << "All users of @a.func must be CallInst";
 
-      const Value* Handle = CI->getArgOperand(0);
+      const Value *Handle = CI->getArgOperand(0);
 
-      const auto* It = DBM.findByUse(Handle);
+      const auto *It = DBM.findByUse(Handle);
       ASSERT_TRUE(It != DBM.end()) << "Handle should resolve into resource";
 
-      const llvm::dxil::ResourceBindingInfo::ResourceBinding& Binding = It->getBinding();
+      const llvm::dxil::ResourceBindingInfo::ResourceBinding &Binding =
+          It->getBinding();
       EXPECT_EQ(0u, Binding.RecordID);
       EXPECT_EQ(1u, Binding.Space);
       EXPECT_EQ(2u, Binding.LowerBound);
@@ -81,7 +82,7 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
       CalledResources++;
     }
 
-    EXPECT_EQ(1u, CalledResources) << "Expected exactly 1 resolved call to create resource";
+    EXPECT_EQ(1u, CalledResources)
+        << "Expected exactly 1 resolved call to create resource";
   }
-
 }

>From 09b63733c9edadf42fbebe7e8a8376770cd016cb Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 10 Feb 2025 11:05:00 -0700
Subject: [PATCH 3/3] Add TODOs

---
 llvm/lib/Analysis/DXILResource.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index bcf8fed90bcad3e..1c34850caa707d7 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -780,6 +780,7 @@ DXILBindingMap::findByUse(const Value *Key) const {
 
   switch (CI->getIntrinsicID()) {
   case Intrinsic::not_intrinsic:
+    // TODO: Walk the call tree
     return Infos.end();
   case Intrinsic::dx_resource_handlefrombinding:
     return find(CI);
@@ -847,6 +848,7 @@ bool DXILResourceBindingWrapperPass::runOnModule(Module &M) {
 }
 
 void DXILResourceBindingWrapperPass::releaseMemory() {
+  // TODO: Can't comment out this code
   /*Map.reset();*/ }
 
 void DXILResourceBindingWrapperPass::print(raw_ostream &OS,



More information about the llvm-commits mailing list