LLVM 23.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
20#include "llvm/Support/Errc.h"
21#include "llvm/Support/Error.h"
23
24using namespace llvm;
25
26namespace {
27class DXContainerWriter {
28public:
29 DXContainerWriter(DXContainerYAML::Object &ObjectFile)
30 : ObjectFile(ObjectFile) {}
31
32 Error write(raw_ostream &OS);
33
34private:
35 DXContainerYAML::Object &ObjectFile;
36
37 Error computePartOffsets();
38 Error validatePartOffsets();
39 Error validateSize(uint32_t Computed);
40
41 void writeHeader(raw_ostream &OS);
42 Error writeParts(raw_ostream &OS);
43};
44} // namespace
45
46Error DXContainerWriter::validateSize(uint32_t Computed) {
47 if (!ObjectFile.Header.FileSize)
48 ObjectFile.Header.FileSize = Computed;
49 else if (*ObjectFile.Header.FileSize < Computed)
50 return createStringError(errc::result_out_of_range,
51 "File size specified is too small.");
52 return Error::success();
53}
54
55Error DXContainerWriter::validatePartOffsets() {
56 if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
57 return createStringError(
58 errc::invalid_argument,
59 "Mismatch between number of parts and part offsets.");
60 uint32_t RollingOffset =
61 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
62 for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
63 if (RollingOffset > std::get<1>(I))
64 return createStringError(errc::invalid_argument,
65 "Offset mismatch, not enough space for data.");
66 RollingOffset =
67 std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
68 }
69 if (Error Err = validateSize(RollingOffset))
70 return Err;
71
72 return Error::success();
73}
74
75Error DXContainerWriter::computePartOffsets() {
76 if (ObjectFile.Header.PartOffsets)
77 return validatePartOffsets();
78 uint32_t RollingOffset =
79 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
80 ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
81 for (const auto &Part : ObjectFile.Parts) {
82 ObjectFile.Header.PartOffsets->push_back(RollingOffset);
83 RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
84 }
85 if (Error Err = validateSize(RollingOffset))
86 return Err;
87
88 return Error::success();
89}
90
91void DXContainerWriter::writeHeader(raw_ostream &OS) {
92 dxbc::Header Header;
93 memcpy(Header.Magic, "DXBC", 4);
94 memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
95 Header.Version.Major = ObjectFile.Header.Version.Major;
96 Header.Version.Minor = ObjectFile.Header.Version.Minor;
97 Header.FileSize = *ObjectFile.Header.FileSize;
98 Header.PartCount = ObjectFile.Parts.size();
100 Header.swapBytes();
101 OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
102 SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
103 ObjectFile.Header.PartOffsets->end());
105 for (auto &O : Offsets)
107 OS.write(reinterpret_cast<char *>(Offsets.data()),
108 Offsets.size() * sizeof(uint32_t));
109}
110
111Error DXContainerWriter::writeParts(raw_ostream &OS) {
112 uint32_t RollingOffset =
113 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
114 for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
115 if (RollingOffset < std::get<1>(I)) {
116 uint32_t PadBytes = std::get<1>(I) - RollingOffset;
117 OS.write_zeros(PadBytes);
118 }
119 DXContainerYAML::Part P = std::get<0>(I);
120 RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
121 uint32_t PartSize = P.Size;
122
123 OS.write(P.Name.c_str(), 4);
125 sys::swapByteOrder(P.Size);
126 OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
127
129
130 uint64_t DataStart = OS.tell();
131 switch (PT) {
132 case dxbc::PartType::DXIL:
133 case dxbc::PartType::ILDB: {
134 if (!P.Program)
135 continue;
136 dxbc::ProgramHeader Header;
137 Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
138 P.Program->MinorVersion);
139 Header.Unused = 0;
140 Header.ShaderKind = P.Program->ShaderKind;
141 memcpy(Header.Bitcode.Magic, "DXIL", 4);
142 Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
143 Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
144 Header.Bitcode.Unused = 0;
145
146 // Compute the optional fields if needed...
147 if (P.Program->DXILOffset)
148 Header.Bitcode.Offset = *P.Program->DXILOffset;
149 else
150 Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
151
152 if (P.Program->DXILSize)
153 Header.Bitcode.Size = *P.Program->DXILSize;
154 else
155 Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
156
157 if (P.Program->Size)
158 Header.Size = *P.Program->Size;
159 else
160 Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
161
162 uint32_t BitcodeOffset = Header.Bitcode.Offset;
164 Header.swapBytes();
165 OS.write(reinterpret_cast<const char *>(&Header),
166 sizeof(dxbc::ProgramHeader));
167 if (P.Program->DXIL) {
168 if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
169 uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
170 OS.write_zeros(PadBytes);
171 }
172 OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
173 P.Program->DXIL->size());
174 }
175 break;
176 }
177 case dxbc::PartType::ILDN: {
178 if (!P.DebugName)
179 continue;
180
181 mcdxbc::DebugName DebugName;
182 DebugName.setFilename(P.DebugName->Filename);
183 // Override default flags with value from YAML.
184 if (P.DebugName->Flags)
185 DebugName.Parameters.Flags = *P.DebugName->Flags;
186 // Override computed filename length with value from YAML.
187 if (P.DebugName->NameLength)
188 DebugName.Parameters.NameLength = *P.DebugName->NameLength;
189 DebugName.write(OS);
190 break;
191 }
192 case dxbc::PartType::SFI0: {
193 // If we don't have any flags we can continue here and the data will be
194 // zeroed out.
195 if (!P.Flags.has_value())
196 continue;
197 uint64_t Flags = P.Flags->getEncodedFlags();
199 sys::swapByteOrder(Flags);
200 OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
201 break;
202 }
203 case dxbc::PartType::HASH: {
204 if (!P.Hash.has_value())
205 continue;
206 dxbc::ShaderHash Hash = {0, {0}};
207 if (P.Hash->IncludesSource)
208 Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
209 memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
211 Hash.swapBytes();
212 OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
213 break;
214 }
215 case dxbc::PartType::PSV0: {
216 if (!P.Info.has_value())
217 continue;
218 mcdxbc::PSVRuntimeInfo PSV;
219 memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
220 PSV.Resources = P.Info->Resources;
221 PSV.EntryName = P.Info->EntryName;
222
223 for (auto El : P.Info->SigInputElements)
224 PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{
225 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
226 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
227 El.Stream});
228
229 for (auto El : P.Info->SigOutputElements)
230 PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{
231 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
232 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
233 El.Stream});
234
235 for (auto El : P.Info->SigPatchOrPrimElements)
236 PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{
237 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
238 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
239 El.Stream});
240
241 static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
242 for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
243 PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
244 P.Info->OutputVectorMasks[I].begin(),
245 P.Info->OutputVectorMasks[I].end());
246 PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
247 P.Info->InputOutputMap[I].begin(),
248 P.Info->InputOutputMap[I].end());
249 }
250
252 P.Info->PatchOrPrimMasks.begin(),
253 P.Info->PatchOrPrimMasks.end());
255 P.Info->InputPatchMap.begin(),
256 P.Info->InputPatchMap.end());
258 P.Info->PatchOutputMap.begin(),
259 P.Info->PatchOutputMap.end());
260
261 PSV.finalize(static_cast<Triple::EnvironmentType>(
262 Triple::Pixel + P.Info->Info.ShaderStage),
263 P.Info->Version);
264 PSV.write(OS, P.Info->Version);
265 break;
266 }
267 case dxbc::PartType::ISG1:
268 case dxbc::PartType::OSG1:
269 case dxbc::PartType::PSG1: {
270 mcdxbc::Signature Sig;
271 if (P.Signature.has_value()) {
272 for (const auto &Param : P.Signature->Parameters) {
273 Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
274 Param.CompType, Param.Register, Param.Mask,
275 Param.ExclusiveMask, Param.MinPrecision);
276 }
277 }
278 Sig.write(OS);
279 break;
280 }
281 case dxbc::PartType::Unknown:
282 break; // Skip any handling for unrecognized parts.
283 case dxbc::PartType::RTS0:
284 if (!P.RootSignature.has_value())
285 continue;
286
287 mcdxbc::RootSignatureDesc RS;
288 RS.Flags = P.RootSignature->getEncodedFlags();
289 RS.Version = P.RootSignature->Version;
290 RS.NumStaticSamplers = P.RootSignature->NumStaticSamplers;
291
292 for (DXContainerYAML::RootParameterLocationYaml &L :
293 P.RootSignature->Parameters.Locations) {
294
295 const dxbc::RootParameterType Type = L.Header.Type;
296 const dxbc::ShaderVisibility Visibility = L.Header.Visibility;
297
298 switch (Type) {
299 case dxbc::RootParameterType::Constants32Bit: {
300 const DXContainerYAML::RootConstantsYaml &ConstantYaml =
301 P.RootSignature->Parameters.getOrInsertConstants(L);
302 mcdxbc::RootConstants Constants;
303
304 Constants.Num32BitValues = ConstantYaml.Num32BitValues;
305 Constants.RegisterSpace = ConstantYaml.RegisterSpace;
306 Constants.ShaderRegister = ConstantYaml.ShaderRegister;
307 RS.ParametersContainer.addParameter(Type, Visibility, Constants);
308 break;
309 }
310 case dxbc::RootParameterType::CBV:
311 case dxbc::RootParameterType::SRV:
312 case dxbc::RootParameterType::UAV: {
313 const DXContainerYAML::RootDescriptorYaml &DescriptorYaml =
314 P.RootSignature->Parameters.getOrInsertDescriptor(L);
315
316 mcdxbc::RootDescriptor Descriptor;
317 Descriptor.RegisterSpace = DescriptorYaml.RegisterSpace;
318 Descriptor.ShaderRegister = DescriptorYaml.ShaderRegister;
319 if (RS.Version > 1)
320 Descriptor.Flags = DescriptorYaml.getEncodedFlags();
321 RS.ParametersContainer.addParameter(Type, Visibility, Descriptor);
322 break;
323 }
324 case dxbc::RootParameterType::DescriptorTable: {
325 const DXContainerYAML::DescriptorTableYaml &TableYaml =
326 P.RootSignature->Parameters.getOrInsertTable(L);
327 mcdxbc::DescriptorTable Table;
328 for (const auto &R : TableYaml.Ranges) {
329 mcdxbc::DescriptorRange Range;
330 Range.RangeType = R.RangeType;
331 Range.NumDescriptors = R.NumDescriptors;
332 Range.BaseShaderRegister = R.BaseShaderRegister;
333 Range.RegisterSpace = R.RegisterSpace;
334 Range.OffsetInDescriptorsFromTableStart =
335 R.OffsetInDescriptorsFromTableStart;
336
337 if (RS.Version > 1)
338 Range.Flags = R.getEncodedFlags();
339
340 Table.Ranges.push_back(Range);
341 }
342 RS.ParametersContainer.addParameter(Type, Visibility, Table);
343 break;
344 }
345 }
346 }
347
348 for (const auto &Param : P.RootSignature->samplers()) {
349 mcdxbc::StaticSampler NewSampler;
350 NewSampler.Filter = Param.Filter;
351 NewSampler.AddressU = Param.AddressU;
352 NewSampler.AddressV = Param.AddressV;
353 NewSampler.AddressW = Param.AddressW;
354 NewSampler.MipLODBias = Param.MipLODBias;
355 NewSampler.MaxAnisotropy = Param.MaxAnisotropy;
356 NewSampler.ComparisonFunc = Param.ComparisonFunc;
357 NewSampler.BorderColor = Param.BorderColor;
358 NewSampler.MinLOD = Param.MinLOD;
359 NewSampler.MaxLOD = Param.MaxLOD;
360 NewSampler.ShaderRegister = Param.ShaderRegister;
361 NewSampler.RegisterSpace = Param.RegisterSpace;
362 NewSampler.ShaderVisibility = Param.ShaderVisibility;
363
364 if (RS.Version > 2)
365 NewSampler.Flags = Param.getEncodedFlags();
366
367 RS.StaticSamplers.push_back(NewSampler);
368 }
369
370 // Handling of offsets
371 RS.RootParameterOffset = RS.computeRootParametersOffset();
372 if (P.RootSignature->RootParametersOffset &&
373 P.RootSignature->RootParametersOffset.value() !=
374 RS.RootParameterOffset) {
375 return createStringError(
376 errc::invalid_argument,
377 "Specified RootParametersOffset does not match required value: %d.",
378 RS.RootParameterOffset);
379 }
380
381 RS.StaticSamplersOffset = RS.computeStaticSamplersOffset();
382 if (P.RootSignature->StaticSamplersOffset &&
383 P.RootSignature->StaticSamplersOffset.value() !=
384 RS.StaticSamplersOffset) {
385 return createStringError(
386 errc::invalid_argument,
387 "Specified StaticSamplersOffset does not match computed value: %d.",
388 RS.StaticSamplersOffset);
389 }
390
391 RS.write(OS);
392 break;
393 }
394 uint64_t BytesWritten = OS.tell() - DataStart;
395 RollingOffset += BytesWritten;
396 if (BytesWritten < PartSize)
397 OS.write_zeros(PartSize - BytesWritten);
398 RollingOffset += PartSize;
399 }
400
401 return Error::success();
402}
403
404Error DXContainerWriter::write(raw_ostream &OS) {
405 if (Error Err = computePartOffsets())
406 return Err;
407 writeHeader(OS);
408 return writeParts(OS);
409}
410
411namespace llvm {
412namespace yaml {
413
415 ErrorHandler EH) {
416 DXContainerWriter Writer(Doc);
417 if (Error Err = Writer.write(Out)) {
418 handleAllErrors(std::move(Err),
419 [&](const ErrorInfoBase &Err) { EH(Err.message()); });
420 return false;
421 }
422 return true;
423}
424
425} // namespace yaml
426} // namespace llvm
#define I(x, y, z)
Definition MD5.cpp:57
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
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)
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 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.
raw_ostream & write(unsigned char C)
void writeHeader(support::endian::Writer &W, bool Is64Bit, uint8_t OSABI, uint8_t ABIVersion, uint16_t EMachine, uint32_t EFlags, uint64_t SHOff, uint16_t SHNum, uint16_t SHStrNdx)
Write an ELF file header (Elf32_Ehdr or Elf64_Ehdr) for an ET_REL object.
Definition ELFWriter.cpp:21
Offsets
Offsets in bytes from the start of the input buffer.
LLVM_ABI PartType parsePartType(StringRef S)
constexpr bool IsBigEndianHost
void swapByteOrder(T &Value)
LLVM_ABI bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
llvm::function_ref< void(const Twine &Msg)> ErrorHandler
Definition yaml2obj.h:68
This is an optimization pass for GlobalISel generic memory operations.
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:830
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:1013
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
FunctionAddr VTableAddr DataStart
Definition InstrProf.h:167
LLVM_ABI Error write(DWPWriter &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue, Dwarf64StrOffsetsPromotion StrOffsetsOptValue, raw_pwrite_stream *OS=nullptr)
Definition DWP.cpp:720
SmallVector< DescriptorRangeYaml > Ranges
uint16_t NameLength
Debug file name length, without null terminator.
static uint8_t getVersion(uint8_t Major, uint8_t Minor)
dxbc::DebugNameHeader Parameters
void setFilename(StringRef DebugFilename)
void write(raw_ostream &OS) const
SmallVector< DescriptorRange > Ranges
dxbc::PSV::v3::RuntimeInfo BaseData
SmallVector< uint32_t > PatchOrPrimMasks
SmallVector< uint32_t > PatchOutputMap
SmallVector< dxbc::PSV::v2::ResourceBindInfo > Resources
SmallVector< PSVSignatureElement > InputElements
void finalize(Triple::EnvironmentType Stage, uint32_t Version=std::numeric_limits< uint32_t >::max())
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
dxbc::TextureAddressMode AddressU
dxbc::TextureAddressMode AddressV
dxbc::StaticBorderColor BorderColor
dxbc::TextureAddressMode AddressW
dxbc::ShaderVisibility ShaderVisibility
Common declarations for yaml2obj.