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"
15129c056dSChris Bieneman #include "llvm/ObjectYAML/ObjectYAML.h"
16129c056dSChris Bieneman #include "llvm/ObjectYAML/yaml2obj.h"
17129c056dSChris Bieneman #include "llvm/Support/Errc.h"
18129c056dSChris Bieneman #include "llvm/Support/Error.h"
19129c056dSChris Bieneman #include "llvm/Support/raw_ostream.h"
20129c056dSChris Bieneman
21129c056dSChris Bieneman using namespace llvm;
22129c056dSChris Bieneman
23129c056dSChris Bieneman namespace {
24129c056dSChris Bieneman class DXContainerWriter {
25129c056dSChris Bieneman public:
DXContainerWriter(DXContainerYAML::Object & ObjectFile)26129c056dSChris Bieneman DXContainerWriter(DXContainerYAML::Object &ObjectFile)
27129c056dSChris Bieneman : ObjectFile(ObjectFile) {}
28129c056dSChris Bieneman
29129c056dSChris Bieneman Error write(raw_ostream &OS);
30129c056dSChris Bieneman
31129c056dSChris Bieneman private:
32129c056dSChris Bieneman DXContainerYAML::Object &ObjectFile;
33129c056dSChris Bieneman
34129c056dSChris Bieneman Error computePartOffsets();
35129c056dSChris Bieneman Error validatePartOffsets();
36129c056dSChris Bieneman Error validateSize(uint32_t Computed);
37129c056dSChris Bieneman
38129c056dSChris Bieneman void writeHeader(raw_ostream &OS);
39129c056dSChris Bieneman void writeParts(raw_ostream &OS);
40129c056dSChris Bieneman };
41129c056dSChris Bieneman } // namespace
42129c056dSChris Bieneman
validateSize(uint32_t Computed)43129c056dSChris Bieneman Error DXContainerWriter::validateSize(uint32_t Computed) {
44129c056dSChris Bieneman if (!ObjectFile.Header.FileSize)
45129c056dSChris Bieneman ObjectFile.Header.FileSize = Computed;
46129c056dSChris Bieneman else if (*ObjectFile.Header.FileSize < Computed)
47129c056dSChris Bieneman return createStringError(errc::result_out_of_range,
48129c056dSChris Bieneman "File size specified is too small.");
49129c056dSChris Bieneman return Error::success();
50129c056dSChris Bieneman }
51129c056dSChris Bieneman
validatePartOffsets()52129c056dSChris Bieneman Error DXContainerWriter::validatePartOffsets() {
53129c056dSChris Bieneman if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
54129c056dSChris Bieneman return createStringError(
55129c056dSChris Bieneman errc::invalid_argument,
56129c056dSChris Bieneman "Mismatch between number of parts and part offsets.");
57129c056dSChris Bieneman uint32_t RollingOffset =
58129c056dSChris Bieneman sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
59129c056dSChris Bieneman for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
60129c056dSChris Bieneman if (RollingOffset > std::get<1>(I))
61129c056dSChris Bieneman return createStringError(errc::invalid_argument,
62129c056dSChris Bieneman "Offset mismatch, not enough space for data.");
63129c056dSChris Bieneman RollingOffset =
64129c056dSChris Bieneman std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
65129c056dSChris Bieneman }
66129c056dSChris Bieneman if (Error Err = validateSize(RollingOffset))
67129c056dSChris Bieneman return Err;
68129c056dSChris Bieneman
69129c056dSChris Bieneman return Error::success();
70129c056dSChris Bieneman }
71129c056dSChris Bieneman
computePartOffsets()72129c056dSChris Bieneman Error DXContainerWriter::computePartOffsets() {
73129c056dSChris Bieneman if (ObjectFile.Header.PartOffsets)
74129c056dSChris Bieneman return validatePartOffsets();
75129c056dSChris Bieneman uint32_t RollingOffset =
76129c056dSChris Bieneman sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
77129c056dSChris Bieneman ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
78129c056dSChris Bieneman for (const auto &Part : ObjectFile.Parts) {
79129c056dSChris Bieneman ObjectFile.Header.PartOffsets->push_back(RollingOffset);
80129c056dSChris Bieneman RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
81129c056dSChris Bieneman }
82129c056dSChris Bieneman if (Error Err = validateSize(RollingOffset))
83129c056dSChris Bieneman return Err;
84129c056dSChris Bieneman
85129c056dSChris Bieneman return Error::success();
86129c056dSChris Bieneman }
87129c056dSChris Bieneman
writeHeader(raw_ostream & OS)88129c056dSChris Bieneman void DXContainerWriter::writeHeader(raw_ostream &OS) {
89129c056dSChris Bieneman dxbc::Header Header;
90129c056dSChris Bieneman memcpy(Header.Magic, "DXBC", 4);
91129c056dSChris Bieneman memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
92129c056dSChris Bieneman Header.Version.Major = ObjectFile.Header.Version.Major;
93129c056dSChris Bieneman Header.Version.Minor = ObjectFile.Header.Version.Minor;
94129c056dSChris Bieneman Header.FileSize = *ObjectFile.Header.FileSize;
95129c056dSChris Bieneman Header.PartCount = ObjectFile.Parts.size();
96129c056dSChris Bieneman if (sys::IsBigEndianHost)
97129c056dSChris Bieneman Header.swapBytes();
98129c056dSChris Bieneman OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
996784adc6SChris Bieneman SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
1006784adc6SChris Bieneman ObjectFile.Header.PartOffsets->end());
101129c056dSChris Bieneman if (sys::IsBigEndianHost)
1026784adc6SChris Bieneman for (auto &O : Offsets)
103129c056dSChris Bieneman sys::swapByteOrder(O);
1046784adc6SChris Bieneman OS.write(reinterpret_cast<char *>(Offsets.data()),
1056784adc6SChris Bieneman Offsets.size() * sizeof(uint32_t));
106129c056dSChris Bieneman }
10721c94523SChris Bieneman
writeParts(raw_ostream & OS)108129c056dSChris Bieneman void DXContainerWriter::writeParts(raw_ostream &OS) {
109129c056dSChris Bieneman uint32_t RollingOffset =
110129c056dSChris Bieneman sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
111129c056dSChris Bieneman for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
112129c056dSChris Bieneman if (RollingOffset < std::get<1>(I)) {
113129c056dSChris Bieneman uint32_t PadBytes = std::get<1>(I) - RollingOffset;
11421c94523SChris Bieneman OS.write_zeros(PadBytes);
115129c056dSChris Bieneman }
116129c056dSChris Bieneman DXContainerYAML::Part P = std::get<0>(I);
117129c056dSChris Bieneman OS.write(P.Name.c_str(), 4);
118129c056dSChris Bieneman if (sys::IsBigEndianHost)
119129c056dSChris Bieneman sys::swapByteOrder(P.Size);
120129c056dSChris Bieneman OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
121129c056dSChris Bieneman RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
122129c056dSChris Bieneman
12321c94523SChris Bieneman if (P.Name == "DXIL" && P.Program) {
12421c94523SChris Bieneman dxbc::ProgramHeader Header;
12521c94523SChris Bieneman Header.MajorVersion = P.Program->MajorVersion;
12621c94523SChris Bieneman Header.MinorVersion = P.Program->MinorVersion;
1271fd0beaaSBenjamin Kramer Header.Unused = 0;
12821c94523SChris Bieneman Header.ShaderKind = P.Program->ShaderKind;
12921c94523SChris Bieneman memcpy(Header.Bitcode.Magic, "DXIL", 4);
13021c94523SChris Bieneman Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
13121c94523SChris Bieneman Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
1321fd0beaaSBenjamin Kramer Header.Bitcode.Unused = 0;
13321c94523SChris Bieneman
13421c94523SChris Bieneman // Compute the optional fields if needed...
13521c94523SChris Bieneman if (P.Program->DXILOffset)
136*611ffcf4SKazu Hirata Header.Bitcode.Offset = P.Program->DXILOffset.value();
13721c94523SChris Bieneman else
13821c94523SChris Bieneman Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
13921c94523SChris Bieneman
14021c94523SChris Bieneman if (P.Program->DXILSize)
141*611ffcf4SKazu Hirata Header.Bitcode.Size = P.Program->DXILSize.value();
14221c94523SChris Bieneman else
14321c94523SChris Bieneman Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
14421c94523SChris Bieneman
14521c94523SChris Bieneman if (P.Program->Size)
146*611ffcf4SKazu Hirata Header.Size = P.Program->Size.value();
14721c94523SChris Bieneman else
14821c94523SChris Bieneman Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
149eb68cbb4SChris Bieneman
150eb68cbb4SChris Bieneman uint32_t BitcodeOffset = Header.Bitcode.Offset;
15121c94523SChris Bieneman if (sys::IsBigEndianHost)
15221c94523SChris Bieneman Header.swapBytes();
15321c94523SChris Bieneman OS.write(reinterpret_cast<const char *>(&Header),
15421c94523SChris Bieneman sizeof(dxbc::ProgramHeader));
15521c94523SChris Bieneman if (P.Program->DXIL) {
156eb68cbb4SChris Bieneman if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
157eb68cbb4SChris Bieneman uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
15821c94523SChris Bieneman OS.write_zeros(PadBytes);
15921c94523SChris Bieneman }
16021c94523SChris Bieneman OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
16121c94523SChris Bieneman P.Program->DXIL->size());
16221c94523SChris Bieneman }
16321c94523SChris Bieneman }
164129c056dSChris Bieneman }
165129c056dSChris Bieneman }
166129c056dSChris Bieneman
write(raw_ostream & OS)167129c056dSChris Bieneman Error DXContainerWriter::write(raw_ostream &OS) {
168129c056dSChris Bieneman if (Error Err = computePartOffsets())
169129c056dSChris Bieneman return Err;
170129c056dSChris Bieneman writeHeader(OS);
171129c056dSChris Bieneman writeParts(OS);
172129c056dSChris Bieneman return Error::success();
173129c056dSChris Bieneman }
174129c056dSChris Bieneman
175129c056dSChris Bieneman namespace llvm {
176129c056dSChris Bieneman namespace yaml {
177129c056dSChris Bieneman
yaml2dxcontainer(DXContainerYAML::Object & Doc,raw_ostream & Out,ErrorHandler EH)178129c056dSChris Bieneman bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
179129c056dSChris Bieneman ErrorHandler EH) {
180129c056dSChris Bieneman DXContainerWriter Writer(Doc);
181129c056dSChris Bieneman if (Error Err = Writer.write(Out)) {
182129c056dSChris Bieneman handleAllErrors(std::move(Err),
183129c056dSChris Bieneman [&](const ErrorInfoBase &Err) { EH(Err.message()); });
184129c056dSChris Bieneman return false;
185129c056dSChris Bieneman }
186129c056dSChris Bieneman return true;
187129c056dSChris Bieneman }
188129c056dSChris Bieneman
189129c056dSChris Bieneman } // namespace yaml
190129c056dSChris Bieneman } // namespace llvm
191