LLVM  9.0.0svn
OcamlGCPrinter.cpp
Go to the documentation of this file.
1 //===- OcamlGCPrinter.cpp - Ocaml frametable emitter ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements printing the assembly code for an Ocaml frametable.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/ADT/Twine.h"
20 #include "llvm/IR/DataLayout.h"
21 #include "llvm/IR/Function.h"
22 #include "llvm/IR/Mangler.h"
23 #include "llvm/IR/Module.h"
24 #include "llvm/MC/MCContext.h"
25 #include "llvm/MC/MCDirectives.h"
26 #include "llvm/MC/MCStreamer.h"
29 #include <cctype>
30 #include <cstddef>
31 #include <cstdint>
32 #include <string>
33 
34 using namespace llvm;
35 
36 namespace {
37 
38 class OcamlGCMetadataPrinter : public GCMetadataPrinter {
39 public:
40  void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
41  void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
42 };
43 
44 } // end anonymous namespace
45 
47  Y("ocaml", "ocaml 3.10-compatible collector");
48 
50 
51 static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
52  const std::string &MId = M.getModuleIdentifier();
53 
54  std::string SymName;
55  SymName += "caml";
56  size_t Letter = SymName.size();
57  SymName.append(MId.begin(), llvm::find(MId, '.'));
58  SymName += "__";
59  SymName += Id;
60 
61  // Capitalize the first letter of the module name.
62  SymName[Letter] = toupper(SymName[Letter]);
63 
64  SmallString<128> TmpStr;
65  Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
66 
67  MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
68 
69  AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
70  AP.OutStreamer->EmitLabel(Sym);
71 }
72 
73 void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
74  AsmPrinter &AP) {
75  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
76  EmitCamlGlobal(M, AP, "code_begin");
77 
78  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
79  EmitCamlGlobal(M, AP, "data_begin");
80 }
81 
82 /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
83 ///
84 /// extern "C" struct align(sizeof(intptr_t)) {
85 /// uint16_t NumDescriptors;
86 /// struct align(sizeof(intptr_t)) {
87 /// void *ReturnAddress;
88 /// uint16_t FrameSize;
89 /// uint16_t NumLiveOffsets;
90 /// uint16_t LiveOffsets[NumLiveOffsets];
91 /// } Descriptors[NumDescriptors];
92 /// } caml${module}__frametable;
93 ///
94 /// Note that this precludes programs from stack frames larger than 64K
95 /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
96 /// either condition is detected in a function which uses the GC.
97 ///
98 void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
99  AsmPrinter &AP) {
100  unsigned IntPtrSize = M.getDataLayout().getPointerSize();
101 
102  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
103  EmitCamlGlobal(M, AP, "code_end");
104 
105  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
106  EmitCamlGlobal(M, AP, "data_end");
107 
108  // FIXME: Why does ocaml emit this??
109  AP.OutStreamer->EmitIntValue(0, IntPtrSize);
110 
111  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
112  EmitCamlGlobal(M, AP, "frametable");
113 
114  int NumDescriptors = 0;
115  for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
116  IE = Info.funcinfo_end();
117  I != IE; ++I) {
118  GCFunctionInfo &FI = **I;
119  if (FI.getStrategy().getName() != getStrategy().getName())
120  // this function is managed by some other GC
121  continue;
122  for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
123  NumDescriptors++;
124  }
125  }
126 
127  if (NumDescriptors >= 1 << 16) {
128  // Very rude!
129  report_fatal_error(" Too much descriptor for ocaml GC");
130  }
131  AP.emitInt16(NumDescriptors);
132  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
133 
134  for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
135  IE = Info.funcinfo_end();
136  I != IE; ++I) {
137  GCFunctionInfo &FI = **I;
138  if (FI.getStrategy().getName() != getStrategy().getName())
139  // this function is managed by some other GC
140  continue;
141 
142  uint64_t FrameSize = FI.getFrameSize();
143  if (FrameSize >= 1 << 16) {
144  // Very rude!
145  report_fatal_error("Function '" + FI.getFunction().getName() +
146  "' is too large for the ocaml GC! "
147  "Frame size " +
148  Twine(FrameSize) + ">= 65536.\n"
149  "(" +
150  Twine(uintptr_t(&FI)) + ")");
151  }
152 
153  AP.OutStreamer->AddComment("live roots for " +
154  Twine(FI.getFunction().getName()));
155  AP.OutStreamer->AddBlankLine();
156 
157  for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
158  size_t LiveCount = FI.live_size(J);
159  if (LiveCount >= 1 << 16) {
160  // Very rude!
161  report_fatal_error("Function '" + FI.getFunction().getName() +
162  "' is too large for the ocaml GC! "
163  "Live root count " +
164  Twine(LiveCount) + " >= 65536.");
165  }
166 
167  AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
168  AP.emitInt16(FrameSize);
169  AP.emitInt16(LiveCount);
170 
172  KE = FI.live_end(J);
173  K != KE; ++K) {
174  if (K->StackOffset >= 1 << 16) {
175  // Very rude!
177  "GC root stack offset is outside of fixed stack frame and out "
178  "of range for ocaml GC!");
179  }
180  AP.emitInt16(K->StackOffset);
181  }
182 
183  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
184  }
185  }
186 }
const TargetLoweringObjectFile & getObjFileLowering() const
Return information about object file lowering.
Definition: AsmPrinter.cpp:213
size_t live_size(const iterator &p) const
Definition: GCMetadata.h:146
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:93
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:139
This class represents lattice values for constants.
Definition: AllocatorList.h:23
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
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:88
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:369
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
An analysis pass which caches information about the entire Module.
Definition: GCMetadata.h:152
MCSection * getDataSection() const
const std::string & getName() const
Return the name of the GC strategy.
Definition: GCStrategy.h:86
Analysis containing CSE Info
Definition: CSEInfo.cpp:20
const Function & getFunction() const
getFunction - Return the function to which this metadata applies.
Definition: GCMetadata.h:105
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:648
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:108
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:78
FuncInfoVec::iterator funcinfo_begin()
Definition: GCMetadata.h:168
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:1206
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:144
Module.h This file contains the declarations for the Module class.
FuncInfoVec::iterator funcinfo_end()
Definition: GCMetadata.h:169
iterator begin()
begin/end - Iterators for safe points.
Definition: GCMetadata.h:134
std::vector< GCPoint >::iterator iterator
Definition: GCMetadata.h:79
.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:130
#define I(x, y, z)
Definition: MD5.cpp:58
MCSection * getTextSection() const
std::vector< GCRoot >::const_iterator live_iterator
Definition: GCMetadata.h:81
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:111
GCMetadataPrinter - Emits GC metadata as assembly code.
live_iterator live_end(const iterator &p)
Definition: GCMetadata.h:145
Garbage collection metadata for a single function.
Definition: GCMetadata.h:77
A static registration template.
Definition: Registry.h:114
void emitInt16(int Value) const
Emit a short directive and value.
void linkOcamlGCPrinter()
Creates an ocaml-compatible metadata printer.