Home | History | Annotate | Download | only in CodeGen
      1 //===-- GCMetadata.cpp - Garbage collector metadata -----------------------===//
      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 the GCFunctionInfo class and GCModuleInfo pass.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/ADT/STLExtras.h"
     15 #include "llvm/CodeGen/GCMetadata.h"
     16 #include "llvm/CodeGen/GCStrategy.h"
     17 #include "llvm/CodeGen/Passes.h"
     18 #include "llvm/IR/Function.h"
     19 #include "llvm/MC/MCSymbol.h"
     20 #include "llvm/Pass.h"
     21 #include "llvm/Support/ErrorHandling.h"
     22 #include "llvm/Support/raw_ostream.h"
     23 #include <algorithm>
     24 #include <cassert>
     25 #include <memory>
     26 #include <string>
     27 
     28 using namespace llvm;
     29 
     30 namespace {
     31 
     32 class Printer : public FunctionPass {
     33   static char ID;
     34 
     35   raw_ostream &OS;
     36 
     37 public:
     38   explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {}
     39 
     40   StringRef getPassName() const override;
     41   void getAnalysisUsage(AnalysisUsage &AU) const override;
     42 
     43   bool runOnFunction(Function &F) override;
     44   bool doFinalization(Module &M) override;
     45 };
     46 
     47 } // end anonymous namespace
     48 
     49 INITIALIZE_PASS(GCModuleInfo, "collector-metadata",
     50                 "Create Garbage Collector Module Metadata", false, false)
     51 
     52 // -----------------------------------------------------------------------------
     53 
     54 GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S)
     55     : F(F), S(S), FrameSize(~0LL) {}
     56 
     57 GCFunctionInfo::~GCFunctionInfo() = default;
     58 
     59 // -----------------------------------------------------------------------------
     60 
     61 char GCModuleInfo::ID = 0;
     62 
     63 GCModuleInfo::GCModuleInfo() : ImmutablePass(ID) {
     64   initializeGCModuleInfoPass(*PassRegistry::getPassRegistry());
     65 }
     66 
     67 GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) {
     68   assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!");
     69   assert(F.hasGC());
     70 
     71   finfo_map_type::iterator I = FInfoMap.find(&F);
     72   if (I != FInfoMap.end())
     73     return *I->second;
     74 
     75   GCStrategy *S = getGCStrategy(F.getGC());
     76   Functions.push_back(llvm::make_unique<GCFunctionInfo>(F, *S));
     77   GCFunctionInfo *GFI = Functions.back().get();
     78   FInfoMap[&F] = GFI;
     79   return *GFI;
     80 }
     81 
     82 void GCModuleInfo::clear() {
     83   Functions.clear();
     84   FInfoMap.clear();
     85   GCStrategyList.clear();
     86 }
     87 
     88 // -----------------------------------------------------------------------------
     89 
     90 char Printer::ID = 0;
     91 
     92 FunctionPass *llvm::createGCInfoPrinter(raw_ostream &OS) {
     93   return new Printer(OS);
     94 }
     95 
     96 StringRef Printer::getPassName() const {
     97   return "Print Garbage Collector Information";
     98 }
     99 
    100 void Printer::getAnalysisUsage(AnalysisUsage &AU) const {
    101   FunctionPass::getAnalysisUsage(AU);
    102   AU.setPreservesAll();
    103   AU.addRequired<GCModuleInfo>();
    104 }
    105 
    106 static const char *DescKind(GC::PointKind Kind) {
    107   switch (Kind) {
    108   case GC::PreCall:
    109     return "pre-call";
    110   case GC::PostCall:
    111     return "post-call";
    112   }
    113   llvm_unreachable("Invalid point kind");
    114 }
    115 
    116 bool Printer::runOnFunction(Function &F) {
    117   if (F.hasGC())
    118     return false;
    119 
    120   GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F);
    121 
    122   OS << "GC roots for " << FD->getFunction().getName() << ":\n";
    123   for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(),
    124                                       RE = FD->roots_end();
    125        RI != RE; ++RI)
    126     OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n";
    127 
    128   OS << "GC safe points for " << FD->getFunction().getName() << ":\n";
    129   for (GCFunctionInfo::iterator PI = FD->begin(), PE = FD->end(); PI != PE;
    130        ++PI) {
    131 
    132     OS << "\t" << PI->Label->getName() << ": " << DescKind(PI->Kind)
    133        << ", live = {";
    134 
    135     for (GCFunctionInfo::live_iterator RI = FD->live_begin(PI),
    136                                        RE = FD->live_end(PI);
    137          ;) {
    138       OS << " " << RI->Num;
    139       if (++RI == RE)
    140         break;
    141       OS << ",";
    142     }
    143 
    144     OS << " }\n";
    145   }
    146 
    147   return false;
    148 }
    149 
    150 bool Printer::doFinalization(Module &M) {
    151   GCModuleInfo *GMI = getAnalysisIfAvailable<GCModuleInfo>();
    152   assert(GMI && "Printer didn't require GCModuleInfo?!");
    153   GMI->clear();
    154   return false;
    155 }
    156 
    157 GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) {
    158   // TODO: Arguably, just doing a linear search would be faster for small N
    159   auto NMI = GCStrategyMap.find(Name);
    160   if (NMI != GCStrategyMap.end())
    161     return NMI->getValue();
    162 
    163   for (auto& Entry : GCRegistry::entries()) {
    164     if (Name == Entry.getName()) {
    165       std::unique_ptr<GCStrategy> S = Entry.instantiate();
    166       S->Name = Name;
    167       GCStrategyMap[Name] = S.get();
    168       GCStrategyList.push_back(std::move(S));
    169       return GCStrategyList.back().get();
    170     }
    171   }
    172 
    173   if (GCRegistry::begin() == GCRegistry::end()) {
    174     // In normal operation, the registry should not be empty.  There should
    175     // be the builtin GCs if nothing else.  The most likely scenario here is
    176     // that we got here without running the initializers used by the Registry
    177     // itself and it's registration mechanism.
    178     const std::string error = ("unsupported GC: " + Name).str() +
    179       " (did you remember to link and initialize the CodeGen library?)";
    180     report_fatal_error(error);
    181   } else
    182     report_fatal_error(std::string("unsupported GC: ") + Name);
    183 }
    184