Skip to content

Commit c668ae9

Browse files
committed
[DirectX] Create symbols for resource handles
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 4f018d3 commit c668ae9

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;
@@ -326,21 +327,23 @@ class ResourceBindingInfo {
326327
private:
327328
ResourceBinding Binding;
328329
TargetExtType *HandleTy;
330+
GlobalVariable *Symbol = nullptr;
329331

330332
public:
331333
ResourceBindingInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
332-
uint32_t Size, TargetExtType *HandleTy)
333-
: Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy) {}
334+
uint32_t Size, TargetExtType *HandleTy,
335+
GlobalVariable *Symbol = nullptr)
336+
: Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
337+
Symbol(Symbol) {}
334338

335339
void setBindingID(unsigned ID) { Binding.RecordID = ID; }
336340

337341
const ResourceBinding &getBinding() const { return Binding; }
338342
TargetExtType *getHandleTy() const { return HandleTy; }
339-
const StringRef getName() const {
340-
// TODO: Get the name from the symbol once we include one here.
341-
return "";
342-
}
343+
const StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
343344

345+
bool hasSymbol() const { return Symbol; }
346+
GlobalVariable *createSymbol(Module &M, StructType *Ty, StringRef Name = "");
344347
MDTuple *getAsMetadata(Module &M, DXILResourceTypeMap &DRTM) const;
345348
MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo RTI) const;
346349

@@ -350,7 +353,8 @@ class ResourceBindingInfo {
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
DXILResourceTypeMap &DRTM) const {
454538
return getAsMetadata(M, DRTM[getHandleTy()]);
@@ -473,13 +557,9 @@ MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
473557
};
474558

475559
MDVals.push_back(getIntMD(Binding.RecordID));
476-
477-
// TODO: We need API to create a symbol of the appropriate type to emit here.
478-
// See https://github.com/llvm/llvm-project/issues/116849
479-
MDVals.push_back(
480-
ValueAsMetadata::get(UndefValue::get(PointerType::getUnqual(Ctx))));
481-
MDVals.push_back(MDString::get(Ctx, ""));
482-
560+
assert(Symbol && "Cannot yet create useful resource metadata without symbol");
561+
MDVals.push_back(ValueAsMetadata::get(Symbol));
562+
MDVals.push_back(MDString::get(Ctx, Symbol->getName()));
483563
MDVals.push_back(getIntMD(Binding.Space));
484564
MDVals.push_back(getIntMD(Binding.LowerBound));
485565
MDVals.push_back(getIntMD(Binding.Size));
@@ -589,6 +669,12 @@ void ResourceBindingInfo::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
589669

590670
void ResourceBindingInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo RTI,
591671
const DataLayout &DL) const {
672+
if (Symbol) {
673+
OS << " Symbol: ";
674+
Symbol->printAsOperand(OS);
675+
OS << "\n";
676+
}
677+
592678
OS << " Binding:\n"
593679
<< " Record ID: " << Binding.RecordID << "\n"
594680
<< " 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));
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)