@@ -114,6 +114,55 @@ static cl::opt<int> ColdCCRelFreq(
114
114
" entry frequency, for a call site to be considered cold for enabling "
115
115
" coldcc" ));
116
116
117
+ // / Is this global variable possibly used by a leak checker as a root? If so,
118
+ // / we might not really want to eliminate the stores to it.
119
+ static bool isLeakCheckerRoot (GlobalVariable *GV) {
120
+ // A global variable is a root if it is a pointer, or could plausibly contain
121
+ // a pointer. There are two challenges; one is that we could have a struct
122
+ // the has an inner member which is a pointer. We recurse through the type to
123
+ // detect these (up to a point). The other is that we may actually be a union
124
+ // of a pointer and another type, and so our LLVM type is an integer which
125
+ // gets converted into a pointer, or our type is an [i8 x #] with a pointer
126
+ // potentially contained here.
127
+
128
+ if (GV->hasPrivateLinkage ())
129
+ return false ;
130
+
131
+ SmallVector<Type *, 4 > Types;
132
+ Types.push_back (GV->getValueType ());
133
+
134
+ unsigned Limit = 20 ;
135
+ do {
136
+ Type *Ty = Types.pop_back_val ();
137
+ switch (Ty->getTypeID ()) {
138
+ default : break ;
139
+ case Type::PointerTyID:
140
+ return true ;
141
+ case Type::FixedVectorTyID:
142
+ case Type::ScalableVectorTyID:
143
+ if (cast<VectorType>(Ty)->getElementType ()->isPointerTy ())
144
+ return true ;
145
+ break ;
146
+ case Type::ArrayTyID:
147
+ Types.push_back (cast<ArrayType>(Ty)->getElementType ());
148
+ break ;
149
+ case Type::StructTyID: {
150
+ StructType *STy = cast<StructType>(Ty);
151
+ if (STy->isOpaque ()) return true ;
152
+ for (Type *InnerTy : STy->elements ()) {
153
+ if (isa<PointerType>(InnerTy)) return true ;
154
+ if (isa<StructType>(InnerTy) || isa<ArrayType>(InnerTy) ||
155
+ isa<VectorType>(InnerTy))
156
+ Types.push_back (InnerTy);
157
+ }
158
+ break ;
159
+ }
160
+ }
161
+ if (--Limit == 0 ) return true ;
162
+ } while (!Types.empty ());
163
+ return false ;
164
+ }
165
+
117
166
// / Given a value that is stored to a global but never read, determine whether
118
167
// / it's safe to remove the store and the chain of computation that feeds the
119
168
// / store.
@@ -122,7 +171,7 @@ static bool IsSafeComputationToRemove(
122
171
do {
123
172
if (isa<Constant>(V))
124
173
return true ;
125
- if (V->hasNUsesOrMore ( 1 ))
174
+ if (! V->hasOneUse ( ))
126
175
return false ;
127
176
if (isa<LoadInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V) ||
128
177
isa<GlobalValue>(V))
@@ -144,12 +193,90 @@ static bool IsSafeComputationToRemove(
144
193
} while (true );
145
194
}
146
195
196
+ // / This GV is a pointer root. Loop over all users of the global and clean up
197
+ // / any that obviously don't assign the global a value that isn't dynamically
198
+ // / allocated.
199
+ static bool
200
+ CleanupPointerRootUsers (GlobalVariable *GV,
201
+ function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
202
+ // A brief explanation of leak checkers. The goal is to find bugs where
203
+ // pointers are forgotten, causing an accumulating growth in memory
204
+ // usage over time. The common strategy for leak checkers is to explicitly
205
+ // allow the memory pointed to by globals at exit. This is popular because it
206
+ // also solves another problem where the main thread of a C++ program may shut
207
+ // down before other threads that are still expecting to use those globals. To
208
+ // handle that case, we expect the program may create a singleton and never
209
+ // destroy it.
210
+
211
+ bool Changed = false ;
212
+
213
+ // If Dead[n].first is the only use of a malloc result, we can delete its
214
+ // chain of computation and the store to the global in Dead[n].second.
215
+ SmallVector<std::pair<Instruction *, Instruction *>, 32 > Dead;
216
+
217
+ SmallVector<User *> Worklist (GV->users ());
218
+ // Constants can't be pointers to dynamically allocated memory.
219
+ while (!Worklist.empty ()) {
220
+ User *U = Worklist.pop_back_val ();
221
+ if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
222
+ Value *V = SI->getValueOperand ();
223
+ if (isa<Constant>(V)) {
224
+ Changed = true ;
225
+ SI->eraseFromParent ();
226
+ } else if (Instruction *I = dyn_cast<Instruction>(V)) {
227
+ if (I->hasOneUse ())
228
+ Dead.push_back (std::make_pair (I, SI));
229
+ }
230
+ } else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
231
+ if (isa<Constant>(MSI->getValue ())) {
232
+ Changed = true ;
233
+ MSI->eraseFromParent ();
234
+ } else if (Instruction *I = dyn_cast<Instruction>(MSI->getValue ())) {
235
+ if (I->hasOneUse ())
236
+ Dead.push_back (std::make_pair (I, MSI));
237
+ }
238
+ } else if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(U)) {
239
+ GlobalVariable *MemSrc = dyn_cast<GlobalVariable>(MTI->getSource ());
240
+ if (MemSrc && MemSrc->isConstant ()) {
241
+ Changed = true ;
242
+ MTI->eraseFromParent ();
243
+ } else if (Instruction *I = dyn_cast<Instruction>(MTI->getSource ())) {
244
+ if (I->hasOneUse ())
245
+ Dead.push_back (std::make_pair (I, MTI));
246
+ }
247
+ } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
248
+ if (isa<GEPOperator>(CE))
249
+ append_range (Worklist, CE->users ());
250
+ }
251
+ }
252
+
253
+ for (int i = 0 , e = Dead.size (); i != e; ++i) {
254
+ if (IsSafeComputationToRemove (Dead[i].first , GetTLI)) {
255
+ Dead[i].second ->eraseFromParent ();
256
+ Instruction *I = Dead[i].first ;
257
+ do {
258
+ if (isAllocationFn (I, GetTLI))
259
+ break ;
260
+ Instruction *J = dyn_cast<Instruction>(I->getOperand (0 ));
261
+ if (!J)
262
+ break ;
263
+ I->eraseFromParent ();
264
+ I = J;
265
+ } while (true );
266
+ I->eraseFromParent ();
267
+ Changed = true ;
268
+ }
269
+ }
270
+
271
+ GV->removeDeadConstantUsers ();
272
+ return Changed;
273
+ }
274
+
147
275
// / We just marked GV constant. Loop over all users of the global, cleaning up
148
276
// / the obvious ones. This is largely just a quick scan over the use list to
149
277
// / clean up the easy and obvious cruft. This returns true if it made a change.
150
- static bool CleanupConstantGlobalUsers (
151
- GlobalVariable *GV, const DataLayout &DL,
152
- function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
278
+ static bool CleanupConstantGlobalUsers (GlobalVariable *GV,
279
+ const DataLayout &DL) {
153
280
Constant *Init = GV->getInitializer ();
154
281
SmallVector<User *, 8 > WorkList (GV->users ());
155
282
SmallPtrSet<User *, 8 > Visited;
@@ -199,30 +326,11 @@ static bool CleanupConstantGlobalUsers(
199
326
}
200
327
}
201
328
} else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
202
- auto *V = SI->getValueOperand ();
203
- if (isa<Constant>(V)) {
204
- EraseFromParent (SI);
205
- } else if (isa<Instruction>(V)) {
206
- EraseFromParent (SI);
207
- if (IsSafeComputationToRemove (V, GetTLI))
208
- RecursivelyDeleteTriviallyDeadInstructions (V);
209
- } else if (isa<Argument>(V)) {
210
- if (!V->getType ()->isPointerTy ())
211
- EraseFromParent (SI);
212
- }
213
- } else if (auto *MSI = dyn_cast<MemSetInst>(U)) { // memset/cpy/mv
214
- if (getUnderlyingObject (MSI->getRawDest ()) == GV)
215
- EraseFromParent (MSI);
216
- } else if (auto *MTI = dyn_cast<MemTransferInst>(U)) {
217
- auto *Src = MTI->getRawSource ();
218
- auto *Dst = MTI->getRawDest ();
219
- if (getUnderlyingObject (Dst) != GV)
220
- continue ;
221
- if (isa<Instruction, Operator>(Src)) {
222
- EraseFromParent (MTI);
223
- if (IsSafeComputationToRemove (Src, GetTLI))
224
- RecursivelyDeleteTriviallyDeadInstructions (Src);
225
- }
329
+ // Store must be unreachable or storing Init into the global.
330
+ EraseFromParent (SI);
331
+ } else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(U)) { // memset/cpy/mv
332
+ if (getUnderlyingObject (MI->getRawDest ()) == GV)
333
+ EraseFromParent (MI);
226
334
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U)) {
227
335
if (II->getIntrinsicID () == Intrinsic::threadlocal_address)
228
336
append_range (WorkList, II->users ());
@@ -770,7 +878,12 @@ static bool OptimizeAwayTrappingUsesOfLoads(
770
878
// If we nuked all of the loads, then none of the stores are needed either,
771
879
// nor is the global.
772
880
if (AllNonStoreUsesGone) {
773
- Changed |= CleanupConstantGlobalUsers (GV, DL, GetTLI);
881
+ if (isLeakCheckerRoot (GV)) {
882
+ Changed |= CleanupPointerRootUsers (GV, GetTLI);
883
+ } else {
884
+ Changed = true ;
885
+ CleanupConstantGlobalUsers (GV, DL);
886
+ }
774
887
if (GV->use_empty ()) {
775
888
LLVM_DEBUG (dbgs () << " *** GLOBAL NOW DEAD!\n " );
776
889
Changed = true ;
@@ -1384,7 +1497,15 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1384
1497
// Delete it now.
1385
1498
if (!GS.IsLoaded ) {
1386
1499
LLVM_DEBUG (dbgs () << " GLOBAL NEVER LOADED: " << *GV << " \n " );
1387
- Changed = CleanupConstantGlobalUsers (GV, DL, GetTLI);
1500
+
1501
+ if (isLeakCheckerRoot (GV)) {
1502
+ // Delete any constant stores to the global.
1503
+ Changed = CleanupPointerRootUsers (GV, GetTLI);
1504
+ } else {
1505
+ // Delete any stores we can find to the global. We may not be able to
1506
+ // make it completely dead though.
1507
+ Changed = CleanupConstantGlobalUsers (GV, DL);
1508
+ }
1388
1509
1389
1510
// If the global is dead now, delete it.
1390
1511
if (GV->use_empty ()) {
@@ -1408,7 +1529,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1408
1529
}
1409
1530
1410
1531
// Clean up any obviously simplifiable users now.
1411
- Changed |= CleanupConstantGlobalUsers (GV, DL, GetTLI );
1532
+ Changed |= CleanupConstantGlobalUsers (GV, DL);
1412
1533
1413
1534
// If the global is dead now, just nuke it.
1414
1535
if (GV->use_empty ()) {
@@ -1463,7 +1584,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1463
1584
}
1464
1585
1465
1586
// Clean up any obviously simplifiable users now.
1466
- CleanupConstantGlobalUsers (GV, DL, GetTLI );
1587
+ CleanupConstantGlobalUsers (GV, DL);
1467
1588
1468
1589
if (GV->use_empty ()) {
1469
1590
LLVM_DEBUG (dbgs () << " *** Substituting initializer allowed us to "
0 commit comments