LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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/CodeGen/GCs.h"
15 #include "llvm/ADT/SmallString.h"
18 #include "llvm/IR/DataLayout.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/MC/MCAsmInfo.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/MCSymbol.h"
26 #include "llvm/Target/Mangler.h"
29 #include <cctype>
30 using namespace llvm;
31 
32 namespace {
33 
34  class OcamlGCMetadataPrinter : public GCMetadataPrinter {
35  public:
36  void beginAssembly(AsmPrinter &AP);
37  void finishAssembly(AsmPrinter &AP);
38  };
39 
40 }
41 
43 Y("ocaml", "ocaml 3.10-compatible collector");
44 
46 
47 static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
48  const std::string &MId = M.getModuleIdentifier();
49 
50  std::string SymName;
51  SymName += "caml";
52  size_t Letter = SymName.size();
53  SymName.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
54  SymName += "__";
55  SymName += Id;
56 
57  // Capitalize the first letter of the module name.
58  SymName[Letter] = toupper(SymName[Letter]);
59 
60  SmallString<128> TmpStr;
61  AP.Mang->getNameWithPrefix(TmpStr, SymName);
62 
63  MCSymbol *Sym = AP.OutContext.GetOrCreateSymbol(TmpStr);
64 
66  AP.OutStreamer.EmitLabel(Sym);
67 }
68 
69 void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) {
71  EmitCamlGlobal(getModule(), AP, "code_begin");
72 
74  EmitCamlGlobal(getModule(), AP, "data_begin");
75 }
76 
77 /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
78 ///
79 /// extern "C" struct align(sizeof(intptr_t)) {
80 /// uint16_t NumDescriptors;
81 /// struct align(sizeof(intptr_t)) {
82 /// void *ReturnAddress;
83 /// uint16_t FrameSize;
84 /// uint16_t NumLiveOffsets;
85 /// uint16_t LiveOffsets[NumLiveOffsets];
86 /// } Descriptors[NumDescriptors];
87 /// } caml${module}__frametable;
88 ///
89 /// Note that this precludes programs from stack frames larger than 64K
90 /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
91 /// either condition is detected in a function which uses the GC.
92 ///
93 void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) {
94  unsigned IntPtrSize = AP.TM.getDataLayout()->getPointerSize();
95 
97  EmitCamlGlobal(getModule(), AP, "code_end");
98 
100  EmitCamlGlobal(getModule(), AP, "data_end");
101 
102  // FIXME: Why does ocaml emit this??
103  AP.OutStreamer.EmitIntValue(0, IntPtrSize);
104 
106  EmitCamlGlobal(getModule(), AP, "frametable");
107 
108  int NumDescriptors = 0;
109  for (iterator I = begin(), IE = end(); I != IE; ++I) {
110  GCFunctionInfo &FI = **I;
111  for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
112  NumDescriptors++;
113  }
114  }
115 
116  if (NumDescriptors >= 1<<16) {
117  // Very rude!
118  report_fatal_error(" Too much descriptor for ocaml GC");
119  }
120  AP.EmitInt16(NumDescriptors);
121  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
122 
123  for (iterator I = begin(), IE = end(); I != IE; ++I) {
124  GCFunctionInfo &FI = **I;
125 
126  uint64_t FrameSize = FI.getFrameSize();
127  if (FrameSize >= 1<<16) {
128  // Very rude!
129  report_fatal_error("Function '" + FI.getFunction().getName() +
130  "' is too large for the ocaml GC! "
131  "Frame size " + Twine(FrameSize) + ">= 65536.\n"
132  "(" + Twine(uintptr_t(&FI)) + ")");
133  }
134 
135  AP.OutStreamer.AddComment("live roots for " +
136  Twine(FI.getFunction().getName()));
138 
139  for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
140  size_t LiveCount = FI.live_size(J);
141  if (LiveCount >= 1<<16) {
142  // Very rude!
143  report_fatal_error("Function '" + FI.getFunction().getName() +
144  "' is too large for the ocaml GC! "
145  "Live root count "+Twine(LiveCount)+" >= 65536.");
146  }
147 
148  AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize);
149  AP.EmitInt16(FrameSize);
150  AP.EmitInt16(LiveCount);
151 
153  KE = FI.live_end(J); K != KE; ++K) {
154  if (K->StackOffset >= 1<<16) {
155  // Very rude!
157  "GC root stack offset is outside of fixed stack frame and out "
158  "of range for ocaml GC!");
159  }
160  AP.EmitInt16(K->StackOffset);
161  }
162 
163  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
164  }
165  }
166 }
const_iterator end(StringRef path)
Get end iterator over path.
Definition: Path.cpp:181
virtual void AddComment(const Twine &T)
Definition: MCStreamer.h:207
The main container class for the LLVM Intermediate Representation.
Definition: Module.h:112
virtual void AddBlankLine()
AddBlankLine - Emit a blank line to a .s file to pretty it up.
Definition: MCStreamer.h:215
MCContext & OutContext
Definition: AsmPrinter.h:72
unsigned getPointerSize(unsigned AS=0) const
Definition: DataLayout.h:261
void getNameWithPrefix(SmallVectorImpl< char > &OutName, const GlobalValue *GV, bool isImplicitlyPrivate, bool UseGlobalPrefix=true)
Definition: Mangler.cpp:90
const_iterator begin(StringRef path)
Get begin iterator over path.
Definition: Path.cpp:173
const MCSection * getDataSection() const
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason, bool gen_crash_diag=true)
StringRef getName() const
Definition: Value.cpp:167
std::vector< GCPoint >::iterator iterator
Definition: GCMetadata.h:85
MCSymbol * GetOrCreateSymbol(StringRef Name)
Definition: MCContext.cpp:118
const std::string & getModuleIdentifier() const
Definition: Module.h:228
void SwitchSection(const MCSection *Section, const MCExpr *Subsection=0)
Definition: MCStreamer.h:284
Mangler * Mang
Definition: AsmPrinter.h:88
MCStreamer & OutStreamer
Definition: AsmPrinter.h:78
void EmitInt16(int Value) const
const MCSection * getTextSection() const
virtual void EmitIntValue(uint64_t Value, unsigned Size)
Definition: MCStreamer.cpp:104
TargetMachine & TM
Definition: AsmPrinter.h:62
uint64_t getFrameSize() const
Definition: GCMetadata.h:139
virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute)=0
EmitSymbolAttribute - Add the given Attribute to Symbol.
size_t live_size(const iterator &p) const
Definition: GCMetadata.h:158
static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id)
virtual void EmitLabel(MCSymbol *Symbol)
Definition: MCStreamer.cpp:212
live_iterator live_begin(const iterator &p)
Definition: GCMetadata.h:156
.type _foo,
Definition: MCDirectives.h:30
virtual const DataLayout * getDataLayout() const
#define I(x, y, z)
Definition: MD5.cpp:54
void EmitAlignment(unsigned NumBits, const GlobalValue *GV=0) const
const TargetLoweringObjectFile & getObjFileLowering() const
getObjFileLowering - Return information about object file lowering.
Definition: AsmPrinter.cpp:129
const Function & getFunction() const
Definition: GCMetadata.h:112
void EmitSymbolValue(const MCSymbol *Sym, unsigned Size)
Definition: MCStreamer.cpp:145
live_iterator live_end(const iterator &p)
Definition: GCMetadata.h:157
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml","ocaml 3.10-compatible collector")
std::vector< GCRoot >::const_iterator live_iterator
Definition: GCMetadata.h:87
void linkOcamlGCPrinter()
Creates an ocaml-compatible metadata printer.