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/CodeGen/AsmPrinter.h"
00016 #include "llvm/CodeGen/GCMetadataPrinter.h"
00017 #include "llvm/Module.h"
00018 #include "llvm/Support/Compiler.h"
00019 #include "llvm/Support/raw_ostream.h"
00020 #include "llvm/Target/TargetAsmInfo.h"
00021 #include "llvm/Target/TargetData.h"
00022 #include "llvm/Target/TargetMachine.h"
00023 
00024 using namespace llvm;
00025 
00026 namespace {
00027 
00028   class VISIBILITY_HIDDEN OcamlGCMetadataPrinter : public GCMetadataPrinter {
00029   public:
00030     void beginAssembly(raw_ostream &OS, AsmPrinter &AP,
00031                        const TargetAsmInfo &TAI);
00032 
00033     void finishAssembly(raw_ostream &OS, AsmPrinter &AP,
00034                         const TargetAsmInfo &TAI);
00035   };
00036 
00037 }
00038 
00039 static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter>
00040 Y("ocaml", "ocaml 3.10-compatible collector");
00041 
00042 void llvm::linkOcamlGCPrinter() { }
00043 
00044 static void EmitCamlGlobal(const Module &M, raw_ostream &OS, AsmPrinter &AP,
00045                            const TargetAsmInfo &TAI, const char *Id) {
00046   const std::string &MId = M.getModuleIdentifier();
00047 
00048   std::string Mangled;
00049   Mangled += TAI.getGlobalPrefix();
00050   Mangled += "caml";
00051   size_t Letter = Mangled.size();
00052   Mangled.append(MId.begin(), std::find(MId.begin(), MId.end(), '.'));
00053   Mangled += "__";
00054   Mangled += Id;
00055 
00056   // Capitalize the first letter of the module name.
00057   Mangled[Letter] = toupper(Mangled[Letter]);
00058 
00059   if (const char *GlobalDirective = TAI.getGlobalDirective())
00060     OS << GlobalDirective << Mangled << "\n";
00061   OS << Mangled << ":\n";
00062 }
00063 
00064 void OcamlGCMetadataPrinter::beginAssembly(raw_ostream &OS, AsmPrinter &AP,
00065                                            const TargetAsmInfo &TAI) {
00066   AP.SwitchToSection(TAI.getTextSection());
00067   EmitCamlGlobal(getModule(), OS, AP, TAI, "code_begin");
00068 
00069   AP.SwitchToSection(TAI.getDataSection());
00070   EmitCamlGlobal(getModule(), OS, AP, TAI, "data_begin");
00071 }
00072 
00073 /// emitAssembly - Print the frametable. The ocaml frametable format is thus:
00074 ///
00075 ///   extern "C" struct align(sizeof(intptr_t)) {
00076 ///     uint16_t NumDescriptors;
00077 ///     struct align(sizeof(intptr_t)) {
00078 ///       void *ReturnAddress;
00079 ///       uint16_t FrameSize;
00080 ///       uint16_t NumLiveOffsets;
00081 ///       uint16_t LiveOffsets[NumLiveOffsets];
00082 ///     } Descriptors[NumDescriptors];
00083 ///   } caml${module}__frametable;
00084 ///
00085 /// Note that this precludes programs from stack frames larger than 64K
00086 /// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if
00087 /// either condition is detected in a function which uses the GC.
00088 ///
00089 void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP,
00090                                             const TargetAsmInfo &TAI) {
00091   const char *AddressDirective;
00092   int AddressAlignLog;
00093   if (AP.TM.getTargetData()->getPointerSize() == sizeof(int32_t)) {
00094     AddressDirective = TAI.getData32bitsDirective();
00095     AddressAlignLog = 2;
00096   } else {
00097     AddressDirective = TAI.getData64bitsDirective();
00098     AddressAlignLog = 3;
00099   }
00100 
00101   AP.SwitchToSection(TAI.getTextSection());
00102   EmitCamlGlobal(getModule(), OS, AP, TAI, "code_end");
00103 
00104   AP.SwitchToSection(TAI.getDataSection());
00105   EmitCamlGlobal(getModule(), OS, AP, TAI, "data_end");
00106 
00107   OS << AddressDirective << 0; // FIXME: Why does ocaml emit this??
00108   AP.EOL();
00109 
00110   AP.SwitchToSection(TAI.getDataSection());
00111   EmitCamlGlobal(getModule(), OS, AP, TAI, "frametable");
00112 
00113   for (iterator I = begin(), IE = end(); I != IE; ++I) {
00114     GCFunctionInfo &FI = **I;
00115 
00116     uint64_t FrameSize = FI.getFrameSize();
00117     if (FrameSize >= 1<<16) {
00118       cerr << "Function '" << FI.getFunction().getNameStart()
00119            << "' is too large for the ocaml GC! "
00120            << "Frame size " << FrameSize << " >= 65536.\n";
00121       cerr << "(" << uintptr_t(&FI) << ")\n";
00122       abort(); // Very rude!
00123     }
00124 
00125     OS << "\t" << TAI.getCommentString() << " live roots for "
00126        << FI.getFunction().getNameStart() << "\n";
00127 
00128     for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) {
00129       size_t LiveCount = FI.live_size(J);
00130       if (LiveCount >= 1<<16) {
00131         cerr << "Function '" << FI.getFunction().getNameStart()
00132              << "' is too large for the ocaml GC! "
00133              << "Live root count " << LiveCount << " >= 65536.\n";
00134         abort(); // Very rude!
00135       }
00136 
00137       OS << AddressDirective
00138          << TAI.getPrivateGlobalPrefix() << "label" << J->Num;
00139       AP.EOL("call return address");
00140 
00141       AP.EmitInt16(FrameSize);
00142       AP.EOL("stack frame size");
00143 
00144       AP.EmitInt16(LiveCount);
00145       AP.EOL("live root count");
00146 
00147       for (GCFunctionInfo::live_iterator K = FI.live_begin(J),
00148                                          KE = FI.live_end(J); K != KE; ++K) {
00149         assert(K->StackOffset < 1<<16 &&
00150                "GC root stack offset is outside of fixed stack frame and out "
00151                "of range for ocaml GC!");
00152 
00153         OS << "\t.word\t" << K->StackOffset;
00154         AP.EOL("stack offset");
00155       }
00156 
00157       AP.EmitAlignment(AddressAlignLog);
00158     }
00159   }
00160 }