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