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" 14fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h" 160b57cec5SDimitry Andric #include "llvm/IR/Function.h" 17*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 18480093f4SDimitry Andric #include "llvm/InitializePasses.h" 190b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 200b57cec5SDimitry Andric #include "llvm/Pass.h" 210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 220b57cec5SDimitry Andric #include <cassert> 230b57cec5SDimitry Andric #include <memory> 240b57cec5SDimitry Andric #include <string> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric 285f757f3fSDimitry Andric bool GCStrategyMap::invalidate(Module &M, const PreservedAnalyses &PA, 295f757f3fSDimitry Andric ModuleAnalysisManager::Invalidator &) { 305f757f3fSDimitry Andric for (const auto &F : M) { 315f757f3fSDimitry Andric if (F.isDeclaration() || !F.hasGC()) 325f757f3fSDimitry Andric continue; 335f757f3fSDimitry Andric if (!StrategyMap.contains(F.getGC())) 345f757f3fSDimitry Andric return true; 355f757f3fSDimitry Andric } 365f757f3fSDimitry Andric return false; 375f757f3fSDimitry Andric } 380b57cec5SDimitry Andric 395f757f3fSDimitry Andric AnalysisKey CollectorMetadataAnalysis::Key; 400b57cec5SDimitry Andric 415f757f3fSDimitry Andric CollectorMetadataAnalysis::Result 425f757f3fSDimitry Andric CollectorMetadataAnalysis::run(Module &M, ModuleAnalysisManager &MAM) { 435f757f3fSDimitry Andric Result R; 445f757f3fSDimitry Andric auto &Map = R.StrategyMap; 455f757f3fSDimitry Andric for (auto &F : M) { 465f757f3fSDimitry Andric if (F.isDeclaration() || !F.hasGC()) 475f757f3fSDimitry Andric continue; 485f757f3fSDimitry Andric if (auto GCName = F.getGC(); !Map.contains(GCName)) 495f757f3fSDimitry Andric Map[GCName] = getGCStrategy(GCName); 505f757f3fSDimitry Andric } 515f757f3fSDimitry Andric return R; 525f757f3fSDimitry Andric } 530b57cec5SDimitry Andric 545f757f3fSDimitry Andric AnalysisKey GCFunctionAnalysis::Key; 550b57cec5SDimitry Andric 565f757f3fSDimitry Andric GCFunctionAnalysis::Result 575f757f3fSDimitry Andric GCFunctionAnalysis::run(Function &F, FunctionAnalysisManager &FAM) { 585f757f3fSDimitry Andric assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!"); 595f757f3fSDimitry Andric assert(F.hasGC() && "Function doesn't have GC!"); 600b57cec5SDimitry Andric 615f757f3fSDimitry Andric auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F); 625f757f3fSDimitry Andric assert( 635f757f3fSDimitry Andric MAMProxy.cachedResultExists<CollectorMetadataAnalysis>(*F.getParent()) && 645f757f3fSDimitry Andric "This pass need module analysis `collector-metadata`!"); 655f757f3fSDimitry Andric auto &Map = 665f757f3fSDimitry Andric MAMProxy.getCachedResult<CollectorMetadataAnalysis>(*F.getParent()) 675f757f3fSDimitry Andric ->StrategyMap; 685f757f3fSDimitry Andric GCFunctionInfo Info(F, *Map[F.getGC()]); 695f757f3fSDimitry Andric return Info; 705f757f3fSDimitry Andric } 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric INITIALIZE_PASS(GCModuleInfo, "collector-metadata", 730b57cec5SDimitry Andric "Create Garbage Collector Module Metadata", false, false) 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric // ----------------------------------------------------------------------------- 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S) 780b57cec5SDimitry Andric : F(F), S(S), FrameSize(~0LL) {} 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric GCFunctionInfo::~GCFunctionInfo() = default; 810b57cec5SDimitry Andric 825f757f3fSDimitry Andric bool GCFunctionInfo::invalidate(Function &F, const PreservedAnalyses &PA, 835f757f3fSDimitry Andric FunctionAnalysisManager::Invalidator &) { 845f757f3fSDimitry Andric auto PAC = PA.getChecker<GCFunctionAnalysis>(); 855f757f3fSDimitry Andric return !PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Function>>(); 865f757f3fSDimitry Andric } 875f757f3fSDimitry Andric 880b57cec5SDimitry Andric // ----------------------------------------------------------------------------- 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric char GCModuleInfo::ID = 0; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric GCModuleInfo::GCModuleInfo() : ImmutablePass(ID) { 930b57cec5SDimitry Andric initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) { 970b57cec5SDimitry Andric assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!"); 980b57cec5SDimitry Andric assert(F.hasGC()); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric finfo_map_type::iterator I = FInfoMap.find(&F); 1010b57cec5SDimitry Andric if (I != FInfoMap.end()) 1020b57cec5SDimitry Andric return *I->second; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric GCStrategy *S = getGCStrategy(F.getGC()); 1058bcb0991SDimitry Andric Functions.push_back(std::make_unique<GCFunctionInfo>(F, *S)); 1060b57cec5SDimitry Andric GCFunctionInfo *GFI = Functions.back().get(); 1070b57cec5SDimitry Andric FInfoMap[&F] = GFI; 1080b57cec5SDimitry Andric return *GFI; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric void GCModuleInfo::clear() { 1120b57cec5SDimitry Andric Functions.clear(); 1130b57cec5SDimitry Andric FInfoMap.clear(); 1140b57cec5SDimitry Andric GCStrategyList.clear(); 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // ----------------------------------------------------------------------------- 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) { 1200b57cec5SDimitry Andric // TODO: Arguably, just doing a linear search would be faster for small N 1210b57cec5SDimitry Andric auto NMI = GCStrategyMap.find(Name); 1220b57cec5SDimitry Andric if (NMI != GCStrategyMap.end()) 1230b57cec5SDimitry Andric return NMI->getValue(); 1240b57cec5SDimitry Andric 125349cc55cSDimitry Andric std::unique_ptr<GCStrategy> S = llvm::getGCStrategy(Name); 1265ffd83dbSDimitry Andric S->Name = std::string(Name); 1270b57cec5SDimitry Andric GCStrategyMap[Name] = S.get(); 1280b57cec5SDimitry Andric GCStrategyList.push_back(std::move(S)); 1290b57cec5SDimitry Andric return GCStrategyList.back().get(); 1300b57cec5SDimitry Andric } 131