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