OcamlGCPrinter.cpp 6.3 KB

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