[SimpleLoopUnswitch] Add trivial unswitching tests with selects.
authorFlorian Hahn <flo@fhahn.com>
Wed, 27 Apr 2022 13:06:35 +0000 (14:06 +0100)
committerFlorian Hahn <flo@fhahn.com>
Wed, 27 Apr 2022 13:06:36 +0000 (14:06 +0100)
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.

llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch-logical-and-or.ll [new file with mode: 0644]
llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch.ll

diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch-logical-and-or.ll b/llvm/test/Transforms/SimpleLoopUnswitch/trivial-unswitch-logical-and-or.ll
new file mode 100644 (file)
index 0000000..c13dd55
--- /dev/null
@@ -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
+}
index 9b46010..57bc34b 100644 (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: