10b57cec5SDimitry Andric //===- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the compiler plugin that is used in order to emit
100b57cec5SDimitry Andric // garbage collection information in a convenient layout for parsing and
110b57cec5SDimitry Andric // loading in the Erlang/OTP runtime.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/GCMetadata.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/GCMetadataPrinter.h"
19fe6060f1SDimitry Andric #include "llvm/IR/BuiltinGCs.h"
200b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
210b57cec5SDimitry Andric #include "llvm/IR/Function.h"
220b57cec5SDimitry Andric #include "llvm/IR/Module.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
260b57cec5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric namespace {
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric class ErlangGCPrinter : public GCMetadataPrinter {
330b57cec5SDimitry Andric public:
340b57cec5SDimitry Andric void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
350b57cec5SDimitry Andric };
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric } // end anonymous namespace
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>
400b57cec5SDimitry Andric X("erlang", "erlang-compatible garbage collector");
410b57cec5SDimitry Andric
finishAssembly(Module & M,GCModuleInfo & Info,AsmPrinter & AP)420b57cec5SDimitry Andric void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
430b57cec5SDimitry Andric AsmPrinter &AP) {
440b57cec5SDimitry Andric MCStreamer &OS = *AP.OutStreamer;
450b57cec5SDimitry Andric unsigned IntPtrSize = M.getDataLayout().getPointerSize();
460b57cec5SDimitry Andric
470b57cec5SDimitry Andric // Put this in a custom .note section.
48*81ad6265SDimitry Andric OS.switchSection(AP.getObjFileLowering().getContext().getELFSection(
49*81ad6265SDimitry Andric ".note.gc", ELF::SHT_PROGBITS, 0));
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric // For each function...
520b57cec5SDimitry Andric for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),
530b57cec5SDimitry Andric IE = Info.funcinfo_end();
540b57cec5SDimitry Andric FI != IE; ++FI) {
550b57cec5SDimitry Andric GCFunctionInfo &MD = **FI;
560b57cec5SDimitry Andric if (MD.getStrategy().getName() != getStrategy().getName())
570b57cec5SDimitry Andric // this function is managed by some other GC
580b57cec5SDimitry Andric continue;
590b57cec5SDimitry Andric /** A compact GC layout. Emit this data structure:
600b57cec5SDimitry Andric *
610b57cec5SDimitry Andric * struct {
620b57cec5SDimitry Andric * int16_t PointCount;
630b57cec5SDimitry Andric * void *SafePointAddress[PointCount];
640b57cec5SDimitry Andric * int16_t StackFrameSize; (in words)
650b57cec5SDimitry Andric * int16_t StackArity;
660b57cec5SDimitry Andric * int16_t LiveCount;
670b57cec5SDimitry Andric * int16_t LiveOffsets[LiveCount];
680b57cec5SDimitry Andric * } __gcmap_<FUNCTIONNAME>;
690b57cec5SDimitry Andric **/
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric // Align to address width.
725ffd83dbSDimitry Andric AP.emitAlignment(IntPtrSize == 4 ? Align(4) : Align(8));
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric // Emit PointCount.
750b57cec5SDimitry Andric OS.AddComment("safe point count");
760b57cec5SDimitry Andric AP.emitInt16(MD.size());
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric // And each safe point...
79fe6060f1SDimitry Andric for (const GCPoint &P : MD) {
800b57cec5SDimitry Andric // Emit the address of the safe point.
810b57cec5SDimitry Andric OS.AddComment("safe point address");
82fe6060f1SDimitry Andric MCSymbol *Label = P.Label;
835ffd83dbSDimitry Andric AP.emitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/);
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric // Stack information never change in safe points! Only print info from the
870b57cec5SDimitry Andric // first call-site.
880b57cec5SDimitry Andric GCFunctionInfo::iterator PI = MD.begin();
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric // Emit the stack frame size.
910b57cec5SDimitry Andric OS.AddComment("stack frame size (in words)");
920b57cec5SDimitry Andric AP.emitInt16(MD.getFrameSize() / IntPtrSize);
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric // Emit stack arity, i.e. the number of stacked arguments.
950b57cec5SDimitry Andric unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
960b57cec5SDimitry Andric unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs
970b57cec5SDimitry Andric ? MD.getFunction().arg_size() - RegisteredArgs
980b57cec5SDimitry Andric : 0;
990b57cec5SDimitry Andric OS.AddComment("stack arity");
1000b57cec5SDimitry Andric AP.emitInt16(StackArity);
1010b57cec5SDimitry Andric
1020b57cec5SDimitry Andric // Emit the number of live roots in the function.
1030b57cec5SDimitry Andric OS.AddComment("live root count");
1040b57cec5SDimitry Andric AP.emitInt16(MD.live_size(PI));
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric // And for each live root...
1070b57cec5SDimitry Andric for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),
1080b57cec5SDimitry Andric LE = MD.live_end(PI);
1090b57cec5SDimitry Andric LI != LE; ++LI) {
1100b57cec5SDimitry Andric // Emit live root's offset within the stack frame.
1110b57cec5SDimitry Andric OS.AddComment("stack index (offset / wordsize)");
1120b57cec5SDimitry Andric AP.emitInt16(LI->StackOffset / IntPtrSize);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric
linkErlangGCPrinter()1170b57cec5SDimitry Andric void llvm::linkErlangGCPrinter() {}
118