LLVM 17.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"
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"
26#include "llvm/MC/MCStreamer.h"
29#include <cctype>
30#include <cstddef>
31#include <cstdint>
32#include <string>
33
34using namespace llvm;
35
36namespace {
37
38class OcamlGCMetadataPrinter : public GCMetadataPrinter {
39public:
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
51static 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
73void 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///
98void 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}
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
Module.h This file contains the declarations for the Module class.
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id)
static StringRef getName(Value *V)
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallString class.
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:84
const TargetLoweringObjectFile & getObjFileLowering() const
Return information about object file lowering.
Definition: AsmPrinter.cpp:371
void emitAlignment(Align Alignment, const GlobalObject *GV=nullptr, unsigned MaxBytesToEmit=0) const
Emit an alignment directive to the specified power of two boundary.
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:94
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:99
void emitInt16(int Value) const
Emit a short directive and value.
std::vector< GCRoot >::const_iterator live_iterator
Definition: GCMetadata.h:81
std::vector< GCPoint >::iterator iterator
Definition: GCMetadata.h:79
GCMetadataPrinter - Emits GC metadata as assembly code.
virtual void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP)
Called after the assembly for the module is generated by the AsmPrinter (but before target specific h...
virtual void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP)
Called before the assembly for the module is generated by the AsmPrinter (but after target specific h...
An analysis pass which caches information about the entire Module.
Definition: GCMetadata.h:152
MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Definition: MCContext.cpp:201
MCSection * getTextSection() const
MCSection * getDataSection() const
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
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
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A static registration template.
Definition: Registry.h:114
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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:1755
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145
void linkOcamlGCPrinter()
Creates an ocaml-compatible metadata printer.
@ MCSA_Global
.type _foo, @gnu_unique_object
Definition: MCDirectives.h:30
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39