LCOV - code coverage report
Current view: top level - lib/CodeGen/AsmPrinter - OcamlGCPrinter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 48 57 84.2 %
Date: 2018-10-20 13:21:21 Functions: 3 4 75.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13