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