1 //===- ErlangGCPrinter.cpp - Erlang/OTP frametable emitter ----------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the compiler plugin that is used in order to emit
11 // garbage collection information in a convenient layout for parsing and
12 // loading in the Erlang/OTP runtime.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "llvm/BinaryFormat/ELF.h"
17 #include "llvm/CodeGen/AsmPrinter.h"
18 #include "llvm/CodeGen/GCMetadata.h"
19 #include "llvm/CodeGen/GCMetadataPrinter.h"
20 #include "llvm/CodeGen/GCStrategy.h"
21 #include "llvm/CodeGen/GCs.h"
22 #include "llvm/IR/DataLayout.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/MC/MCContext.h"
26 #include "llvm/MC/MCSectionELF.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/MCSymbol.h"
29 #include "llvm/Target/TargetLoweringObjectFile.h"
30
31 using namespace llvm;
32
33 namespace {
34
35 class ErlangGCPrinter : public GCMetadataPrinter {
36 public:
37 void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
38 };
39
40 } // end anonymous namespace
41
42 static GCMetadataPrinterRegistry::Add<ErlangGCPrinter>
43 X("erlang", "erlang-compatible garbage collector");
44
finishAssembly(Module & M,GCModuleInfo & Info,AsmPrinter & AP)45 void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
46 AsmPrinter &AP) {
47 MCStreamer &OS = *AP.OutStreamer;
48 unsigned IntPtrSize = M.getDataLayout().getPointerSize();
49
50 // Put this in a custom .note section.
51 OS.SwitchSection(
52 AP.getObjFileLowering().getContext().getELFSection(".note.gc",
53 ELF::SHT_PROGBITS, 0));
54
55 // For each function...
56 for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),
57 IE = Info.funcinfo_end();
58 FI != IE; ++FI) {
59 GCFunctionInfo &MD = **FI;
60 if (MD.getStrategy().getName() != getStrategy().getName())
61 // this function is managed by some other GC
62 continue;
63 /** A compact GC layout. Emit this data structure:
64 *
65 * struct {
66 * int16_t PointCount;
67 * void *SafePointAddress[PointCount];
68 * int16_t StackFrameSize; (in words)
69 * int16_t StackArity;
70 * int16_t LiveCount;
71 * int16_t LiveOffsets[LiveCount];
72 * } __gcmap_<FUNCTIONNAME>;
73 **/
74
75 // Align to address width.
76 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
77
78 // Emit PointCount.
79 OS.AddComment("safe point count");
80 AP.emitInt16(MD.size());
81
82 // And each safe point...
83 for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE;
84 ++PI) {
85 // Emit the address of the safe point.
86 OS.AddComment("safe point address");
87 MCSymbol *Label = PI->Label;
88 AP.EmitLabelPlusOffset(Label /*Hi*/, 0 /*Offset*/, 4 /*Size*/);
89 }
90
91 // Stack information never change in safe points! Only print info from the
92 // first call-site.
93 GCFunctionInfo::iterator PI = MD.begin();
94
95 // Emit the stack frame size.
96 OS.AddComment("stack frame size (in words)");
97 AP.emitInt16(MD.getFrameSize() / IntPtrSize);
98
99 // Emit stack arity, i.e. the number of stacked arguments.
100 unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
101 unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs
102 ? MD.getFunction().arg_size() - RegisteredArgs
103 : 0;
104 OS.AddComment("stack arity");
105 AP.emitInt16(StackArity);
106
107 // Emit the number of live roots in the function.
108 OS.AddComment("live root count");
109 AP.emitInt16(MD.live_size(PI));
110
111 // And for each live root...
112 for (GCFunctionInfo::live_iterator LI = MD.live_begin(PI),
113 LE = MD.live_end(PI);
114 LI != LE; ++LI) {
115 // Emit live root's offset within the stack frame.
116 OS.AddComment("stack index (offset / wordsize)");
117 AP.emitInt16(LI->StackOffset / IntPtrSize);
118 }
119 }
120 }
121
linkErlangGCPrinter()122 void llvm::linkErlangGCPrinter() {}
123