|
| 1 | +//===- YkIR/YkIRWRiter.cpp -- Yk JIT IR Serialiaser---------------------===// |
| 2 | +// |
| 3 | +// Converts an LLVM module into Yk's on-disk AOT IR. |
| 4 | +// |
| 5 | +//===-------------------------------------------------------------------===// |
| 6 | + |
| 7 | +#include "llvm/ADT/Triple.h" |
| 8 | +#include "llvm/BinaryFormat/ELF.h" |
| 9 | +#include "llvm/IR/Constants.h" |
| 10 | +#include "llvm/IR/Module.h" |
| 11 | +#include "llvm/MC/MCContext.h" |
| 12 | +#include "llvm/MC/MCSectionELF.h" |
| 13 | +#include "llvm/MC/MCStreamer.h" |
| 14 | + |
| 15 | +using namespace llvm; |
| 16 | +using namespace std; |
| 17 | + |
| 18 | +namespace { |
| 19 | + |
| 20 | +const char *SectionName = ".yk_ir"; |
| 21 | +const uint32_t Magic = 0xedd5f00d; |
| 22 | +const uint32_t Version = 0; |
| 23 | + |
| 24 | +enum OpCode { |
| 25 | + Nop = 0, |
| 26 | +}; |
| 27 | + |
| 28 | +class YkIRWriter { |
| 29 | +private: |
| 30 | + Module &M; |
| 31 | + MCStreamer &OutStreamer; |
| 32 | + |
| 33 | +public: |
| 34 | + YkIRWriter(Module &M, MCStreamer &OutStreamer) |
| 35 | + : M(M), OutStreamer(OutStreamer) {} |
| 36 | + |
| 37 | + // Serialises a null-terminated string. |
| 38 | + void serialiseString(StringRef S) { |
| 39 | + OutStreamer.emitBinaryData(S); |
| 40 | + OutStreamer.emitInt8(0); // null terminator. |
| 41 | + } |
| 42 | + |
| 43 | + void serialiseBlock(BasicBlock &BB) { |
| 44 | + // num_instrs: |
| 45 | + OutStreamer.emitSizeT(BB.size()); |
| 46 | + // instrs: |
| 47 | + for (Instruction &I : BB) { |
| 48 | + (void)I; |
| 49 | + OutStreamer.emitInt8(OpCode::Nop); |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + void serialiseFunc(Function &F) { |
| 54 | + // name: |
| 55 | + serialiseString(F.getName()); |
| 56 | + // num_blocks: |
| 57 | + OutStreamer.emitSizeT(F.size()); |
| 58 | + // blocks: |
| 59 | + for (BasicBlock &BB : F) { |
| 60 | + serialiseBlock(BB); |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + void serialise() { |
| 65 | + // header: |
| 66 | + OutStreamer.emitInt32(Magic); |
| 67 | + OutStreamer.emitInt32(Version); |
| 68 | + |
| 69 | + // num_funcs: |
| 70 | + OutStreamer.emitSizeT(M.size()); |
| 71 | + // funcs: |
| 72 | + for (Function &F : M) { |
| 73 | + serialiseFunc(F); |
| 74 | + } |
| 75 | + } |
| 76 | +}; |
| 77 | +} // anonymous namespace |
| 78 | + |
| 79 | +// Create an ELF section for storing Yk IR into. |
| 80 | +MCSection *createYkIRSection(MCContext &Ctx, const MCSection *TextSec) { |
| 81 | + if (Ctx.getObjectFileType() != MCContext::IsELF) |
| 82 | + return nullptr; |
| 83 | + |
| 84 | + const MCSectionELF *ElfSec = static_cast<const MCSectionELF *>(TextSec); |
| 85 | + unsigned Flags = ELF::SHF_LINK_ORDER; |
| 86 | + StringRef GroupName; |
| 87 | + |
| 88 | + // Ensure the loader loads it. |
| 89 | + Flags |= ELF::SHF_ALLOC; |
| 90 | + |
| 91 | + return Ctx.getELFSection(SectionName, ELF::SHT_LLVM_BB_ADDR_MAP, Flags, 0, |
| 92 | + GroupName, true, ElfSec->getUniqueID(), |
| 93 | + cast<MCSymbolELF>(TextSec->getBeginSymbol())); |
| 94 | +} |
| 95 | + |
| 96 | +// Emit a start/end IR marker. |
| 97 | +// |
| 98 | +// The JIT uses a start and end marker to make a Rust slice of the IR. |
| 99 | +void emitStartOrEndSymbol(MCContext &MCtxt, MCStreamer &OutStreamer, |
| 100 | + bool Start) { |
| 101 | + std::string SymName("ykllvm.yk_ir."); |
| 102 | + if (Start) |
| 103 | + SymName.append("start"); |
| 104 | + else |
| 105 | + SymName.append("stop"); |
| 106 | + |
| 107 | + MCSymbol *Sym = MCtxt.getOrCreateSymbol(SymName); |
| 108 | + OutStreamer.emitSymbolAttribute(Sym, llvm::MCSA_Global); |
| 109 | + OutStreamer.emitLabel(Sym); |
| 110 | +} |
| 111 | + |
| 112 | +namespace llvm { |
| 113 | + |
| 114 | +// Emit Yk IR into the resulting ELF binary. |
| 115 | +void embedYkIR(MCContext &Ctx, MCStreamer &OutStreamer, Module &M) { |
| 116 | + MCSection *YkIRSec = |
| 117 | + createYkIRSection(Ctx, std::get<0>(OutStreamer.getCurrentSection())); |
| 118 | + |
| 119 | + OutStreamer.pushSection(); |
| 120 | + OutStreamer.switchSection(YkIRSec); |
| 121 | + emitStartOrEndSymbol(Ctx, OutStreamer, true); |
| 122 | + YkIRWriter(M, OutStreamer).serialise(); |
| 123 | + emitStartOrEndSymbol(Ctx, OutStreamer, false); |
| 124 | + OutStreamer.popSection(); |
| 125 | +} |
| 126 | +} // namespace llvm |
0 commit comments