@@ -160,12 +160,12 @@ static bool isLeakCheckerRoot(GlobalVariable *GV) {
160160// / Given a value that is stored to a global but never read, determine whether
161161// / it's safe to remove the store and the chain of computation that feeds the
162162// / store.
163- static bool IsSafeComputationToRemove (
163+ static bool isSafeComputationToRemove (
164164 Value *V, function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
165165 do {
166166 if (isa<Constant>(V))
167167 return true ;
168- if (! V->hasOneUse ( ))
168+ if (V->hasNUsesOrMore ( 1 ))
169169 return false ;
170170 if (isa<LoadInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V) ||
171171 isa<GlobalValue>(V))
@@ -187,11 +187,21 @@ static bool IsSafeComputationToRemove(
187187 } while (true );
188188}
189189
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+ */
193203static bool
194- CleanupPointerRootUsers (GlobalVariable *GV,
204+ cleanupPointerRootUsers (GlobalVariable *GV,
195205 function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
196206 // A brief explanation of leak checkers. The goal is to find bugs where
197207 // pointers are forgotten, causing an accumulating growth in memory
@@ -204,60 +214,38 @@ CleanupPointerRootUsers(GlobalVariable *GV,
204214
205215 bool Changed = false ;
206216
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;
211220 SmallVector<User *> Worklist (GV->users ());
212- // Constants can't be pointers to dynamically allocated memory.
213221 while (!Worklist.empty ()) {
214222 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 ());
223228 }
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 ()});
231232 }
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 ()});
240236 }
241- } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
242- if (isa<GEPOperator>(CE))
243- append_range (Worklist, CE->users ());
244237 }
245238 }
246239
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);
261249 Changed = true ;
262250 }
263251 }
@@ -872,7 +860,7 @@ static bool OptimizeAwayTrappingUsesOfLoads(
872860 // nor is the global.
873861 if (AllNonStoreUsesGone) {
874862 if (isLeakCheckerRoot (GV)) {
875- Changed |= CleanupPointerRootUsers (GV, GetTLI);
863+ Changed |= cleanupPointerRootUsers (GV, GetTLI);
876864 } else {
877865 Changed = true ;
878866 CleanupConstantGlobalUsers (GV, DL);
@@ -1494,7 +1482,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
14941482
14951483 if (isLeakCheckerRoot (GV)) {
14961484 // Delete any constant stores to the global.
1497- Changed = CleanupPointerRootUsers (GV, GetTLI);
1485+ Changed = cleanupPointerRootUsers (GV, GetTLI);
14981486 } else {
14991487 // Delete any stores we can find to the global. We may not be able to
15001488 // make it completely dead though.
0 commit comments