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 @throw_npe() 6 7; It is illegal to preserve make_implicit notion of the condition being 8; unswitched because we may exit loop before we reach the condition, so 9; there is no guarantee that following implicit branch always means getting 10; to throw_npe block. 11define i32 @test_should_drop_make_implicit(i32* %p1, i32* %p2) { 12; CHECK-LABEL: @test_should_drop_make_implicit( 13; CHECK-NEXT: entry: 14; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 15; CHECK-NOT: !make.implicit 16; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 17; CHECK: entry.split.us: 18; CHECK-NEXT: br label [[LOOP_US:%.*]] 19; CHECK: loop.us: 20; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ] 21; CHECK-NEXT: [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4 22; CHECK-NEXT: [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0 23; CHECK-NEXT: br i1 [[SIDE_EXIT_COND_US]], label [[SIDE_EXIT_SPLIT_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]] 24; CHECK: null_check_block.us: 25; CHECK-NEXT: br label [[THROW_NPE_SPLIT_US:%.*]] 26; CHECK: side_exit.split.us: 27; CHECK-NEXT: br label [[SIDE_EXIT:%.*]] 28; CHECK: throw_npe.split.us: 29; CHECK-NEXT: br label [[THROW_NPE:%.*]] 30; CHECK: entry.split: 31; CHECK-NEXT: br label [[LOOP:%.*]] 32; CHECK: loop: 33; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 34; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1]], align 4 35; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0 36; CHECK-NEXT: br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT_SPLIT:%.*]], label [[NULL_CHECK_BLOCK:%.*]] 37; CHECK: null_check_block: 38; CHECK-NEXT: br label [[BACKEDGE]] 39; CHECK: backedge: 40; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 41; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 42; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 43; CHECK: side_exit.split: 44; CHECK-NEXT: br label [[SIDE_EXIT]] 45; CHECK: side_exit: 46; CHECK-NEXT: ret i32 0 47; CHECK: throw_npe: 48; CHECK-NEXT: call void @throw_npe() 49; CHECK-NEXT: unreachable 50; CHECK: exit: 51; CHECK-NEXT: [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 52; CHECK-NEXT: ret i32 [[X_LCSSA2]] 53; 54entry: 55 %null_check = icmp eq i32* %p2, null 56 br label %loop 57loop: 58 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 59 %x = load i32, i32* %p1 60 %side_exit_cond = icmp eq i32 %x, 0 61 br i1 %side_exit_cond, label %side_exit, label %null_check_block 62 63null_check_block: 64 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0 65 66backedge: 67 %iv.next = add i32 %iv,1 68 %loop_cond = icmp slt i32 %iv.next, 10000 69 br i1 %loop_cond, label %loop, label %exit 70 71side_exit: 72 ret i32 0 73 74throw_npe: 75 call void @throw_npe() 76 unreachable 77 78exit: 79 ret i32 %x 80} 81 82; Here make.implicit notion may be preserved because we always get to throw_npe 83; after following true branch. This is a trivial unswitch. 84define i32 @test_may_keep_make_implicit_trivial(i32* %p1, i32* %p2) { 85; CHECK-LABEL: @test_may_keep_make_implicit_trivial( 86; CHECK-NEXT: entry: 87; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 88; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0 89; CHECK: entry.split: 90; CHECK-NEXT: br label [[LOOP:%.*]] 91; CHECK: loop: 92; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 93; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1:%.*]], align 4 94; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0 95; CHECK-NEXT: br label [[SIDE_EXIT_BLOCK:%.*]] 96; CHECK: side_exit_block: 97; CHECK-NEXT: br i1 [[SIDE_EXIT_COND]], label [[SIDE_EXIT:%.*]], label [[BACKEDGE]] 98; CHECK: backedge: 99; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 100; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 101; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 102; CHECK: side_exit: 103; CHECK-NEXT: ret i32 0 104; CHECK: throw_npe: 105; CHECK-NEXT: call void @throw_npe() 106; CHECK-NEXT: unreachable 107; CHECK: exit: 108; CHECK-NEXT: [[X_LCSSA2:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 109; CHECK-NEXT: ret i32 [[X_LCSSA2]] 110; 111entry: 112 %null_check = icmp eq i32* %p2, null 113 br label %loop 114loop: 115 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 116 %x = load i32, i32* %p1 117 %side_exit_cond = icmp eq i32 %x, 0 118 br i1 %null_check, label %throw_npe, label %side_exit_block, !make.implicit !0 119 120side_exit_block: 121 br i1 %side_exit_cond, label %side_exit, label %backedge 122 123backedge: 124 %iv.next = add i32 %iv,1 125 %loop_cond = icmp slt i32 %iv.next, 10000 126 br i1 %loop_cond, label %loop, label %exit 127 128side_exit: 129 ret i32 0 130 131throw_npe: 132 call void @throw_npe() 133 unreachable 134 135exit: 136 ret i32 %x 137} 138 139; TODO: This is a non-trivial unswitch, but it would still be legal to keep 140; !make.implicit in entry block. Currently we do not have enough analysis to 141; prove it. 142define i32 @test_may_keep_make_implicit_non_trivial(i32* %p1, i32* %p2) { 143; CHECK-LABEL: @test_may_keep_make_implicit_non_trivial( 144; CHECK-NEXT: entry: 145; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i32* [[P2:%.*]], null 146; CHECK-NOT: !make.implicit 147; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]] 148; CHECK: entry.split.us: 149; CHECK-NEXT: br label [[LOOP_US:%.*]] 150; CHECK: loop.us: 151; CHECK-NEXT: [[IV_US:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT_US]] ] 152; CHECK-NEXT: [[X_US:%.*]] = load i32, i32* [[P1:%.*]], align 4 153; CHECK-NEXT: [[INNER_BLOCK_COND_US:%.*]] = icmp eq i32 [[X_US]], 0 154; CHECK-NEXT: br i1 [[INNER_BLOCK_COND_US]], label [[INNER_BLOCK_US:%.*]], label [[NULL_CHECK_BLOCK_US:%.*]] 155; CHECK: inner_block.us: 156; CHECK-NEXT: br label [[NULL_CHECK_BLOCK_US]] 157; CHECK: null_check_block.us: 158; CHECK-NEXT: br label [[THROW_NPE_SPLIT_US:%.*]] 159; CHECK: throw_npe.split.us: 160; CHECK-NEXT: br label [[THROW_NPE:%.*]] 161; CHECK: entry.split: 162; CHECK-NEXT: br label [[LOOP:%.*]] 163; CHECK: loop: 164; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY_SPLIT]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ] 165; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P1]], align 4 166; CHECK-NEXT: [[INNER_BLOCK_COND:%.*]] = icmp eq i32 [[X]], 0 167; CHECK-NEXT: br i1 [[INNER_BLOCK_COND]], label [[INNER_BLOCK:%.*]], label [[NULL_CHECK_BLOCK:%.*]] 168; CHECK: inner_block: 169; CHECK-NEXT: br label [[NULL_CHECK_BLOCK]] 170; CHECK: null_check_block: 171; CHECK-NEXT: br label [[BACKEDGE]] 172; CHECK: backedge: 173; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 174; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000 175; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]] 176; CHECK: throw_npe: 177; CHECK-NEXT: call void @throw_npe() 178; CHECK-NEXT: unreachable 179; CHECK: exit: 180; CHECK-NEXT: [[X_LCSSA1:%.*]] = phi i32 [ [[X]], [[BACKEDGE]] ] 181; CHECK-NEXT: ret i32 [[X_LCSSA1]] 182; 183entry: 184 %null_check = icmp eq i32* %p2, null 185 br label %loop 186loop: 187 %iv = phi i32 [0, %entry], [%iv.next, %backedge] 188 %x = load i32, i32* %p1 189 %inner_block_cond = icmp eq i32 %x, 0 190 br i1 %inner_block_cond, label %inner_block, label %null_check_block 191 192inner_block: 193 br label %null_check_block 194 195null_check_block: 196 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0 197 198backedge: 199 %iv.next = add i32 %iv,1 200 %loop_cond = icmp slt i32 %iv.next, 10000 201 br i1 %loop_cond, label %loop, label %exit 202 203throw_npe: 204 call void @throw_npe() 205 unreachable 206 207exit: 208 ret i32 %x 209} 210 211!0 = !{} 212