Skip to content
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

[LICM] allow MemoryAccess creation failure #116813

Merged
merged 7 commits into from
Nov 20, 2024

Conversation

DianQK
Copy link
Member

@DianQK DianQK commented Nov 19, 2024

Fixes #116809.

After running some passes (SimpleLoopUnswitch, LoopInstSimplify, etc.), MemorySSA might be outdated, and the instruction I may have become a non-memory touching instruction.

LICM has already handled this, but it does not pass CreationMustSucceed=false to createDefinedAccess.

@llvmbot
Copy link
Member

llvmbot commented Nov 19, 2024

@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: DianQK (DianQK)

Changes

Fixes #116809.


Full diff: https://github.com/llvm/llvm-project/pull/116813.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp (+2-2)
  • (added) llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-pred-removed.ll (+24)
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index aa3cbc5e4bddc2..d807c66bd96195 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -1678,7 +1678,7 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
       if (BasicBlock *ClonedBB = cast_or_null<BasicBlock>(VMap->lookup(BB)))
         if (!DT.isReachableFromEntry(ClonedBB)) {
           for (BasicBlock *SuccBB : successors(ClonedBB))
-            SuccBB->removePredecessor(ClonedBB);
+            SuccBB->removePredecessor(ClonedBB, /*KeepOneInputPHIs*/ true);
           DeadBlocks.push_back(ClonedBB);
         }
 
@@ -1716,7 +1716,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
     auto *BB = DeathCandidates.pop_back_val();
     if (!DeadBlockSet.count(BB) && !DT.isReachableFromEntry(BB)) {
       for (BasicBlock *SuccBB : successors(BB)) {
-        SuccBB->removePredecessor(BB);
+        SuccBB->removePredecessor(BB, /*KeepOneInputPHIs*/ true);
         DeathCandidates.push_back(SuccBB);
       }
       DeadBlockSet.insert(BB);
diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-pred-removed.ll b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-pred-removed.ll
new file mode 100644
index 00000000000000..3545492f1e5e23
--- /dev/null
+++ b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-pred-removed.ll
@@ -0,0 +1,24 @@
+; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>),print<memoryssa>' -verify-memoryssa -disable-output -S < %s 2>&1 | FileCheck %s
+; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>,licm)' -verify-memoryssa -disable-output -S 
+
+; Check that SimpleLoopUnswitch preserves the MemoryDef of `call i32 @bar()` by preserving the PHI node.
+; Also, check that executing LICM after SimpleLoopUnswitch does not result in a crash.
+
+; CHECK: %unswitched.select = phi ptr [ @bar, %bb2 ]
+; CHECK-NEXT: MemoryDef
+; CHECK-NEXT: call i32 %unswitched.select()
+
+define i32 @foo(i1 %arg, ptr %arg1) {
+bb:
+  br label %bb2
+
+bb2:                                              ; preds = %bb2, %bb
+  %i = select i1 %arg, ptr %arg1, ptr @bar
+  %i3 = call i32 %i()
+  br i1 %arg, label %bb2, label %bb4
+
+bb4:                                              ; preds = %bb2
+  ret i32 %i3
+}
+
+declare i32 @bar() nounwind willreturn memory(none)

@DianQK DianQK changed the title [SimpleLoopUnswitch] Preserve one PHI when removing a predecessor of a BB [SimpleLoopUnswitch] Keep one PHI when removing a predecessor of a BB Nov 19, 2024
@dtcxzyw
Copy link
Member

dtcxzyw commented Nov 19, 2024

Does it fix #116228?

@@ -1678,7 +1678,7 @@ deleteDeadClonedBlocks(Loop &L, ArrayRef<BasicBlock *> ExitBlocks,
if (BasicBlock *ClonedBB = cast_or_null<BasicBlock>(VMap->lookup(BB)))
if (!DT.isReachableFromEntry(ClonedBB)) {
for (BasicBlock *SuccBB : successors(ClonedBB))
SuccBB->removePredecessor(ClonedBB);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a test case for now yet, but I think we also need to keep one phi here.

; Also, check that executing LICM after SimpleLoopUnswitch does not result in a crash.

; CHECK: %unswitched.select = phi ptr [ @bar, %bb2 ]
; CHECK-NEXT: MemoryDef
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot use /llvm/utils/update_test_checks.py because I want to check MemoryDef here.

@@ -0,0 +1,24 @@
; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>),print<memoryssa>' -verify-memoryssa -disable-output -S < %s 2>&1 | FileCheck %s
; RUN: opt -passes='loop-mssa(simple-loop-unswitch<nontrivial>,licm)' -verify-memoryssa -disable-output -S
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, I like /llvm/utils/update_test_checks.py, but verifying that it does not crash is sufficient.

@@ -1716,7 +1716,7 @@ static void deleteDeadBlocksFromLoop(Loop &L,
auto *BB = DeathCandidates.pop_back_val();
if (!DeadBlockSet.count(BB) && !DT.isReachableFromEntry(BB)) {
for (BasicBlock *SuccBB : successors(BB)) {
SuccBB->removePredecessor(BB);
SuccBB->removePredecessor(BB, /*KeepOneInputPHIs*/ true);
DeathCandidates.push_back(SuccBB);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: why can't MemorySSA be updated here? Is it because MemorySSAUpdater does not yet support this?

@DianQK
Copy link
Member Author

DianQK commented Nov 19, 2024

Does it fix #116228?

Maybe. It also hit other assertions. :(

Edit: I think this is a different issue.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add more detail to the PR description to explain why you think this is the right fix? This is not how such assertion failures are usually addressed.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, you're basically trying to fix this problem by preventing simplifications that may make a call memory(none) from occurring. This is definitely not a battle you can win :) SimpleLoopUnswitch is not the only pass that can do such simplifications. LoopInstSimplify is usually the easier way to produce such cases.

The more robust way to fix this is, when creating a new memory access that is essentially a clone of an existing one, to pass CreationMustSucceed=false to createDefinedAccess() and then handle no access being created.

The relevant code here (

MemoryAccess *NewMemAcc = MSSAU.createMemoryAccessInBB(
) already handles no access being created, but the API it goes through (createMemoryAccessInBB) currently doesn't have the CreationMustSucceed flag, so you'll have to add it first.

@DianQK DianQK changed the title [SimpleLoopUnswitch] Keep one PHI when removing a predecessor of a BB [LICM] allow MemoryAccess creation failure Nov 19, 2024
@DianQK
Copy link
Member Author

DianQK commented Nov 19, 2024

If I understand correctly, you're basically trying to fix this problem by preventing simplifications that may make a call memory(none) from occurring. This is definitely not a battle you can win :) SimpleLoopUnswitch is not the only pass that can do such simplifications. LoopInstSimplify is usually the easier way to produce such cases.

The more robust way to fix this is, when creating a new memory access that is essentially a clone of an existing one, to pass CreationMustSucceed=false to createDefinedAccess() and then handle no access being created.

The relevant code here (

MemoryAccess *NewMemAcc = MSSAU.createMemoryAccessInBB(

) already handles no access being created, but the API it goes through (createMemoryAccessInBB) currently doesn't have the CreationMustSucceed flag, so you'll have to add it first.

That was my initial thought. But, as I kept digging into the root cause of the failure, I noticed the MemorySSA being outdated. Then, I found that many calls to removePredecessor(BB, /*KeepOneInputPHIs*/ true) so I made this somewhat wired PR. Upon reconsideration, I realized I could think this outdated result as a conservative analysis result.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

llvm/test/Transforms/LICM/PR116813-memoryssa-outdated.ll Outdated Show resolved Hide resolved
@DianQK DianQK merged commit 18b02bb into llvm:main Nov 20, 2024
5 of 8 checks passed
@DianQK DianQK deleted the simple-loop-unswitch-memory-ssa branch November 20, 2024 11:52
@DianQK DianQK added this to the LLVM 19.X Release milestone Nov 21, 2024
@DianQK
Copy link
Member Author

DianQK commented Nov 21, 2024

/cherry-pick 18b02bb

@llvmbot
Copy link
Member

llvmbot commented Nov 21, 2024

/pull-request #117082

DianQK added a commit to llvmbot/llvm-project that referenced this pull request Nov 21, 2024
Fixes llvm#116809.

After running some passes (SimpleLoopUnswitch, LoopInstSimplify, etc.),
MemorySSA might be outdated, and the instruction `I` may have become a
non-memory touching instruction.

LICM has already handled this, but it does not pass
`CreationMustSucceed=false` to `createDefinedAccess`.

(cherry picked from commit 18b02bb)
DianQK added a commit to llvmbot/llvm-project that referenced this pull request Nov 21, 2024
Fixes llvm#116809.

After running some passes (SimpleLoopUnswitch, LoopInstSimplify, etc.),
MemorySSA might be outdated, and the instruction `I` may have become a
non-memory touching instruction.

LICM has already handled this, but it does not pass
`CreationMustSucceed=false` to `createDefinedAccess`.

(cherry picked from commit 18b02bb)
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Nov 25, 2024
Fixes llvm#116809.

After running some passes (SimpleLoopUnswitch, LoopInstSimplify, etc.),
MemorySSA might be outdated, and the instruction `I` may have become a
non-memory touching instruction.

LICM has already handled this, but it does not pass
`CreationMustSucceed=false` to `createDefinedAccess`.

(cherry picked from commit 18b02bb)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
4 participants