| //===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// Binary emitter for yaml to DXContainer binary | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/ADT/Sequence.h" | |
| #include "llvm/BinaryFormat/DXContainer.h" | |
| #include "llvm/MC/DXContainerInfo.h" | |
| #include "llvm/MC/DXContainerPSVInfo.h" | |
| #include "llvm/MC/DXContainerRootSignature.h" | |
| #include "llvm/ObjectYAML/DXContainerYAML.h" | |
| #include "llvm/ObjectYAML/yaml2obj.h" | |
| #include "llvm/Support/Errc.h" | |
| #include "llvm/Support/Error.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| namespace { | |
| class DXContainerWriter { | |
| public: | |
| DXContainerWriter(DXContainerYAML::Object &ObjectFile) | |
| : ObjectFile(ObjectFile) {} | |
| Error write(raw_ostream &OS); | |
| private: | |
| DXContainerYAML::Object &ObjectFile; | |
| Error computePartOffsets(); | |
| Error validatePartOffsets(); | |
| Error validateSize(uint32_t Computed); | |
| void writeHeader(raw_ostream &OS); | |
| Error writeParts(raw_ostream &OS); | |
| }; | |
| } // namespace | |
| Error DXContainerWriter::validateSize(uint32_t Computed) { | |
| if (!ObjectFile.Header.FileSize) | |
| ObjectFile.Header.FileSize = Computed; | |
| else if (*ObjectFile.Header.FileSize < Computed) | |
| return createStringError(errc::result_out_of_range, | |
| "File size specified is too small."); | |
| return Error::success(); | |
| } | |
| Error DXContainerWriter::validatePartOffsets() { | |
| if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size()) | |
| return createStringError( | |
| errc::invalid_argument, | |
| "Mismatch between number of parts and part offsets."); | |
| uint32_t RollingOffset = | |
| sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t)); | |
| for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) { | |
| if (RollingOffset > std::get<1>(I)) | |
| return createStringError(errc::invalid_argument, | |
| "Offset mismatch, not enough space for data."); | |
| RollingOffset = | |
| std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size; | |
| } | |
| if (Error Err = validateSize(RollingOffset)) | |
| return Err; | |
| return Error::success(); | |
| } | |
| Error DXContainerWriter::computePartOffsets() { | |
| if (ObjectFile.Header.PartOffsets) | |
| return validatePartOffsets(); | |
| uint32_t RollingOffset = | |
| sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t)); | |
| ObjectFile.Header.PartOffsets = std::vector<uint32_t>(); | |
| for (const auto &Part : ObjectFile.Parts) { | |
| ObjectFile.Header.PartOffsets->push_back(RollingOffset); | |
| RollingOffset += sizeof(dxbc::PartHeader) + Part.Size; | |
| } | |
| if (Error Err = validateSize(RollingOffset)) | |
| return Err; | |
| return Error::success(); | |
| } | |
| void DXContainerWriter::writeHeader(raw_ostream &OS) { | |
| dxbc::Header Header; | |
| memcpy(Header.Magic, "DXBC", 4); | |
| memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16); | |
| Header.Version.Major = ObjectFile.Header.Version.Major; | |
| Header.Version.Minor = ObjectFile.Header.Version.Minor; | |
| Header.FileSize = *ObjectFile.Header.FileSize; | |
| Header.PartCount = ObjectFile.Parts.size(); | |
| if (sys::IsBigEndianHost) | |
| Header.swapBytes(); | |
| OS.write(reinterpret_cast<char *>(&Header), sizeof(Header)); | |
| SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(), | |
| ObjectFile.Header.PartOffsets->end()); | |
| if (sys::IsBigEndianHost) | |
| for (auto &O : Offsets) | |
| sys::swapByteOrder(O); | |
| OS.write(reinterpret_cast<char *>(Offsets.data()), | |
| Offsets.size() * sizeof(uint32_t)); | |
| } | |
| // TODO use it for VERS too | |
| template <typename T> | |
| static void assign_if(T &Dst, const std::optional<T> &Src) { | |
| if (Src) | |
| Dst = *Src; | |
| } | |
| static void | |
| assignSectionHeader(dxbc::SourceInfo::SectionHeader &Dst, | |
| const DXContainerYAML::SourceInfo::Section &Src) { | |
| assign_if(Dst.AlignedSizeInBytes, Src.GenericHeader.AlignedSizeInBytes); | |
| assign_if(Dst.Flags, Src.GenericHeader.Flags); | |
| assign_if(Dst.Type, Src.GenericHeader.Type); | |
| } | |
| Error DXContainerWriter::writeParts(raw_ostream &OS) { | |
| uint32_t RollingOffset = | |
| sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t)); | |
| for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) { | |
| if (RollingOffset < std::get<1>(I)) { | |
| uint32_t PadBytes = std::get<1>(I) - RollingOffset; | |
| OS.write_zeros(PadBytes); | |
| } | |
| DXContainerYAML::Part P = std::get<0>(I); | |
| RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader); | |
| uint32_t PartSize = P.Size; | |
| OS.write(P.Name.c_str(), 4); | |
| if (sys::IsBigEndianHost) | |
| sys::swapByteOrder(P.Size); | |
| OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t)); | |
| dxbc::PartType PT = dxbc::parsePartType(P.Name); | |
| uint64_t DataStart = OS.tell(); | |
| switch (PT) { | |
| case dxbc::PartType::DXIL: | |
| case dxbc::PartType::ILDB: { | |
| if (!P.Program) | |
| continue; | |
| dxbc::ProgramHeader Header; | |
| Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion, | |
| P.Program->MinorVersion); | |
| Header.Unused = 0; | |
| Header.ShaderKind = P.Program->ShaderKind; | |
| memcpy(Header.Bitcode.Magic, "DXIL", 4); | |
| Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion; | |
| Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion; | |
| Header.Bitcode.Unused = 0; | |
| // Compute the optional fields if needed... | |
| if (P.Program->DXILOffset) | |
| Header.Bitcode.Offset = *P.Program->DXILOffset; | |
| else | |
| Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader); | |
| if (P.Program->DXILSize) | |
| Header.Bitcode.Size = *P.Program->DXILSize; | |
| else | |
| Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0; | |
| if (P.Program->Size) | |
| Header.Size = *P.Program->Size; | |
| else | |
| Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size; | |
| uint32_t BitcodeOffset = Header.Bitcode.Offset; | |
| if (sys::IsBigEndianHost) | |
| Header.swapBytes(); | |
| OS.write(reinterpret_cast<const char *>(&Header), | |
| sizeof(dxbc::ProgramHeader)); | |
| if (P.Program->DXIL) { | |
| if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) { | |
| uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader); | |
| OS.write_zeros(PadBytes); | |
| } | |
| OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()), | |
| P.Program->DXIL->size()); | |
| } | |
| break; | |
| } | |
| case dxbc::PartType::ILDN: { | |
| if (!P.DebugName) | |
| continue; | |
| mcdxbc::DebugName DebugName; | |
| DebugName.setFilename(P.DebugName->Filename); | |
| // Override default flags with value from YAML. | |
| if (P.DebugName->Flags) | |
| DebugName.Parameters.Flags = *P.DebugName->Flags; | |
| // Override computed filename length with value from YAML. | |
| if (P.DebugName->NameLength) | |
| DebugName.Parameters.NameLength = *P.DebugName->NameLength; | |
| DebugName.write(OS); | |
| break; | |
| } | |
| case dxbc::PartType::PRIV: { | |
| if (!P.PrivateData) | |
| continue; | |
| OS.write(reinterpret_cast<char *>(P.PrivateData->data()), | |
| P.PrivateData->size()); | |
| break; | |
| } | |
| case dxbc::PartType::SFI0: { | |
| // If we don't have any flags we can continue here and the data will be | |
| // zeroed out. | |
| if (!P.Flags.has_value()) | |
| continue; | |
| uint64_t Flags = P.Flags->getEncodedFlags(); | |
| if (sys::IsBigEndianHost) | |
| sys::swapByteOrder(Flags); | |
| OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t)); | |
| break; | |
| } | |
| case dxbc::PartType::HASH: { | |
| if (!P.Hash.has_value()) | |
| continue; | |
| dxbc::ShaderHash Hash = {0, {0}}; | |
| if (P.Hash->IncludesSource) | |
| Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource); | |
| memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16); | |
| if (sys::IsBigEndianHost) | |
| Hash.swapBytes(); | |
| OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash)); | |
| break; | |
| } | |
| case dxbc::PartType::PSV0: { | |
| if (!P.Info.has_value()) | |
| continue; | |
| mcdxbc::PSVRuntimeInfo PSV; | |
| memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo)); | |
| PSV.Resources = P.Info->Resources; | |
| PSV.EntryName = P.Info->EntryName; | |
| for (auto El : P.Info->SigInputElements) | |
| PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{ | |
| El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol, | |
| El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask, | |
| El.Stream}); | |
| for (auto El : P.Info->SigOutputElements) | |
| PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{ | |
| El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol, | |
| El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask, | |
| El.Stream}); | |
| for (auto El : P.Info->SigPatchOrPrimElements) | |
| PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{ | |
| El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol, | |
| El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask, | |
| El.Stream}); | |
| static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size()); | |
| for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) { | |
| PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(), | |
| P.Info->OutputVectorMasks[I].begin(), | |
| P.Info->OutputVectorMasks[I].end()); | |
| PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(), | |
| P.Info->InputOutputMap[I].begin(), | |
| P.Info->InputOutputMap[I].end()); | |
| } | |
| PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(), | |
| P.Info->PatchOrPrimMasks.begin(), | |
| P.Info->PatchOrPrimMasks.end()); | |
| PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(), | |
| P.Info->InputPatchMap.begin(), | |
| P.Info->InputPatchMap.end()); | |
| PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(), | |
| P.Info->PatchOutputMap.begin(), | |
| P.Info->PatchOutputMap.end()); | |
| PSV.finalize(static_cast<Triple::EnvironmentType>( | |
| Triple::Pixel + P.Info->Info.ShaderStage), | |
| P.Info->Version); | |
| PSV.write(OS, P.Info->Version); | |
| break; | |
| } | |
| case dxbc::PartType::ISG1: | |
| case dxbc::PartType::OSG1: | |
| case dxbc::PartType::PSG1: { | |
| mcdxbc::Signature Sig; | |
| if (P.Signature.has_value()) { | |
| for (const auto &Param : P.Signature->Parameters) { | |
| Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue, | |
| Param.CompType, Param.Register, Param.Mask, | |
| Param.ExclusiveMask, Param.MinPrecision); | |
| } | |
| } | |
| Sig.write(OS); | |
| break; | |
| } | |
| case dxbc::PartType::Unknown: | |
| break; // Skip any handling for unrecognized parts. | |
| case dxbc::PartType::RTS0: { | |
| if (!P.RootSignature.has_value()) | |
| continue; | |
| mcdxbc::RootSignatureDesc RS; | |
| RS.Flags = P.RootSignature->getEncodedFlags(); | |
| RS.Version = P.RootSignature->Version; | |
| RS.NumStaticSamplers = P.RootSignature->NumStaticSamplers; | |
| for (DXContainerYAML::RootParameterLocationYaml &L : | |
| P.RootSignature->Parameters.Locations) { | |
| const dxbc::RootParameterType Type = L.Header.Type; | |
| const dxbc::ShaderVisibility Visibility = L.Header.Visibility; | |
| switch (Type) { | |
| case dxbc::RootParameterType::Constants32Bit: { | |
| const DXContainerYAML::RootConstantsYaml &ConstantYaml = | |
| P.RootSignature->Parameters.getOrInsertConstants(L); | |
| mcdxbc::RootConstants Constants; | |
| Constants.Num32BitValues = ConstantYaml.Num32BitValues; | |
| Constants.RegisterSpace = ConstantYaml.RegisterSpace; | |
| Constants.ShaderRegister = ConstantYaml.ShaderRegister; | |
| RS.ParametersContainer.addParameter(Type, Visibility, Constants); | |
| break; | |
| } | |
| case dxbc::RootParameterType::CBV: | |
| case dxbc::RootParameterType::SRV: | |
| case dxbc::RootParameterType::UAV: { | |
| const DXContainerYAML::RootDescriptorYaml &DescriptorYaml = | |
| P.RootSignature->Parameters.getOrInsertDescriptor(L); | |
| mcdxbc::RootDescriptor Descriptor; | |
| Descriptor.RegisterSpace = DescriptorYaml.RegisterSpace; | |
| Descriptor.ShaderRegister = DescriptorYaml.ShaderRegister; | |
| if (RS.Version > 1) | |
| Descriptor.Flags = DescriptorYaml.getEncodedFlags(); | |
| RS.ParametersContainer.addParameter(Type, Visibility, Descriptor); | |
| break; | |
| } | |
| case dxbc::RootParameterType::DescriptorTable: { | |
| const DXContainerYAML::DescriptorTableYaml &TableYaml = | |
| P.RootSignature->Parameters.getOrInsertTable(L); | |
| mcdxbc::DescriptorTable Table; | |
| for (const auto &R : TableYaml.Ranges) { | |
| mcdxbc::DescriptorRange Range; | |
| Range.RangeType = R.RangeType; | |
| Range.NumDescriptors = R.NumDescriptors; | |
| Range.BaseShaderRegister = R.BaseShaderRegister; | |
| Range.RegisterSpace = R.RegisterSpace; | |
| Range.OffsetInDescriptorsFromTableStart = | |
| R.OffsetInDescriptorsFromTableStart; | |
| if (RS.Version > 1) | |
| Range.Flags = R.getEncodedFlags(); | |
| Table.Ranges.push_back(Range); | |
| } | |
| RS.ParametersContainer.addParameter(Type, Visibility, Table); | |
| break; | |
| } | |
| } | |
| } | |
| for (const auto &Param : P.RootSignature->samplers()) { | |
| mcdxbc::StaticSampler NewSampler; | |
| NewSampler.Filter = Param.Filter; | |
| NewSampler.AddressU = Param.AddressU; | |
| NewSampler.AddressV = Param.AddressV; | |
| NewSampler.AddressW = Param.AddressW; | |
| NewSampler.MipLODBias = Param.MipLODBias; | |
| NewSampler.MaxAnisotropy = Param.MaxAnisotropy; | |
| NewSampler.ComparisonFunc = Param.ComparisonFunc; | |
| NewSampler.BorderColor = Param.BorderColor; | |
| NewSampler.MinLOD = Param.MinLOD; | |
| NewSampler.MaxLOD = Param.MaxLOD; | |
| NewSampler.ShaderRegister = Param.ShaderRegister; | |
| NewSampler.RegisterSpace = Param.RegisterSpace; | |
| NewSampler.ShaderVisibility = Param.ShaderVisibility; | |
| if (RS.Version > 2) | |
| NewSampler.Flags = Param.getEncodedFlags(); | |
| RS.StaticSamplers.push_back(NewSampler); | |
| } | |
| // Handling of offsets | |
| RS.RootParameterOffset = RS.computeRootParametersOffset(); | |
| if (P.RootSignature->RootParametersOffset && | |
| P.RootSignature->RootParametersOffset.value() != | |
| RS.RootParameterOffset) { | |
| return createStringError( | |
| errc::invalid_argument, | |
| "Specified RootParametersOffset does not match required value: %d.", | |
| RS.RootParameterOffset); | |
| } | |
| RS.StaticSamplersOffset = RS.computeStaticSamplersOffset(); | |
| if (P.RootSignature->StaticSamplersOffset && | |
| P.RootSignature->StaticSamplersOffset.value() != | |
| RS.StaticSamplersOffset) { | |
| return createStringError( | |
| errc::invalid_argument, | |
| "Specified StaticSamplersOffset does not match computed value: %d.", | |
| RS.StaticSamplersOffset); | |
| } | |
| RS.write(OS); | |
| break; | |
| } | |
| case dxbc::PartType::SRCI: { | |
| if (!P.SourceInfo.has_value()) | |
| continue; | |
| mcdxbc::SourceInfoBuilder SourceInfo; | |
| auto &ContentsYAML = P.SourceInfo->Contents; | |
| SourceInfo.setCompressionType(ContentsYAML.Parameters.Type); | |
| if (ContentsYAML.Entries.size() != P.SourceInfo->Names.Entries.size()) | |
| return createStringError( | |
| errc::invalid_argument, | |
| "number of entries in Names section must match number of entries " | |
| "in Contents section in SRCI part"); | |
| for (size_t I : llvm::seq(ContentsYAML.Entries.size())) | |
| SourceInfo.addFile(P.SourceInfo->Names.Entries[I].FileName, | |
| ContentsYAML.Entries[I].FileContent); | |
| for (auto &ArgEntry : P.SourceInfo->Args.Args) | |
| SourceInfo.addArg(ArgEntry.first, ArgEntry.second); | |
| SourceInfo.computeEntries(); | |
| // If entries field values are provided in YAML, override them in | |
| // SourceInfo. | |
| for (size_t I : llvm::seq(ContentsYAML.Entries.size())) { | |
| auto &ContentEntryYAML = ContentsYAML.Entries[I]; | |
| auto &ContentEntry = SourceInfo.BaseData.Contents.Entries[I]; | |
| assign_if(ContentEntry.Parameters.AlignedSizeInBytes, | |
| ContentEntryYAML.AlignedSizeInBytes); | |
| assign_if(ContentEntry.Parameters.Flags, ContentEntryYAML.Flags); | |
| assign_if(ContentEntry.Parameters.ContentSizeInBytes, | |
| ContentEntryYAML.ContentSizeInBytes); | |
| auto &NameEntryYAML = P.SourceInfo->Names.Entries[I]; | |
| auto &NameEntry = SourceInfo.BaseData.Names.Entries[I]; | |
| assign_if(NameEntry.Parameters.AlignedSizeInBytes, | |
| NameEntryYAML.AlignedSizeInBytes); | |
| assign_if(NameEntry.Parameters.Flags, NameEntryYAML.Flags); | |
| assign_if(NameEntry.Parameters.NameSizeInBytes, | |
| NameEntryYAML.NameSizeInBytes); | |
| assign_if(NameEntry.Parameters.ContentSizeInBytes, | |
| NameEntryYAML.ContentSizeInBytes); | |
| } | |
| SourceInfo.finalize(); | |
| // If section header field values are provided in YAML, override them in | |
| // SourceInfo. | |
| auto &Contents = SourceInfo.BaseData.Contents; | |
| assignSectionHeader(Contents.GenericHeader, ContentsYAML); | |
| assign_if(Contents.Parameters.AlignedSizeInBytes, | |
| ContentsYAML.Parameters.AlignedSizeInBytes); | |
| assign_if(Contents.Parameters.Flags, ContentsYAML.Parameters.Flags); | |
| assign_if(Contents.Parameters.EntriesSizeInBytes, | |
| ContentsYAML.Parameters.EntriesSizeInBytes); | |
| assign_if(Contents.Parameters.UncompressedEntriesSizeInBytes, | |
| ContentsYAML.Parameters.UncompressedEntriesSizeInBytes); | |
| if (ContentsYAML.Parameters.Count && | |
| ContentsYAML.Parameters.Count != Contents.Parameters.Count) | |
| return createStringError( | |
| errc::invalid_argument, | |
| "the value of Count field in Contents header must match the number " | |
| "of entries in Contents section"); | |
| auto &NamesYAML = P.SourceInfo->Names; | |
| auto &Names = SourceInfo.BaseData.Names; | |
| assignSectionHeader(Names.GenericHeader, NamesYAML); | |
| assign_if(Names.Parameters.Flags, NamesYAML.Parameters.Flags); | |
| assign_if(Names.Parameters.EntriesSizeInBytes, | |
| NamesYAML.Parameters.EntriesSizeInBytes); | |
| if (NamesYAML.Parameters.Count && | |
| NamesYAML.Parameters.Count != Names.Parameters.Count) | |
| return createStringError( | |
| errc::invalid_argument, | |
| "the value of Count field in Names header must match the number of " | |
| "entries in Names section"); | |
| auto &ArgsYAML = P.SourceInfo->Args; | |
| auto &Args = SourceInfo.BaseData.Args; | |
| assignSectionHeader(Args.GenericHeader, ArgsYAML); | |
| assign_if(Args.Parameters.Flags, ArgsYAML.Parameters.Flags); | |
| assign_if(Args.Parameters.SizeInBytes, ArgsYAML.Parameters.SizeInBytes); | |
| if (ArgsYAML.Parameters.Count && | |
| ArgsYAML.Parameters.Count != Args.Parameters.Count) | |
| return createStringError(errc::invalid_argument, | |
| "the value of Count field in Args header must " | |
| "match the number of entries in Args section"); | |
| assign_if(SourceInfo.BaseData.Parameters.AlignedSizeInBytes, | |
| P.SourceInfo->Parameters.AlignedSizeInBytes); | |
| assign_if(SourceInfo.BaseData.Parameters.Flags, | |
| P.SourceInfo->Parameters.Flags); | |
| assign_if(SourceInfo.BaseData.Parameters.SectionCount, | |
| P.SourceInfo->Parameters.SectionCount); | |
| SourceInfo.write(OS); | |
| break; | |
| } | |
| case dxbc::PartType::VERS: { | |
| if (!P.CompilerVersion) | |
| continue; | |
| mcdxbc::CompilerVersion CompilerVersion; | |
| CompilerVersion.Parameters.Major = | |
| P.CompilerVersion->Major.value_or(CompilerVersion.Parameters.Major); | |
| CompilerVersion.Parameters.Minor = | |
| P.CompilerVersion->Minor.value_or(CompilerVersion.Parameters.Minor); | |
| if (P.CompilerVersion->IsDebugBuild || P.CompilerVersion->IsValidated) | |
| CompilerVersion.Parameters.Flags = dxbc::CompilerVersionFlags::Default; | |
| if (P.CompilerVersion->IsDebugBuild.value_or(false)) | |
| CompilerVersion.Parameters.Flags |= dxbc::CompilerVersionFlags::Debug; | |
| if (P.CompilerVersion->IsValidated.value_or(false)) | |
| CompilerVersion.Parameters.Flags |= | |
| dxbc::CompilerVersionFlags::Internal; | |
| CompilerVersion.Parameters.CommitCount = | |
| P.CompilerVersion->CommitCount.value_or( | |
| CompilerVersion.Parameters.CommitCount); | |
| if (P.CompilerVersion->CommitSha) | |
| CompilerVersion.setCommitSha(*P.CompilerVersion->CommitSha); | |
| if (P.CompilerVersion->CustomVersionString) | |
| CompilerVersion.setVersionString( | |
| *P.CompilerVersion->CustomVersionString); | |
| CompilerVersion.Parameters.ContentSizeInBytes = | |
| P.CompilerVersion->ContentSizeInBytes.value_or( | |
| CompilerVersion.Parameters.ContentSizeInBytes); | |
| CompilerVersion.write(OS); | |
| break; | |
| } | |
| } | |
| uint64_t BytesWritten = OS.tell() - DataStart; | |
| RollingOffset += BytesWritten; | |
| if (BytesWritten < PartSize) | |
| OS.write_zeros(PartSize - BytesWritten); | |
| RollingOffset += PartSize; | |
| } | |
| return Error::success(); | |
| } | |
| Error DXContainerWriter::write(raw_ostream &OS) { | |
| if (Error Err = computePartOffsets()) | |
| return Err; | |
| writeHeader(OS); | |
| return writeParts(OS); | |
| } | |
| namespace llvm { | |
| namespace yaml { | |
| bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out, | |
| ErrorHandler EH) { | |
| DXContainerWriter Writer(Doc); | |
| if (Error Err = Writer.write(Out)) { | |
| handleAllErrors(std::move(Err), | |
| [&](const ErrorInfoBase &Err) { EH(Err.message()); }); | |
| return false; | |
| } | |
| return true; | |
| } | |
| } // namespace yaml | |
| } // namespace llvm |