1 //===- RootSignatureMetadata.h - HLSL Root Signature helpers --------------===//
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 implements a library for working with HLSL Root Signatures
10 /// and their metadata representation.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
15 #include "llvm/IR/IRBuilder.h"
16 #include "llvm/IR/Metadata.h"
17 #include "llvm/Support/ScopedPrinter.h"
18
19 namespace llvm {
20 namespace hlsl {
21 namespace rootsig {
22
23 static const EnumEntry<dxil::ResourceClass> ResourceClassNames[] = {
24 {"CBV", dxil::ResourceClass::CBuffer},
25 {"SRV", dxil::ResourceClass::SRV},
26 {"UAV", dxil::ResourceClass::UAV},
27 {"Sampler", dxil::ResourceClass::Sampler},
28 };
29
getResourceName(dxil::ResourceClass Class)30 static std::optional<StringRef> getResourceName(dxil::ResourceClass Class) {
31 for (const auto &ClassEnum : ResourceClassNames)
32 if (ClassEnum.Value == Class)
33 return ClassEnum.Name;
34 return std::nullopt;
35 }
36
37 namespace {
38
39 // We use the OverloadVisit with std::visit to ensure the compiler catches if a
40 // new RootElement variant type is added but it's metadata generation isn't
41 // handled.
42 template <class... Ts> struct OverloadedVisit : Ts... {
43 using Ts::operator()...;
44 };
45 template <class... Ts> OverloadedVisit(Ts...) -> OverloadedVisit<Ts...>;
46
47 } // namespace
48
BuildRootSignature()49 MDNode *MetadataBuilder::BuildRootSignature() {
50 const auto Visitor = OverloadedVisit{
51 [this](const dxbc::RootFlags &Flags) -> MDNode * {
52 return BuildRootFlags(Flags);
53 },
54 [this](const RootConstants &Constants) -> MDNode * {
55 return BuildRootConstants(Constants);
56 },
57 [this](const RootDescriptor &Descriptor) -> MDNode * {
58 return BuildRootDescriptor(Descriptor);
59 },
60 [this](const DescriptorTableClause &Clause) -> MDNode * {
61 return BuildDescriptorTableClause(Clause);
62 },
63 [this](const DescriptorTable &Table) -> MDNode * {
64 return BuildDescriptorTable(Table);
65 },
66 [this](const StaticSampler &Sampler) -> MDNode * {
67 return BuildStaticSampler(Sampler);
68 },
69 };
70
71 for (const RootElement &Element : Elements) {
72 MDNode *ElementMD = std::visit(Visitor, Element);
73 assert(ElementMD != nullptr &&
74 "Root Element must be initialized and validated");
75 GeneratedMetadata.push_back(ElementMD);
76 }
77
78 return MDNode::get(Ctx, GeneratedMetadata);
79 }
80
BuildRootFlags(const dxbc::RootFlags & Flags)81 MDNode *MetadataBuilder::BuildRootFlags(const dxbc::RootFlags &Flags) {
82 IRBuilder<> Builder(Ctx);
83 Metadata *Operands[] = {
84 MDString::get(Ctx, "RootFlags"),
85 ConstantAsMetadata::get(Builder.getInt32(llvm::to_underlying(Flags))),
86 };
87 return MDNode::get(Ctx, Operands);
88 }
89
BuildRootConstants(const RootConstants & Constants)90 MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {
91 IRBuilder<> Builder(Ctx);
92 Metadata *Operands[] = {
93 MDString::get(Ctx, "RootConstants"),
94 ConstantAsMetadata::get(
95 Builder.getInt32(llvm::to_underlying(Constants.Visibility))),
96 ConstantAsMetadata::get(Builder.getInt32(Constants.Reg.Number)),
97 ConstantAsMetadata::get(Builder.getInt32(Constants.Space)),
98 ConstantAsMetadata::get(Builder.getInt32(Constants.Num32BitConstants)),
99 };
100 return MDNode::get(Ctx, Operands);
101 }
102
BuildRootDescriptor(const RootDescriptor & Descriptor)103 MDNode *MetadataBuilder::BuildRootDescriptor(const RootDescriptor &Descriptor) {
104 IRBuilder<> Builder(Ctx);
105 std::optional<StringRef> ResName = getResourceName(
106 dxil::ResourceClass(llvm::to_underlying(Descriptor.Type)));
107 assert(ResName && "Provided an invalid Resource Class");
108 llvm::SmallString<7> Name({"Root", *ResName});
109 Metadata *Operands[] = {
110 MDString::get(Ctx, Name),
111 ConstantAsMetadata::get(
112 Builder.getInt32(llvm::to_underlying(Descriptor.Visibility))),
113 ConstantAsMetadata::get(Builder.getInt32(Descriptor.Reg.Number)),
114 ConstantAsMetadata::get(Builder.getInt32(Descriptor.Space)),
115 ConstantAsMetadata::get(
116 Builder.getInt32(llvm::to_underlying(Descriptor.Flags))),
117 };
118 return MDNode::get(Ctx, Operands);
119 }
120
BuildDescriptorTable(const DescriptorTable & Table)121 MDNode *MetadataBuilder::BuildDescriptorTable(const DescriptorTable &Table) {
122 IRBuilder<> Builder(Ctx);
123 SmallVector<Metadata *> TableOperands;
124 // Set the mandatory arguments
125 TableOperands.push_back(MDString::get(Ctx, "DescriptorTable"));
126 TableOperands.push_back(ConstantAsMetadata::get(
127 Builder.getInt32(llvm::to_underlying(Table.Visibility))));
128
129 // Remaining operands are references to the table's clauses. The in-memory
130 // representation of the Root Elements created from parsing will ensure that
131 // the previous N elements are the clauses for this table.
132 assert(Table.NumClauses <= GeneratedMetadata.size() &&
133 "Table expected all owned clauses to be generated already");
134 // So, add a refence to each clause to our operands
135 TableOperands.append(GeneratedMetadata.end() - Table.NumClauses,
136 GeneratedMetadata.end());
137 // Then, remove those clauses from the general list of Root Elements
138 GeneratedMetadata.pop_back_n(Table.NumClauses);
139
140 return MDNode::get(Ctx, TableOperands);
141 }
142
BuildDescriptorTableClause(const DescriptorTableClause & Clause)143 MDNode *MetadataBuilder::BuildDescriptorTableClause(
144 const DescriptorTableClause &Clause) {
145 IRBuilder<> Builder(Ctx);
146 std::optional<StringRef> ResName =
147 getResourceName(dxil::ResourceClass(llvm::to_underlying(Clause.Type)));
148 assert(ResName && "Provided an invalid Resource Class");
149 Metadata *Operands[] = {
150 MDString::get(Ctx, *ResName),
151 ConstantAsMetadata::get(Builder.getInt32(Clause.NumDescriptors)),
152 ConstantAsMetadata::get(Builder.getInt32(Clause.Reg.Number)),
153 ConstantAsMetadata::get(Builder.getInt32(Clause.Space)),
154 ConstantAsMetadata::get(Builder.getInt32(Clause.Offset)),
155 ConstantAsMetadata::get(
156 Builder.getInt32(llvm::to_underlying(Clause.Flags))),
157 };
158 return MDNode::get(Ctx, Operands);
159 }
160
BuildStaticSampler(const StaticSampler & Sampler)161 MDNode *MetadataBuilder::BuildStaticSampler(const StaticSampler &Sampler) {
162 IRBuilder<> Builder(Ctx);
163 Metadata *Operands[] = {
164 MDString::get(Ctx, "StaticSampler"),
165 ConstantAsMetadata::get(
166 Builder.getInt32(llvm::to_underlying(Sampler.Filter))),
167 ConstantAsMetadata::get(
168 Builder.getInt32(llvm::to_underlying(Sampler.AddressU))),
169 ConstantAsMetadata::get(
170 Builder.getInt32(llvm::to_underlying(Sampler.AddressV))),
171 ConstantAsMetadata::get(
172 Builder.getInt32(llvm::to_underlying(Sampler.AddressW))),
173 ConstantAsMetadata::get(llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx),
174 Sampler.MipLODBias)),
175 ConstantAsMetadata::get(Builder.getInt32(Sampler.MaxAnisotropy)),
176 ConstantAsMetadata::get(
177 Builder.getInt32(llvm::to_underlying(Sampler.CompFunc))),
178 ConstantAsMetadata::get(
179 Builder.getInt32(llvm::to_underlying(Sampler.BorderColor))),
180 ConstantAsMetadata::get(
181 llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx), Sampler.MinLOD)),
182 ConstantAsMetadata::get(
183 llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx), Sampler.MaxLOD)),
184 ConstantAsMetadata::get(Builder.getInt32(Sampler.Reg.Number)),
185 ConstantAsMetadata::get(Builder.getInt32(Sampler.Space)),
186 ConstantAsMetadata::get(
187 Builder.getInt32(llvm::to_underlying(Sampler.Visibility))),
188 };
189 return MDNode::get(Ctx, Operands);
190 }
191
192 } // namespace rootsig
193 } // namespace hlsl
194 } // namespace llvm
195