Skip to content

Commit 0e2466f

Browse files
authored
[DirectX] Create symbols for resource handles (#119775)
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
1 parent 79e859e commit 0e2466f

File tree

5 files changed

+194
-36
lines changed

5 files changed

+194
-36
lines changed

llvm/include/llvm/Analysis/DXILResource.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ class ResourceTypeInfo {
271271
GloballyCoherent, HasCounter) {}
272272

273273
TargetExtType *getHandleTy() const { return HandleTy; }
274+
StructType *createElementStruct();
274275

275276
// Conditions to check before accessing specific views.
276277
bool isUAV() const;
@@ -329,28 +330,31 @@ class ResourceBindingInfo {
329330
private:
330331
ResourceBinding Binding;
331332
TargetExtType *HandleTy;
333+
GlobalVariable *Symbol = nullptr;
332334

333335
public:
334336
ResourceBindingInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
335-
uint32_t Size, TargetExtType *HandleTy)
336-
: Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy) {}
337+
uint32_t Size, TargetExtType *HandleTy,
338+
GlobalVariable *Symbol = nullptr)
339+
: Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
340+
Symbol(Symbol) {}
337341

338342
void setBindingID(unsigned ID) { Binding.RecordID = ID; }
339343

340344
const ResourceBinding &getBinding() const { return Binding; }
341345
TargetExtType *getHandleTy() const { return HandleTy; }
342-
const StringRef getName() const {
343-
// TODO: Get the name from the symbol once we include one here.
344-
return "";
345-
}
346+
const StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
346347

348+
bool hasSymbol() const { return Symbol; }
349+
GlobalVariable *createSymbol(Module &M, StructType *Ty, StringRef Name = "");
347350
MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo &RTI) const;
348351

349352
std::pair<uint32_t, uint32_t>
350353
getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const;
351354

352355
bool operator==(const ResourceBindingInfo &RHS) const {
353-
return std::tie(Binding, HandleTy) == std::tie(RHS.Binding, RHS.HandleTy);
356+
return std::tie(Binding, HandleTy, Symbol) ==
357+
std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
354358
}
355359
bool operator!=(const ResourceBindingInfo &RHS) const {
356360
return !(*this == RHS);

llvm/lib/Analysis/DXILResource.cpp

Lines changed: 93 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,81 @@ ResourceTypeInfo::ResourceTypeInfo(TargetExtType *HandleTy,
216216
llvm_unreachable("Unknown handle type");
217217
}
218218

219+
static void formatTypeName(SmallString<64> &Dest, StringRef Name,
220+
bool isWriteable, bool isROV) {
221+
Dest = isWriteable ? (isROV ? "RasterizerOrdered" : "RW") : "";
222+
Dest += Name;
223+
}
224+
225+
StructType *ResourceTypeInfo::createElementStruct() {
226+
SmallString<64> TypeName;
227+
228+
switch (Kind) {
229+
case ResourceKind::Texture1D:
230+
case ResourceKind::Texture2D:
231+
case ResourceKind::Texture3D:
232+
case ResourceKind::TextureCube:
233+
case ResourceKind::Texture1DArray:
234+
case ResourceKind::Texture2DArray:
235+
case ResourceKind::TextureCubeArray: {
236+
auto *RTy = cast<TextureExtType>(HandleTy);
237+
formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
238+
RTy->isROV());
239+
return StructType::create(RTy->getResourceType(), TypeName);
240+
}
241+
case ResourceKind::Texture2DMS:
242+
case ResourceKind::Texture2DMSArray: {
243+
auto *RTy = cast<MSTextureExtType>(HandleTy);
244+
formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
245+
/*IsROV=*/false);
246+
return StructType::create(RTy->getResourceType(), TypeName);
247+
}
248+
case ResourceKind::TypedBuffer: {
249+
auto *RTy = cast<TypedBufferExtType>(HandleTy);
250+
formatTypeName(TypeName, getResourceKindName(Kind), RTy->isWriteable(),
251+
RTy->isROV());
252+
return StructType::create(RTy->getResourceType(), TypeName);
253+
}
254+
case ResourceKind::RawBuffer: {
255+
auto *RTy = cast<RawBufferExtType>(HandleTy);
256+
formatTypeName(TypeName, "ByteAddressBuffer", RTy->isWriteable(),
257+
RTy->isROV());
258+
return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
259+
TypeName);
260+
}
261+
case ResourceKind::StructuredBuffer: {
262+
auto *RTy = cast<RawBufferExtType>(HandleTy);
263+
formatTypeName(TypeName, "StructuredBuffer", RTy->isWriteable(),
264+
RTy->isROV());
265+
return StructType::create(RTy->getResourceType(), TypeName);
266+
}
267+
case ResourceKind::FeedbackTexture2D:
268+
case ResourceKind::FeedbackTexture2DArray: {
269+
auto *RTy = cast<FeedbackTextureExtType>(HandleTy);
270+
TypeName = formatv("{0}<{1}>", getResourceKindName(Kind),
271+
llvm::to_underlying(RTy->getFeedbackType()));
272+
return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
273+
TypeName);
274+
}
275+
case ResourceKind::CBuffer:
276+
return StructType::create(HandleTy->getContext(), "cbuffer");
277+
case ResourceKind::Sampler: {
278+
auto *RTy = cast<SamplerExtType>(HandleTy);
279+
TypeName = formatv("SamplerState<{0}>",
280+
llvm::to_underlying(RTy->getSamplerType()));
281+
return StructType::create(Type::getInt32Ty(HandleTy->getContext()),
282+
TypeName);
283+
}
284+
case ResourceKind::TBuffer:
285+
case ResourceKind::RTAccelerationStructure:
286+
llvm_unreachable("Unhandled resource kind");
287+
case ResourceKind::Invalid:
288+
case ResourceKind::NumEntries:
289+
llvm_unreachable("Invalid resource kind");
290+
}
291+
llvm_unreachable("Unhandled ResourceKind enum");
292+
}
293+
219294
bool ResourceTypeInfo::isUAV() const { return RC == ResourceClass::UAV; }
220295

221296
bool ResourceTypeInfo::isCBuffer() const {
@@ -449,6 +524,15 @@ void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
449524
}
450525
}
451526

527+
GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
528+
StringRef Name) {
529+
assert(!Symbol && "Symbol has already been created");
530+
Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
531+
GlobalValue::ExternalLinkage,
532+
/*Initializer=*/nullptr, Name);
533+
return Symbol;
534+
}
535+
452536
MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
453537
dxil::ResourceTypeInfo &RTI) const {
454538
LLVMContext &Ctx = M.getContext();
@@ -468,13 +552,9 @@ MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
468552
};
469553

470554
MDVals.push_back(getIntMD(Binding.RecordID));
471-
472-
// TODO: We need API to create a symbol of the appropriate type to emit here.
473-
// See https://github.com/llvm/llvm-project/issues/116849
474-
MDVals.push_back(
475-
ValueAsMetadata::get(UndefValue::get(PointerType::getUnqual(Ctx))));
476-
MDVals.push_back(MDString::get(Ctx, ""));
477-
555+
assert(Symbol && "Cannot yet create useful resource metadata without symbol");
556+
MDVals.push_back(ValueAsMetadata::get(Symbol));
557+
MDVals.push_back(MDString::get(Ctx, Symbol->getName()));
478558
MDVals.push_back(getIntMD(Binding.Space));
479559
MDVals.push_back(getIntMD(Binding.LowerBound));
480560
MDVals.push_back(getIntMD(Binding.Size));
@@ -573,6 +653,12 @@ ResourceBindingInfo::getAnnotateProps(Module &M,
573653

574654
void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI,
575655
const DataLayout &DL) const {
656+
if (Symbol) {
657+
OS << " Symbol: ";
658+
Symbol->printAsOperand(OS);
659+
OS << "\n";
660+
}
661+
576662
OS << " Binding:\n"
577663
<< " Record ID: " << Binding.RecordID << "\n"
578664
<< " Space: " << Binding.Space << "\n"

llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ static NamedMDNode *emitResourceMetadata(Module &M, DXILBindingMap &DBM,
7777
const dxil::Resources &MDResources) {
7878
LLVMContext &Context = M.getContext();
7979

80+
for (ResourceBindingInfo &RI : DBM)
81+
if (!RI.hasSymbol())
82+
RI.createSymbol(M, DRTM[RI.getHandleTy()].createElementStruct());
83+
8084
SmallVector<Metadata *> SRVs, UAVs, CBufs, Smps;
8185
for (const ResourceBindingInfo &RI : DBM.srvs())
8286
SRVs.push_back(RI.getAsMetadata(M, DRTM[RI.getHandleTy()]));
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
; RUN: opt -S -passes=dxil-translate-metadata %s | FileCheck %s
2+
3+
target triple = "dxil-pc-shadermodel6.6-compute"
4+
5+
%struct.S = type { <4 x float>, <4 x i32> }
6+
7+
define void @test() {
8+
; Buffer<float4>
9+
%float4 = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0)
10+
@llvm.dx.handle.fromBinding(i32 0, i32 0, i32 1, i32 0, i1 false)
11+
; CHECK: %TypedBuffer = type { <4 x float> }
12+
13+
; Buffer<int>
14+
%int = call target("dx.TypedBuffer", i32, 0, 0, 1)
15+
@llvm.dx.handle.fromBinding(i32 0, i32 1, i32 1, i32 0, i1 false)
16+
; CHECK: %TypedBuffer.0 = type { i32 }
17+
18+
; Buffer<uint3>
19+
%uint3 = call target("dx.TypedBuffer", <3 x i32>, 0, 0, 0)
20+
@llvm.dx.handle.fromBinding(i32 0, i32 2, i32 1, i32 0, i1 false)
21+
; CHECK: %TypedBuffer.1 = type { <3 x i32> }
22+
23+
; StructuredBuffer<S>
24+
%struct0 = call target("dx.RawBuffer", %struct.S, 0, 0)
25+
@llvm.dx.handle.fromBinding(i32 0, i32 10, i32 1, i32 0, i1 true)
26+
; CHECK: %StructuredBuffer = type { %struct.S }
27+
28+
; ByteAddressBuffer
29+
%byteaddr = call target("dx.RawBuffer", i8, 0, 0)
30+
@llvm.dx.handle.fromBinding(i32 0, i32 20, i32 1, i32 0, i1 false)
31+
; CHECK: %ByteAddressBuffer = type { i32 }
32+
33+
ret void
34+
}
35+
36+
; CHECK: @[[T0:.*]] = external constant %TypedBuffer
37+
; CHECK-NEXT: @[[T1:.*]] = external constant %TypedBuffer.0
38+
; CHECK-NEXT: @[[T2:.*]] = external constant %TypedBuffer.1
39+
; CHECK-NEXT: @[[S0:.*]] = external constant %StructuredBuffer
40+
; CHECK-NEXT: @[[B0:.*]] = external constant %ByteAddressBuffer
41+
42+
; CHECK: !{i32 0, ptr @[[T0]], !""
43+
; CHECK: !{i32 1, ptr @[[T1]], !""
44+
; CHECK: !{i32 2, ptr @[[T2]], !""
45+
; CHECK: !{i32 3, ptr @[[S0]], !""
46+
; CHECK: !{i32 4, ptr @[[B0]], !""
47+
48+
attributes #0 = { nocallback nofree nosync nounwind willreturn memory(none) }

0 commit comments

Comments
 (0)