Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp
35271 views
//===- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter ----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the compiler plugin that is used in order to emit9// garbage collection information in a convenient layout for parsing and10// loading in the Erlang/OTP runtime.11//12//===----------------------------------------------------------------------===//1314#include "llvm/BinaryFormat/ELF.h"15#include "llvm/CodeGen/AsmPrinter.h"16#include "llvm/CodeGen/GCMetadata.h"17#include "llvm/CodeGen/GCMetadataPrinter.h"18#include "llvm/IR/BuiltinGCs.h"19#include "llvm/IR/DataLayout.h"20#include "llvm/IR/Function.h"21#include "llvm/IR/Module.h"22#include "llvm/MC/MCContext.h"23#include "llvm/MC/MCSectionELF.h"24#include "llvm/MC/MCStreamer.h"25#include "llvm/Target/TargetLoweringObjectFile.h"2627using namespace llvm;2829namespace {3031class ErlangGCPrinter : public GCMetadataPrinter {32public:33void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;34};3536} // end anonymous namespace3738static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>39X("erlang", "erlang-compatible garbage collector");4041void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,42AsmPrinter &AP) {43MCStreamer &OS = *AP.OutStreamer;44unsigned IntPtrSize = M.getDataLayout().getPointerSize();4546// Put this in a custom .note section.47OS.switchSection(AP.getObjFileLowering().getContext().getELFSection(48".note.gc", ELF::SHT_PROGBITS, 0));4950// For each function...51for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),52IE = Info.funcinfo_end();53FI != IE; ++FI) {54GCFunctionInfo &MD = **FI;55if (MD.getStrategy().getName() != getStrategy().getName())56// this function is managed by some other GC57continue;58/** A compact GC layout. Emit this data structure:59*60* struct {61* int16_t PointCount;62* void *SafePointAddress[PointCount];63* int16_t StackFrameSize; (in words)64* int16_t StackArity;65* int16_t LiveCount;66* int16_t LiveOffsets[LiveCount];67* } __gcmap_<FUNCTIONNAME>;68**/6970// Align to address width.71AP.emitAlignment(IntPtrSize == 4 ? Align(4) : Align(8));7273// Emit PointCount.74OS.AddComment("safe point count");75AP.emitInt16(MD.size());7677// And each safe point...78for (const GCPoint &P : MD) {79// Emit the address of the safe point.80OS.AddComment("safe point address");81MCSymbol *Label = P.Label;82AP.emitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/);83}8485// Stack information never change in safe points! Only print info from the86// first call-site.87GCFunctionInfo::iterator PI = MD.begin();8889// Emit the stack frame size.90OS.AddComment("stack frame size (in words)");91AP.emitInt16(MD.getFrameSize() / IntPtrSize);9293// Emit stack arity, i.e. the number of stacked arguments.94unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;95unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs96? MD.getFunction().arg_size() - RegisteredArgs97: 0;98OS.AddComment("stack arity");99AP.emitInt16(StackArity);100101// Emit the number of live roots in the function.102OS.AddComment("live root count");103AP.emitInt16(MD.live_size(PI));104105// And for each live root...106for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),107LE = MD.live_end(PI);108LI != LE; ++LI) {109// Emit live root's offset within the stack frame.110OS.AddComment("stack index (offset / wordsize)");111AP.emitInt16(LI->StackOffset / IntPtrSize);112}113}114}115116void llvm::linkErlangGCPrinter() {}117118119