OcamlGCPrinter.cpp revision cb3718832375a581c5ea23f15918f3ea447a446c
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/Support/raw_ostream.h" 19#include "llvm/Target/TargetAsmInfo.h" 20#include "llvm/Target/TargetData.h" 21#include "llvm/Target/TargetMachine.h" 22 23using namespace llvm; 24 25namespace { 26 27 class VISIBILITY_HIDDEN OcamlGCMetadataPrinter : public GCMetadataPrinter { 28 public: 29 void beginAssembly(raw_ostream &OS, AsmPrinter &AP, 30 const TargetAsmInfo &TAI); 31 32 void finishAssembly(raw_ostream &OS, AsmPrinter &AP, 33 const TargetAsmInfo &TAI); 34 }; 35 36} 37 38static GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter> 39Y("ocaml", "ocaml 3.10-compatible collector"); 40 41void llvm::linkOcamlGCPrinter() { } 42 43static void EmitCamlGlobal(const Module &M, raw_ostream &OS, AsmPrinter &AP, 44 const TargetAsmInfo &TAI, const char *Id) { 45 const std::string &MId = M.getModuleIdentifier(); 46 47 std::string Mangled; 48 Mangled += TAI.getGlobalPrefix(); 49 Mangled += "caml"; 50 size_t Letter = Mangled.size(); 51 Mangled.append(MId.begin(), std::find(MId.begin(), MId.end(), '.')); 52 Mangled += "__"; 53 Mangled += Id; 54 55 // Capitalize the first letter of the module name. 56 Mangled[Letter] = toupper(Mangled[Letter]); 57 58 if (const char *GlobalDirective = TAI.getGlobalDirective()) 59 OS << GlobalDirective << Mangled << "\n"; 60 OS << Mangled << ":\n"; 61} 62 63void OcamlGCMetadataPrinter::beginAssembly(raw_ostream &OS, AsmPrinter &AP, 64 const TargetAsmInfo &TAI) { 65 AP.SwitchToTextSection(TAI.getTextSection()); 66 EmitCamlGlobal(getModule(), OS, AP, TAI, "code_begin"); 67 68 AP.SwitchToDataSection(TAI.getDataSection()); 69 EmitCamlGlobal(getModule(), OS, AP, TAI, "data_begin"); 70} 71 72/// emitAssembly - Print the frametable. The ocaml frametable format is thus: 73/// 74/// extern "C" struct align(sizeof(intptr_t)) { 75/// uint16_t NumDescriptors; 76/// struct align(sizeof(intptr_t)) { 77/// void *ReturnAddress; 78/// uint16_t FrameSize; 79/// uint16_t NumLiveOffsets; 80/// uint16_t LiveOffsets[NumLiveOffsets]; 81/// } Descriptors[NumDescriptors]; 82/// } caml${module}__frametable; 83/// 84/// Note that this precludes programs from stack frames larger than 64K 85/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if 86/// either condition is detected in a function which uses the GC. 87/// 88void OcamlGCMetadataPrinter::finishAssembly(raw_ostream &OS, AsmPrinter &AP, 89 const TargetAsmInfo &TAI) { 90 const char *AddressDirective; 91 int AddressAlignLog; 92 if (AP.TM.getTargetData()->getPointerSize() == sizeof(int32_t)) { 93 AddressDirective = TAI.getData32bitsDirective(); 94 AddressAlignLog = 2; 95 } else { 96 AddressDirective = TAI.getData64bitsDirective(); 97 AddressAlignLog = 3; 98 } 99 100 AP.SwitchToTextSection(TAI.getTextSection()); 101 EmitCamlGlobal(getModule(), OS, AP, TAI, "code_end"); 102 103 AP.SwitchToDataSection(TAI.getDataSection()); 104 EmitCamlGlobal(getModule(), OS, AP, TAI, "data_end"); 105 106 OS << AddressDirective << 0; // FIXME: Why does ocaml emit this?? 107 AP.EOL(); 108 109 AP.SwitchToDataSection(TAI.getDataSection()); 110 EmitCamlGlobal(getModule(), OS, AP, TAI, "frametable"); 111 112 for (iterator I = begin(), IE = end(); I != IE; ++I) { 113 GCFunctionInfo &FI = **I; 114 115 uint64_t FrameSize = FI.getFrameSize(); 116 if (FrameSize >= 1<<16) { 117 cerr << "Function '" << FI.getFunction().getNameStart() 118 << "' is too large for the ocaml GC! " 119 << "Frame size " << FrameSize << " >= 65536.\n"; 120 cerr << "(" << uintptr_t(&FI) << ")\n"; 121 abort(); // Very rude! 122 } 123 124 OS << "\t" << TAI.getCommentString() << " live roots for " 125 << FI.getFunction().getNameStart() << "\n"; 126 127 for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { 128 size_t LiveCount = FI.live_size(J); 129 if (LiveCount >= 1<<16) { 130 cerr << "Function '" << FI.getFunction().getNameStart() 131 << "' is too large for the ocaml GC! " 132 << "Live root count " << LiveCount << " >= 65536.\n"; 133 abort(); // Very rude! 134 } 135 136 OS << AddressDirective 137 << TAI.getPrivateGlobalPrefix() << "label" << J->Num; 138 AP.EOL("call return address"); 139 140 AP.EmitInt16(FrameSize); 141 AP.EOL("stack frame size"); 142 143 AP.EmitInt16(LiveCount); 144 AP.EOL("live root count"); 145 146 for (GCFunctionInfo::live_iterator K = FI.live_begin(J), 147 KE = FI.live_end(J); K != KE; ++K) { 148 assert(K->StackOffset < 1<<16 && 149 "GC root stack offset is outside of fixed stack frame and out " 150 "of range for ocaml GC!"); 151 152 OS << "\t.word\t" << K->StackOffset; 153 AP.EOL("stack offset"); 154 } 155 156 AP.EmitAlignment(AddressAlignLog); 157 } 158 } 159} 160