OcamlGCPrinter.cpp revision b8f832d331b5206b235262e4395b969d68cf439c
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 // Very rude! 113 report_fatal_error("Function '" + FI.getFunction().getName() + 114 "' is too large for the ocaml GC! " 115 "Frame size " + Twine(FrameSize) + ">= 65536.\n" 116 "(" + Twine(uintptr_t(&FI)) + ")"); 117 } 118 119 AP.OutStreamer.AddComment("live roots for " + 120 Twine(FI.getFunction().getName())); 121 AP.OutStreamer.AddBlankLine(); 122 123 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { 124 size_t LiveCount = FI.live_size(J); 125 if (LiveCount >= 1<<16) { 126 // Very rude! 127 report_fatal_error("Function '" + FI.getFunction().getName() + 128 "' is too large for the ocaml GC! " 129 "Live root count "+Twine(LiveCount)+" >= 65536."); 130 } 131 132 AP.OutStreamer.EmitSymbolValue(J->Label, IntPtrSize, 0); 133 AP.EmitInt16(FrameSize); 134 AP.EmitInt16(LiveCount); 135 136 for (GCFunctionInfo::live_iterator K = FI.live_begin(J), 137 KE = FI.live_end(J); K != KE; ++K) { 138 assert(K->StackOffset < 1<<16 && 139 "GC root stack offset is outside of fixed stack frame and out " 140 "of range for ocaml GC!"); 141 142 AP.EmitInt32(K->StackOffset); 143 } 144 145 AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); 146 } 147 } 148} 149