[llvm] [HLSL] Analyze updateCounter usage (PR #135669)

Helena Kotas via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 22 11:15:44 PDT 2025


================
@@ -280,4 +274,159 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
   }
 }
 
+// Test that several calls to decrement on the same resource don't raise a
+// Diagnositic and resolves to a single decrement entry
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterDecrement) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  ret void
+}
+  )";
+
+  auto M = parseAsm(Assembly);
+
+  DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const auto *const Binding = DRM.find(CI);
+      ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Decrement);
+    }
+  }
+}
+
+// Test that several calls to increment on the same resource don't raise a
+// Diagnositic and resolves to a single increment entry
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterIncrement) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  ret void
+}
+  )";
+
+  auto M = parseAsm(Assembly);
+
+  DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const auto *const Binding = DRM.find(CI);
+      ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Increment);
+    }
+  }
+}
+
+// Test that looking up a resource that doesn't have the counter updated
+// resoves to unknown
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  ret void
+}
+  )";
+
+  auto M = parseAsm(Assembly);
+
+  DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const auto *const Binding = DRM.find(CI);
+      ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Unknown);
+    }
+  }
+}
+
+// Test that multiple different resources with unique incs/decs aren't
+// marked invalid
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 3, i32 2, i32 1, i1 false)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1)
+  ret void
+}
+  )";
+
+  auto M = parseAsm(Assembly);
+
+  DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
+
+  ResourceCounterDirection Dirs[2] = {ResourceCounterDirection::Decrement,
+                                      ResourceCounterDirection::Increment};
+  ResourceCounterDirection *Dir = Dirs;
+
+  for (const Function &F : M->functions()) {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const auto *const Binding = DRM.find(CI);
+      ASSERT_EQ(Binding->CounterDirection, *Dir);
----------------
hekota wrote:

If by some convoluted bug there happen to be 3 instances of `handlefrombinding` or `updatecounter` intrinsics, this will crash. Consider replacing `Dir` with something like `ExpectedDirectionIndex` and check the value is not OOB before accessing `Dirs`. 

https://github.com/llvm/llvm-project/pull/135669


More information about the llvm-commits mailing list