Skip to content

[DirectX] Create symbols for resource handles #119775

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
merged 1 commit into from
Dec 18, 2024

Conversation

bogner
Copy link
Contributor

@bogner bogner commented Dec 12, 2024

We need to create symbols with "the original shape of resource and element type" to put in the resource metadata in order to generate valid DXIL.

Note that DXC generally doesn't emit an actual symbol outside of library shaders (it emits an undef of a pointer to the type), but since we have to deal with opaque pointers we would need a way to smuggle the type through to match that. Instead, we simply emit symbols for now.

Fixed #116849

@llvmbot
Copy link
Member

llvmbot commented Dec 12, 2024

@llvm/pr-subscribers-backend-directx

Author: Justin Bogner (bogner)

Changes

We need to create symbols with "the original shape of resource and element type" to put in the resource metadata in order to generate valid DXIL.

Note that DXC generally doesn't emit an actual symbol outside of library shaders (it emits an undef of a pointer to the type), but since we have to deal with opaque pointers we would need a way to smuggle the type through to match that. Instead, we simply emit symbols for now.

Fixed #116849


Patch is 21.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/119775.diff

5 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DXILResource.h (+11-7)
  • (modified) llvm/lib/Analysis/DXILResource.cpp (+93-7)
  • (modified) llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp (+4)
  • (added) llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll (+48)
  • (modified) llvm/unittests/Analysis/DXILResourceTest.cpp (+38-22)
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 2f5dded46538ea..b59798a3d64a47 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -270,6 +270,7 @@ class ResourceTypeInfo {
                          GloballyCoherent, HasCounter) {}
 
   TargetExtType *getHandleTy() const { return HandleTy; }
+  StructType *createElementStruct();
 
   // Conditions to check before accessing specific views.
   bool isUAV() const;
@@ -325,21 +326,23 @@ class ResourceBindingInfo {
 private:
   ResourceBinding Binding;
   TargetExtType *HandleTy;
+  GlobalVariable *Symbol = nullptr;
 
 public:
   ResourceBindingInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
-                      uint32_t Size, TargetExtType *HandleTy)
-      : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy) {}
+                      uint32_t Size, TargetExtType *HandleTy,
+                      GlobalVariable *Symbol = nullptr)
+      : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
+        Symbol(Symbol) {}
 
   void setBindingID(unsigned ID) { Binding.RecordID = ID; }
 
   const ResourceBinding &getBinding() const { return Binding; }
   TargetExtType *getHandleTy() const { return HandleTy; }
-  const StringRef getName() const {
-    // TODO: Get the name from the symbol once we include one here.
-    return "";
-  }
+  const StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
 
+  bool hasSymbol() const { return Symbol; }
+  GlobalVariable *createSymbol(Module &M, StructType *Ty, StringRef Name = "");
   MDTuple *getAsMetadata(Module &M, DXILResourceTypeMap &DRTM) const;
   MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo RTI) const;
 
@@ -349,7 +352,8 @@ class ResourceBindingInfo {
   getAnnotateProps(Module &M, dxil::ResourceTypeInfo RTI) const;
 
   bool operator==(const ResourceBindingInfo &RHS) const {
-    return std::tie(Binding, HandleTy) == std::tie(RHS.Binding, RHS.HandleTy);
+    return std::tie(Binding, HandleTy, Symbol) ==
+           std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
   }
   bool operator!=(const ResourceBindingInfo &RHS) const {
     return !(*this == RHS);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index e1942a0c4930cd..793929e0e40dfa 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -216,6 +216,81 @@ ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy,
     llvm_unreachable("Unknown handle type");
 }
 
+static void formatTypeName(SmallString<64> &Dest, StringRef Name,
+                           bool isWriteable, bool isROV) {
+  Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : "";
+  Dest += Name;
+}
+
+StructType *ResourceTypeInfo::createElementStruct() {
+  SmallString<64> TypeName;
+
+  switch (Kind) {
+  case ResourceKind::Texture1D:
+  case ResourceKind::Texture2D:
+  case ResourceKind::Texture3D:
+  case ResourceKind::TextureCube:
+  case ResourceKind::Texture1DArray:
+  case ResourceKind::Texture2DArray:
+  case ResourceKind::TextureCubeArray: {
+    auto *RTy = cast<TextureExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::Texture2DMS:
+  case ResourceKind::Texture2DMSArray: {
+    auto *RTy = cast<MSTextureExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   /*IsROV=*/false);
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::TypedBuffer: {
+    auto *RTy = cast<TypedBufferExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::RawBuffer: {
+    auto *RTy = cast<RawBufferExtType>(HandleTy);
+    formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
+                              TypeName);
+  }
+  case ResourceKind::StructuredBuffer: {
+    auto *RTy = cast<RawBufferExtType>(HandleTy);
+    formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::FeedbackTexture2D:
+  case ResourceKind::FeedbackTexture2DArray: {
+    auto *RTy = cast<FeedbackTextureExtType>(HandleTy);
+    TypeName = formatv("{0}<{1}>", getResourceKindName(Kind),
+                       llvm::to_underlying(RTy->getFeedbackType()));
+    return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
+                              TypeName);
+  }
+  case ResourceKind::CBuffer:
+    return StructType::create(HandleTy->getContext(), "cbuffer");
+  case ResourceKind::Sampler: {
+    auto *RTy = cast<SamplerExtType>(HandleTy);
+    TypeName = formatv("SamplerState<{0}>",
+                       llvm::to_underlying(RTy->getSamplerType()));
+    return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
+                              TypeName);
+  }
+  case ResourceKind::TBuffer:
+  case ResourceKind::RTAccelerationStructure:
+    llvm_unreachable("Unhandled resource kind");
+  case ResourceKind::Invalid:
+  case ResourceKind::NumEntries:
+    llvm_unreachable("Invalid resource kind");
+  }
+  llvm_unreachable("Unhandled ResourceKind enum");
+}
+
 bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
 
 bool ResourceTypeInfo::isCBuffer() const {
@@ -450,6 +525,15 @@ void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
   }
 }
 
+GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
+                                                  StringRef Name) {
+  assert(!Symbol && "Symbol has already been created");
+  Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
+                              GlobalValue::ExternalLinkage,
+                              /*Initializer=*/nullptr, Name);
+  return Symbol;
+}
+
 MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
                                             DXILResourceTypeMap &DRTM) const {
   return getAsMetadata(M, DRTM[getHandleTy()]);
@@ -474,13 +558,9 @@ MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
   };
 
   MDVals.push_back(getIntMD(Binding.RecordID));
-
-  // TODO: We need API to create a symbol of the appropriate type to emit here.
-  // See https://github.com/llvm/llvm-project/issues/116849
-  MDVals.push_back(
-      ValueAsMetadata::get(UndefValue::get(PointerType::getUnqual(Ctx))));
-  MDVals.push_back(MDString::get(Ctx, ""));
-
+  assert(Symbol && "Cannot yet create useful resource metadata without symbol");
+  MDVals.push_back(ValueAsMetadata::get(Symbol));
+  MDVals.push_back(MDString::get(Ctx, Symbol->getName()));
   MDVals.push_back(getIntMD(Binding.Space));
   MDVals.push_back(getIntMD(Binding.LowerBound));
   MDVals.push_back(getIntMD(Binding.Size));
@@ -590,6 +670,12 @@ void ResourceBindingInfo::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
 
 void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo RTI,
                                 const DataLayout &DL) const {
+  if (Symbol) {
+    OS << "  Symbol: ";
+    Symbol->printAsOperand(OS);
+    OS << "\n";
+  }
+
   OS << "  Binding:\n"
      << "    Record ID: " << Binding.RecordID << "\n"
      << "    Space: " << Binding.Space << "\n"
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 9763fe6a8a3455..9443ccd9c82a53 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -77,6 +77,10 @@ static NamedMDNode *emitResourceMetadata(Module &M, DXILBindingMap &DBM,
                                          const dxil::Resources &MDResources) {
   LLVMContext &Context = M.getContext();
 
+  for (ResourceBindingInfo &RI : DBM)
+    if (!RI.hasSymbol())
+      RI.createSymbol(M, DRTM[RI.getHandleTy()].createElementStruct());
+
   SmallVector<Metadata *> SRVs, UAVs, CBufs, Smps;
   for (const ResourceBindingInfo &RI : DBM.srvs())
     SRVs.push_back(RI.getAsMetadata(M, DRTM));
diff --git a/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll b/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
new file mode 100644
index 00000000000000..5ac4baa96c6599
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -passes=dxil-translate-metadata %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+%struct.S = type { <4 x float>, <4 x i32> }
+
+define void @test() {
+  ; Buffer<float4>
+  %float4 = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  ; CHECK: %TypedBuffer = type { <4 x float> }
+
+  ; Buffer<int>
+  %int = call target("dx.TypedBuffer", i32, 0, 0, 1)
+      @llvm.dx.handle.fromBinding(i32 0, i32 1, i32 1, i32 0, i1 false)
+  ; CHECK: %TypedBuffer.0 = type { i32 }
+
+  ; Buffer<uint3>
+  %uint3 = call target("dx.TypedBuffer", <3 x i32>, 0, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 2, i32 1, i32 0, i1 false)
+  ; CHECK: %TypedBuffer.1 = type { <3 x i32> }
+
+  ; StructuredBuffer<S>
+  %struct0 = call target("dx.RawBuffer", %struct.S, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 10, i32 1, i32 0, i1 true)
+  ; CHECK: %StructuredBuffer = type { %struct.S }
+
+  ; ByteAddressBuffer
+  %byteaddr = call target("dx.RawBuffer", i8, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 20, i32 1, i32 0, i1 false)
+  ; CHECK: %ByteAddressBuffer = type { i32 }
+
+  ret void
+}
+
+; CHECK:      @[[T0:.*]] = external constant %TypedBuffer
+; CHECK-NEXT: @[[T1:.*]] = external constant %TypedBuffer.0
+; CHECK-NEXT: @[[T2:.*]] = external constant %TypedBuffer.1
+; CHECK-NEXT: @[[S0:.*]] = external constant %StructuredBuffer
+; CHECK-NEXT: @[[B0:.*]] = external constant %ByteAddressBuffer
+
+; CHECK: !{i32 0, ptr @[[T0]], !""
+; CHECK: !{i32 1, ptr @[[T1]], !""
+; CHECK: !{i32 2, ptr @[[T2]], !""
+; CHECK: !{i32 3, ptr @[[S0]], !""
+; CHECK: !{i32 4, ptr @[[B0]], !""
+
+attributes #0 = { nocallback nofree nosync nounwind willreturn memory(none) }
diff --git a/llvm/unittests/Analysis/DXILResourceTest.cpp b/llvm/unittests/Analysis/DXILResourceTest.cpp
index 784ea7702c0d5f..4c005f817af59d 100644
--- a/llvm/unittests/Analysis/DXILResourceTest.cpp
+++ b/llvm/unittests/Analysis/DXILResourceTest.cpp
@@ -120,7 +120,6 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   Type *Int32x2Ty = FixedVectorType::get(Int32Ty, 2);
 
   MDBuilder TestMD(Context, Int32Ty, Int1Ty);
-  Value *DummyGV = UndefValue::get(PointerType::getUnqual(Context));
 
   // ByteAddressBuffer Buffer;
   ResourceTypeInfo RTI(llvm::TargetExtType::get(
@@ -131,11 +130,12 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   ResourceBindingInfo RBI(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GlobalVariable *GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer");
   std::pair<uint32_t, uint32_t> Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000bU);
   EXPECT_EQ(Props.second, 0U);
   MDTuple *MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 11, 0, nullptr));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "Buffer", 0, 0, 1, 11, 0, nullptr));
 
   // RWByteAddressBuffer BufferOut : register(u3, space2);
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -149,12 +149,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/1, /*Space=*/2, /*LowerBound=*/3, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "BufferOut");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000100bU);
   EXPECT_EQ(Props.second, 0U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(1, DummyGV, "", 2, 3, 1, 11, false, false, false,
-                             nullptr));
+  EXPECT_MDEQ(MD, TestMD.get(1, GV, "BufferOut", 2, 3, 1, 11, false, false,
+                             false, nullptr));
 
   // struct BufType0 { int i; float f; double d; };
   // StructuredBuffer<BufType0> Buffer0 : register(t0);
@@ -171,12 +172,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer0");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000030cU);
   EXPECT_EQ(Props.second, 0x00000010U);
   MD = RBI.getAsMetadata(M, RTI);
   EXPECT_MDEQ(MD,
-              TestMD.get(0, DummyGV, "", 0, 0, 1, 12, 0, TestMD.get(1, 16)));
+              TestMD.get(0, GV, "Buffer0", 0, 0, 1, 12, 0, TestMD.get(1, 16)));
 
   // StructuredBuffer<float3> Buffer1 : register(t1);
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -190,12 +192,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/1, /*Space=*/0, /*LowerBound=*/1, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer1");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000cU);
   EXPECT_EQ(Props.second, 0x0000000cU);
   MD = RBI.getAsMetadata(M, RTI);
   EXPECT_MDEQ(MD,
-              TestMD.get(1, DummyGV, "", 0, 1, 1, 12, 0, TestMD.get(1, 12)));
+              TestMD.get(1, GV, "Buffer1", 0, 1, 1, 12, 0, TestMD.get(1, 12)));
 
   // Texture2D<float4> ColorMapTexture : register(t2);
   RTI = ResourceTypeInfo(
@@ -211,11 +214,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/2, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ColorMapTexture");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00000002U);
   EXPECT_EQ(Props.second, 0x00000409U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(2, DummyGV, "", 0, 2, 1, 2, 0, TestMD.get(0, 9)));
+  EXPECT_MDEQ(MD, TestMD.get(2, GV, "ColorMapTexture", 0, 2, 1, 2, 0,
+                             TestMD.get(0, 9)));
 
   // Texture2DMS<float, 8> DepthBuffer : register(t0);
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -233,11 +238,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "DepthBuffer");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00000003U);
   EXPECT_EQ(Props.second, 0x00080109U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 3, 8, TestMD.get(0, 9)));
+  EXPECT_MDEQ(
+      MD, TestMD.get(0, GV, "DepthBuffer", 0, 0, 1, 3, 8, TestMD.get(0, 9)));
 
   // FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> feedbackMinMip;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -252,12 +259,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "feedbackMinMip");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001011U);
   EXPECT_EQ(Props.second, 0U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 17, false, false, false,
-                             TestMD.get(2, 0)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "feedbackMinMip", 0, 0, 1, 17, false, false,
+                             false, TestMD.get(2, 0)));
 
   // FeedbackTexture2DArray<SAMPLER_FEEDBACK_MIP_REGION_USED> feedbackMipRegion;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -272,12 +280,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "feedbackMipRegion");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001012U);
   EXPECT_EQ(Props.second, 0x00000001U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 18, false, false, false,
-                             TestMD.get(2, 1)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "feedbackMipRegion", 0, 0, 1, 18, false,
+                             false, false, TestMD.get(2, 1)));
 
   // globallycoherent RWTexture2D<int2> OutputTexture : register(u0, space2);
   RTI = ResourceTypeInfo(
@@ -296,12 +305,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/2, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "OutputTexture");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00005002U);
   EXPECT_EQ(Props.second, 0x00000204U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 2, 0, 1, 2, true, false, false,
-                             TestMD.get(0, 4)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "OutputTexture", 2, 0, 1, 2, true, false,
+                             false, TestMD.get(0, 4)));
 
   // RasterizerOrderedBuffer<float4> ROB;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -319,11 +329,12 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ROB");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000300aU);
   EXPECT_EQ(Props.second, 0x00000409U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 10, false, false, true,
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "ROB", 0, 0, 1, 10, false, false, true,
                              TestMD.get(0, 9)));
 
   // RWStructuredBuffer<ParticleMotion> g_OutputBuffer : register(u2);
@@ -345,12 +356,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "g_OutputBuffer");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000920cU);
   EXPECT_EQ(Props.second, 0x00000014U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 2, 1, 12, false, true, false,
-                             TestMD.get(1, 20)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "g_OutputBuffer", 0, 2, 1, 12, false, true,
+                             false, TestMD.get(1, 20)));
 
   // RWTexture2DMSArray<uint, 8> g_rw_t2dmsa;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -371,12 +383,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "g_rw_t2dmsa");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001008U);
   EXPECT_EQ(Props.second, 0x00080105U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 8, false, false, false,
-                             TestMD.get(0, 5)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "g_rw_t2dmsa", 0, 0, 1, 8, false, false,
+                             false, TestMD.get(0, 5)));
 
   // cbuffer cb0 { float4 g_X; float4 g_Y; }
   StructType *CBufType0 =
@@ -390,11 +403,12 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000dU);
   EXPECT_EQ(Props.second, 0x00000020U);
   MD = RB...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Dec 12, 2024

@llvm/pr-subscribers-llvm-analysis

Author: Justin Bogner (bogner)

Changes

We need to create symbols with "the original shape of resource and element type" to put in the resource metadata in order to generate valid DXIL.

Note that DXC generally doesn't emit an actual symbol outside of library shaders (it emits an undef of a pointer to the type), but since we have to deal with opaque pointers we would need a way to smuggle the type through to match that. Instead, we simply emit symbols for now.

Fixed #116849


Patch is 21.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/119775.diff

5 Files Affected:

  • (modified) llvm/include/llvm/Analysis/DXILResource.h (+11-7)
  • (modified) llvm/lib/Analysis/DXILResource.cpp (+93-7)
  • (modified) llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp (+4)
  • (added) llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll (+48)
  • (modified) llvm/unittests/Analysis/DXILResourceTest.cpp (+38-22)
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 2f5dded46538ea..b59798a3d64a47 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -270,6 +270,7 @@ class ResourceTypeInfo {
                          GloballyCoherent, HasCounter) {}
 
   TargetExtType *getHandleTy() const { return HandleTy; }
+  StructType *createElementStruct();
 
   // Conditions to check before accessing specific views.
   bool isUAV() const;
@@ -325,21 +326,23 @@ class ResourceBindingInfo {
 private:
   ResourceBinding Binding;
   TargetExtType *HandleTy;
+  GlobalVariable *Symbol = nullptr;
 
 public:
   ResourceBindingInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
-                      uint32_t Size, TargetExtType *HandleTy)
-      : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy) {}
+                      uint32_t Size, TargetExtType *HandleTy,
+                      GlobalVariable *Symbol = nullptr)
+      : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
+        Symbol(Symbol) {}
 
   void setBindingID(unsigned ID) { Binding.RecordID = ID; }
 
   const ResourceBinding &getBinding() const { return Binding; }
   TargetExtType *getHandleTy() const { return HandleTy; }
-  const StringRef getName() const {
-    // TODO: Get the name from the symbol once we include one here.
-    return "";
-  }
+  const StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
 
+  bool hasSymbol() const { return Symbol; }
+  GlobalVariable *createSymbol(Module &M, StructType *Ty, StringRef Name = "");
   MDTuple *getAsMetadata(Module &M, DXILResourceTypeMap &DRTM) const;
   MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo RTI) const;
 
@@ -349,7 +352,8 @@ class ResourceBindingInfo {
   getAnnotateProps(Module &M, dxil::ResourceTypeInfo RTI) const;
 
   bool operator==(const ResourceBindingInfo &RHS) const {
-    return std::tie(Binding, HandleTy) == std::tie(RHS.Binding, RHS.HandleTy);
+    return std::tie(Binding, HandleTy, Symbol) ==
+           std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
   }
   bool operator!=(const ResourceBindingInfo &RHS) const {
     return !(*this == RHS);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index e1942a0c4930cd..793929e0e40dfa 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -216,6 +216,81 @@ ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy,
     llvm_unreachable("Unknown handle type");
 }
 
+static void formatTypeName(SmallString<64> &Dest, StringRef Name,
+                           bool isWriteable, bool isROV) {
+  Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : "";
+  Dest += Name;
+}
+
+StructType *ResourceTypeInfo::createElementStruct() {
+  SmallString<64> TypeName;
+
+  switch (Kind) {
+  case ResourceKind::Texture1D:
+  case ResourceKind::Texture2D:
+  case ResourceKind::Texture3D:
+  case ResourceKind::TextureCube:
+  case ResourceKind::Texture1DArray:
+  case ResourceKind::Texture2DArray:
+  case ResourceKind::TextureCubeArray: {
+    auto *RTy = cast<TextureExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::Texture2DMS:
+  case ResourceKind::Texture2DMSArray: {
+    auto *RTy = cast<MSTextureExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   /*IsROV=*/false);
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::TypedBuffer: {
+    auto *RTy = cast<TypedBufferExtType>(HandleTy);
+    formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::RawBuffer: {
+    auto *RTy = cast<RawBufferExtType>(HandleTy);
+    formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
+                              TypeName);
+  }
+  case ResourceKind::StructuredBuffer: {
+    auto *RTy = cast<RawBufferExtType>(HandleTy);
+    formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
+                   RTy->isROV());
+    return StructType::create(RTy->getResourceType(), TypeName);
+  }
+  case ResourceKind::FeedbackTexture2D:
+  case ResourceKind::FeedbackTexture2DArray: {
+    auto *RTy = cast<FeedbackTextureExtType>(HandleTy);
+    TypeName = formatv("{0}<{1}>", getResourceKindName(Kind),
+                       llvm::to_underlying(RTy->getFeedbackType()));
+    return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
+                              TypeName);
+  }
+  case ResourceKind::CBuffer:
+    return StructType::create(HandleTy->getContext(), "cbuffer");
+  case ResourceKind::Sampler: {
+    auto *RTy = cast<SamplerExtType>(HandleTy);
+    TypeName = formatv("SamplerState<{0}>",
+                       llvm::to_underlying(RTy->getSamplerType()));
+    return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
+                              TypeName);
+  }
+  case ResourceKind::TBuffer:
+  case ResourceKind::RTAccelerationStructure:
+    llvm_unreachable("Unhandled resource kind");
+  case ResourceKind::Invalid:
+  case ResourceKind::NumEntries:
+    llvm_unreachable("Invalid resource kind");
+  }
+  llvm_unreachable("Unhandled ResourceKind enum");
+}
+
 bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
 
 bool ResourceTypeInfo::isCBuffer() const {
@@ -450,6 +525,15 @@ void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
   }
 }
 
+GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
+                                                  StringRef Name) {
+  assert(!Symbol && "Symbol has already been created");
+  Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
+                              GlobalValue::ExternalLinkage,
+                              /*Initializer=*/nullptr, Name);
+  return Symbol;
+}
+
 MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
                                             DXILResourceTypeMap &DRTM) const {
   return getAsMetadata(M, DRTM[getHandleTy()]);
@@ -474,13 +558,9 @@ MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
   };
 
   MDVals.push_back(getIntMD(Binding.RecordID));
-
-  // TODO: We need API to create a symbol of the appropriate type to emit here.
-  // See https://github.com/llvm/llvm-project/issues/116849
-  MDVals.push_back(
-      ValueAsMetadata::get(UndefValue::get(PointerType::getUnqual(Ctx))));
-  MDVals.push_back(MDString::get(Ctx, ""));
-
+  assert(Symbol && "Cannot yet create useful resource metadata without symbol");
+  MDVals.push_back(ValueAsMetadata::get(Symbol));
+  MDVals.push_back(MDString::get(Ctx, Symbol->getName()));
   MDVals.push_back(getIntMD(Binding.Space));
   MDVals.push_back(getIntMD(Binding.LowerBound));
   MDVals.push_back(getIntMD(Binding.Size));
@@ -590,6 +670,12 @@ void ResourceBindingInfo::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
 
 void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo RTI,
                                 const DataLayout &DL) const {
+  if (Symbol) {
+    OS << "  Symbol: ";
+    Symbol->printAsOperand(OS);
+    OS << "\n";
+  }
+
   OS << "  Binding:\n"
      << "    Record ID: " << Binding.RecordID << "\n"
      << "    Space: " << Binding.Space << "\n"
diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
index 9763fe6a8a3455..9443ccd9c82a53 100644
--- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
+++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp
@@ -77,6 +77,10 @@ static NamedMDNode *emitResourceMetadata(Module &M, DXILBindingMap &DBM,
                                          const dxil::Resources &MDResources) {
   LLVMContext &Context = M.getContext();
 
+  for (ResourceBindingInfo &RI : DBM)
+    if (!RI.hasSymbol())
+      RI.createSymbol(M, DRTM[RI.getHandleTy()].createElementStruct());
+
   SmallVector<Metadata *> SRVs, UAVs, CBufs, Smps;
   for (const ResourceBindingInfo &RI : DBM.srvs())
     SRVs.push_back(RI.getAsMetadata(M, DRTM));
diff --git a/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll b/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
new file mode 100644
index 00000000000000..5ac4baa96c6599
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/Metadata/resource-symbols.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -passes=dxil-translate-metadata %s | FileCheck %s
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+%struct.S = type { <4 x float>, <4 x i32> }
+
+define void @test() {
+  ; Buffer<float4>
+  %float4 = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 0, i32 1, i32 0, i1 false)
+  ; CHECK: %TypedBuffer = type { <4 x float> }
+
+  ; Buffer<int>
+  %int = call target("dx.TypedBuffer", i32, 0, 0, 1)
+      @llvm.dx.handle.fromBinding(i32 0, i32 1, i32 1, i32 0, i1 false)
+  ; CHECK: %TypedBuffer.0 = type { i32 }
+
+  ; Buffer<uint3>
+  %uint3 = call target("dx.TypedBuffer", <3 x i32>, 0, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 2, i32 1, i32 0, i1 false)
+  ; CHECK: %TypedBuffer.1 = type { <3 x i32> }
+
+  ; StructuredBuffer<S>
+  %struct0 = call target("dx.RawBuffer", %struct.S, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 10, i32 1, i32 0, i1 true)
+  ; CHECK: %StructuredBuffer = type { %struct.S }
+
+  ; ByteAddressBuffer
+  %byteaddr = call target("dx.RawBuffer", i8, 0, 0)
+      @llvm.dx.handle.fromBinding(i32 0, i32 20, i32 1, i32 0, i1 false)
+  ; CHECK: %ByteAddressBuffer = type { i32 }
+
+  ret void
+}
+
+; CHECK:      @[[T0:.*]] = external constant %TypedBuffer
+; CHECK-NEXT: @[[T1:.*]] = external constant %TypedBuffer.0
+; CHECK-NEXT: @[[T2:.*]] = external constant %TypedBuffer.1
+; CHECK-NEXT: @[[S0:.*]] = external constant %StructuredBuffer
+; CHECK-NEXT: @[[B0:.*]] = external constant %ByteAddressBuffer
+
+; CHECK: !{i32 0, ptr @[[T0]], !""
+; CHECK: !{i32 1, ptr @[[T1]], !""
+; CHECK: !{i32 2, ptr @[[T2]], !""
+; CHECK: !{i32 3, ptr @[[S0]], !""
+; CHECK: !{i32 4, ptr @[[B0]], !""
+
+attributes #0 = { nocallback nofree nosync nounwind willreturn memory(none) }
diff --git a/llvm/unittests/Analysis/DXILResourceTest.cpp b/llvm/unittests/Analysis/DXILResourceTest.cpp
index 784ea7702c0d5f..4c005f817af59d 100644
--- a/llvm/unittests/Analysis/DXILResourceTest.cpp
+++ b/llvm/unittests/Analysis/DXILResourceTest.cpp
@@ -120,7 +120,6 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   Type *Int32x2Ty = FixedVectorType::get(Int32Ty, 2);
 
   MDBuilder TestMD(Context, Int32Ty, Int1Ty);
-  Value *DummyGV = UndefValue::get(PointerType::getUnqual(Context));
 
   // ByteAddressBuffer Buffer;
   ResourceTypeInfo RTI(llvm::TargetExtType::get(
@@ -131,11 +130,12 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   ResourceBindingInfo RBI(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GlobalVariable *GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer");
   std::pair<uint32_t, uint32_t> Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000bU);
   EXPECT_EQ(Props.second, 0U);
   MDTuple *MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 11, 0, nullptr));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "Buffer", 0, 0, 1, 11, 0, nullptr));
 
   // RWByteAddressBuffer BufferOut : register(u3, space2);
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -149,12 +149,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/1, /*Space=*/2, /*LowerBound=*/3, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "BufferOut");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000100bU);
   EXPECT_EQ(Props.second, 0U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(1, DummyGV, "", 2, 3, 1, 11, false, false, false,
-                             nullptr));
+  EXPECT_MDEQ(MD, TestMD.get(1, GV, "BufferOut", 2, 3, 1, 11, false, false,
+                             false, nullptr));
 
   // struct BufType0 { int i; float f; double d; };
   // StructuredBuffer<BufType0> Buffer0 : register(t0);
@@ -171,12 +172,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer0");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000030cU);
   EXPECT_EQ(Props.second, 0x00000010U);
   MD = RBI.getAsMetadata(M, RTI);
   EXPECT_MDEQ(MD,
-              TestMD.get(0, DummyGV, "", 0, 0, 1, 12, 0, TestMD.get(1, 16)));
+              TestMD.get(0, GV, "Buffer0", 0, 0, 1, 12, 0, TestMD.get(1, 16)));
 
   // StructuredBuffer<float3> Buffer1 : register(t1);
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -190,12 +192,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/1, /*Space=*/0, /*LowerBound=*/1, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "Buffer1");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000cU);
   EXPECT_EQ(Props.second, 0x0000000cU);
   MD = RBI.getAsMetadata(M, RTI);
   EXPECT_MDEQ(MD,
-              TestMD.get(1, DummyGV, "", 0, 1, 1, 12, 0, TestMD.get(1, 12)));
+              TestMD.get(1, GV, "Buffer1", 0, 1, 1, 12, 0, TestMD.get(1, 12)));
 
   // Texture2D<float4> ColorMapTexture : register(t2);
   RTI = ResourceTypeInfo(
@@ -211,11 +214,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/2, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ColorMapTexture");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00000002U);
   EXPECT_EQ(Props.second, 0x00000409U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(2, DummyGV, "", 0, 2, 1, 2, 0, TestMD.get(0, 9)));
+  EXPECT_MDEQ(MD, TestMD.get(2, GV, "ColorMapTexture", 0, 2, 1, 2, 0,
+                             TestMD.get(0, 9)));
 
   // Texture2DMS<float, 8> DepthBuffer : register(t0);
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -233,11 +238,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "DepthBuffer");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00000003U);
   EXPECT_EQ(Props.second, 0x00080109U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 3, 8, TestMD.get(0, 9)));
+  EXPECT_MDEQ(
+      MD, TestMD.get(0, GV, "DepthBuffer", 0, 0, 1, 3, 8, TestMD.get(0, 9)));
 
   // FeedbackTexture2D<SAMPLER_FEEDBACK_MIN_MIP> feedbackMinMip;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -252,12 +259,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "feedbackMinMip");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001011U);
   EXPECT_EQ(Props.second, 0U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 17, false, false, false,
-                             TestMD.get(2, 0)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "feedbackMinMip", 0, 0, 1, 17, false, false,
+                             false, TestMD.get(2, 0)));
 
   // FeedbackTexture2DArray<SAMPLER_FEEDBACK_MIP_REGION_USED> feedbackMipRegion;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -272,12 +280,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "feedbackMipRegion");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001012U);
   EXPECT_EQ(Props.second, 0x00000001U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 18, false, false, false,
-                             TestMD.get(2, 1)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "feedbackMipRegion", 0, 0, 1, 18, false,
+                             false, false, TestMD.get(2, 1)));
 
   // globallycoherent RWTexture2D<int2> OutputTexture : register(u0, space2);
   RTI = ResourceTypeInfo(
@@ -296,12 +305,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/2, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "OutputTexture");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00005002U);
   EXPECT_EQ(Props.second, 0x00000204U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 2, 0, 1, 2, true, false, false,
-                             TestMD.get(0, 4)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "OutputTexture", 2, 0, 1, 2, true, false,
+                             false, TestMD.get(0, 4)));
 
   // RasterizerOrderedBuffer<float4> ROB;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -319,11 +329,12 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "ROB");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000300aU);
   EXPECT_EQ(Props.second, 0x00000409U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 10, false, false, true,
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "ROB", 0, 0, 1, 10, false, false, true,
                              TestMD.get(0, 9)));
 
   // RWStructuredBuffer<ParticleMotion> g_OutputBuffer : register(u2);
@@ -345,12 +356,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "g_OutputBuffer");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000920cU);
   EXPECT_EQ(Props.second, 0x00000014U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 2, 1, 12, false, true, false,
-                             TestMD.get(1, 20)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "g_OutputBuffer", 0, 2, 1, 12, false, true,
+                             false, TestMD.get(1, 20)));
 
   // RWTexture2DMSArray<uint, 8> g_rw_t2dmsa;
   RTI = ResourceTypeInfo(llvm::TargetExtType::get(
@@ -371,12 +383,13 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "g_rw_t2dmsa");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x00001008U);
   EXPECT_EQ(Props.second, 0x00080105U);
   MD = RBI.getAsMetadata(M, RTI);
-  EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 8, false, false, false,
-                             TestMD.get(0, 5)));
+  EXPECT_MDEQ(MD, TestMD.get(0, GV, "g_rw_t2dmsa", 0, 0, 1, 8, false, false,
+                             false, TestMD.get(0, 5)));
 
   // cbuffer cb0 { float4 g_X; float4 g_Y; }
   StructType *CBufType0 =
@@ -390,11 +403,12 @@ TEST(DXILResource, AnnotationsAndMetadata) {
   RBI = ResourceBindingInfo(
       /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1,
       RTI.getHandleTy());
+  GV = RBI.createSymbol(M, RTI.createElementStruct(), "");
   Props = RBI.getAnnotateProps(M, RTI);
   EXPECT_EQ(Props.first, 0x0000000dU);
   EXPECT_EQ(Props.second, 0x00000020U);
   MD = RB...
[truncated]

@hekota
Copy link
Member

hekota commented Dec 14, 2024

If there already is a global variable for the resource in the module, shouldn't we be using that instead of creating a new symbol?

@bogner
Copy link
Contributor Author

bogner commented Dec 16, 2024

If there already is a global variable for the resource in the module, shouldn't we be using that instead of creating a new symbol?

The only global variables in the module before this point are the globals for the resource handles. These are (1) the wrong type (they're the handle object itself) and (2) it isn't clear what's happening with them long term. The mechanism here creates a global of the type that DXIL wants in the final output.

@bogner bogner force-pushed the users/bogner/119773 branch 3 times, most recently from f8291d2 to 4f018d3 Compare December 16, 2024 23:15
@bogner bogner force-pushed the 2024-12-12-resource-symbols branch from 612bd2f to c668ae9 Compare December 16, 2024 23:21
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!

Copy link
Contributor

@spall spall left a comment

Choose a reason for hiding this comment

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

LGTM

We need to create symbols with "the original shape of resource and
element type" to put in the resource metadata in order to generate valid
DXIL.

Note that DXC generally doesn't emit an actual symbol outside of library
shaders (it emits an undef of a pointer to the type), but since we have
to deal with opaque pointers we would need a way to smuggle the type
through to match that. Instead, we simply emit symbols for now.

Fixed llvm#116849
@bogner bogner changed the base branch from users/bogner/119773 to main December 18, 2024 16:09
@bogner bogner force-pushed the 2024-12-12-resource-symbols branch from c668ae9 to 4e5ac01 Compare December 18, 2024 16:09
@bogner bogner linked an issue Dec 18, 2024 that may be closed by this pull request
@bogner bogner merged commit 0e2466f into llvm:main Dec 18, 2024
6 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

[DirectX] Don't emit %dxilOpaquePtrReservedName for resource globals
4 participants