Skip to content

Commit 80ba2b7

Browse files
committed
[GlobalOpt] Handle operators separately when removing GV users
This patch fixes the functionality of CleanupPointerRootUsers by separately handling cases where the global variable is wrapped within an operator. Fixes #64680.
1 parent b047a20 commit 80ba2b7

File tree

3 files changed

+38
-55
lines changed

3 files changed

+38
-55
lines changed

llvm/lib/Transforms/IPO/GlobalOpt.cpp

Lines changed: 38 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -201,61 +201,54 @@ CleanupPointerRootUsers(GlobalVariable *GV,
201201

202202
bool Changed = false;
203203

204-
// If Dead[n].first is the only use of a malloc result, we can delete its
205-
// chain of computation and the store to the global in Dead[n].second.
206-
SmallVector<std::pair<Instruction *, Instruction *>, 32> Dead;
207-
204+
// Collect all stores to GV.
205+
SmallVector<Instruction *, 8> Writes;
208206
SmallVector<User *> Worklist(GV->users());
209-
// Constants can't be pointers to dynamically allocated memory.
210207
while (!Worklist.empty()) {
211208
User *U = Worklist.pop_back_val();
212-
if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
213-
Value *V = SI->getValueOperand();
214-
if (isa<Constant>(V)) {
215-
Changed = true;
216-
SI->eraseFromParent();
217-
} else if (Instruction *I = dyn_cast<Instruction>(V)) {
218-
if (I->hasOneUse())
219-
Dead.push_back(std::make_pair(I, SI));
220-
}
221-
} else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
222-
if (isa<Constant>(MSI->getValue())) {
223-
Changed = true;
224-
MSI->eraseFromParent();
225-
} else if (Instruction *I = dyn_cast<Instruction>(MSI->getValue())) {
226-
if (I->hasOneUse())
227-
Dead.push_back(std::make_pair(I, MSI));
228-
}
229-
} else if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(U)) {
230-
GlobalVariable *MemSrc = dyn_cast<GlobalVariable>(MTI->getSource());
231-
if (MemSrc && MemSrc->isConstant()) {
232-
Changed = true;
233-
MTI->eraseFromParent();
234-
} else if (Instruction *I = dyn_cast<Instruction>(MTI->getSource())) {
235-
if (I->hasOneUse())
236-
Dead.push_back(std::make_pair(I, MTI));
237-
}
238-
} else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U)) {
209+
if (auto *SI = dyn_cast<StoreInst>(U)) {
210+
Writes.push_back(SI);
211+
} else if (auto *CE = dyn_cast<ConstantExpr>(U)) {
239212
if (isa<GEPOperator>(CE))
240213
append_range(Worklist, CE->users());
214+
} else if (auto *MI = dyn_cast<MemIntrinsic>(U)) {
215+
if (MI->getRawDest() == GV)
216+
Writes.push_back(MI);
241217
}
242218
}
243219

244-
for (int i = 0, e = Dead.size(); i != e; ++i) {
245-
if (IsSafeComputationToRemove(Dead[i].first, GetTLI)) {
246-
Dead[i].second->eraseFromParent();
247-
Instruction *I = Dead[i].first;
248-
do {
249-
if (isAllocationFn(I, GetTLI))
250-
break;
251-
Instruction *J = dyn_cast<Instruction>(I->getOperand(0));
252-
if (!J)
253-
break;
254-
I->eraseFromParent();
255-
I = J;
256-
} while (true);
220+
auto RemoveComputationChain = [&GetTLI](Instruction *I) {
221+
do {
222+
if (isAllocationFn(I, GetTLI))
223+
break;
224+
Instruction *J = dyn_cast<Instruction>(I->getOperand(0));
225+
if (!J)
226+
break;
257227
I->eraseFromParent();
228+
I = J;
229+
} while (true);
230+
I->eraseFromParent();
231+
};
232+
233+
// Remove the store if it's value operand is a constant or a computation
234+
// chain. If the value operand is a computation chain, determine if it is safe
235+
// to remove it before removing the store. Remove both the store and the
236+
// computation chain if it is safe to do so.
237+
while (!Writes.empty()) {
238+
auto *Write = Writes.pop_back_val();
239+
auto *V = Write->getOperand(0);
240+
if (isa<Constant>(V)) {
258241
Changed = true;
242+
Write->eraseFromParent();
243+
} else if (isa<Instruction>(V)) {
244+
if (IsSafeComputationToRemove(V, GetTLI)) {
245+
Changed = true;
246+
Write->eraseFromParent();
247+
RemoveComputationChain(cast<Instruction>(V));
248+
} else {
249+
Changed = true;
250+
Write->eraseFromParent();
251+
}
259252
}
260253
}
261254

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

llvm/test/Transforms/GlobalOpt/pr54572.ll

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,10 @@
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:[a-zA-Z0-9_$"\\.-]+]] = internal unnamed_addr global ptr null
11-
; CHECK: @[[C:[a-zA-Z0-9_$"\\.-]+]] = internal unnamed_addr constant [2 x ptr] zeroinitializer
12-
;.
139
define void @test() {
1410
; CHECK-LABEL: @test(
15-
; CHECK-NEXT: 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)
1611
; CHECK-NEXT: ret void
1712
;
1813
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)
1914
ret void
2015
}
21-
;.
22-
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
23-
;.

0 commit comments

Comments
 (0)