1//===------ dxcontainer2yaml.cpp - obj2yaml conversion tool -----*- C++ -*-===//
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#include "obj2yaml.h"
10#include "llvm/Object/DXContainer.h"
11#include "llvm/ObjectYAML/DXContainerYAML.h"
12#include "llvm/Support/Error.h"
13
14#include <algorithm>
15
16using namespace llvm;
17using namespace llvm::object;
18
19static DXContainerYAML::Signature dumpSignature(const DirectX::Signature &Sig) {
20 DXContainerYAML::Signature YAML;
21 for (auto Param : Sig)
22 YAML.Parameters.push_back(Elt: DXContainerYAML::SignatureParameter{
23 .Stream: Param.Stream, .Name: Sig.getName(Offset: Param.NameOffset).str(), .Index: Param.Index,
24 .SystemValue: Param.SystemValue, .CompType: Param.CompType, .Register: Param.Register, .Mask: Param.Mask,
25 .ExclusiveMask: Param.ExclusiveMask, .MinPrecision: Param.MinPrecision});
26 return YAML;
27}
28
29static Expected<DXContainerYAML::Object *>
30dumpDXContainer(MemoryBufferRef Source) {
31 assert(file_magic::dxcontainer_object == identify_magic(Source.getBuffer()));
32
33 Expected<DXContainer> ExDXC = DXContainer::create(Object: Source);
34 if (!ExDXC)
35 return ExDXC.takeError();
36 DXContainer Container = *ExDXC;
37
38 std::unique_ptr<DXContainerYAML::Object> Obj =
39 std::make_unique<DXContainerYAML::Object>();
40
41 for (uint8_t Byte : Container.getHeader().FileHash.Digest)
42 Obj->Header.Hash.push_back(x: Byte);
43 Obj->Header.Version.Major = Container.getHeader().Version.Major;
44 Obj->Header.Version.Minor = Container.getHeader().Version.Minor;
45 Obj->Header.FileSize = Container.getHeader().FileSize;
46 Obj->Header.PartCount = Container.getHeader().PartCount;
47
48 Obj->Header.PartOffsets = std::vector<uint32_t>();
49 for (const auto P : Container) {
50 Obj->Header.PartOffsets->push_back(x: P.Offset);
51 Obj->Parts.push_back(
52 x: DXContainerYAML::Part(P.Part.getName().str(), P.Part.Size));
53 DXContainerYAML::Part &NewPart = Obj->Parts.back();
54 dxbc::PartType PT = dxbc::parsePartType(S: P.Part.getName());
55 switch (PT) {
56 case dxbc::PartType::DXIL: {
57 std::optional<DXContainer::DXILData> DXIL = Container.getDXIL();
58 assert(DXIL && "Since we are iterating and found a DXIL part, "
59 "this should never not have a value");
60 NewPart.Program = DXContainerYAML::DXILProgram{
61 .MajorVersion: DXIL->first.getMajorVersion(),
62 .MinorVersion: DXIL->first.getMinorVersion(),
63 .ShaderKind: DXIL->first.ShaderKind,
64 .Size: DXIL->first.Size,
65 .DXILMajorVersion: DXIL->first.Bitcode.MajorVersion,
66 .DXILMinorVersion: DXIL->first.Bitcode.MinorVersion,
67 .DXILOffset: DXIL->first.Bitcode.Offset,
68 .DXILSize: DXIL->first.Bitcode.Size,
69 .DXIL: std::vector<llvm::yaml::Hex8>(
70 DXIL->second, DXIL->second + DXIL->first.Bitcode.Size)};
71 break;
72 }
73 case dxbc::PartType::SFI0: {
74 std::optional<uint64_t> Flags = Container.getShaderFeatureFlags();
75 // Omit the flags in the YAML if they are missing or zero.
76 if (Flags && *Flags > 0)
77 NewPart.Flags = DXContainerYAML::ShaderFeatureFlags(*Flags);
78 break;
79 }
80 case dxbc::PartType::HASH: {
81 std::optional<dxbc::ShaderHash> Hash = Container.getShaderHash();
82 if (Hash && Hash->isPopulated())
83 NewPart.Hash = DXContainerYAML::ShaderHash(*Hash);
84 break;
85 }
86 case dxbc::PartType::PSV0: {
87 const auto &PSVInfo = Container.getPSVInfo();
88 if (!PSVInfo)
89 break;
90 if (const auto *P =
91 std::get_if<dxbc::PSV::v0::RuntimeInfo>(ptr: &PSVInfo->getInfo())) {
92 if (!Container.getDXIL())
93 break;
94 NewPart.Info =
95 DXContainerYAML::PSVInfo(P, Container.getDXIL()->first.ShaderKind);
96 } else if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(
97 ptr: &PSVInfo->getInfo()))
98 NewPart.Info = DXContainerYAML::PSVInfo(P);
99 else if (const auto *P =
100 std::get_if<dxbc::PSV::v2::RuntimeInfo>(ptr: &PSVInfo->getInfo()))
101 NewPart.Info = DXContainerYAML::PSVInfo(P);
102 else if (const auto *P =
103 std::get_if<dxbc::PSV::v3::RuntimeInfo>(ptr: &PSVInfo->getInfo()))
104 NewPart.Info = DXContainerYAML::PSVInfo(P, PSVInfo->getStringTable());
105 NewPart.Info->ResourceStride = PSVInfo->getResourceStride();
106 for (auto Res : PSVInfo->getResources())
107 NewPart.Info->Resources.push_back(Elt: Res);
108
109 for (auto El : PSVInfo->getSigInputElements())
110 NewPart.Info->SigInputElements.push_back(
111 Elt: DXContainerYAML::SignatureElement(
112 El, PSVInfo->getStringTable(),
113 PSVInfo->getSemanticIndexTable()));
114 for (auto El : PSVInfo->getSigOutputElements())
115 NewPart.Info->SigOutputElements.push_back(
116 Elt: DXContainerYAML::SignatureElement(
117 El, PSVInfo->getStringTable(),
118 PSVInfo->getSemanticIndexTable()));
119 for (auto El : PSVInfo->getSigPatchOrPrimElements())
120 NewPart.Info->SigPatchOrPrimElements.push_back(
121 Elt: DXContainerYAML::SignatureElement(
122 El, PSVInfo->getStringTable(),
123 PSVInfo->getSemanticIndexTable()));
124
125 if (PSVInfo->usesViewID()) {
126 for (int I = 0; I < 4; ++I)
127 for (auto Mask : PSVInfo->getOutputVectorMasks(Idx: I))
128 NewPart.Info->OutputVectorMasks[I].push_back(Elt: Mask);
129 for (auto Mask : PSVInfo->getPatchOrPrimMasks())
130 NewPart.Info->PatchOrPrimMasks.push_back(Elt: Mask);
131 }
132
133 for (int I = 0; I < 4; ++I)
134 for (auto Mask : PSVInfo->getInputOutputMap(Idx: I))
135 NewPart.Info->InputOutputMap[I].push_back(Elt: Mask);
136
137 for (auto Mask : PSVInfo->getInputPatchMap())
138 NewPart.Info->InputPatchMap.push_back(Elt: Mask);
139
140 for (auto Mask : PSVInfo->getPatchOutputMap())
141 NewPart.Info->PatchOutputMap.push_back(Elt: Mask);
142
143 break;
144 }
145 case dxbc::PartType::ISG1:
146 NewPart.Signature = dumpSignature(Sig: Container.getInputSignature());
147 break;
148 case dxbc::PartType::OSG1:
149 NewPart.Signature = dumpSignature(Sig: Container.getOutputSignature());
150 break;
151 case dxbc::PartType::PSG1:
152 NewPart.Signature = dumpSignature(Sig: Container.getPatchConstantSignature());
153 break;
154 case dxbc::PartType::Unknown:
155 break;
156 }
157 }
158
159 return Obj.release();
160}
161
162llvm::Error dxcontainer2yaml(llvm::raw_ostream &Out,
163 llvm::MemoryBufferRef Source) {
164 Expected<DXContainerYAML::Object *> YAMLOrErr = dumpDXContainer(Source);
165 if (!YAMLOrErr)
166 return YAMLOrErr.takeError();
167
168 std::unique_ptr<DXContainerYAML::Object> YAML(YAMLOrErr.get());
169 yaml::Output Yout(Out);
170 Yout << *YAML;
171
172 return Error::success();
173}
174