316 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -passes='simple-loop-unswitch<nontrivial>' -S < %s | FileCheck %s3; RUN: opt -passes='loop(simple-loop-unswitch<nontrivial>),verify<loops>' -S < %s | FileCheck %s4 5declare void @may_exit()6declare void @throw_npe()7 8; It is illegal to preserve make_implicit notion of the condition being9; unswitched because we may exit loop before we reach the condition, so10; there is no guarantee that following implicit branch always means getting11; to throw_npe block.12define i32 @test_should_drop_make_implicit(ptr %p1, ptr %p2) {13; CHECK-LABEL: @test_should_drop_make_implicit(14; CHECK-NEXT: entry:15; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[P2:%.*]], null16; CHECK-NEXT: [[NULL_CHECK_FR:%.*]] = freeze i1 [[NULL_CHECK]]17; CHECK-NEXT: br i1 [[NULL_CHECK_FR]], 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, ptr [[P1:%.*]], align 423; CHECK-NEXT: [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 024; 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, ptr [[P1]], align 436; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 037; 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]], 142; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 1000043; 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 048; CHECK: throw_npe:49; CHECK-NEXT: call void @throw_npe()50; CHECK-NEXT: unreachable51; 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 ptr %p2, null57 br label %loop58loop:59 %iv = phi i32 [0, %entry], [%iv.next, %backedge]60 %x = load i32, ptr %p161 %side_exit_cond = icmp eq i32 %x, 062 br i1 %side_exit_cond, label %side_exit, label %null_check_block63 64null_check_block:65 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !066 67backedge:68 %iv.next = add i32 %iv,169 %loop_cond = icmp slt i32 %iv.next, 1000070 br i1 %loop_cond, label %loop, label %exit71 72side_exit:73 ret i32 074 75throw_npe:76 call void @throw_npe()77 unreachable78 79exit:80 ret i32 %x81}82 83; Here make.implicit notion may be preserved because we always get to throw_npe84; after following true branch. This is a trivial unswitch.85define i32 @test_may_keep_make_implicit_trivial(ptr %p1, ptr %p2) {86; CHECK-LABEL: @test_may_keep_make_implicit_trivial(87; CHECK-NEXT: entry:88; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[P2:%.*]], null89; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !090; 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, ptr [[P1:%.*]], align 495; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 096; 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]], 1101; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000102; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]103; CHECK: side_exit:104; CHECK-NEXT: ret i32 0105; CHECK: throw_npe:106; CHECK-NEXT: call void @throw_npe()107; CHECK-NEXT: unreachable108; 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 ptr %p2, null114 br label %loop115loop:116 %iv = phi i32 [0, %entry], [%iv.next, %backedge]117 %x = load i32, ptr %p1118 %side_exit_cond = icmp eq i32 %x, 0119 br i1 %null_check, label %throw_npe, label %side_exit_block, !make.implicit !0120 121side_exit_block:122 br i1 %side_exit_cond, label %side_exit, label %backedge123 124backedge:125 %iv.next = add i32 %iv,1126 %loop_cond = icmp slt i32 %iv.next, 10000127 br i1 %loop_cond, label %loop, label %exit128 129side_exit:130 ret i32 0131 132throw_npe:133 call void @throw_npe()134 unreachable135 136exit:137 ret i32 %x138}139 140define i32 @test_may_keep_make_implicit_non_trivial(ptr %p1, ptr %p2) {141; CHECK-LABEL: @test_may_keep_make_implicit_non_trivial(142; CHECK-NEXT: entry:143; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[P2:%.*]], null144; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[ENTRY_SPLIT_US:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0145; 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, ptr [[P1:%.*]], align 4150; CHECK-NEXT: [[INNER_BLOCK_COND_US:%.*]] = icmp eq i32 [[X_US]], 0151; 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, ptr [[P1]], align 4163; CHECK-NEXT: [[INNER_BLOCK_COND:%.*]] = icmp eq i32 [[X]], 0164; 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]], 1171; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000172; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]173; CHECK: throw_npe:174; CHECK-NEXT: call void @throw_npe()175; CHECK-NEXT: unreachable176; 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 ptr %p2, null182 br label %loop183loop:184 %iv = phi i32 [0, %entry], [%iv.next, %backedge]185 %x = load i32, ptr %p1186 %inner_block_cond = icmp eq i32 %x, 0187 br i1 %inner_block_cond, label %inner_block, label %null_check_block188 189inner_block:190 br label %null_check_block191 192null_check_block:193 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0194 195backedge:196 %iv.next = add i32 %iv,1197 %loop_cond = icmp slt i32 %iv.next, 10000198 br i1 %loop_cond, label %loop, label %exit199 200throw_npe:201 call void @throw_npe()202 unreachable203 204exit:205 ret i32 %x206}207 208; Here make.implicit notion should be dropped because of exiting call.209define i32 @test_should_drop_make_implicit_exiting_call(ptr %p1, ptr %p2) {210; CHECK-LABEL: @test_should_drop_make_implicit_exiting_call(211; CHECK-NEXT: entry:212; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[P2:%.*]], null213; CHECK-NEXT: [[NULL_CHECK_FR:%.*]] = freeze i1 [[NULL_CHECK]]214; CHECK-NEXT: br i1 [[NULL_CHECK_FR]], 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, ptr [[P1:%.*]], align 4221; CHECK-NEXT: [[SIDE_EXIT_COND_US:%.*]] = icmp eq i32 [[X_US]], 0222; 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, ptr [[P1]], align 4231; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0232; CHECK-NEXT: br label [[BACKEDGE]]233; CHECK: backedge:234; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1235; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000236; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[EXIT:%.*]]237; CHECK: throw_npe:238; CHECK-NEXT: call void @throw_npe()239; CHECK-NEXT: unreachable240; 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 ptr %p2, null246 br label %loop247loop:248 %iv = phi i32 [0, %entry], [%iv.next, %backedge]249 call void @may_exit()250 %x = load i32, ptr %p1251 %side_exit_cond = icmp eq i32 %x, 0252 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0253 254backedge:255 %iv.next = add i32 %iv,1256 %loop_cond = icmp slt i32 %iv.next, 10000257 br i1 %loop_cond, label %loop, label %exit258 259throw_npe:260 call void @throw_npe()261 unreachable262 263exit:264 ret i32 %x265}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(ptr %p1, ptr %p2) {269; CHECK-LABEL: @test_may_keep_make_implicit_exiting_call(270; CHECK-NEXT: entry:271; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq ptr [[P2:%.*]], null272; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[THROW_NPE:%.*]], label [[ENTRY_SPLIT:%.*]], !make.implicit !0273; 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, ptr [[P1:%.*]], align 4278; CHECK-NEXT: [[SIDE_EXIT_COND:%.*]] = icmp eq i32 [[X]], 0279; CHECK-NEXT: br label [[BACKEDGE]]280; CHECK: backedge:281; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1282; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[IV_NEXT]], 10000283; 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: unreachable288; 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 ptr %p2, null294 br label %loop295loop:296 %iv = phi i32 [0, %entry], [%iv.next, %backedge]297 %x = load i32, ptr %p1298 %side_exit_cond = icmp eq i32 %x, 0299 br i1 %null_check, label %throw_npe, label %backedge, !make.implicit !0300 301backedge:302 %iv.next = add i32 %iv,1303 %loop_cond = icmp slt i32 %iv.next, 10000304 call void @may_exit()305 br i1 %loop_cond, label %loop, label %exit306 307throw_npe:308 call void @throw_npe()309 unreachable310 311exit:312 ret i32 %x313}314 315!0 = !{}316