222 lines
5.9 KiB
LLVM
222 lines
5.9 KiB
LLVM
|
; 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
|
||
|
}
|
||
|
|
||
|
; Variants of the above test with swapped branch destinations.
|
||
|
|
||
|
define void @test1_swapped(i1 %c) {
|
||
|
; CHECK-LABEL: define void @test1_swapped(
|
||
|
; CHECK-SAME: i1 [[C:%.*]]) {
|
||
|
; CHECK-NEXT: start:
|
||
|
; CHECK-NEXT: [[C_FR:%.*]] = freeze i1 [[C]]
|
||
|
; CHECK-NEXT: br i1 [[C_FR]], label [[START_SPLIT_US:%.*]], label [[START_SPLIT:%.*]]
|
||
|
; CHECK: start.split.us:
|
||
|
; CHECK-NEXT: br label [[LOOP_US:%.*]]
|
||
|
; CHECK: loop.us:
|
||
|
; CHECK-NEXT: call void @foo()
|
||
|
; CHECK-NEXT: br label [[LOOP_US]]
|
||
|
; CHECK: start.split:
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: call void @foo()
|
||
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||
|
; CHECK: exit:
|
||
|
; CHECK-NEXT: ret void
|
||
|
;
|
||
|
start:
|
||
|
br label %loop
|
||
|
|
||
|
loop:
|
||
|
%fn = load ptr, ptr @vtable, align 8
|
||
|
call void %fn()
|
||
|
br i1 %c, label %loop, label %exit
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @test2_swapped(i1 %c, ptr %p) {
|
||
|
; CHECK-LABEL: define void @test2_swapped(
|
||
|
; 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 [[LOOP_US]]
|
||
|
; CHECK: .split:
|
||
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||
|
; CHECK: loop:
|
||
|
; CHECK-NEXT: call void @foo()
|
||
|
; CHECK-NEXT: call void @bar()
|
||
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||
|
; 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 %loop, label %exit
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|
||
|
|
||
|
define void @test3_swapped(i1 %c, ptr %p) {
|
||
|
; CHECK-LABEL: define void @test3_swapped(
|
||
|
; 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 [[LOOP_US]]
|
||
|
; 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 [[EXIT:%.*]]
|
||
|
; 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 %loop, label %exit
|
||
|
|
||
|
exit:
|
||
|
ret void
|
||
|
}
|