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