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