Skip to content

Commit bd76371

Browse files
committed
[GlobalOpt] Merge cleanup functions into one
Change-Id: I3bada185f07d72f379ec2417257e2a07f210c261
1 parent 7e9338b commit bd76371

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
@@ -185,78 +185,12 @@ static bool isSafeComputationToRemove(
185185
} while (true);
186186
}
187187

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

14941434
// If the global is dead now, delete it.
14951435
if (GV->use_empty()) {
@@ -1513,7 +1453,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
15131453
}
15141454

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

15181458
// If the global is dead now, just nuke it.
15191459
if (GV->use_empty()) {
@@ -1568,7 +1508,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
15681508
}
15691509

15701510
// Clean up any obviously simplifiable users now.
1571-
CleanupConstantGlobalUsers(GV, DL);
1511+
cleanupConstantGlobalUsers(GV, DL, GetTLI);
15721512

15731513
if (GV->use_empty()) {
15741514
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)