Line data Source code
1 : //===-- GCMetadata.cpp - Garbage collector metadata -----------------------===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file implements the GCFunctionInfo class and GCModuleInfo pass.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "llvm/ADT/STLExtras.h"
15 : #include "llvm/CodeGen/GCMetadata.h"
16 : #include "llvm/CodeGen/GCStrategy.h"
17 : #include "llvm/CodeGen/Passes.h"
18 : #include "llvm/IR/Function.h"
19 : #include "llvm/MC/MCSymbol.h"
20 : #include "llvm/Pass.h"
21 : #include "llvm/Support/ErrorHandling.h"
22 : #include "llvm/Support/raw_ostream.h"
23 : #include <algorithm>
24 : #include <cassert>
25 : #include <memory>
26 : #include <string>
27 :
28 : using namespace llvm;
29 :
30 : namespace {
31 :
32 : class Printer : public FunctionPass {
33 : static char ID;
34 :
35 : raw_ostream &OS;
36 :
37 : public:
38 0 : explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {}
39 :
40 : StringRef getPassName() const override;
41 : void getAnalysisUsage(AnalysisUsage &AU) const override;
42 :
43 : bool runOnFunction(Function &F) override;
44 : bool doFinalization(Module &M) override;
45 : };
46 :
47 : } // end anonymous namespace
48 :
49 200697 : INITIALIZE_PASS(GCModuleInfo, "collector-metadata",
50 : "Create Garbage Collector Module Metadata", false, false)
51 :
52 : // -----------------------------------------------------------------------------
53 :
54 66 : GCFunctionInfo::GCFunctionInfo(const Function &F, GCStrategy &S)
55 132 : : F(F), S(S), FrameSize(~0LL) {}
56 :
57 : GCFunctionInfo::~GCFunctionInfo() = default;
58 :
59 : // -----------------------------------------------------------------------------
60 :
61 : char GCModuleInfo::ID = 0;
62 :
63 82137 : GCModuleInfo::GCModuleInfo() : ImmutablePass(ID) {
64 27379 : initializeGCModuleInfoPass(*PassRegistry::getPassRegistry());
65 27379 : }
66 :
67 264 : GCFunctionInfo &GCModuleInfo::getFunctionInfo(const Function &F) {
68 : assert(!F.isDeclaration() && "Can only get GCFunctionInfo for a definition!");
69 : assert(F.hasGC());
70 :
71 264 : finfo_map_type::iterator I = FInfoMap.find(&F);
72 264 : if (I != FInfoMap.end())
73 198 : return *I->second;
74 :
75 66 : GCStrategy *S = getGCStrategy(F.getGC());
76 132 : Functions.push_back(llvm::make_unique<GCFunctionInfo>(F, *S));
77 : GCFunctionInfo *GFI = Functions.back().get();
78 66 : FInfoMap[&F] = GFI;
79 66 : return *GFI;
80 : }
81 :
82 0 : void GCModuleInfo::clear() {
83 : Functions.clear();
84 0 : FInfoMap.clear();
85 : GCStrategyList.clear();
86 0 : }
87 :
88 : // -----------------------------------------------------------------------------
89 :
90 : char Printer::ID = 0;
91 :
92 0 : FunctionPass *llvm::createGCInfoPrinter(raw_ostream &OS) {
93 0 : return new Printer(OS);
94 : }
95 :
96 0 : StringRef Printer::getPassName() const {
97 0 : return "Print Garbage Collector Information";
98 : }
99 :
100 0 : void Printer::getAnalysisUsage(AnalysisUsage &AU) const {
101 0 : FunctionPass::getAnalysisUsage(AU);
102 : AU.setPreservesAll();
103 : AU.addRequired<GCModuleInfo>();
104 0 : }
105 :
106 : static const char *DescKind(GC::PointKind Kind) {
107 0 : switch (Kind) {
108 : case GC::PreCall:
109 : return "pre-call";
110 0 : case GC::PostCall:
111 : return "post-call";
112 : }
113 0 : llvm_unreachable("Invalid point kind");
114 : }
115 :
116 0 : bool Printer::runOnFunction(Function &F) {
117 0 : if (F.hasGC())
118 : return false;
119 :
120 0 : GCFunctionInfo *FD = &getAnalysis<GCModuleInfo>().getFunctionInfo(F);
121 :
122 0 : OS << "GC roots for " << FD->getFunction().getName() << ":\n";
123 : for (GCFunctionInfo::roots_iterator RI = FD->roots_begin(),
124 : RE = FD->roots_end();
125 0 : RI != RE; ++RI)
126 0 : OS << "\t" << RI->Num << "\t" << RI->StackOffset << "[sp]\n";
127 :
128 0 : OS << "GC safe points for " << FD->getFunction().getName() << ":\n";
129 0 : for (GCFunctionInfo::iterator PI = FD->begin(), PE = FD->end(); PI != PE;
130 : ++PI) {
131 :
132 0 : OS << "\t" << PI->Label->getName() << ": " << DescKind(PI->Kind)
133 0 : << ", live = {";
134 :
135 : for (GCFunctionInfo::live_iterator RI = FD->live_begin(PI),
136 : RE = FD->live_end(PI);
137 : ;) {
138 0 : OS << " " << RI->Num;
139 0 : if (++RI == RE)
140 : break;
141 0 : OS << ",";
142 : }
143 :
144 0 : OS << " }\n";
145 : }
146 :
147 : return false;
148 : }
149 :
150 0 : bool Printer::doFinalization(Module &M) {
151 0 : GCModuleInfo *GMI = getAnalysisIfAvailable<GCModuleInfo>();
152 : assert(GMI && "Printer didn't require GCModuleInfo?!");
153 0 : GMI->clear();
154 0 : return false;
155 : }
156 :
157 66 : GCStrategy *GCModuleInfo::getGCStrategy(const StringRef Name) {
158 : // TODO: Arguably, just doing a linear search would be faster for small N
159 66 : auto NMI = GCStrategyMap.find(Name);
160 132 : if (NMI != GCStrategyMap.end())
161 41 : return NMI->getValue();
162 :
163 85 : for (auto& Entry : GCRegistry::entries()) {
164 : if (Name == Entry.getName()) {
165 25 : std::unique_ptr<GCStrategy> S = Entry.instantiate();
166 50 : S->Name = Name;
167 25 : GCStrategyMap[Name] = S.get();
168 25 : GCStrategyList.push_back(std::move(S));
169 : return GCStrategyList.back().get();
170 : }
171 : }
172 :
173 0 : if (GCRegistry::begin() == GCRegistry::end()) {
174 : // In normal operation, the registry should not be empty. There should
175 : // be the builtin GCs if nothing else. The most likely scenario here is
176 : // that we got here without running the initializers used by the Registry
177 : // itself and it's registration mechanism.
178 0 : const std::string error = ("unsupported GC: " + Name).str() +
179 0 : " (did you remember to link and initialize the CodeGen library?)";
180 0 : report_fatal_error(error);
181 : } else
182 0 : report_fatal_error(std::string("unsupported GC: ") + Name);
183 : }
|