LLVM  15.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 (std::unique_ptr<GCFunctionInfo> &FI :
116  llvm::make_range(Info.funcinfo_begin(), Info.funcinfo_end())) {
117  if (FI->getStrategy().getName() != getStrategy().getName())
118  // this function is managed by some other GC
119  continue;
120  NumDescriptors += FI->size();
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 ? Align(4) : Align(8));
129 
130  for (std::unique_ptr<GCFunctionInfo> &FI :
131  llvm::make_range(Info.funcinfo_begin(), Info.funcinfo_end())) {
132  if (FI->getStrategy().getName() != getStrategy().getName())
133  // this function is managed by some other GC
134  continue;
135 
136  uint64_t FrameSize = FI->getFrameSize();
137  if (FrameSize >= 1 << 16) {
138  // Very rude!
139  report_fatal_error("Function '" + FI->getFunction().getName() +
140  "' is too large for the ocaml GC! "
141  "Frame size " +
142  Twine(FrameSize) +
143  ">= 65536.\n"
144  "(" +
145  Twine(reinterpret_cast<uintptr_t>(FI.get())) + ")");
146  }
147 
148  AP.OutStreamer->AddComment("live roots for " +
149  Twine(FI->getFunction().getName()));
150  AP.OutStreamer->addBlankLine();
151 
152  for (GCFunctionInfo::iterator J = FI->begin(), JE = FI->end(); J != JE;
153  ++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 
167  for (GCFunctionInfo::live_iterator K = FI->live_begin(J),
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 ? Align(4) : Align(8));
180  }
181  }
182 }
AsmPrinter.h
getName
static StringRef getName(Value *V)
Definition: ProvenanceAnalysisEvaluator.cpp:42
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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::make_range
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Definition: iterator_range.h:53
MCDirectives.h
ErrorHandling.h
llvm::GCFunctionInfo::iterator
std::vector< GCPoint >::iterator iterator
Definition: GCMetadata.h:79
llvm::AsmPrinter::emitAlignment
void emitAlignment(Align Alignment, const GlobalObject *GV=nullptr, unsigned MaxBytesToEmit=0) const
Emit an alignment directive to the specified power of two boundary.
Definition: AsmPrinter.cpp:2681
Module.h
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:207
llvm::MCObjectFileInfo::getDataSection
MCSection * getDataSection() const
Definition: MCObjectFileInfo.h:268
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
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:119
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:143
Info
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
Align
uint64_t Align
Definition: ELFObjHandler.cpp:81
llvm::MCObjectFileInfo::getTextSection
MCSection * getTextSection() const
Definition: MCObjectFileInfo.h:267
llvm::SmallString< 128 >
EmitCamlGlobal
static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id)
Definition: OcamlGCPrinter.cpp:51
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:1637
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:65
Mangler.h
DataLayout.h
TargetLoweringObjectFile.h
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:382
MCStreamer.h
llvm::Registry::Add
A static registration template.
Definition: Registry.h:114
llvm::AMDGPU::VGPRIndexMode::Id
Id
Definition: SIDefines.h:241
llvm::GCModuleInfo
An analysis pass which caches information about the entire Module.
Definition: GCMetadata.h:152
llvm::AsmPrinter::emitInt16
void emitInt16(int Value) const
Emit a short directive and value.
Definition: AsmPrinter.cpp:2635