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