@@ -187,78 +187,12 @@ static bool isSafeComputationToRemove(
187
187
} while (true );
188
188
}
189
189
190
- /* *
191
- * Cleans up pointer root users of a global variable.
192
- *
193
- * This function iterates over all users of the global variable and collects
194
- * all stores and memtransfer instructions. It then erases all writes and
195
- * removes computation chains if they are safe to remove. Finally, it removes
196
- * dead constant users of the global variable.
197
- *
198
- * @param GV The global variable to clean up.
199
- * @param GetTLI A function reference to obtain the TargetLibraryInfo for a
200
- * given function.
201
- * @return True if any changes were made, false otherwise.
202
- */
203
- static bool
204
- cleanupPointerRootUsers (GlobalVariable *GV,
205
- function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
206
- // A brief explanation of leak checkers. The goal is to find bugs where
207
- // pointers are forgotten, causing an accumulating growth in memory
208
- // usage over time. The common strategy for leak checkers is to explicitly
209
- // allow the memory pointed to by globals at exit. This is popular because it
210
- // also solves another problem where the main thread of a C++ program may shut
211
- // down before other threads that are still expecting to use those globals. To
212
- // handle that case, we expect the program may create a singleton and never
213
- // destroy it.
214
-
215
- bool Changed = false ;
216
-
217
- // Iterate over all users of the global and collect all
218
- // stores, memtransfer and memset instructions.
219
- SmallVector<std::pair<Instruction *, Value *>> Writes;
220
- SmallVector<User *> Worklist (GV->users ());
221
- while (!Worklist.empty ()) {
222
- User *U = Worklist.pop_back_val ();
223
- if (auto *SI = dyn_cast<StoreInst>(U)) {
224
- Writes.push_back ({SI, SI->getValueOperand ()});
225
- } else if (auto *CE = dyn_cast<ConstantExpr>(U)) {
226
- if (isa<GEPOperator>(CE)) {
227
- append_range (Worklist, CE->users ());
228
- }
229
- } else if (auto *MTI = dyn_cast<MemTransferInst>(U)) {
230
- if (MTI->getRawDest () == GV) {
231
- Writes.push_back ({MTI, MTI->getSource ()});
232
- }
233
- } else if (auto *MSI = dyn_cast<MemSetInst>(U)) {
234
- if (MSI->getRawDest () == GV) {
235
- Writes.push_back ({MSI, MSI->getValue ()});
236
- }
237
- }
238
- }
239
-
240
- // Finally, erase all writes and remove computation chains if they are safe
241
- // to remove.
242
- for (auto [WriteInst, V] : Writes) {
243
- if (isa<Constant>(V) || isa<Instruction>(V))
244
- WriteInst->eraseFromParent ();
245
-
246
- if (auto *Inst = dyn_cast<Instruction>(V)) {
247
- if (isSafeComputationToRemove (V, GetTLI))
248
- RecursivelyDeleteTriviallyDeadInstructions (V);
249
- Changed = true ;
250
- }
251
- }
252
-
253
- GV->removeDeadConstantUsers ();
254
- return Changed;
255
- }
256
-
257
190
// / We just marked GV constant. Loop over all users of the global, cleaning up
258
191
// / the obvious ones. This is largely just a quick scan over the use list to
259
192
// / clean up the easy and obvious cruft. This returns true if it made a change.
260
- static bool CleanupConstantGlobalUsers (GlobalVariable *GV,
261
- const DataLayout &DL) {
193
+ static bool cleanupConstantGlobalUsers (
194
+ GlobalVariable *GV, const DataLayout &DL,
195
+ function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
262
196
Constant *Init = GV->getInitializer ();
263
197
SmallVector<User *, 8 > WorkList (GV->users ());
264
198
SmallPtrSet<User *, 8 > Visited;
@@ -308,11 +242,30 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
308
242
}
309
243
}
310
244
} else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
311
- // Store must be unreachable or storing Init into the global.
312
- EraseFromParent (SI);
313
- } else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(U)) { // memset/cpy/mv
314
- if (getUnderlyingObject (MI->getRawDest ()) == GV)
315
- EraseFromParent (MI);
245
+ auto *V = SI->getValueOperand ();
246
+ if (isa<Constant>(V)) {
247
+ EraseFromParent (SI);
248
+ } else if (isa<Instruction>(V)) {
249
+ EraseFromParent (SI);
250
+ if (isSafeComputationToRemove (V, GetTLI))
251
+ RecursivelyDeleteTriviallyDeadInstructions (V);
252
+ } else if (isa<Argument>(V)) {
253
+ if (!V->getType ()->isPointerTy ())
254
+ EraseFromParent (SI);
255
+ }
256
+ } else if (auto *MSI = dyn_cast<MemSetInst>(U)) { // memset/cpy/mv
257
+ if (getUnderlyingObject (MSI->getRawDest ()) == GV)
258
+ EraseFromParent (MSI);
259
+ } else if (auto *MTI = dyn_cast<MemTransferInst>(U)) {
260
+ auto *Src = MTI->getRawSource ();
261
+ auto *Dst = MTI->getRawDest ();
262
+ if (getUnderlyingObject (Dst) != GV)
263
+ continue ;
264
+ if (isa<Instruction, Operator>(Src)) {
265
+ EraseFromParent (MTI);
266
+ if (isSafeComputationToRemove (Src, GetTLI))
267
+ RecursivelyDeleteTriviallyDeadInstructions (Src);
268
+ }
316
269
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U)) {
317
270
if (II->getIntrinsicID () == Intrinsic::threadlocal_address)
318
271
append_range (WorkList, II->users ());
@@ -859,12 +812,7 @@ static bool OptimizeAwayTrappingUsesOfLoads(
859
812
// If we nuked all of the loads, then none of the stores are needed either,
860
813
// nor is the global.
861
814
if (AllNonStoreUsesGone) {
862
- if (isLeakCheckerRoot (GV)) {
863
- Changed |= cleanupPointerRootUsers (GV, GetTLI);
864
- } else {
865
- Changed = true ;
866
- CleanupConstantGlobalUsers (GV, DL);
867
- }
815
+ Changed |= cleanupConstantGlobalUsers (GV, DL, GetTLI);
868
816
if (GV->use_empty ()) {
869
817
LLVM_DEBUG (dbgs () << " *** GLOBAL NOW DEAD!\n " );
870
818
Changed = true ;
@@ -1479,15 +1427,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1479
1427
// Delete it now.
1480
1428
if (!GS.IsLoaded ) {
1481
1429
LLVM_DEBUG (dbgs () << " GLOBAL NEVER LOADED: " << *GV << " \n " );
1482
-
1483
- if (isLeakCheckerRoot (GV)) {
1484
- // Delete any constant stores to the global.
1485
- Changed = cleanupPointerRootUsers (GV, GetTLI);
1486
- } else {
1487
- // Delete any stores we can find to the global. We may not be able to
1488
- // make it completely dead though.
1489
- Changed = CleanupConstantGlobalUsers (GV, DL);
1490
- }
1430
+ Changed = cleanupConstantGlobalUsers (GV, DL, GetTLI);
1491
1431
1492
1432
// If the global is dead now, delete it.
1493
1433
if (GV->use_empty ()) {
@@ -1511,7 +1451,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1511
1451
}
1512
1452
1513
1453
// Clean up any obviously simplifiable users now.
1514
- Changed |= CleanupConstantGlobalUsers (GV, DL);
1454
+ Changed |= cleanupConstantGlobalUsers (GV, DL, GetTLI );
1515
1455
1516
1456
// If the global is dead now, just nuke it.
1517
1457
if (GV->use_empty ()) {
@@ -1566,7 +1506,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1566
1506
}
1567
1507
1568
1508
// Clean up any obviously simplifiable users now.
1569
- CleanupConstantGlobalUsers (GV, DL);
1509
+ cleanupConstantGlobalUsers (GV, DL, GetTLI );
1570
1510
1571
1511
if (GV->use_empty ()) {
1572
1512
LLVM_DEBUG (dbgs () << " *** Substituting initializer allowed us to "
0 commit comments