xref: /aosp_15_r20/external/llvm/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- OcamlGCPrinter.cpp - Ocaml frametable emitter ---------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This file implements printing the assembly code for an Ocaml frametable.
11*9880d681SAndroid Build Coastguard Worker //
12*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
13*9880d681SAndroid Build Coastguard Worker 
14*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/GCs.h"
15*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/SmallString.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/AsmPrinter.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/GCMetadataPrinter.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/DataLayout.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Mangler.h"
20*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Module.h"
21*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCAsmInfo.h"
22*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCContext.h"
23*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCStreamer.h"
24*9880d681SAndroid Build Coastguard Worker #include "llvm/MC/MCSymbol.h"
25*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/ErrorHandling.h"
26*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/FormattedStream.h"
27*9880d681SAndroid Build Coastguard Worker #include "llvm/Target/TargetLoweringObjectFile.h"
28*9880d681SAndroid Build Coastguard Worker #include "llvm/Target/TargetMachine.h"
29*9880d681SAndroid Build Coastguard Worker #include "llvm/Target/TargetSubtargetInfo.h"
30*9880d681SAndroid Build Coastguard Worker #include <cctype>
31*9880d681SAndroid Build Coastguard Worker using namespace llvm;
32*9880d681SAndroid Build Coastguard Worker 
33*9880d681SAndroid Build Coastguard Worker namespace {
34*9880d681SAndroid Build Coastguard Worker 
35*9880d681SAndroid Build Coastguard Worker class OcamlGCMetadataPrinter : public GCMetadataPrinter {
36*9880d681SAndroid Build Coastguard Worker public:
37*9880d681SAndroid Build Coastguard Worker   void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
38*9880d681SAndroid Build Coastguard Worker   void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
39*9880d681SAndroid Build Coastguard Worker };
40*9880d681SAndroid Build Coastguard Worker }
41*9880d681SAndroid Build Coastguard Worker 
42*9880d681SAndroid Build Coastguard Worker static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
43*9880d681SAndroid Build Coastguard Worker     Y("ocaml", "ocaml 3.10-compatible collector");
44*9880d681SAndroid Build Coastguard Worker 
linkOcamlGCPrinter()45*9880d681SAndroid Build Coastguard Worker void llvm::linkOcamlGCPrinter() {}
46*9880d681SAndroid Build Coastguard Worker 
EmitCamlGlobal(const Module & M,AsmPrinter & AP,const char * Id)47*9880d681SAndroid Build Coastguard Worker static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
48*9880d681SAndroid Build Coastguard Worker   const std::string &MId = M.getModuleIdentifier();
49*9880d681SAndroid Build Coastguard Worker 
50*9880d681SAndroid Build Coastguard Worker   std::string SymName;
51*9880d681SAndroid Build Coastguard Worker   SymName += "caml";
52*9880d681SAndroid Build Coastguard Worker   size_t Letter = SymName.size();
53*9880d681SAndroid Build Coastguard Worker   SymName.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
54*9880d681SAndroid Build Coastguard Worker   SymName += "__";
55*9880d681SAndroid Build Coastguard Worker   SymName += Id;
56*9880d681SAndroid Build Coastguard Worker 
57*9880d681SAndroid Build Coastguard Worker   // Capitalize the first letter of the module name.
58*9880d681SAndroid Build Coastguard Worker   SymName[Letter] = toupper(SymName[Letter]);
59*9880d681SAndroid Build Coastguard Worker 
60*9880d681SAndroid Build Coastguard Worker   SmallString<128> TmpStr;
61*9880d681SAndroid Build Coastguard Worker   Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
62*9880d681SAndroid Build Coastguard Worker 
63*9880d681SAndroid Build Coastguard Worker   MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
64*9880d681SAndroid Build Coastguard Worker 
65*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
66*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->EmitLabel(Sym);
67*9880d681SAndroid Build Coastguard Worker }
68*9880d681SAndroid Build Coastguard Worker 
beginAssembly(Module & M,GCModuleInfo & Info,AsmPrinter & AP)69*9880d681SAndroid Build Coastguard Worker void OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
70*9880d681SAndroid Build Coastguard Worker                                            AsmPrinter &AP) {
71*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
72*9880d681SAndroid Build Coastguard Worker   EmitCamlGlobal(M, AP, "code_begin");
73*9880d681SAndroid Build Coastguard Worker 
74*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
75*9880d681SAndroid Build Coastguard Worker   EmitCamlGlobal(M, AP, "data_begin");
76*9880d681SAndroid Build Coastguard Worker }
77*9880d681SAndroid Build Coastguard Worker 
78*9880d681SAndroid Build Coastguard Worker /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
79*9880d681SAndroid Build Coastguard Worker ///
80*9880d681SAndroid Build Coastguard Worker ///   extern "C" struct align(sizeof(intptr_t)) {
81*9880d681SAndroid Build Coastguard Worker ///     uint16_t NumDescriptors;
82*9880d681SAndroid Build Coastguard Worker ///     struct align(sizeof(intptr_t)) {
83*9880d681SAndroid Build Coastguard Worker ///       void *ReturnAddress;
84*9880d681SAndroid Build Coastguard Worker ///       uint16_t FrameSize;
85*9880d681SAndroid Build Coastguard Worker ///       uint16_t NumLiveOffsets;
86*9880d681SAndroid Build Coastguard Worker ///       uint16_t LiveOffsets[NumLiveOffsets];
87*9880d681SAndroid Build Coastguard Worker ///     } Descriptors[NumDescriptors];
88*9880d681SAndroid Build Coastguard Worker ///   } caml${module}__frametable;
89*9880d681SAndroid Build Coastguard Worker ///
90*9880d681SAndroid Build Coastguard Worker /// Note that this precludes programs from stack frames larger than 64K
91*9880d681SAndroid Build Coastguard Worker /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
92*9880d681SAndroid Build Coastguard Worker /// either condition is detected in a function which uses the GC.
93*9880d681SAndroid Build Coastguard Worker ///
finishAssembly(Module & M,GCModuleInfo & Info,AsmPrinter & AP)94*9880d681SAndroid Build Coastguard Worker void OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
95*9880d681SAndroid Build Coastguard Worker                                             AsmPrinter &AP) {
96*9880d681SAndroid Build Coastguard Worker   unsigned IntPtrSize = M.getDataLayout().getPointerSize();
97*9880d681SAndroid Build Coastguard Worker 
98*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
99*9880d681SAndroid Build Coastguard Worker   EmitCamlGlobal(M, AP, "code_end");
100*9880d681SAndroid Build Coastguard Worker 
101*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
102*9880d681SAndroid Build Coastguard Worker   EmitCamlGlobal(M, AP, "data_end");
103*9880d681SAndroid Build Coastguard Worker 
104*9880d681SAndroid Build Coastguard Worker   // FIXME: Why does ocaml emit this??
105*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->EmitIntValue(0, IntPtrSize);
106*9880d681SAndroid Build Coastguard Worker 
107*9880d681SAndroid Build Coastguard Worker   AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
108*9880d681SAndroid Build Coastguard Worker   EmitCamlGlobal(M, AP, "frametable");
109*9880d681SAndroid Build Coastguard Worker 
110*9880d681SAndroid Build Coastguard Worker   int NumDescriptors = 0;
111*9880d681SAndroid Build Coastguard Worker   for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
112*9880d681SAndroid Build Coastguard Worker                                            IE = Info.funcinfo_end();
113*9880d681SAndroid Build Coastguard Worker        I != IE; ++I) {
114*9880d681SAndroid Build Coastguard Worker     GCFunctionInfo &FI = **I;
115*9880d681SAndroid Build Coastguard Worker     if (FI.getStrategy().getName() != getStrategy().getName())
116*9880d681SAndroid Build Coastguard Worker       // this function is managed by some other GC
117*9880d681SAndroid Build Coastguard Worker       continue;
118*9880d681SAndroid Build Coastguard Worker     for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
119*9880d681SAndroid Build Coastguard Worker       NumDescriptors++;
120*9880d681SAndroid Build Coastguard Worker     }
121*9880d681SAndroid Build Coastguard Worker   }
122*9880d681SAndroid Build Coastguard Worker 
123*9880d681SAndroid Build Coastguard Worker   if (NumDescriptors >= 1 << 16) {
124*9880d681SAndroid Build Coastguard Worker     // Very rude!
125*9880d681SAndroid Build Coastguard Worker     report_fatal_error(" Too much descriptor for ocaml GC");
126*9880d681SAndroid Build Coastguard Worker   }
127*9880d681SAndroid Build Coastguard Worker   AP.EmitInt16(NumDescriptors);
128*9880d681SAndroid Build Coastguard Worker   AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
129*9880d681SAndroid Build Coastguard Worker 
130*9880d681SAndroid Build Coastguard Worker   for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
131*9880d681SAndroid Build Coastguard Worker                                            IE = Info.funcinfo_end();
132*9880d681SAndroid Build Coastguard Worker        I != IE; ++I) {
133*9880d681SAndroid Build Coastguard Worker     GCFunctionInfo &FI = **I;
134*9880d681SAndroid Build Coastguard Worker     if (FI.getStrategy().getName() != getStrategy().getName())
135*9880d681SAndroid Build Coastguard Worker       // this function is managed by some other GC
136*9880d681SAndroid Build Coastguard Worker       continue;
137*9880d681SAndroid Build Coastguard Worker 
138*9880d681SAndroid Build Coastguard Worker     uint64_t FrameSize = FI.getFrameSize();
139*9880d681SAndroid Build Coastguard Worker     if (FrameSize >= 1 << 16) {
140*9880d681SAndroid Build Coastguard Worker       // Very rude!
141*9880d681SAndroid Build Coastguard Worker       report_fatal_error("Function '" + FI.getFunction().getName() +
142*9880d681SAndroid Build Coastguard Worker                          "' is too large for the ocaml GC! "
143*9880d681SAndroid Build Coastguard Worker                          "Frame size " +
144*9880d681SAndroid Build Coastguard Worker                          Twine(FrameSize) + ">= 65536.\n"
145*9880d681SAndroid Build Coastguard Worker                                             "(" +
146*9880d681SAndroid Build Coastguard Worker                          Twine(uintptr_t(&FI)) + ")");
147*9880d681SAndroid Build Coastguard Worker     }
148*9880d681SAndroid Build Coastguard Worker 
149*9880d681SAndroid Build Coastguard Worker     AP.OutStreamer->AddComment("live roots for " +
150*9880d681SAndroid Build Coastguard Worker                                Twine(FI.getFunction().getName()));
151*9880d681SAndroid Build Coastguard Worker     AP.OutStreamer->AddBlankLine();
152*9880d681SAndroid Build Coastguard Worker 
153*9880d681SAndroid Build Coastguard Worker     for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
154*9880d681SAndroid Build Coastguard Worker       size_t LiveCount = FI.live_size(J);
155*9880d681SAndroid Build Coastguard Worker       if (LiveCount >= 1 << 16) {
156*9880d681SAndroid Build Coastguard Worker         // Very rude!
157*9880d681SAndroid Build Coastguard Worker         report_fatal_error("Function '" + FI.getFunction().getName() +
158*9880d681SAndroid Build Coastguard Worker                            "' is too large for the ocaml GC! "
159*9880d681SAndroid Build Coastguard Worker                            "Live root count " +
160*9880d681SAndroid Build Coastguard Worker                            Twine(LiveCount) + " >= 65536.");
161*9880d681SAndroid Build Coastguard Worker       }
162*9880d681SAndroid Build Coastguard Worker 
163*9880d681SAndroid Build Coastguard Worker       AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
164*9880d681SAndroid Build Coastguard Worker       AP.EmitInt16(FrameSize);
165*9880d681SAndroid Build Coastguard Worker       AP.EmitInt16(LiveCount);
166*9880d681SAndroid Build Coastguard Worker 
167*9880d681SAndroid Build Coastguard Worker       for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
168*9880d681SAndroid Build Coastguard Worker                                          KE = FI.live_end(J);
169*9880d681SAndroid Build Coastguard Worker            K != KE; ++K) {
170*9880d681SAndroid Build Coastguard Worker         if (K->StackOffset >= 1 << 16) {
171*9880d681SAndroid Build Coastguard Worker           // Very rude!
172*9880d681SAndroid Build Coastguard Worker           report_fatal_error(
173*9880d681SAndroid Build Coastguard Worker               "GC root stack offset is outside of fixed stack frame and out "
174*9880d681SAndroid Build Coastguard Worker               "of range for ocaml GC!");
175*9880d681SAndroid Build Coastguard Worker         }
176*9880d681SAndroid Build Coastguard Worker         AP.EmitInt16(K->StackOffset);
177*9880d681SAndroid Build Coastguard Worker       }
178*9880d681SAndroid Build Coastguard Worker 
179*9880d681SAndroid Build Coastguard Worker       AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
180*9880d681SAndroid Build Coastguard Worker     }
181*9880d681SAndroid Build Coastguard Worker   }
182*9880d681SAndroid Build Coastguard Worker }
183