blob: c8a63cf2393bec0aa1440d5686c06218d355bea2 [file] [log] [blame]
Gordon Henriksen5eca0752008-08-17 18:44:35 +00001//===-- OcamlGCPrinter.cpp - Ocaml frametable emitter ---------------------===//
Gordon Henriksen572742e2008-01-07 02:31:11 +00002//
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//
Gordon Henriksen5eca0752008-08-17 18:44:35 +000010// This file implements printing the assembly code for an Ocaml frametable.
Gordon Henriksen572742e2008-01-07 02:31:11 +000011//
12//===----------------------------------------------------------------------===//
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000013
Gordon Henriksen5a29c9e2008-08-17 12:56:54 +000014#include "llvm/CodeGen/GCs.h"
Gordon Henriksen572742e2008-01-07 02:31:11 +000015#include "llvm/CodeGen/AsmPrinter.h"
Gordon Henriksen5eca0752008-08-17 18:44:35 +000016#include "llvm/CodeGen/GCMetadataPrinter.h"
Gordon Henriksen572742e2008-01-07 02:31:11 +000017#include "llvm/Module.h"
Chris Lattneraf76e592009-08-22 20:48:53 +000018#include "llvm/MC/MCAsmInfo.h"
Chris Lattner7d73c7f2010-04-04 07:39:04 +000019#include "llvm/MC/MCContext.h"
Chris Lattner9a38e672010-03-14 07:36:49 +000020#include "llvm/MC/MCSymbol.h"
21#include "llvm/MC/MCStreamer.h"
Chris Lattner7d73c7f2010-04-04 07:39:04 +000022#include "llvm/Target/Mangler.h"
Gordon Henriksen572742e2008-01-07 02:31:11 +000023#include "llvm/Target/TargetData.h"
Chris Lattnerf0144122009-07-28 03:13:23 +000024#include "llvm/Target/TargetLoweringObjectFile.h"
Gordon Henriksen572742e2008-01-07 02:31:11 +000025#include "llvm/Target/TargetMachine.h"
Chris Lattner7d73c7f2010-04-04 07:39:04 +000026#include "llvm/ADT/SmallString.h"
Chris Lattner6c2f9e12009-08-19 05:49:37 +000027#include "llvm/Support/ErrorHandling.h"
Chris Lattner0ad9c912010-01-22 22:09:00 +000028#include "llvm/Support/FormattedStream.h"
Gordon Henriksen572742e2008-01-07 02:31:11 +000029using namespace llvm;
30
31namespace {
32
Nick Lewycky6726b6d2009-10-25 06:33:48 +000033 class OcamlGCMetadataPrinter : public GCMetadataPrinter {
Gordon Henriksenc317a602008-08-17 12:08:44 +000034 public:
Chris Lattner7d73c7f2010-04-04 07:39:04 +000035 void beginAssembly(AsmPrinter &AP);
36 void finishAssembly(AsmPrinter &AP);
Gordon Henriksen572742e2008-01-07 02:31:11 +000037 };
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000038
Gordon Henriksen572742e2008-01-07 02:31:11 +000039}
40
Gordon Henriksenc317a602008-08-17 12:08:44 +000041static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
42Y("ocaml", "ocaml 3.10-compatible collector");
43
Gordon Henriksen5eca0752008-08-17 18:44:35 +000044void llvm::linkOcamlGCPrinter() { }
Gordon Henriksen572742e2008-01-07 02:31:11 +000045
Chris Lattner7d73c7f2010-04-04 07:39:04 +000046static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
Gordon Henriksen572742e2008-01-07 02:31:11 +000047 const std::string &MId = M.getModuleIdentifier();
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000048
Chris Lattner7d73c7f2010-04-04 07:39:04 +000049 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;
Mikhail Glushenkovdd2ad842010-07-01 01:00:22 +000055
Gordon Henriksen572742e2008-01-07 02:31:11 +000056 // Capitalize the first letter of the module name.
Chris Lattner7d73c7f2010-04-04 07:39:04 +000057 SymName[Letter] = toupper(SymName[Letter]);
Mikhail Glushenkovdd2ad842010-07-01 01:00:22 +000058
Chris Lattner7d73c7f2010-04-04 07:39:04 +000059 SmallString<128> TmpStr;
60 AP.Mang->getNameWithPrefix(TmpStr, SymName);
Mikhail Glushenkovdd2ad842010-07-01 01:00:22 +000061
Chris Lattner7d73c7f2010-04-04 07:39:04 +000062 MCSymbol *Sym = AP.OutContext.GetOrCreateSymbol(TmpStr);
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000063
Chris Lattner7d73c7f2010-04-04 07:39:04 +000064 AP.OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global);
65 AP.OutStreamer.EmitLabel(Sym);
Gordon Henriksen572742e2008-01-07 02:31:11 +000066}
67
Chris Lattner7d73c7f2010-04-04 07:39:04 +000068void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) {
Chris Lattner6c2f9e12009-08-19 05:49:37 +000069 AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection());
Chris Lattner7d73c7f2010-04-04 07:39:04 +000070 EmitCamlGlobal(getModule(), AP, "code_begin");
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000071
Chris Lattner6c2f9e12009-08-19 05:49:37 +000072 AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
Chris Lattner7d73c7f2010-04-04 07:39:04 +000073 EmitCamlGlobal(getModule(), AP, "data_begin");
Gordon Henriksen572742e2008-01-07 02:31:11 +000074}
75
76/// emitAssembly - Print the frametable. The ocaml frametable format is thus:
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000077///
Gordon Henriksen572742e2008-01-07 02:31:11 +000078/// 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;
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000087///
Gordon Henriksen572742e2008-01-07 02:31:11 +000088/// Note that this precludes programs from stack frames larger than 64K
89/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
Gordon Henriksen5eca0752008-08-17 18:44:35 +000090/// either condition is detected in a function which uses the GC.
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000091///
Chris Lattner7d73c7f2010-04-04 07:39:04 +000092void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) {
93 unsigned IntPtrSize = AP.TM.getTargetData()->getPointerSize();
Gordon Henriksen572742e2008-01-07 02:31:11 +000094
Chris Lattner6c2f9e12009-08-19 05:49:37 +000095 AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection());
Chris Lattner7d73c7f2010-04-04 07:39:04 +000096 EmitCamlGlobal(getModule(), AP, "code_end");
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +000097
Chris Lattner6c2f9e12009-08-19 05:49:37 +000098 AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
Chris Lattner7d73c7f2010-04-04 07:39:04 +000099 EmitCamlGlobal(getModule(), AP, "data_end");
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000100
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000101 // FIXME: Why does ocaml emit this??
102 AP.OutStreamer.EmitIntValue(0, IntPtrSize, 0);
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000103
Chris Lattner6c2f9e12009-08-19 05:49:37 +0000104 AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000105 EmitCamlGlobal(getModule(), AP, "frametable");
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000106
Nicolas Geoffray3816c252010-05-24 12:24:11 +0000107 int NumDescriptors = 0;
108 for (iterator I = begin(), IE = end(); I != IE; ++I) {
109 GCFunctionInfo &FI = **I;
110 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
111 NumDescriptors++;
112 }
113 }
114
115 if (NumDescriptors >= 1<<16) {
116 // Very rude!
117 report_fatal_error(" Too much descriptor for ocaml GC");
118 }
119 AP.EmitInt16(NumDescriptors);
120 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
121
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000122 for (iterator I = begin(), IE = end(); I != IE; ++I) {
123 GCFunctionInfo &FI = **I;
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000124
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000125 uint64_t FrameSize = FI.getFrameSize();
126 if (FrameSize >= 1<<16) {
Benjamin Kramer1bd73352010-04-08 10:44:28 +0000127 // Very rude!
128 report_fatal_error("Function '" + FI.getFunction().getName() +
129 "' is too large for the ocaml GC! "
130 "Frame size " + Twine(FrameSize) + ">= 65536.\n"
131 "(" + Twine(uintptr_t(&FI)) + ")");
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000132 }
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000133
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000134 AP.OutStreamer.AddComment("live roots for " +
135 Twine(FI.getFunction().getName()));
136 AP.OutStreamer.AddBlankLine();
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000137
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000138 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
139 size_t LiveCount = FI.live_size(J);
Gordon Henriksen08db7362008-08-09 03:48:46 +0000140 if (LiveCount >= 1<<16) {
Benjamin Kramer1bd73352010-04-08 10:44:28 +0000141 // Very rude!
142 report_fatal_error("Function '" + FI.getFunction().getName() +
143 "' is too large for the ocaml GC! "
144 "Live root count "+Twine(LiveCount)+" >= 65536.");
Gordon Henriksen572742e2008-01-07 02:31:11 +0000145 }
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000146
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000147 AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize, 0);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000148 AP.EmitInt16(FrameSize);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000149 AP.EmitInt16(LiveCount);
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000150
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000151 for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
152 KE = FI.live_end(J); K != KE; ++K) {
Nicolas Geoffray3816c252010-05-24 12:24:11 +0000153 if (K->StackOffset >= 1<<16) {
154 // Very rude!
155 report_fatal_error(
156 "GC root stack offset is outside of fixed stack frame and out "
157 "of range for ocaml GC!");
158 }
159 AP.EmitInt16(K->StackOffset);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000160 }
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000161
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000162 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000163 }
164 }
165}