LLVM 19.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
18#include "llvm/Support/Errc.h"
19#include "llvm/Support/Error.h"
21
22using namespace llvm;
23
24namespace {
25class DXContainerWriter {
26public:
27 DXContainerWriter(DXContainerYAML::Object &ObjectFile)
29
31
32private:
34
35 Error computePartOffsets();
36 Error validatePartOffsets();
37 Error validateSize(uint32_t Computed);
38
39 void writeHeader(raw_ostream &OS);
40 void writeParts(raw_ostream &OS);
41};
42} // namespace
43
44Error DXContainerWriter::validateSize(uint32_t Computed) {
45 if (!ObjectFile.Header.FileSize)
46 ObjectFile.Header.FileSize = Computed;
47 else if (*ObjectFile.Header.FileSize < Computed)
48 return createStringError(errc::result_out_of_range,
49 "File size specified is too small.");
50 return Error::success();
51}
52
53Error DXContainerWriter::validatePartOffsets() {
54 if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
55 return createStringError(
56 errc::invalid_argument,
57 "Mismatch between number of parts and part offsets.");
58 uint32_t RollingOffset =
59 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
60 for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
61 if (RollingOffset > std::get<1>(I))
62 return createStringError(errc::invalid_argument,
63 "Offset mismatch, not enough space for data.");
64 RollingOffset =
65 std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
66 }
67 if (Error Err = validateSize(RollingOffset))
68 return Err;
69
70 return Error::success();
71}
72
73Error DXContainerWriter::computePartOffsets() {
74 if (ObjectFile.Header.PartOffsets)
75 return validatePartOffsets();
76 uint32_t RollingOffset =
77 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
78 ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
79 for (const auto &Part : ObjectFile.Parts) {
80 ObjectFile.Header.PartOffsets->push_back(RollingOffset);
81 RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
82 }
83 if (Error Err = validateSize(RollingOffset))
84 return Err;
85
86 return Error::success();
87}
88
89void DXContainerWriter::writeHeader(raw_ostream &OS) {
90 dxbc::Header Header;
91 memcpy(Header.Magic, "DXBC", 4);
92 memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
93 Header.Version.Major = ObjectFile.Header.Version.Major;
94 Header.Version.Minor = ObjectFile.Header.Version.Minor;
95 Header.FileSize = *ObjectFile.Header.FileSize;
96 Header.PartCount = ObjectFile.Parts.size();
98 Header.swapBytes();
99 OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
100 SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
101 ObjectFile.Header.PartOffsets->end());
103 for (auto &O : Offsets)
105 OS.write(reinterpret_cast<char *>(Offsets.data()),
106 Offsets.size() * sizeof(uint32_t));
107}
108
109void DXContainerWriter::writeParts(raw_ostream &OS) {
110 uint32_t RollingOffset =
111 sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
112 for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
113 if (RollingOffset < std::get<1>(I)) {
114 uint32_t PadBytes = std::get<1>(I) - RollingOffset;
115 OS.write_zeros(PadBytes);
116 }
117 DXContainerYAML::Part P = std::get<0>(I);
118 RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
119 uint32_t PartSize = P.Size;
120
121 OS.write(P.Name.c_str(), 4);
123 sys::swapByteOrder(P.Size);
124 OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
125
127
128 uint64_t DataStart = OS.tell();
129 switch (PT) {
130 case dxbc::PartType::DXIL: {
131 if (!P.Program)
132 continue;
133 dxbc::ProgramHeader Header;
134 Header.MajorVersion = P.Program->MajorVersion;
135 Header.MinorVersion = P.Program->MinorVersion;
136 Header.Unused = 0;
137 Header.ShaderKind = P.Program->ShaderKind;
138 memcpy(Header.Bitcode.Magic, "DXIL", 4);
139 Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
140 Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
141 Header.Bitcode.Unused = 0;
142
143 // Compute the optional fields if needed...
144 if (P.Program->DXILOffset)
145 Header.Bitcode.Offset = *P.Program->DXILOffset;
146 else
147 Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
148
149 if (P.Program->DXILSize)
150 Header.Bitcode.Size = *P.Program->DXILSize;
151 else
152 Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
153
154 if (P.Program->Size)
155 Header.Size = *P.Program->Size;
156 else
157 Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
158
159 uint32_t BitcodeOffset = Header.Bitcode.Offset;
161 Header.swapBytes();
162 OS.write(reinterpret_cast<const char *>(&Header),
163 sizeof(dxbc::ProgramHeader));
164 if (P.Program->DXIL) {
165 if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
166 uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
167 OS.write_zeros(PadBytes);
168 }
169 OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
170 P.Program->DXIL->size());
171 }
172 break;
173 }
174 case dxbc::PartType::SFI0: {
175 // If we don't have any flags we can continue here and the data will be
176 // zeroed out.
177 if (!P.Flags.has_value())
178 continue;
179 uint64_t Flags = P.Flags->getEncodedFlags();
181 sys::swapByteOrder(Flags);
182 OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
183 break;
184 }
185 case dxbc::PartType::HASH: {
186 if (!P.Hash.has_value())
187 continue;
188 dxbc::ShaderHash Hash = {0, {0}};
189 if (P.Hash->IncludesSource)
190 Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
191 memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
193 Hash.swapBytes();
194 OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
195 break;
196 }
197 case dxbc::PartType::PSV0: {
198 if (!P.Info.has_value())
199 continue;
201 memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v2::RuntimeInfo));
202 PSV.Resources = P.Info->Resources;
203
204 for (auto El : P.Info->SigInputElements)
206 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
207 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
208 El.Stream});
209
210 for (auto El : P.Info->SigOutputElements)
212 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
213 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
214 El.Stream});
215
216 for (auto El : P.Info->SigPatchOrPrimElements)
218 El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
219 El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
220 El.Stream});
221
222 static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
223 for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
224 PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
225 P.Info->OutputVectorMasks[I].begin(),
226 P.Info->OutputVectorMasks[I].end());
227 PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
228 P.Info->InputOutputMap[I].begin(),
229 P.Info->InputOutputMap[I].end());
230 }
231
233 P.Info->PatchOrPrimMasks.begin(),
234 P.Info->PatchOrPrimMasks.end());
236 P.Info->InputPatchMap.begin(),
237 P.Info->InputPatchMap.end());
239 P.Info->PatchOutputMap.begin(),
240 P.Info->PatchOutputMap.end());
241
242 PSV.finalize(static_cast<Triple::EnvironmentType>(
243 Triple::Pixel + P.Info->Info.ShaderStage));
244 PSV.write(OS, P.Info->Version);
245 break;
246 }
247 case dxbc::PartType::ISG1:
248 case dxbc::PartType::OSG1:
249 case dxbc::PartType::PSG1: {
251 if (P.Signature.has_value()) {
252 for (const auto &Param : P.Signature->Parameters) {
253 Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
254 Param.CompType, Param.Register, Param.Mask,
255 Param.ExclusiveMask, Param.MinPrecision);
256 }
257 }
258 Sig.write(OS);
259 break;
260 }
261 case dxbc::PartType::Unknown:
262 break; // Skip any handling for unrecognized parts.
263 }
264 uint64_t BytesWritten = OS.tell() - DataStart;
265 RollingOffset += BytesWritten;
266 if (BytesWritten < PartSize)
267 OS.write_zeros(PartSize - BytesWritten);
268 RollingOffset += PartSize;
269 }
270}
271
272Error DXContainerWriter::write(raw_ostream &OS) {
273 if (Error Err = computePartOffsets())
274 return Err;
275 writeHeader(OS);
276 writeParts(OS);
277 return Error::success();
278}
279
280namespace llvm {
281namespace yaml {
282
284 ErrorHandler EH) {
285 DXContainerWriter Writer(Doc);
286 if (Error Err = Writer.write(Out)) {
287 handleAllErrors(std::move(Err),
288 [&](const ErrorInfoBase &Err) { EH(Err.message()); });
289 return false;
290 }
291 return true;
292}
293
294} // namespace yaml
295} // namespace llvm
#define I(x, y, z)
Definition: MD5.cpp:58
#define P(N)
if(VerifyEach)
raw_pwrite_stream & OS
Base class for error info classes.
Definition: Error.h:45
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
iterator insert(iterator I, T &&Elt)
Definition: SmallVector.h:818
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
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:229
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
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:150
raw_ostream & write(unsigned char C)
Offsets
Offsets in bytes from the start of the input buffer.
Definition: SIInstrInfo.h:1525
PartType parsePartType(StringRef S)
Definition: DXContainer.cpp:21
constexpr bool IsBigEndianHost
Definition: SwapByteOrder.h:26
void swapByteOrder(T &Value)
Definition: SwapByteOrder.h:61
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:862
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:970
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)
Definition: DWP.cpp:601
Use this type to describe the size and type of a DXIL container part.
Definition: DXContainer.h:93
SmallVector< uint32_t > PatchOrPrimMasks
SmallVector< uint32_t > PatchOutputMap
SmallVector< dxbc::PSV::v2::ResourceBindInfo > Resources
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
dxbc::PSV::v2::RuntimeInfo BaseData
void finalize(Triple::EnvironmentType Stage)
std::array< SmallVector< uint32_t >, 4 > OutputVectorMasks
std::array< SmallVector< uint32_t >, 4 > InputOutputMap
Common declarations for yaml2obj.