Skip to content

Commit 82f091c

Browse files
committed
[GlobalOpt] Improve cleanup of pointer root users
This patch fixes the functionality of CleanupPointerRootUsers by eliminating code redundancy and refactoring the safety checks before removing store/memcpy/memmove value operands. This patch additionally fixes some function names to conform with the LLVM style guide. Fixes #64680. Change-Id: I972dc76758ced16cefcb08474b756ec89e0c047f
1 parent bfa3ffb commit 82f091c

File tree

3 files changed

+42
-39
lines changed

3 files changed

+42
-39
lines changed

llvm/lib/Transforms/IPO/GlobalOpt.cpp

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -160,15 +160,15 @@ 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) {
165+
assert(isa<Instruction>(V) && "Expected an instruction");
165166
do {
166167
if (isa<Constant>(V))
167168
return true;
168-
if (!V->hasOneUse())
169+
if (V->getNumUses() > 0)
169170
return false;
170-
if (isa<LoadInst>(V) || isa<InvokeInst>(V) || isa<Argument>(V) ||
171-
isa<GlobalValue>(V))
171+
if (isa<LoadInst, InvokeInst, Argument, GlobalValue>(V))
172172
return false;
173173
if (isAllocationFn(V, GetTLI))
174174
return true;
@@ -191,7 +191,7 @@ static bool IsSafeComputationToRemove(
191191
/// any that obviously don't assign the global a value that isn't dynamically
192192
/// allocated.
193193
static bool
194-
CleanupPointerRootUsers(GlobalVariable *GV,
194+
cleanupPointerRootUsers(GlobalVariable *GV,
195195
function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
196196
// A brief explanation of leak checkers. The goal is to find bugs where
197197
// pointers are forgotten, causing an accumulating growth in memory
@@ -203,10 +203,7 @@ CleanupPointerRootUsers(GlobalVariable *GV,
203203
// destroy it.
204204

205205
bool Changed = false;
206-
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;
206+
SmallVector<Instruction *> Dead;
210207

211208
SmallVector<User *> Worklist(GV->users());
212209
// Constants can't be pointers to dynamically allocated memory.
@@ -218,46 +215,44 @@ CleanupPointerRootUsers(GlobalVariable *GV,
218215
Changed = true;
219216
SI->eraseFromParent();
220217
} else if (Instruction *I = dyn_cast<Instruction>(V)) {
221-
if (I->hasOneUse())
222-
Dead.push_back(std::make_pair(I, SI));
218+
Dead.push_back(I);
219+
SI->eraseFromParent();
223220
}
224221
} else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
225222
if (isa<Constant>(MSI->getValue())) {
226223
Changed = true;
227224
MSI->eraseFromParent();
228225
} else if (Instruction *I = dyn_cast<Instruction>(MSI->getValue())) {
229-
if (I->hasOneUse())
230-
Dead.push_back(std::make_pair(I, MSI));
226+
Dead.push_back(I);
227+
MSI->eraseFromParent();
231228
}
232229
} else if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(U)) {
233230
GlobalVariable *MemSrc = dyn_cast<GlobalVariable>(MTI->getSource());
234231
if (MemSrc && MemSrc->isConstant()) {
235232
Changed = true;
236233
MTI->eraseFromParent();
237234
} else if (Instruction *I = dyn_cast<Instruction>(MTI->getSource())) {
238-
if (I->hasOneUse())
239-
Dead.push_back(std::make_pair(I, MTI));
235+
Dead.push_back(I);
236+
MTI->eraseFromParent();
240237
}
241238
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
242239
if (isa<GEPOperator>(CE))
243240
append_range(Worklist, CE->users());
244241
}
245242
}
246243

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;
244+
for (auto *Inst : Dead) {
245+
if (isSafeComputationToRemove(Inst, GetTLI)) {
251246
do {
252-
if (isAllocationFn(I, GetTLI))
247+
if (isAllocationFn(Inst, GetTLI))
253248
break;
254-
Instruction *J = dyn_cast<Instruction>(I->getOperand(0));
249+
Instruction *J = dyn_cast<Instruction>(Inst->getOperand(0));
255250
if (!J)
256251
break;
257-
I->eraseFromParent();
258-
I = J;
252+
Inst->eraseFromParent();
253+
Inst = J;
259254
} while (true);
260-
I->eraseFromParent();
255+
Inst->eraseFromParent();
261256
Changed = true;
262257
}
263258
}
@@ -269,8 +264,9 @@ CleanupPointerRootUsers(GlobalVariable *GV,
269264
/// We just marked GV constant. Loop over all users of the global, cleaning up
270265
/// the obvious ones. This is largely just a quick scan over the use list to
271266
/// clean up the easy and obvious cruft. This returns true if it made a change.
272-
static bool CleanupConstantGlobalUsers(GlobalVariable *GV,
273-
const DataLayout &DL) {
267+
static bool cleanupConstantGlobalUsers(
268+
GlobalVariable *GV, const DataLayout &DL,
269+
function_ref<TargetLibraryInfo &(Function &)> GetTLI) {
274270
Constant *Init = GV->getInitializer();
275271
SmallVector<User *, 8> WorkList(GV->users());
276272
SmallPtrSet<User *, 8> Visited;
@@ -872,10 +868,10 @@ static bool OptimizeAwayTrappingUsesOfLoads(
872868
// nor is the global.
873869
if (AllNonStoreUsesGone) {
874870
if (isLeakCheckerRoot(GV)) {
875-
Changed |= CleanupPointerRootUsers(GV, GetTLI);
871+
Changed |= cleanupPointerRootUsers(GV, GetTLI);
876872
} else {
877873
Changed = true;
878-
CleanupConstantGlobalUsers(GV, DL);
874+
cleanupConstantGlobalUsers(GV, DL, GetTLI);
879875
}
880876
if (GV->use_empty()) {
881877
LLVM_DEBUG(dbgs() << " *** GLOBAL NOW DEAD!\n");
@@ -1494,11 +1490,11 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
14941490

14951491
if (isLeakCheckerRoot(GV)) {
14961492
// Delete any constant stores to the global.
1497-
Changed = CleanupPointerRootUsers(GV, GetTLI);
1493+
Changed = cleanupPointerRootUsers(GV, GetTLI);
14981494
} else {
14991495
// Delete any stores we can find to the global. We may not be able to
15001496
// make it completely dead though.
1501-
Changed = CleanupConstantGlobalUsers(GV, DL);
1497+
Changed = cleanupConstantGlobalUsers(GV, DL, GetTLI);
15021498
}
15031499

15041500
// If the global is dead now, delete it.
@@ -1523,7 +1519,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
15231519
}
15241520

15251521
// Clean up any obviously simplifiable users now.
1526-
Changed |= CleanupConstantGlobalUsers(GV, DL);
1522+
Changed |= cleanupConstantGlobalUsers(GV, DL, GetTLI);
15271523

15281524
// If the global is dead now, just nuke it.
15291525
if (GV->use_empty()) {
@@ -1578,7 +1574,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS,
15781574
}
15791575

15801576
// Clean up any obviously simplifiable users now.
1581-
CleanupConstantGlobalUsers(GV, DL);
1577+
cleanupConstantGlobalUsers(GV, DL, GetTLI);
15821578

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

llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-gep-constexpr.ll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ define i32 @load_gv_from_op_remove_store(ptr %p) local_unnamed_addr {
9999
; CHECK-NEXT: call void @fn0()
100100
; CHECK-NEXT: br label [[IF_END]]
101101
; CHECK: if.end:
102-
; CHECK-NEXT: store ptr [[E]], ptr getelementptr inbounds ([3 x ptr], ptr @b, i64 0, i64 2), align 16
103102
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @a, align 4
104103
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
105104
; CHECK-NEXT: store i32 [[INC]], ptr @a, align 4

llvm/test/Transforms/GlobalOpt/dead-store-status.ll

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
12
; RUN: opt < %s -passes=globalopt -S | FileCheck %s
23

34
; When removing the store to @global in @foo, the pass would incorrectly return
45
; false. This was caught by the pass return status check that is hidden under
56
; EXPENSIVE_CHECKS.
67

7-
; CHECK: @global = internal unnamed_addr global ptr null, align 1
8-
9-
; CHECK-LABEL: @foo
10-
; CHECK-NEXT: entry:
11-
; CHECK-NEXT: ret i16 undef
12-
138
@global = internal unnamed_addr global ptr null, align 1
149

1510
; Function Attrs: nofree noinline norecurse nounwind writeonly
1611
define i16 @foo(i16 %c) local_unnamed_addr #0 {
12+
; CHECK-LABEL: define i16 @foo(
13+
; CHECK-SAME: i16 [[C:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
14+
; CHECK-NEXT: [[ENTRY:.*:]]
15+
; CHECK-NEXT: ret i16 undef
16+
;
1717
entry:
1818
%local1.addr = alloca i16, align 1
1919
store ptr %local1.addr, ptr @global, align 1
@@ -22,6 +22,14 @@ entry:
2222

2323
; Function Attrs: noinline nounwind writeonly
2424
define i16 @bar() local_unnamed_addr #1 {
25+
; CHECK-LABEL: define i16 @bar(
26+
; CHECK-SAME: ) local_unnamed_addr #[[ATTR1:[0-9]+]] {
27+
; CHECK-NEXT: [[ENTRY:.*:]]
28+
; CHECK-NEXT: [[LOCAL2:%.*]] = alloca [1 x i16], align 1
29+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr nonnull [[LOCAL2]])
30+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr nonnull [[LOCAL2]])
31+
; CHECK-NEXT: ret i16 undef
32+
;
2533
entry:
2634
%local2 = alloca [1 x i16], align 1
2735
call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %local2)

0 commit comments

Comments
 (0)