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