xref: /freebsd-src/contrib/llvm-project/llvm/lib/ObjectYAML/DXContainerEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
1506c3fb27SDimitry 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;
134*0fca6ea1SDimitry Andric       Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
135*0fca6ea1SDimitry Andric                                                        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     }
19706c3fb27SDimitry Andric     case dxbc::PartType::PSV0: {
19806c3fb27SDimitry Andric       if (!P.Info.has_value())
19906c3fb27SDimitry Andric         continue;
20006c3fb27SDimitry Andric       mcdxbc::PSVRuntimeInfo PSV;
201*0fca6ea1SDimitry Andric       memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
20206c3fb27SDimitry Andric       PSV.Resources = P.Info->Resources;
203*0fca6ea1SDimitry Andric       PSV.EntryName = P.Info->EntryName;
20406c3fb27SDimitry Andric 
2055f757f3fSDimitry Andric       for (auto El : P.Info->SigInputElements)
2065f757f3fSDimitry Andric         PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{
2075f757f3fSDimitry Andric             El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2085f757f3fSDimitry Andric             El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2095f757f3fSDimitry Andric             El.Stream});
2105f757f3fSDimitry Andric 
2115f757f3fSDimitry Andric       for (auto El : P.Info->SigOutputElements)
2125f757f3fSDimitry Andric         PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{
2135f757f3fSDimitry Andric             El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2145f757f3fSDimitry Andric             El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2155f757f3fSDimitry Andric             El.Stream});
2165f757f3fSDimitry Andric 
2175f757f3fSDimitry Andric       for (auto El : P.Info->SigPatchOrPrimElements)
2185f757f3fSDimitry Andric         PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{
2195f757f3fSDimitry Andric             El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2205f757f3fSDimitry Andric             El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2215f757f3fSDimitry Andric             El.Stream});
2225f757f3fSDimitry Andric 
2235f757f3fSDimitry Andric       static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
2245f757f3fSDimitry Andric       for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
2255f757f3fSDimitry Andric         PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
2265f757f3fSDimitry Andric                                         P.Info->OutputVectorMasks[I].begin(),
2275f757f3fSDimitry Andric                                         P.Info->OutputVectorMasks[I].end());
2285f757f3fSDimitry Andric         PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
2295f757f3fSDimitry Andric                                      P.Info->InputOutputMap[I].begin(),
2305f757f3fSDimitry Andric                                      P.Info->InputOutputMap[I].end());
2315f757f3fSDimitry Andric       }
2325f757f3fSDimitry Andric 
2335f757f3fSDimitry Andric       PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),
2345f757f3fSDimitry Andric                                   P.Info->PatchOrPrimMasks.begin(),
2355f757f3fSDimitry Andric                                   P.Info->PatchOrPrimMasks.end());
2365f757f3fSDimitry Andric       PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),
2375f757f3fSDimitry Andric                                P.Info->InputPatchMap.begin(),
2385f757f3fSDimitry Andric                                P.Info->InputPatchMap.end());
2395f757f3fSDimitry Andric       PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),
2405f757f3fSDimitry Andric                                 P.Info->PatchOutputMap.begin(),
2415f757f3fSDimitry Andric                                 P.Info->PatchOutputMap.end());
2425f757f3fSDimitry Andric 
2435f757f3fSDimitry Andric       PSV.finalize(static_cast<Triple::EnvironmentType>(
24406c3fb27SDimitry Andric           Triple::Pixel + P.Info->Info.ShaderStage));
24506c3fb27SDimitry Andric       PSV.write(OS, P.Info->Version);
24606c3fb27SDimitry Andric       break;
24706c3fb27SDimitry Andric     }
2485f757f3fSDimitry Andric     case dxbc::PartType::ISG1:
2495f757f3fSDimitry Andric     case dxbc::PartType::OSG1:
2505f757f3fSDimitry Andric     case dxbc::PartType::PSG1: {
2515f757f3fSDimitry Andric       mcdxbc::Signature Sig;
2525f757f3fSDimitry Andric       if (P.Signature.has_value()) {
2535f757f3fSDimitry Andric         for (const auto &Param : P.Signature->Parameters) {
2545f757f3fSDimitry Andric           Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
2555f757f3fSDimitry Andric                        Param.CompType, Param.Register, Param.Mask,
2565f757f3fSDimitry Andric                        Param.ExclusiveMask, Param.MinPrecision);
2575f757f3fSDimitry Andric         }
2585f757f3fSDimitry Andric       }
2595f757f3fSDimitry Andric       Sig.write(OS);
2605f757f3fSDimitry Andric       break;
2615f757f3fSDimitry Andric     }
262bdd1243dSDimitry Andric     case dxbc::PartType::Unknown:
263bdd1243dSDimitry Andric       break; // Skip any handling for unrecognized parts.
264bdd1243dSDimitry Andric     }
265bdd1243dSDimitry Andric     uint64_t BytesWritten = OS.tell() - DataStart;
266bdd1243dSDimitry Andric     RollingOffset += BytesWritten;
267bdd1243dSDimitry Andric     if (BytesWritten < PartSize)
268bdd1243dSDimitry Andric       OS.write_zeros(PartSize - BytesWritten);
269bdd1243dSDimitry Andric     RollingOffset += PartSize;
27081ad6265SDimitry Andric   }
27181ad6265SDimitry Andric }
27281ad6265SDimitry Andric 
27381ad6265SDimitry Andric Error DXContainerWriter::write(raw_ostream &OS) {
27481ad6265SDimitry Andric   if (Error Err = computePartOffsets())
27581ad6265SDimitry Andric     return Err;
27681ad6265SDimitry Andric   writeHeader(OS);
27781ad6265SDimitry Andric   writeParts(OS);
27881ad6265SDimitry Andric   return Error::success();
27981ad6265SDimitry Andric }
28081ad6265SDimitry Andric 
28181ad6265SDimitry Andric namespace llvm {
28281ad6265SDimitry Andric namespace yaml {
28381ad6265SDimitry Andric 
28481ad6265SDimitry Andric bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
28581ad6265SDimitry Andric                       ErrorHandler EH) {
28681ad6265SDimitry Andric   DXContainerWriter Writer(Doc);
28781ad6265SDimitry Andric   if (Error Err = Writer.write(Out)) {
28881ad6265SDimitry Andric     handleAllErrors(std::move(Err),
28981ad6265SDimitry Andric                     [&](const ErrorInfoBase &Err) { EH(Err.message()); });
29081ad6265SDimitry Andric     return false;
29181ad6265SDimitry Andric   }
29281ad6265SDimitry Andric   return true;
29381ad6265SDimitry Andric }
29481ad6265SDimitry Andric 
29581ad6265SDimitry Andric } // namespace yaml
29681ad6265SDimitry Andric } // namespace llvm
297