xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/AsmPrinter/ErlangGCPrinter.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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