1//===- DXContainerYAML.cpp - DXContainer YAMLIO implementation ------------===//
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// This file defines classes for handling the YAML representation of
10// DXContainerYAML.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ObjectYAML/DXContainerYAML.h"
15#include "llvm/ADT/ScopeExit.h"
16#include "llvm/BinaryFormat/DXContainer.h"
17#include "llvm/Support/ScopedPrinter.h"
18
19namespace llvm {
20
21// This assert is duplicated here to leave a breadcrumb of the places that need
22// to be updated if flags grow past 64-bits.
23static_assert((uint64_t)dxbc::FeatureFlags::NextUnusedBit <= 1ull << 63,
24 "Shader flag bits exceed enum size.");
25
26DXContainerYAML::ShaderFeatureFlags::ShaderFeatureFlags(uint64_t FlagData) {
27#define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \
28 Val = (FlagData & (uint64_t)dxbc::FeatureFlags::Val) > 0;
29#include "llvm/BinaryFormat/DXContainerConstants.def"
30}
31
32uint64_t DXContainerYAML::ShaderFeatureFlags::getEncodedFlags() {
33 uint64_t Flag = 0;
34#define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \
35 if (Val) \
36 Flag |= (uint64_t)dxbc::FeatureFlags::Val;
37#include "llvm/BinaryFormat/DXContainerConstants.def"
38 return Flag;
39}
40
41DXContainerYAML::ShaderHash::ShaderHash(const dxbc::ShaderHash &Data)
42 : IncludesSource((Data.Flags & static_cast<uint32_t>(
43 dxbc::HashFlags::IncludesSource)) != 0),
44 Digest(16, 0) {
45 memcpy(dest: Digest.data(), src: &Data.Digest[0], n: 16);
46}
47
48DXContainerYAML::PSVInfo::PSVInfo() : Version(0) {
49 memset(s: &Info, c: 0, n: sizeof(Info));
50}
51
52DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v0::RuntimeInfo *P,
53 uint16_t Stage)
54 : Version(0) {
55 memset(s: &Info, c: 0, n: sizeof(Info));
56 memcpy(dest: &Info, src: P, n: sizeof(dxbc::PSV::v0::RuntimeInfo));
57
58 assert(Stage < std::numeric_limits<uint8_t>::max() &&
59 "Stage should be a very small number");
60 // We need to bring the stage in separately since it isn't part of the v1 data
61 // structure.
62 Info.ShaderStage = static_cast<uint8_t>(Stage);
63}
64
65DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v1::RuntimeInfo *P)
66 : Version(1) {
67 memset(s: &Info, c: 0, n: sizeof(Info));
68 memcpy(dest: &Info, src: P, n: sizeof(dxbc::PSV::v1::RuntimeInfo));
69}
70
71DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v2::RuntimeInfo *P)
72 : Version(2) {
73 memset(s: &Info, c: 0, n: sizeof(Info));
74 memcpy(dest: &Info, src: P, n: sizeof(dxbc::PSV::v2::RuntimeInfo));
75}
76
77DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v3::RuntimeInfo *P,
78 StringRef StringTable)
79 : Version(3),
80 EntryName(StringTable.substr(Start: P->EntryNameOffset,
81 N: StringTable.find(C: '\0', From: P->EntryNameOffset) -
82 P->EntryNameOffset)) {
83 memset(s: &Info, c: 0, n: sizeof(Info));
84 memcpy(dest: &Info, src: P, n: sizeof(dxbc::PSV::v3::RuntimeInfo));
85}
86
87namespace yaml {
88
89void MappingTraits<DXContainerYAML::VersionTuple>::mapping(
90 IO &IO, DXContainerYAML::VersionTuple &Version) {
91 IO.mapRequired(Key: "Major", Val&: Version.Major);
92 IO.mapRequired(Key: "Minor", Val&: Version.Minor);
93}
94
95void MappingTraits<DXContainerYAML::FileHeader>::mapping(
96 IO &IO, DXContainerYAML::FileHeader &Header) {
97 IO.mapRequired(Key: "Hash", Val&: Header.Hash);
98 IO.mapRequired(Key: "Version", Val&: Header.Version);
99 IO.mapOptional(Key: "FileSize", Val&: Header.FileSize);
100 IO.mapRequired(Key: "PartCount", Val&: Header.PartCount);
101 IO.mapOptional(Key: "PartOffsets", Val&: Header.PartOffsets);
102}
103
104void MappingTraits<DXContainerYAML::DXILProgram>::mapping(
105 IO &IO, DXContainerYAML::DXILProgram &Program) {
106 IO.mapRequired(Key: "MajorVersion", Val&: Program.MajorVersion);
107 IO.mapRequired(Key: "MinorVersion", Val&: Program.MinorVersion);
108 IO.mapRequired(Key: "ShaderKind", Val&: Program.ShaderKind);
109 IO.mapOptional(Key: "Size", Val&: Program.Size);
110 IO.mapRequired(Key: "DXILMajorVersion", Val&: Program.DXILMajorVersion);
111 IO.mapRequired(Key: "DXILMinorVersion", Val&: Program.DXILMinorVersion);
112 IO.mapOptional(Key: "DXILSize", Val&: Program.DXILSize);
113 IO.mapOptional(Key: "DXIL", Val&: Program.DXIL);
114}
115
116void MappingTraits<DXContainerYAML::ShaderFeatureFlags>::mapping(
117 IO &IO, DXContainerYAML::ShaderFeatureFlags &Flags) {
118#define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) \
119 IO.mapRequired(#Val, Flags.Val);
120#include "llvm/BinaryFormat/DXContainerConstants.def"
121}
122
123void MappingTraits<DXContainerYAML::ShaderHash>::mapping(
124 IO &IO, DXContainerYAML::ShaderHash &Hash) {
125 IO.mapRequired(Key: "IncludesSource", Val&: Hash.IncludesSource);
126 IO.mapRequired(Key: "Digest", Val&: Hash.Digest);
127}
128
129void MappingTraits<DXContainerYAML::PSVInfo>::mapping(
130 IO &IO, DXContainerYAML::PSVInfo &PSV) {
131 IO.mapRequired(Key: "Version", Val&: PSV.Version);
132
133 // Store the PSV version in the YAML context.
134 void *OldContext = IO.getContext();
135 uint32_t Version = PSV.Version;
136 IO.setContext(&Version);
137
138 // Restore the YAML context on function exit.
139 auto RestoreContext = make_scope_exit(F: [&]() { IO.setContext(OldContext); });
140
141 // Shader stage is only included in binaries for v1 and later, but we always
142 // include it since it simplifies parsing and file construction.
143 IO.mapRequired(Key: "ShaderStage", Val&: PSV.Info.ShaderStage);
144 PSV.mapInfoForVersion(IO);
145
146 IO.mapRequired(Key: "ResourceStride", Val&: PSV.ResourceStride);
147 IO.mapRequired(Key: "Resources", Val&: PSV.Resources);
148 if (PSV.Version == 0)
149 return;
150 IO.mapRequired(Key: "SigInputElements", Val&: PSV.SigInputElements);
151 IO.mapRequired(Key: "SigOutputElements", Val&: PSV.SigOutputElements);
152 IO.mapRequired(Key: "SigPatchOrPrimElements", Val&: PSV.SigPatchOrPrimElements);
153
154 Triple::EnvironmentType Stage = dxbc::getShaderStage(Kind: PSV.Info.ShaderStage);
155 if (PSV.Info.UsesViewID) {
156 MutableArrayRef<SmallVector<llvm::yaml::Hex32>> MutableOutMasks(
157 PSV.OutputVectorMasks);
158 IO.mapRequired(Key: "OutputVectorMasks", Val&: MutableOutMasks);
159 if (Stage == Triple::EnvironmentType::Hull)
160 IO.mapRequired(Key: "PatchOrPrimMasks", Val&: PSV.PatchOrPrimMasks);
161 }
162 MutableArrayRef<SmallVector<llvm::yaml::Hex32>> MutableIOMap(
163 PSV.InputOutputMap);
164 IO.mapRequired(Key: "InputOutputMap", Val&: MutableIOMap);
165
166 if (Stage == Triple::EnvironmentType::Hull)
167 IO.mapRequired(Key: "InputPatchMap", Val&: PSV.InputPatchMap);
168
169 if (Stage == Triple::EnvironmentType::Domain)
170 IO.mapRequired(Key: "PatchOutputMap", Val&: PSV.PatchOutputMap);
171}
172
173void MappingTraits<DXContainerYAML::SignatureParameter>::mapping(
174 IO &IO, DXContainerYAML::SignatureParameter &S) {
175 IO.mapRequired(Key: "Stream", Val&: S.Stream);
176 IO.mapRequired(Key: "Name", Val&: S.Name);
177 IO.mapRequired(Key: "Index", Val&: S.Index);
178 IO.mapRequired(Key: "SystemValue", Val&: S.SystemValue);
179 IO.mapRequired(Key: "CompType", Val&: S.CompType);
180 IO.mapRequired(Key: "Register", Val&: S.Register);
181 IO.mapRequired(Key: "Mask", Val&: S.Mask);
182 IO.mapRequired(Key: "ExclusiveMask", Val&: S.ExclusiveMask);
183 IO.mapRequired(Key: "MinPrecision", Val&: S.MinPrecision);
184}
185
186void MappingTraits<DXContainerYAML::Signature>::mapping(
187 IO &IO, DXContainerYAML::Signature &S) {
188 IO.mapRequired(Key: "Parameters", Val&: S.Parameters);
189}
190
191void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO,
192 DXContainerYAML::Part &P) {
193 IO.mapRequired(Key: "Name", Val&: P.Name);
194 IO.mapRequired(Key: "Size", Val&: P.Size);
195 IO.mapOptional(Key: "Program", Val&: P.Program);
196 IO.mapOptional(Key: "Flags", Val&: P.Flags);
197 IO.mapOptional(Key: "Hash", Val&: P.Hash);
198 IO.mapOptional(Key: "PSVInfo", Val&: P.Info);
199 IO.mapOptional(Key: "Signature", Val&: P.Signature);
200}
201
202void MappingTraits<DXContainerYAML::Object>::mapping(
203 IO &IO, DXContainerYAML::Object &Obj) {
204 IO.mapTag(Tag: "!dxcontainer", Default: true);
205 IO.mapRequired(Key: "Header", Val&: Obj.Header);
206 IO.mapRequired(Key: "Parts", Val&: Obj.Parts);
207}
208
209void MappingTraits<DXContainerYAML::ResourceBindInfo>::mapping(
210 IO &IO, DXContainerYAML::ResourceBindInfo &Res) {
211 IO.mapRequired(Key: "Type", Val&: Res.Type);
212 IO.mapRequired(Key: "Space", Val&: Res.Space);
213 IO.mapRequired(Key: "LowerBound", Val&: Res.LowerBound);
214 IO.mapRequired(Key: "UpperBound", Val&: Res.UpperBound);
215
216 const uint32_t *PSVVersion = static_cast<uint32_t *>(IO.getContext());
217 if (*PSVVersion < 2)
218 return;
219
220 IO.mapRequired(Key: "Kind", Val&: Res.Kind);
221 IO.mapRequired(Key: "Flags", Val&: Res.Flags);
222}
223
224void MappingTraits<DXContainerYAML::SignatureElement>::mapping(
225 IO &IO, DXContainerYAML::SignatureElement &El) {
226 IO.mapRequired(Key: "Name", Val&: El.Name);
227 IO.mapRequired(Key: "Indices", Val&: El.Indices);
228 IO.mapRequired(Key: "StartRow", Val&: El.StartRow);
229 IO.mapRequired(Key: "Cols", Val&: El.Cols);
230 IO.mapRequired(Key: "StartCol", Val&: El.StartCol);
231 IO.mapRequired(Key: "Allocated", Val&: El.Allocated);
232 IO.mapRequired(Key: "Kind", Val&: El.Kind);
233 IO.mapRequired(Key: "ComponentType", Val&: El.Type);
234 IO.mapRequired(Key: "Interpolation", Val&: El.Mode);
235 IO.mapRequired(Key: "DynamicMask", Val&: El.DynamicMask);
236 IO.mapRequired(Key: "Stream", Val&: El.Stream);
237}
238
239void ScalarEnumerationTraits<dxbc::PSV::SemanticKind>::enumeration(
240 IO &IO, dxbc::PSV::SemanticKind &Value) {
241 for (const auto &E : dxbc::PSV::getSemanticKinds())
242 IO.enumCase(Val&: Value, Str: E.Name.str().c_str(), ConstVal: E.Value);
243}
244
245void ScalarEnumerationTraits<dxbc::PSV::ComponentType>::enumeration(
246 IO &IO, dxbc::PSV::ComponentType &Value) {
247 for (const auto &E : dxbc::PSV::getComponentTypes())
248 IO.enumCase(Val&: Value, Str: E.Name.str().c_str(), ConstVal: E.Value);
249}
250
251void ScalarEnumerationTraits<dxbc::PSV::InterpolationMode>::enumeration(
252 IO &IO, dxbc::PSV::InterpolationMode &Value) {
253 for (const auto &E : dxbc::PSV::getInterpolationModes())
254 IO.enumCase(Val&: Value, Str: E.Name.str().c_str(), ConstVal: E.Value);
255}
256
257void ScalarEnumerationTraits<dxbc::D3DSystemValue>::enumeration(
258 IO &IO, dxbc::D3DSystemValue &Value) {
259 for (const auto &E : dxbc::getD3DSystemValues())
260 IO.enumCase(Val&: Value, Str: E.Name.str().c_str(), ConstVal: E.Value);
261}
262
263void ScalarEnumerationTraits<dxbc::SigMinPrecision>::enumeration(
264 IO &IO, dxbc::SigMinPrecision &Value) {
265 for (const auto &E : dxbc::getSigMinPrecisions())
266 IO.enumCase(Val&: Value, Str: E.Name.str().c_str(), ConstVal: E.Value);
267}
268
269void ScalarEnumerationTraits<dxbc::SigComponentType>::enumeration(
270 IO &IO, dxbc::SigComponentType &Value) {
271 for (const auto &E : dxbc::getSigComponentTypes())
272 IO.enumCase(Val&: Value, Str: E.Name.str().c_str(), ConstVal: E.Value);
273}
274
275} // namespace yaml
276
277void DXContainerYAML::PSVInfo::mapInfoForVersion(yaml::IO &IO) {
278 dxbc::PipelinePSVInfo &StageInfo = Info.StageInfo;
279 Triple::EnvironmentType Stage = dxbc::getShaderStage(Kind: Info.ShaderStage);
280
281 switch (Stage) {
282 case Triple::EnvironmentType::Pixel:
283 IO.mapRequired(Key: "DepthOutput", Val&: StageInfo.PS.DepthOutput);
284 IO.mapRequired(Key: "SampleFrequency", Val&: StageInfo.PS.SampleFrequency);
285 break;
286 case Triple::EnvironmentType::Vertex:
287 IO.mapRequired(Key: "OutputPositionPresent", Val&: StageInfo.VS.OutputPositionPresent);
288 break;
289 case Triple::EnvironmentType::Geometry:
290 IO.mapRequired(Key: "InputPrimitive", Val&: StageInfo.GS.InputPrimitive);
291 IO.mapRequired(Key: "OutputTopology", Val&: StageInfo.GS.OutputTopology);
292 IO.mapRequired(Key: "OutputStreamMask", Val&: StageInfo.GS.OutputStreamMask);
293 IO.mapRequired(Key: "OutputPositionPresent", Val&: StageInfo.GS.OutputPositionPresent);
294 break;
295 case Triple::EnvironmentType::Hull:
296 IO.mapRequired(Key: "InputControlPointCount",
297 Val&: StageInfo.HS.InputControlPointCount);
298 IO.mapRequired(Key: "OutputControlPointCount",
299 Val&: StageInfo.HS.OutputControlPointCount);
300 IO.mapRequired(Key: "TessellatorDomain", Val&: StageInfo.HS.TessellatorDomain);
301 IO.mapRequired(Key: "TessellatorOutputPrimitive",
302 Val&: StageInfo.HS.TessellatorOutputPrimitive);
303 break;
304 case Triple::EnvironmentType::Domain:
305 IO.mapRequired(Key: "InputControlPointCount",
306 Val&: StageInfo.DS.InputControlPointCount);
307 IO.mapRequired(Key: "OutputPositionPresent", Val&: StageInfo.DS.OutputPositionPresent);
308 IO.mapRequired(Key: "TessellatorDomain", Val&: StageInfo.DS.TessellatorDomain);
309 break;
310 case Triple::EnvironmentType::Mesh:
311 IO.mapRequired(Key: "GroupSharedBytesUsed", Val&: StageInfo.MS.GroupSharedBytesUsed);
312 IO.mapRequired(Key: "GroupSharedBytesDependentOnViewID",
313 Val&: StageInfo.MS.GroupSharedBytesDependentOnViewID);
314 IO.mapRequired(Key: "PayloadSizeInBytes", Val&: StageInfo.MS.PayloadSizeInBytes);
315 IO.mapRequired(Key: "MaxOutputVertices", Val&: StageInfo.MS.MaxOutputVertices);
316 IO.mapRequired(Key: "MaxOutputPrimitives", Val&: StageInfo.MS.MaxOutputPrimitives);
317 break;
318 case Triple::EnvironmentType::Amplification:
319 IO.mapRequired(Key: "PayloadSizeInBytes", Val&: StageInfo.AS.PayloadSizeInBytes);
320 break;
321 default:
322 break;
323 }
324
325 IO.mapRequired(Key: "MinimumWaveLaneCount", Val&: Info.MinimumWaveLaneCount);
326 IO.mapRequired(Key: "MaximumWaveLaneCount", Val&: Info.MaximumWaveLaneCount);
327
328 if (Version == 0)
329 return;
330
331 IO.mapRequired(Key: "UsesViewID", Val&: Info.UsesViewID);
332
333 switch (Stage) {
334 case Triple::EnvironmentType::Geometry:
335 IO.mapRequired(Key: "MaxVertexCount", Val&: Info.GeomData.MaxVertexCount);
336 break;
337 case Triple::EnvironmentType::Hull:
338 case Triple::EnvironmentType::Domain:
339 IO.mapRequired(Key: "SigPatchConstOrPrimVectors",
340 Val&: Info.GeomData.SigPatchConstOrPrimVectors);
341 break;
342 case Triple::EnvironmentType::Mesh:
343 IO.mapRequired(Key: "SigPrimVectors", Val&: Info.GeomData.MeshInfo.SigPrimVectors);
344 IO.mapRequired(Key: "MeshOutputTopology",
345 Val&: Info.GeomData.MeshInfo.MeshOutputTopology);
346 break;
347 default:
348 break;
349 }
350
351 IO.mapRequired(Key: "SigInputVectors", Val&: Info.SigInputVectors);
352 MutableArrayRef<uint8_t> Vec(Info.SigOutputVectors);
353 IO.mapRequired(Key: "SigOutputVectors", Val&: Vec);
354
355 if (Version == 1)
356 return;
357
358 IO.mapRequired(Key: "NumThreadsX", Val&: Info.NumThreadsX);
359 IO.mapRequired(Key: "NumThreadsY", Val&: Info.NumThreadsY);
360 IO.mapRequired(Key: "NumThreadsZ", Val&: Info.NumThreadsZ);
361
362 if (Version == 2)
363 return;
364
365 IO.mapRequired(Key: "EntryName", Val&: EntryName);
366}
367
368} // namespace llvm
369