LLVM 22.0.0git
DXContainerEmitter.cpp
Go to the documentation of this file.
1//===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//
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
10/// Binary emitter for yaml to DXContainer binary
11///
12//===----------------------------------------------------------------------===//
13
19#include "llvm/Support/Errc.h"
20#include "llvm/Support/Error.h"
22
23using namespace llvm;
24
25namespace {
26class DXContainerWriter {
27public:
28 DXContainerWriter(DXContainerYAML::Object &ObjectFile)
30
32
33private:
35
36 Error computePartOffsets();
37 Error validatePartOffsets();
38 Error validateSize(uint32_t Computed);
39
40 void writeHeader(raw_ostream &OS);
41 Error writeParts(raw_ostream &OS);
42};
43} // namespace
44
45Error DXContainerWriter::validateSize(uint32_t Computed) {
46 if (!ObjectFile.Header.FileSize)
47 ObjectFile.Header.FileSize = Computed;
48 else if (*ObjectFile.Header.FileSize < Computed)
49 return createStringError(errc::result_out_of_range,
50 "File size specified is too small.");
51 return Error::success();
52}
53
54Error DXContainerWriter::validatePartOffsets() {
55 if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
56 return createStringError(
57 errc::invalid_argument,
58 "Mismatch between number of parts and part offsets.");
59 uint32_t RollingOffset =
60 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
61 for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
62 if (RollingOffset > std::get<1>(I))
63 return createStringError(errc::invalid_argument,
64 "Offset mismatch, not enough space for data.");
65 RollingOffset =
66 std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
67 }
68 if (Error Err = validateSize(RollingOffset))
69 return Err;
70
71 return Error::success();
72}
73
74Error DXContainerWriter::computePartOffsets() {
75 if (ObjectFile.Header.PartOffsets)
76 return validatePartOffsets();
77 uint32_t RollingOffset =
78 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
79 ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
80 for (const auto &Part : ObjectFile.Parts) {
81 ObjectFile.Header.PartOffsets->push_back(RollingOffset);
82 RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
83 }
84 if (Error Err = validateSize(RollingOffset))
85 return Err;
86
87 return Error::success();
88}
89
90void DXContainerWriter::writeHeader(raw_ostream &OS) {
91 dxbc::Header Header;
92 memcpy(Header.Magic, "DXBC", 4);
93 memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
94 Header.Version.Major = ObjectFile.Header.Version.Major;
95 Header.Version.Minor = ObjectFile.Header.Version.Minor;
96 Header.FileSize = *ObjectFile.Header.FileSize;
97 Header.PartCount = ObjectFile.Parts.size();
99 Header.swapBytes();
100 OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
101 SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
102 ObjectFile.Header.PartOffsets->end());
104 for (auto &O : Offsets)
106 OS.write(reinterpret_cast<char *>(Offsets.data()),
107 Offsets.size() * sizeof(uint32_t));
108}
109
110Error DXContainerWriter::writeParts(raw_ostream &OS) {
111 uint32_t RollingOffset =
112 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
113 for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
114 if (RollingOffset < std::get<1>(I)) {
115 uint32_t PadBytes = std::get<1>(I) - RollingOffset;
116 OS.write_zeros(PadBytes);
117 }
118 DXContainerYAML::Part P = std::get<0>(I);
119 RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
120 uint32_t PartSize = P.Size;
121
122 OS.write(P.Name.c_str(), 4);
124 sys::swapByteOrder(P.Size);
125 OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
126
128
129 uint64_t DataStart = OS.tell();
130 switch (PT) {
131 case dxbc::PartType::DXIL: {
132 if (!P.Program)
133 continue;
134 dxbc::ProgramHeader Header;
135 Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
136 P.Program->MinorVersion);
137 Header.Unused = 0;
138 Header.ShaderKind = P.Program->ShaderKind;
139 memcpy(Header.Bitcode.Magic, "DXIL", 4);
140 Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
141 Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
142 Header.Bitcode.Unused = 0;
143
144 // Compute the optional fields if needed...
145 if (P.Program->DXILOffset)
146 Header.Bitcode.Offset = *P.Program->DXILOffset;
147 else
148 Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
149
150 if (P.Program->DXILSize)
151 Header.Bitcode.Size = *P.Program->DXILSize;
152 else
153 Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
154
155 if (P.Program->Size)
156 Header.Size = *P.Program->Size;
157 else
158 Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
159
160 uint32_t BitcodeOffset = Header.Bitcode.Offset;
162 Header.swapBytes();
163 OS.write(reinterpret_cast<const char *>(&Header),
164 sizeof(dxbc::ProgramHeader));
165 if (P.Program->DXIL) {
166 if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
167 uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
168 OS.write_zeros(PadBytes);
169 }
170 OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
171 P.Program->DXIL->size());
172 }
173 break;
174 }
175 case dxbc::PartType::SFI0: {
176 // If we don't have any flags we can continue here and the data will be
177 // zeroed out.
178 if (!P.Flags.has_value())
179 continue;
180 uint64_t Flags = P.Flags->getEncodedFlags();
182 sys::swapByteOrder(Flags);
183 OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
184 break;
185 }
186 case dxbc::PartType::HASH: {
187 if (!P.Hash.has_value())
188 continue;
189 dxbc::ShaderHash Hash = {0, {0}};
190 if (P.Hash->IncludesSource)
191 Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
192 memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
194 Hash.swapBytes();
195 OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
196 break;
197 }
198 case dxbc::PartType::PSV0: {
199 if (!P.Info.has_value())
200 continue;
202 memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
203 PSV.Resources = P.Info->Resources;
204 PSV.EntryName = P.Info->EntryName;
205
206 for (auto El : P.Info->SigInputElements)
208 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
209 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
210 El.Stream});
211
212 for (auto El : P.Info->SigOutputElements)
214 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
215 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
216 El.Stream});
217
218 for (auto El : P.Info->SigPatchOrPrimElements)
220 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
221 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
222 El.Stream});
223
224 static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
225 for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
226 PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
227 P.Info->OutputVectorMasks[I].begin(),
228 P.Info->OutputVectorMasks[I].end());
229 PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
230 P.Info->InputOutputMap[I].begin(),
231 P.Info->InputOutputMap[I].end());
232 }
233
235 P.Info->PatchOrPrimMasks.begin(),
236 P.Info->PatchOrPrimMasks.end());
238 P.Info->InputPatchMap.begin(),
239 P.Info->InputPatchMap.end());
241 P.Info->PatchOutputMap.begin(),
242 P.Info->PatchOutputMap.end());
243
244 PSV.finalize(static_cast<Triple::EnvironmentType>(
245 Triple::Pixel + P.Info->Info.ShaderStage));
246 PSV.write(OS, P.Info->Version);
247 break;
248 }
249 case dxbc::PartType::ISG1:
250 case dxbc::PartType::OSG1:
251 case dxbc::PartType::PSG1: {
253 if (P.Signature.has_value()) {
254 for (const auto &Param : P.Signature->Parameters) {
255 Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
256 Param.CompType, Param.Register, Param.Mask,
257 Param.ExclusiveMask, Param.MinPrecision);
258 }
259 }
260 Sig.write(OS);
261 break;
262 }
263 case dxbc::PartType::Unknown:
264 break; // Skip any handling for unrecognized parts.
265 case dxbc::PartType::RTS0:
266 if (!P.RootSignature.has_value())
267 continue;
268
270 RS.Flags = P.RootSignature->getEncodedFlags();
271 RS.Version = P.RootSignature->Version;
272 RS.NumStaticSamplers = P.RootSignature->NumStaticSamplers;
273
275 P.RootSignature->Parameters.Locations) {
276
277 assert(dxbc::isValidParameterType(L.Header.Type) &&
278 "invalid DXContainer YAML");
279 assert(dxbc::isValidShaderVisibility(L.Header.Visibility) &&
280 "invalid DXContainer YAML");
282 dxbc::ShaderVisibility Visibility =
283 dxbc::ShaderVisibility(L.Header.Visibility);
284
285 switch (Type) {
286 case dxbc::RootParameterType::Constants32Bit: {
287 const DXContainerYAML::RootConstantsYaml &ConstantYaml =
288 P.RootSignature->Parameters.getOrInsertConstants(L);
290
291 Constants.Num32BitValues = ConstantYaml.Num32BitValues;
292 Constants.RegisterSpace = ConstantYaml.RegisterSpace;
293 Constants.ShaderRegister = ConstantYaml.ShaderRegister;
294 RS.ParametersContainer.addParameter(Type, Visibility, Constants);
295 break;
296 }
297 case dxbc::RootParameterType::CBV:
298 case dxbc::RootParameterType::SRV:
299 case dxbc::RootParameterType::UAV: {
300 const DXContainerYAML::RootDescriptorYaml &DescriptorYaml =
301 P.RootSignature->Parameters.getOrInsertDescriptor(L);
302
303 mcdxbc::RootDescriptor Descriptor;
304 Descriptor.RegisterSpace = DescriptorYaml.RegisterSpace;
305 Descriptor.ShaderRegister = DescriptorYaml.ShaderRegister;
306 if (RS.Version > 1)
307 Descriptor.Flags = DescriptorYaml.getEncodedFlags();
308 RS.ParametersContainer.addParameter(Type, Visibility, Descriptor);
309 break;
310 }
311 case dxbc::RootParameterType::DescriptorTable: {
312 const DXContainerYAML::DescriptorTableYaml &TableYaml =
313 P.RootSignature->Parameters.getOrInsertTable(L);
315 for (const auto &R : TableYaml.Ranges) {
316
318 Range.RangeType = R.RangeType;
319 Range.NumDescriptors = R.NumDescriptors;
320 Range.BaseShaderRegister = R.BaseShaderRegister;
321 Range.RegisterSpace = R.RegisterSpace;
322 Range.OffsetInDescriptorsFromTableStart =
323 R.OffsetInDescriptorsFromTableStart;
324
325 if (RS.Version > 1)
326 Range.Flags = R.getEncodedFlags();
327
328 Table.Ranges.push_back(Range);
329 }
330 RS.ParametersContainer.addParameter(Type, Visibility, Table);
331 break;
332 }
333 }
334 }
335
336 for (const auto &Param : P.RootSignature->samplers()) {
338 NewSampler.Filter = Param.Filter;
339 NewSampler.AddressU = Param.AddressU;
340 NewSampler.AddressV = Param.AddressV;
341 NewSampler.AddressW = Param.AddressW;
342 NewSampler.MipLODBias = Param.MipLODBias;
343 NewSampler.MaxAnisotropy = Param.MaxAnisotropy;
344 NewSampler.ComparisonFunc = Param.ComparisonFunc;
345 NewSampler.BorderColor = Param.BorderColor;
346 NewSampler.MinLOD = Param.MinLOD;
347 NewSampler.MaxLOD = Param.MaxLOD;
348 NewSampler.ShaderRegister = Param.ShaderRegister;
349 NewSampler.RegisterSpace = Param.RegisterSpace;
350 NewSampler.ShaderVisibility = Param.ShaderVisibility;
351
352 RS.StaticSamplers.push_back(NewSampler);
353 }
354
355 // Handling of offsets
357 if (P.RootSignature->RootParametersOffset &&
358 P.RootSignature->RootParametersOffset.value() !=
360 return createStringError(
361 errc::invalid_argument,
362 "Specified RootParametersOffset does not match required value: %d.",
364 }
365
367 if (P.RootSignature->StaticSamplersOffset &&
368 P.RootSignature->StaticSamplersOffset.value() !=
370 return createStringError(
371 errc::invalid_argument,
372 "Specified StaticSamplersOffset does not match computed value: %d.",
374 }
375
376 RS.write(OS);
377 break;
378 }
379 uint64_t BytesWritten = OS.tell() - DataStart;
380 RollingOffset += BytesWritten;
381 if (BytesWritten < PartSize)
382 OS.write_zeros(PartSize - BytesWritten);
383 RollingOffset += PartSize;
384 }
385
386 return Error::success();
387}
388
389Error DXContainerWriter::write(raw_ostream &OS) {
390 if (Error Err = computePartOffsets())
391 return Err;
392 writeHeader(OS);
393 return writeParts(OS);
394}
395
396namespace llvm {
397namespace yaml {
398
400 ErrorHandler EH) {
401 DXContainerWriter Writer(Doc);
402 if (Error Err = Writer.write(Out)) {
403 handleAllErrors(std::move(Err),
404 [&](const ErrorInfoBase &Err) { EH(Err.message()); });
405 return false;
406 }
407 return true;
408}
409
410} // namespace yaml
411} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define I(x, y, z)
Definition: MD5.cpp:58
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
if(PassOpts->AAPipeline)
raw_pwrite_stream & OS
Base class for error info classes.
Definition: Error.h:44
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
static ErrorSuccess success()
Create a success value.
Definition: Error.h:336
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:806
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
An efficient, type-erasing, non-owning reference to a callable.
void addParam(uint32_t Stream, StringRef Name, uint32_t Index, dxbc::D3DSystemValue SystemValue, dxbc::SigComponentType CompType, uint32_t Register, uint8_t Mask, uint8_t ExclusiveMask, dxbc::SigMinPrecision MinPrecision)
void write(raw_ostream &OS)
This class is the base class for all object file types.
Definition: ObjectFile.h:231
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:148
raw_ostream & write(unsigned char C)
Offsets
Offsets in bytes from the start of the input buffer.
Definition: SIInstrInfo.h:1695
bool isValidShaderVisibility(uint32_t V)
Definition: DXContainer.h:222
LLVM_ABI PartType parsePartType(StringRef S)
Definition: DXContainer.cpp:21
bool isValidParameterType(uint32_t V)
Definition: DXContainer.h:205
constexpr bool IsBigEndianHost
Definition: SwapByteOrder.h:26
void swapByteOrder(T &Value)
Definition: SwapByteOrder.h:61
LLVM_ABI bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition: STLExtras.h:860
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition: Error.h:990
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1305
LLVM_ABI Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition: DWP.cpp:622
SmallVector< DescriptorRangeYaml > Ranges
Use this type to describe the size and type of a DXIL container part.
Definition: DXContainer.h:99
static uint8_t getVersion(uint8_t Major, uint8_t Minor)
Definition: DXContainer.h:141
SmallVector< dxbc::RTS0::v2::DescriptorRange > Ranges
dxbc::PSV::v3::RuntimeInfo BaseData
SmallVector< uint32_t > PatchOrPrimMasks
SmallVector< uint32_t > PatchOutputMap
SmallVector< dxbc::PSV::v2::ResourceBindInfo > Resources
void finalize(Triple::EnvironmentType Stage)
SmallVector< PSVSignatureElement > InputElements
SmallVector< uint32_t > InputPatchMap
SmallVector< PSVSignatureElement > OutputElements
SmallVector< PSVSignatureElement > PatchOrPrimElements
void write(raw_ostream &OS, uint32_t Version=std::numeric_limits< uint32_t >::max()) const
std::array< SmallVector< uint32_t >, 4 > OutputVectorMasks
std::array< SmallVector< uint32_t >, 4 > InputOutputMap
void addParameter(dxbc::RootParameterType Type, dxbc::ShaderVisibility Visibility, RootConstants Constant)
LLVM_ABI uint32_t computeRootParametersOffset() const
LLVM_ABI void write(raw_ostream &OS) const
LLVM_ABI uint32_t computeStaticSamplersOffset() const
SmallVector< dxbc::RTS0::v1::StaticSampler > StaticSamplers
mcdxbc::RootParametersContainer ParametersContainer
Common declarations for yaml2obj.