[SimpleLoopUnswitch] Add trivial unswitching tests with selects.

Add tests with selects that match both logical AND and logical OR. Note
that some of the tests get miscompiled at the moment.

Also moves a related test to the newly added test file.
This commit is contained in:
Florian Hahn 2022-04-27 14:06:35 +01:00
parent 4059770af5
commit 51be0925b4
No known key found for this signature in database
GPG Key ID: CF59919C6547A668
2 changed files with 264 additions and 57 deletions

View File

@ -0,0 +1,264 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes='loop-mssa(simple-loop-unswitch)' -S %s | FileCheck %s
; Test cases for trivial unswitching with selects that matches both a logical and & or.
declare void @some_func()
define void @test_select_logical_and_or_with_and_1(i1 noundef %cond1, i1 noundef %cond2) {
; CHECK-LABEL: @test_select_logical_and_or_with_and_1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, false
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
; CHECK-NEXT: br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]]
; CHECK: loop.latch:
; CHECK-NEXT: call void @some_func()
; CHECK-NEXT: br label [[LOOP_HEADER]]
; CHECK: exit:
; CHECK-NEXT: br label [[EXIT_SPLIT]]
; CHECK: exit.split:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%cond_and1 = and i1 %cond2, %cond1
%sel = select i1 %cond_and1, i1 true, i1 false
br i1 %sel, label %exit, label %loop.latch
loop.latch:
call void @some_func()
br label %loop.header
exit:
ret void
}
define void @test_select_logical_and_or_with_and_2(i1 noundef %cond1, i1 noundef %cond2) {
; CHECK-LABEL: @test_select_logical_and_or_with_and_2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 true, true
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
; CHECK-NEXT: br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: loop.latch:
; CHECK-NEXT: call void @some_func()
; CHECK-NEXT: br label [[LOOP_HEADER]]
; CHECK: exit:
; CHECK-NEXT: br label [[EXIT_SPLIT]]
; CHECK: exit.split:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%cond_and1 = and i1 %cond2, %cond1
%sel = select i1 %cond_and1, i1 true, i1 false
br i1 %sel, label %loop.latch, label %exit
loop.latch:
call void @some_func()
br label %loop.header
exit:
ret void
}
define void @test_select_logical_and_or_with_or_1(i1 noundef %cond1, i1 noundef %cond2) {
; CHECK-LABEL: @test_select_logical_and_or_with_or_1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 false, false
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
; CHECK-NEXT: br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]]
; CHECK: loop.latch:
; CHECK-NEXT: call void @some_func()
; CHECK-NEXT: br label [[LOOP_HEADER]]
; CHECK: exit:
; CHECK-NEXT: br label [[EXIT_SPLIT]]
; CHECK: exit.split:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%cond_and1 = or i1 %cond2, %cond1
%sel = select i1 %cond_and1, i1 true, i1 false
br i1 %sel, label %exit, label %loop.latch
loop.latch:
call void @some_func()
br label %loop.header
exit:
ret void
}
define void @test_select_logical_and_or_with_or_2(i1 noundef %cond1, i1 noundef %cond2) {
; CHECK-LABEL: @test_select_logical_and_or_with_or_2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 true, true
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false
; CHECK-NEXT: br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]]
; CHECK: loop.latch:
; CHECK-NEXT: call void @some_func()
; CHECK-NEXT: br label [[LOOP_HEADER]]
; CHECK: exit:
; CHECK-NEXT: br label [[EXIT_SPLIT]]
; CHECK: exit.split:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%cond_and1 = or i1 %cond2, %cond1
%sel = select i1 %cond_and1, i1 true, i1 false
br i1 %sel, label %loop.latch, label %exit
loop.latch:
call void @some_func()
br label %loop.header
exit:
ret void
}
; Check that loop unswitch looks through a combination of or and select instructions.
; Note that cond6 can be unswitched because `select i1 %cond_or5, i1 true, i1 false` is
; both logical-or and logical-and.
define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) {
; CHECK-LABEL: @test_partial_condition_unswitch_or_select(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br i1 [[COND6:%.*]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
; CHECK: entry.split.split:
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
; CHECK: loop_begin:
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
; CHECK-NEXT: [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1
; CHECK-NEXT: [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]]
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
; CHECK-NEXT: br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]]
; CHECK: do_something:
; CHECK-NEXT: call void @some_func() #[[ATTR0:[0-9]+]]
; CHECK-NEXT: br label [[LOOP_BEGIN]]
; CHECK: loop_exit:
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]]
; CHECK: loop_exit.split1:
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
; CHECK: loop_exit.split:
; CHECK-NEXT: ret i32 0
;
entry:
br label %loop_begin
loop_begin:
%var_val = load i32, i32* %var
%var_cond = trunc i32 %var_val to i1
%cond_or1 = or i1 %var_cond, %cond1
%cond_or2 = or i1 %cond2, %cond3
%cond_or3 = or i1 %cond_or1, %cond_or2
%cond_xor1 = xor i1 %cond5, %var_cond
%cond_and1 = and i1 %cond6, %var_cond
%cond_or4 = or i1 %cond_xor1, %cond_and1
%cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
%cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
br i1 %cond_or6, label %loop_exit, label %do_something
do_something:
call void @some_func() noreturn nounwind
br label %loop_begin
loop_exit:
ret i32 0
}
define i32 @test_partial_condition_unswitch_or_select_noundef(i32* noundef %var, i1 noundef %cond1, i1 noundef %cond2, i1 noundef %cond3, i1 noundef %cond4, i1 noundef %cond5, i1 noundef %cond6) {
; CHECK-LABEL: @test_partial_condition_unswitch_or_select_noundef(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]]
; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]]
; CHECK: entry.split:
; CHECK-NEXT: br i1 [[COND6:%.*]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]]
; CHECK: entry.split.split:
; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]]
; CHECK: loop_begin:
; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4
; CHECK-NEXT: [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1
; CHECK-NEXT: [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false
; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false
; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]]
; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]]
; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]]
; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]]
; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]]
; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false
; CHECK-NEXT: br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]]
; CHECK: do_something:
; CHECK-NEXT: call void @some_func() #[[ATTR0]]
; CHECK-NEXT: br label [[LOOP_BEGIN]]
; CHECK: loop_exit:
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]]
; CHECK: loop_exit.split1:
; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]]
; CHECK: loop_exit.split:
; CHECK-NEXT: ret i32 0
;
entry:
br label %loop_begin
loop_begin:
%var_val = load i32, i32* %var
%var_cond = trunc i32 %var_val to i1
%cond_or1 = or i1 %var_cond, %cond1
%cond_or2 = or i1 %cond2, %cond3
%cond_or3 = or i1 %cond_or1, %cond_or2
%cond_xor1 = xor i1 %cond5, %var_cond
%cond_and1 = and i1 %cond6, %var_cond
%cond_or4 = or i1 %cond_xor1, %cond_and1
%cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
%cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
br i1 %cond_or6, label %loop_exit, label %do_something
do_something:
call void @some_func() noreturn nounwind
br label %loop_begin
loop_exit:
ret i32 0
}

View File

@ -634,63 +634,6 @@ loop_exit:
; CHECK-NEXT: ret
}
; Check that loop unswitch looks through a combination of or and select instructions.
; Note that cond6 can be unswitched because `select i1 %cond_or5, i1 true, i1 false` is
; both logical-or and logical-and.
define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) {
; CHECK-LABEL: @test_partial_condition_unswitch_or_select(
entry:
br label %loop_begin
; CHECK-NEXT: entry:
; CHECK-NEXT: %[[INV_OR1:.*]] = or i1 %cond4, %cond2
; CHECK-NEXT: %[[INV_OR2:.*]] = or i1 %[[INV_OR1]], %cond3
; CHECK-NEXT: %[[INV_OR3:.*]] = or i1 %[[INV_OR2]], %cond1
; CHECK-NEXT: br i1 %[[INV_OR3]], label %loop_exit.split, label %entry.split
;
; CHECK: entry.split:
; CHECK-NEXT: br i1 %cond6, label %loop_exit.split1, label %entry.split.split
;
; CHECK: entry.split.split:
; CHECK-NEXT: br label %loop_begin
loop_begin:
%var_val = load i32, i32* %var
%var_cond = trunc i32 %var_val to i1
%cond_or1 = or i1 %var_cond, %cond1
%cond_or2 = or i1 %cond2, %cond3
%cond_or3 = or i1 %cond_or1, %cond_or2
%cond_xor1 = xor i1 %cond5, %var_cond
%cond_and1 = and i1 %cond6, %var_cond
%cond_or4 = or i1 %cond_xor1, %cond_and1
%cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4
%cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4
br i1 %cond_or6, label %loop_exit, label %do_something
; CHECK: loop_begin:
; CHECK-NEXT: %[[VAR:.*]] = load i32
; CHECK-NEXT: %[[VAR_COND:.*]] = trunc i32 %[[VAR]] to i1
; CHECK-NEXT: %[[COND_OR1:.*]] = or i1 %[[VAR_COND]], false
; CHECK-NEXT: %[[COND_OR2:.*]] = or i1 false, false
; CHECK-NEXT: %[[COND_OR3:.*]] = or i1 %[[COND_OR1]], %[[COND_OR2]]
; CHECK-NEXT: %[[COND_XOR:.*]] = xor i1 %cond5, %[[VAR_COND]]
; CHECK-NEXT: %[[COND_AND:.*]] = and i1 false, %[[VAR_COND]]
; CHECK-NEXT: %[[COND_OR4:.*]] = or i1 %[[COND_XOR]], %[[COND_AND]]
; CHECK-NEXT: %[[COND_OR5:.*]] = select i1 %[[COND_OR3]], i1 true, i1 %[[COND_OR4]]
; CHECK-NEXT: %[[COND_OR6:.*]] = select i1 %[[COND_OR5]], i1 true, i1 false
; CHECK-NEXT: br i1 %[[COND_OR6]], label %loop_exit, label %do_something
do_something:
call void @some_func() noreturn nounwind
br label %loop_begin
; CHECK: do_something:
; CHECK-NEXT: call
; CHECK-NEXT: br label %loop_begin
loop_exit:
ret i32 0
; CHECK: loop_exit.split:
; CHECK-NEXT: ret
}
define i32 @test_partial_condition_unswitch_with_lcssa_phi1(i32* %var, i1 %cond, i32 %x) {
; CHECK-LABEL: @test_partial_condition_unswitch_with_lcssa_phi1(
entry: