1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
|
//===-- GlobalDCE.cpp - DCE unreachable internal functions ----------------===//
//
// This transform is designed to eliminate unreachable internal globals
// FIXME: GlobalDCE should update the callgraph, not destroy it!
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO.h"
#include "llvm/Module.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Analysis/CallGraph.h"
#include "Support/DepthFirstIterator.h"
#include "Support/Statistic.h"
#include <algorithm>
namespace {
Statistic<> NumFunctions("globaldce","Number of functions removed");
Statistic<> NumVariables("globaldce","Number of global variables removed");
Statistic<> NumCPRs("globaldce", "Number of const pointer refs removed");
Statistic<> NumConsts("globaldce", "Number of init constants removed");
bool RemoveUnreachableFunctions(Module &M, CallGraph &CallGraph) {
// Calculate which functions are reachable from the external functions in
// the call graph.
//
std::set<CallGraphNode*> ReachableNodes(df_begin(&CallGraph),
df_end(&CallGraph));
// Loop over the functions in the module twice. The first time is used to
// drop references that functions have to each other before they are
// deleted. The second pass removes the functions that need to be removed.
//
std::vector<CallGraphNode*> FunctionsToDelete; // Track unused functions
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
CallGraphNode *N = CallGraph[I];
if (!ReachableNodes.count(N)) { // Not reachable??
I->dropAllReferences();
N->removeAllCalledFunctions();
FunctionsToDelete.push_back(N);
++NumFunctions;
}
}
// Nothing to do if no unreachable functions have been found...
if (FunctionsToDelete.empty()) return false;
// Unreachables functions have been found and should have no references to
// them, delete them now.
//
for (std::vector<CallGraphNode*>::iterator I = FunctionsToDelete.begin(),
E = FunctionsToDelete.end(); I != E; ++I)
delete CallGraph.removeFunctionFromModule(*I);
return true;
}
struct GlobalDCE : public Pass {
// run - Do the GlobalDCE pass on the specified module, optionally updating
// the specified callgraph to reflect the changes.
//
bool run(Module &M) {
return RemoveUnreachableFunctions(M, getAnalysis<CallGraph>()) |
RemoveUnreachableGlobalVariables(M);
}
// getAnalysisUsage - This function works on the call graph of a module.
// It is capable of updating the call graph to reflect the new state of the
// module.
//
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<CallGraph>();
}
private:
std::vector<GlobalValue*> WorkList;
inline bool RemoveIfDead(GlobalValue *GV);
void DestroyInitializer(Constant *C);
bool RemoveUnreachableGlobalVariables(Module &M);
bool RemoveUnusedConstantPointerRef(GlobalValue &GV);
bool SafeToDestroyConstant(Constant *C);
};
RegisterOpt<GlobalDCE> X("globaldce", "Dead Global Elimination");
}
Pass *createGlobalDCEPass() { return new GlobalDCE(); }
// RemoveIfDead - If this global value is dead, remove it from the current
// module and return true.
//
bool GlobalDCE::RemoveIfDead(GlobalValue *GV) {
// If there is only one use of the global value, it might be a
// ConstantPointerRef... which means that this global might actually be
// dead.
if (GV->use_size() == 1)
RemoveUnusedConstantPointerRef(*GV);
if (!GV->use_empty()) return false;
if (GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) {
// Eliminate all global variables that are unused, and that are internal, or
// do not have an initializer.
//
if (GVar->hasInternalLinkage() || GVar->isExternal()) {
Constant *Init = GVar->hasInitializer() ? GVar->getInitializer() : 0;
GV->getParent()->getGlobalList().erase(GVar);
++NumVariables;
// If there was an initializer for the global variable, try to destroy it
// now.
if (Init) DestroyInitializer(Init);
// If the global variable is still on the worklist, remove it now.
std::vector<GlobalValue*>::iterator I = std::find(WorkList.begin(),
WorkList.end(), GV);
while (I != WorkList.end())
I = std::find(WorkList.erase(I), WorkList.end(), GV);
return true;
}
} else {
Function *F = cast<Function>(GV);
// FIXME: TODO
}
return false;
}
// DestroyInitializer - A global variable was just destroyed and C is its
// initializer. If we can, destroy C and all of the constants it refers to.
//
void GlobalDCE::DestroyInitializer(Constant *C) {
// Cannot destroy constants still being used, and cannot destroy primitive
// types.
if (!C->use_empty() || C->getType()->isPrimitiveType()) return;
// If this is a CPR, the global value referred to may be dead now! Add it to
// the worklist.
//
if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(C)) {
WorkList.push_back(CPR->getValue());
C->destroyConstant();
++NumCPRs;
} else {
bool DestroyContents = true;
// As an optimization to the GlobalDCE algorithm, do attempt to destroy the
// contents of an array of primitive types, because we know that this will
// never succeed, and there could be a lot of them.
//
if (ConstantArray *CA = dyn_cast<ConstantArray>(C))
if (CA->getType()->getElementType()->isPrimitiveType())
DestroyContents = false; // Nothing we can do with the subcontents
// All other constants refer to other constants. Destroy them if possible
// as well.
//
std::vector<Value*> SubConstants;
if (DestroyContents) SubConstants.insert(SubConstants.end(),
C->op_begin(), C->op_end());
// Destroy the actual constant...
C->destroyConstant();
++NumConsts;
if (DestroyContents) {
// Remove duplicates from SubConstants, so that we do not call
// DestroyInitializer on the same constant twice (the first call might
// delete it, so this would be bad)
//
std::sort(SubConstants.begin(), SubConstants.end());
SubConstants.erase(std::unique(SubConstants.begin(), SubConstants.end()),
SubConstants.end());
// Loop over the subconstants, destroying them as well.
for (unsigned i = 0, e = SubConstants.size(); i != e; ++i)
DestroyInitializer(cast<Constant>(SubConstants[i]));
}
}
}
bool GlobalDCE::RemoveUnreachableGlobalVariables(Module &M) {
bool Changed = false;
WorkList.reserve(M.gsize());
// Insert all of the globals into the WorkList, making sure to run
// RemoveUnusedConstantPointerRef at least once on all globals...
//
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
Changed |= RemoveUnusedConstantPointerRef(*I);
WorkList.push_back(I);
}
for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I) {
Changed |= RemoveUnusedConstantPointerRef(*I);
WorkList.push_back(I);
}
// Loop over the worklist, deleting global objects that we can. Whenever we
// delete something that might make something else dead, it gets added to the
// worklist.
//
while (!WorkList.empty()) {
GlobalValue *GV = WorkList.back();
WorkList.pop_back();
Changed |= RemoveIfDead(GV);
}
// Make sure that all memory is free'd from the worklist...
std::vector<GlobalValue*>().swap(WorkList);
return Changed;
}
// RemoveUnusedConstantPointerRef - Loop over all of the uses of the specified
// GlobalValue, looking for the constant pointer ref that may be pointing to it.
// If found, check to see if the constant pointer ref is safe to destroy, and if
// so, nuke it. This will reduce the reference count on the global value, which
// might make it deader.
//
bool GlobalDCE::RemoveUnusedConstantPointerRef(GlobalValue &GV) {
for (Value::use_iterator I = GV.use_begin(), E = GV.use_end(); I != E; ++I)
if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(*I))
if (SafeToDestroyConstant(CPR)) { // Only if unreferenced...
CPR->destroyConstant();
++NumCPRs;
return true;
}
return false;
}
// SafeToDestroyConstant - It is safe to destroy a constant iff it is only used
// by constants itself. Note that constants cannot be cyclic, so this test is
// pretty easy to implement recursively.
//
bool GlobalDCE::SafeToDestroyConstant(Constant *C) {
for (Value::use_iterator I = C->use_begin(), E = C->use_end(); I != E; ++I)
if (Constant *User = dyn_cast<Constant>(*I)) {
if (!SafeToDestroyConstant(User)) return false;
} else {
return false;
}
return true;
}
|