Path: blob/main/contrib/llvm-project/llvm/lib/ObjectYAML/DXContainerEmitter.cpp
35234 views
//===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// Binary emitter for yaml to DXContainer binary10///11//===----------------------------------------------------------------------===//1213#include "llvm/BinaryFormat/DXContainer.h"14#include "llvm/MC/DXContainerPSVInfo.h"15#include "llvm/ObjectYAML/ObjectYAML.h"16#include "llvm/ObjectYAML/yaml2obj.h"17#include "llvm/Support/Errc.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/raw_ostream.h"2021using namespace llvm;2223namespace {24class DXContainerWriter {25public:26DXContainerWriter(DXContainerYAML::Object &ObjectFile)27: ObjectFile(ObjectFile) {}2829Error write(raw_ostream &OS);3031private:32DXContainerYAML::Object &ObjectFile;3334Error computePartOffsets();35Error validatePartOffsets();36Error validateSize(uint32_t Computed);3738void writeHeader(raw_ostream &OS);39void writeParts(raw_ostream &OS);40};41} // namespace4243Error DXContainerWriter::validateSize(uint32_t Computed) {44if (!ObjectFile.Header.FileSize)45ObjectFile.Header.FileSize = Computed;46else if (*ObjectFile.Header.FileSize < Computed)47return createStringError(errc::result_out_of_range,48"File size specified is too small.");49return Error::success();50}5152Error DXContainerWriter::validatePartOffsets() {53if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())54return createStringError(55errc::invalid_argument,56"Mismatch between number of parts and part offsets.");57uint32_t RollingOffset =58sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));59for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {60if (RollingOffset > std::get<1>(I))61return createStringError(errc::invalid_argument,62"Offset mismatch, not enough space for data.");63RollingOffset =64std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;65}66if (Error Err = validateSize(RollingOffset))67return Err;6869return Error::success();70}7172Error DXContainerWriter::computePartOffsets() {73if (ObjectFile.Header.PartOffsets)74return validatePartOffsets();75uint32_t RollingOffset =76sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));77ObjectFile.Header.PartOffsets = std::vector<uint32_t>();78for (const auto &Part : ObjectFile.Parts) {79ObjectFile.Header.PartOffsets->push_back(RollingOffset);80RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;81}82if (Error Err = validateSize(RollingOffset))83return Err;8485return Error::success();86}8788void DXContainerWriter::writeHeader(raw_ostream &OS) {89dxbc::Header Header;90memcpy(Header.Magic, "DXBC", 4);91memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);92Header.Version.Major = ObjectFile.Header.Version.Major;93Header.Version.Minor = ObjectFile.Header.Version.Minor;94Header.FileSize = *ObjectFile.Header.FileSize;95Header.PartCount = ObjectFile.Parts.size();96if (sys::IsBigEndianHost)97Header.swapBytes();98OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));99SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),100ObjectFile.Header.PartOffsets->end());101if (sys::IsBigEndianHost)102for (auto &O : Offsets)103sys::swapByteOrder(O);104OS.write(reinterpret_cast<char *>(Offsets.data()),105Offsets.size() * sizeof(uint32_t));106}107108void DXContainerWriter::writeParts(raw_ostream &OS) {109uint32_t RollingOffset =110sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));111for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {112if (RollingOffset < std::get<1>(I)) {113uint32_t PadBytes = std::get<1>(I) - RollingOffset;114OS.write_zeros(PadBytes);115}116DXContainerYAML::Part P = std::get<0>(I);117RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);118uint32_t PartSize = P.Size;119120OS.write(P.Name.c_str(), 4);121if (sys::IsBigEndianHost)122sys::swapByteOrder(P.Size);123OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));124125dxbc::PartType PT = dxbc::parsePartType(P.Name);126127uint64_t DataStart = OS.tell();128switch (PT) {129case dxbc::PartType::DXIL: {130if (!P.Program)131continue;132dxbc::ProgramHeader Header;133Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,134P.Program->MinorVersion);135Header.Unused = 0;136Header.ShaderKind = P.Program->ShaderKind;137memcpy(Header.Bitcode.Magic, "DXIL", 4);138Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;139Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;140Header.Bitcode.Unused = 0;141142// Compute the optional fields if needed...143if (P.Program->DXILOffset)144Header.Bitcode.Offset = *P.Program->DXILOffset;145else146Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);147148if (P.Program->DXILSize)149Header.Bitcode.Size = *P.Program->DXILSize;150else151Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;152153if (P.Program->Size)154Header.Size = *P.Program->Size;155else156Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;157158uint32_t BitcodeOffset = Header.Bitcode.Offset;159if (sys::IsBigEndianHost)160Header.swapBytes();161OS.write(reinterpret_cast<const char *>(&Header),162sizeof(dxbc::ProgramHeader));163if (P.Program->DXIL) {164if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {165uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);166OS.write_zeros(PadBytes);167}168OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),169P.Program->DXIL->size());170}171break;172}173case dxbc::PartType::SFI0: {174// If we don't have any flags we can continue here and the data will be175// zeroed out.176if (!P.Flags.has_value())177continue;178uint64_t Flags = P.Flags->getEncodedFlags();179if (sys::IsBigEndianHost)180sys::swapByteOrder(Flags);181OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));182break;183}184case dxbc::PartType::HASH: {185if (!P.Hash.has_value())186continue;187dxbc::ShaderHash Hash = {0, {0}};188if (P.Hash->IncludesSource)189Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);190memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);191if (sys::IsBigEndianHost)192Hash.swapBytes();193OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));194break;195}196case dxbc::PartType::PSV0: {197if (!P.Info.has_value())198continue;199mcdxbc::PSVRuntimeInfo PSV;200memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));201PSV.Resources = P.Info->Resources;202PSV.EntryName = P.Info->EntryName;203204for (auto El : P.Info->SigInputElements)205PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{206El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,207El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,208El.Stream});209210for (auto El : P.Info->SigOutputElements)211PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{212El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,213El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,214El.Stream});215216for (auto El : P.Info->SigPatchOrPrimElements)217PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{218El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,219El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,220El.Stream});221222static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());223for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {224PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),225P.Info->OutputVectorMasks[I].begin(),226P.Info->OutputVectorMasks[I].end());227PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),228P.Info->InputOutputMap[I].begin(),229P.Info->InputOutputMap[I].end());230}231232PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),233P.Info->PatchOrPrimMasks.begin(),234P.Info->PatchOrPrimMasks.end());235PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),236P.Info->InputPatchMap.begin(),237P.Info->InputPatchMap.end());238PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),239P.Info->PatchOutputMap.begin(),240P.Info->PatchOutputMap.end());241242PSV.finalize(static_cast<Triple::EnvironmentType>(243Triple::Pixel + P.Info->Info.ShaderStage));244PSV.write(OS, P.Info->Version);245break;246}247case dxbc::PartType::ISG1:248case dxbc::PartType::OSG1:249case dxbc::PartType::PSG1: {250mcdxbc::Signature Sig;251if (P.Signature.has_value()) {252for (const auto &Param : P.Signature->Parameters) {253Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,254Param.CompType, Param.Register, Param.Mask,255Param.ExclusiveMask, Param.MinPrecision);256}257}258Sig.write(OS);259break;260}261case dxbc::PartType::Unknown:262break; // Skip any handling for unrecognized parts.263}264uint64_t BytesWritten = OS.tell() - DataStart;265RollingOffset += BytesWritten;266if (BytesWritten < PartSize)267OS.write_zeros(PartSize - BytesWritten);268RollingOffset += PartSize;269}270}271272Error DXContainerWriter::write(raw_ostream &OS) {273if (Error Err = computePartOffsets())274return Err;275writeHeader(OS);276writeParts(OS);277return Error::success();278}279280namespace llvm {281namespace yaml {282283bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,284ErrorHandler EH) {285DXContainerWriter Writer(Doc);286if (Error Err = Writer.write(Out)) {287handleAllErrors(std::move(Err),288[&](const ErrorInfoBase &Err) { EH(Err.message()); });289return false;290}291return true;292}293294} // namespace yaml295} // namespace llvm296297298