blob: e0cc241dd23f262310fcf03db7aa593524bea333 [file] [log] [blame]
Eugene Zelenko6ac7a342017-06-07 23:53:32 +00001//===- OcamlGCPrinter.cpp - Ocaml frametable emitter ----------------------===//
Gordon Henriksenc7e991b2008-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 Henriksend930f912008-08-17 18:44:35 +000010// This file implements printing the assembly code for an Ocaml frametable.
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000011//
12//===----------------------------------------------------------------------===//
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000013
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000014#include "llvm/ADT/STLExtras.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000015#include "llvm/ADT/SmallString.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000016#include "llvm/ADT/Twine.h"
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000017#include "llvm/CodeGen/AsmPrinter.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000018#include "llvm/CodeGen/GCMetadata.h"
Gordon Henriksend930f912008-08-17 18:44:35 +000019#include "llvm/CodeGen/GCMetadataPrinter.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000020#include "llvm/CodeGen/GCs.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000021#include "llvm/CodeGen/TargetLoweringObjectFile.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000022#include "llvm/IR/DataLayout.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000023#include "llvm/IR/Function.h"
Rafael Espindola894843c2014-01-07 21:19:40 +000024#include "llvm/IR/Mangler.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000025#include "llvm/IR/Module.h"
Chris Lattneref8240b2010-04-04 07:39:04 +000026#include "llvm/MC/MCContext.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000027#include "llvm/MC/MCDirectives.h"
Chris Lattner8e2b12b162010-03-14 07:36:49 +000028#include "llvm/MC/MCStreamer.h"
Chris Lattner4b7dadb2009-08-19 05:49:37 +000029#include "llvm/Support/ErrorHandling.h"
Nick Lewycky0de20af2010-12-19 20:43:38 +000030#include <cctype>
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000031#include <cstddef>
32#include <cstdint>
33#include <string>
34
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000035using namespace llvm;
36
37namespace {
38
Philip Reames36319532015-01-16 23:16:12 +000039class OcamlGCMetadataPrinter : public GCMetadataPrinter {
40public:
41 void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
42 void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
43};
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000044
45} // end anonymous namespace
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000046
Gordon Henriksendbe06d32008-08-17 12:08:44 +000047static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
Philip Reames36319532015-01-16 23:16:12 +000048 Y("ocaml", "ocaml 3.10-compatible collector");
Gordon Henriksendbe06d32008-08-17 12:08:44 +000049
Philip Reames36319532015-01-16 23:16:12 +000050void llvm::linkOcamlGCPrinter() {}
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000051
Chris Lattneref8240b2010-04-04 07:39:04 +000052static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000053 const std::string &MId = M.getModuleIdentifier();
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000054
Chris Lattneref8240b2010-04-04 07:39:04 +000055 std::string SymName;
56 SymName += "caml";
57 size_t Letter = SymName.size();
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000058 SymName.append(MId.begin(), llvm::find(MId, '.'));
Chris Lattneref8240b2010-04-04 07:39:04 +000059 SymName += "__";
60 SymName += Id;
Mikhail Glushenkov4721ad82010-07-01 01:00:22 +000061
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000062 // Capitalize the first letter of the module name.
Chris Lattneref8240b2010-04-04 07:39:04 +000063 SymName[Letter] = toupper(SymName[Letter]);
Mikhail Glushenkov4721ad82010-07-01 01:00:22 +000064
Chris Lattneref8240b2010-04-04 07:39:04 +000065 SmallString<128> TmpStr;
Rafael Espindolac233f742015-06-23 13:59:29 +000066 Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
Mikhail Glushenkov4721ad82010-07-01 01:00:22 +000067
Jim Grosbach6f482002015-05-18 18:43:14 +000068 MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000069
Lang Hames9ff69c82015-04-24 19:11:51 +000070 AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
71 AP.OutStreamer->EmitLabel(Sym);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000072}
73
Philip Reames1e308972014-12-11 01:47:23 +000074void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
75 AsmPrinter &AP) {
Lang Hames9ff69c82015-04-24 19:11:51 +000076 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
Philip Reamesde226052014-12-09 23:57:54 +000077 EmitCamlGlobal(M, AP, "code_begin");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000078
Lang Hames9ff69c82015-04-24 19:11:51 +000079 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
Philip Reamesde226052014-12-09 23:57:54 +000080 EmitCamlGlobal(M, AP, "data_begin");
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000081}
82
83/// emitAssembly - Print the frametable. The ocaml frametable format is thus:
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000084///
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000085/// extern "C" struct align(sizeof(intptr_t)) {
86/// uint16_t NumDescriptors;
87/// struct align(sizeof(intptr_t)) {
88/// void *ReturnAddress;
89/// uint16_t FrameSize;
90/// uint16_t NumLiveOffsets;
91/// uint16_t LiveOffsets[NumLiveOffsets];
92/// } Descriptors[NumDescriptors];
93/// } caml${module}__frametable;
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000094///
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000095/// Note that this precludes programs from stack frames larger than 64K
96/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
Gordon Henriksend930f912008-08-17 18:44:35 +000097/// either condition is detected in a function which uses the GC.
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000098///
Philip Reames1e308972014-12-11 01:47:23 +000099void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
100 AsmPrinter &AP) {
Mehdi Aminibd7287e2015-07-16 06:11:10 +0000101 unsigned IntPtrSize = M.getDataLayout().getPointerSize();
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000102
Lang Hames9ff69c82015-04-24 19:11:51 +0000103 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
Philip Reamesde226052014-12-09 23:57:54 +0000104 EmitCamlGlobal(M, AP, "code_end");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000105
Lang Hames9ff69c82015-04-24 19:11:51 +0000106 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
Philip Reamesde226052014-12-09 23:57:54 +0000107 EmitCamlGlobal(M, AP, "data_end");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000108
Chris Lattneref8240b2010-04-04 07:39:04 +0000109 // FIXME: Why does ocaml emit this??
Lang Hames9ff69c82015-04-24 19:11:51 +0000110 AP.OutStreamer->EmitIntValue(0, IntPtrSize);
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000111
Lang Hames9ff69c82015-04-24 19:11:51 +0000112 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
Philip Reamesde226052014-12-09 23:57:54 +0000113 EmitCamlGlobal(M, AP, "frametable");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000114
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000115 int NumDescriptors = 0;
Philip Reames1e308972014-12-11 01:47:23 +0000116 for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
Philip Reames36319532015-01-16 23:16:12 +0000117 IE = Info.funcinfo_end();
118 I != IE; ++I) {
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000119 GCFunctionInfo &FI = **I;
Philip Reames1e308972014-12-11 01:47:23 +0000120 if (FI.getStrategy().getName() != getStrategy().getName())
121 // this function is managed by some other GC
122 continue;
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000123 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
124 NumDescriptors++;
125 }
126 }
127
Philip Reames36319532015-01-16 23:16:12 +0000128 if (NumDescriptors >= 1 << 16) {
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000129 // Very rude!
130 report_fatal_error(" Too much descriptor for ocaml GC");
131 }
132 AP.EmitInt16(NumDescriptors);
133 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
134
Philip Reames1e308972014-12-11 01:47:23 +0000135 for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
Philip Reames36319532015-01-16 23:16:12 +0000136 IE = Info.funcinfo_end();
137 I != IE; ++I) {
Gordon Henriksend930f912008-08-17 18:44:35 +0000138 GCFunctionInfo &FI = **I;
Philip Reames1e308972014-12-11 01:47:23 +0000139 if (FI.getStrategy().getName() != getStrategy().getName())
140 // this function is managed by some other GC
141 continue;
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000142
Gordon Henriksend930f912008-08-17 18:44:35 +0000143 uint64_t FrameSize = FI.getFrameSize();
Philip Reames36319532015-01-16 23:16:12 +0000144 if (FrameSize >= 1 << 16) {
Benjamin Kramera6769262010-04-08 10:44:28 +0000145 // Very rude!
146 report_fatal_error("Function '" + FI.getFunction().getName() +
147 "' is too large for the ocaml GC! "
Philip Reames36319532015-01-16 23:16:12 +0000148 "Frame size " +
149 Twine(FrameSize) + ">= 65536.\n"
150 "(" +
151 Twine(uintptr_t(&FI)) + ")");
Gordon Henriksend930f912008-08-17 18:44:35 +0000152 }
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000153
Lang Hames9ff69c82015-04-24 19:11:51 +0000154 AP.OutStreamer->AddComment("live roots for " +
155 Twine(FI.getFunction().getName()));
156 AP.OutStreamer->AddBlankLine();
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000157
Gordon Henriksend930f912008-08-17 18:44:35 +0000158 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
159 size_t LiveCount = FI.live_size(J);
Philip Reames36319532015-01-16 23:16:12 +0000160 if (LiveCount >= 1 << 16) {
Benjamin Kramera6769262010-04-08 10:44:28 +0000161 // Very rude!
162 report_fatal_error("Function '" + FI.getFunction().getName() +
163 "' is too large for the ocaml GC! "
Philip Reames36319532015-01-16 23:16:12 +0000164 "Live root count " +
165 Twine(LiveCount) + " >= 65536.");
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000166 }
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000167
Lang Hames9ff69c82015-04-24 19:11:51 +0000168 AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000169 AP.EmitInt16(FrameSize);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000170 AP.EmitInt16(LiveCount);
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000171
Gordon Henriksend930f912008-08-17 18:44:35 +0000172 for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
Philip Reames36319532015-01-16 23:16:12 +0000173 KE = FI.live_end(J);
174 K != KE; ++K) {
175 if (K->StackOffset >= 1 << 16) {
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000176 // Very rude!
177 report_fatal_error(
Philip Reames36319532015-01-16 23:16:12 +0000178 "GC root stack offset is outside of fixed stack frame and out "
179 "of range for ocaml GC!");
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000180 }
181 AP.EmitInt16(K->StackOffset);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000182 }
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000183
Chris Lattneref8240b2010-04-04 07:39:04 +0000184 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000185 }
186 }
187}