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