@@ -160,12 +160,12 @@ static bool isLeakCheckerRoot(GlobalVariable *GV) {
160
160
// / Given a value that is stored to a global but never read, determine whether
161
161
// / it's safe to remove the store and the chain of computation that feeds the
162
162
// / store.
163
- static bool IsSafeComputationToRemove (
163
+ static bool isSafeComputationToRemove (
164
164
Value *V, function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
165
165
do {
166
166
if (isa<Constant>(V))
167
167
return true ;
168
- if (! V->hasOneUse ( ))
168
+ if (V->hasNUsesOrMore ( 1 ))
169
169
return false ;
170
170
if (isa<LoadInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V) ||
171
171
isa<GlobalValue>(V))
@@ -187,11 +187,21 @@ static bool IsSafeComputationToRemove(
187
187
} while (true );
188
188
}
189
189
190
- // / This GV is a pointer root. Loop over all users of the global and clean up
191
- // / any that obviously don't assign the global a value that isn't dynamically
192
- // / allocated.
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
+ */
193
203
static bool
194
- CleanupPointerRootUsers (GlobalVariable *GV,
204
+ cleanupPointerRootUsers (GlobalVariable *GV,
195
205
function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
196
206
// A brief explanation of leak checkers. The goal is to find bugs where
197
207
// pointers are forgotten, causing an accumulating growth in memory
@@ -204,60 +214,38 @@ CleanupPointerRootUsers(GlobalVariable *GV,
204
214
205
215
bool Changed = false ;
206
216
207
- // If Dead[n].first is the only use of a malloc result, we can delete its
208
- // chain of computation and the store to the global in Dead[n].second.
209
- SmallVector<std::pair<Instruction *, Instruction *>, 32 > Dead;
210
-
217
+ // Iterate over all users of the global and collect all
218
+ // stores, memtransfer and memset instructions.
219
+ SmallVector<std::pair<Instruction *, Value *>> Writes;
211
220
SmallVector<User *> Worklist (GV->users ());
212
- // Constants can't be pointers to dynamically allocated memory.
213
221
while (!Worklist.empty ()) {
214
222
User *U = Worklist.pop_back_val ();
215
- if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
216
- Value *V = SI->getValueOperand ();
217
- if (isa<Constant>(V)) {
218
- Changed = true ;
219
- SI->eraseFromParent ();
220
- } else if (Instruction *I = dyn_cast<Instruction>(V)) {
221
- if (I->hasOneUse ())
222
- Dead.push_back (std::make_pair (I, SI));
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 ());
223
228
}
224
- } else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
225
- if (isa<Constant>(MSI->getValue ())) {
226
- Changed = true ;
227
- MSI->eraseFromParent ();
228
- } else if (Instruction *I = dyn_cast<Instruction>(MSI->getValue ())) {
229
- if (I->hasOneUse ())
230
- Dead.push_back (std::make_pair (I, MSI));
229
+ } else if (auto *MTI = dyn_cast<MemTransferInst>(U)) {
230
+ if (MTI->getRawDest () == GV) {
231
+ Writes.push_back ({MTI, MTI->getSource ()});
231
232
}
232
- } else if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(U)) {
233
- GlobalVariable *MemSrc = dyn_cast<GlobalVariable>(MTI->getSource ());
234
- if (MemSrc && MemSrc->isConstant ()) {
235
- Changed = true ;
236
- MTI->eraseFromParent ();
237
- } else if (Instruction *I = dyn_cast<Instruction>(MTI->getSource ())) {
238
- if (I->hasOneUse ())
239
- Dead.push_back (std::make_pair (I, MTI));
233
+ } else if (auto *MSI = dyn_cast<MemSetInst>(U)) {
234
+ if (MSI->getRawDest () == GV) {
235
+ Writes.push_back ({MSI, MSI->getValue ()});
240
236
}
241
- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
242
- if (isa<GEPOperator>(CE))
243
- append_range (Worklist, CE->users ());
244
237
}
245
238
}
246
239
247
- for (int i = 0 , e = Dead.size (); i != e; ++i) {
248
- if (IsSafeComputationToRemove (Dead[i].first , GetTLI)) {
249
- Dead[i].second ->eraseFromParent ();
250
- Instruction *I = Dead[i].first ;
251
- do {
252
- if (isAllocationFn (I, GetTLI))
253
- break ;
254
- Instruction *J = dyn_cast<Instruction>(I->getOperand (0 ));
255
- if (!J)
256
- break ;
257
- I->eraseFromParent ();
258
- I = J;
259
- } while (true );
260
- I->eraseFromParent ();
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);
261
249
Changed = true ;
262
250
}
263
251
}
@@ -872,7 +860,7 @@ static bool OptimizeAwayTrappingUsesOfLoads(
872
860
// nor is the global.
873
861
if (AllNonStoreUsesGone) {
874
862
if (isLeakCheckerRoot (GV)) {
875
- Changed |= CleanupPointerRootUsers (GV, GetTLI);
863
+ Changed |= cleanupPointerRootUsers (GV, GetTLI);
876
864
} else {
877
865
Changed = true ;
878
866
CleanupConstantGlobalUsers (GV, DL);
@@ -1494,7 +1482,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
1494
1482
1495
1483
if (isLeakCheckerRoot (GV)) {
1496
1484
// Delete any constant stores to the global.
1497
- Changed = CleanupPointerRootUsers (GV, GetTLI);
1485
+ Changed = cleanupPointerRootUsers (GV, GetTLI);
1498
1486
} else {
1499
1487
// Delete any stores we can find to the global. We may not be able to
1500
1488
// make it completely dead though.
0 commit comments