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/IR/Module.h"
18#include "llvm/InitializePasses.h"
19#include "llvm/MC/MCSymbol.h"
20#include "llvm/Pass.h"
21#include "llvm/Support/raw_ostream.h"
22#include <cassert>
23#include <memory>
24#include <string>
25
26using namespace llvm;
27
28bool GCStrategyMap::invalidate(Module &M, const PreservedAnalyses &PA,
29 ModuleAnalysisManager::Invalidator &) {
30 for (const auto &F : M) {
31 if (F.isDeclaration() || !F.hasGC())
32 continue;
33 if (!StrategyMap.contains(Key: F.getGC()))
34 return true;
35 }
36 return false;
37}
38
39AnalysisKey CollectorMetadataAnalysis::Key;
40
41CollectorMetadataAnalysis::Result
42CollectorMetadataAnalysis::run(Module &M, ModuleAnalysisManager &MAM) {
43 Result R;
44 auto &Map = R.StrategyMap;
45 for (auto &F : M) {
46 if (F.isDeclaration() || !F.hasGC())
47 continue;
48 if (auto GCName = F.getGC(); !Map.contains(Key: GCName))
49 Map[GCName] = getGCStrategy(Name: GCName);
50 }
51 return R;
52}
53
54AnalysisKey GCFunctionAnalysis::Key;
55
56GCFunctionAnalysis::Result
57GCFunctionAnalysis::run(Function &F, FunctionAnalysisManager &FAM) {
58 assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!");
59 assert(F.hasGC() && "Function doesn't have GC!");
60
61 auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(IR&: F);
62 assert(
63 MAMProxy.cachedResultExists<CollectorMetadataAnalysis>(*F.getParent()) &&
64 "This pass need module analysis `collector-metadata`!");
65 auto &Map =
66 MAMProxy.getCachedResult<CollectorMetadataAnalysis>(IR&: *F.getParent())
67 ->StrategyMap;
68 GCFunctionInfo Info(F, *Map[F.getGC()]);
69 return Info;
70}
71
72INITIALIZE_PASS(GCModuleInfo, "collector-metadata",
73 "Create Garbage Collector Module Metadata", false, false)
74
75// -----------------------------------------------------------------------------
76
77GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S)
78 : F(F), S(S), FrameSize(~0LL) {}
79
80GCFunctionInfo::~GCFunctionInfo() = default;
81
82bool GCFunctionInfo::invalidate(Function &F, const PreservedAnalyses &PA,
83 FunctionAnalysisManager::Invalidator &) {
84 auto PAC = PA.getChecker<GCFunctionAnalysis>();
85 return !PAC.preserved() && !PAC.preservedSet<AllAnalysesOn<Function>>();
86}
87
88// -----------------------------------------------------------------------------
89
90char GCModuleInfo::ID = 0;
91
92GCModuleInfo::GCModuleInfo() : ImmutablePass(ID) {
93 initializeGCModuleInfoPass(Registry&: *PassRegistry::getPassRegistry());
94}
95
96GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) {
97 assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!");
98 assert(F.hasGC());
99
100 finfo_map_type::iterator I = FInfoMap.find(Val: &F);
101 if (I != FInfoMap.end())
102 return *I->second;
103
104 GCStrategy *S = getGCStrategy(Name: F.getGC());
105 Functions.push_back(x: std::make_unique<GCFunctionInfo>(args: F, args&: *S));
106 GCFunctionInfo *GFI = Functions.back().get();
107 FInfoMap[&F] = GFI;
108 return *GFI;
109}
110
111void GCModuleInfo::clear() {
112 Functions.clear();
113 FInfoMap.clear();
114 GCStrategyList.clear();
115}
116
117// -----------------------------------------------------------------------------
118
119GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) {
120 // TODO: Arguably, just doing a linear search would be faster for small N
121 auto NMI = GCStrategyMap.find(Key: Name);
122 if (NMI != GCStrategyMap.end())
123 return NMI->getValue();
124
125 std::unique_ptr<GCStrategy> S = llvm::getGCStrategy(Name);
126 S->Name = std::string(Name);
127 GCStrategyMap[Name] = S.get();
128 GCStrategyList.push_back(Elt: std::move(S));
129 return GCStrategyList.back().get();
130}
131