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