|  | //===- DXContainerYAML.cpp - DXContainer YAMLIO implementation ------------===// | 
|  | // | 
|  | // 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines classes for handling the YAML representation of | 
|  | // DXContainerYAML. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/ObjectYAML/DXContainerYAML.h" | 
|  | #include "llvm/ADT/ScopeExit.h" | 
|  | #include "llvm/BinaryFormat/DXContainer.h" | 
|  | #include "llvm/Support/ScopedPrinter.h" | 
|  |  | 
|  | namespace llvm { | 
|  |  | 
|  | // This assert is duplicated here to leave a breadcrumb of the places that need | 
|  | // to be updated if flags grow past 64-bits. | 
|  | static_assert((uint64_t)dxbc::FeatureFlags::NextUnusedBit <= 1ull << 63, | 
|  | "Shader flag bits exceed enum size."); | 
|  |  | 
|  | DXContainerYAML::ShaderFeatureFlags::ShaderFeatureFlags(uint64_t FlagData) { | 
|  | #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str)                      \ | 
|  | Val = (FlagData & (uint64_t)dxbc::FeatureFlags::Val) > 0; | 
|  | #include "llvm/BinaryFormat/DXContainerConstants.def" | 
|  | } | 
|  |  | 
|  | uint64_t DXContainerYAML::ShaderFeatureFlags::getEncodedFlags() { | 
|  | uint64_t Flag = 0; | 
|  | #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str)                      \ | 
|  | if (Val)                                                                     \ | 
|  | Flag |= (uint64_t)dxbc::FeatureFlags::Val; | 
|  | #include "llvm/BinaryFormat/DXContainerConstants.def" | 
|  | return Flag; | 
|  | } | 
|  |  | 
|  | DXContainerYAML::ShaderHash::ShaderHash(const dxbc::ShaderHash &Data) | 
|  | : IncludesSource((Data.Flags & static_cast<uint32_t>( | 
|  | dxbc::HashFlags::IncludesSource)) != 0), | 
|  | Digest(16, 0) { | 
|  | memcpy(Digest.data(), &Data.Digest[0], 16); | 
|  | } | 
|  |  | 
|  | DXContainerYAML::PSVInfo::PSVInfo() : Version(0) { | 
|  | memset(&Info, 0, sizeof(Info)); | 
|  | } | 
|  |  | 
|  | DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v0::RuntimeInfo *P, | 
|  | uint16_t Stage) | 
|  | : Version(0) { | 
|  | memset(&Info, 0, sizeof(Info)); | 
|  | memcpy(&Info, P, sizeof(dxbc::PSV::v0::RuntimeInfo)); | 
|  |  | 
|  | assert(Stage < std::numeric_limits<uint8_t>::max() && | 
|  | "Stage should be a very small number"); | 
|  | // We need to bring the stage in separately since it isn't part of the v1 data | 
|  | // structure. | 
|  | Info.ShaderStage = static_cast<uint8_t>(Stage); | 
|  | } | 
|  |  | 
|  | DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v1::RuntimeInfo *P) | 
|  | : Version(1) { | 
|  | memset(&Info, 0, sizeof(Info)); | 
|  | memcpy(&Info, P, sizeof(dxbc::PSV::v1::RuntimeInfo)); | 
|  | } | 
|  |  | 
|  | DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v2::RuntimeInfo *P) | 
|  | : Version(2) { | 
|  | memset(&Info, 0, sizeof(Info)); | 
|  | memcpy(&Info, P, sizeof(dxbc::PSV::v2::RuntimeInfo)); | 
|  | } | 
|  |  | 
|  | DXContainerYAML::PSVInfo::PSVInfo(const dxbc::PSV::v3::RuntimeInfo *P, | 
|  | StringRef StringTable) | 
|  | : Version(3), | 
|  | EntryName(StringTable.substr(P->EntryNameOffset, | 
|  | StringTable.find('\0', P->EntryNameOffset) - | 
|  | P->EntryNameOffset)) { | 
|  | memset(&Info, 0, sizeof(Info)); | 
|  | memcpy(&Info, P, sizeof(dxbc::PSV::v3::RuntimeInfo)); | 
|  | } | 
|  |  | 
|  | namespace yaml { | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::VersionTuple>::mapping( | 
|  | IO &IO, DXContainerYAML::VersionTuple &Version) { | 
|  | IO.mapRequired("Major", Version.Major); | 
|  | IO.mapRequired("Minor", Version.Minor); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::FileHeader>::mapping( | 
|  | IO &IO, DXContainerYAML::FileHeader &Header) { | 
|  | IO.mapRequired("Hash", Header.Hash); | 
|  | IO.mapRequired("Version", Header.Version); | 
|  | IO.mapOptional("FileSize", Header.FileSize); | 
|  | IO.mapRequired("PartCount", Header.PartCount); | 
|  | IO.mapOptional("PartOffsets", Header.PartOffsets); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::DXILProgram>::mapping( | 
|  | IO &IO, DXContainerYAML::DXILProgram &Program) { | 
|  | IO.mapRequired("MajorVersion", Program.MajorVersion); | 
|  | IO.mapRequired("MinorVersion", Program.MinorVersion); | 
|  | IO.mapRequired("ShaderKind", Program.ShaderKind); | 
|  | IO.mapOptional("Size", Program.Size); | 
|  | IO.mapRequired("DXILMajorVersion", Program.DXILMajorVersion); | 
|  | IO.mapRequired("DXILMinorVersion", Program.DXILMinorVersion); | 
|  | IO.mapOptional("DXILSize", Program.DXILSize); | 
|  | IO.mapOptional("DXIL", Program.DXIL); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::ShaderFeatureFlags>::mapping( | 
|  | IO &IO, DXContainerYAML::ShaderFeatureFlags &Flags) { | 
|  | #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str)                      \ | 
|  | IO.mapRequired(#Val, Flags.Val); | 
|  | #include "llvm/BinaryFormat/DXContainerConstants.def" | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::ShaderHash>::mapping( | 
|  | IO &IO, DXContainerYAML::ShaderHash &Hash) { | 
|  | IO.mapRequired("IncludesSource", Hash.IncludesSource); | 
|  | IO.mapRequired("Digest", Hash.Digest); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::PSVInfo>::mapping( | 
|  | IO &IO, DXContainerYAML::PSVInfo &PSV) { | 
|  | IO.mapRequired("Version", PSV.Version); | 
|  |  | 
|  | // Store the PSV version in the YAML context. | 
|  | void *OldContext = IO.getContext(); | 
|  | uint32_t Version = PSV.Version; | 
|  | IO.setContext(&Version); | 
|  |  | 
|  | // Restore the YAML context on function exit. | 
|  | auto RestoreContext = make_scope_exit([&]() { IO.setContext(OldContext); }); | 
|  |  | 
|  | // Shader stage is only included in binaries for v1 and later, but we always | 
|  | // include it since it simplifies parsing and file construction. | 
|  | IO.mapRequired("ShaderStage", PSV.Info.ShaderStage); | 
|  | PSV.mapInfoForVersion(IO); | 
|  |  | 
|  | IO.mapRequired("ResourceStride", PSV.ResourceStride); | 
|  | IO.mapRequired("Resources", PSV.Resources); | 
|  | if (PSV.Version == 0) | 
|  | return; | 
|  | IO.mapRequired("SigInputElements", PSV.SigInputElements); | 
|  | IO.mapRequired("SigOutputElements", PSV.SigOutputElements); | 
|  | IO.mapRequired("SigPatchOrPrimElements", PSV.SigPatchOrPrimElements); | 
|  |  | 
|  | Triple::EnvironmentType Stage = dxbc::getShaderStage(PSV.Info.ShaderStage); | 
|  | if (PSV.Info.UsesViewID) { | 
|  | MutableArrayRef<SmallVector<llvm::yaml::Hex32>> MutableOutMasks( | 
|  | PSV.OutputVectorMasks); | 
|  | IO.mapRequired("OutputVectorMasks", MutableOutMasks); | 
|  | if (Stage == Triple::EnvironmentType::Hull) | 
|  | IO.mapRequired("PatchOrPrimMasks", PSV.PatchOrPrimMasks); | 
|  | } | 
|  | MutableArrayRef<SmallVector<llvm::yaml::Hex32>> MutableIOMap( | 
|  | PSV.InputOutputMap); | 
|  | IO.mapRequired("InputOutputMap", MutableIOMap); | 
|  |  | 
|  | if (Stage == Triple::EnvironmentType::Hull) | 
|  | IO.mapRequired("InputPatchMap", PSV.InputPatchMap); | 
|  |  | 
|  | if (Stage == Triple::EnvironmentType::Domain) | 
|  | IO.mapRequired("PatchOutputMap", PSV.PatchOutputMap); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::SignatureParameter>::mapping( | 
|  | IO &IO, DXContainerYAML::SignatureParameter &S) { | 
|  | IO.mapRequired("Stream", S.Stream); | 
|  | IO.mapRequired("Name", S.Name); | 
|  | IO.mapRequired("Index", S.Index); | 
|  | IO.mapRequired("SystemValue", S.SystemValue); | 
|  | IO.mapRequired("CompType", S.CompType); | 
|  | IO.mapRequired("Register", S.Register); | 
|  | IO.mapRequired("Mask", S.Mask); | 
|  | IO.mapRequired("ExclusiveMask", S.ExclusiveMask); | 
|  | IO.mapRequired("MinPrecision", S.MinPrecision); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::Signature>::mapping( | 
|  | IO &IO, DXContainerYAML::Signature &S) { | 
|  | IO.mapRequired("Parameters", S.Parameters); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::Part>::mapping(IO &IO, | 
|  | DXContainerYAML::Part &P) { | 
|  | IO.mapRequired("Name", P.Name); | 
|  | IO.mapRequired("Size", P.Size); | 
|  | IO.mapOptional("Program", P.Program); | 
|  | IO.mapOptional("Flags", P.Flags); | 
|  | IO.mapOptional("Hash", P.Hash); | 
|  | IO.mapOptional("PSVInfo", P.Info); | 
|  | IO.mapOptional("Signature", P.Signature); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::Object>::mapping( | 
|  | IO &IO, DXContainerYAML::Object &Obj) { | 
|  | IO.mapTag("!dxcontainer", true); | 
|  | IO.mapRequired("Header", Obj.Header); | 
|  | IO.mapRequired("Parts", Obj.Parts); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::ResourceFlags>::mapping( | 
|  | IO &IO, DXContainerYAML::ResourceFlags &Flags) { | 
|  | #define RESOURCE_FLAG(FlagIndex, Enum) IO.mapRequired(#Enum, Flags.Bits.Enum); | 
|  | #include "llvm/BinaryFormat/DXContainerConstants.def" | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::ResourceBindInfo>::mapping( | 
|  | IO &IO, DXContainerYAML::ResourceBindInfo &Res) { | 
|  | IO.mapRequired("Type", Res.Type); | 
|  | IO.mapRequired("Space", Res.Space); | 
|  | IO.mapRequired("LowerBound", Res.LowerBound); | 
|  | IO.mapRequired("UpperBound", Res.UpperBound); | 
|  |  | 
|  | const uint32_t *PSVVersion = static_cast<uint32_t *>(IO.getContext()); | 
|  | if (*PSVVersion < 2) | 
|  | return; | 
|  |  | 
|  | IO.mapRequired("Kind", Res.Kind); | 
|  | IO.mapRequired("Flags", Res.Flags); | 
|  | } | 
|  |  | 
|  | void MappingTraits<DXContainerYAML::SignatureElement>::mapping( | 
|  | IO &IO, DXContainerYAML::SignatureElement &El) { | 
|  | IO.mapRequired("Name", El.Name); | 
|  | IO.mapRequired("Indices", El.Indices); | 
|  | IO.mapRequired("StartRow", El.StartRow); | 
|  | IO.mapRequired("Cols", El.Cols); | 
|  | IO.mapRequired("StartCol", El.StartCol); | 
|  | IO.mapRequired("Allocated", El.Allocated); | 
|  | IO.mapRequired("Kind", El.Kind); | 
|  | IO.mapRequired("ComponentType", El.Type); | 
|  | IO.mapRequired("Interpolation", El.Mode); | 
|  | IO.mapRequired("DynamicMask", El.DynamicMask); | 
|  | IO.mapRequired("Stream", El.Stream); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::PSV::SemanticKind>::enumeration( | 
|  | IO &IO, dxbc::PSV::SemanticKind &Value) { | 
|  | for (const auto &E : dxbc::PSV::getSemanticKinds()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::PSV::ComponentType>::enumeration( | 
|  | IO &IO, dxbc::PSV::ComponentType &Value) { | 
|  | for (const auto &E : dxbc::PSV::getComponentTypes()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::PSV::InterpolationMode>::enumeration( | 
|  | IO &IO, dxbc::PSV::InterpolationMode &Value) { | 
|  | for (const auto &E : dxbc::PSV::getInterpolationModes()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::PSV::ResourceType>::enumeration( | 
|  | IO &IO, dxbc::PSV::ResourceType &Value) { | 
|  | for (const auto &E : dxbc::PSV::getResourceTypes()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::PSV::ResourceKind>::enumeration( | 
|  | IO &IO, dxbc::PSV::ResourceKind &Value) { | 
|  | for (const auto &E : dxbc::PSV::getResourceKinds()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::D3DSystemValue>::enumeration( | 
|  | IO &IO, dxbc::D3DSystemValue &Value) { | 
|  | for (const auto &E : dxbc::getD3DSystemValues()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::SigMinPrecision>::enumeration( | 
|  | IO &IO, dxbc::SigMinPrecision &Value) { | 
|  | for (const auto &E : dxbc::getSigMinPrecisions()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | void ScalarEnumerationTraits<dxbc::SigComponentType>::enumeration( | 
|  | IO &IO, dxbc::SigComponentType &Value) { | 
|  | for (const auto &E : dxbc::getSigComponentTypes()) | 
|  | IO.enumCase(Value, E.Name.str().c_str(), E.Value); | 
|  | } | 
|  |  | 
|  | } // namespace yaml | 
|  |  | 
|  | void DXContainerYAML::PSVInfo::mapInfoForVersion(yaml::IO &IO) { | 
|  | dxbc::PipelinePSVInfo &StageInfo = Info.StageInfo; | 
|  | Triple::EnvironmentType Stage = dxbc::getShaderStage(Info.ShaderStage); | 
|  |  | 
|  | switch (Stage) { | 
|  | case Triple::EnvironmentType::Pixel: | 
|  | IO.mapRequired("DepthOutput", StageInfo.PS.DepthOutput); | 
|  | IO.mapRequired("SampleFrequency", StageInfo.PS.SampleFrequency); | 
|  | break; | 
|  | case Triple::EnvironmentType::Vertex: | 
|  | IO.mapRequired("OutputPositionPresent", StageInfo.VS.OutputPositionPresent); | 
|  | break; | 
|  | case Triple::EnvironmentType::Geometry: | 
|  | IO.mapRequired("InputPrimitive", StageInfo.GS.InputPrimitive); | 
|  | IO.mapRequired("OutputTopology", StageInfo.GS.OutputTopology); | 
|  | IO.mapRequired("OutputStreamMask", StageInfo.GS.OutputStreamMask); | 
|  | IO.mapRequired("OutputPositionPresent", StageInfo.GS.OutputPositionPresent); | 
|  | break; | 
|  | case Triple::EnvironmentType::Hull: | 
|  | IO.mapRequired("InputControlPointCount", | 
|  | StageInfo.HS.InputControlPointCount); | 
|  | IO.mapRequired("OutputControlPointCount", | 
|  | StageInfo.HS.OutputControlPointCount); | 
|  | IO.mapRequired("TessellatorDomain", StageInfo.HS.TessellatorDomain); | 
|  | IO.mapRequired("TessellatorOutputPrimitive", | 
|  | StageInfo.HS.TessellatorOutputPrimitive); | 
|  | break; | 
|  | case Triple::EnvironmentType::Domain: | 
|  | IO.mapRequired("InputControlPointCount", | 
|  | StageInfo.DS.InputControlPointCount); | 
|  | IO.mapRequired("OutputPositionPresent", StageInfo.DS.OutputPositionPresent); | 
|  | IO.mapRequired("TessellatorDomain", StageInfo.DS.TessellatorDomain); | 
|  | break; | 
|  | case Triple::EnvironmentType::Mesh: | 
|  | IO.mapRequired("GroupSharedBytesUsed", StageInfo.MS.GroupSharedBytesUsed); | 
|  | IO.mapRequired("GroupSharedBytesDependentOnViewID", | 
|  | StageInfo.MS.GroupSharedBytesDependentOnViewID); | 
|  | IO.mapRequired("PayloadSizeInBytes", StageInfo.MS.PayloadSizeInBytes); | 
|  | IO.mapRequired("MaxOutputVertices", StageInfo.MS.MaxOutputVertices); | 
|  | IO.mapRequired("MaxOutputPrimitives", StageInfo.MS.MaxOutputPrimitives); | 
|  | break; | 
|  | case Triple::EnvironmentType::Amplification: | 
|  | IO.mapRequired("PayloadSizeInBytes", StageInfo.AS.PayloadSizeInBytes); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | IO.mapRequired("MinimumWaveLaneCount", Info.MinimumWaveLaneCount); | 
|  | IO.mapRequired("MaximumWaveLaneCount", Info.MaximumWaveLaneCount); | 
|  |  | 
|  | if (Version == 0) | 
|  | return; | 
|  |  | 
|  | IO.mapRequired("UsesViewID", Info.UsesViewID); | 
|  |  | 
|  | switch (Stage) { | 
|  | case Triple::EnvironmentType::Geometry: | 
|  | IO.mapRequired("MaxVertexCount", Info.GeomData.MaxVertexCount); | 
|  | break; | 
|  | case Triple::EnvironmentType::Hull: | 
|  | case Triple::EnvironmentType::Domain: | 
|  | IO.mapRequired("SigPatchConstOrPrimVectors", | 
|  | Info.GeomData.SigPatchConstOrPrimVectors); | 
|  | break; | 
|  | case Triple::EnvironmentType::Mesh: | 
|  | IO.mapRequired("SigPrimVectors", Info.GeomData.MeshInfo.SigPrimVectors); | 
|  | IO.mapRequired("MeshOutputTopology", | 
|  | Info.GeomData.MeshInfo.MeshOutputTopology); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  |  | 
|  | IO.mapRequired("SigInputVectors", Info.SigInputVectors); | 
|  | MutableArrayRef<uint8_t> Vec(Info.SigOutputVectors); | 
|  | IO.mapRequired("SigOutputVectors", Vec); | 
|  |  | 
|  | if (Version == 1) | 
|  | return; | 
|  |  | 
|  | IO.mapRequired("NumThreadsX", Info.NumThreadsX); | 
|  | IO.mapRequired("NumThreadsY", Info.NumThreadsY); | 
|  | IO.mapRequired("NumThreadsZ", Info.NumThreadsZ); | 
|  |  | 
|  | if (Version == 2) | 
|  | return; | 
|  |  | 
|  | IO.mapRequired("EntryName", EntryName); | 
|  | } | 
|  |  | 
|  | } // namespace llvm |