Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
35234 views
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
14
#include "llvm/BinaryFormat/DXContainer.h"
15
#include "llvm/MC/DXContainerPSVInfo.h"
16
#include "llvm/ObjectYAML/ObjectYAML.h"
17
#include "llvm/ObjectYAML/yaml2obj.h"
18
#include "llvm/Support/Errc.h"
19
#include "llvm/Support/Error.h"
20
#include "llvm/Support/raw_ostream.h"
21
22
using namespace llvm;
23
24
namespace {
25
class DXContainerWriter {
26
public:
27
DXContainerWriter(DXContainerYAML::Object &ObjectFile)
28
: ObjectFile(ObjectFile) {}
29
30
Error write(raw_ostream &OS);
31
32
private:
33
DXContainerYAML::Object &ObjectFile;
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
44
Error 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
53
Error 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
73
Error 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
89
void 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();
97
if (sys::IsBigEndianHost)
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());
102
if (sys::IsBigEndianHost)
103
for (auto &O : Offsets)
104
sys::swapByteOrder(O);
105
OS.write(reinterpret_cast<char *>(Offsets.data()),
106
Offsets.size() * sizeof(uint32_t));
107
}
108
109
void 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);
122
if (sys::IsBigEndianHost)
123
sys::swapByteOrder(P.Size);
124
OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
125
126
dxbc::PartType PT = dxbc::parsePartType(P.Name);
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.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
135
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;
160
if (sys::IsBigEndianHost)
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();
180
if (sys::IsBigEndianHost)
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);
192
if (sys::IsBigEndianHost)
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;
200
mcdxbc::PSVRuntimeInfo PSV;
201
memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
202
PSV.Resources = P.Info->Resources;
203
PSV.EntryName = P.Info->EntryName;
204
205
for (auto El : P.Info->SigInputElements)
206
PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{
207
El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
208
El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
209
El.Stream});
210
211
for (auto El : P.Info->SigOutputElements)
212
PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{
213
El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
214
El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
215
El.Stream});
216
217
for (auto El : P.Info->SigPatchOrPrimElements)
218
PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{
219
El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
220
El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
221
El.Stream});
222
223
static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
224
for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
225
PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
226
P.Info->OutputVectorMasks[I].begin(),
227
P.Info->OutputVectorMasks[I].end());
228
PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
229
P.Info->InputOutputMap[I].begin(),
230
P.Info->InputOutputMap[I].end());
231
}
232
233
PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),
234
P.Info->PatchOrPrimMasks.begin(),
235
P.Info->PatchOrPrimMasks.end());
236
PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),
237
P.Info->InputPatchMap.begin(),
238
P.Info->InputPatchMap.end());
239
PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),
240
P.Info->PatchOutputMap.begin(),
241
P.Info->PatchOutputMap.end());
242
243
PSV.finalize(static_cast<Triple::EnvironmentType>(
244
Triple::Pixel + P.Info->Info.ShaderStage));
245
PSV.write(OS, P.Info->Version);
246
break;
247
}
248
case dxbc::PartType::ISG1:
249
case dxbc::PartType::OSG1:
250
case dxbc::PartType::PSG1: {
251
mcdxbc::Signature Sig;
252
if (P.Signature.has_value()) {
253
for (const auto &Param : P.Signature->Parameters) {
254
Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
255
Param.CompType, Param.Register, Param.Mask,
256
Param.ExclusiveMask, Param.MinPrecision);
257
}
258
}
259
Sig.write(OS);
260
break;
261
}
262
case dxbc::PartType::Unknown:
263
break; // Skip any handling for unrecognized parts.
264
}
265
uint64_t BytesWritten = OS.tell() - DataStart;
266
RollingOffset += BytesWritten;
267
if (BytesWritten < PartSize)
268
OS.write_zeros(PartSize - BytesWritten);
269
RollingOffset += PartSize;
270
}
271
}
272
273
Error DXContainerWriter::write(raw_ostream &OS) {
274
if (Error Err = computePartOffsets())
275
return Err;
276
writeHeader(OS);
277
writeParts(OS);
278
return Error::success();
279
}
280
281
namespace llvm {
282
namespace yaml {
283
284
bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
285
ErrorHandler EH) {
286
DXContainerWriter Writer(Doc);
287
if (Error Err = Writer.write(Out)) {
288
handleAllErrors(std::move(Err),
289
[&](const ErrorInfoBase &Err) { EH(Err.message()); });
290
return false;
291
}
292
return true;
293
}
294
295
} // namespace yaml
296
} // namespace llvm
297
298