LLVM  14.0.0git
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"
19 #include "llvm/IR/BuiltinGCs.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 ? Align(4) : Align(8));
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) +
149  ">= 65536.\n"
150  "(" +
151  Twine(reinterpret_cast<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 ? Align(4) : Align(8));
185  }
186  }
187 }
AsmPrinter.h
getName
static StringRef getName(Value *V)
Definition: ProvenanceAnalysisEvaluator.cpp:42
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
GCMetadata.h
llvm::MCSymbol
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::GCFunctionInfo::live_begin
live_iterator live_begin(const iterator &p)
live_begin/live_end - Iterators for live roots at a given safe point.
Definition: GCMetadata.h:144
MCDirectives.h
ErrorHandling.h
llvm::GCFunctionInfo
Garbage collection metadata for a single function.
Definition: GCMetadata.h:77
llvm::GCFunctionInfo::iterator
std::vector< GCPoint >::iterator iterator
Definition: GCMetadata.h:79
llvm::GCStrategy::getName
const std::string & getName() const
Return the name of the GC strategy.
Definition: GCStrategy.h:86
Module.h
llvm::GCFunctionInfo::getStrategy
GCStrategy & getStrategy()
getStrategy - Return the GC strategy for the function.
Definition: GCMetadata.h:108
STLExtras.h
llvm::GCMetadataPrinter
GCMetadataPrinter - Emits GC metadata as assembly code.
Definition: GCMetadataPrinter.h:39
llvm::MCContext::getOrCreateSymbol
MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Definition: MCContext.cpp:191
llvm::MCObjectFileInfo::getDataSection
MCSection * getDataSection() const
Definition: MCObjectFileInfo.h:259
llvm::GCFunctionInfo::live_iterator
std::vector< GCRoot >::const_iterator live_iterator
Definition: GCMetadata.h:81
SmallString.h
llvm::AsmPrinter::OutStreamer
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:97
Twine.h
llvm::GCFunctionInfo::begin
iterator begin()
begin/end - Iterators for safe points.
Definition: GCMetadata.h:134
MCContext.h
Y
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
llvm::Mangler::getNameWithPrefix
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:114
llvm::AsmPrinter::emitAlignment
void emitAlignment(Align Alignment, const GlobalObject *GV=nullptr) const
Emit an alignment directive to the specified power of two boundary.
Definition: AsmPrinter.cpp:2450
llvm::report_fatal_error
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:140
Info
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
llvm::GCFunctionInfo::getFrameSize
uint64_t getFrameSize() const
getFrameSize/setFrameSize - Records the function's frame size.
Definition: GCMetadata.h:130
Align
uint64_t Align
Definition: ELFObjHandler.cpp:83
llvm::GCFunctionInfo::live_end
live_iterator live_end(const iterator &p)
Definition: GCMetadata.h:145
llvm::MCObjectFileInfo::getTextSection
MCSection * getTextSection() const
Definition: MCObjectFileInfo.h:258
llvm::GCFunctionInfo::live_size
size_t live_size(const iterator &p) const
Definition: GCMetadata.h:146
llvm::SmallString< 128 >
EmitCamlGlobal
static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id)
Definition: OcamlGCPrinter.cpp:51
llvm::ARM_PROC::IE
@ IE
Definition: ARMBaseInfo.h:27
uint64_t
llvm::find
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1571
I
#define I(x, y, z)
Definition: MD5.cpp:59
llvm::linkOcamlGCPrinter
void linkOcamlGCPrinter()
Creates an ocaml-compatible metadata printer.
Definition: OcamlGCPrinter.cpp:49
BuiltinGCs.h
llvm::AsmPrinter::OutContext
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:92
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:67
Mangler.h
DataLayout.h
TargetLoweringObjectFile.h
llvm::GCFunctionInfo::end
iterator end()
Definition: GCMetadata.h:135
llvm::Value::getName
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
Function.h
llvm::AsmPrinter
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:82
GCMetadataPrinter.h
llvm::MCSA_Global
@ MCSA_Global
.type _foo, @gnu_unique_object
Definition: MCDirectives.h:30
llvm::AsmPrinter::getObjFileLowering
const TargetLoweringObjectFile & getObjFileLowering() const
Return information about object file lowering.
Definition: AsmPrinter.cpp:224
MCStreamer.h
llvm::Registry::Add
A static registration template.
Definition: Registry.h:114
llvm::AMDGPU::VGPRIndexMode::Id
Id
Definition: SIDefines.h:228
llvm::GCModuleInfo
An analysis pass which caches information about the entire Module.
Definition: GCMetadata.h:152
llvm::GCFunctionInfo::getFunction
const Function & getFunction() const
getFunction - Return the function to which this metadata applies.
Definition: GCMetadata.h:105
llvm::AsmPrinter::emitInt16
void emitInt16(int Value) const
Emit a short directive and value.
Definition: AsmPrinter.cpp:2404