181ad6265SDimitry Andric //===- DXContainerEmitter.cpp - Convert YAML to a DXContainer -------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric ///
981ad6265SDimitry Andric /// \file
1081ad6265SDimitry Andric /// Binary emitter for yaml to DXContainer binary
1181ad6265SDimitry Andric ///
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric
1481ad6265SDimitry Andric #include "llvm/BinaryFormat/DXContainer.h"
1506c3fb27SDimitry Andric #include "llvm/MC/DXContainerPSVInfo.h"
1681ad6265SDimitry Andric #include "llvm/ObjectYAML/ObjectYAML.h"
1781ad6265SDimitry Andric #include "llvm/ObjectYAML/yaml2obj.h"
1881ad6265SDimitry Andric #include "llvm/Support/Errc.h"
1981ad6265SDimitry Andric #include "llvm/Support/Error.h"
2081ad6265SDimitry Andric #include "llvm/Support/raw_ostream.h"
2181ad6265SDimitry Andric
2281ad6265SDimitry Andric using namespace llvm;
2381ad6265SDimitry Andric
2481ad6265SDimitry Andric namespace {
2581ad6265SDimitry Andric class DXContainerWriter {
2681ad6265SDimitry Andric public:
DXContainerWriter(DXContainerYAML::Object & ObjectFile)2781ad6265SDimitry Andric DXContainerWriter(DXContainerYAML::Object &ObjectFile)
2881ad6265SDimitry Andric : ObjectFile(ObjectFile) {}
2981ad6265SDimitry Andric
3081ad6265SDimitry Andric Error write(raw_ostream &OS);
3181ad6265SDimitry Andric
3281ad6265SDimitry Andric private:
3381ad6265SDimitry Andric DXContainerYAML::Object &ObjectFile;
3481ad6265SDimitry Andric
3581ad6265SDimitry Andric Error computePartOffsets();
3681ad6265SDimitry Andric Error validatePartOffsets();
3781ad6265SDimitry Andric Error validateSize(uint32_t Computed);
3881ad6265SDimitry Andric
3981ad6265SDimitry Andric void writeHeader(raw_ostream &OS);
4081ad6265SDimitry Andric void writeParts(raw_ostream &OS);
4181ad6265SDimitry Andric };
4281ad6265SDimitry Andric } // namespace
4381ad6265SDimitry Andric
validateSize(uint32_t Computed)4481ad6265SDimitry Andric Error DXContainerWriter::validateSize(uint32_t Computed) {
4581ad6265SDimitry Andric if (!ObjectFile.Header.FileSize)
4681ad6265SDimitry Andric ObjectFile.Header.FileSize = Computed;
4781ad6265SDimitry Andric else if (*ObjectFile.Header.FileSize < Computed)
4881ad6265SDimitry Andric return createStringError(errc::result_out_of_range,
4981ad6265SDimitry Andric "File size specified is too small.");
5081ad6265SDimitry Andric return Error::success();
5181ad6265SDimitry Andric }
5281ad6265SDimitry Andric
validatePartOffsets()5381ad6265SDimitry Andric Error DXContainerWriter::validatePartOffsets() {
5481ad6265SDimitry Andric if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
5581ad6265SDimitry Andric return createStringError(
5681ad6265SDimitry Andric errc::invalid_argument,
5781ad6265SDimitry Andric "Mismatch between number of parts and part offsets.");
5881ad6265SDimitry Andric uint32_t RollingOffset =
5981ad6265SDimitry Andric sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
6081ad6265SDimitry Andric for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
6181ad6265SDimitry Andric if (RollingOffset > std::get<1>(I))
6281ad6265SDimitry Andric return createStringError(errc::invalid_argument,
6381ad6265SDimitry Andric "Offset mismatch, not enough space for data.");
6481ad6265SDimitry Andric RollingOffset =
6581ad6265SDimitry Andric std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
6681ad6265SDimitry Andric }
6781ad6265SDimitry Andric if (Error Err = validateSize(RollingOffset))
6881ad6265SDimitry Andric return Err;
6981ad6265SDimitry Andric
7081ad6265SDimitry Andric return Error::success();
7181ad6265SDimitry Andric }
7281ad6265SDimitry Andric
computePartOffsets()7381ad6265SDimitry Andric Error DXContainerWriter::computePartOffsets() {
7481ad6265SDimitry Andric if (ObjectFile.Header.PartOffsets)
7581ad6265SDimitry Andric return validatePartOffsets();
7681ad6265SDimitry Andric uint32_t RollingOffset =
7781ad6265SDimitry Andric sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
7881ad6265SDimitry Andric ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
7981ad6265SDimitry Andric for (const auto &Part : ObjectFile.Parts) {
8081ad6265SDimitry Andric ObjectFile.Header.PartOffsets->push_back(RollingOffset);
8181ad6265SDimitry Andric RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
8281ad6265SDimitry Andric }
8381ad6265SDimitry Andric if (Error Err = validateSize(RollingOffset))
8481ad6265SDimitry Andric return Err;
8581ad6265SDimitry Andric
8681ad6265SDimitry Andric return Error::success();
8781ad6265SDimitry Andric }
8881ad6265SDimitry Andric
writeHeader(raw_ostream & OS)8981ad6265SDimitry Andric void DXContainerWriter::writeHeader(raw_ostream &OS) {
9081ad6265SDimitry Andric dxbc::Header Header;
9181ad6265SDimitry Andric memcpy(Header.Magic, "DXBC", 4);
9281ad6265SDimitry Andric memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
9381ad6265SDimitry Andric Header.Version.Major = ObjectFile.Header.Version.Major;
9481ad6265SDimitry Andric Header.Version.Minor = ObjectFile.Header.Version.Minor;
9581ad6265SDimitry Andric Header.FileSize = *ObjectFile.Header.FileSize;
9681ad6265SDimitry Andric Header.PartCount = ObjectFile.Parts.size();
9781ad6265SDimitry Andric if (sys::IsBigEndianHost)
9881ad6265SDimitry Andric Header.swapBytes();
9981ad6265SDimitry Andric OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
10081ad6265SDimitry Andric SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
10181ad6265SDimitry Andric ObjectFile.Header.PartOffsets->end());
10281ad6265SDimitry Andric if (sys::IsBigEndianHost)
10381ad6265SDimitry Andric for (auto &O : Offsets)
10481ad6265SDimitry Andric sys::swapByteOrder(O);
10581ad6265SDimitry Andric OS.write(reinterpret_cast<char *>(Offsets.data()),
10681ad6265SDimitry Andric Offsets.size() * sizeof(uint32_t));
10781ad6265SDimitry Andric }
10881ad6265SDimitry Andric
writeParts(raw_ostream & OS)10981ad6265SDimitry Andric void DXContainerWriter::writeParts(raw_ostream &OS) {
11081ad6265SDimitry Andric uint32_t RollingOffset =
11181ad6265SDimitry Andric sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
11281ad6265SDimitry Andric for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
11381ad6265SDimitry Andric if (RollingOffset < std::get<1>(I)) {
11481ad6265SDimitry Andric uint32_t PadBytes = std::get<1>(I) - RollingOffset;
11581ad6265SDimitry Andric OS.write_zeros(PadBytes);
11681ad6265SDimitry Andric }
11781ad6265SDimitry Andric DXContainerYAML::Part P = std::get<0>(I);
118bdd1243dSDimitry Andric RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
119bdd1243dSDimitry Andric uint32_t PartSize = P.Size;
120bdd1243dSDimitry Andric
12181ad6265SDimitry Andric OS.write(P.Name.c_str(), 4);
12281ad6265SDimitry Andric if (sys::IsBigEndianHost)
12381ad6265SDimitry Andric sys::swapByteOrder(P.Size);
12481ad6265SDimitry Andric OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
12581ad6265SDimitry Andric
126bdd1243dSDimitry Andric dxbc::PartType PT = dxbc::parsePartType(P.Name);
127bdd1243dSDimitry Andric
128bdd1243dSDimitry Andric uint64_t DataStart = OS.tell();
129bdd1243dSDimitry Andric switch (PT) {
130bdd1243dSDimitry Andric case dxbc::PartType::DXIL: {
131bdd1243dSDimitry Andric if (!P.Program)
132bdd1243dSDimitry Andric continue;
13381ad6265SDimitry Andric dxbc::ProgramHeader Header;
134*0fca6ea1SDimitry Andric Header.Version = dxbc::ProgramHeader::getVersion(P.Program->MajorVersion,
135*0fca6ea1SDimitry Andric P.Program->MinorVersion);
13681ad6265SDimitry Andric Header.Unused = 0;
13781ad6265SDimitry Andric Header.ShaderKind = P.Program->ShaderKind;
13881ad6265SDimitry Andric memcpy(Header.Bitcode.Magic, "DXIL", 4);
13981ad6265SDimitry Andric Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
14081ad6265SDimitry Andric Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
14181ad6265SDimitry Andric Header.Bitcode.Unused = 0;
14281ad6265SDimitry Andric
14381ad6265SDimitry Andric // Compute the optional fields if needed...
14481ad6265SDimitry Andric if (P.Program->DXILOffset)
145bdd1243dSDimitry Andric Header.Bitcode.Offset = *P.Program->DXILOffset;
14681ad6265SDimitry Andric else
14781ad6265SDimitry Andric Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
14881ad6265SDimitry Andric
14981ad6265SDimitry Andric if (P.Program->DXILSize)
150bdd1243dSDimitry Andric Header.Bitcode.Size = *P.Program->DXILSize;
15181ad6265SDimitry Andric else
15281ad6265SDimitry Andric Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
15381ad6265SDimitry Andric
15481ad6265SDimitry Andric if (P.Program->Size)
155bdd1243dSDimitry Andric Header.Size = *P.Program->Size;
15681ad6265SDimitry Andric else
15781ad6265SDimitry Andric Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
15881ad6265SDimitry Andric
15981ad6265SDimitry Andric uint32_t BitcodeOffset = Header.Bitcode.Offset;
16081ad6265SDimitry Andric if (sys::IsBigEndianHost)
16181ad6265SDimitry Andric Header.swapBytes();
16281ad6265SDimitry Andric OS.write(reinterpret_cast<const char *>(&Header),
16381ad6265SDimitry Andric sizeof(dxbc::ProgramHeader));
16481ad6265SDimitry Andric if (P.Program->DXIL) {
16581ad6265SDimitry Andric if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
16681ad6265SDimitry Andric uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
16781ad6265SDimitry Andric OS.write_zeros(PadBytes);
16881ad6265SDimitry Andric }
16981ad6265SDimitry Andric OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
17081ad6265SDimitry Andric P.Program->DXIL->size());
17181ad6265SDimitry Andric }
172bdd1243dSDimitry Andric break;
17381ad6265SDimitry Andric }
174bdd1243dSDimitry Andric case dxbc::PartType::SFI0: {
175bdd1243dSDimitry Andric // If we don't have any flags we can continue here and the data will be
176bdd1243dSDimitry Andric // zeroed out.
177bdd1243dSDimitry Andric if (!P.Flags.has_value())
178bdd1243dSDimitry Andric continue;
179bdd1243dSDimitry Andric uint64_t Flags = P.Flags->getEncodedFlags();
180bdd1243dSDimitry Andric if (sys::IsBigEndianHost)
181bdd1243dSDimitry Andric sys::swapByteOrder(Flags);
182bdd1243dSDimitry Andric OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
183bdd1243dSDimitry Andric break;
184bdd1243dSDimitry Andric }
185bdd1243dSDimitry Andric case dxbc::PartType::HASH: {
186bdd1243dSDimitry Andric if (!P.Hash.has_value())
187bdd1243dSDimitry Andric continue;
188bdd1243dSDimitry Andric dxbc::ShaderHash Hash = {0, {0}};
189bdd1243dSDimitry Andric if (P.Hash->IncludesSource)
190bdd1243dSDimitry Andric Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
191bdd1243dSDimitry Andric memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
192bdd1243dSDimitry Andric if (sys::IsBigEndianHost)
193bdd1243dSDimitry Andric Hash.swapBytes();
194bdd1243dSDimitry Andric OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
195bdd1243dSDimitry Andric break;
196bdd1243dSDimitry Andric }
19706c3fb27SDimitry Andric case dxbc::PartType::PSV0: {
19806c3fb27SDimitry Andric if (!P.Info.has_value())
19906c3fb27SDimitry Andric continue;
20006c3fb27SDimitry Andric mcdxbc::PSVRuntimeInfo PSV;
201*0fca6ea1SDimitry Andric memcpy(&PSV.BaseData, &P.Info->Info, sizeof(dxbc::PSV::v3::RuntimeInfo));
20206c3fb27SDimitry Andric PSV.Resources = P.Info->Resources;
203*0fca6ea1SDimitry Andric PSV.EntryName = P.Info->EntryName;
20406c3fb27SDimitry Andric
2055f757f3fSDimitry Andric for (auto El : P.Info->SigInputElements)
2065f757f3fSDimitry Andric PSV.InputElements.push_back(mcdxbc::PSVSignatureElement{
2075f757f3fSDimitry Andric El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2085f757f3fSDimitry Andric El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2095f757f3fSDimitry Andric El.Stream});
2105f757f3fSDimitry Andric
2115f757f3fSDimitry Andric for (auto El : P.Info->SigOutputElements)
2125f757f3fSDimitry Andric PSV.OutputElements.push_back(mcdxbc::PSVSignatureElement{
2135f757f3fSDimitry Andric El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2145f757f3fSDimitry Andric El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2155f757f3fSDimitry Andric El.Stream});
2165f757f3fSDimitry Andric
2175f757f3fSDimitry Andric for (auto El : P.Info->SigPatchOrPrimElements)
2185f757f3fSDimitry Andric PSV.PatchOrPrimElements.push_back(mcdxbc::PSVSignatureElement{
2195f757f3fSDimitry Andric El.Name, El.Indices, El.StartRow, El.Cols, El.StartCol,
2205f757f3fSDimitry Andric El.Allocated, El.Kind, El.Type, El.Mode, El.DynamicMask,
2215f757f3fSDimitry Andric El.Stream});
2225f757f3fSDimitry Andric
2235f757f3fSDimitry Andric static_assert(PSV.OutputVectorMasks.size() == PSV.InputOutputMap.size());
2245f757f3fSDimitry Andric for (unsigned I = 0; I < PSV.OutputVectorMasks.size(); ++I) {
2255f757f3fSDimitry Andric PSV.OutputVectorMasks[I].insert(PSV.OutputVectorMasks[I].begin(),
2265f757f3fSDimitry Andric P.Info->OutputVectorMasks[I].begin(),
2275f757f3fSDimitry Andric P.Info->OutputVectorMasks[I].end());
2285f757f3fSDimitry Andric PSV.InputOutputMap[I].insert(PSV.InputOutputMap[I].begin(),
2295f757f3fSDimitry Andric P.Info->InputOutputMap[I].begin(),
2305f757f3fSDimitry Andric P.Info->InputOutputMap[I].end());
2315f757f3fSDimitry Andric }
2325f757f3fSDimitry Andric
2335f757f3fSDimitry Andric PSV.PatchOrPrimMasks.insert(PSV.PatchOrPrimMasks.begin(),
2345f757f3fSDimitry Andric P.Info->PatchOrPrimMasks.begin(),
2355f757f3fSDimitry Andric P.Info->PatchOrPrimMasks.end());
2365f757f3fSDimitry Andric PSV.InputPatchMap.insert(PSV.InputPatchMap.begin(),
2375f757f3fSDimitry Andric P.Info->InputPatchMap.begin(),
2385f757f3fSDimitry Andric P.Info->InputPatchMap.end());
2395f757f3fSDimitry Andric PSV.PatchOutputMap.insert(PSV.PatchOutputMap.begin(),
2405f757f3fSDimitry Andric P.Info->PatchOutputMap.begin(),
2415f757f3fSDimitry Andric P.Info->PatchOutputMap.end());
2425f757f3fSDimitry Andric
2435f757f3fSDimitry Andric PSV.finalize(static_cast<Triple::EnvironmentType>(
24406c3fb27SDimitry Andric Triple::Pixel + P.Info->Info.ShaderStage));
24506c3fb27SDimitry Andric PSV.write(OS, P.Info->Version);
24606c3fb27SDimitry Andric break;
24706c3fb27SDimitry Andric }
2485f757f3fSDimitry Andric case dxbc::PartType::ISG1:
2495f757f3fSDimitry Andric case dxbc::PartType::OSG1:
2505f757f3fSDimitry Andric case dxbc::PartType::PSG1: {
2515f757f3fSDimitry Andric mcdxbc::Signature Sig;
2525f757f3fSDimitry Andric if (P.Signature.has_value()) {
2535f757f3fSDimitry Andric for (const auto &Param : P.Signature->Parameters) {
2545f757f3fSDimitry Andric Sig.addParam(Param.Stream, Param.Name, Param.Index, Param.SystemValue,
2555f757f3fSDimitry Andric Param.CompType, Param.Register, Param.Mask,
2565f757f3fSDimitry Andric Param.ExclusiveMask, Param.MinPrecision);
2575f757f3fSDimitry Andric }
2585f757f3fSDimitry Andric }
2595f757f3fSDimitry Andric Sig.write(OS);
2605f757f3fSDimitry Andric break;
2615f757f3fSDimitry Andric }
262bdd1243dSDimitry Andric case dxbc::PartType::Unknown:
263bdd1243dSDimitry Andric break; // Skip any handling for unrecognized parts.
264bdd1243dSDimitry Andric }
265bdd1243dSDimitry Andric uint64_t BytesWritten = OS.tell() - DataStart;
266bdd1243dSDimitry Andric RollingOffset += BytesWritten;
267bdd1243dSDimitry Andric if (BytesWritten < PartSize)
268bdd1243dSDimitry Andric OS.write_zeros(PartSize - BytesWritten);
269bdd1243dSDimitry Andric RollingOffset += PartSize;
27081ad6265SDimitry Andric }
27181ad6265SDimitry Andric }
27281ad6265SDimitry Andric
write(raw_ostream & OS)27381ad6265SDimitry Andric Error DXContainerWriter::write(raw_ostream &OS) {
27481ad6265SDimitry Andric if (Error Err = computePartOffsets())
27581ad6265SDimitry Andric return Err;
27681ad6265SDimitry Andric writeHeader(OS);
27781ad6265SDimitry Andric writeParts(OS);
27881ad6265SDimitry Andric return Error::success();
27981ad6265SDimitry Andric }
28081ad6265SDimitry Andric
28181ad6265SDimitry Andric namespace llvm {
28281ad6265SDimitry Andric namespace yaml {
28381ad6265SDimitry Andric
yaml2dxcontainer(DXContainerYAML::Object & Doc,raw_ostream & Out,ErrorHandler EH)28481ad6265SDimitry Andric bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out,
28581ad6265SDimitry Andric ErrorHandler EH) {
28681ad6265SDimitry Andric DXContainerWriter Writer(Doc);
28781ad6265SDimitry Andric if (Error Err = Writer.write(Out)) {
28881ad6265SDimitry Andric handleAllErrors(std::move(Err),
28981ad6265SDimitry Andric [&](const ErrorInfoBase &Err) { EH(Err.message()); });
29081ad6265SDimitry Andric return false;
29181ad6265SDimitry Andric }
29281ad6265SDimitry Andric return true;
29381ad6265SDimitry Andric }
29481ad6265SDimitry Andric
29581ad6265SDimitry Andric } // namespace yaml
29681ad6265SDimitry Andric } // namespace llvm
297