MCDXContainerWriter.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //===- llvm/MC/MCDXContainerWriter.cpp - DXContainer Writer -----*- C++ -*-===//
  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. #include "llvm/MC/MCDXContainerWriter.h"
  9. #include "llvm/BinaryFormat/DXContainer.h"
  10. #include "llvm/MC/MCAsmLayout.h"
  11. #include "llvm/MC/MCAssembler.h"
  12. #include "llvm/MC/MCContext.h"
  13. #include "llvm/MC/MCSection.h"
  14. #include "llvm/MC/MCValue.h"
  15. #include "llvm/Support/Alignment.h"
  16. #include "llvm/Support/EndianStream.h"
  17. using namespace llvm;
  18. MCDXContainerTargetWriter::~MCDXContainerTargetWriter() {}
  19. namespace {
  20. class DXContainerObjectWriter : public MCObjectWriter {
  21. ::support::endian::Writer W;
  22. /// The target specific DXContainer writer instance.
  23. std::unique_ptr<MCDXContainerTargetWriter> TargetObjectWriter;
  24. public:
  25. DXContainerObjectWriter(std::unique_ptr<MCDXContainerTargetWriter> MOTW,
  26. raw_pwrite_stream &OS)
  27. : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {}
  28. ~DXContainerObjectWriter() override {}
  29. private:
  30. void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
  31. const MCFragment *Fragment, const MCFixup &Fixup,
  32. MCValue Target, uint64_t &FixedValue) override {}
  33. void executePostLayoutBinding(MCAssembler &Asm,
  34. const MCAsmLayout &Layout) override {}
  35. uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
  36. };
  37. } // namespace
  38. uint64_t DXContainerObjectWriter::writeObject(MCAssembler &Asm,
  39. const MCAsmLayout &Layout) {
  40. // Start the file size as the header plus the size of the part offsets.
  41. // Presently DXContainer files usually contain 7-10 parts. Reserving space for
  42. // 16 part offsets gives us a little room for growth.
  43. llvm::SmallVector<uint64_t, 16> PartOffsets;
  44. uint64_t PartOffset = 0;
  45. for (const MCSection &Sec : Asm) {
  46. uint64_t SectionSize = Layout.getSectionAddressSize(&Sec);
  47. // Skip empty sections.
  48. if (SectionSize == 0)
  49. continue;
  50. assert(SectionSize < std::numeric_limits<uint32_t>::max() &&
  51. "Section size too large for DXContainer");
  52. PartOffsets.push_back(PartOffset);
  53. PartOffset += sizeof(dxbc::PartHeader) + SectionSize;
  54. PartOffset = alignTo(PartOffset, Align(4ul));
  55. // The DXIL part also writes a program header, so we need to include its
  56. // size when computing the offset for a part after the DXIL part.
  57. if (Sec.getName() == "DXIL")
  58. PartOffset += sizeof(dxbc::ProgramHeader);
  59. }
  60. assert(PartOffset < std::numeric_limits<uint32_t>::max() &&
  61. "Part data too large for DXContainer");
  62. uint64_t PartStart =
  63. sizeof(dxbc::Header) + (PartOffsets.size() * sizeof(uint32_t));
  64. uint64_t FileSize = PartStart + PartOffset;
  65. assert(FileSize < std::numeric_limits<uint32_t>::max() &&
  66. "File size too large for DXContainer");
  67. // Write the header.
  68. W.write<char>({'D', 'X', 'B', 'C'});
  69. // Write 16-bytes of 0's for the hash.
  70. W.OS.write_zeros(16);
  71. // Write 1.0 for file format version.
  72. W.write<uint16_t>(1u);
  73. W.write<uint16_t>(0u);
  74. // Write the file size.
  75. W.write<uint32_t>(static_cast<uint32_t>(FileSize));
  76. // Write the number of parts.
  77. W.write<uint32_t>(static_cast<uint32_t>(PartOffsets.size()));
  78. // Write the offsets for the part headers for each part.
  79. for (uint64_t Offset : PartOffsets)
  80. W.write<uint32_t>(static_cast<uint32_t>(PartStart + Offset));
  81. for (const MCSection &Sec : Asm) {
  82. uint64_t SectionSize = Layout.getSectionAddressSize(&Sec);
  83. // Skip empty sections.
  84. if (SectionSize == 0)
  85. continue;
  86. unsigned Start = W.OS.tell();
  87. // Write section header.
  88. W.write<char>(ArrayRef<char>(Sec.getName().data(), 4));
  89. uint64_t PartSize = SectionSize;
  90. if (Sec.getName() == "DXIL")
  91. PartSize += sizeof(dxbc::ProgramHeader);
  92. // DXContainer parts should be 4-byte aligned.
  93. PartSize = alignTo(PartSize, Align(4));
  94. W.write<uint32_t>(static_cast<uint32_t>(PartSize));
  95. if (Sec.getName() == "DXIL") {
  96. dxbc::ProgramHeader Header;
  97. memset(reinterpret_cast<void *>(&Header), 0, sizeof(dxbc::ProgramHeader));
  98. const Triple &TT = Asm.getContext().getTargetTriple();
  99. VersionTuple Version = TT.getOSVersion();
  100. Header.MajorVersion = static_cast<uint8_t>(Version.getMajor());
  101. if (Version.getMinor())
  102. Header.MinorVersion = static_cast<uint8_t>(*Version.getMinor());
  103. if (TT.hasEnvironment())
  104. Header.ShaderKind =
  105. static_cast<uint16_t>(TT.getEnvironment() - Triple::Pixel);
  106. // The program header's size field is in 32-bit words.
  107. Header.Size = (SectionSize + sizeof(dxbc::ProgramHeader) + 3) / 4;
  108. memcpy(Header.Bitcode.Magic, "DXIL", 4);
  109. Header.Bitcode.Offset = sizeof(dxbc::BitcodeHeader);
  110. Header.Bitcode.Size = SectionSize;
  111. if (sys::IsBigEndianHost)
  112. Header.swapBytes();
  113. W.write<char>(ArrayRef<char>(reinterpret_cast<char *>(&Header),
  114. sizeof(dxbc::ProgramHeader)));
  115. }
  116. Asm.writeSectionData(W.OS, &Sec, Layout);
  117. unsigned Size = W.OS.tell() - Start;
  118. W.OS.write_zeros(offsetToAlignment(Size, Align(4)));
  119. }
  120. return 0;
  121. }
  122. std::unique_ptr<MCObjectWriter> llvm::createDXContainerObjectWriter(
  123. std::unique_ptr<MCDXContainerTargetWriter> MOTW, raw_pwrite_stream &OS) {
  124. return std::make_unique<DXContainerObjectWriter>(std::move(MOTW), OS);
  125. }