Skip to content

Commit eaa2602

Browse files
committed
[GlobalOpt] Remove all stores to GV
When CleanupPointerRootUsers is called on GV, the assumption is that there is no load from GV. Erase all stores to GV in this case. Fixes #64680.
1 parent a53401e commit eaa2602

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

llvm/lib/Transforms/IPO/GlobalOpt.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,9 @@ CleanupPointerRootUsers(GlobalVariable *GV,
204204
// If Dead[n].first is the only use of a malloc result, we can delete its
205205
// chain of computation and the store to the global in Dead[n].second.
206206
SmallVector<std::pair<Instruction *, Instruction *>, 32> Dead;
207-
207+
SmallVector<StoreInst *> StoresToGV;
208208
SmallVector<User *> Worklist(GV->users());
209+
209210
// Constants can't be pointers to dynamically allocated memory.
210211
while (!Worklist.empty()) {
211212
User *U = Worklist.pop_back_val();
@@ -217,6 +218,8 @@ CleanupPointerRootUsers(GlobalVariable *GV,
217218
} else if (Instruction *I = dyn_cast<Instruction>(V)) {
218219
if (I->hasOneUse())
219220
Dead.push_back(std::make_pair(I, SI));
221+
else
222+
StoresToGV.push_back(SI);
220223
}
221224
} else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
222225
if (isa<Constant>(MSI->getValue())) {
@@ -241,6 +244,11 @@ CleanupPointerRootUsers(GlobalVariable *GV,
241244
}
242245
}
243246

247+
// We assert here that GV is never load from so
248+
// we can safely remove all stores to GV.
249+
for (StoreInst *SI : StoresToGV)
250+
SI->eraseFromParent();
251+
244252
for (int i = 0, e = Dead.size(); i != e; ++i) {
245253
if (IsSafeComputationToRemove(Dead[i].first, GetTLI)) {
246254
Dead[i].second->eraseFromParent();
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt -passes=globalopt < %s -S | FileCheck %s
3+
4+
@a = internal unnamed_addr global i32 0, align 4
5+
@b = internal unnamed_addr global [3 x ptr] zeroinitializer, align 16
6+
7+
define i32 @main() local_unnamed_addr {
8+
; CHECK-LABEL: define i32 @main() local_unnamed_addr {
9+
; CHECK-NEXT: entry:
10+
; CHECK-NEXT: [[E:%.*]] = alloca i32, align 4
11+
; CHECK-NEXT: [[DOTPR:%.*]] = load i32, ptr @a, align 4
12+
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[DOTPR]], 3
13+
; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
14+
; CHECK: for.body:
15+
; CHECK-NEXT: store i32 8, ptr [[E]], align 4
16+
; CHECK-NEXT: call void @bar20_()
17+
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[E]], align 4
18+
; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP0]], 0
19+
; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
20+
; CHECK: if.then:
21+
; CHECK-NEXT: call void @foo()
22+
; CHECK-NEXT: br label [[IF_END]]
23+
; CHECK: if.end:
24+
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @a, align 4
25+
; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
26+
; CHECK-NEXT: store i32 [[INC]], ptr @a, align 4
27+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP1]], 2
28+
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]]
29+
; CHECK: for.end:
30+
; CHECK-NEXT: ret i32 0
31+
;
32+
entry:
33+
%e = alloca i32, align 4
34+
%.pr = load i32, ptr @a, align 4
35+
%cmp1 = icmp slt i32 %.pr, 3
36+
br i1 %cmp1, label %for.body, label %for.end
37+
38+
for.body: ; preds = %entry, %if.end
39+
store i32 8, ptr %e, align 4
40+
call void @bar20_()
41+
%0 = load i32, ptr %e, align 4
42+
%tobool.not = icmp eq i32 %0, 0
43+
br i1 %tobool.not, label %if.then, label %if.end
44+
45+
if.then: ; preds = %for.body
46+
call void @foo()
47+
br label %if.end
48+
49+
if.end: ; preds = %if.then, %for.body
50+
store ptr %e, ptr getelementptr inbounds ([3 x ptr], ptr @b, i64 0, i64 2), align 16
51+
%1 = load i32, ptr @a, align 4
52+
%inc = add nsw i32 %1, 1
53+
store i32 %inc, ptr @a, align 4
54+
%cmp = icmp slt i32 %1, 2
55+
br i1 %cmp, label %for.body, label %for.end
56+
57+
for.end: ; preds = %if.end, %entry
58+
ret i32 0
59+
}
60+
61+
declare void @bar20_() local_unnamed_addr
62+
declare void @foo() local_unnamed_addr

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
; false. This was caught by the pass return status check that is hidden under
55
; EXPENSIVE_CHECKS.
66

7-
; CHECK: @global = internal unnamed_addr global ptr null, align 1
8-
97
; CHECK-LABEL: @foo
108
; CHECK-NEXT: entry:
119
; CHECK-NEXT: ret i16 undef

0 commit comments

Comments
 (0)