blob: 3145cc90dc73b4a98942ff1e6f9d5285b2b24493 [file] [log] [blame]
Eugene Zelenko6ac7a342017-06-07 23:53:32 +00001//===- OcamlGCPrinter.cpp - Ocaml frametable emitter ----------------------===//
Gordon Henriksenc7e991b2008-01-07 02:31:11 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Gordon Henriksenc7e991b2008-01-07 02:31:11 +00006//
7//===----------------------------------------------------------------------===//
8//
Gordon Henriksend930f912008-08-17 18:44:35 +00009// This file implements printing the assembly code for an Ocaml frametable.
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000010//
11//===----------------------------------------------------------------------===//
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000012
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000013#include "llvm/ADT/STLExtras.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000014#include "llvm/ADT/SmallString.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000015#include "llvm/ADT/Twine.h"
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000016#include "llvm/CodeGen/AsmPrinter.h"
Philip Reames9b8c1022018-11-10 16:08:10 +000017#include "llvm/CodeGen/BuiltinGCs.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 Carruth9fb823b2013-01-02 11:36:10 +000020#include "llvm/IR/DataLayout.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000021#include "llvm/IR/Function.h"
Rafael Espindola894843c2014-01-07 21:19:40 +000022#include "llvm/IR/Mangler.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000023#include "llvm/IR/Module.h"
Chris Lattneref8240b2010-04-04 07:39:04 +000024#include "llvm/MC/MCContext.h"
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000025#include "llvm/MC/MCDirectives.h"
Chris Lattner8e2b12b162010-03-14 07:36:49 +000026#include "llvm/MC/MCStreamer.h"
Chris Lattner4b7dadb2009-08-19 05:49:37 +000027#include "llvm/Support/ErrorHandling.h"
David Blaikie6054e652018-03-23 23:58:19 +000028#include "llvm/Target/TargetLoweringObjectFile.h"
Nick Lewycky0de20af2010-12-19 20:43:38 +000029#include <cctype>
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000030#include <cstddef>
31#include <cstdint>
32#include <string>
33
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000034using namespace llvm;
35
36namespace {
37
Philip Reames36319532015-01-16 23:16:12 +000038class OcamlGCMetadataPrinter : public GCMetadataPrinter {
39public:
40 void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
41 void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
42};
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000043
44} // end anonymous namespace
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000045
Gordon Henriksendbe06d32008-08-17 12:08:44 +000046static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
Philip Reames36319532015-01-16 23:16:12 +000047 Y("ocaml", "ocaml 3.10-compatible collector");
Gordon Henriksendbe06d32008-08-17 12:08:44 +000048
Philip Reames36319532015-01-16 23:16:12 +000049void llvm::linkOcamlGCPrinter() {}
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000050
Chris Lattneref8240b2010-04-04 07:39:04 +000051static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000052 const std::string &MId = M.getModuleIdentifier();
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000053
Chris Lattneref8240b2010-04-04 07:39:04 +000054 std::string SymName;
55 SymName += "caml";
56 size_t Letter = SymName.size();
Eugene Zelenko6ac7a342017-06-07 23:53:32 +000057 SymName.append(MId.begin(), llvm::find(MId, '.'));
Chris Lattneref8240b2010-04-04 07:39:04 +000058 SymName += "__";
59 SymName += Id;
Mikhail Glushenkov4721ad82010-07-01 01:00:22 +000060
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000061 // Capitalize the first letter of the module name.
Chris Lattneref8240b2010-04-04 07:39:04 +000062 SymName[Letter] = toupper(SymName[Letter]);
Mikhail Glushenkov4721ad82010-07-01 01:00:22 +000063
Chris Lattneref8240b2010-04-04 07:39:04 +000064 SmallString<128> TmpStr;
Rafael Espindolac233f742015-06-23 13:59:29 +000065 Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
Mikhail Glushenkov4721ad82010-07-01 01:00:22 +000066
Jim Grosbach6f482002015-05-18 18:43:14 +000067 MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000068
Lang Hames9ff69c82015-04-24 19:11:51 +000069 AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
70 AP.OutStreamer->EmitLabel(Sym);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000071}
72
Philip Reames1e308972014-12-11 01:47:23 +000073void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
74 AsmPrinter &AP) {
Lang Hames9ff69c82015-04-24 19:11:51 +000075 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
Philip Reamesde226052014-12-09 23:57:54 +000076 EmitCamlGlobal(M, AP, "code_begin");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000077
Lang Hames9ff69c82015-04-24 19:11:51 +000078 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
Philip Reamesde226052014-12-09 23:57:54 +000079 EmitCamlGlobal(M, AP, "data_begin");
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000080}
81
82/// emitAssembly - Print the frametable. The ocaml frametable format is thus:
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000083///
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000084/// extern "C" struct align(sizeof(intptr_t)) {
85/// uint16_t NumDescriptors;
86/// struct align(sizeof(intptr_t)) {
87/// void *ReturnAddress;
88/// uint16_t FrameSize;
89/// uint16_t NumLiveOffsets;
90/// uint16_t LiveOffsets[NumLiveOffsets];
91/// } Descriptors[NumDescriptors];
92/// } caml${module}__frametable;
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000093///
Gordon Henriksenc7e991b2008-01-07 02:31:11 +000094/// Note that this precludes programs from stack frames larger than 64K
95/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
Gordon Henriksend930f912008-08-17 18:44:35 +000096/// either condition is detected in a function which uses the GC.
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +000097///
Philip Reames1e308972014-12-11 01:47:23 +000098void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
99 AsmPrinter &AP) {
Mehdi Aminibd7287e2015-07-16 06:11:10 +0000100 unsigned IntPtrSize = M.getDataLayout().getPointerSize();
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000101
Lang Hames9ff69c82015-04-24 19:11:51 +0000102 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
Philip Reamesde226052014-12-09 23:57:54 +0000103 EmitCamlGlobal(M, AP, "code_end");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000104
Lang Hames9ff69c82015-04-24 19:11:51 +0000105 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
Philip Reamesde226052014-12-09 23:57:54 +0000106 EmitCamlGlobal(M, AP, "data_end");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000107
Chris Lattneref8240b2010-04-04 07:39:04 +0000108 // FIXME: Why does ocaml emit this??
Lang Hames9ff69c82015-04-24 19:11:51 +0000109 AP.OutStreamer->EmitIntValue(0, IntPtrSize);
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000110
Lang Hames9ff69c82015-04-24 19:11:51 +0000111 AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
Philip Reamesde226052014-12-09 23:57:54 +0000112 EmitCamlGlobal(M, AP, "frametable");
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000113
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000114 int NumDescriptors = 0;
Philip Reames1e308972014-12-11 01:47:23 +0000115 for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
Philip Reames36319532015-01-16 23:16:12 +0000116 IE = Info.funcinfo_end();
117 I != IE; ++I) {
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000118 GCFunctionInfo &FI = **I;
Philip Reames1e308972014-12-11 01:47:23 +0000119 if (FI.getStrategy().getName() != getStrategy().getName())
120 // this function is managed by some other GC
121 continue;
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000122 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
123 NumDescriptors++;
124 }
125 }
126
Philip Reames36319532015-01-16 23:16:12 +0000127 if (NumDescriptors >= 1 << 16) {
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000128 // Very rude!
129 report_fatal_error(" Too much descriptor for ocaml GC");
130 }
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000131 AP.emitInt16(NumDescriptors);
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000132 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
133
Philip Reames1e308972014-12-11 01:47:23 +0000134 for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
Philip Reames36319532015-01-16 23:16:12 +0000135 IE = Info.funcinfo_end();
136 I != IE; ++I) {
Gordon Henriksend930f912008-08-17 18:44:35 +0000137 GCFunctionInfo &FI = **I;
Philip Reames1e308972014-12-11 01:47:23 +0000138 if (FI.getStrategy().getName() != getStrategy().getName())
139 // this function is managed by some other GC
140 continue;
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000141
Gordon Henriksend930f912008-08-17 18:44:35 +0000142 uint64_t FrameSize = FI.getFrameSize();
Philip Reames36319532015-01-16 23:16:12 +0000143 if (FrameSize >= 1 << 16) {
Benjamin Kramera6769262010-04-08 10:44:28 +0000144 // Very rude!
145 report_fatal_error("Function '" + FI.getFunction().getName() +
146 "' is too large for the ocaml GC! "
Philip Reames36319532015-01-16 23:16:12 +0000147 "Frame size " +
148 Twine(FrameSize) + ">= 65536.\n"
149 "(" +
150 Twine(uintptr_t(&FI)) + ")");
Gordon Henriksend930f912008-08-17 18:44:35 +0000151 }
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000152
Lang Hames9ff69c82015-04-24 19:11:51 +0000153 AP.OutStreamer->AddComment("live roots for " +
154 Twine(FI.getFunction().getName()));
155 AP.OutStreamer->AddBlankLine();
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000156
Gordon Henriksend930f912008-08-17 18:44:35 +0000157 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
158 size_t LiveCount = FI.live_size(J);
Philip Reames36319532015-01-16 23:16:12 +0000159 if (LiveCount >= 1 << 16) {
Benjamin Kramera6769262010-04-08 10:44:28 +0000160 // Very rude!
161 report_fatal_error("Function '" + FI.getFunction().getName() +
162 "' is too large for the ocaml GC! "
Philip Reames36319532015-01-16 23:16:12 +0000163 "Live root count " +
164 Twine(LiveCount) + " >= 65536.");
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000165 }
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000166
Lang Hames9ff69c82015-04-24 19:11:51 +0000167 AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000168 AP.emitInt16(FrameSize);
169 AP.emitInt16(LiveCount);
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000170
Gordon Henriksend930f912008-08-17 18:44:35 +0000171 for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
Philip Reames36319532015-01-16 23:16:12 +0000172 KE = FI.live_end(J);
173 K != KE; ++K) {
174 if (K->StackOffset >= 1 << 16) {
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000175 // Very rude!
176 report_fatal_error(
Philip Reames36319532015-01-16 23:16:12 +0000177 "GC root stack offset is outside of fixed stack frame and out "
178 "of range for ocaml GC!");
Nicolas Geoffrayc5327222010-05-24 12:24:11 +0000179 }
Rafael Espindola4b4d85f2018-03-29 23:32:54 +0000180 AP.emitInt16(K->StackOffset);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000181 }
Mikhail Glushenkovb2f9a732009-01-16 06:53:46 +0000182
Chris Lattneref8240b2010-04-04 07:39:04 +0000183 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
Gordon Henriksenc7e991b2008-01-07 02:31:11 +0000184 }
185 }
186}