xref: /llvm-project/llvm/lib/ObjectYAML/DXContainerEmitter.cpp (revision f42117c8517cc928c6373bad35ebf75d94fe865b)
1129c056dSChris Bieneman //===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//
2129c056dSChris Bieneman //
3129c056dSChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4129c056dSChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
5129c056dSChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6129c056dSChris Bieneman //
7129c056dSChris Bieneman //===----------------------------------------------------------------------===//
8129c056dSChris Bieneman ///
9129c056dSChris Bieneman /// \file
10129c056dSChris Bieneman /// Binary emitter for yaml to DXContainer binary
11129c056dSChris Bieneman ///
12129c056dSChris Bieneman //===----------------------------------------------------------------------===//
13129c056dSChris Bieneman 
14129c056dSChris Bieneman #include "llvm/BinaryFormat/DXContainer.h"
15ad93908eSChris Bieneman #include "llvm/MC/DXContainerPSVInfo.h"
16129c056dSChris Bieneman #include "llvm/ObjectYAML/ObjectYAML.h"
17129c056dSChris Bieneman #include "llvm/ObjectYAML/yaml2obj.h"
18129c056dSChris Bieneman #include "llvm/Support/Errc.h"
19129c056dSChris Bieneman #include "llvm/Support/Error.h"
20129c056dSChris Bieneman #include "llvm/Support/raw_ostream.h"
21129c056dSChris Bieneman 
22129c056dSChris Bieneman using namespace llvm;
23129c056dSChris Bieneman 
24129c056dSChris Bieneman namespace {
25129c056dSChris Bieneman class DXContainerWriter {
26129c056dSChris Bieneman public:
DXContainerWriter(DXContainerYAML::Object & ObjectFile)27129c056dSChris Bieneman   DXContainerWriter(DXContainerYAML::Object &ObjectFile)
28129c056dSChris Bieneman       : ObjectFile(ObjectFile) {}
29129c056dSChris Bieneman 
30129c056dSChris Bieneman   Error write(raw_ostream &OS);
31129c056dSChris Bieneman 
32129c056dSChris Bieneman private:
33129c056dSChris Bieneman   DXContainerYAML::Object &ObjectFile;
34129c056dSChris Bieneman 
35129c056dSChris Bieneman   Error computePartOffsets();
36129c056dSChris Bieneman   Error validatePartOffsets();
37129c056dSChris Bieneman   Error validateSize(uint32_t Computed);
38129c056dSChris Bieneman 
39129c056dSChris Bieneman   void writeHeader(raw_ostream &OS);
40129c056dSChris Bieneman   void writeParts(raw_ostream &OS);
41129c056dSChris Bieneman };
42129c056dSChris Bieneman } // namespace
43129c056dSChris Bieneman 
validateSize(uint32_t Computed)44129c056dSChris Bieneman Error DXContainerWriter::validateSize(uint32_t Computed) {
45129c056dSChris Bieneman   if (!ObjectFile.Header.FileSize)
46129c056dSChris Bieneman     ObjectFile.Header.FileSize = Computed;
47129c056dSChris Bieneman   else if (*ObjectFile.Header.FileSize < Computed)
48129c056dSChris Bieneman     return createStringError(errc::result_out_of_range,
49129c056dSChris Bieneman                              "File size specified is too small.");
50129c056dSChris Bieneman   return Error::success();
51129c056dSChris Bieneman }
52129c056dSChris Bieneman 
validatePartOffsets()53129c056dSChris Bieneman Error DXContainerWriter::validatePartOffsets() {
54129c056dSChris Bieneman   if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
55129c056dSChris Bieneman     return createStringError(
56129c056dSChris Bieneman         errc::invalid_argument,
57129c056dSChris Bieneman         "Mismatch between number of parts and part offsets.");
58129c056dSChris Bieneman   uint32_t RollingOffset =
59129c056dSChris Bieneman       sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
60129c056dSChris Bieneman   for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
61129c056dSChris Bieneman     if (RollingOffset > std::get<1>(I))
62129c056dSChris Bieneman       return createStringError(errc::invalid_argument,
63129c056dSChris Bieneman                                "Offset mismatch, not enough space for data.");
64129c056dSChris Bieneman     RollingOffset =
65129c056dSChris Bieneman         std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
66129c056dSChris Bieneman   }
67129c056dSChris Bieneman   if (Error Err = validateSize(RollingOffset))
68129c056dSChris Bieneman     return Err;
69129c056dSChris Bieneman 
70129c056dSChris Bieneman   return Error::success();
71129c056dSChris Bieneman }
72129c056dSChris Bieneman 
computePartOffsets()73129c056dSChris Bieneman Error DXContainerWriter::computePartOffsets() {
74129c056dSChris Bieneman   if (ObjectFile.Header.PartOffsets)
75129c056dSChris Bieneman     return validatePartOffsets();
76129c056dSChris Bieneman   uint32_t RollingOffset =
77129c056dSChris Bieneman       sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
78129c056dSChris Bieneman   ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
79129c056dSChris Bieneman   for (const auto &Part : ObjectFile.Parts) {
80129c056dSChris Bieneman     ObjectFile.Header.PartOffsets->push_back(RollingOffset);
81129c056dSChris Bieneman     RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
82129c056dSChris Bieneman   }
83129c056dSChris Bieneman   if (Error Err = validateSize(RollingOffset))
84129c056dSChris Bieneman     return Err;
85129c056dSChris Bieneman 
86129c056dSChris Bieneman   return Error::success();
87129c056dSChris Bieneman }
88129c056dSChris Bieneman 
writeHeader(raw_ostream & OS)89129c056dSChris Bieneman void DXContainerWriter::writeHeader(raw_ostream &OS) {
90129c056dSChris Bieneman   dxbc::Header Header;
91129c056dSChris Bieneman   memcpy(Header.Magic, "DXBC", 4);
92129c056dSChris Bieneman   memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
93129c056dSChris Bieneman   Header.Version.Major = ObjectFile.Header.Version.Major;
94129c056dSChris Bieneman   Header.Version.Minor = ObjectFile.Header.Version.Minor;
95129c056dSChris Bieneman   Header.FileSize = *ObjectFile.Header.FileSize;
96129c056dSChris Bieneman   Header.PartCount = ObjectFile.Parts.size();
97129c056dSChris Bieneman   if (sys::IsBigEndianHost)
98129c056dSChris Bieneman     Header.swapBytes();
99129c056dSChris Bieneman   OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
1006784adc6SChris Bieneman   SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
1016784adc6SChris Bieneman                                 ObjectFile.Header.PartOffsets->end());
102129c056dSChris Bieneman   if (sys::IsBigEndianHost)
1036784adc6SChris Bieneman     for (auto &O : Offsets)
104129c056dSChris Bieneman       sys::swapByteOrder(O);
1056784adc6SChris Bieneman   OS.write(reinterpret_cast<char *>(Offsets.data()),
1066784adc6SChris Bieneman            Offsets.size() * sizeof(uint32_t));
107129c056dSChris Bieneman }
10821c94523SChris Bieneman 
writeParts(raw_ostream & OS)109129c056dSChris Bieneman void DXContainerWriter::writeParts(raw_ostream &OS) {
110129c056dSChris Bieneman   uint32_t RollingOffset =
111129c056dSChris Bieneman       sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
112129c056dSChris Bieneman   for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
113129c056dSChris Bieneman     if (RollingOffset < std::get<1>(I)) {
114129c056dSChris Bieneman       uint32_t PadBytes = std::get<1>(I) - RollingOffset;
11521c94523SChris Bieneman       OS.write_zeros(PadBytes);
116129c056dSChris Bieneman     }
117129c056dSChris Bieneman     DXContainerYAML::Part P = std::get<0>(I);
11849dc58f5SChris Bieneman     RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
11949dc58f5SChris Bieneman     uint32_t PartSize = P.Size;
12049dc58f5SChris Bieneman 
121129c056dSChris Bieneman     OS.write(P.Name.c_str(), 4);
122129c056dSChris Bieneman     if (sys::IsBigEndianHost)
123129c056dSChris Bieneman       sys::swapByteOrder(P.Size);
124129c056dSChris Bieneman     OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
125129c056dSChris Bieneman 
12649dc58f5SChris Bieneman     dxbc::PartType PT = dxbc::parsePartType(P.Name);
12749dc58f5SChris Bieneman 
12849dc58f5SChris Bieneman     uint64_t DataStart = OS.tell();
1292556ba4aSChris Bieneman     switch (PT) {
1302556ba4aSChris Bieneman     case dxbc::PartType::DXIL: {
13149dc58f5SChris Bieneman       if (!P.Program)
13249dc58f5SChris Bieneman         continue;
13321c94523SChris Bieneman       dxbc::ProgramHeader Header;
134*f42117c8SXiang Li       Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
135*f42117c8SXiang Li                                                        P.Program->MinorVersion);
1361fd0beaaSBenjamin Kramer       Header.Unused = 0;
13721c94523SChris Bieneman       Header.ShaderKind = P.Program->ShaderKind;
13821c94523SChris Bieneman       memcpy(Header.Bitcode.Magic, "DXIL", 4);
13921c94523SChris Bieneman       Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
14021c94523SChris Bieneman       Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
1411fd0beaaSBenjamin Kramer       Header.Bitcode.Unused = 0;
14221c94523SChris Bieneman 
14321c94523SChris Bieneman       // Compute the optional fields if needed...
14421c94523SChris Bieneman       if (P.Program->DXILOffset)
14567ba5c50SFangrui Song         Header.Bitcode.Offset = *P.Program->DXILOffset;
14621c94523SChris Bieneman       else
14721c94523SChris Bieneman         Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
14821c94523SChris Bieneman 
14921c94523SChris Bieneman       if (P.Program->DXILSize)
15067ba5c50SFangrui Song         Header.Bitcode.Size = *P.Program->DXILSize;
15121c94523SChris Bieneman       else
15221c94523SChris Bieneman         Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
15321c94523SChris Bieneman 
15421c94523SChris Bieneman       if (P.Program->Size)
15567ba5c50SFangrui Song         Header.Size = *P.Program->Size;
15621c94523SChris Bieneman       else
15721c94523SChris Bieneman         Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
158eb68cbb4SChris Bieneman 
159eb68cbb4SChris Bieneman       uint32_t BitcodeOffset = Header.Bitcode.Offset;
16021c94523SChris Bieneman       if (sys::IsBigEndianHost)
16121c94523SChris Bieneman         Header.swapBytes();
16221c94523SChris Bieneman       OS.write(reinterpret_cast<const char *>(&Header),
16321c94523SChris Bieneman                sizeof(dxbc::ProgramHeader));
16421c94523SChris Bieneman       if (P.Program->DXIL) {
165eb68cbb4SChris Bieneman         if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
166eb68cbb4SChris Bieneman           uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
16721c94523SChris Bieneman           OS.write_zeros(PadBytes);
16821c94523SChris Bieneman         }
16921c94523SChris Bieneman         OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
17021c94523SChris Bieneman                  P.Program->DXIL->size());
17121c94523SChris Bieneman       }
1722556ba4aSChris Bieneman       break;
1732556ba4aSChris Bieneman     }
1742556ba4aSChris Bieneman     case dxbc::PartType::SFI0: {
17549dc58f5SChris Bieneman       // If we don't have any flags we can continue here and the data will be
17649dc58f5SChris Bieneman       // zeroed out.
17749dc58f5SChris Bieneman       if (!P.Flags.has_value())
17849dc58f5SChris Bieneman         continue;
17949dc58f5SChris Bieneman       uint64_t Flags = P.Flags->getEncodedFlags();
18049dc58f5SChris Bieneman       if (sys::IsBigEndianHost)
18149dc58f5SChris Bieneman         sys::swapByteOrder(Flags);
18249dc58f5SChris Bieneman       OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
1832556ba4aSChris Bieneman       break;
1842556ba4aSChris Bieneman     }
1852556ba4aSChris Bieneman     case dxbc::PartType::HASH: {
1862556ba4aSChris Bieneman       if (!P.Hash.has_value())
1872556ba4aSChris Bieneman         continue;
1882556ba4aSChris Bieneman       dxbc::ShaderHash Hash = {0, {0}};
1892556ba4aSChris Bieneman       if (P.Hash->IncludesSource)
1902556ba4aSChris Bieneman         Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
1912556ba4aSChris Bieneman       memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
1922556ba4aSChris Bieneman       if (sys::IsBigEndianHost)
1932556ba4aSChris Bieneman         Hash.swapBytes();
1942556ba4aSChris Bieneman       OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
1952556ba4aSChris Bieneman       break;
1962556ba4aSChris Bieneman     }
197ad93908eSChris Bieneman     case dxbc::PartType::PSV0: {
198ad93908eSChris Bieneman       if (!P.Info.has_value())
199ad93908eSChris Bieneman         continue;
200ad93908eSChris Bieneman       mcdxbc::PSVRuntimeInfo PSV;
201c62c7463SCooper Partin       memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
202dd3f7b02SChris Bieneman       PSV.Resources = P.Info->Resources;
203c62c7463SCooper Partin       PSV.EntryName = P.Info->EntryName;
204ad93908eSChris Bieneman 
2050c3f51c0SChris Bieneman       for (auto El : P.Info->SigInputElements)
2060c3f51c0SChris Bieneman         PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{
2070c3f51c0SChris Bieneman             El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2080c3f51c0SChris Bieneman             El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2090c3f51c0SChris Bieneman             El.Stream});
2100c3f51c0SChris Bieneman 
2110c3f51c0SChris Bieneman       for (auto El : P.Info->SigOutputElements)
2120c3f51c0SChris Bieneman         PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{
2130c3f51c0SChris Bieneman             El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2140c3f51c0SChris Bieneman             El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2150c3f51c0SChris Bieneman             El.Stream});
2160c3f51c0SChris Bieneman 
2170c3f51c0SChris Bieneman       for (auto El : P.Info->SigPatchOrPrimElements)
2180c3f51c0SChris Bieneman         PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{
2190c3f51c0SChris Bieneman             El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2200c3f51c0SChris Bieneman             El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2210c3f51c0SChris Bieneman             El.Stream});
2220c3f51c0SChris Bieneman 
223b799e9daSChris B       static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
224b799e9daSChris B       for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
225b799e9daSChris B         PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
226b799e9daSChris B                                         P.Info->OutputVectorMasks[I].begin(),
227b799e9daSChris B                                         P.Info->OutputVectorMasks[I].end());
228b799e9daSChris B         PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
229b799e9daSChris B                                      P.Info->InputOutputMap[I].begin(),
230b799e9daSChris B                                      P.Info->InputOutputMap[I].end());
231b799e9daSChris B       }
232b799e9daSChris B 
233b799e9daSChris B       PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),
234b799e9daSChris B                                   P.Info->PatchOrPrimMasks.begin(),
235b799e9daSChris B                                   P.Info->PatchOrPrimMasks.end());
236b799e9daSChris B       PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),
237b799e9daSChris B                                P.Info->InputPatchMap.begin(),
238b799e9daSChris B                                P.Info->InputPatchMap.end());
239b799e9daSChris B       PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),
240b799e9daSChris B                                 P.Info->PatchOutputMap.begin(),
241b799e9daSChris B                                 P.Info->PatchOutputMap.end());
242b799e9daSChris B 
2430c3f51c0SChris Bieneman       PSV.finalize(static_cast<Triple::EnvironmentType>(
244ad93908eSChris Bieneman           Triple::Pixel + P.Info->Info.ShaderStage));
245ad93908eSChris Bieneman       PSV.write(OS, P.Info->Version);
246ad93908eSChris Bieneman       break;
247ad93908eSChris Bieneman     }
2489f87522bSChris B     case dxbc::PartType::ISG1:
2499f87522bSChris B     case dxbc::PartType::OSG1:
2509f87522bSChris B     case dxbc::PartType::PSG1: {
2519f87522bSChris B       mcdxbc::Signature Sig;
2529f87522bSChris B       if (P.Signature.has_value()) {
2539f87522bSChris B         for (const auto &Param : P.Signature->Parameters) {
2549f87522bSChris B           Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
2559f87522bSChris B                        Param.CompType, Param.Register, Param.Mask,
2569f87522bSChris B                        Param.ExclusiveMask, Param.MinPrecision);
2579f87522bSChris B         }
2589f87522bSChris B       }
2599f87522bSChris B       Sig.write(OS);
2609f87522bSChris B       break;
2619f87522bSChris B     }
2622556ba4aSChris Bieneman     case dxbc::PartType::Unknown:
2632556ba4aSChris Bieneman       break; // Skip any handling for unrecognized parts.
26421c94523SChris Bieneman     }
26549dc58f5SChris Bieneman     uint64_t BytesWritten = OS.tell() - DataStart;
26649dc58f5SChris Bieneman     RollingOffset += BytesWritten;
26749dc58f5SChris Bieneman     if (BytesWritten < PartSize)
26849dc58f5SChris Bieneman       OS.write_zeros(PartSize - BytesWritten);
26949dc58f5SChris Bieneman     RollingOffset += PartSize;
270129c056dSChris Bieneman   }
271129c056dSChris Bieneman }
272129c056dSChris Bieneman 
write(raw_ostream & OS)273129c056dSChris Bieneman Error DXContainerWriter::write(raw_ostream &OS) {
274129c056dSChris Bieneman   if (Error Err = computePartOffsets())
275129c056dSChris Bieneman     return Err;
276129c056dSChris Bieneman   writeHeader(OS);
277129c056dSChris Bieneman   writeParts(OS);
278129c056dSChris Bieneman   return Error::success();
279129c056dSChris Bieneman }
280129c056dSChris Bieneman 
281129c056dSChris Bieneman namespace llvm {
282129c056dSChris Bieneman namespace yaml {
283129c056dSChris Bieneman 
yaml2dxcontainer(DXContainerYAML::Object & Doc,raw_ostream & Out,ErrorHandler EH)284129c056dSChris Bieneman bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
285129c056dSChris Bieneman                       ErrorHandler EH) {
286129c056dSChris Bieneman   DXContainerWriter Writer(Doc);
287129c056dSChris Bieneman   if (Error Err = Writer.write(Out)) {
288129c056dSChris Bieneman     handleAllErrors(std::move(Err),
289129c056dSChris Bieneman                     [&](const ErrorInfoBase &Err) { EH(Err.message()); });
290129c056dSChris Bieneman     return false;
291129c056dSChris Bieneman   }
292129c056dSChris Bieneman   return true;
293129c056dSChris Bieneman }
294129c056dSChris Bieneman 
295129c056dSChris Bieneman } // namespace yaml
296129c056dSChris Bieneman } // namespace llvm
297