xref: /llvm-project/llvm/tools/obj2yaml/dxcontainer2yaml.cpp (revision f42117c8517cc928c6373bad35ebf75d94fe865b)
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 
16 using namespace llvm;
17 using namespace llvm::object;
18 
dumpSignature(const DirectX::Signature & Sig)19 static DXContainerYAML::Signature dumpSignature(const DirectX::Signature &Sig) {
20   DXContainerYAML::Signature YAML;
21   for (auto Param : Sig)
22     YAML.Parameters.push_back(DXContainerYAML::SignatureParameter{
23         Param.Stream, Sig.getName(Param.NameOffset).str(), Param.Index,
24         Param.SystemValue, Param.CompType, Param.Register, Param.Mask,
25         Param.ExclusiveMask, Param.MinPrecision});
26   return YAML;
27 }
28 
29 static Expected<DXContainerYAML::Object *>
dumpDXContainer(MemoryBufferRef Source)30 dumpDXContainer(MemoryBufferRef Source) {
31   assert(file_magic::dxcontainer_object == identify_magic(Source.getBuffer()));
32 
33   Expected<DXContainer> ExDXC = DXContainer::create(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(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(P.Offset);
51     Obj->Parts.push_back(
52         DXContainerYAML::Part(P.Part.getName().str(), P.Part.Size));
53     DXContainerYAML::Part &NewPart = Obj->Parts.back();
54     dxbc::PartType PT = dxbc::parsePartType(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           DXIL->first.getMajorVersion(),
62           DXIL->first.getMinorVersion(),
63           DXIL->first.ShaderKind,
64           DXIL->first.Size,
65           DXIL->first.Bitcode.MajorVersion,
66           DXIL->first.Bitcode.MinorVersion,
67           DXIL->first.Bitcode.Offset,
68           DXIL->first.Bitcode.Size,
69           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>(&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                      &PSVInfo->getInfo()))
98         NewPart.Info = DXContainerYAML::PSVInfo(P);
99       else if (const auto *P =
100                    std::get_if<dxbc::PSV::v2::RuntimeInfo>(&PSVInfo->getInfo()))
101         NewPart.Info = DXContainerYAML::PSVInfo(P);
102       else if (const auto *P =
103                    std::get_if<dxbc::PSV::v3::RuntimeInfo>(&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(Res);
108 
109       for (auto El : PSVInfo->getSigInputElements())
110         NewPart.Info->SigInputElements.push_back(
111             DXContainerYAML::SignatureElement(
112                 El, PSVInfo->getStringTable(),
113                 PSVInfo->getSemanticIndexTable()));
114       for (auto El : PSVInfo->getSigOutputElements())
115         NewPart.Info->SigOutputElements.push_back(
116             DXContainerYAML::SignatureElement(
117                 El, PSVInfo->getStringTable(),
118                 PSVInfo->getSemanticIndexTable()));
119       for (auto El : PSVInfo->getSigPatchOrPrimElements())
120         NewPart.Info->SigPatchOrPrimElements.push_back(
121             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(I))
128             NewPart.Info->OutputVectorMasks[I].push_back(Mask);
129         for (auto Mask : PSVInfo->getPatchOrPrimMasks())
130           NewPart.Info->PatchOrPrimMasks.push_back(Mask);
131       }
132 
133       for (int I = 0; I < 4; ++I)
134         for (auto Mask : PSVInfo->getInputOutputMap(I))
135           NewPart.Info->InputOutputMap[I].push_back(Mask);
136 
137       for (auto Mask : PSVInfo->getInputPatchMap())
138         NewPart.Info->InputPatchMap.push_back(Mask);
139 
140       for (auto Mask : PSVInfo->getPatchOutputMap())
141         NewPart.Info->PatchOutputMap.push_back(Mask);
142 
143       break;
144     }
145     case dxbc::PartType::ISG1:
146       NewPart.Signature = dumpSignature(Container.getInputSignature());
147       break;
148     case dxbc::PartType::OSG1:
149       NewPart.Signature = dumpSignature(Container.getOutputSignature());
150       break;
151     case dxbc::PartType::PSG1:
152       NewPart.Signature = dumpSignature(Container.getPatchConstantSignature());
153       break;
154     case dxbc::PartType::Unknown:
155       break;
156     }
157   }
158 
159   return Obj.release();
160 }
161 
dxcontainer2yaml(llvm::raw_ostream & Out,llvm::MemoryBufferRef Source)162 llvm::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