10b57cec5SDimitry Andric //===-- GCMetadata.cpp - Garbage collector metadata -----------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the GCFunctionInfo class and GCModuleInfo pass. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/CodeGen/GCMetadata.h" 14*480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/GCStrategy.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 170b57cec5SDimitry Andric #include "llvm/IR/Function.h" 18*480093f4SDimitry Andric #include "llvm/InitializePasses.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 200b57cec5SDimitry Andric #include "llvm/Pass.h" 210b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 230b57cec5SDimitry Andric #include <algorithm> 240b57cec5SDimitry Andric #include <cassert> 250b57cec5SDimitry Andric #include <memory> 260b57cec5SDimitry Andric #include <string> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric using namespace llvm; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric namespace { 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric class Printer : public FunctionPass { 330b57cec5SDimitry Andric static char ID; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric raw_ostream &OS; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric public: 380b57cec5SDimitry Andric explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {} 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric StringRef getPassName() const override; 410b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric bool runOnFunction(Function &F) override; 440b57cec5SDimitry Andric bool doFinalization(Module &M) override; 450b57cec5SDimitry Andric }; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric } // end anonymous namespace 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric INITIALIZE_PASS(GCModuleInfo, "collector-metadata", 500b57cec5SDimitry Andric "Create Garbage Collector Module Metadata", false, false) 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric // ----------------------------------------------------------------------------- 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S) 550b57cec5SDimitry Andric : F(F), S(S), FrameSize(~0LL) {} 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric GCFunctionInfo::~GCFunctionInfo() = default; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // ----------------------------------------------------------------------------- 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric char GCModuleInfo::ID = 0; 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric GCModuleInfo::GCModuleInfo() : ImmutablePass(ID) { 640b57cec5SDimitry Andric initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) { 680b57cec5SDimitry Andric assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!"); 690b57cec5SDimitry Andric assert(F.hasGC()); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric finfo_map_type::iterator I = FInfoMap.find(&F); 720b57cec5SDimitry Andric if (I != FInfoMap.end()) 730b57cec5SDimitry Andric return *I->second; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric GCStrategy *S = getGCStrategy(F.getGC()); 768bcb0991SDimitry Andric Functions.push_back(std::make_unique<GCFunctionInfo>(F, *S)); 770b57cec5SDimitry Andric GCFunctionInfo *GFI = Functions.back().get(); 780b57cec5SDimitry Andric FInfoMap[&F] = GFI; 790b57cec5SDimitry Andric return *GFI; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric void GCModuleInfo::clear() { 830b57cec5SDimitry Andric Functions.clear(); 840b57cec5SDimitry Andric FInfoMap.clear(); 850b57cec5SDimitry Andric GCStrategyList.clear(); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric // ----------------------------------------------------------------------------- 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric char Printer::ID = 0; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric FunctionPass *llvm::createGCInfoPrinter(raw_ostream &OS) { 930b57cec5SDimitry Andric return new Printer(OS); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric StringRef Printer::getPassName() const { 970b57cec5SDimitry Andric return "Print Garbage Collector Information"; 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric void Printer::getAnalysisUsage(AnalysisUsage &AU) const { 1010b57cec5SDimitry Andric FunctionPass::getAnalysisUsage(AU); 1020b57cec5SDimitry Andric AU.setPreservesAll(); 1030b57cec5SDimitry Andric AU.addRequired<GCModuleInfo>(); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric bool Printer::runOnFunction(Function &F) { 1070b57cec5SDimitry Andric if (F.hasGC()) 1080b57cec5SDimitry Andric return false; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric OS << "GC roots for " << FD->getFunction().getName() << ":\n"; 1130b57cec5SDimitry Andric for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(), 1140b57cec5SDimitry Andric RE = FD->roots_end(); 1150b57cec5SDimitry Andric RI != RE; ++RI) 1160b57cec5SDimitry Andric OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n"; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric OS << "GC safe points for " << FD->getFunction().getName() << ":\n"; 1190b57cec5SDimitry Andric for (GCFunctionInfo::iterator PI = FD->begin(), PE = FD->end(); PI != PE; 1200b57cec5SDimitry Andric ++PI) { 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric OS << "\t" << PI->Label->getName() << ": " << "post-call" 1230b57cec5SDimitry Andric << ", live = {"; 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric for (GCFunctionInfo::live_iterator RI = FD->live_begin(PI), 1260b57cec5SDimitry Andric RE = FD->live_end(PI); 1270b57cec5SDimitry Andric ;) { 1280b57cec5SDimitry Andric OS << " " << RI->Num; 1290b57cec5SDimitry Andric if (++RI == RE) 1300b57cec5SDimitry Andric break; 1310b57cec5SDimitry Andric OS << ","; 1320b57cec5SDimitry Andric } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric OS << " }\n"; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric return false; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric bool Printer::doFinalization(Module &M) { 1410b57cec5SDimitry Andric GCModuleInfo *GMI = getAnalysisIfAvailable<GCModuleInfo>(); 1420b57cec5SDimitry Andric assert(GMI && "Printer didn't require GCModuleInfo?!"); 1430b57cec5SDimitry Andric GMI->clear(); 1440b57cec5SDimitry Andric return false; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) { 1480b57cec5SDimitry Andric // TODO: Arguably, just doing a linear search would be faster for small N 1490b57cec5SDimitry Andric auto NMI = GCStrategyMap.find(Name); 1500b57cec5SDimitry Andric if (NMI != GCStrategyMap.end()) 1510b57cec5SDimitry Andric return NMI->getValue(); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric for (auto& Entry : GCRegistry::entries()) { 1540b57cec5SDimitry Andric if (Name == Entry.getName()) { 1550b57cec5SDimitry Andric std::unique_ptr<GCStrategy> S = Entry.instantiate(); 1560b57cec5SDimitry Andric S->Name = Name; 1570b57cec5SDimitry Andric GCStrategyMap[Name] = S.get(); 1580b57cec5SDimitry Andric GCStrategyList.push_back(std::move(S)); 1590b57cec5SDimitry Andric return GCStrategyList.back().get(); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric if (GCRegistry::begin() == GCRegistry::end()) { 1640b57cec5SDimitry Andric // In normal operation, the registry should not be empty. There should 1650b57cec5SDimitry Andric // be the builtin GCs if nothing else. The most likely scenario here is 1660b57cec5SDimitry Andric // that we got here without running the initializers used by the Registry 1670b57cec5SDimitry Andric // itself and it's registration mechanism. 1680b57cec5SDimitry Andric const std::string error = ("unsupported GC: " + Name).str() + 1690b57cec5SDimitry Andric " (did you remember to link and initialize the CodeGen library?)"; 1700b57cec5SDimitry Andric report_fatal_error(error); 1710b57cec5SDimitry Andric } else 1720b57cec5SDimitry Andric report_fatal_error(std::string("unsupported GC: ") + Name); 1730b57cec5SDimitry Andric } 174