1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -passes='loop-mssa(simple-loop-unswitch)' -S %s | FileCheck %s 3 4; Test cases for trivial unswitching with selects that matches both a logical and & or. 5 6declare void @some_func() 7 8define void @test_select_logical_and_or_with_and_1(i1 noundef %cond1, i1 noundef %cond2) { 9; CHECK-LABEL: @test_select_logical_and_or_with_and_1( 10; CHECK-NEXT: entry: 11; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]] 12; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] 13; CHECK: entry.split: 14; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 15; CHECK: loop.header: 16; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, false 17; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false 18; CHECK-NEXT: br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]] 19; CHECK: loop.latch: 20; CHECK-NEXT: call void @some_func() 21; CHECK-NEXT: br label [[LOOP_HEADER]] 22; CHECK: exit: 23; CHECK-NEXT: br label [[EXIT_SPLIT]] 24; CHECK: exit.split: 25; CHECK-NEXT: ret void 26; 27entry: 28 br label %loop.header 29 30loop.header: 31 %cond_and1 = and i1 %cond2, %cond1 32 %sel = select i1 %cond_and1, i1 true, i1 false 33 br i1 %sel, label %exit, label %loop.latch 34 35loop.latch: 36 call void @some_func() 37 br label %loop.header 38 39exit: 40 ret void 41} 42 43define void @test_select_logical_and_or_with_and_2(i1 noundef %cond1, i1 noundef %cond2) { 44; CHECK-LABEL: @test_select_logical_and_or_with_and_2( 45; CHECK-NEXT: entry: 46; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]] 47; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]] 48; CHECK: entry.split: 49; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 50; CHECK: loop.header: 51; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 true, true 52; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false 53; CHECK-NEXT: br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]] 54; CHECK: loop.latch: 55; CHECK-NEXT: call void @some_func() 56; CHECK-NEXT: br label [[LOOP_HEADER]] 57; CHECK: exit: 58; CHECK-NEXT: br label [[EXIT_SPLIT]] 59; CHECK: exit.split: 60; CHECK-NEXT: ret void 61; 62entry: 63 br label %loop.header 64 65loop.header: 66 %cond_and1 = and i1 %cond2, %cond1 67 %sel = select i1 %cond_and1, i1 true, i1 false 68 br i1 %sel, label %loop.latch, label %exit 69 70loop.latch: 71 call void @some_func() 72 br label %loop.header 73 74exit: 75 ret void 76} 77 78define void @test_select_logical_and_or_with_or_1(i1 noundef %cond1, i1 noundef %cond2) { 79; CHECK-LABEL: @test_select_logical_and_or_with_or_1( 80; CHECK-NEXT: entry: 81; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND2:%.*]], [[COND1:%.*]] 82; CHECK-NEXT: br i1 [[TMP0]], label [[EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] 83; CHECK: entry.split: 84; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 85; CHECK: loop.header: 86; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 false, false 87; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false 88; CHECK-NEXT: br i1 [[SEL]], label [[EXIT:%.*]], label [[LOOP_LATCH:%.*]] 89; CHECK: loop.latch: 90; CHECK-NEXT: call void @some_func() 91; CHECK-NEXT: br label [[LOOP_HEADER]] 92; CHECK: exit: 93; CHECK-NEXT: br label [[EXIT_SPLIT]] 94; CHECK: exit.split: 95; CHECK-NEXT: ret void 96; 97entry: 98 br label %loop.header 99 100loop.header: 101 %cond_and1 = or i1 %cond2, %cond1 102 %sel = select i1 %cond_and1, i1 true, i1 false 103 br i1 %sel, label %exit, label %loop.latch 104 105loop.latch: 106 call void @some_func() 107 br label %loop.header 108 109exit: 110 ret void 111} 112 113 114define void @test_select_logical_and_or_with_or_2(i1 noundef %cond1, i1 noundef %cond2) { 115; CHECK-LABEL: @test_select_logical_and_or_with_or_2( 116; CHECK-NEXT: entry: 117; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[COND2:%.*]], [[COND1:%.*]] 118; CHECK-NEXT: br i1 [[TMP0]], label [[ENTRY_SPLIT:%.*]], label [[EXIT_SPLIT:%.*]] 119; CHECK: entry.split: 120; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] 121; CHECK: loop.header: 122; CHECK-NEXT: [[COND_AND1:%.*]] = or i1 true, true 123; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND_AND1]], i1 true, i1 false 124; CHECK-NEXT: br i1 [[SEL]], label [[LOOP_LATCH:%.*]], label [[EXIT:%.*]] 125; CHECK: loop.latch: 126; CHECK-NEXT: call void @some_func() 127; CHECK-NEXT: br label [[LOOP_HEADER]] 128; CHECK: exit: 129; CHECK-NEXT: br label [[EXIT_SPLIT]] 130; CHECK: exit.split: 131; CHECK-NEXT: ret void 132; 133entry: 134 br label %loop.header 135 136loop.header: 137 %cond_and1 = or i1 %cond2, %cond1 138 %sel = select i1 %cond_and1, i1 true, i1 false 139 br i1 %sel, label %loop.latch, label %exit 140 141loop.latch: 142 call void @some_func() 143 br label %loop.header 144 145exit: 146 ret void 147} 148 149; Check that loop unswitch looks through a combination of or and select instructions. 150; Note that cond6 can be unswitched because `select i1 %cond_or5, i1 true, i1 false` is 151; both logical-or and logical-and. 152define i32 @test_partial_condition_unswitch_or_select(i32* %var, i1 %cond1, i1 %cond2, i1 %cond3, i1 %cond4, i1 %cond5, i1 %cond6) { 153; CHECK-LABEL: @test_partial_condition_unswitch_or_select( 154; CHECK-NEXT: entry: 155; CHECK-NEXT: [[COND4_FR:%.*]] = freeze i1 [[COND4:%.*]] 156; CHECK-NEXT: [[COND2_FR:%.*]] = freeze i1 [[COND2:%.*]] 157; CHECK-NEXT: [[COND3_FR:%.*]] = freeze i1 [[COND3:%.*]] 158; CHECK-NEXT: [[COND1_FR:%.*]] = freeze i1 [[COND1:%.*]] 159; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4_FR]], [[COND2_FR]] 160; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3_FR]] 161; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1_FR]] 162; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] 163; CHECK: entry.split: 164; CHECK-NEXT: [[COND6_FR:%.*]] = freeze i1 [[COND6:%.*]] 165; CHECK-NEXT: br i1 [[COND6_FR]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]] 166; CHECK: entry.split.split: 167; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]] 168; CHECK: loop_begin: 169; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4 170; CHECK-NEXT: [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1 171; CHECK-NEXT: [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false 172; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false 173; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]] 174; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]] 175; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]] 176; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]] 177; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]] 178; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false 179; CHECK-NEXT: br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]] 180; CHECK: do_something: 181; CHECK-NEXT: call void @some_func() #[[ATTR0:[0-9]+]] 182; CHECK-NEXT: br label [[LOOP_BEGIN]] 183; CHECK: loop_exit: 184; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]] 185; CHECK: loop_exit.split1: 186; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]] 187; CHECK: loop_exit.split: 188; CHECK-NEXT: ret i32 0 189; 190entry: 191 br label %loop_begin 192 193loop_begin: 194 %var_val = load i32, i32* %var 195 %var_cond = trunc i32 %var_val to i1 196 %cond_or1 = or i1 %var_cond, %cond1 197 %cond_or2 = or i1 %cond2, %cond3 198 %cond_or3 = or i1 %cond_or1, %cond_or2 199 %cond_xor1 = xor i1 %cond5, %var_cond 200 %cond_and1 = and i1 %cond6, %var_cond 201 %cond_or4 = or i1 %cond_xor1, %cond_and1 202 %cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4 203 %cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4 204 br i1 %cond_or6, label %loop_exit, label %do_something 205 206do_something: 207 call void @some_func() noreturn nounwind 208 br label %loop_begin 209 210loop_exit: 211 ret i32 0 212} 213 214define 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) { 215; CHECK-LABEL: @test_partial_condition_unswitch_or_select_noundef( 216; CHECK-NEXT: entry: 217; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[COND4:%.*]], [[COND2:%.*]] 218; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[TMP0]], [[COND3:%.*]] 219; CHECK-NEXT: [[TMP2:%.*]] = or i1 [[TMP1]], [[COND1:%.*]] 220; CHECK-NEXT: br i1 [[TMP2]], label [[LOOP_EXIT_SPLIT:%.*]], label [[ENTRY_SPLIT:%.*]] 221; CHECK: entry.split: 222; CHECK-NEXT: br i1 [[COND6:%.*]], label [[LOOP_EXIT_SPLIT1:%.*]], label [[ENTRY_SPLIT_SPLIT:%.*]] 223; CHECK: entry.split.split: 224; CHECK-NEXT: br label [[LOOP_BEGIN:%.*]] 225; CHECK: loop_begin: 226; CHECK-NEXT: [[VAR_VAL:%.*]] = load i32, i32* [[VAR:%.*]], align 4 227; CHECK-NEXT: [[VAR_COND:%.*]] = trunc i32 [[VAR_VAL]] to i1 228; CHECK-NEXT: [[COND_OR1:%.*]] = or i1 [[VAR_COND]], false 229; CHECK-NEXT: [[COND_OR2:%.*]] = or i1 false, false 230; CHECK-NEXT: [[COND_OR3:%.*]] = or i1 [[COND_OR1]], [[COND_OR2]] 231; CHECK-NEXT: [[COND_XOR1:%.*]] = xor i1 [[COND5:%.*]], [[VAR_COND]] 232; CHECK-NEXT: [[COND_AND1:%.*]] = and i1 false, [[VAR_COND]] 233; CHECK-NEXT: [[COND_OR4:%.*]] = or i1 [[COND_XOR1]], [[COND_AND1]] 234; CHECK-NEXT: [[COND_OR5:%.*]] = select i1 [[COND_OR3]], i1 true, i1 [[COND_OR4]] 235; CHECK-NEXT: [[COND_OR6:%.*]] = select i1 [[COND_OR5]], i1 true, i1 false 236; CHECK-NEXT: br i1 [[COND_OR6]], label [[LOOP_EXIT:%.*]], label [[DO_SOMETHING:%.*]] 237; CHECK: do_something: 238; CHECK-NEXT: call void @some_func() #[[ATTR0]] 239; CHECK-NEXT: br label [[LOOP_BEGIN]] 240; CHECK: loop_exit: 241; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT1]] 242; CHECK: loop_exit.split1: 243; CHECK-NEXT: br label [[LOOP_EXIT_SPLIT]] 244; CHECK: loop_exit.split: 245; CHECK-NEXT: ret i32 0 246; 247entry: 248 br label %loop_begin 249 250loop_begin: 251 %var_val = load i32, i32* %var 252 %var_cond = trunc i32 %var_val to i1 253 %cond_or1 = or i1 %var_cond, %cond1 254 %cond_or2 = or i1 %cond2, %cond3 255 %cond_or3 = or i1 %cond_or1, %cond_or2 256 %cond_xor1 = xor i1 %cond5, %var_cond 257 %cond_and1 = and i1 %cond6, %var_cond 258 %cond_or4 = or i1 %cond_xor1, %cond_and1 259 %cond_or5 = select i1 %cond_or3, i1 true, i1 %cond_or4 260 %cond_or6 = select i1 %cond_or5, i1 true, i1 %cond4 261 br i1 %cond_or6, label %loop_exit, label %do_something 262 263do_something: 264 call void @some_func() noreturn nounwind 265 br label %loop_begin 266 267loop_exit: 268 ret i32 0 269} 270