| 1 | //===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | /// |
| 9 | /// \file |
| 10 | /// Binary emitter for yaml to DXContainer binary |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "llvm/ADT/Sequence.h" |
| 15 | #include "llvm/BinaryFormat/DXContainer.h" |
| 16 | #include "llvm/MC/DXContainerInfo.h" |
| 17 | #include "llvm/MC/DXContainerPSVInfo.h" |
| 18 | #include "llvm/MC/DXContainerRootSignature.h" |
| 19 | #include "llvm/ObjectYAML/DXContainerYAML.h" |
| 20 | #include "llvm/ObjectYAML/yaml2obj.h" |
| 21 | #include "llvm/Support/Errc.h" |
| 22 | #include "llvm/Support/Error.h" |
| 23 | #include "llvm/Support/raw_ostream.h" |
| 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | namespace { |
| 28 | class DXContainerWriter { |
| 29 | public: |
| 30 | DXContainerWriter(DXContainerYAML::Object &ObjectFile) |
| 31 | : ObjectFile(ObjectFile) {} |
| 32 | |
| 33 | Error write(raw_ostream &OS); |
| 34 | |
| 35 | private: |
| 36 | DXContainerYAML::Object &ObjectFile; |
| 37 | |
| 38 | Error computePartOffsets(); |
| 39 | Error validatePartOffsets(); |
| 40 | Error validateSize(uint32_t Computed); |
| 41 | |
| 42 | void writeHeader(raw_ostream &OS); |
| 43 | Error writeParts(raw_ostream &OS); |
| 44 | }; |
| 45 | } // namespace |
| 46 | |
| 47 | Error DXContainerWriter::validateSize(uint32_t Computed) { |
| 48 | if (!ObjectFile.Header.FileSize) |
| 49 | ObjectFile.Header.FileSize = Computed; |
| 50 | else if (*ObjectFile.Header.FileSize < Computed) |
| 51 | return createStringError(EC: errc::result_out_of_range, |
| 52 | S: "File size specified is too small." ); |
| 53 | return Error::success(); |
| 54 | } |
| 55 | |
| 56 | Error DXContainerWriter::validatePartOffsets() { |
| 57 | if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size()) |
| 58 | return createStringError( |
| 59 | EC: errc::invalid_argument, |
| 60 | S: "Mismatch between number of parts and part offsets." ); |
| 61 | uint32_t RollingOffset = |
| 62 | sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t)); |
| 63 | for (auto I : llvm::zip(t&: ObjectFile.Parts, u&: *ObjectFile.Header.PartOffsets)) { |
| 64 | if (RollingOffset > std::get<1>(t&: I)) |
| 65 | return createStringError(EC: errc::invalid_argument, |
| 66 | S: "Offset mismatch, not enough space for data." ); |
| 67 | RollingOffset = |
| 68 | std::get<1>(t&: I) + sizeof(dxbc::PartHeader) + std::get<0>(t&: I).Size; |
| 69 | } |
| 70 | if (Error Err = validateSize(Computed: RollingOffset)) |
| 71 | return Err; |
| 72 | |
| 73 | return Error::success(); |
| 74 | } |
| 75 | |
| 76 | Error DXContainerWriter::computePartOffsets() { |
| 77 | if (ObjectFile.Header.PartOffsets) |
| 78 | return validatePartOffsets(); |
| 79 | uint32_t RollingOffset = |
| 80 | sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t)); |
| 81 | ObjectFile.Header.PartOffsets = std::vector<uint32_t>(); |
| 82 | for (const auto &Part : ObjectFile.Parts) { |
| 83 | ObjectFile.Header.PartOffsets->push_back(x: RollingOffset); |
| 84 | RollingOffset += sizeof(dxbc::PartHeader) + Part.Size; |
| 85 | } |
| 86 | if (Error Err = validateSize(Computed: RollingOffset)) |
| 87 | return Err; |
| 88 | |
| 89 | return Error::success(); |
| 90 | } |
| 91 | |
| 92 | void DXContainerWriter::(raw_ostream &OS) { |
| 93 | dxbc::Header ; |
| 94 | memcpy(dest: Header.Magic, src: "DXBC" , n: 4); |
| 95 | memcpy(dest: Header.FileHash.Digest, src: ObjectFile.Header.Hash.data(), n: 16); |
| 96 | Header.Version.Major = ObjectFile.Header.Version.Major; |
| 97 | Header.Version.Minor = ObjectFile.Header.Version.Minor; |
| 98 | Header.FileSize = *ObjectFile.Header.FileSize; |
| 99 | Header.PartCount = ObjectFile.Parts.size(); |
| 100 | if (sys::IsBigEndianHost) |
| 101 | Header.swapBytes(); |
| 102 | OS.write(Ptr: reinterpret_cast<char *>(&Header), Size: sizeof(Header)); |
| 103 | SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(), |
| 104 | ObjectFile.Header.PartOffsets->end()); |
| 105 | if (sys::IsBigEndianHost) |
| 106 | for (auto &O : Offsets) |
| 107 | sys::swapByteOrder(Value&: O); |
| 108 | OS.write(Ptr: reinterpret_cast<char *>(Offsets.data()), |
| 109 | Size: Offsets.size() * sizeof(uint32_t)); |
| 110 | } |
| 111 | |
| 112 | // TODO use it for VERS too |
| 113 | template <typename T> |
| 114 | static void assign_if(T &Dst, const std::optional<T> &Src) { |
| 115 | if (Src) |
| 116 | Dst = *Src; |
| 117 | } |
| 118 | |
| 119 | static void |
| 120 | (dxbc::SourceInfo::SectionHeader &Dst, |
| 121 | const DXContainerYAML::SourceInfo::Section &Src) { |
| 122 | assign_if(Dst&: Dst.AlignedSizeInBytes, Src: Src.GenericHeader.AlignedSizeInBytes); |
| 123 | assign_if(Dst&: Dst.Flags, Src: Src.GenericHeader.Flags); |
| 124 | assign_if(Dst&: Dst.Type, Src: Src.GenericHeader.Type); |
| 125 | } |
| 126 | |
| 127 | Error DXContainerWriter::writeParts(raw_ostream &OS) { |
| 128 | uint32_t RollingOffset = |
| 129 | sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t)); |
| 130 | for (auto I : llvm::zip(t&: ObjectFile.Parts, u&: *ObjectFile.Header.PartOffsets)) { |
| 131 | if (RollingOffset < std::get<1>(t&: I)) { |
| 132 | uint32_t PadBytes = std::get<1>(t&: I) - RollingOffset; |
| 133 | OS.write_zeros(NumZeros: PadBytes); |
| 134 | } |
| 135 | DXContainerYAML::Part P = std::get<0>(t&: I); |
| 136 | RollingOffset = std::get<1>(t&: I) + sizeof(dxbc::PartHeader); |
| 137 | uint32_t PartSize = P.Size; |
| 138 | |
| 139 | OS.write(Ptr: P.Name.c_str(), Size: 4); |
| 140 | if (sys::IsBigEndianHost) |
| 141 | sys::swapByteOrder(Value&: P.Size); |
| 142 | OS.write(Ptr: reinterpret_cast<const char *>(&P.Size), Size: sizeof(uint32_t)); |
| 143 | |
| 144 | dxbc::PartType PT = dxbc::parsePartType(S: P.Name); |
| 145 | |
| 146 | uint64_t DataStart = OS.tell(); |
| 147 | switch (PT) { |
| 148 | case dxbc::PartType::DXIL: |
| 149 | case dxbc::PartType::ILDB: { |
| 150 | if (!P.Program) |
| 151 | continue; |
| 152 | dxbc::ProgramHeader ; |
| 153 | Header.Version = dxbc::ProgramHeader::getVersion(Major: P.Program->MajorVersion, |
| 154 | Minor: P.Program->MinorVersion); |
| 155 | Header.Unused = 0; |
| 156 | Header.ShaderKind = P.Program->ShaderKind; |
| 157 | memcpy(dest: Header.Bitcode.Magic, src: "DXIL" , n: 4); |
| 158 | Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion; |
| 159 | Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion; |
| 160 | Header.Bitcode.Unused = 0; |
| 161 | |
| 162 | // Compute the optional fields if needed... |
| 163 | if (P.Program->DXILOffset) |
| 164 | Header.Bitcode.Offset = *P.Program->DXILOffset; |
| 165 | else |
| 166 | Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader); |
| 167 | |
| 168 | if (P.Program->DXILSize) |
| 169 | Header.Bitcode.Size = *P.Program->DXILSize; |
| 170 | else |
| 171 | Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0; |
| 172 | |
| 173 | if (P.Program->Size) |
| 174 | Header.Size = *P.Program->Size; |
| 175 | else |
| 176 | Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size; |
| 177 | |
| 178 | uint32_t BitcodeOffset = Header.Bitcode.Offset; |
| 179 | if (sys::IsBigEndianHost) |
| 180 | Header.swapBytes(); |
| 181 | OS.write(Ptr: reinterpret_cast<const char *>(&Header), |
| 182 | Size: sizeof(dxbc::ProgramHeader)); |
| 183 | if (P.Program->DXIL) { |
| 184 | if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) { |
| 185 | uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader); |
| 186 | OS.write_zeros(NumZeros: PadBytes); |
| 187 | } |
| 188 | OS.write(Ptr: reinterpret_cast<char *>(P.Program->DXIL->data()), |
| 189 | Size: P.Program->DXIL->size()); |
| 190 | } |
| 191 | break; |
| 192 | } |
| 193 | case dxbc::PartType::ILDN: { |
| 194 | if (!P.DebugName) |
| 195 | continue; |
| 196 | |
| 197 | mcdxbc::DebugName DebugName; |
| 198 | DebugName.setFilename(P.DebugName->Filename); |
| 199 | // Override default flags with value from YAML. |
| 200 | if (P.DebugName->Flags) |
| 201 | DebugName.Parameters.Flags = *P.DebugName->Flags; |
| 202 | // Override computed filename length with value from YAML. |
| 203 | if (P.DebugName->NameLength) |
| 204 | DebugName.Parameters.NameLength = *P.DebugName->NameLength; |
| 205 | DebugName.write(OS); |
| 206 | break; |
| 207 | } |
| 208 | case dxbc::PartType::PRIV: { |
| 209 | if (!P.PrivateData) |
| 210 | continue; |
| 211 | OS.write(Ptr: reinterpret_cast<char *>(P.PrivateData->data()), |
| 212 | Size: P.PrivateData->size()); |
| 213 | break; |
| 214 | } |
| 215 | case dxbc::PartType::SFI0: { |
| 216 | // If we don't have any flags we can continue here and the data will be |
| 217 | // zeroed out. |
| 218 | if (!P.Flags.has_value()) |
| 219 | continue; |
| 220 | uint64_t Flags = P.Flags->getEncodedFlags(); |
| 221 | if (sys::IsBigEndianHost) |
| 222 | sys::swapByteOrder(Value&: Flags); |
| 223 | OS.write(Ptr: reinterpret_cast<char *>(&Flags), Size: sizeof(uint64_t)); |
| 224 | break; |
| 225 | } |
| 226 | case dxbc::PartType::HASH: { |
| 227 | if (!P.Hash.has_value()) |
| 228 | continue; |
| 229 | dxbc::ShaderHash Hash = {.Flags: 0, .Digest: {0}}; |
| 230 | if (P.Hash->IncludesSource) |
| 231 | Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource); |
| 232 | memcpy(dest: &Hash.Digest[0], src: &P.Hash->Digest[0], n: 16); |
| 233 | if (sys::IsBigEndianHost) |
| 234 | Hash.swapBytes(); |
| 235 | OS.write(Ptr: reinterpret_cast<char *>(&Hash), Size: sizeof(dxbc::ShaderHash)); |
| 236 | break; |
| 237 | } |
| 238 | case dxbc::PartType::PSV0: { |
| 239 | if (!P.Info.has_value()) |
| 240 | continue; |
| 241 | mcdxbc::PSVRuntimeInfo PSV; |
| 242 | memcpy(dest: &PSV.BaseData, src: &P.Info->Info, n: sizeof(dxbc::PSV::v3::RuntimeInfo)); |
| 243 | PSV.Resources = P.Info->Resources; |
| 244 | PSV.EntryName = P.Info->EntryName; |
| 245 | |
| 246 | for (auto El : P.Info->SigInputElements) |
| 247 | PSV.InputElements.push_back(Elt: mcdxbc::PSVSignatureElement{ |
| 248 | .Name: El.Name, .Indices: El.Indices, .StartRow: El.StartRow, .Cols: El.Cols, .StartCol: El.StartCol, |
| 249 | .Allocated: El.Allocated, .Kind: El.Kind, .Type: El.Type, .Mode: El.Mode, .DynamicMask: El.DynamicMask, |
| 250 | .Stream: El.Stream}); |
| 251 | |
| 252 | for (auto El : P.Info->SigOutputElements) |
| 253 | PSV.OutputElements.push_back(Elt: mcdxbc::PSVSignatureElement{ |
| 254 | .Name: El.Name, .Indices: El.Indices, .StartRow: El.StartRow, .Cols: El.Cols, .StartCol: El.StartCol, |
| 255 | .Allocated: El.Allocated, .Kind: El.Kind, .Type: El.Type, .Mode: El.Mode, .DynamicMask: El.DynamicMask, |
| 256 | .Stream: El.Stream}); |
| 257 | |
| 258 | for (auto El : P.Info->SigPatchOrPrimElements) |
| 259 | PSV.PatchOrPrimElements.push_back(Elt: mcdxbc::PSVSignatureElement{ |
| 260 | .Name: El.Name, .Indices: El.Indices, .StartRow: El.StartRow, .Cols: El.Cols, .StartCol: El.StartCol, |
| 261 | .Allocated: El.Allocated, .Kind: El.Kind, .Type: El.Type, .Mode: El.Mode, .DynamicMask: El.DynamicMask, |
| 262 | .Stream: El.Stream}); |
| 263 | |
| 264 | static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size()); |
| 265 | for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) { |
| 266 | PSV.OutputVectorMasks[I].insert(I: PSV.OutputVectorMasks[I].begin(), |
| 267 | From: P.Info->OutputVectorMasks[I].begin(), |
| 268 | To: P.Info->OutputVectorMasks[I].end()); |
| 269 | PSV.InputOutputMap[I].insert(I: PSV.InputOutputMap[I].begin(), |
| 270 | From: P.Info->InputOutputMap[I].begin(), |
| 271 | To: P.Info->InputOutputMap[I].end()); |
| 272 | } |
| 273 | |
| 274 | PSV.PatchOrPrimMasks.insert(I: PSV.PatchOrPrimMasks.begin(), |
| 275 | From: P.Info->PatchOrPrimMasks.begin(), |
| 276 | To: P.Info->PatchOrPrimMasks.end()); |
| 277 | PSV.InputPatchMap.insert(I: PSV.InputPatchMap.begin(), |
| 278 | From: P.Info->InputPatchMap.begin(), |
| 279 | To: P.Info->InputPatchMap.end()); |
| 280 | PSV.PatchOutputMap.insert(I: PSV.PatchOutputMap.begin(), |
| 281 | From: P.Info->PatchOutputMap.begin(), |
| 282 | To: P.Info->PatchOutputMap.end()); |
| 283 | |
| 284 | PSV.finalize(Stage: static_cast<Triple::EnvironmentType>( |
| 285 | Triple::Pixel + P.Info->Info.ShaderStage), |
| 286 | Version: P.Info->Version); |
| 287 | PSV.write(OS, Version: P.Info->Version); |
| 288 | break; |
| 289 | } |
| 290 | case dxbc::PartType::ISG1: |
| 291 | case dxbc::PartType::OSG1: |
| 292 | case dxbc::PartType::PSG1: { |
| 293 | mcdxbc::Signature Sig; |
| 294 | if (P.Signature.has_value()) { |
| 295 | for (const auto &Param : P.Signature->Parameters) { |
| 296 | Sig.addParam(Stream: Param.Stream, Name: Param.Name, Index: Param.Index, SystemValue: Param.SystemValue, |
| 297 | CompType: Param.CompType, Register: Param.Register, Mask: Param.Mask, |
| 298 | ExclusiveMask: Param.ExclusiveMask, MinPrecision: Param.MinPrecision); |
| 299 | } |
| 300 | } |
| 301 | Sig.write(OS); |
| 302 | break; |
| 303 | } |
| 304 | case dxbc::PartType::Unknown: |
| 305 | break; // Skip any handling for unrecognized parts. |
| 306 | case dxbc::PartType::RTS0: { |
| 307 | if (!P.RootSignature.has_value()) |
| 308 | continue; |
| 309 | |
| 310 | mcdxbc::RootSignatureDesc RS; |
| 311 | RS.Flags = P.RootSignature->getEncodedFlags(); |
| 312 | RS.Version = P.RootSignature->Version; |
| 313 | RS.NumStaticSamplers = P.RootSignature->NumStaticSamplers; |
| 314 | |
| 315 | for (DXContainerYAML::RootParameterLocationYaml &L : |
| 316 | P.RootSignature->Parameters.Locations) { |
| 317 | |
| 318 | const dxbc::RootParameterType Type = L.Header.Type; |
| 319 | const dxbc::ShaderVisibility Visibility = L.Header.Visibility; |
| 320 | |
| 321 | switch (Type) { |
| 322 | case dxbc::RootParameterType::Constants32Bit: { |
| 323 | const DXContainerYAML::RootConstantsYaml &ConstantYaml = |
| 324 | P.RootSignature->Parameters.getOrInsertConstants(ParamDesc&: L); |
| 325 | mcdxbc::RootConstants Constants; |
| 326 | |
| 327 | Constants.Num32BitValues = ConstantYaml.Num32BitValues; |
| 328 | Constants.RegisterSpace = ConstantYaml.RegisterSpace; |
| 329 | Constants.ShaderRegister = ConstantYaml.ShaderRegister; |
| 330 | RS.ParametersContainer.addParameter(Type, Visibility, Constant: Constants); |
| 331 | break; |
| 332 | } |
| 333 | case dxbc::RootParameterType::CBV: |
| 334 | case dxbc::RootParameterType::SRV: |
| 335 | case dxbc::RootParameterType::UAV: { |
| 336 | const DXContainerYAML::RootDescriptorYaml &DescriptorYaml = |
| 337 | P.RootSignature->Parameters.getOrInsertDescriptor(ParamDesc&: L); |
| 338 | |
| 339 | mcdxbc::RootDescriptor Descriptor; |
| 340 | Descriptor.RegisterSpace = DescriptorYaml.RegisterSpace; |
| 341 | Descriptor.ShaderRegister = DescriptorYaml.ShaderRegister; |
| 342 | if (RS.Version > 1) |
| 343 | Descriptor.Flags = DescriptorYaml.getEncodedFlags(); |
| 344 | RS.ParametersContainer.addParameter(Type, Visibility, Descriptor); |
| 345 | break; |
| 346 | } |
| 347 | case dxbc::RootParameterType::DescriptorTable: { |
| 348 | const DXContainerYAML::DescriptorTableYaml &TableYaml = |
| 349 | P.RootSignature->Parameters.getOrInsertTable(ParamDesc&: L); |
| 350 | mcdxbc::DescriptorTable Table; |
| 351 | for (const auto &R : TableYaml.Ranges) { |
| 352 | mcdxbc::DescriptorRange Range; |
| 353 | Range.RangeType = R.RangeType; |
| 354 | Range.NumDescriptors = R.NumDescriptors; |
| 355 | Range.BaseShaderRegister = R.BaseShaderRegister; |
| 356 | Range.RegisterSpace = R.RegisterSpace; |
| 357 | Range.OffsetInDescriptorsFromTableStart = |
| 358 | R.OffsetInDescriptorsFromTableStart; |
| 359 | |
| 360 | if (RS.Version > 1) |
| 361 | Range.Flags = R.getEncodedFlags(); |
| 362 | |
| 363 | Table.Ranges.push_back(Elt: Range); |
| 364 | } |
| 365 | RS.ParametersContainer.addParameter(Type, Visibility, Table); |
| 366 | break; |
| 367 | } |
| 368 | } |
| 369 | } |
| 370 | |
| 371 | for (const auto &Param : P.RootSignature->samplers()) { |
| 372 | mcdxbc::StaticSampler NewSampler; |
| 373 | NewSampler.Filter = Param.Filter; |
| 374 | NewSampler.AddressU = Param.AddressU; |
| 375 | NewSampler.AddressV = Param.AddressV; |
| 376 | NewSampler.AddressW = Param.AddressW; |
| 377 | NewSampler.MipLODBias = Param.MipLODBias; |
| 378 | NewSampler.MaxAnisotropy = Param.MaxAnisotropy; |
| 379 | NewSampler.ComparisonFunc = Param.ComparisonFunc; |
| 380 | NewSampler.BorderColor = Param.BorderColor; |
| 381 | NewSampler.MinLOD = Param.MinLOD; |
| 382 | NewSampler.MaxLOD = Param.MaxLOD; |
| 383 | NewSampler.ShaderRegister = Param.ShaderRegister; |
| 384 | NewSampler.RegisterSpace = Param.RegisterSpace; |
| 385 | NewSampler.ShaderVisibility = Param.ShaderVisibility; |
| 386 | |
| 387 | if (RS.Version > 2) |
| 388 | NewSampler.Flags = Param.getEncodedFlags(); |
| 389 | |
| 390 | RS.StaticSamplers.push_back(Elt: NewSampler); |
| 391 | } |
| 392 | |
| 393 | // Handling of offsets |
| 394 | RS.RootParameterOffset = RS.computeRootParametersOffset(); |
| 395 | if (P.RootSignature->RootParametersOffset && |
| 396 | P.RootSignature->RootParametersOffset.value() != |
| 397 | RS.RootParameterOffset) { |
| 398 | return createStringError( |
| 399 | EC: errc::invalid_argument, |
| 400 | Fmt: "Specified RootParametersOffset does not match required value: %d." , |
| 401 | Vals: RS.RootParameterOffset); |
| 402 | } |
| 403 | |
| 404 | RS.StaticSamplersOffset = RS.computeStaticSamplersOffset(); |
| 405 | if (P.RootSignature->StaticSamplersOffset && |
| 406 | P.RootSignature->StaticSamplersOffset.value() != |
| 407 | RS.StaticSamplersOffset) { |
| 408 | return createStringError( |
| 409 | EC: errc::invalid_argument, |
| 410 | Fmt: "Specified StaticSamplersOffset does not match computed value: %d." , |
| 411 | Vals: RS.StaticSamplersOffset); |
| 412 | } |
| 413 | |
| 414 | RS.write(OS); |
| 415 | break; |
| 416 | } |
| 417 | case dxbc::PartType::SRCI: { |
| 418 | if (!P.SourceInfo.has_value()) |
| 419 | continue; |
| 420 | mcdxbc::SourceInfoBuilder SourceInfo; |
| 421 | auto &ContentsYAML = P.SourceInfo->Contents; |
| 422 | SourceInfo.setCompressionType(ContentsYAML.Parameters.Type); |
| 423 | |
| 424 | if (ContentsYAML.Entries.size() != P.SourceInfo->Names.Entries.size()) |
| 425 | return createStringError( |
| 426 | EC: errc::invalid_argument, |
| 427 | S: "number of entries in Names section must match number of entries " |
| 428 | "in Contents section in SRCI part" ); |
| 429 | |
| 430 | for (size_t I : llvm::seq(Size: ContentsYAML.Entries.size())) |
| 431 | SourceInfo.addFile(Name: P.SourceInfo->Names.Entries[I].FileName, |
| 432 | Content: ContentsYAML.Entries[I].FileContent); |
| 433 | for (auto &ArgEntry : P.SourceInfo->Args.Args) |
| 434 | SourceInfo.addArg(Name: ArgEntry.first, Value: ArgEntry.second); |
| 435 | |
| 436 | SourceInfo.computeEntries(); |
| 437 | |
| 438 | // If entries field values are provided in YAML, override them in |
| 439 | // SourceInfo. |
| 440 | for (size_t I : llvm::seq(Size: ContentsYAML.Entries.size())) { |
| 441 | auto &ContentEntryYAML = ContentsYAML.Entries[I]; |
| 442 | auto &ContentEntry = SourceInfo.BaseData.Contents.Entries[I]; |
| 443 | assign_if(Dst&: ContentEntry.Parameters.AlignedSizeInBytes, |
| 444 | Src: ContentEntryYAML.AlignedSizeInBytes); |
| 445 | assign_if(Dst&: ContentEntry.Parameters.Flags, Src: ContentEntryYAML.Flags); |
| 446 | assign_if(Dst&: ContentEntry.Parameters.ContentSizeInBytes, |
| 447 | Src: ContentEntryYAML.ContentSizeInBytes); |
| 448 | |
| 449 | auto &NameEntryYAML = P.SourceInfo->Names.Entries[I]; |
| 450 | auto &NameEntry = SourceInfo.BaseData.Names.Entries[I]; |
| 451 | assign_if(Dst&: NameEntry.Parameters.AlignedSizeInBytes, |
| 452 | Src: NameEntryYAML.AlignedSizeInBytes); |
| 453 | assign_if(Dst&: NameEntry.Parameters.Flags, Src: NameEntryYAML.Flags); |
| 454 | assign_if(Dst&: NameEntry.Parameters.NameSizeInBytes, |
| 455 | Src: NameEntryYAML.NameSizeInBytes); |
| 456 | assign_if(Dst&: NameEntry.Parameters.ContentSizeInBytes, |
| 457 | Src: NameEntryYAML.ContentSizeInBytes); |
| 458 | } |
| 459 | |
| 460 | SourceInfo.finalize(); |
| 461 | |
| 462 | // If section header field values are provided in YAML, override them in |
| 463 | // SourceInfo. |
| 464 | auto &Contents = SourceInfo.BaseData.Contents; |
| 465 | assignSectionHeader(Dst&: Contents.GenericHeader, Src: ContentsYAML); |
| 466 | assign_if(Dst&: Contents.Parameters.AlignedSizeInBytes, |
| 467 | Src: ContentsYAML.Parameters.AlignedSizeInBytes); |
| 468 | assign_if(Dst&: Contents.Parameters.Flags, Src: ContentsYAML.Parameters.Flags); |
| 469 | assign_if(Dst&: Contents.Parameters.EntriesSizeInBytes, |
| 470 | Src: ContentsYAML.Parameters.EntriesSizeInBytes); |
| 471 | assign_if(Dst&: Contents.Parameters.UncompressedEntriesSizeInBytes, |
| 472 | Src: ContentsYAML.Parameters.UncompressedEntriesSizeInBytes); |
| 473 | if (ContentsYAML.Parameters.Count && |
| 474 | ContentsYAML.Parameters.Count != Contents.Parameters.Count) |
| 475 | return createStringError( |
| 476 | EC: errc::invalid_argument, |
| 477 | S: "the value of Count field in Contents header must match the number " |
| 478 | "of entries in Contents section" ); |
| 479 | |
| 480 | auto &NamesYAML = P.SourceInfo->Names; |
| 481 | auto &Names = SourceInfo.BaseData.Names; |
| 482 | assignSectionHeader(Dst&: Names.GenericHeader, Src: NamesYAML); |
| 483 | assign_if(Dst&: Names.Parameters.Flags, Src: NamesYAML.Parameters.Flags); |
| 484 | assign_if(Dst&: Names.Parameters.EntriesSizeInBytes, |
| 485 | Src: NamesYAML.Parameters.EntriesSizeInBytes); |
| 486 | if (NamesYAML.Parameters.Count && |
| 487 | NamesYAML.Parameters.Count != Names.Parameters.Count) |
| 488 | return createStringError( |
| 489 | EC: errc::invalid_argument, |
| 490 | S: "the value of Count field in Names header must match the number of " |
| 491 | "entries in Names section" ); |
| 492 | |
| 493 | auto &ArgsYAML = P.SourceInfo->Args; |
| 494 | auto &Args = SourceInfo.BaseData.Args; |
| 495 | assignSectionHeader(Dst&: Args.GenericHeader, Src: ArgsYAML); |
| 496 | assign_if(Dst&: Args.Parameters.Flags, Src: ArgsYAML.Parameters.Flags); |
| 497 | assign_if(Dst&: Args.Parameters.SizeInBytes, Src: ArgsYAML.Parameters.SizeInBytes); |
| 498 | if (ArgsYAML.Parameters.Count && |
| 499 | ArgsYAML.Parameters.Count != Args.Parameters.Count) |
| 500 | return createStringError(EC: errc::invalid_argument, |
| 501 | S: "the value of Count field in Args header must " |
| 502 | "match the number of entries in Args section" ); |
| 503 | |
| 504 | assign_if(Dst&: SourceInfo.BaseData.Parameters.AlignedSizeInBytes, |
| 505 | Src: P.SourceInfo->Parameters.AlignedSizeInBytes); |
| 506 | assign_if(Dst&: SourceInfo.BaseData.Parameters.Flags, |
| 507 | Src: P.SourceInfo->Parameters.Flags); |
| 508 | assign_if(Dst&: SourceInfo.BaseData.Parameters.SectionCount, |
| 509 | Src: P.SourceInfo->Parameters.SectionCount); |
| 510 | |
| 511 | SourceInfo.write(OS); |
| 512 | break; |
| 513 | } |
| 514 | case dxbc::PartType::VERS: { |
| 515 | if (!P.CompilerVersion) |
| 516 | continue; |
| 517 | |
| 518 | mcdxbc::CompilerVersion CompilerVersion; |
| 519 | CompilerVersion.Parameters.Major = |
| 520 | P.CompilerVersion->Major.value_or(u&: CompilerVersion.Parameters.Major); |
| 521 | CompilerVersion.Parameters.Minor = |
| 522 | P.CompilerVersion->Minor.value_or(u&: CompilerVersion.Parameters.Minor); |
| 523 | |
| 524 | if (P.CompilerVersion->IsDebugBuild || P.CompilerVersion->IsValidated) |
| 525 | CompilerVersion.Parameters.Flags = dxbc::CompilerVersionFlags::Default; |
| 526 | if (P.CompilerVersion->IsDebugBuild.value_or(u: false)) |
| 527 | CompilerVersion.Parameters.Flags |= dxbc::CompilerVersionFlags::Debug; |
| 528 | if (P.CompilerVersion->IsValidated.value_or(u: false)) |
| 529 | CompilerVersion.Parameters.Flags |= |
| 530 | dxbc::CompilerVersionFlags::Internal; |
| 531 | |
| 532 | CompilerVersion.Parameters.CommitCount = |
| 533 | P.CompilerVersion->CommitCount.value_or( |
| 534 | u&: CompilerVersion.Parameters.CommitCount); |
| 535 | |
| 536 | if (P.CompilerVersion->CommitSha) |
| 537 | CompilerVersion.setCommitSha(*P.CompilerVersion->CommitSha); |
| 538 | if (P.CompilerVersion->CustomVersionString) |
| 539 | CompilerVersion.setVersionString( |
| 540 | *P.CompilerVersion->CustomVersionString); |
| 541 | |
| 542 | CompilerVersion.Parameters.ContentSizeInBytes = |
| 543 | P.CompilerVersion->ContentSizeInBytes.value_or( |
| 544 | u&: CompilerVersion.Parameters.ContentSizeInBytes); |
| 545 | |
| 546 | CompilerVersion.write(OS); |
| 547 | break; |
| 548 | } |
| 549 | } |
| 550 | uint64_t BytesWritten = OS.tell() - DataStart; |
| 551 | RollingOffset += BytesWritten; |
| 552 | if (BytesWritten < PartSize) |
| 553 | OS.write_zeros(NumZeros: PartSize - BytesWritten); |
| 554 | RollingOffset += PartSize; |
| 555 | } |
| 556 | |
| 557 | return Error::success(); |
| 558 | } |
| 559 | |
| 560 | Error DXContainerWriter::write(raw_ostream &OS) { |
| 561 | if (Error Err = computePartOffsets()) |
| 562 | return Err; |
| 563 | writeHeader(OS); |
| 564 | return writeParts(OS); |
| 565 | } |
| 566 | |
| 567 | namespace llvm { |
| 568 | namespace yaml { |
| 569 | |
| 570 | bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out, |
| 571 | ErrorHandler EH) { |
| 572 | DXContainerWriter Writer(Doc); |
| 573 | if (Error Err = Writer.write(OS&: Out)) { |
| 574 | handleAllErrors(E: std::move(Err), |
| 575 | Handlers: [&](const ErrorInfoBase &Err) { EH(Err.message()); }); |
| 576 | return false; |
| 577 | } |
| 578 | return true; |
| 579 | } |
| 580 | |
| 581 | } // namespace yaml |
| 582 | } // namespace llvm |
| 583 | |