@@ -158,12 +158,12 @@ static bool isLeakCheckerRoot(GlobalVariable *GV) {
158158// / Given a value that is stored to a global but never read, determine whether
159159// / it's safe to remove the store and the chain of computation that feeds the
160160// / store.
161- static bool IsSafeComputationToRemove (
161+ static bool isSafeComputationToRemove (
162162 Value *V, function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
163163 do {
164164 if (isa<Constant>(V))
165165 return true ;
166- if (! V->hasOneUse ( ))
166+ if (V->hasNUsesOrMore ( 1 ))
167167 return false ;
168168 if (isa<LoadInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V) ||
169169 isa<GlobalValue>(V))
@@ -185,11 +185,21 @@ static bool IsSafeComputationToRemove(
185185 } while (true );
186186}
187187
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+ */
191201static bool
192- CleanupPointerRootUsers (GlobalVariable *GV,
202+ cleanupPointerRootUsers (GlobalVariable *GV,
193203 function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
194204 // A brief explanation of leak checkers. The goal is to find bugs where
195205 // pointers are forgotten, causing an accumulating growth in memory
@@ -202,60 +212,38 @@ CleanupPointerRootUsers(GlobalVariable *GV,
202212
203213 bool Changed = false ;
204214
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;
209218 SmallVector<User *> Worklist (GV->users ());
210- // Constants can't be pointers to dynamically allocated memory.
211219 while (!Worklist.empty ()) {
212220 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 ());
221226 }
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 ()});
229230 }
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 ()});
238234 }
239- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
240- if (isa<GEPOperator>(CE))
241- append_range (Worklist, CE->users ());
242235 }
243236 }
244237
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);
259247 Changed = true ;
260248 }
261249 }
@@ -870,7 +858,7 @@ static bool OptimizeAwayTrappingUsesOfLoads(
870858 // nor is the global.
871859 if (AllNonStoreUsesGone) {
872860 if (isLeakCheckerRoot (GV)) {
873- Changed |= CleanupPointerRootUsers (GV, GetTLI);
861+ Changed |= cleanupPointerRootUsers (GV, GetTLI);
874862 } else {
875863 Changed = true ;
876864 CleanupConstantGlobalUsers (GV, DL);
@@ -1496,7 +1484,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
14961484
14971485 if (isLeakCheckerRoot (GV)) {
14981486 // Delete any constant stores to the global.
1499- Changed = CleanupPointerRootUsers (GV, GetTLI);
1487+ Changed = cleanupPointerRootUsers (GV, GetTLI);
15001488 } else {
15011489 // Delete any stores we can find to the global. We may not be able to
15021490 // make it completely dead though.
0 commit comments