Skip to content

Commit 618e500

Browse files
committed
[DirectX] Generate dx.resources metadata entry
This code adds initial support for generating the HLSL resources metadata entries. It has a lot of `FIXMEs` laying around because there is a lot more work to do here, but this lays a solid groundwork and can accurately handle some trivial cases. I've filed a swath of issues covering the deficiencies here and left the issues in comments so that we can easily follow them. One big change to make sooner rather than later is to move some of this code into a new libLLVMFrontendHLSL so that we can share it with the Clang CodeGen layer. Reviewed By: python3kgae Differential Revision: https://reviews.llvm.org/D134682
1 parent 3d7946c commit 618e500

File tree

5 files changed

+380
-0
lines changed

5 files changed

+380
-0
lines changed

llvm/lib/Target/DirectX/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ add_llvm_target(DirectXCodeGen
2121
DXILOpBuilder.cpp
2222
DXILOpLowering.cpp
2323
DXILPrepare.cpp
24+
DXILResource.cpp
2425
DXILTranslateMetadata.cpp
2526
PointerTypeAnalysis.cpp
2627

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
//===- DXILResource.cpp - DXIL Resource helper objects --------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file This file contains helper objects for working with DXIL Resources.
10+
///
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "DXILResource.h"
14+
#include "llvm/ADT/StringSwitch.h"
15+
#include "llvm/IR/IRBuilder.h"
16+
#include "llvm/IR/Metadata.h"
17+
#include "llvm/IR/Module.h"
18+
19+
using namespace llvm;
20+
using namespace llvm::dxil;
21+
22+
GlobalVariable *FrontendResource::getGlobalVariable() {
23+
return cast<GlobalVariable>(
24+
cast<ConstantAsMetadata>(Entry->getOperand(0))->getValue());
25+
}
26+
27+
StringRef FrontendResource::getSourceType() {
28+
return cast<MDString>(Entry->getOperand(1))->getString();
29+
}
30+
31+
Constant *FrontendResource::getID() {
32+
return cast<ConstantAsMetadata>(Entry->getOperand(2))->getValue();
33+
}
34+
35+
void Resources::collectUAVs() {
36+
NamedMDNode *Entry = Mod.getNamedMetadata("hlsl.uavs");
37+
if (!Entry || Entry->getNumOperands() == 0)
38+
return;
39+
40+
uint32_t Counter = 0;
41+
for (auto *UAV : Entry->operands()) {
42+
UAVs.push_back(UAVResource(Counter++, FrontendResource(cast<MDNode>(UAV))));
43+
}
44+
}
45+
46+
ResourceBase::ResourceBase(uint32_t I, FrontendResource R)
47+
: ID(I), GV(R.getGlobalVariable()), Name(""), Space(0), LowerBound(0),
48+
RangeSize(1) {
49+
if (auto *ArrTy = dyn_cast<ArrayType>(GV->getInitializer()->getType()))
50+
RangeSize = ArrTy->getNumElements();
51+
}
52+
53+
UAVResource::UAVResource(uint32_t I, FrontendResource R)
54+
: ResourceBase(I, R), Shape(Kinds::Invalid), GloballyCoherent(false),
55+
HasCounter(false), IsROV(false), ExtProps() {
56+
parseSourceType(R.getSourceType());
57+
}
58+
59+
// FIXME: Capture this in HLSL source. I would go do this right now, but I want
60+
// to get this in first so that I can make sure to capture all the extra
61+
// information we need to remove the source type string from here (See issue:
62+
// https://github.com/llvm/llvm-project/issues/57991).
63+
void UAVResource::parseSourceType(StringRef S) {
64+
IsROV = S.startswith("RasterizerOrdered");
65+
if (IsROV)
66+
S = S.substr(strlen("RasterizerOrdered"));
67+
if (S.startswith("RW"))
68+
S = S.substr(strlen("RW"));
69+
70+
// Note: I'm deliberately not handling any of the Texture buffer types at the
71+
// moment. I want to resolve the issue above before adding Texture or Sampler
72+
// support.
73+
Shape = StringSwitch<ResourceBase::Kinds>(S)
74+
.StartsWith("Buffer<", Kinds::TypedBuffer)
75+
.StartsWith("ByteAddressBuffer<", Kinds::RawBuffer)
76+
.StartsWith("StructuredBuffer<", Kinds::StructuredBuffer)
77+
.Default(Kinds::Invalid);
78+
assert(Shape != Kinds::Invalid && "Unsupported buffer type");
79+
80+
S = S.substr(S.find("<") + 1);
81+
82+
constexpr size_t PrefixLen = StringRef("vector<").size();
83+
if (S.startswith("vector<"))
84+
S = S.substr(PrefixLen, S.find(",") - PrefixLen);
85+
else
86+
S = S.substr(0, S.find(">"));
87+
88+
ComponentType ElTy = StringSwitch<ResourceBase::ComponentType>(S)
89+
.Case("bool", ComponentType::I1)
90+
.Case("int16_t", ComponentType::I16)
91+
.Case("uint16_t", ComponentType::U16)
92+
.Case("int32_t", ComponentType::I32)
93+
.Case("uint32_t", ComponentType::U32)
94+
.Case("int64_t", ComponentType::I64)
95+
.Case("uint64_t", ComponentType::U64)
96+
.Case("half", ComponentType::F16)
97+
.Case("float", ComponentType::F32)
98+
.Case("double", ComponentType::F64)
99+
.Default(ComponentType::Invalid);
100+
if (ElTy != ComponentType::Invalid)
101+
ExtProps.ElementType = ElTy;
102+
}
103+
104+
MDNode *ResourceBase::ExtendedProperties::write(LLVMContext &Ctx) {
105+
IRBuilder<> B(Ctx);
106+
SmallVector<Metadata *> Entries;
107+
if (ElementType) {
108+
Entries.emplace_back(
109+
ConstantAsMetadata::get(B.getInt32(TypedBufferElementType)));
110+
Entries.emplace_back(ConstantAsMetadata::get(
111+
B.getInt32(static_cast<uint32_t>(*ElementType))));
112+
}
113+
if (Entries.empty())
114+
return nullptr;
115+
return MDNode::get(Ctx, Entries);
116+
}
117+
118+
void ResourceBase::write(LLVMContext &Ctx,
119+
MutableArrayRef<Metadata *> Entries) {
120+
IRBuilder<> B(Ctx);
121+
Entries[0] = ConstantAsMetadata::get(B.getInt32(ID));
122+
Entries[1] = ConstantAsMetadata::get(GV);
123+
Entries[2] = MDString::get(Ctx, Name);
124+
Entries[3] = ConstantAsMetadata::get(B.getInt32(Space));
125+
Entries[4] = ConstantAsMetadata::get(B.getInt32(LowerBound));
126+
Entries[5] = ConstantAsMetadata::get(B.getInt32(RangeSize));
127+
}
128+
129+
MDNode *UAVResource::write() {
130+
auto &Ctx = GV->getContext();
131+
IRBuilder<> B(Ctx);
132+
Metadata *Entries[11];
133+
ResourceBase::write(Ctx, Entries);
134+
Entries[6] =
135+
ConstantAsMetadata::get(B.getInt32(static_cast<uint32_t>(Shape)));
136+
Entries[7] = ConstantAsMetadata::get(B.getInt1(GloballyCoherent));
137+
Entries[8] = ConstantAsMetadata::get(B.getInt1(HasCounter));
138+
Entries[9] = ConstantAsMetadata::get(B.getInt1(IsROV));
139+
Entries[10] = ExtProps.write(Ctx);
140+
return MDNode::get(Ctx, Entries);
141+
}
142+
143+
void Resources::write() {
144+
Metadata *ResourceMDs[4] = {nullptr, nullptr, nullptr, nullptr};
145+
SmallVector<Metadata *> UAVMDs;
146+
for (auto &UAV : UAVs)
147+
UAVMDs.emplace_back(UAV.write());
148+
149+
if (!UAVMDs.empty())
150+
ResourceMDs[1] = MDNode::get(Mod.getContext(), UAVMDs);
151+
152+
NamedMDNode *DXResMD = Mod.getOrInsertNamedMetadata("dx.resources");
153+
DXResMD->addOperand(MDNode::get(Mod.getContext(), ResourceMDs));
154+
155+
NamedMDNode *Entry = Mod.getNamedMetadata("hlsl.uavs");
156+
if (Entry)
157+
Entry->eraseFromParent();
158+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//===- DXILResource.h - DXIL Resource helper objects ----------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file This file contains helper objects for working with DXIL Resources.
10+
///
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_TARGET_DIRECTX_DXILRESOURCE_H
14+
#define LLVM_TARGET_DIRECTX_DXILRESOURCE_H
15+
16+
#include "llvm/ADT/Optional.h"
17+
#include "llvm/ADT/SmallVector.h"
18+
#include "llvm/ADT/StringRef.h"
19+
#include "llvm/IR/Metadata.h"
20+
#include <cstdint>
21+
22+
namespace llvm {
23+
class Module;
24+
class GlobalVariable;
25+
26+
namespace dxil {
27+
28+
// FIXME: Ultimately this class and some of these utilities should be moved into
29+
// a new LLVMFrontendHLSL library so that they can be reused in Clang.
30+
// See issue https://github.com/llvm/llvm-project/issues/58000.
31+
class FrontendResource {
32+
MDNode *Entry;
33+
34+
public:
35+
FrontendResource(MDNode *E) : Entry(E) {
36+
assert(Entry->getNumOperands() == 3 && "Unexpected metadata shape");
37+
}
38+
39+
GlobalVariable *getGlobalVariable();
40+
StringRef getSourceType();
41+
Constant *getID();
42+
};
43+
44+
class ResourceBase {
45+
protected:
46+
uint32_t ID;
47+
GlobalVariable *GV;
48+
StringRef Name;
49+
uint32_t Space;
50+
uint32_t LowerBound;
51+
uint32_t RangeSize;
52+
ResourceBase(uint32_t I, FrontendResource R);
53+
54+
void write(LLVMContext &Ctx, MutableArrayRef<Metadata *> Entries);
55+
56+
// The value ordering of this enumeration is part of the DXIL ABI. Elements
57+
// can only be added to the end, and not removed.
58+
enum class Kinds : uint32_t {
59+
Invalid = 0,
60+
Texture1D,
61+
Texture2D,
62+
Texture2DMS,
63+
Texture3D,
64+
TextureCube,
65+
Texture1DArray,
66+
Texture2DArray,
67+
Texture2DMSArray,
68+
TextureCubeArray,
69+
TypedBuffer,
70+
RawBuffer,
71+
StructuredBuffer,
72+
CBuffer,
73+
Sampler,
74+
TBuffer,
75+
RTAccelerationStructure,
76+
FeedbackTexture2D,
77+
FeedbackTexture2DArray,
78+
NumEntries,
79+
};
80+
81+
// The value ordering of this enumeration is part of the DXIL ABI. Elements
82+
// can only be added to the end, and not removed.
83+
enum class ComponentType : uint32_t {
84+
Invalid = 0,
85+
I1,
86+
I16,
87+
U16,
88+
I32,
89+
U32,
90+
I64,
91+
U64,
92+
F16,
93+
F32,
94+
F64,
95+
SNormF16,
96+
UNormF16,
97+
SNormF32,
98+
UNormF32,
99+
SNormF64,
100+
UNormF64,
101+
PackedS8x32,
102+
PackedU8x32,
103+
LastEntry
104+
};
105+
106+
public:
107+
struct ExtendedProperties {
108+
llvm::Optional<ComponentType> ElementType;
109+
110+
// The value ordering of this enumeration is part of the DXIL ABI. Elements
111+
// can only be added to the end, and not removed.
112+
enum Tags : uint32_t {
113+
TypedBufferElementType = 0,
114+
StructuredBufferElementStride,
115+
SamplerFeedbackKind,
116+
Atomic64Use
117+
};
118+
119+
MDNode *write(LLVMContext &Ctx);
120+
};
121+
};
122+
123+
class UAVResource : public ResourceBase {
124+
ResourceBase::Kinds Shape;
125+
bool GloballyCoherent;
126+
bool HasCounter;
127+
bool IsROV;
128+
ResourceBase::ExtendedProperties ExtProps;
129+
130+
void parseSourceType(StringRef S);
131+
132+
public:
133+
UAVResource(uint32_t I, FrontendResource R);
134+
135+
MDNode *write();
136+
};
137+
138+
// FIXME: Fully computing the resource structures requires analyzing the IR
139+
// because some flags are set based on what operations are performed on the
140+
// resource. This partial patch handles some of the leg work, but not all of it.
141+
// See issue https://github.com/llvm/llvm-project/issues/57936.
142+
class Resources {
143+
Module &Mod;
144+
llvm::SmallVector<UAVResource> UAVs;
145+
146+
void collectUAVs();
147+
148+
public:
149+
Resources(Module &M) : Mod(M) { collectUAVs(); }
150+
151+
void write();
152+
};
153+
154+
} // namespace dxil
155+
} // namespace llvm
156+
157+
#endif // LLVM_TARGET_DIRECTX_DXILRESOURCE_H

llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//===----------------------------------------------------------------------===//
1010

1111
#include "DXILMetadata.h"
12+
#include "DXILResource.h"
1213
#include "DirectX.h"
1314
#include "llvm/ADT/StringSet.h"
1415
#include "llvm/ADT/Triple.h"
@@ -38,6 +39,9 @@ bool DXILTranslateMetadata::runOnModule(Module &M) {
3839
if (ValVerMD.isEmpty())
3940
ValVerMD.update(VersionTuple(1, 0));
4041
dxil::createShaderModelMD(M);
42+
43+
dxil::Resources Res(M);
44+
Res.write();
4145
return false;
4246
}
4347

0 commit comments

Comments
 (0)