1 //===-- GCMetadata.cpp - Garbage collector metadata -----------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the GCFunctionInfo class and GCModuleInfo pass. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/CodeGen/GCMetadata.h" 14 #include "llvm/ADT/StringExtras.h" 15 #include "llvm/CodeGen/Passes.h" 16 #include "llvm/IR/Function.h" 17 #include "llvm/InitializePasses.h" 18 #include "llvm/MC/MCSymbol.h" 19 #include "llvm/Pass.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <cassert> 22 #include <memory> 23 #include <string> 24 25 using namespace llvm; 26 27 namespace { 28 29 class Printer : public FunctionPass { 30 static char ID; 31 32 raw_ostream &OS; 33 34 public: 35 explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {} 36 37 StringRef getPassName() const override; 38 void getAnalysisUsage(AnalysisUsage &AU) const override; 39 40 bool runOnFunction(Function &F) override; 41 bool doFinalization(Module &M) override; 42 }; 43 44 } // end anonymous namespace 45 46 INITIALIZE_PASS(GCModuleInfo, "collector-metadata", 47 "Create Garbage Collector Module Metadata", false, false) 48 49 // ----------------------------------------------------------------------------- 50 51 GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S) 52 : F(F), S(S), FrameSize(~0LL) {} 53 54 GCFunctionInfo::~GCFunctionInfo() = default; 55 56 // ----------------------------------------------------------------------------- 57 58 char GCModuleInfo::ID = 0; 59 60 GCModuleInfo::GCModuleInfo() : ImmutablePass(ID) { 61 initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); 62 } 63 64 GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) { 65 assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!"); 66 assert(F.hasGC()); 67 68 finfo_map_type::iterator I = FInfoMap.find(&F); 69 if (I != FInfoMap.end()) 70 return *I->second; 71 72 GCStrategy *S = getGCStrategy(F.getGC()); 73 Functions.push_back(std::make_unique<GCFunctionInfo>(F, *S)); 74 GCFunctionInfo *GFI = Functions.back().get(); 75 FInfoMap[&F] = GFI; 76 return *GFI; 77 } 78 79 void GCModuleInfo::clear() { 80 Functions.clear(); 81 FInfoMap.clear(); 82 GCStrategyList.clear(); 83 } 84 85 // ----------------------------------------------------------------------------- 86 87 char Printer::ID = 0; 88 89 FunctionPass *llvm::createGCInfoPrinter(raw_ostream &OS) { 90 return new Printer(OS); 91 } 92 93 StringRef Printer::getPassName() const { 94 return "Print Garbage Collector Information"; 95 } 96 97 void Printer::getAnalysisUsage(AnalysisUsage &AU) const { 98 FunctionPass::getAnalysisUsage(AU); 99 AU.setPreservesAll(); 100 AU.addRequired<GCModuleInfo>(); 101 } 102 103 bool Printer::runOnFunction(Function &F) { 104 if (F.hasGC()) 105 return false; 106 107 GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F); 108 109 OS << "GC roots for " << FD->getFunction().getName() << ":\n"; 110 for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(), 111 RE = FD->roots_end(); 112 RI != RE; ++RI) 113 OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n"; 114 115 OS << "GC safe points for " << FD->getFunction().getName() << ":\n"; 116 for (GCFunctionInfo::iterator PI = FD->begin(), PE = FD->end(); PI != PE; 117 ++PI) { 118 119 OS << "\t" << PI->Label->getName() << ": " << "post-call" 120 << ", live = {"; 121 122 ListSeparator LS(","); 123 for (const GCRoot &R : make_range(FD->live_begin(PI), FD->live_end(PI))) 124 OS << LS << " " << R.Num; 125 126 OS << " }\n"; 127 } 128 129 return false; 130 } 131 132 bool Printer::doFinalization(Module &M) { 133 GCModuleInfo *GMI = getAnalysisIfAvailable<GCModuleInfo>(); 134 assert(GMI && "Printer didn't require GCModuleInfo?!"); 135 GMI->clear(); 136 return false; 137 } 138 139 GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) { 140 // TODO: Arguably, just doing a linear search would be faster for small N 141 auto NMI = GCStrategyMap.find(Name); 142 if (NMI != GCStrategyMap.end()) 143 return NMI->getValue(); 144 145 std::unique_ptr<GCStrategy> S = llvm::getGCStrategy(Name); 146 S->Name = std::string(Name); 147 GCStrategyMap[Name] = S.get(); 148 GCStrategyList.push_back(std::move(S)); 149 return GCStrategyList.back().get(); 150 } 151