about summary refs log tree commit diff
path: root/src/rustllvm/RustGCMetadataPrinter.cpp
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2011-08-18 18:08:36 -0700
committerPatrick Walton <pcwalton@mimiga.net>2011-08-18 18:09:45 -0700
commit4a894dae8ec784480cc7d8b127a79f9418e8fa7d (patch)
treeeec0f27322f603be45c40c208acd7ac86d869dbf /src/rustllvm/RustGCMetadataPrinter.cpp
parentd81d86440f16d9f6bc6a97625615da7b51167669 (diff)
downloadrust-4a894dae8ec784480cc7d8b127a79f9418e8fa7d.tar.gz
rust-4a894dae8ec784480cc7d8b127a79f9418e8fa7d.zip
rustllvm: Emit a stack map for frames with only static type descriptors
Diffstat (limited to 'src/rustllvm/RustGCMetadataPrinter.cpp')
-rw-r--r--src/rustllvm/RustGCMetadataPrinter.cpp162
1 files changed, 159 insertions, 3 deletions
diff --git a/src/rustllvm/RustGCMetadataPrinter.cpp b/src/rustllvm/RustGCMetadataPrinter.cpp
index d17d7da1703..d2ee0c3baeb 100644
--- a/src/rustllvm/RustGCMetadataPrinter.cpp
+++ b/src/rustllvm/RustGCMetadataPrinter.cpp
@@ -11,10 +11,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#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/Module.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCSymbol.h"
@@ -27,19 +29,173 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormattedStream.h"
 #include <cctype>
+#include <map>
 
 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<RustGCMetaType,const Constant *>
+      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) {};
+    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<RustGCMetadataPrinter>
-Y("rust", "Rust GC metadata printer");
+X("rust", "Rust GC metadata printer");
+
+
+typedef std::vector< std::pair< MCSymbol *,std::vector<GCRoot> > > RootMap;
+
+std::pair<RustGCMetaType,const Constant *>
+RustGCMetadataPrinter::GetGCMetadataForRoot(const GCRoot &Root) {
+  const GlobalVariable *GCMetaVar =
+    cast<const GlobalVariable>(Root.Metadata->stripPointerCasts());
+
+  const Constant *GCMetaInit = GCMetaVar->getInitializer();
+  if (isa<ConstantAggregateZero>(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<const ConstantStruct>(GCMetaVar->getInitializer());
+
+  RustGCMetaType GCMetaType = (RustGCMetaType)
+    (cast<const ConstantInt>(GCMeta->getOperand(0))->getZExtValue());
+  const Constant *Payload = cast<const Constant>(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<RustGCMetaType,const Constant *> Pair =
+    GetGCMetadataForRoot(Root);
+  const GlobalValue *Tydesc;
+
+  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<const GlobalValue>(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<RustGCMetaType,const Constant *> 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<GCRoot> 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<MCSymbol *> 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);
+    FrameMapLabels.push_back(FrameMapLabel);
+    ++MI, ++i;
+  }
+
+  MI = Map.begin(), i = 0;
+  while (MI != ME) {
+    Out.EmitLabel(FrameMapLabels[i]);
+
+    std::vector<GCRoot> &Roots = MI->second;
+    Out.EmitIntValue(Roots.size(), WordSize, 0);
+
+    std::vector<GCRoot>::iterator RI = Roots.begin(), RE = Roots.end();
+    while (RI != RE) {
+      Out.EmitIntValue(RI->StackOffset, WordSize, 0);
+      EmitGCMetadata(AP, Out, *RI);
+      ++RI;
+    }
+
+    ++MI, ++i;
+  }
+}