17a7e6055SDimitry Andric //===- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter ----------------===//
2139f7f9bSDimitry Andric //
3139f7f9bSDimitry Andric //                     The LLVM Compiler Infrastructure
4139f7f9bSDimitry Andric //
5139f7f9bSDimitry Andric // This file is distributed under the University of Illinois Open Source
6139f7f9bSDimitry Andric // License. See LICENSE.TXT for details.
7139f7f9bSDimitry Andric //
8139f7f9bSDimitry Andric //===----------------------------------------------------------------------===//
9139f7f9bSDimitry Andric //
10139f7f9bSDimitry Andric // This file implements the compiler plugin that is used in order to emit
11139f7f9bSDimitry Andric // garbage collection information in a convenient layout for parsing and
12139f7f9bSDimitry Andric // loading in the Erlang/OTP runtime.
13139f7f9bSDimitry Andric //
14139f7f9bSDimitry Andric //===----------------------------------------------------------------------===//
15139f7f9bSDimitry Andric 
16db17bf38SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
17139f7f9bSDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
18*b5893f02SDimitry Andric #include "llvm/CodeGen/BuiltinGCs.h"
197a7e6055SDimitry Andric #include "llvm/CodeGen/GCMetadata.h"
20139f7f9bSDimitry Andric #include "llvm/CodeGen/GCMetadataPrinter.h"
217a7e6055SDimitry Andric #include "llvm/CodeGen/GCStrategy.h"
22139f7f9bSDimitry Andric #include "llvm/IR/DataLayout.h"
23139f7f9bSDimitry Andric #include "llvm/IR/Function.h"
247a7e6055SDimitry Andric #include "llvm/IR/Module.h"
25139f7f9bSDimitry Andric #include "llvm/MC/MCContext.h"
26139f7f9bSDimitry Andric #include "llvm/MC/MCSectionELF.h"
27139f7f9bSDimitry Andric #include "llvm/MC/MCStreamer.h"
28139f7f9bSDimitry Andric #include "llvm/MC/MCSymbol.h"
294ba319b5SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
30139f7f9bSDimitry Andric 
31139f7f9bSDimitry Andric using namespace llvm;
32139f7f9bSDimitry Andric 
33139f7f9bSDimitry Andric namespace {
34139f7f9bSDimitry Andric 
35139f7f9bSDimitry Andric class ErlangGCPrinter : public GCMetadataPrinter {
36139f7f9bSDimitry Andric public:
37ff0cc061SDimitry Andric   void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
38139f7f9bSDimitry Andric };
397a7e6055SDimitry Andric 
407a7e6055SDimitry Andric } // end anonymous namespace
41139f7f9bSDimitry Andric 
42139f7f9bSDimitry Andric static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>
43139f7f9bSDimitry Andric     X("erlang", "erlang-compatible garbage collector");
44139f7f9bSDimitry Andric 
finishAssembly(Module & M,GCModuleInfo & Info,AsmPrinter & AP)4539d628a0SDimitry Andric void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
4639d628a0SDimitry Andric                                      AsmPrinter &AP) {
47ff0cc061SDimitry Andric   MCStreamer &OS = *AP.OutStreamer;
487d523365SDimitry Andric   unsigned IntPtrSize = M.getDataLayout().getPointerSize();
49139f7f9bSDimitry Andric 
50139f7f9bSDimitry Andric   // Put this in a custom .note section.
51ff0cc061SDimitry Andric   OS.SwitchSection(
52ff0cc061SDimitry Andric       AP.getObjFileLowering().getContext().getELFSection(".note.gc",
53ff0cc061SDimitry Andric                                                          ELF::SHT_PROGBITS, 0));
54139f7f9bSDimitry Andric 
55139f7f9bSDimitry Andric   // For each function...
5639d628a0SDimitry Andric   for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),
5739d628a0SDimitry Andric                                            IE = Info.funcinfo_end();
5839d628a0SDimitry Andric        FI != IE; ++FI) {
59139f7f9bSDimitry Andric     GCFunctionInfo &MD = **FI;
6039d628a0SDimitry Andric     if (MD.getStrategy().getName() != getStrategy().getName())
6139d628a0SDimitry Andric       // this function is managed by some other GC
6239d628a0SDimitry Andric       continue;
63139f7f9bSDimitry Andric     /** A compact GC layout. Emit this data structure:
64139f7f9bSDimitry Andric      *
65139f7f9bSDimitry Andric      * struct {
66139f7f9bSDimitry Andric      *   int16_t PointCount;
67139f7f9bSDimitry Andric      *   void *SafePointAddress[PointCount];
68139f7f9bSDimitry Andric      *   int16_t StackFrameSize; (in words)
69139f7f9bSDimitry Andric      *   int16_t StackArity;
70139f7f9bSDimitry Andric      *   int16_t LiveCount;
71139f7f9bSDimitry Andric      *   int16_t LiveOffsets[LiveCount];
72139f7f9bSDimitry Andric      * } __gcmap_<FUNCTIONNAME>;
73139f7f9bSDimitry Andric      **/
74139f7f9bSDimitry Andric 
75139f7f9bSDimitry Andric     // Align to address width.
76139f7f9bSDimitry Andric     AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
77139f7f9bSDimitry Andric 
78139f7f9bSDimitry Andric     // Emit PointCount.
79139f7f9bSDimitry Andric     OS.AddComment("safe point count");
804ba319b5SDimitry Andric     AP.emitInt16(MD.size());
81139f7f9bSDimitry Andric 
82139f7f9bSDimitry Andric     // And each safe point...
83139f7f9bSDimitry Andric     for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE;
84139f7f9bSDimitry Andric          ++PI) {
85139f7f9bSDimitry Andric       // Emit the address of the safe point.
86139f7f9bSDimitry Andric       OS.AddComment("safe point address");
87139f7f9bSDimitry Andric       MCSymbol *Label = PI->Label;
88139f7f9bSDimitry Andric       AP.EmitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/);
89139f7f9bSDimitry Andric     }
90139f7f9bSDimitry Andric 
91139f7f9bSDimitry Andric     // Stack information never change in safe points! Only print info from the
92139f7f9bSDimitry Andric     // first call-site.
93139f7f9bSDimitry Andric     GCFunctionInfo::iterator PI = MD.begin();
94139f7f9bSDimitry Andric 
95139f7f9bSDimitry Andric     // Emit the stack frame size.
96139f7f9bSDimitry Andric     OS.AddComment("stack frame size (in words)");
974ba319b5SDimitry Andric     AP.emitInt16(MD.getFrameSize() / IntPtrSize);
98139f7f9bSDimitry Andric 
99139f7f9bSDimitry Andric     // Emit stack arity, i.e. the number of stacked arguments.
100139f7f9bSDimitry Andric     unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
101ff0cc061SDimitry Andric     unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs
102ff0cc061SDimitry Andric                               ? MD.getFunction().arg_size() - RegisteredArgs
103ff0cc061SDimitry Andric                               : 0;
104139f7f9bSDimitry Andric     OS.AddComment("stack arity");
1054ba319b5SDimitry Andric     AP.emitInt16(StackArity);
106139f7f9bSDimitry Andric 
107139f7f9bSDimitry Andric     // Emit the number of live roots in the function.
108139f7f9bSDimitry Andric     OS.AddComment("live root count");
1094ba319b5SDimitry Andric     AP.emitInt16(MD.live_size(PI));
110139f7f9bSDimitry Andric 
111139f7f9bSDimitry Andric     // And for each live root...
112139f7f9bSDimitry Andric     for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),
113139f7f9bSDimitry Andric                                        LE = MD.live_end(PI);
114139f7f9bSDimitry Andric          LI != LE; ++LI) {
115139f7f9bSDimitry Andric       // Emit live root's offset within the stack frame.
116139f7f9bSDimitry Andric       OS.AddComment("stack index (offset / wordsize)");
1174ba319b5SDimitry Andric       AP.emitInt16(LI->StackOffset / IntPtrSize);
118139f7f9bSDimitry Andric     }
119139f7f9bSDimitry Andric   }
120139f7f9bSDimitry Andric }
1217a7e6055SDimitry Andric 
linkErlangGCPrinter()1227a7e6055SDimitry Andric void llvm::linkErlangGCPrinter() {}
123