| ; 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: br label [[LOOP_HEADER:%.*]] |
| ; CHECK: loop.header: |
| ; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]] |
| ; 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: 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: br label [[LOOP_HEADER:%.*]] |
| ; CHECK: loop.header: |
| ; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]] |
| ; 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: 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. |
| 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: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]] |
| ; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]] |
| ; CHECK-NEXT: [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]] |
| ; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]] |
| ; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4_FR]], [[COND2_FR]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3_FR]] |
| ; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1_FR]] |
| ; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] |
| ; CHECK: entry.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 [[COND6:%.*]], [[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_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 |
| } |
| |
| ; Same as test_partial_condition_unswitch_or_select, but with arguments marked |
| ; as noundef. |
| 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 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 [[COND6:%.*]], [[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_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 |
| } |
| |
| ; Test case for PR55526. |
| define void @test_pr55526(i16 %a) { |
| ; CHECK-LABEL: @test_pr55526( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i16 [[A:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[TOBOOL]], label [[ENTRY_SPLIT:%.*]], label [[EXIT:%.*]] |
| ; CHECK: entry.split: |
| ; CHECK-NEXT: br label [[LOOP:%.*]] |
| ; CHECK: loop: |
| ; CHECK-NEXT: [[SEL:%.*]] = select i1 true, i1 true, i1 false |
| ; CHECK-NEXT: br label [[LOOP]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %tobool = icmp ne i16 %a, 0 |
| br label %loop |
| |
| loop: |
| %sel = select i1 %tobool, i1 true, i1 false |
| br i1 %sel, label %loop, label %exit |
| |
| exit: |
| ret void |
| } |