xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjectYAML/DXContainerEmitter.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
181ad6265SDimitry Andric //===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric ///
981ad6265SDimitry Andric /// \file
1081ad6265SDimitry Andric /// Binary emitter for yaml to DXContainer binary
1181ad6265SDimitry Andric ///
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "llvm/BinaryFormat/DXContainer.h"
15*06c3fb27SDimitry Andric #include "llvm/MC/DXContainerPSVInfo.h"
1681ad6265SDimitry Andric #include "llvm/ObjectYAML/ObjectYAML.h"
1781ad6265SDimitry Andric #include "llvm/ObjectYAML/yaml2obj.h"
1881ad6265SDimitry Andric #include "llvm/Support/Errc.h"
1981ad6265SDimitry Andric #include "llvm/Support/Error.h"
2081ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
2181ad6265SDimitry Andric 
2281ad6265SDimitry Andric using namespace llvm;
2381ad6265SDimitry Andric 
2481ad6265SDimitry Andric namespace {
2581ad6265SDimitry Andric class DXContainerWriter {
2681ad6265SDimitry Andric public:
2781ad6265SDimitry Andric   DXContainerWriter(DXContainerYAML::Object &ObjectFile)
2881ad6265SDimitry Andric       : ObjectFile(ObjectFile) {}
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric   Error write(raw_ostream &OS);
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric private:
3381ad6265SDimitry Andric   DXContainerYAML::Object &ObjectFile;
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric   Error computePartOffsets();
3681ad6265SDimitry Andric   Error validatePartOffsets();
3781ad6265SDimitry Andric   Error validateSize(uint32_t Computed);
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric   void writeHeader(raw_ostream &OS);
4081ad6265SDimitry Andric   void writeParts(raw_ostream &OS);
4181ad6265SDimitry Andric };
4281ad6265SDimitry Andric } // namespace
4381ad6265SDimitry Andric 
4481ad6265SDimitry Andric Error DXContainerWriter::validateSize(uint32_t Computed) {
4581ad6265SDimitry Andric   if (!ObjectFile.Header.FileSize)
4681ad6265SDimitry Andric     ObjectFile.Header.FileSize = Computed;
4781ad6265SDimitry Andric   else if (*ObjectFile.Header.FileSize < Computed)
4881ad6265SDimitry Andric     return createStringError(errc::result_out_of_range,
4981ad6265SDimitry Andric                              "File size specified is too small.");
5081ad6265SDimitry Andric   return Error::success();
5181ad6265SDimitry Andric }
5281ad6265SDimitry Andric 
5381ad6265SDimitry Andric Error DXContainerWriter::validatePartOffsets() {
5481ad6265SDimitry Andric   if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
5581ad6265SDimitry Andric     return createStringError(
5681ad6265SDimitry Andric         errc::invalid_argument,
5781ad6265SDimitry Andric         "Mismatch between number of parts and part offsets.");
5881ad6265SDimitry Andric   uint32_t RollingOffset =
5981ad6265SDimitry Andric       sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
6081ad6265SDimitry Andric   for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
6181ad6265SDimitry Andric     if (RollingOffset > std::get<1>(I))
6281ad6265SDimitry Andric       return createStringError(errc::invalid_argument,
6381ad6265SDimitry Andric                                "Offset mismatch, not enough space for data.");
6481ad6265SDimitry Andric     RollingOffset =
6581ad6265SDimitry Andric         std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
6681ad6265SDimitry Andric   }
6781ad6265SDimitry Andric   if (Error Err = validateSize(RollingOffset))
6881ad6265SDimitry Andric     return Err;
6981ad6265SDimitry Andric 
7081ad6265SDimitry Andric   return Error::success();
7181ad6265SDimitry Andric }
7281ad6265SDimitry Andric 
7381ad6265SDimitry Andric Error DXContainerWriter::computePartOffsets() {
7481ad6265SDimitry Andric   if (ObjectFile.Header.PartOffsets)
7581ad6265SDimitry Andric     return validatePartOffsets();
7681ad6265SDimitry Andric   uint32_t RollingOffset =
7781ad6265SDimitry Andric       sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
7881ad6265SDimitry Andric   ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
7981ad6265SDimitry Andric   for (const auto &Part : ObjectFile.Parts) {
8081ad6265SDimitry Andric     ObjectFile.Header.PartOffsets->push_back(RollingOffset);
8181ad6265SDimitry Andric     RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
8281ad6265SDimitry Andric   }
8381ad6265SDimitry Andric   if (Error Err = validateSize(RollingOffset))
8481ad6265SDimitry Andric     return Err;
8581ad6265SDimitry Andric 
8681ad6265SDimitry Andric   return Error::success();
8781ad6265SDimitry Andric }
8881ad6265SDimitry Andric 
8981ad6265SDimitry Andric void DXContainerWriter::writeHeader(raw_ostream &OS) {
9081ad6265SDimitry Andric   dxbc::Header Header;
9181ad6265SDimitry Andric   memcpy(Header.Magic, "DXBC", 4);
9281ad6265SDimitry Andric   memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
9381ad6265SDimitry Andric   Header.Version.Major = ObjectFile.Header.Version.Major;
9481ad6265SDimitry Andric   Header.Version.Minor = ObjectFile.Header.Version.Minor;
9581ad6265SDimitry Andric   Header.FileSize = *ObjectFile.Header.FileSize;
9681ad6265SDimitry Andric   Header.PartCount = ObjectFile.Parts.size();
9781ad6265SDimitry Andric   if (sys::IsBigEndianHost)
9881ad6265SDimitry Andric     Header.swapBytes();
9981ad6265SDimitry Andric   OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
10081ad6265SDimitry Andric   SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
10181ad6265SDimitry Andric                                 ObjectFile.Header.PartOffsets->end());
10281ad6265SDimitry Andric   if (sys::IsBigEndianHost)
10381ad6265SDimitry Andric     for (auto &O : Offsets)
10481ad6265SDimitry Andric       sys::swapByteOrder(O);
10581ad6265SDimitry Andric   OS.write(reinterpret_cast<char *>(Offsets.data()),
10681ad6265SDimitry Andric            Offsets.size() * sizeof(uint32_t));
10781ad6265SDimitry Andric }
10881ad6265SDimitry Andric 
10981ad6265SDimitry Andric void DXContainerWriter::writeParts(raw_ostream &OS) {
11081ad6265SDimitry Andric   uint32_t RollingOffset =
11181ad6265SDimitry Andric       sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
11281ad6265SDimitry Andric   for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
11381ad6265SDimitry Andric     if (RollingOffset < std::get<1>(I)) {
11481ad6265SDimitry Andric       uint32_t PadBytes = std::get<1>(I) - RollingOffset;
11581ad6265SDimitry Andric       OS.write_zeros(PadBytes);
11681ad6265SDimitry Andric     }
11781ad6265SDimitry Andric     DXContainerYAML::Part P = std::get<0>(I);
118bdd1243dSDimitry Andric     RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
119bdd1243dSDimitry Andric     uint32_t PartSize = P.Size;
120bdd1243dSDimitry Andric 
12181ad6265SDimitry Andric     OS.write(P.Name.c_str(), 4);
12281ad6265SDimitry Andric     if (sys::IsBigEndianHost)
12381ad6265SDimitry Andric       sys::swapByteOrder(P.Size);
12481ad6265SDimitry Andric     OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
12581ad6265SDimitry Andric 
126bdd1243dSDimitry Andric     dxbc::PartType PT = dxbc::parsePartType(P.Name);
127bdd1243dSDimitry Andric 
128bdd1243dSDimitry Andric     uint64_t DataStart = OS.tell();
129bdd1243dSDimitry Andric     switch (PT) {
130bdd1243dSDimitry Andric     case dxbc::PartType::DXIL: {
131bdd1243dSDimitry Andric       if (!P.Program)
132bdd1243dSDimitry Andric         continue;
13381ad6265SDimitry Andric       dxbc::ProgramHeader Header;
13481ad6265SDimitry Andric       Header.MajorVersion = P.Program->MajorVersion;
13581ad6265SDimitry Andric       Header.MinorVersion = P.Program->MinorVersion;
13681ad6265SDimitry Andric       Header.Unused = 0;
13781ad6265SDimitry Andric       Header.ShaderKind = P.Program->ShaderKind;
13881ad6265SDimitry Andric       memcpy(Header.Bitcode.Magic, "DXIL", 4);
13981ad6265SDimitry Andric       Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
14081ad6265SDimitry Andric       Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
14181ad6265SDimitry Andric       Header.Bitcode.Unused = 0;
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric       // Compute the optional fields if needed...
14481ad6265SDimitry Andric       if (P.Program->DXILOffset)
145bdd1243dSDimitry Andric         Header.Bitcode.Offset = *P.Program->DXILOffset;
14681ad6265SDimitry Andric       else
14781ad6265SDimitry Andric         Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric       if (P.Program->DXILSize)
150bdd1243dSDimitry Andric         Header.Bitcode.Size = *P.Program->DXILSize;
15181ad6265SDimitry Andric       else
15281ad6265SDimitry Andric         Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric       if (P.Program->Size)
155bdd1243dSDimitry Andric         Header.Size = *P.Program->Size;
15681ad6265SDimitry Andric       else
15781ad6265SDimitry Andric         Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
15881ad6265SDimitry Andric 
15981ad6265SDimitry Andric       uint32_t BitcodeOffset = Header.Bitcode.Offset;
16081ad6265SDimitry Andric       if (sys::IsBigEndianHost)
16181ad6265SDimitry Andric         Header.swapBytes();
16281ad6265SDimitry Andric       OS.write(reinterpret_cast<const char *>(&Header),
16381ad6265SDimitry Andric                sizeof(dxbc::ProgramHeader));
16481ad6265SDimitry Andric       if (P.Program->DXIL) {
16581ad6265SDimitry Andric         if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
16681ad6265SDimitry Andric           uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
16781ad6265SDimitry Andric           OS.write_zeros(PadBytes);
16881ad6265SDimitry Andric         }
16981ad6265SDimitry Andric         OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
17081ad6265SDimitry Andric                  P.Program->DXIL->size());
17181ad6265SDimitry Andric       }
172bdd1243dSDimitry Andric       break;
17381ad6265SDimitry Andric     }
174bdd1243dSDimitry Andric     case dxbc::PartType::SFI0: {
175bdd1243dSDimitry Andric       // If we don't have any flags we can continue here and the data will be
176bdd1243dSDimitry Andric       // zeroed out.
177bdd1243dSDimitry Andric       if (!P.Flags.has_value())
178bdd1243dSDimitry Andric         continue;
179bdd1243dSDimitry Andric       uint64_t Flags = P.Flags->getEncodedFlags();
180bdd1243dSDimitry Andric       if (sys::IsBigEndianHost)
181bdd1243dSDimitry Andric         sys::swapByteOrder(Flags);
182bdd1243dSDimitry Andric       OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
183bdd1243dSDimitry Andric       break;
184bdd1243dSDimitry Andric     }
185bdd1243dSDimitry Andric     case dxbc::PartType::HASH: {
186bdd1243dSDimitry Andric       if (!P.Hash.has_value())
187bdd1243dSDimitry Andric         continue;
188bdd1243dSDimitry Andric       dxbc::ShaderHash Hash = {0, {0}};
189bdd1243dSDimitry Andric       if (P.Hash->IncludesSource)
190bdd1243dSDimitry Andric         Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
191bdd1243dSDimitry Andric       memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
192bdd1243dSDimitry Andric       if (sys::IsBigEndianHost)
193bdd1243dSDimitry Andric         Hash.swapBytes();
194bdd1243dSDimitry Andric       OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
195bdd1243dSDimitry Andric       break;
196bdd1243dSDimitry Andric     }
197*06c3fb27SDimitry Andric     case dxbc::PartType::PSV0: {
198*06c3fb27SDimitry Andric       if (!P.Info.has_value())
199*06c3fb27SDimitry Andric         continue;
200*06c3fb27SDimitry Andric       mcdxbc::PSVRuntimeInfo PSV;
201*06c3fb27SDimitry Andric       memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v2::RuntimeInfo));
202*06c3fb27SDimitry Andric       PSV.Resources = P.Info->Resources;
203*06c3fb27SDimitry Andric 
204*06c3fb27SDimitry Andric       if (sys::IsBigEndianHost)
205*06c3fb27SDimitry Andric         PSV.swapBytes(static_cast<Triple::EnvironmentType>(
206*06c3fb27SDimitry Andric             Triple::Pixel + P.Info->Info.ShaderStage));
207*06c3fb27SDimitry Andric       PSV.write(OS, P.Info->Version);
208*06c3fb27SDimitry Andric       break;
209*06c3fb27SDimitry Andric     }
210bdd1243dSDimitry Andric     case dxbc::PartType::Unknown:
211bdd1243dSDimitry Andric       break; // Skip any handling for unrecognized parts.
212bdd1243dSDimitry Andric     }
213bdd1243dSDimitry Andric     uint64_t BytesWritten = OS.tell() - DataStart;
214bdd1243dSDimitry Andric     RollingOffset += BytesWritten;
215bdd1243dSDimitry Andric     if (BytesWritten < PartSize)
216bdd1243dSDimitry Andric       OS.write_zeros(PartSize - BytesWritten);
217bdd1243dSDimitry Andric     RollingOffset += PartSize;
21881ad6265SDimitry Andric   }
21981ad6265SDimitry Andric }
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric Error DXContainerWriter::write(raw_ostream &OS) {
22281ad6265SDimitry Andric   if (Error Err = computePartOffsets())
22381ad6265SDimitry Andric     return Err;
22481ad6265SDimitry Andric   writeHeader(OS);
22581ad6265SDimitry Andric   writeParts(OS);
22681ad6265SDimitry Andric   return Error::success();
22781ad6265SDimitry Andric }
22881ad6265SDimitry Andric 
22981ad6265SDimitry Andric namespace llvm {
23081ad6265SDimitry Andric namespace yaml {
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
23381ad6265SDimitry Andric                       ErrorHandler EH) {
23481ad6265SDimitry Andric   DXContainerWriter Writer(Doc);
23581ad6265SDimitry Andric   if (Error Err = Writer.write(Out)) {
23681ad6265SDimitry Andric     handleAllErrors(std::move(Err),
23781ad6265SDimitry Andric                     [&](const ErrorInfoBase &Err) { EH(Err.message()); });
23881ad6265SDimitry Andric     return false;
23981ad6265SDimitry Andric   }
24081ad6265SDimitry Andric   return true;
24181ad6265SDimitry Andric }
24281ad6265SDimitry Andric 
24381ad6265SDimitry Andric } // namespace yaml
24481ad6265SDimitry Andric } // namespace llvm
245