Skip to content

Commit fe47475

Browse files
committed
[GlobalOpt] Merge cleanup functions into one
Change-Id: I3bada185f07d72f379ec2417257e2a07f210c261
1 parent 49e8593 commit fe47475

File tree

2 files changed

+46
-91
lines changed

2 files changed

+46
-91
lines changed

llvm/lib/Transforms/IPO/GlobalOpt.cpp

Lines changed: 31 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -187,78 +187,12 @@ static bool isSafeComputationToRemove(
187187
} while (true);
188188
}
189189

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-
*/
203-
static bool
204-
cleanupPointerRootUsers(GlobalVariable *GV,
205-
function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
206-
// A brief explanation of leak checkers. The goal is to find bugs where
207-
// pointers are forgotten, causing an accumulating growth in memory
208-
// usage over time. The common strategy for leak checkers is to explicitly
209-
// allow the memory pointed to by globals at exit. This is popular because it
210-
// also solves another problem where the main thread of a C++ program may shut
211-
// down before other threads that are still expecting to use those globals. To
212-
// handle that case, we expect the program may create a singleton and never
213-
// destroy it.
214-
215-
bool Changed = false;
216-
217-
// Iterate over all users of the global and collect all
218-
// stores, memtransfer and memset instructions.
219-
SmallVector<std::pair<Instruction *, Value *>> Writes;
220-
SmallVector<User *> Worklist(GV->users());
221-
while (!Worklist.empty()) {
222-
User *U = Worklist.pop_back_val();
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());
228-
}
229-
} else if (auto *MTI = dyn_cast<MemTransferInst>(U)) {
230-
if (MTI->getRawDest() == GV) {
231-
Writes.push_back({MTI, MTI->getSource()});
232-
}
233-
} else if (auto *MSI = dyn_cast<MemSetInst>(U)) {
234-
if (MSI->getRawDest() == GV) {
235-
Writes.push_back({MSI, MSI->getValue()});
236-
}
237-
}
238-
}
239-
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);
249-
Changed = true;
250-
}
251-
}
252-
253-
GV->removeDeadConstantUsers();
254-
return Changed;
255-
}
256-
257190
/// We just marked GV constant. Loop over all users of the global, cleaning up
258191
/// the obvious ones. This is largely just a quick scan over the use list to
259192
/// clean up the easy and obvious cruft. This returns true if it made a change.
260-
static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
261-
const DataLayout &DL) {
193+
static bool cleanupConstantGlobalUsers(
194+
GlobalVariable *GV, const DataLayout &DL,
195+
function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
262196
Constant *Init = GV->getInitializer();
263197
SmallVector<User *, 8> WorkList(GV->users());
264198
SmallPtrSet<User *, 8> Visited;
@@ -308,11 +242,30 @@ static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
308242
}
309243
}
310244
} else if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
311-
// Store must be unreachable or storing Init into the global.
312-
EraseFromParent(SI);
313-
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(U)) { // memset/cpy/mv
314-
if (getUnderlyingObject(MI->getRawDest()) == GV)
315-
EraseFromParent(MI);
245+
auto *V = SI->getValueOperand();
246+
if (isa<Constant>(V)) {
247+
EraseFromParent(SI);
248+
} else if (isa<Instruction>(V)) {
249+
EraseFromParent(SI);
250+
if (isSafeComputationToRemove(V, GetTLI))
251+
RecursivelyDeleteTriviallyDeadInstructions(V);
252+
} else if (isa<Argument>(V)) {
253+
if (!V->getType()->isPointerTy())
254+
EraseFromParent(SI);
255+
}
256+
} else if (auto *MSI = dyn_cast<MemSetInst>(U)) { // memset/cpy/mv
257+
if (getUnderlyingObject(MSI->getRawDest()) == GV)
258+
EraseFromParent(MSI);
259+
} else if (auto *MTI = dyn_cast<MemTransferInst>(U)) {
260+
auto *Src = MTI->getRawSource();
261+
auto *Dst = MTI->getRawDest();
262+
if (getUnderlyingObject(Dst) != GV)
263+
continue;
264+
if (isa<Instruction, Operator>(Src)) {
265+
EraseFromParent(MTI);
266+
if (isSafeComputationToRemove(Src, GetTLI))
267+
RecursivelyDeleteTriviallyDeadInstructions(Src);
268+
}
316269
} else if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(U)) {
317270
if (II->getIntrinsicID() == Intrinsic::threadlocal_address)
318271
append_range(WorkList, II->users());
@@ -859,12 +812,7 @@ static bool OptimizeAwayTrappingUsesOfLoads(
859812
// If we nuked all of the loads, then none of the stores are needed either,
860813
// nor is the global.
861814
if (AllNonStoreUsesGone) {
862-
if (isLeakCheckerRoot(GV)) {
863-
Changed |= cleanupPointerRootUsers(GV, GetTLI);
864-
} else {
865-
Changed = true;
866-
CleanupConstantGlobalUsers(GV, DL);
867-
}
815+
Changed |= cleanupConstantGlobalUsers(GV, DL, GetTLI);
868816
if (GV->use_empty()) {
869817
LLVM_DEBUG(dbgs() << " *** GLOBAL NOW DEAD!\n");
870818
Changed = true;
@@ -1479,15 +1427,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
14791427
// Delete it now.
14801428
if (!GS.IsLoaded) {
14811429
LLVM_DEBUG(dbgs() << "GLOBAL NEVER LOADED: " << *GV << "\n");
1482-
1483-
if (isLeakCheckerRoot(GV)) {
1484-
// Delete any constant stores to the global.
1485-
Changed = cleanupPointerRootUsers(GV, GetTLI);
1486-
} else {
1487-
// Delete any stores we can find to the global. We may not be able to
1488-
// make it completely dead though.
1489-
Changed = CleanupConstantGlobalUsers(GV, DL);
1490-
}
1430+
Changed = cleanupConstantGlobalUsers(GV, DL, GetTLI);
14911431

14921432
// If the global is dead now, delete it.
14931433
if (GV->use_empty()) {
@@ -1511,7 +1451,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
15111451
}
15121452

15131453
// Clean up any obviously simplifiable users now.
1514-
Changed |= CleanupConstantGlobalUsers(GV, DL);
1454+
Changed |= cleanupConstantGlobalUsers(GV, DL, GetTLI);
15151455

15161456
// If the global is dead now, just nuke it.
15171457
if (GV->use_empty()) {
@@ -1566,7 +1506,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
15661506
}
15671507

15681508
// Clean up any obviously simplifiable users now.
1569-
CleanupConstantGlobalUsers(GV, DL);
1509+
cleanupConstantGlobalUsers(GV, DL, GetTLI);
15701510

15711511
if (GV->use_empty()) {
15721512
LLVM_DEBUG(dbgs() << " *** Substituting initializer allowed us to "

llvm/test/Transforms/GlobalOpt/pr54572.ll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,25 @@
66

77
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg)
88

9+
;.
10+
; CHECK: @b = internal unnamed_addr global ptr null
11+
;.
912
define void @test() {
1013
; CHECK-LABEL: @test(
1114
; CHECK-NEXT: ret void
1215
;
1316
call void @llvm.memcpy.p0.p0.i64(ptr @b, ptr getelementptr inbounds ([2 x ptr], ptr @c, i64 0, i64 1), i64 8, i1 false)
1417
ret void
1518
}
19+
20+
define void @neg_test(ptr %arg) {
21+
; CHECK-LABEL: @neg_test(
22+
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr @b, ptr [[ARG:%.*]], i64 8, i1 false)
23+
; CHECK-NEXT: ret void
24+
;
25+
call void @llvm.memcpy.p0.p0.i64(ptr @b, ptr %arg, i64 8, i1 false)
26+
ret void
27+
}
28+
;.
29+
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
30+
;.

0 commit comments

Comments
 (0)