1129c056dSChris Bieneman //===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//
2129c056dSChris Bieneman //
3129c056dSChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4129c056dSChris Bieneman // See https://llvm.org/LICENSE.txt for license information.
5129c056dSChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6129c056dSChris Bieneman //
7129c056dSChris Bieneman //===----------------------------------------------------------------------===//
8129c056dSChris Bieneman ///
9129c056dSChris Bieneman /// \file
10129c056dSChris Bieneman /// Binary emitter for yaml to DXContainer binary
11129c056dSChris Bieneman ///
12129c056dSChris Bieneman //===----------------------------------------------------------------------===//
13129c056dSChris Bieneman
14129c056dSChris Bieneman #include "llvm/BinaryFormat/DXContainer.h"
15ad93908eSChris Bieneman #include "llvm/MC/DXContainerPSVInfo.h"
16129c056dSChris Bieneman #include "llvm/ObjectYAML/ObjectYAML.h"
17129c056dSChris Bieneman #include "llvm/ObjectYAML/yaml2obj.h"
18129c056dSChris Bieneman #include "llvm/Support/Errc.h"
19129c056dSChris Bieneman #include "llvm/Support/Error.h"
20129c056dSChris Bieneman #include "llvm/Support/raw_ostream.h"
21129c056dSChris Bieneman
22129c056dSChris Bieneman using namespace llvm;
23129c056dSChris Bieneman
24129c056dSChris Bieneman namespace {
25129c056dSChris Bieneman class DXContainerWriter {
26129c056dSChris Bieneman public:
DXContainerWriter(DXContainerYAML::Object & ObjectFile)27129c056dSChris Bieneman DXContainerWriter(DXContainerYAML::Object &ObjectFile)
28129c056dSChris Bieneman : ObjectFile(ObjectFile) {}
29129c056dSChris Bieneman
30129c056dSChris Bieneman Error write(raw_ostream &OS);
31129c056dSChris Bieneman
32129c056dSChris Bieneman private:
33129c056dSChris Bieneman DXContainerYAML::Object &ObjectFile;
34129c056dSChris Bieneman
35129c056dSChris Bieneman Error computePartOffsets();
36129c056dSChris Bieneman Error validatePartOffsets();
37129c056dSChris Bieneman Error validateSize(uint32_t Computed);
38129c056dSChris Bieneman
39129c056dSChris Bieneman void writeHeader(raw_ostream &OS);
40129c056dSChris Bieneman void writeParts(raw_ostream &OS);
41129c056dSChris Bieneman };
42129c056dSChris Bieneman } // namespace
43129c056dSChris Bieneman
validateSize(uint32_t Computed)44129c056dSChris Bieneman Error DXContainerWriter::validateSize(uint32_t Computed) {
45129c056dSChris Bieneman if (!ObjectFile.Header.FileSize)
46129c056dSChris Bieneman ObjectFile.Header.FileSize = Computed;
47129c056dSChris Bieneman else if (*ObjectFile.Header.FileSize < Computed)
48129c056dSChris Bieneman return createStringError(errc::result_out_of_range,
49129c056dSChris Bieneman "File size specified is too small.");
50129c056dSChris Bieneman return Error::success();
51129c056dSChris Bieneman }
52129c056dSChris Bieneman
validatePartOffsets()53129c056dSChris Bieneman Error DXContainerWriter::validatePartOffsets() {
54129c056dSChris Bieneman if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
55129c056dSChris Bieneman return createStringError(
56129c056dSChris Bieneman errc::invalid_argument,
57129c056dSChris Bieneman "Mismatch between number of parts and part offsets.");
58129c056dSChris Bieneman uint32_t RollingOffset =
59129c056dSChris Bieneman sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
60129c056dSChris Bieneman for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
61129c056dSChris Bieneman if (RollingOffset > std::get<1>(I))
62129c056dSChris Bieneman return createStringError(errc::invalid_argument,
63129c056dSChris Bieneman "Offset mismatch, not enough space for data.");
64129c056dSChris Bieneman RollingOffset =
65129c056dSChris Bieneman std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
66129c056dSChris Bieneman }
67129c056dSChris Bieneman if (Error Err = validateSize(RollingOffset))
68129c056dSChris Bieneman return Err;
69129c056dSChris Bieneman
70129c056dSChris Bieneman return Error::success();
71129c056dSChris Bieneman }
72129c056dSChris Bieneman
computePartOffsets()73129c056dSChris Bieneman Error DXContainerWriter::computePartOffsets() {
74129c056dSChris Bieneman if (ObjectFile.Header.PartOffsets)
75129c056dSChris Bieneman return validatePartOffsets();
76129c056dSChris Bieneman uint32_t RollingOffset =
77129c056dSChris Bieneman sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
78129c056dSChris Bieneman ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
79129c056dSChris Bieneman for (const auto &Part : ObjectFile.Parts) {
80129c056dSChris Bieneman ObjectFile.Header.PartOffsets->push_back(RollingOffset);
81129c056dSChris Bieneman RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
82129c056dSChris Bieneman }
83129c056dSChris Bieneman if (Error Err = validateSize(RollingOffset))
84129c056dSChris Bieneman return Err;
85129c056dSChris Bieneman
86129c056dSChris Bieneman return Error::success();
87129c056dSChris Bieneman }
88129c056dSChris Bieneman
writeHeader(raw_ostream & OS)89129c056dSChris Bieneman void DXContainerWriter::writeHeader(raw_ostream &OS) {
90129c056dSChris Bieneman dxbc::Header Header;
91129c056dSChris Bieneman memcpy(Header.Magic, "DXBC", 4);
92129c056dSChris Bieneman memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
93129c056dSChris Bieneman Header.Version.Major = ObjectFile.Header.Version.Major;
94129c056dSChris Bieneman Header.Version.Minor = ObjectFile.Header.Version.Minor;
95129c056dSChris Bieneman Header.FileSize = *ObjectFile.Header.FileSize;
96129c056dSChris Bieneman Header.PartCount = ObjectFile.Parts.size();
97129c056dSChris Bieneman if (sys::IsBigEndianHost)
98129c056dSChris Bieneman Header.swapBytes();
99129c056dSChris Bieneman OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
1006784adc6SChris Bieneman SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
1016784adc6SChris Bieneman ObjectFile.Header.PartOffsets->end());
102129c056dSChris Bieneman if (sys::IsBigEndianHost)
1036784adc6SChris Bieneman for (auto &O : Offsets)
104129c056dSChris Bieneman sys::swapByteOrder(O);
1056784adc6SChris Bieneman OS.write(reinterpret_cast<char *>(Offsets.data()),
1066784adc6SChris Bieneman Offsets.size() * sizeof(uint32_t));
107129c056dSChris Bieneman }
10821c94523SChris Bieneman
writeParts(raw_ostream & OS)109129c056dSChris Bieneman void DXContainerWriter::writeParts(raw_ostream &OS) {
110129c056dSChris Bieneman uint32_t RollingOffset =
111129c056dSChris Bieneman sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
112129c056dSChris Bieneman for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
113129c056dSChris Bieneman if (RollingOffset < std::get<1>(I)) {
114129c056dSChris Bieneman uint32_t PadBytes = std::get<1>(I) - RollingOffset;
11521c94523SChris Bieneman OS.write_zeros(PadBytes);
116129c056dSChris Bieneman }
117129c056dSChris Bieneman DXContainerYAML::Part P = std::get<0>(I);
11849dc58f5SChris Bieneman RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
11949dc58f5SChris Bieneman uint32_t PartSize = P.Size;
12049dc58f5SChris Bieneman
121129c056dSChris Bieneman OS.write(P.Name.c_str(), 4);
122129c056dSChris Bieneman if (sys::IsBigEndianHost)
123129c056dSChris Bieneman sys::swapByteOrder(P.Size);
124129c056dSChris Bieneman OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
125129c056dSChris Bieneman
12649dc58f5SChris Bieneman dxbc::PartType PT = dxbc::parsePartType(P.Name);
12749dc58f5SChris Bieneman
12849dc58f5SChris Bieneman uint64_t DataStart = OS.tell();
1292556ba4aSChris Bieneman switch (PT) {
1302556ba4aSChris Bieneman case dxbc::PartType::DXIL: {
13149dc58f5SChris Bieneman if (!P.Program)
13249dc58f5SChris Bieneman continue;
13321c94523SChris Bieneman dxbc::ProgramHeader Header;
134*f42117c8SXiang Li Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
135*f42117c8SXiang Li P.Program->MinorVersion);
1361fd0beaaSBenjamin Kramer Header.Unused = 0;
13721c94523SChris Bieneman Header.ShaderKind = P.Program->ShaderKind;
13821c94523SChris Bieneman memcpy(Header.Bitcode.Magic, "DXIL", 4);
13921c94523SChris Bieneman Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
14021c94523SChris Bieneman Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
1411fd0beaaSBenjamin Kramer Header.Bitcode.Unused = 0;
14221c94523SChris Bieneman
14321c94523SChris Bieneman // Compute the optional fields if needed...
14421c94523SChris Bieneman if (P.Program->DXILOffset)
14567ba5c50SFangrui Song Header.Bitcode.Offset = *P.Program->DXILOffset;
14621c94523SChris Bieneman else
14721c94523SChris Bieneman Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
14821c94523SChris Bieneman
14921c94523SChris Bieneman if (P.Program->DXILSize)
15067ba5c50SFangrui Song Header.Bitcode.Size = *P.Program->DXILSize;
15121c94523SChris Bieneman else
15221c94523SChris Bieneman Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
15321c94523SChris Bieneman
15421c94523SChris Bieneman if (P.Program->Size)
15567ba5c50SFangrui Song Header.Size = *P.Program->Size;
15621c94523SChris Bieneman else
15721c94523SChris Bieneman Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
158eb68cbb4SChris Bieneman
159eb68cbb4SChris Bieneman uint32_t BitcodeOffset = Header.Bitcode.Offset;
16021c94523SChris Bieneman if (sys::IsBigEndianHost)
16121c94523SChris Bieneman Header.swapBytes();
16221c94523SChris Bieneman OS.write(reinterpret_cast<const char *>(&Header),
16321c94523SChris Bieneman sizeof(dxbc::ProgramHeader));
16421c94523SChris Bieneman if (P.Program->DXIL) {
165eb68cbb4SChris Bieneman if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
166eb68cbb4SChris Bieneman uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
16721c94523SChris Bieneman OS.write_zeros(PadBytes);
16821c94523SChris Bieneman }
16921c94523SChris Bieneman OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
17021c94523SChris Bieneman P.Program->DXIL->size());
17121c94523SChris Bieneman }
1722556ba4aSChris Bieneman break;
1732556ba4aSChris Bieneman }
1742556ba4aSChris Bieneman case dxbc::PartType::SFI0: {
17549dc58f5SChris Bieneman // If we don't have any flags we can continue here and the data will be
17649dc58f5SChris Bieneman // zeroed out.
17749dc58f5SChris Bieneman if (!P.Flags.has_value())
17849dc58f5SChris Bieneman continue;
17949dc58f5SChris Bieneman uint64_t Flags = P.Flags->getEncodedFlags();
18049dc58f5SChris Bieneman if (sys::IsBigEndianHost)
18149dc58f5SChris Bieneman sys::swapByteOrder(Flags);
18249dc58f5SChris Bieneman OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
1832556ba4aSChris Bieneman break;
1842556ba4aSChris Bieneman }
1852556ba4aSChris Bieneman case dxbc::PartType::HASH: {
1862556ba4aSChris Bieneman if (!P.Hash.has_value())
1872556ba4aSChris Bieneman continue;
1882556ba4aSChris Bieneman dxbc::ShaderHash Hash = {0, {0}};
1892556ba4aSChris Bieneman if (P.Hash->IncludesSource)
1902556ba4aSChris Bieneman Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
1912556ba4aSChris Bieneman memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
1922556ba4aSChris Bieneman if (sys::IsBigEndianHost)
1932556ba4aSChris Bieneman Hash.swapBytes();
1942556ba4aSChris Bieneman OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
1952556ba4aSChris Bieneman break;
1962556ba4aSChris Bieneman }
197ad93908eSChris Bieneman case dxbc::PartType::PSV0: {
198ad93908eSChris Bieneman if (!P.Info.has_value())
199ad93908eSChris Bieneman continue;
200ad93908eSChris Bieneman mcdxbc::PSVRuntimeInfo PSV;
201c62c7463SCooper Partin memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
202dd3f7b02SChris Bieneman PSV.Resources = P.Info->Resources;
203c62c7463SCooper Partin PSV.EntryName = P.Info->EntryName;
204ad93908eSChris Bieneman
2050c3f51c0SChris Bieneman for (auto El : P.Info->SigInputElements)
2060c3f51c0SChris Bieneman PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{
2070c3f51c0SChris Bieneman El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2080c3f51c0SChris Bieneman El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2090c3f51c0SChris Bieneman El.Stream});
2100c3f51c0SChris Bieneman
2110c3f51c0SChris Bieneman for (auto El : P.Info->SigOutputElements)
2120c3f51c0SChris Bieneman PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{
2130c3f51c0SChris Bieneman El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2140c3f51c0SChris Bieneman El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2150c3f51c0SChris Bieneman El.Stream});
2160c3f51c0SChris Bieneman
2170c3f51c0SChris Bieneman for (auto El : P.Info->SigPatchOrPrimElements)
2180c3f51c0SChris Bieneman PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{
2190c3f51c0SChris Bieneman El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2200c3f51c0SChris Bieneman El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2210c3f51c0SChris Bieneman El.Stream});
2220c3f51c0SChris Bieneman
223b799e9daSChris B static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
224b799e9daSChris B for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
225b799e9daSChris B PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
226b799e9daSChris B P.Info->OutputVectorMasks[I].begin(),
227b799e9daSChris B P.Info->OutputVectorMasks[I].end());
228b799e9daSChris B PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
229b799e9daSChris B P.Info->InputOutputMap[I].begin(),
230b799e9daSChris B P.Info->InputOutputMap[I].end());
231b799e9daSChris B }
232b799e9daSChris B
233b799e9daSChris B PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),
234b799e9daSChris B P.Info->PatchOrPrimMasks.begin(),
235b799e9daSChris B P.Info->PatchOrPrimMasks.end());
236b799e9daSChris B PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),
237b799e9daSChris B P.Info->InputPatchMap.begin(),
238b799e9daSChris B P.Info->InputPatchMap.end());
239b799e9daSChris B PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),
240b799e9daSChris B P.Info->PatchOutputMap.begin(),
241b799e9daSChris B P.Info->PatchOutputMap.end());
242b799e9daSChris B
2430c3f51c0SChris Bieneman PSV.finalize(static_cast<Triple::EnvironmentType>(
244ad93908eSChris Bieneman Triple::Pixel + P.Info->Info.ShaderStage));
245ad93908eSChris Bieneman PSV.write(OS, P.Info->Version);
246ad93908eSChris Bieneman break;
247ad93908eSChris Bieneman }
2489f87522bSChris B case dxbc::PartType::ISG1:
2499f87522bSChris B case dxbc::PartType::OSG1:
2509f87522bSChris B case dxbc::PartType::PSG1: {
2519f87522bSChris B mcdxbc::Signature Sig;
2529f87522bSChris B if (P.Signature.has_value()) {
2539f87522bSChris B for (const auto &Param : P.Signature->Parameters) {
2549f87522bSChris B Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
2559f87522bSChris B Param.CompType, Param.Register, Param.Mask,
2569f87522bSChris B Param.ExclusiveMask, Param.MinPrecision);
2579f87522bSChris B }
2589f87522bSChris B }
2599f87522bSChris B Sig.write(OS);
2609f87522bSChris B break;
2619f87522bSChris B }
2622556ba4aSChris Bieneman case dxbc::PartType::Unknown:
2632556ba4aSChris Bieneman break; // Skip any handling for unrecognized parts.
26421c94523SChris Bieneman }
26549dc58f5SChris Bieneman uint64_t BytesWritten = OS.tell() - DataStart;
26649dc58f5SChris Bieneman RollingOffset += BytesWritten;
26749dc58f5SChris Bieneman if (BytesWritten < PartSize)
26849dc58f5SChris Bieneman OS.write_zeros(PartSize - BytesWritten);
26949dc58f5SChris Bieneman RollingOffset += PartSize;
270129c056dSChris Bieneman }
271129c056dSChris Bieneman }
272129c056dSChris Bieneman
write(raw_ostream & OS)273129c056dSChris Bieneman Error DXContainerWriter::write(raw_ostream &OS) {
274129c056dSChris Bieneman if (Error Err = computePartOffsets())
275129c056dSChris Bieneman return Err;
276129c056dSChris Bieneman writeHeader(OS);
277129c056dSChris Bieneman writeParts(OS);
278129c056dSChris Bieneman return Error::success();
279129c056dSChris Bieneman }
280129c056dSChris Bieneman
281129c056dSChris Bieneman namespace llvm {
282129c056dSChris Bieneman namespace yaml {
283129c056dSChris Bieneman
yaml2dxcontainer(DXContainerYAML::Object & Doc,raw_ostream & Out,ErrorHandler EH)284129c056dSChris Bieneman bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
285129c056dSChris Bieneman ErrorHandler EH) {
286129c056dSChris Bieneman DXContainerWriter Writer(Doc);
287129c056dSChris Bieneman if (Error Err = Writer.write(Out)) {
288129c056dSChris Bieneman handleAllErrors(std::move(Err),
289129c056dSChris Bieneman [&](const ErrorInfoBase &Err) { EH(Err.message()); });
290129c056dSChris Bieneman return false;
291129c056dSChris Bieneman }
292129c056dSChris Bieneman return true;
293129c056dSChris Bieneman }
294129c056dSChris Bieneman
295129c056dSChris Bieneman } // namespace yaml
296129c056dSChris Bieneman } // namespace llvm
297