OcamlGCPrinter.cpp 6.2 KB

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