LLVM API Documentation
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 }