mcize the gc metadata printing stuff.
[oota-llvm.git] / lib / CodeGen / AsmPrinter / OcamlGCPrinter.cpp
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/CodeGen/AsmPrinter.h"
16 #include "llvm/CodeGen/GCMetadataPrinter.h"
17 #include "llvm/Module.h"
18 #include "llvm/MC/MCAsmInfo.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCSymbol.h"
21 #include "llvm/MC/MCStreamer.h"
22 #include "llvm/Target/Mangler.h"
23 #include "llvm/Target/TargetData.h"
24 #include "llvm/Target/TargetLoweringObjectFile.h"
25 #include "llvm/Target/TargetMachine.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/Support/ErrorHandling.h"
28 #include "llvm/Support/FormattedStream.h"
29 using namespace llvm;
30
31 namespace {
32
33   class OcamlGCMetadataPrinter : public GCMetadataPrinter {
34   public:
35     void beginAssembly(AsmPrinter &AP);
36     void finishAssembly(AsmPrinter &AP);
37   };
38
39 }
40
41 static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
42 Y("ocaml", "ocaml 3.10-compatible collector");
43
44 void llvm::linkOcamlGCPrinter() { }
45
46 static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
47   const std::string &MId = M.getModuleIdentifier();
48
49   std::string SymName;
50   SymName += "caml";
51   size_t Letter = SymName.size();
52   SymName.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
53   SymName += "__";
54   SymName += Id;
55   
56   // Capitalize the first letter of the module name.
57   SymName[Letter] = toupper(SymName[Letter]);
58   
59   SmallString<128> TmpStr;
60   AP.Mang->getNameWithPrefix(TmpStr, SymName);
61   
62   MCSymbol *Sym = AP.OutContext.GetOrCreateSymbol(TmpStr);
63
64   AP.OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global);
65   AP.OutStreamer.EmitLabel(Sym);
66 }
67
68 void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) {
69   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection());
70   EmitCamlGlobal(getModule(), AP, "code_begin");
71
72   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
73   EmitCamlGlobal(getModule(), AP, "data_begin");
74 }
75
76 /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
77 ///
78 ///   extern "C" struct align(sizeof(intptr_t)) {
79 ///     uint16_t NumDescriptors;
80 ///     struct align(sizeof(intptr_t)) {
81 ///       void *ReturnAddress;
82 ///       uint16_t FrameSize;
83 ///       uint16_t NumLiveOffsets;
84 ///       uint16_t LiveOffsets[NumLiveOffsets];
85 ///     } Descriptors[NumDescriptors];
86 ///   } caml${module}__frametable;
87 ///
88 /// Note that this precludes programs from stack frames larger than 64K
89 /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
90 /// either condition is detected in a function which uses the GC.
91 ///
92 void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) {
93   unsigned IntPtrSize = AP.TM.getTargetData()->getPointerSize();
94
95   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection());
96   EmitCamlGlobal(getModule(), AP, "code_end");
97
98   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
99   EmitCamlGlobal(getModule(), AP, "data_end");
100
101   // FIXME: Why does ocaml emit this??
102   AP.OutStreamer.EmitIntValue(0, IntPtrSize, 0);
103
104   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
105   EmitCamlGlobal(getModule(), AP, "frametable");
106
107   for (iterator I = begin(), IE = end(); I != IE; ++I) {
108     GCFunctionInfo &FI = **I;
109
110     uint64_t FrameSize = FI.getFrameSize();
111     if (FrameSize >= 1<<16) {
112       std::string msg;
113       raw_string_ostream Msg(msg);
114       Msg << "Function '" << FI.getFunction().getName()
115            << "' is too large for the ocaml GC! "
116            << "Frame size " << FrameSize << " >= 65536.\n";
117       Msg << "(" << uintptr_t(&FI) << ")";
118       llvm_report_error(Msg.str()); // Very rude!
119     }
120
121     AP.OutStreamer.AddComment("live roots for " +
122                               Twine(FI.getFunction().getName()));
123     AP.OutStreamer.AddBlankLine();
124
125     for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
126       size_t LiveCount = FI.live_size(J);
127       if (LiveCount >= 1<<16) {
128         std::string msg;
129         raw_string_ostream Msg(msg);
130         Msg << "Function '" << FI.getFunction().getName()
131              << "' is too large for the ocaml GC! "
132              << "Live root count " << LiveCount << " >= 65536.";
133         llvm_report_error(Msg.str()); // Very rude!
134       }
135
136       AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize, 0);
137       AP.EmitInt16(FrameSize);
138       AP.EmitInt16(LiveCount);
139
140       for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
141                                          KE = FI.live_end(J); K != KE; ++K) {
142         assert(K->StackOffset < 1<<16 &&
143                "GC root stack offset is outside of fixed stack frame and out "
144                "of range for ocaml GC!");
145
146         AP.EmitInt32(K->StackOffset);
147       }
148
149       AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
150     }
151   }
152 }