LLVM  16.0.0git
DXContainerEmitter.cpp
Go to the documentation of this file.
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 
17 #include "llvm/Support/Errc.h"
18 #include "llvm/Support/Error.h"
20 
21 using namespace llvm;
22 
23 namespace {
24 class DXContainerWriter {
25 public:
26  DXContainerWriter(DXContainerYAML::Object &ObjectFile)
28 
29  Error write(raw_ostream &OS);
30 
31 private:
33 
34  Error computePartOffsets();
35  Error validatePartOffsets();
36  Error validateSize(uint32_t Computed);
37 
38  void writeHeader(raw_ostream &OS);
39  void writeParts(raw_ostream &OS);
40 };
41 } // namespace
42 
43 Error DXContainerWriter::validateSize(uint32_t Computed) {
44  if (!ObjectFile.Header.FileSize)
45  ObjectFile.Header.FileSize = Computed;
46  else if (*ObjectFile.Header.FileSize < Computed)
48  "File size specified is too small.");
49  return Error::success();
50 }
51 
52 Error DXContainerWriter::validatePartOffsets() {
53  if (ObjectFile.Parts.size() != ObjectFile.Header.PartOffsets->size())
54  return createStringError(
56  "Mismatch between number of parts and part offsets.");
57  uint32_t RollingOffset =
58  sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
59  for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
60  if (RollingOffset > std::get<1>(I))
62  "Offset mismatch, not enough space for data.");
63  RollingOffset =
64  std::get<1>(I) + sizeof(dxbc::PartHeader) + std::get<0>(I).Size;
65  }
66  if (Error Err = validateSize(RollingOffset))
67  return Err;
68 
69  return Error::success();
70 }
71 
72 Error DXContainerWriter::computePartOffsets() {
73  if (ObjectFile.Header.PartOffsets)
74  return validatePartOffsets();
75  uint32_t RollingOffset =
76  sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
77  ObjectFile.Header.PartOffsets = std::vector<uint32_t>();
78  for (const auto &Part : ObjectFile.Parts) {
79  ObjectFile.Header.PartOffsets->push_back(RollingOffset);
80  RollingOffset += sizeof(dxbc::PartHeader) + Part.Size;
81  }
82  if (Error Err = validateSize(RollingOffset))
83  return Err;
84 
85  return Error::success();
86 }
87 
88 void DXContainerWriter::writeHeader(raw_ostream &OS) {
89  dxbc::Header Header;
90  memcpy(Header.Magic, "DXBC", 4);
91  memcpy(Header.FileHash.Digest, ObjectFile.Header.Hash.data(), 16);
92  Header.Version.Major = ObjectFile.Header.Version.Major;
93  Header.Version.Minor = ObjectFile.Header.Version.Minor;
94  Header.FileSize = *ObjectFile.Header.FileSize;
95  Header.PartCount = ObjectFile.Parts.size();
97  Header.swapBytes();
98  OS.write(reinterpret_cast<char *>(&Header), sizeof(Header));
99  SmallVector<uint32_t> Offsets(ObjectFile.Header.PartOffsets->begin(),
100  ObjectFile.Header.PartOffsets->end());
102  for (auto &O : Offsets)
104  OS.write(reinterpret_cast<char *>(Offsets.data()),
105  Offsets.size() * sizeof(uint32_t));
106 }
107 
108 void DXContainerWriter::writeParts(raw_ostream &OS) {
109  uint32_t RollingOffset =
110  sizeof(dxbc::Header) + (ObjectFile.Header.PartCount * sizeof(uint32_t));
111  for (auto I : llvm::zip(ObjectFile.Parts, *ObjectFile.Header.PartOffsets)) {
112  if (RollingOffset < std::get<1>(I)) {
113  uint32_t PadBytes = std::get<1>(I) - RollingOffset;
114  OS.write_zeros(PadBytes);
115  }
116  DXContainerYAML::Part P = std::get<0>(I);
117  RollingOffset = std::get<1>(I) + sizeof(dxbc::PartHeader);
118  uint32_t PartSize = P.Size;
119 
120  OS.write(P.Name.c_str(), 4);
122  sys::swapByteOrder(P.Size);
123  OS.write(reinterpret_cast<const char *>(&P.Size), sizeof(uint32_t));
124 
126 
127  uint64_t DataStart = OS.tell();
128  switch (PT) {
129  case dxbc::PartType::DXIL: {
130  if (!P.Program)
131  continue;
132  dxbc::ProgramHeader Header;
133  Header.MajorVersion = P.Program->MajorVersion;
134  Header.MinorVersion = P.Program->MinorVersion;
135  Header.Unused = 0;
136  Header.ShaderKind = P.Program->ShaderKind;
137  memcpy(Header.Bitcode.Magic, "DXIL", 4);
138  Header.Bitcode.MajorVersion = P.Program->DXILMajorVersion;
139  Header.Bitcode.MinorVersion = P.Program->DXILMinorVersion;
140  Header.Bitcode.Unused = 0;
141 
142  // Compute the optional fields if needed...
143  if (P.Program->DXILOffset)
144  Header.Bitcode.Offset = P.Program->DXILOffset.value();
145  else
146  Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
147 
148  if (P.Program->DXILSize)
149  Header.Bitcode.Size = P.Program->DXILSize.value();
150  else
151  Header.Bitcode.Size = P.Program->DXIL ? P.Program->DXIL->size() : 0;
152 
153  if (P.Program->Size)
154  Header.Size = P.Program->Size.value();
155  else
156  Header.Size = sizeof(dxbc::ProgramHeader) + Header.Bitcode.Size;
157 
158  uint32_t BitcodeOffset = Header.Bitcode.Offset;
160  Header.swapBytes();
161  OS.write(reinterpret_cast<const char *>(&Header),
162  sizeof(dxbc::ProgramHeader));
163  if (P.Program->DXIL) {
164  if (BitcodeOffset > sizeof(dxbc::BitcodeHeader)) {
165  uint32_t PadBytes = BitcodeOffset - sizeof(dxbc::BitcodeHeader);
166  OS.write_zeros(PadBytes);
167  }
168  OS.write(reinterpret_cast<char *>(P.Program->DXIL->data()),
169  P.Program->DXIL->size());
170  }
171  break;
172  }
173  case dxbc::PartType::SFI0: {
174  // If we don't have any flags we can continue here and the data will be
175  // zeroed out.
176  if (!P.Flags.has_value())
177  continue;
178  uint64_t Flags = P.Flags->getEncodedFlags();
180  sys::swapByteOrder(Flags);
181  OS.write(reinterpret_cast<char *>(&Flags), sizeof(uint64_t));
182  break;
183  }
184  case dxbc::PartType::HASH: {
185  if (!P.Hash.has_value())
186  continue;
187  dxbc::ShaderHash Hash = {0, {0}};
188  if (P.Hash->IncludesSource)
189  Hash.Flags |= static_cast<uint32_t>(dxbc::HashFlags::IncludesSource);
190  memcpy(&Hash.Digest[0], &P.Hash->Digest[0], 16);
192  Hash.swapBytes();
193  OS.write(reinterpret_cast<char *>(&Hash), sizeof(dxbc::ShaderHash));
194  break;
195  }
197  break; // Skip any handling for unrecognized parts.
198  }
199  uint64_t BytesWritten = OS.tell() - DataStart;
200  RollingOffset += BytesWritten;
201  if (BytesWritten < PartSize)
202  OS.write_zeros(PartSize - BytesWritten);
203  RollingOffset += PartSize;
204  }
205 }
206 
208  if (Error Err = computePartOffsets())
209  return Err;
210  writeHeader(OS);
211  writeParts(OS);
212  return Error::success();
213 }
214 
215 namespace llvm {
216 namespace yaml {
217 
219  ErrorHandler EH) {
220  DXContainerWriter Writer(Doc);
221  if (Error Err = Writer.write(Out)) {
223  [&](const ErrorInfoBase &Err) { EH(Err.message()); });
224  return false;
225  }
226  return true;
227 }
228 
229 } // namespace yaml
230 } // namespace llvm
llvm::raw_ostream::tell
uint64_t tell() const
tell - Return the current offset with the file.
Definition: raw_ostream.h:135
llvm::errc::invalid_argument
@ invalid_argument
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ObjectYAML.h
llvm::sys::IsBigEndianHost
constexpr bool IsBigEndianHost
Definition: SwapByteOrder.h:98
llvm::errc::result_out_of_range
@ result_out_of_range
llvm::sys::swapByteOrder
void swapByteOrder(T &Value)
Definition: SwapByteOrder.h:158
llvm::raw_ostream::write_zeros
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
Definition: raw_ostream.cpp:499
P
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
Definition: README-SSE.txt:411
llvm::write
Error write(MCStreamer &Out, ArrayRef< std::string > Inputs)
Definition: DWP.cpp:549
llvm::SmallVector< uint32_t >
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::dxbc::PartType::Unknown
@ Unknown
Error.h
Errc.h
llvm::dxbc::PartType
PartType
Definition: DXContainer.h:131
llvm::dxbc::PartHeader
Use this type to describe the size and type of a DXIL container part.
Definition: DXContainer.h:85
llvm::dxbc::ShaderHash::swapBytes
void swapBytes()
Definition: DXContainer.h:55
llvm::dxbc::ShaderHash::Flags
uint32_t Flags
Definition: DXContainer.h:50
llvm::raw_ostream::write
raw_ostream & write(unsigned char C)
Definition: raw_ostream.cpp:218
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
llvm::yaml::yaml2dxcontainer
bool yaml2dxcontainer(DXContainerYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH)
Definition: DXContainerEmitter.cpp:218
llvm::ErrorInfoBase
Base class for error info classes.
Definition: Error.h:46
llvm::function_ref
An efficient, type-erasing, non-owning reference to a callable.
Definition: STLFunctionalExtras.h:36
llvm::dxbc::parsePartType
PartType parsePartType(StringRef S)
Definition: DXContainer.cpp:20
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:264
uint64_t
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
I
#define I(x, y, z)
Definition: MD5.cpp:58
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::codeview::CodeViewContainer::ObjectFile
@ ObjectFile
DXContainer.h
yaml2obj.h
if
if(llvm_vc STREQUAL "") set(fake_version_inc "$
Definition: CMakeLists.txt:14
llvm::dxbc::HashFlags::IncludesSource
@ IncludesSource
uint32_t
llvm::dxbc::BitcodeHeader
Definition: DXContainer.h:96
llvm::DXContainerYAML::Object
Definition: DXContainerYAML.h:83
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1238
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::zip
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition: STLExtras.h:879
llvm::dxbc::ShaderHash::Digest
uint8_t Digest[16]
Definition: DXContainer.h:51
llvm::dxbc::Header
Definition: DXContainer.h:68
llvm::omp::RTLDependInfoFields::Flags
@ Flags
raw_ostream.h
llvm::SI::KernelInputOffsets::Offsets
Offsets
Offsets in bytes from the start of the input buffer.
Definition: SIInstrInfo.h:1314
llvm::dxbc::ShaderHash
Definition: DXContainer.h:49
llvm::dxbc::ProgramHeader
Definition: DXContainer.h:113
llvm::handleAllErrors
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition: Error.h:965
llvm::DXContainerYAML::Part
Definition: DXContainerYAML.h:73
write
static void write(bool isBE, void *P, T V)
Definition: RuntimeDyldELF.cpp:37