15eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen//===-- OcamlGCPrinter.cpp - Ocaml frametable emitter ---------------------===// 2572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// 3572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// The LLVM Compiler Infrastructure 4572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// 5572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// This file is distributed under the University of Illinois Open Source 6572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// License. See LICENSE.TXT for details. 7572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// 8572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//===----------------------------------------------------------------------===// 9572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// 105eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen// This file implements printing the assembly code for an Ocaml frametable. 11572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen// 12572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen//===----------------------------------------------------------------------===// 135c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 145a29c9eed157af51a8d338b5a225b146881819e8Gordon Henriksen#include "llvm/CodeGen/GCs.h" 15d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/ADT/SmallString.h" 16572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen#include "llvm/CodeGen/AsmPrinter.h" 175eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen#include "llvm/CodeGen/GCMetadataPrinter.h" 180b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/DataLayout.h" 1936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/IR/Mangler.h" 200b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/IR/Module.h" 21af76e592c7f9deff0e55c13dbb4a34f07f1c7f64Chris Lattner#include "llvm/MC/MCAsmInfo.h" 227d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner#include "llvm/MC/MCContext.h" 239a38e67590fa1431bd7e950f4ce2684d9f572176Chris Lattner#include "llvm/MC/MCStreamer.h" 24d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/MC/MCSymbol.h" 25d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/ErrorHandling.h" 26d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/Support/FormattedStream.h" 27f0144127b98425d214e59e4a1a4b342b78e3642bChris Lattner#include "llvm/Target/TargetLoweringObjectFile.h" 28572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen#include "llvm/Target/TargetMachine.h" 2937ed9c199ca639565f6ce88105f9e39e898d82d0Stephen Hines#include "llvm/Target/TargetSubtargetInfo.h" 30476b242fe7a61e5f9ac6214b0bc5c680d24f152eNick Lewycky#include <cctype> 31572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksenusing namespace llvm; 32572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 33572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksennamespace { 34572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 35ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesclass OcamlGCMetadataPrinter : public GCMetadataPrinter { 36ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinespublic: 37ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override; 38ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) override; 39ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines}; 40572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen} 41572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 42c317a60c2714a5b90700a11ba646285cb754a5d3Gordon Henriksenstatic GCMetadataPrinterRegistry::Add<OcamlGCMetadataPrinter> 43ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines Y("ocaml", "ocaml 3.10-compatible collector"); 44c317a60c2714a5b90700a11ba646285cb754a5d3Gordon Henriksen 45ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesvoid llvm::linkOcamlGCPrinter() {} 46572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 477d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattnerstatic void EmitCamlGlobal(const Module &M, AsmPrinter &AP, const char *Id) { 48572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen const std::string &MId = M.getModuleIdentifier(); 495c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 507d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner std::string SymName; 517d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner SymName += "caml"; 527d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner size_t Letter = SymName.size(); 537d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner SymName.append(MId.begin(), std::find(MId.begin(), MId.end(), '.')); 547d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner SymName += "__"; 557d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner SymName += Id; 56dd2ad8432f104282ff43c94457f474ea0a264175Mikhail Glushenkov 57572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen // Capitalize the first letter of the module name. 587d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner SymName[Letter] = toupper(SymName[Letter]); 59dd2ad8432f104282ff43c94457f474ea0a264175Mikhail Glushenkov 607d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner SmallString<128> TmpStr; 61f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar Mangler::getNameWithPrefix(TmpStr, SymName, M.getDataLayout()); 62dd2ad8432f104282ff43c94457f474ea0a264175Mikhail Glushenkov 636948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar MCSymbol *Sym = AP.OutContext.getOrCreateSymbol(TmpStr); 647d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner 656948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->EmitSymbolAttribute(Sym, MCSA_Global); 666948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->EmitLabel(Sym); 67572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen} 68572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 69ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesvoid OcamlGCMetadataPrinter::beginAssembly(Module &M, GCModuleInfo &Info, 70ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines AsmPrinter &AP) { 716948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection()); 72ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines EmitCamlGlobal(M, AP, "code_begin"); 735c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 746948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); 75ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines EmitCamlGlobal(M, AP, "data_begin"); 76572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen} 77572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 78572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// emitAssembly - Print the frametable. The ocaml frametable format is thus: 795c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov/// 80572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// extern "C" struct align(sizeof(intptr_t)) { 81572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// uint16_t NumDescriptors; 82572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// struct align(sizeof(intptr_t)) { 83572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// void *ReturnAddress; 84572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// uint16_t FrameSize; 85572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// uint16_t NumLiveOffsets; 86572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// uint16_t LiveOffsets[NumLiveOffsets]; 87572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// } Descriptors[NumDescriptors]; 88572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// } caml${module}__frametable; 895c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov/// 90572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// Note that this precludes programs from stack frames larger than 64K 91572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter will abort if 925eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen/// either condition is detected in a function which uses the GC. 935c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov/// 94ebe69fe11e48d322045d5949c83283927a0d790bStephen Hinesvoid OcamlGCMetadataPrinter::finishAssembly(Module &M, GCModuleInfo &Info, 95ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines AsmPrinter &AP) { 96f3ef5332fa3f4d5ec72c178a2b19dac363a19383Pirama Arumuga Nainar unsigned IntPtrSize = M.getDataLayout().getPointerSize(); 97572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen 986948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getTextSection()); 99ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines EmitCamlGlobal(M, AP, "code_end"); 1005c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1016948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); 102ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines EmitCamlGlobal(M, AP, "data_end"); 1035c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1047d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner // FIXME: Why does ocaml emit this?? 1056948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->EmitIntValue(0, IntPtrSize); 1065c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1076948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->SwitchSection(AP.getObjFileLowering().getDataSection()); 108ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines EmitCamlGlobal(M, AP, "frametable"); 1095c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1103816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray int NumDescriptors = 0; 111ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), 112ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines IE = Info.funcinfo_end(); 113ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines I != IE; ++I) { 1143816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray GCFunctionInfo &FI = **I; 115ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (FI.getStrategy().getName() != getStrategy().getName()) 116ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines // this function is managed by some other GC 117ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines continue; 1183816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { 1193816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray NumDescriptors++; 1203816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray } 1213816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray } 1223816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray 123ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (NumDescriptors >= 1 << 16) { 1243816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray // Very rude! 1253816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray report_fatal_error(" Too much descriptor for ocaml GC"); 1263816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray } 1273816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray AP.EmitInt16(NumDescriptors); 1283816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); 1293816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray 130ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines for (GCModuleInfo::FuncInfoVec::iterator I = Info.funcinfo_begin(), 131ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines IE = Info.funcinfo_end(); 132ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines I != IE; ++I) { 1335eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen GCFunctionInfo &FI = **I; 134ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (FI.getStrategy().getName() != getStrategy().getName()) 135ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines // this function is managed by some other GC 136ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines continue; 1375c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1385eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen uint64_t FrameSize = FI.getFrameSize(); 139ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (FrameSize >= 1 << 16) { 1401bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer // Very rude! 1411bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer report_fatal_error("Function '" + FI.getFunction().getName() + 1421bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer "' is too large for the ocaml GC! " 143ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines "Frame size " + 144ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines Twine(FrameSize) + ">= 65536.\n" 145ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines "(" + 146ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines Twine(uintptr_t(&FI)) + ")"); 1475eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen } 1485c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1496948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->AddComment("live roots for " + 1506948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar Twine(FI.getFunction().getName())); 1516948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->AddBlankLine(); 1525c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1535eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen for (GCFunctionInfo::iterator J = FI.begin(), JE = FI.end(); J != JE; ++J) { 1545eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen size_t LiveCount = FI.live_size(J); 155ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (LiveCount >= 1 << 16) { 1561bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer // Very rude! 1571bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer report_fatal_error("Function '" + FI.getFunction().getName() + 1581bd7335a17010bd4d8f86736cf73cac9f3fb80a5Benjamin Kramer "' is too large for the ocaml GC! " 159ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines "Live root count " + 160ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines Twine(LiveCount) + " >= 65536."); 161572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen } 1625c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1636948897e478cbd66626159776a8017b3c18579b9Pirama Arumuga Nainar AP.OutStreamer->EmitSymbolValue(J->Label, IntPtrSize); 164572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen AP.EmitInt16(FrameSize); 165572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen AP.EmitInt16(LiveCount); 1665c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1675eca075b74d62c621b160aa216b4cd50829a2cc7Gordon Henriksen for (GCFunctionInfo::live_iterator K = FI.live_begin(J), 168ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines KE = FI.live_end(J); 169ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines K != KE; ++K) { 170ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines if (K->StackOffset >= 1 << 16) { 1713816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray // Very rude! 1723816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray report_fatal_error( 173ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines "GC root stack offset is outside of fixed stack frame and out " 174ebe69fe11e48d322045d5949c83283927a0d790bStephen Hines "of range for ocaml GC!"); 1753816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray } 1763816c25fdc03fb2945ecfe4df41e1834ea386245Nicolas Geoffray AP.EmitInt16(K->StackOffset); 177572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen } 1785c1799b29375fcd899f67a31fb4dda4ef3e2127fMikhail Glushenkov 1797d73c7f0d618dd6661cd55834c58aa62f22b28feChris Lattner AP.EmitAlignment(IntPtrSize == 4 ? 2 : 3); 180572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen } 181572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen } 182572742e876478d3ec7ff0750c0473d7621804b15Gordon Henriksen} 183