-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[GlobalOpt] Handle operators separately when removing GV users #84694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[GlobalOpt] Handle operators separately when removing GV users #84694
Conversation
@llvm/pr-subscribers-llvm-binary-utilities @llvm/pr-subscribers-llvm-transforms Author: Anshil Gandhi (gandhi56) ChangesWhen CleanupPointerRootUsers is called on GV, Fixes #64680. Full diff: https://github.com/llvm/llvm-project/pull/84694.diff 3 Files Affected:
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index da714c9a75701b..2b3154eeb6100f 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -204,8 +204,9 @@ CleanupPointerRootUsers(GlobalVariable *GV,
// If Dead[n].first is the only use of a malloc result, we can delete its
// chain of computation and the store to the global in Dead[n].second.
SmallVector<std::pair<Instruction *, Instruction *>, 32> Dead;
-
+ SmallVector<StoreInst *> StoresToGV;
SmallVector<User *> Worklist(GV->users());
+
// Constants can't be pointers to dynamically allocated memory.
while (!Worklist.empty()) {
User *U = Worklist.pop_back_val();
@@ -217,6 +218,8 @@ CleanupPointerRootUsers(GlobalVariable *GV,
} else if (Instruction *I = dyn_cast<Instruction>(V)) {
if (I->hasOneUse())
Dead.push_back(std::make_pair(I, SI));
+ else
+ StoresToGV.push_back(SI);
}
} else if (MemSetInst *MSI = dyn_cast<MemSetInst>(U)) {
if (isa<Constant>(MSI->getValue())) {
@@ -241,6 +244,11 @@ CleanupPointerRootUsers(GlobalVariable *GV,
}
}
+ // We assert here that GV is never load from so
+ // we can safely remove all stores to GV.
+ for (StoreInst *SI : StoresToGV)
+ SI->eraseFromParent();
+
for (int i = 0, e = Dead.size(); i != e; ++i) {
if (IsSafeComputationToRemove(Dead[i].first, GetTLI)) {
Dead[i].second->eraseFromParent();
diff --git a/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-stores.ll b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-stores.ll
new file mode 100644
index 00000000000000..980fb6f5dc8bfe
--- /dev/null
+++ b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-stores.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -passes=globalopt < %s -S | FileCheck %s
+
+@a = internal unnamed_addr global i32 0, align 4
+@b = internal unnamed_addr global [3 x ptr] zeroinitializer, align 16
+
+define i32 @main() local_unnamed_addr {
+; CHECK-LABEL: define i32 @main() local_unnamed_addr {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[E:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[DOTPR:%.*]] = load i32, ptr @a, align 4
+; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[DOTPR]], 3
+; CHECK-NEXT: br i1 [[CMP1]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+; CHECK: for.body:
+; CHECK-NEXT: store i32 8, ptr [[E]], align 4
+; CHECK-NEXT: call void @bar20_()
+; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[E]], align 4
+; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[IF_END]]
+; CHECK: if.end:
+; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @a, align 4
+; CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP1]], 1
+; CHECK-NEXT: store i32 [[INC]], ptr @a, align 4
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP1]], 2
+; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END]]
+; CHECK: for.end:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ %e = alloca i32, align 4
+ %.pr = load i32, ptr @a, align 4
+ %cmp1 = icmp slt i32 %.pr, 3
+ br i1 %cmp1, label %for.body, label %for.end
+
+for.body: ; preds = %entry, %if.end
+ store i32 8, ptr %e, align 4
+ call void @bar20_()
+ %0 = load i32, ptr %e, align 4
+ %tobool.not = icmp eq i32 %0, 0
+ br i1 %tobool.not, label %if.then, label %if.end
+
+if.then: ; preds = %for.body
+ call void @foo()
+ br label %if.end
+
+if.end: ; preds = %if.then, %for.body
+ store ptr %e, ptr getelementptr inbounds ([3 x ptr], ptr @b, i64 0, i64 2), align 16
+ %1 = load i32, ptr @a, align 4
+ %inc = add nsw i32 %1, 1
+ store i32 %inc, ptr @a, align 4
+ %cmp = icmp slt i32 %1, 2
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end: ; preds = %if.end, %entry
+ ret i32 0
+}
+
+declare void @bar20_() local_unnamed_addr
+declare void @foo() local_unnamed_addr
diff --git a/llvm/test/Transforms/GlobalOpt/dead-store-status.ll b/llvm/test/Transforms/GlobalOpt/dead-store-status.ll
index 9a8fbb8d65f0e0..597c08929af902 100644
--- a/llvm/test/Transforms/GlobalOpt/dead-store-status.ll
+++ b/llvm/test/Transforms/GlobalOpt/dead-store-status.ll
@@ -4,8 +4,6 @@
; false. This was caught by the pass return status check that is hidden under
; EXPENSIVE_CHECKS.
-; CHECK: @global = internal unnamed_addr global ptr null, align 1
-
; CHECK-LABEL: @foo
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i16 undef
|
eaa2602
to
3b9a9d6
Compare
I see a flaw in my solution, I will update this PR with a more effective solution. Stay tuned! |
3b9a9d6
to
b71057a
Compare
Internal CI passed. |
ping |
Ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please clarify the commit title and description to provide more details on the change. Refactor CleanupPointerRootUsers
makes it sound like there's no change in functionality, but IIUC this adds new functionality.
4b6f1ca
to
80ba2b7
Compare
bd76371
to
fe47475
Compare
Internal CI passed |
@efriedma-quic Is anyone familiar with how to run valgrind tests? Or any other comments on this PR? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the testcase is just running a program that stores the result of a malloc to an internal global variable under valgrind. I don't have any specific examples handy; maybe someone else does.
continue; | ||
if (isa<Instruction, Operator>(Src)) { | ||
EraseFromParent(MTI); | ||
if (isSafeComputationToRemove(Src, GetTLI)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was trying to say that you can just call RecursivelyDeleteTriviallyDeadInstructions without checking if the instruction is dead; it internally checks if the instruction is dead.
But more importantly, it means isSafeComputationToRemove isn't actually doing anything useful, so the end result is that this behaves identically to D69428.
@efriedma-quic I took a second look through all the cleanup routines. |
Deleting stores where we can prove the stored value isn't a pointer to an allocation should be fine; it doesn't impact the controversial cases. (But the current version of the patch is more aggressive, maybe by accident.) |
b7e7d55
to
82f091c
Compare
Assuming GV is a pointer root which is never read from, the store instruction can be removed even if it's value operand is a pointer. I think the logic implemented to decide whether or not source value operands should be removed was a little messy. Hence the test from #64680 was failing. |
ping |
Assuming you are expecting @efriedma-quic reply, don't forget "note" from https://llvm.org/docs/CodeReview.html#acknowledge-all-reviewer-feedback |
ping |
82f091c
to
67a0a21
Compare
Remove CleanupPointerRootUsers and isLeakCheckerRoot. Replace calls to CleanupPointerRootUsers with an extended version of CleanupConstantGlobalUsers. Fixes llvm#64680. Change-Id: I4c3fc52890eec1a3706cba9ecb916fd344672756
67a0a21
to
39a1484
Compare
ping |
If you patch isn't getting appropriate review, merging it is not an appropriate way to escalate. Appropriate ways include privately emailing reviewers, or starting a thread on Discourse. I apologize for not continuing to review this in a timely fashion. I should not have ignored the patch like this, after I started reviewing. There are basically two ways forward for this patch: one, you preserve the "leak root" check so that allocation checking tools don't break. Two, we explicitly decide to break any tools that depend on "leak root" checking (probably needs an RFC). Your patch is currently doing neither one of those; it's still trying to straddle the middle in a way I can't understand. |
I am sorry about that, I thought I saw an approval. I really appreciate your comments, I will work on a new PR to resolve this issue. |
…ing GV users" (#132971) Reverts llvm/llvm-project#84694 . Review was incomplete.
FWIW, my opinion on what to do here is #109718 (comment). |
Refactor globalopt by eliminating redundant code. Fix #64680.