forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MSSA] Don't require clone creation to succeed (llvm#76819)
Sometimes, we create a MemoryAccess for an instruction, which is later simplified (e.g. via devirtualization) such that the new instruction has no memory effects anymore. If we later clone the instruction (e.g. during unswitching), then MSSA will not create a MemoryAccess for the new instruction, triggering an assert. Disable the assertion (by passing CreationMustSucceed=false) and adjust getDefiningAccessForClone() to work correctly in that case. This PR implements the alternative suggestion by alinas from llvm#76142.
- Loading branch information
1 parent
6637ba1
commit c90fa93
Showing
2 changed files
with
121 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
llvm/test/Transforms/SimpleLoopUnswitch/memssa-readnone-access.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 | ||
; RUN: opt -S -passes="loop-mssa(loop-instsimplify,simple-loop-unswitch<nontrivial>)" < %s | FileCheck %s | ||
|
||
@vtable = constant ptr @foo | ||
|
||
declare void @foo() memory(none) | ||
declare void @bar() | ||
|
||
; The call becomes known readnone after simplification, but still have a | ||
; MemoryAccess. Make sure this does not lead to an assertion failure. | ||
define void @test(i1 %c) { | ||
; CHECK-LABEL: define void @test( | ||
; CHECK-SAME: i1 [[C:%.*]]) { | ||
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]] | ||
; CHECK-NEXT: br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | ||
; CHECK: .split.us: | ||
; CHECK-NEXT: br label [[LOOP_US:%.*]] | ||
; CHECK: loop.us: | ||
; CHECK-NEXT: call void @foo() | ||
; CHECK-NEXT: br label [[EXIT_SPLIT_US:%.*]] | ||
; CHECK: exit.split.us: | ||
; CHECK-NEXT: br label [[EXIT:%.*]] | ||
; CHECK: .split: | ||
; CHECK-NEXT: br label [[LOOP:%.*]] | ||
; CHECK: loop: | ||
; CHECK-NEXT: call void @foo() | ||
; CHECK-NEXT: br label [[LOOP]] | ||
; CHECK: exit: | ||
; CHECK-NEXT: ret void | ||
; | ||
br label %loop | ||
|
||
loop: | ||
%fn = load ptr, ptr @vtable, align 8 | ||
call void %fn() | ||
br i1 %c, label %exit, label %loop | ||
|
||
exit: | ||
ret void | ||
} | ||
|
||
; Variant with another access after the call. | ||
define void @test2(i1 %c, ptr %p) { | ||
; CHECK-LABEL: define void @test2( | ||
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) { | ||
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]] | ||
; CHECK-NEXT: br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | ||
; CHECK: .split.us: | ||
; CHECK-NEXT: br label [[LOOP_US:%.*]] | ||
; CHECK: loop.us: | ||
; CHECK-NEXT: call void @foo() | ||
; CHECK-NEXT: call void @bar() | ||
; CHECK-NEXT: br label [[EXIT_SPLIT_US:%.*]] | ||
; CHECK: exit.split.us: | ||
; CHECK-NEXT: br label [[EXIT:%.*]] | ||
; CHECK: .split: | ||
; CHECK-NEXT: br label [[LOOP:%.*]] | ||
; CHECK: loop: | ||
; CHECK-NEXT: call void @foo() | ||
; CHECK-NEXT: call void @bar() | ||
; CHECK-NEXT: br label [[LOOP]] | ||
; CHECK: exit: | ||
; CHECK-NEXT: ret void | ||
; | ||
br label %loop | ||
|
||
loop: | ||
%fn = load ptr, ptr @vtable, align 8 | ||
call void %fn() | ||
call void @bar() | ||
br i1 %c, label %exit, label %loop | ||
|
||
exit: | ||
ret void | ||
} | ||
|
||
; Variant with another access after the call and no access before the call. | ||
define void @test3(i1 %c, ptr %p) { | ||
; CHECK-LABEL: define void @test3( | ||
; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) { | ||
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]] | ||
; CHECK-NEXT: br i1 [[C_FR]], label [[DOTSPLIT_US:%.*]], label [[DOTSPLIT:%.*]] | ||
; CHECK: .split.us: | ||
; CHECK-NEXT: br label [[LOOP_US:%.*]] | ||
; CHECK: loop.us: | ||
; CHECK-NEXT: br label [[SPLIT_US:%.*]] | ||
; CHECK: split.us: | ||
; CHECK-NEXT: call void @foo() | ||
; CHECK-NEXT: call void @bar() | ||
; CHECK-NEXT: br label [[EXIT_SPLIT_US:%.*]] | ||
; CHECK: exit.split.us: | ||
; CHECK-NEXT: br label [[EXIT:%.*]] | ||
; CHECK: .split: | ||
; CHECK-NEXT: br label [[LOOP:%.*]] | ||
; CHECK: loop: | ||
; CHECK-NEXT: br label [[SPLIT:%.*]] | ||
; CHECK: split: | ||
; CHECK-NEXT: call void @foo() | ||
; CHECK-NEXT: call void @bar() | ||
; CHECK-NEXT: br label [[LOOP]] | ||
; CHECK: exit: | ||
; CHECK-NEXT: ret void | ||
; | ||
br label %loop | ||
|
||
loop: | ||
%fn = load ptr, ptr @vtable, align 8 | ||
br label %split | ||
|
||
split: | ||
call void %fn() | ||
call void @bar() | ||
br i1 %c, label %exit, label %loop | ||
|
||
exit: | ||
ret void | ||
} |