Line data Source code
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 3 : 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 :
45 3 : void ErlangGCPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
46 : AsmPrinter &AP) {
47 : MCStreamer &OS = *AP.OutStreamer;
48 3 : unsigned IntPtrSize = M.getDataLayout().getPointerSize();
49 :
50 : // Put this in a custom .note section.
51 3 : OS.SwitchSection(
52 6 : AP.getObjFileLowering().getContext().getELFSection(".note.gc",
53 3 : ELF::SHT_PROGBITS, 0));
54 :
55 : // For each function...
56 : for (GCModuleInfo::FuncInfoVec::iterator FI = Info.funcinfo_begin(),
57 : IE = Info.funcinfo_end();
58 6 : FI != IE; ++FI) {
59 : GCFunctionInfo &MD = **FI;
60 9 : 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 5 : AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
77 :
78 : // Emit PointCount.
79 6 : OS.AddComment("safe point count");
80 3 : AP.emitInt16(MD.size());
81 :
82 : // And each safe point...
83 6 : for (GCFunctionInfo::iterator PI = MD.begin(), PE = MD.end(); PI != PE;
84 : ++PI) {
85 : // Emit the address of the safe point.
86 6 : OS.AddComment("safe point address");
87 3 : MCSymbol *Label = PI->Label;
88 3 : 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 6 : OS.AddComment("stack frame size (in words)");
97 3 : AP.emitInt16(MD.getFrameSize() / IntPtrSize);
98 :
99 : // Emit stack arity, i.e. the number of stacked arguments.
100 3 : unsigned RegisteredArgs = IntPtrSize == 4 ? 5 : 6;
101 3 : unsigned StackArity = MD.getFunction().arg_size() > RegisteredArgs
102 0 : ? MD.getFunction().arg_size() - RegisteredArgs
103 3 : : 0;
104 6 : OS.AddComment("stack arity");
105 3 : AP.emitInt16(StackArity);
106 :
107 : // Emit the number of live roots in the function.
108 6 : OS.AddComment("live root count");
109 3 : 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 3 : LI != LE; ++LI) {
115 : // Emit live root's offset within the stack frame.
116 0 : OS.AddComment("stack index (offset / wordsize)");
117 0 : AP.emitInt16(LI->StackOffset / IntPtrSize);
118 : }
119 : }
120 3 : }
121 :
122 0 : void llvm::linkErlangGCPrinter() {}
|