1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -enable-nontrivial-unswitch=true -simple-loop-unswitch -S < %s | FileCheck %s 3; RUN: opt -enable-nontrivial-unswitch=true -passes='loop(unswitch),verify<loops>' -S < %s | FileCheck %s 4 5declare void @may_exit() 6declare void @throw_npe() 7 8; It is illegal to preserve make_implicit notion of the condition being 9; unswitched because we may exit loop before we reach the condition, so 10; there is no guarantee that following implicit branch always means getting 11; to throw_npe block. 12define i32 @test_should_drop_make_implicit(i32* %p1, i32* %p2) { 13; CHECK-LABEL: @test_should_drop_make_implicit( 14; CHECK-NEXT: entry: 15; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 16; CHECK-NOT: !make.implicit 17; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 18; CHECK: entry.split.us: 19; CHECK-NEXT: br label [[LOOP_US:%.*]] 20; CHECK: loop.us: 21; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ] 22; CHECK-NEXT: [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4 23; CHECK-NEXT: [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0 24; CHECK-NEXT: br i1 [[SIDE_EXIT_COND_US]], label [[SIDE_EXIT_SPLIT_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]] 25; CHECK: null_check_block.us: 26; CHECK-NEXT: br label [[THROW_NPE_SPLIT_US:%.*]] 27; CHECK: side_exit.split.us: 28; CHECK-NEXT: br label [[SIDE_EXIT:%.*]] 29; CHECK: throw_npe.split.us: 30; CHECK-NEXT: br label [[THROW_NPE:%.*]] 31; CHECK: entry.split: 32; CHECK-NEXT: br label [[LOOP:%.*]] 33; CHECK: loop: 34; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 35; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1]], align 4 36; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0 37; CHECK-NEXT: br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT_SPLIT:%.*]], label [[NULL_CHECK_BLOCK:%.*]] 38; CHECK: null_check_block: 39; CHECK-NEXT: br label [[BACKEDGE]] 40; CHECK: backedge: 41; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 42; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 43; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 44; CHECK: side_exit.split: 45; CHECK-NEXT: br label [[SIDE_EXIT]] 46; CHECK: side_exit: 47; CHECK-NEXT: ret i32 0 48; CHECK: throw_npe: 49; CHECK-NEXT: call void @throw_npe() 50; CHECK-NEXT: unreachable 51; CHECK: exit: 52; CHECK-NEXT: [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 53; CHECK-NEXT: ret i32 [[X_LCSSA2]] 54; 55entry: 56 %null_check = icmp eq i32* %p2, null 57 br label %loop 58loop: 59 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 60 %x = load i32, i32* %p1 61 %side_exit_cond = icmp eq i32 %x, 0 62 br i1 %side_exit_cond, label %side_exit, label %null_check_block 63 64null_check_block: 65 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0 66 67backedge: 68 %iv.next = add i32 %iv,1 69 %loop_cond = icmp slt i32 %iv.next, 10000 70 br i1 %loop_cond, label %loop, label %exit 71 72side_exit: 73 ret i32 0 74 75throw_npe: 76 call void @throw_npe() 77 unreachable 78 79exit: 80 ret i32 %x 81} 82 83; Here make.implicit notion may be preserved because we always get to throw_npe 84; after following true branch. This is a trivial unswitch. 85define i32 @test_may_keep_make_implicit_trivial(i32* %p1, i32* %p2) { 86; CHECK-LABEL: @test_may_keep_make_implicit_trivial( 87; CHECK-NEXT: entry: 88; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 89; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0 90; CHECK: entry.split: 91; CHECK-NEXT: br label [[LOOP:%.*]] 92; CHECK: loop: 93; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 94; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1:%.*]], align 4 95; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0 96; CHECK-NEXT: br label [[SIDE_EXIT_BLOCK:%.*]] 97; CHECK: side_exit_block: 98; CHECK-NEXT: br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT:%.*]], label [[BACKEDGE]] 99; CHECK: backedge: 100; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 101; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 102; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 103; CHECK: side_exit: 104; CHECK-NEXT: ret i32 0 105; CHECK: throw_npe: 106; CHECK-NEXT: call void @throw_npe() 107; CHECK-NEXT: unreachable 108; CHECK: exit: 109; CHECK-NEXT: [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 110; CHECK-NEXT: ret i32 [[X_LCSSA2]] 111; 112entry: 113 %null_check = icmp eq i32* %p2, null 114 br label %loop 115loop: 116 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 117 %x = load i32, i32* %p1 118 %side_exit_cond = icmp eq i32 %x, 0 119 br i1 %null_check, label %throw_npe, label %side_exit_block, !make.implicit !0 120 121side_exit_block: 122 br i1 %side_exit_cond, label %side_exit, label %backedge 123 124backedge: 125 %iv.next = add i32 %iv,1 126 %loop_cond = icmp slt i32 %iv.next, 10000 127 br i1 %loop_cond, label %loop, label %exit 128 129side_exit: 130 ret i32 0 131 132throw_npe: 133 call void @throw_npe() 134 unreachable 135 136exit: 137 ret i32 %x 138} 139 140define i32 @test_may_keep_make_implicit_non_trivial(i32* %p1, i32* %p2) { 141; CHECK-LABEL: @test_may_keep_make_implicit_non_trivial( 142; CHECK-NEXT: entry: 143; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 144; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0 145; CHECK: entry.split.us: 146; CHECK-NEXT: br label [[LOOP_US:%.*]] 147; CHECK: loop.us: 148; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ] 149; CHECK-NEXT: [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4 150; CHECK-NEXT: [[INNER_BLOCK_COND_US:%.*]] = icmp eq i32 [[X_US]], 0 151; CHECK-NEXT: br i1 [[INNER_BLOCK_COND_US]], label [[INNER_BLOCK_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]] 152; CHECK: inner_block.us: 153; CHECK-NEXT: br label [[NULL_CHECK_BLOCK_US]] 154; CHECK: null_check_block.us: 155; CHECK-NEXT: br label [[THROW_NPE_SPLIT_US:%.*]] 156; CHECK: throw_npe.split.us: 157; CHECK-NEXT: br label [[THROW_NPE:%.*]] 158; CHECK: entry.split: 159; CHECK-NEXT: br label [[LOOP:%.*]] 160; CHECK: loop: 161; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 162; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1]], align 4 163; CHECK-NEXT: [[INNER_BLOCK_COND:%.*]] = icmp eq i32 [[X]], 0 164; CHECK-NEXT: br i1 [[INNER_BLOCK_COND]], label [[INNER_BLOCK:%.*]], label [[NULL_CHECK_BLOCK:%.*]] 165; CHECK: inner_block: 166; CHECK-NEXT: br label [[NULL_CHECK_BLOCK]] 167; CHECK: null_check_block: 168; CHECK-NEXT: br label [[BACKEDGE]] 169; CHECK: backedge: 170; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 171; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 172; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 173; CHECK: throw_npe: 174; CHECK-NEXT: call void @throw_npe() 175; CHECK-NEXT: unreachable 176; CHECK: exit: 177; CHECK-NEXT: [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 178; CHECK-NEXT: ret i32 [[X_LCSSA1]] 179; 180entry: 181 %null_check = icmp eq i32* %p2, null 182 br label %loop 183loop: 184 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 185 %x = load i32, i32* %p1 186 %inner_block_cond = icmp eq i32 %x, 0 187 br i1 %inner_block_cond, label %inner_block, label %null_check_block 188 189inner_block: 190 br label %null_check_block 191 192null_check_block: 193 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0 194 195backedge: 196 %iv.next = add i32 %iv,1 197 %loop_cond = icmp slt i32 %iv.next, 10000 198 br i1 %loop_cond, label %loop, label %exit 199 200throw_npe: 201 call void @throw_npe() 202 unreachable 203 204exit: 205 ret i32 %x 206} 207 208; Here make.implicit notion should be dropped because of exiting call. 209define i32 @test_should_drop_make_implicit_exiting_call(i32* %p1, i32* %p2) { 210; CHECK-LABEL: @test_should_drop_make_implicit_exiting_call( 211; CHECK-NEXT: entry: 212; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 213; CHECK-NOT: !make.implicit 214; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 215; CHECK: entry.split.us: 216; CHECK-NEXT: br label [[LOOP_US:%.*]] 217; CHECK: loop.us: 218; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ] 219; CHECK-NEXT: call void @may_exit() 220; CHECK-NEXT: [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4 221; CHECK-NEXT: [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0 222; CHECK-NEXT: br label [[THROW_NPE_SPLIT_US:%.*]] 223; CHECK: throw_npe.split.us: 224; CHECK-NEXT: br label [[THROW_NPE:%.*]] 225; CHECK: entry.split: 226; CHECK-NEXT: br label [[LOOP:%.*]] 227; CHECK: loop: 228; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 229; CHECK-NEXT: call void @may_exit() 230; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1]], align 4 231; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0 232; CHECK-NEXT: br label [[BACKEDGE]] 233; CHECK: backedge: 234; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 235; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 236; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 237; CHECK: throw_npe: 238; CHECK-NEXT: call void @throw_npe() 239; CHECK-NEXT: unreachable 240; CHECK: exit: 241; CHECK-NEXT: [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 242; CHECK-NEXT: ret i32 [[X_LCSSA1]] 243; 244entry: 245 %null_check = icmp eq i32* %p2, null 246 br label %loop 247loop: 248 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 249 call void @may_exit() 250 %x = load i32, i32* %p1 251 %side_exit_cond = icmp eq i32 %x, 0 252 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0 253 254backedge: 255 %iv.next = add i32 %iv,1 256 %loop_cond = icmp slt i32 %iv.next, 10000 257 br i1 %loop_cond, label %loop, label %exit 258 259throw_npe: 260 call void @throw_npe() 261 unreachable 262 263exit: 264 ret i32 %x 265} 266 267; Here exiting call goes after the null check, so make.implicit may be preserved. 268define i32 @test_may_keep_make_implicit_exiting_call(i32* %p1, i32* %p2) { 269; CHECK-LABEL: @test_may_keep_make_implicit_exiting_call( 270; CHECK-NEXT: entry: 271; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 272; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0 273; CHECK: entry.split: 274; CHECK-NEXT: br label [[LOOP:%.*]] 275; CHECK: loop: 276; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 277; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1:%.*]], align 4 278; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0 279; CHECK-NEXT: br label [[BACKEDGE]] 280; CHECK: backedge: 281; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 282; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 283; CHECK-NEXT: call void @may_exit() 284; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 285; CHECK: throw_npe: 286; CHECK-NEXT: call void @throw_npe() 287; CHECK-NEXT: unreachable 288; CHECK: exit: 289; CHECK-NEXT: [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 290; CHECK-NEXT: ret i32 [[X_LCSSA1]] 291; 292entry: 293 %null_check = icmp eq i32* %p2, null 294 br label %loop 295loop: 296 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 297 %x = load i32, i32* %p1 298 %side_exit_cond = icmp eq i32 %x, 0 299 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0 300 301backedge: 302 %iv.next = add i32 %iv,1 303 %loop_cond = icmp slt i32 %iv.next, 10000 304 call void @may_exit() 305 br i1 %loop_cond, label %loop, label %exit 306 307throw_npe: 308 call void @throw_npe() 309 unreachable 310 311exit: 312 ret i32 %x 313} 314 315!0 = !{} 316