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