LLVM  4.0.0
OcamlGCPrinter.cpp
Go to the documentation of this file.
1 //===-- OcamlGCPrinter.cpp - Ocaml 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 printing the assembly code for an Ocaml frametable.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/CodeGen/GCs.h"
15 #include "llvm/ADT/SmallString.h"
18 #include "llvm/IR/DataLayout.h"
19 #include "llvm/IR/Mangler.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/MC/MCAsmInfo.h"
22 #include "llvm/MC/MCContext.h"
23 #include "llvm/MC/MCStreamer.h"
24 #include "llvm/MC/MCSymbol.h"
30 #include <cctype>
31 using namespace llvm;
32 
33 namespace {
34 
35 class OcamlGCMetadataPrinter : public GCMetadataPrinter {
36 public:
37  void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
38  void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
39 };
40 }
41 
43  Y("ocaml", "ocaml 3.10-compatible collector");
44 
46 
47 static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
48  const std::string &MId = M.getModuleIdentifier();
49 
50  std::string SymName;
51  SymName += "caml";
52  size_t Letter = SymName.size();
53  SymName.append(MId.begin(), find(MId, '.'));
54  SymName += "__";
55  SymName += Id;
56 
57  // Capitalize the first letter of the module name.
58  SymName[Letter] = toupper(SymName[Letter]);
59 
60  SmallString<128> TmpStr;
61  Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
62 
63  MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
64 
65  AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
66  AP.OutStreamer->EmitLabel(Sym);
67 }
68 
69 void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
70  AsmPrinter &AP) {
71  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
72  EmitCamlGlobal(M, AP, "code_begin");
73 
74  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
75  EmitCamlGlobal(M, AP, "data_begin");
76 }
77 
78 /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
79 ///
80 /// extern "C" struct align(sizeof(intptr_t)) {
81 /// uint16_t NumDescriptors;
82 /// struct align(sizeof(intptr_t)) {
83 /// void *ReturnAddress;
84 /// uint16_t FrameSize;
85 /// uint16_t NumLiveOffsets;
86 /// uint16_t LiveOffsets[NumLiveOffsets];
87 /// } Descriptors[NumDescriptors];
88 /// } caml${module}__frametable;
89 ///
90 /// Note that this precludes programs from stack frames larger than 64K
91 /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
92 /// either condition is detected in a function which uses the GC.
93 ///
94 void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
95  AsmPrinter &AP) {
96  unsigned IntPtrSize = M.getDataLayout().getPointerSize();
97 
98  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
99  EmitCamlGlobal(M, AP, "code_end");
100 
101  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
102  EmitCamlGlobal(M, AP, "data_end");
103 
104  // FIXME: Why does ocaml emit this??
105  AP.OutStreamer->EmitIntValue(0, IntPtrSize);
106 
107  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
108  EmitCamlGlobal(M, AP, "frametable");
109 
110  int NumDescriptors = 0;
111  for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
112  IE = Info.funcinfo_end();
113  I != IE; ++I) {
114  GCFunctionInfo &FI = **I;
115  if (FI.getStrategy().getName() != getStrategy().getName())
116  // this function is managed by some other GC
117  continue;
118  for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
119  NumDescriptors++;
120  }
121  }
122 
123  if (NumDescriptors >= 1 << 16) {
124  // Very rude!
125  report_fatal_error(" Too much descriptor for ocaml GC");
126  }
127  AP.EmitInt16(NumDescriptors);
128  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
129 
130  for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
131  IE = Info.funcinfo_end();
132  I != IE; ++I) {
133  GCFunctionInfo &FI = **I;
134  if (FI.getStrategy().getName() != getStrategy().getName())
135  // this function is managed by some other GC
136  continue;
137 
138  uint64_t FrameSize = FI.getFrameSize();
139  if (FrameSize >= 1 << 16) {
140  // Very rude!
141  report_fatal_error("Function '" + FI.getFunction().getName() +
142  "' is too large for the ocaml GC! "
143  "Frame size " +
144  Twine(FrameSize) + ">= 65536.\n"
145  "(" +
146  Twine(uintptr_t(&FI)) + ")");
147  }
148 
149  AP.OutStreamer->AddComment("live roots for " +
150  Twine(FI.getFunction().getName()));
151  AP.OutStreamer->AddBlankLine();
152 
153  for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
154  size_t LiveCount = FI.live_size(J);
155  if (LiveCount >= 1 << 16) {
156  // Very rude!
157  report_fatal_error("Function '" + FI.getFunction().getName() +
158  "' is too large for the ocaml GC! "
159  "Live root count " +
160  Twine(LiveCount) + " >= 65536.");
161  }
162 
163  AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
164  AP.EmitInt16(FrameSize);
165  AP.EmitInt16(LiveCount);
166 
168  KE = FI.live_end(J);
169  K != KE; ++K) {
170  if (K->StackOffset >= 1 << 16) {
171  // Very rude!
173  "GC root stack offset is outside of fixed stack frame and out "
174  "of range for ocaml GC!");
175  }
176  AP.EmitInt16(K->StackOffset);
177  }
178 
179  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
180  }
181  }
182 }
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:84
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:39
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:52
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:79
MCSection * getDataSection() const
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:191
std::vector< GCPoint >::iterator iterator
Definition: GCMetadata.h:76
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
An analysis pass which caches information about the entire Module.
Definition: GCMetadata.h:155
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
Definition: Module.h:193
const std::string & getName() const
Return the name of the GC strategy.
Definition: GCStrategy.h:101
void EmitInt16(int Value) const
Emit a short directive and value.
GCStrategy & getStrategy()
getStrategy - Return the GC strategy for the function.
Definition: GCMetadata.h:107
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:67
uint64_t getFrameSize() const
getFrameSize/setFrameSize - Records the function's frame size.
Definition: GCMetadata.h:130
MCSection * getTextSection() const
FuncInfoVec::iterator funcinfo_begin()
Definition: GCMetadata.h:171
size_t live_size(const iterator &p) const
Definition: GCMetadata.h:149
void EmitAlignment(unsigned NumBits, const GlobalObject *GO=nullptr) const
Emit an alignment directive to the specified power of two boundary.
static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id)
auto find(R &&Range, const T &Val) -> decltype(std::begin(Range))
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:757
live_iterator live_begin(const iterator &p)
live_begin/live_end - Iterators for live roots at a given safe point.
Definition: GCMetadata.h:147
Module.h This file contains the declarations for the Module class.
FuncInfoVec::iterator funcinfo_end()
Definition: GCMetadata.h:172
iterator begin()
begin/end - Iterators for safe points.
Definition: GCMetadata.h:135
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
Definition: Module.cpp:384
.type _foo,
Definition: MCDirectives.h:30
MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Definition: MCContext.cpp:114
void getNameWithPrefix(raw_ostream &OS, const GlobalValue *GV, bool CannotUsePrivateLabel) const
Print the appropriate prefix and the specified global variable's name.
Definition: Mangler.cpp:108
#define I(x, y, z)
Definition: MD5.cpp:54
const TargetLoweringObjectFile & getObjFileLowering() const
Return information about object file lowering.
Definition: AsmPrinter.cpp:144
const Function & getFunction() const
getFunction - Return the function to which this metadata applies.
Definition: GCMetadata.h:103
GCMetadataPrinter - Emits GC metadata as assembly code.
live_iterator live_end(const iterator &p)
Definition: GCMetadata.h:148
Garbage collection metadata for a single function.
Definition: GCMetadata.h:74
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml","ocaml 3.10-compatible collector")
unsigned getPointerSize(unsigned AS=0) const
Layout pointer size FIXME: The defaults need to be removed once all of the backends/clients are updat...
Definition: DataLayout.cpp:608
std::vector< GCRoot >::const_iterator live_iterator
Definition: GCMetadata.h:78
A static registration template.
Definition: Registry.h:115
void linkOcamlGCPrinter()
Creates an ocaml-compatible metadata printer.