15eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen//===-- OcamlGCPrinter.cpp - Ocaml frametable emitter ---------------------===//
2572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//
3572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//                     The LLVM Compiler Infrastructure
4572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//
5572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// This file is distributed under the University of Illinois Open Source
6572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// License. See LICENSE.TXT for details.
7572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//
8572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//===----------------------------------------------------------------------===//
9572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//
105eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen// This file implements printing the assembly code for an Ocaml frametable.
11572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//
12572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//===----------------------------------------------------------------------===//
135c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
145a29c9eed157af51a8d338b5a225b146881819e8Gordon Henriksen#include "llvm/CodeGen/GCs.h"
15d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/ADT/SmallString.h"
16572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen#include "llvm/CodeGen/AsmPrinter.h"
175eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen#include "llvm/CodeGen/GCMetadataPrinter.h"
180b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/DataLayout.h"
1936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/IR/Mangler.h"
200b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Module.h"
21af76e592c7f9deff0e55c13dbb4a34f07f1c7f64Chris Lattner#include "llvm/MC/MCAsmInfo.h"
227d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner#include "llvm/MC/MCContext.h"
239a38e67590fa1431bd7e950f4ce2684d9f572176Chris Lattner#include "llvm/MC/MCStreamer.h"
24d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/MC/MCSymbol.h"
25d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/ErrorHandling.h"
26d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/FormattedStream.h"
27f0144127b98425d214e59e4a1a4b342b78e3642bChris Lattner#include "llvm/Target/TargetLoweringObjectFile.h"
28572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen#include "llvm/Target/TargetMachine.h"
2937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines#include "llvm/Target/TargetSubtargetInfo.h"
30476b242fe7a61e5f9ac6214b0bc5c680d24f152eNick Lewycky#include <cctype>
31572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksenusing namespace llvm;
32572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
33572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksennamespace {
34572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
35ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesclass OcamlGCMetadataPrinter : public GCMetadataPrinter {
36ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinespublic:
37ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
38ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override;
39ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines};
40572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen}
41572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
42c317a60c2714a5b90700a11ba646285cb754a5d3Gordon Henriksenstatic GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
43ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    Y("ocaml", "ocaml 3.10-compatible collector");
44c317a60c2714a5b90700a11ba646285cb754a5d3Gordon Henriksen
45ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesvoid llvm::linkOcamlGCPrinter() {}
46572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
477d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattnerstatic void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
48572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen  const std::string &MId = M.getModuleIdentifier();
495c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
507d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  std::string SymName;
517d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  SymName += "caml";
527d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  size_t Letter = SymName.size();
537d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  SymName.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
547d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  SymName += "__";
557d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  SymName += Id;
56dd2ad8432f104282ff43c94457f474ea0a264175Mikhail Glushenkov
57572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen  // Capitalize the first letter of the module name.
587d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  SymName[Letter] = toupper(SymName[Letter]);
59dd2ad8432f104282ff43c94457f474ea0a264175Mikhail Glushenkov
607d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  SmallString<128> TmpStr;
61f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout());
62dd2ad8432f104282ff43c94457f474ea0a264175Mikhail Glushenkov
636948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr);
647d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner
656948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global);
666948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->EmitLabel(Sym);
67572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen}
68572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
69ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesvoid OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info,
70ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                                           AsmPrinter &AP) {
716948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
72ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EmitCamlGlobal(M, AP, "code_begin");
735c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
746948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
75ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EmitCamlGlobal(M, AP, "data_begin");
76572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen}
77572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
78572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// emitAssembly - Print the frametable. The ocaml frametable format is thus:
795c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov///
80572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///   extern "C" struct align(sizeof(intptr_t)) {
81572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///     uint16_t NumDescriptors;
82572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///     struct align(sizeof(intptr_t)) {
83572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///       void *ReturnAddress;
84572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///       uint16_t FrameSize;
85572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///       uint16_t NumLiveOffsets;
86572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///       uint16_t LiveOffsets[NumLiveOffsets];
87572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///     } Descriptors[NumDescriptors];
88572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen///   } caml${module}__frametable;
895c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov///
90572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// Note that this precludes programs from stack frames larger than 64K
91572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
925eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen/// either condition is detected in a function which uses the GC.
935c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov///
94ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesvoid OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info,
95ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                                            AsmPrinter &AP) {
96f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar  unsigned IntPtrSize = M.getDataLayout().getPointerSize();
97572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen
986948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection());
99ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EmitCamlGlobal(M, AP, "code_end");
1005c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1016948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
102ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EmitCamlGlobal(M, AP, "data_end");
1035c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1047d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner  // FIXME: Why does ocaml emit this??
1056948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->EmitIntValue(0, IntPtrSize);
1065c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1076948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar  AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection());
108ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  EmitCamlGlobal(M, AP, "frametable");
1095c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1103816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray  int NumDescriptors = 0;
111ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
112ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                                           IE = Info.funcinfo_end();
113ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines       I != IE; ++I) {
1143816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray    GCFunctionInfo &FI = **I;
115ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    if (FI.getStrategy().getName() != getStrategy().getName())
116ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      // this function is managed by some other GC
117ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      continue;
1183816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray    for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
1193816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray      NumDescriptors++;
1203816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray    }
1213816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray  }
1223816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray
123ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  if (NumDescriptors >= 1 << 16) {
1243816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray    // Very rude!
1253816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray    report_fatal_error(" Too much descriptor for ocaml GC");
1263816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray  }
1273816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray  AP.EmitInt16(NumDescriptors);
1283816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray  AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
1293816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray
130ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines  for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(),
131ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                                           IE = Info.funcinfo_end();
132ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines       I != IE; ++I) {
1335eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen    GCFunctionInfo &FI = **I;
134ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    if (FI.getStrategy().getName() != getStrategy().getName())
135ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      // this function is managed by some other GC
136ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      continue;
1375c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1385eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen    uint64_t FrameSize = FI.getFrameSize();
139ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines    if (FrameSize >= 1 << 16) {
1401bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer      // Very rude!
1411bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer      report_fatal_error("Function '" + FI.getFunction().getName() +
1421bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer                         "' is too large for the ocaml GC! "
143ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                         "Frame size " +
144ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                         Twine(FrameSize) + ">= 65536.\n"
145ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                                            "(" +
146ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                         Twine(uintptr_t(&FI)) + ")");
1475eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen    }
1485c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1496948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar    AP.OutStreamer->AddComment("live roots for " +
1506948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar                               Twine(FI.getFunction().getName()));
1516948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar    AP.OutStreamer->AddBlankLine();
1525c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1535eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen    for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
1545eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen      size_t LiveCount = FI.live_size(J);
155ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines      if (LiveCount >= 1 << 16) {
1561bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer        // Very rude!
1571bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer        report_fatal_error("Function '" + FI.getFunction().getName() +
1581bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer                           "' is too large for the ocaml GC! "
159ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                           "Live root count " +
160ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                           Twine(LiveCount) + " >= 65536.");
161572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen      }
1625c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1636948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar      AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize);
164572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen      AP.EmitInt16(FrameSize);
165572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen      AP.EmitInt16(LiveCount);
1665c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1675eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen      for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
168ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines                                         KE = FI.live_end(J);
169ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines           K != KE; ++K) {
170ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines        if (K->StackOffset >= 1 << 16) {
1713816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray          // Very rude!
1723816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray          report_fatal_error(
173ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines              "GC root stack offset is outside of fixed stack frame and out "
174ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines              "of range for ocaml GC!");
1753816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray        }
1763816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray        AP.EmitInt16(K->StackOffset);
177572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen      }
1785c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov
1797d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner      AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
180572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen    }
181572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen  }
182572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen}
183