Skip to content

Commit 612bd2f

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 7bf113d commit 612bd2f

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
@@ -270,6 +270,7 @@ class ResourceTypeInfo {
270270
GloballyCoherent, HasCounter) {}
271271

272272
TargetExtType *getHandleTy() const { return HandleTy; }
273+
StructType *createElementStruct();
273274

274275
// Conditions to check before accessing specific views.
275276
bool isUAV() const;
@@ -325,21 +326,23 @@ class ResourceBindingInfo {
325326
private:
326327
ResourceBinding Binding;
327328
TargetExtType *HandleTy;
329+
GlobalVariable *Symbol = nullptr;
328330

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

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

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

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

@@ -349,7 +352,8 @@ class ResourceBindingInfo {
349352
getAnnotateProps(Module &M, dxil::ResourceTypeInfo RTI) const;
350353

351354
bool operator==(const ResourceBindingInfo &RHS) const {
352-
return std::tie(Binding, HandleTy) == std::tie(RHS.Binding, RHS.HandleTy);
355+
return std::tie(Binding, HandleTy, Symbol) ==
356+
std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol);
353357
}
354358
bool operator!=(const ResourceBindingInfo &RHS) const {
355359
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 {
@@ -450,6 +525,15 @@ void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
450525
}
451526
}
452527

528+
GlobalVariable *ResourceBindingInfo::createSymbol(Module &M, StructType *Ty,
529+
StringRef Name) {
530+
assert(!Symbol && "Symbol has already been created");
531+
Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
532+
GlobalValue::ExternalLinkage,
533+
/*Initializer=*/nullptr, Name);
534+
return Symbol;
535+
}
536+
453537
MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
454538
DXILResourceTypeMap &DRTM) const {
455539
return getAsMetadata(M, DRTM[getHandleTy()]);
@@ -474,13 +558,9 @@ MDTuple *ResourceBindingInfo::getAsMetadata(Module &M,
474558
};
475559

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

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