118 lines · cpp
1//===- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter ----------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the compiler plugin that is used in order to emit10// garbage collection information in a convenient layout for parsing and11// loading in the Erlang/OTP runtime.12//13//===----------------------------------------------------------------------===//14 15#include "llvm/BinaryFormat/ELF.h"16#include "llvm/CodeGen/AsmPrinter.h"17#include "llvm/CodeGen/GCMetadata.h"18#include "llvm/CodeGen/GCMetadataPrinter.h"19#include "llvm/IR/BuiltinGCs.h"20#include "llvm/IR/DataLayout.h"21#include "llvm/IR/Function.h"22#include "llvm/IR/Module.h"23#include "llvm/MC/MCContext.h"24#include "llvm/MC/MCSectionELF.h"25#include "llvm/MC/MCStreamer.h"26#include "llvm/Target/TargetLoweringObjectFile.h"27 28using namespace llvm;29 30namespace {31 32class ErlangGCPrinter : public GCMetadataPrinter {33public:34 void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;35};36 37} // end anonymous namespace38 39static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>40 X("erlang", "erlang-compatible garbage collector");41 42void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,43 AsmPrinter &AP) {44 MCStreamer &OS = *AP.OutStreamer;45 unsigned IntPtrSize = M.getDataLayout().getPointerSize();46 47 // Put this in a custom .note section.48 OS.switchSection(AP.getObjFileLowering().getContext().getELFSection(49 ".note.gc", ELF::SHT_PROGBITS, 0));50 51 // For each function...52 for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),53 IE = Info.funcinfo_end();54 FI != IE; ++FI) {55 GCFunctionInfo &MD = **FI;56 if (MD.getStrategy().getName() != getStrategy().getName())57 // this function is managed by some other GC58 continue;59 /** A compact GC layout. Emit this data structure:60 *61 * struct {62 * int16_t PointCount;63 * void *SafePointAddress[PointCount];64 * int16_t StackFrameSize; (in words)65 * int16_t StackArity;66 * int16_t LiveCount;67 * int16_t LiveOffsets[LiveCount];68 * } __gcmap_<FUNCTIONNAME>;69 **/70 71 // Align to address width.72 AP.emitAlignment(IntPtrSize == 4 ? Align(4) : Align(8));73 74 // Emit PointCount.75 OS.AddComment("safe point count");76 AP.emitInt16(MD.size());77 78 // And each safe point...79 for (const GCPoint &P : MD) {80 // Emit the address of the safe point.81 OS.AddComment("safe point address");82 MCSymbol *Label = P.Label;83 AP.emitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/);84 }85 86 // Stack information never change in safe points! Only print info from the87 // first call-site.88 GCFunctionInfo::iterator PI = MD.begin();89 90 // Emit the stack frame size.91 OS.AddComment("stack frame size (in words)");92 AP.emitInt16(MD.getFrameSize() / IntPtrSize);93 94 // Emit stack arity, i.e. the number of stacked arguments.95 unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;96 unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs97 ? MD.getFunction().arg_size() - RegisteredArgs98 : 0;99 OS.AddComment("stack arity");100 AP.emitInt16(StackArity);101 102 // Emit the number of live roots in the function.103 OS.AddComment("live root count");104 AP.emitInt16(MD.live_size(PI));105 106 // And for each live root...107 for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),108 LE = MD.live_end(PI);109 LI != LE; ++LI) {110 // Emit live root's offset within the stack frame.111 OS.AddComment("stack index (offset / wordsize)");112 AP.emitInt16(LI->StackOffset / IntPtrSize);113 }114 }115}116 117void llvm::linkErlangGCPrinter() {}118