//===-- RustGCPrinter.cpp - Rust garbage collection map printer -----------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the emitter for the Rust garbage collection stack maps. // //===----------------------------------------------------------------------===// #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/CodeGen/GCs.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/GCMetadataPrinter.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCStreamer.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" #include #include using namespace llvm; namespace { enum RustGCMetaType { RGCMT_DestIndex, // Type descriptor index -> type descriptor. RGCMT_SrcIndex, // Value -> type descriptor index. RGCMT_Static // Value with static type descriptor. }; class RustGCMetadataPrinter : public GCMetadataPrinter { private: std::pair GetGCMetadataForRoot(const GCRoot &Root); void EmitGCMetadata(AsmPrinter &AP, MCStreamer &Out, GCRoot &Root); bool HandleDestIndex(const GCRoot &Root); public: void beginAssembly(AsmPrinter &AP) {}; void finishAssembly(AsmPrinter &AP); }; struct OrderedSymbol { unsigned Index; MCSymbol *Sym; OrderedSymbol(unsigned I, MCSymbol *S) : Index(I), Sym(S) {} static OrderedSymbol make(unsigned I, MCSymbol *S) { OrderedSymbol OS(I, S); return OS; } }; } static GCMetadataPrinterRegistry::Add X("rust", "Rust GC metadata printer"); typedef std::vector< std::pair< MCSymbol *,std::vector > > RootMap; std::pair RustGCMetadataPrinter::GetGCMetadataForRoot(const GCRoot &Root) { const GlobalVariable *GCMetaVar = cast(Root.Metadata->stripPointerCasts()); const Constant *GCMetaInit = GCMetaVar->getInitializer(); if (isa(GCMetaInit)) { // "zeroinitializer": expand to (0, 0). IntegerType *I32 = IntegerType::get(GCMetaInit->getContext(), 32); ConstantInt *Zero = ConstantInt::get(I32, 0); return std::make_pair(RGCMT_DestIndex, Zero); } const ConstantStruct *GCMeta = cast(GCMetaVar->getInitializer()); RustGCMetaType GCMetaType = (RustGCMetaType) (cast(GCMeta->getOperand(0))->getZExtValue()); const Constant *Payload = cast(GCMeta->getOperand(1)); return std::make_pair(GCMetaType, Payload); } void RustGCMetadataPrinter::EmitGCMetadata(AsmPrinter &AP, MCStreamer &Out, GCRoot &Root) { int WordSize = AP.TM.getTargetData()->getPointerSize(); std::pair Pair = GetGCMetadataForRoot(Root); const GlobalValue *Tydesc = 0; switch (Pair.first) { case RGCMT_DestIndex: // Dest index. assert(0 && "Dest index should not be here!"); case RGCMT_SrcIndex: // TODO: Use the mapping to find the tydesc frame offset. Out.EmitIntValue(1, WordSize, 0); Out.EmitIntValue(0, WordSize, 0); return; case 2: // Static type descriptor. Out.EmitIntValue(0, WordSize, 0); Tydesc = cast(Pair.second); break; } MCSymbol *TydescSym = AP.Mang->getSymbol(Tydesc); Out.EmitSymbolValue(TydescSym, WordSize, 0); } // Records the destination index of a type descriptor in the type descriptor // map, if this GC root is a destination index. Returns true if the GC root is // a destination index and false otherwise. bool RustGCMetadataPrinter::HandleDestIndex(const GCRoot &Root) { std::pair Pair = GetGCMetadataForRoot(Root); return Pair.first == RGCMT_DestIndex; // TODO } void RustGCMetadataPrinter::finishAssembly(AsmPrinter &AP) { MCStreamer &Out = AP.OutStreamer; // Use the data section. Out.SwitchSection(AP.getObjFileLowering().getDataSection()); // Iterate over each function. RootMap Map; iterator FI = begin(), FE = end(); while (FI != FE) { GCFunctionInfo &GCFI = **FI; // Iterate over each safe point. GCFunctionInfo::iterator SPI = GCFI.begin(), SPE = GCFI.end(); while (SPI != SPE) { std::vector Roots; // Iterate over each live root. GCFunctionInfo::live_iterator LI = GCFI.live_begin(SPI); GCFunctionInfo::live_iterator LE = GCFI.live_end(SPI); while (LI != LE) { if (!HandleDestIndex(*LI)) Roots.push_back(*LI); ++LI; } Map.push_back(std::make_pair(SPI->Label, Roots)); ++SPI; } ++FI; } // Write out the map. Out.AddBlankLine(); int WordSize = AP.TM.getTargetData()->getPointerSize(); MCSymbol *SafePointSym = AP.GetExternalSymbolSymbol("rust_gc_safe_points"); Out.EmitSymbolAttribute(SafePointSym, MCSA_Global); Out.EmitLabel(SafePointSym); Out.EmitIntValue(Map.size(), WordSize, 0); std::vector FrameMapLabels; RootMap::iterator MI = Map.begin(), ME = Map.end(); unsigned i = 0; while (MI != ME) { Out.EmitSymbolValue(MI->first, WordSize, 0); MCSymbol *FrameMapLabel = AP.GetTempSymbol("rust_frame_map_label", i); Out.EmitSymbolValue(FrameMapLabel, WordSize, 0); FrameMapLabels.push_back(FrameMapLabel); ++MI, ++i; } MI = Map.begin(), i = 0; while (MI != ME) { Out.EmitLabel(FrameMapLabels[i]); std::vector &Roots = MI->second; Out.EmitIntValue(Roots.size(), WordSize, 0); std::vector::iterator RI = Roots.begin(), RE = Roots.end(); while (RI != RE) { Out.EmitIntValue(RI->StackOffset, WordSize, 0); EmitGCMetadata(AP, Out, *RI); ++RI; } ++MI, ++i; } }