blob: 1db178f020ec7ad8052367e13a66478d5947ff16 [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;
55
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]);
58
59 SmallString<128> TmpStr;
60 AP.Mang->getNameWithPrefix(TmpStr, SymName);
61
62 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
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000107 for (iterator I = begin(), IE = end(); I != IE; ++I) {
108 GCFunctionInfo &FI = **I;
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000109
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000110 uint64_t FrameSize = FI.getFrameSize();
111 if (FrameSize >= 1<<16) {
Torok Edwin7d696d82009-07-11 13:10:19 +0000112 std::string msg;
113 raw_string_ostream Msg(msg);
Daniel Dunbar460f6562009-07-26 09:48:23 +0000114 Msg << "Function '" << FI.getFunction().getName()
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000115 << "' is too large for the ocaml GC! "
116 << "Frame size " << FrameSize << " >= 65536.\n";
Torok Edwin7d696d82009-07-11 13:10:19 +0000117 Msg << "(" << uintptr_t(&FI) << ")";
118 llvm_report_error(Msg.str()); // Very rude!
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000119 }
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000120
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000121 AP.OutStreamer.AddComment("live roots for " +
122 Twine(FI.getFunction().getName()));
123 AP.OutStreamer.AddBlankLine();
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000124
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000125 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
126 size_t LiveCount = FI.live_size(J);
Gordon Henriksen08db7362008-08-09 03:48:46 +0000127 if (LiveCount >= 1<<16) {
Torok Edwin7d696d82009-07-11 13:10:19 +0000128 std::string msg;
129 raw_string_ostream Msg(msg);
Daniel Dunbar460f6562009-07-26 09:48:23 +0000130 Msg << "Function '" << FI.getFunction().getName()
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000131 << "' is too large for the ocaml GC! "
Torok Edwin7d696d82009-07-11 13:10:19 +0000132 << "Live root count " << LiveCount << " >= 65536.";
133 llvm_report_error(Msg.str()); // Very rude!
Gordon Henriksen572742e2008-01-07 02:31:11 +0000134 }
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000135
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000136 AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize, 0);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000137 AP.EmitInt16(FrameSize);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000138 AP.EmitInt16(LiveCount);
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000139
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000140 for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
141 KE = FI.live_end(J); K != KE; ++K) {
142 assert(K->StackOffset < 1<<16 &&
Gordon Henriksen572742e2008-01-07 02:31:11 +0000143 "GC root stack offset is outside of fixed stack frame and out "
Gordon Henriksen5eca0752008-08-17 18:44:35 +0000144 "of range for ocaml GC!");
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000145
Chris Lattnerf537ce12010-01-22 23:43:14 +0000146 AP.EmitInt32(K->StackOffset);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000147 }
Mikhail Glushenkov5c1799b2009-01-16 06:53:46 +0000148
Chris Lattner7d73c7f2010-04-04 07:39:04 +0000149 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
Gordon Henriksen572742e2008-01-07 02:31:11 +0000150 }
151 }
152}