LLVM API Documentation

OcamlGCPrinter.cpp
Go to the documentation of this file.
00001 //===-- OcamlGCPrinter.cpp - Ocaml frametable emitter ---------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements printing the assembly code for an Ocaml frametable.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "llvm/CodeGen/GCs.h"
00015 #include "llvm/ADT/SmallString.h"
00016 #include "llvm/CodeGen/AsmPrinter.h"
00017 #include "llvm/CodeGen/GCMetadataPrinter.h"
00018 #include "llvm/IR/DataLayout.h"
00019 #include "llvm/IR/Mangler.h"
00020 #include "llvm/IR/Module.h"
00021 #include "llvm/MC/MCAsmInfo.h"
00022 #include "llvm/MC/MCContext.h"
00023 #include "llvm/MC/MCStreamer.h"
00024 #include "llvm/MC/MCSymbol.h"
00025 #include "llvm/Support/ErrorHandling.h"
00026 #include "llvm/Support/FormattedStream.h"
00027 #include "llvm/Target/TargetLoweringObjectFile.h"
00028 #include "llvm/Target/TargetMachine.h"
00029 #include "llvm/Target/TargetSubtargetInfo.h"
00030 #include <cctype>
00031 using namespace llvm;
00032 
00033 namespace {
00034 
00035   class OcamlGCMetadataPrinter : public GCMetadataPrinter {
00036   public:
00037     void beginAssembly(AsmPrinter &AP) override;
00038     void finishAssembly(AsmPrinter &AP) override;
00039   };
00040 
00041 }
00042 
00043 static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
00044 Y("ocaml", "ocaml 3.10-compatible collector");
00045 
00046 void llvm::linkOcamlGCPrinter() { }
00047 
00048 static void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) {
00049   const std::string &MId = M.getModuleIdentifier();
00050 
00051   std::string SymName;
00052   SymName += "caml";
00053   size_t Letter = SymName.size();
00054   SymName.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
00055   SymName += "__";
00056   SymName += Id;
00057 
00058   // Capitalize the first letter of the module name.
00059   SymName[Letter] = toupper(SymName[Letter]);
00060 
00061   SmallString<128> TmpStr;
00062   AP.Mang->getNameWithPrefix(TmpStr, SymName);
00063 
00064   MCSymbol *Sym = AP.OutContext.GetOrCreateSymbol(TmpStr);
00065 
00066   AP.OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global);
00067   AP.OutStreamer.EmitLabel(Sym);
00068 }
00069 
00070 void OcamlGCMetadataPrinter::beginAssembly(AsmPrinter &AP) {
00071   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection());
00072   EmitCamlGlobal(getModule(), AP, "code_begin");
00073 
00074   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
00075   EmitCamlGlobal(getModule(), AP, "data_begin");
00076 }
00077 
00078 /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
00079 ///
00080 ///   extern "C" struct align(sizeof(intptr_t)) {
00081 ///     uint16_t NumDescriptors;
00082 ///     struct align(sizeof(intptr_t)) {
00083 ///       void *ReturnAddress;
00084 ///       uint16_t FrameSize;
00085 ///       uint16_t NumLiveOffsets;
00086 ///       uint16_t LiveOffsets[NumLiveOffsets];
00087 ///     } Descriptors[NumDescriptors];
00088 ///   } caml${module}__frametable;
00089 ///
00090 /// Note that this precludes programs from stack frames larger than 64K
00091 /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
00092 /// either condition is detected in a function which uses the GC.
00093 ///
00094 void OcamlGCMetadataPrinter::finishAssembly(AsmPrinter &AP) {
00095   unsigned IntPtrSize =
00096       AP.TM.getSubtargetImpl()->getDataLayout()->getPointerSize();
00097 
00098   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getTextSection());
00099   EmitCamlGlobal(getModule(), AP, "code_end");
00100 
00101   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
00102   EmitCamlGlobal(getModule(), AP, "data_end");
00103 
00104   // FIXME: Why does ocaml emit this??
00105   AP.OutStreamer.EmitIntValue(0, IntPtrSize);
00106 
00107   AP.OutStreamer.SwitchSection(AP.getObjFileLowering().getDataSection());
00108   EmitCamlGlobal(getModule(), AP, "frametable");
00109 
00110   int NumDescriptors = 0;
00111   for (iterator I = begin(), IE = end(); I != IE; ++I) {
00112     GCFunctionInfo &FI = **I;
00113     for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
00114       NumDescriptors++;
00115     }
00116   }
00117 
00118   if (NumDescriptors >= 1<<16) {
00119     // Very rude!
00120     report_fatal_error(" Too much descriptor for ocaml GC");
00121   }
00122   AP.EmitInt16(NumDescriptors);
00123   AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
00124 
00125   for (iterator I = begin(), IE = end(); I != IE; ++I) {
00126     GCFunctionInfo &FI = **I;
00127 
00128     uint64_t FrameSize = FI.getFrameSize();
00129     if (FrameSize >= 1<<16) {
00130       // Very rude!
00131       report_fatal_error("Function '" + FI.getFunction().getName() +
00132                          "' is too large for the ocaml GC! "
00133                          "Frame size " + Twine(FrameSize) + ">= 65536.\n"
00134                          "(" + Twine(uintptr_t(&FI)) + ")");
00135     }
00136 
00137     AP.OutStreamer.AddComment("live roots for " +
00138                               Twine(FI.getFunction().getName()));
00139     AP.OutStreamer.AddBlankLine();
00140 
00141     for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
00142       size_t LiveCount = FI.live_size(J);
00143       if (LiveCount >= 1<<16) {
00144         // Very rude!
00145         report_fatal_error("Function '" + FI.getFunction().getName() +
00146                            "' is too large for the ocaml GC! "
00147                            "Live root count "+Twine(LiveCount)+" >= 65536.");
00148       }
00149 
00150       AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize);
00151       AP.EmitInt16(FrameSize);
00152       AP.EmitInt16(LiveCount);
00153 
00154       for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
00155                                          KE = FI.live_end(J); K != KE; ++K) {
00156         if (K->StackOffset >= 1<<16) {
00157           // Very rude!
00158           report_fatal_error(
00159                  "GC root stack offset is outside of fixed stack frame and out "
00160                  "of range for ocaml GC!");
00161         }
00162         AP.EmitInt16(K->StackOffset);
00163       }
00164 
00165       AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3);
00166     }
00167   }
00168 }