From 963d3a22b34de33fc41a9e3e9ac733e9b6d241be Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 20 Sep 2021 15:41:28 +0100 Subject: [PATCH] [DSE] Add additional tests to cover review comments. Adds additional tests following comments from D109844. Also removes unusued in.ptr arguments and places in the call tests that used loads instead of a getval call. --- .../captures-before-call.ll | 156 +++++++--- .../captures-before-load.ll | 273 ++++++++++++++++++ 2 files changed, 392 insertions(+), 37 deletions(-) diff --git a/llvm/test/Transforms/DeadStoreElimination/captures-before-call.ll b/llvm/test/Transforms/DeadStoreElimination/captures-before-call.ll index 0fa2a2da2fc5..e334ad8f42a1 100644 --- a/llvm/test/Transforms/DeadStoreElimination/captures-before-call.ll +++ b/llvm/test/Transforms/DeadStoreElimination/captures-before-call.ll @@ -43,7 +43,7 @@ declare void @escape_and_clobber(i32*) declare void @escape_writeonly(i32*) writeonly declare void @clobber() -define i32 @test_not_captured_before_call_same_bb(i32** %in.ptr) { +define i32 @test_not_captured_before_call_same_bb() { ; CHECK-LABEL: @test_not_captured_before_call_same_bb( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -60,7 +60,7 @@ define i32 @test_not_captured_before_call_same_bb(i32** %in.ptr) { ret i32 %r } -define i32 @test_not_captured_before_call_same_bb_escape_unreachable_block(i32** %in.ptr) { +define i32 @test_not_captured_before_call_same_bb_escape_unreachable_block() { ; CHECK-LABEL: @test_not_captured_before_call_same_bb_escape_unreachable_block( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -84,28 +84,26 @@ unreach: ret i32 0 } -define i32 @test_captured_and_clobbered_after_load_same_bb_2(i32** %in.ptr) { +define i32 @test_captured_and_clobbered_after_load_same_bb_2() { ; CHECK-LABEL: @test_captured_and_clobbered_after_load_same_bb_2( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 -; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 -; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: [[R:%.*]] = call i32 @getval() ; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) ; CHECK-NEXT: store i32 99, i32* [[A]], align 4 ; CHECK-NEXT: call void @clobber() -; CHECK-NEXT: ret i32 [[IN_LV_2]] +; CHECK-NEXT: ret i32 [[R]] ; %a = alloca i32, align 4 store i32 55, i32* %a - %in.lv.1 = load i32* , i32** %in.ptr, align 2 - %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + %r = call i32 @getval() call void @escape_and_clobber(i32* %a) store i32 99, i32* %a, align 4 call void @clobber() - ret i32 %in.lv.2 + ret i32 %r } -define i32 @test_captured_after_call_same_bb_2_clobbered_later(i32** %in.ptr) { +define i32 @test_captured_after_call_same_bb_2_clobbered_later() { ; CHECK-LABEL: @test_captured_after_call_same_bb_2_clobbered_later( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -124,7 +122,7 @@ define i32 @test_captured_after_call_same_bb_2_clobbered_later(i32** %in.ptr) { ret i32 %r } -define i32 @test_captured_sibling_path_to_call_other_blocks_1(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_sibling_path_to_call_other_blocks_1(i1 %c.1) { ; CHECK-LABEL: @test_captured_sibling_path_to_call_other_blocks_1( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -160,7 +158,7 @@ exit: ret i32 %p } -define i32 @test_captured_before_call_other_blocks_2(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_before_call_other_blocks_2(i1 %c.1) { ; CHECK-LABEL: @test_captured_before_call_other_blocks_2( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -196,7 +194,7 @@ exit: ret i32 %p } -define i32 @test_captured_before_call_other_blocks_4(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_before_call_other_blocks_4(i1 %c.1) { ; CHECK-LABEL: @test_captured_before_call_other_blocks_4( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -231,7 +229,7 @@ exit: ret i32 %p } -define i32 @test_captured_before_call_other_blocks_5(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_before_call_other_blocks_5(i1 %c.1) { ; CHECK-LABEL: @test_captured_before_call_other_blocks_5( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -262,7 +260,7 @@ exit: ret i32 %r } -define i32 @test_captured_before_call_other_blocks_6(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_before_call_other_blocks_6(i1 %c.1) { ; CHECK-LABEL: @test_captured_before_call_other_blocks_6( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -295,7 +293,7 @@ exit: ret i32 %r } -define i32 @test_not_captured_before_call_other_blocks_1(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_1(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_1( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -327,7 +325,7 @@ exit: ret i32 %r } -define i32 @test_not_captured_before_call_other_blocks_2(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_2(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_2( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -361,7 +359,7 @@ exit: ret i32 %r } -define i32 @test_not_captured_before_call_other_blocks_3(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_3(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_3( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -393,7 +391,7 @@ exit: ret i32 %r } -define i32 @test_not_captured_before_call_other_blocks_4(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_4(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_4( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -429,7 +427,7 @@ exit: ret i32 %p } -define i32 @test_not_captured_before_call_other_blocks_5(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_5(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_5( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -462,7 +460,7 @@ exit: ret i32 %p } -define i32 @test_not_captured_before_call_other_blocks_6(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_6(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_6( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -497,7 +495,7 @@ exit: ret i32 %p } -define i32 @test_not_captured_before_call_other_blocks_7(i32** %in.ptr, i1 %c.1) { +define i32 @test_not_captured_before_call_other_blocks_7(i1 %c.1) { ; CHECK-LABEL: @test_not_captured_before_call_other_blocks_7( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -532,7 +530,7 @@ exit: ret i32 %p } -define i32 @test_not_captured_before_call_same_bb_but_read(i32** %in.ptr) { +define i32 @test_not_captured_before_call_same_bb_but_read() { ; CHECK-LABEL: @test_not_captured_before_call_same_bb_but_read( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 @@ -553,64 +551,60 @@ define i32 @test_not_captured_before_call_same_bb_but_read(i32** %in.ptr) { ret i32 %res } -define i32 @test_captured_after_loop(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_after_loop(i1 %c.1) { ; CHECK-LABEL: @test_captured_after_loop( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 -; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: [[R:%.*]] = call i32 @getval() ; CHECK-NEXT: store i32 99, i32* [[A]], align 4 ; CHECK-NEXT: br i1 [[C_1:%.*]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) -; CHECK-NEXT: ret i32 [[IN_LV_2]] +; CHECK-NEXT: ret i32 [[R]] ; %a = alloca i32, align 4 store i32 55, i32* %a br label %loop loop: - %in.lv.1 = load i32* , i32** %in.ptr, align 2 - %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + %r = call i32 @getval() store i32 99, i32* %a, align 4 br i1 %c.1, label %loop, label %exit exit: call void @escape_and_clobber(i32* %a) - ret i32 %in.lv.2 + ret i32 %r } -define i32 @test_captured_in_loop(i32** %in.ptr, i1 %c.1) { +define i32 @test_captured_in_loop(i1 %c.1) { ; CHECK-LABEL: @test_captured_in_loop( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 55, i32* [[A]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 -; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: [[R:%.*]] = call i32 @getval() ; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) ; CHECK-NEXT: store i32 99, i32* [[A]], align 4 ; CHECK-NEXT: br i1 [[C_1:%.*]], label [[LOOP]], label [[EXIT:%.*]] ; CHECK: exit: ; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) -; CHECK-NEXT: ret i32 [[IN_LV_2]] +; CHECK-NEXT: ret i32 [[R]] ; %a = alloca i32, align 4 store i32 55, i32* %a br label %loop loop: - %in.lv.1 = load i32* , i32** %in.ptr, align 2 - %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + %r = call i32 @getval() call void @escape_writeonly(i32* %a) store i32 99, i32* %a, align 4 br i1 %c.1, label %loop, label %exit exit: call void @escape_and_clobber(i32* %a) - ret i32 %in.lv.2 + ret i32 %r } declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) @@ -641,3 +635,91 @@ bb: call void @clobber() ret void } + + +define void @test_invoke_captures() personality i8* undef { +; CHECK-LABEL: @test_invoke_captures( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: invoke void @clobber() +; CHECK-NEXT: to label [[BB2:%.*]] unwind label [[BB5:%.*]] +; CHECK: bb2: +; CHECK-NEXT: store i32 0, i32* [[A]], align 8 +; CHECK-NEXT: invoke void @escape(i32* [[A]]) +; CHECK-NEXT: to label [[BB9:%.*]] unwind label [[BB10:%.*]] +; CHECK: bb4: +; CHECK-NEXT: ret void +; CHECK: bb5: +; CHECK-NEXT: [[LP_1:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: ret void +; CHECK: bb9: +; CHECK-NEXT: ret void +; CHECK: bb10: +; CHECK-NEXT: [[LP_2:%.*]] = landingpad { i8*, i32 } +; CHECK-NEXT: cleanup +; CHECK-NEXT: unreachable +; +bb: + %a = alloca i32 + store i32 99, i32* %a + invoke void @clobber() + to label %bb2 unwind label %bb5 + +bb2: + store i32 0, i32* %a, align 8 + invoke void @escape(i32* %a) + to label %bb9 unwind label %bb10 + +bb4: + ret void + +bb5: + %lp.1 = landingpad { i8*, i32 } + cleanup + ret void + +bb9: + ret void + +bb10: + %lp.2 = landingpad { i8*, i32 } + cleanup + unreachable +} + +declare noalias i32* @alloc() nounwind +declare i32 @getval_nounwind() nounwind + +define i32 @test_not_captured_before_load_same_bb_noalias_call() { +; CHECK-LABEL: @test_not_captured_before_load_same_bb_noalias_call( +; CHECK-NEXT: [[A:%.*]] = call i32* @alloc() +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: [[R:%.*]] = call i32 @getval_nounwind() +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[R]] +; + %a = call i32* @alloc() + store i32 55, i32* %a + %r = call i32 @getval_nounwind() + store i32 99, i32* %a, align 4 + call void @escape_and_clobber(i32* %a) + ret i32 %r +} + +define i32 @test_not_captured_before_load_same_bb_noalias_arg(i32* noalias %a) { +; CHECK-LABEL: @test_not_captured_before_load_same_bb_noalias_arg( +; CHECK-NEXT: store i32 55, i32* [[A:%.*]], align 4 +; CHECK-NEXT: [[R:%.*]] = call i32 @getval_nounwind() +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[R]] +; + store i32 55, i32* %a + %r = call i32 @getval_nounwind() + store i32 99, i32* %a, align 4 + call void @escape_and_clobber(i32* %a) + ret i32 %r +} diff --git a/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll b/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll index ad8f6337de7d..3db3ef35f6a7 100644 --- a/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll +++ b/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll @@ -235,6 +235,42 @@ exit: ret i32 %p } +define i32 @test_only_captured_sibling_path_with_ret_to_load_other_blocks(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_only_captured_sibling_path_with_ret_to_load_other_blocks( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: ret i32 0 +; CHECK: else: +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %else + +then: + call void @escape_writeonly(i32* %a) + ret i32 0 + +else: + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + br label %exit + +exit: + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %in.lv.2 +} + define i32 @test_captured_before_load_other_blocks_2(i32** %in.ptr, i1 %c.1) { ; CHECK-LABEL: @test_captured_before_load_other_blocks_2( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -652,6 +688,31 @@ define i32 @test_not_captured_before_load_same_bb_but_read(i32** %in.ptr) { ret i32 %res } +define i32 @test_not_captured_before_load_may_alias_same_bb_but_read(i32** %in.ptr, i32* %b, i1 %c) { +; CHECK-LABEL: @test_not_captured_before_load_may_alias_same_bb_but_read( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: [[PTR:%.*]] = select i1 [[C:%.*]], i32* [[A]], i32* [[B:%.*]] +; CHECK-NEXT: [[LV:%.*]] = load i32, i32* [[PTR]], align 4 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: [[RES:%.*]] = add i32 [[IN_LV_2]], [[LV]] +; CHECK-NEXT: ret i32 [[RES]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + %ptr = select i1 %c, i32* %a, i32* %b + %lv = load i32, i32* %ptr + store i32 99, i32* %a, align 4 + call void @escape_and_clobber(i32* %a) + %res = add i32 %in.lv.2, %lv + ret i32 %res +} + define i32 @test_captured_after_loop(i32** %in.ptr, i1 %c.1) { ; CHECK-LABEL: @test_captured_after_loop( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 @@ -797,3 +858,215 @@ exit: call void @escape_and_clobber(i32* %gep.a.0) ret void } + +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #0 +declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) #1 + +declare void @use.i64(i64) + +define i64 @test_a_not_captured_at_all(i64** %ptr, i64** %ptr.2, i1 %c) { +; CHECK-LABEL: @test_a_not_captured_at_all( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca i64, align 8 +; CHECK-NEXT: [[B:%.*]] = alloca i64, align 8 +; CHECK-NEXT: store i64* [[B]], i64** [[PTR:%.*]], align 8 +; CHECK-NEXT: [[LV_1:%.*]] = load i64*, i64** [[PTR_2:%.*]], align 8 +; CHECK-NEXT: br i1 [[C:%.*]], label [[EXIT:%.*]], label [[THEN:%.*]] +; CHECK: then: +; CHECK-NEXT: [[LV_2:%.*]] = load i64, i64* [[LV_1]], align 4 +; CHECK-NEXT: call void @use.i64(i64 [[LV_2]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[A_CAST:%.*]] = bitcast i64* [[A]] to i8* +; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[A_CAST]]) +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[A_CAST]], i8 0, i64 8, i1 false) +; CHECK-NEXT: [[L:%.*]] = load i64, i64* [[A]], align 4 +; CHECK-NEXT: ret i64 [[L]] +; +entry: + %a = alloca i64, align 8 + %b = alloca i64, align 8 + store i64* %b, i64** %ptr, align 8 + %lv.1 = load i64*, i64** %ptr.2, align 8 + br i1 %c, label %exit, label %then + +then: + %lv.2 = load i64, i64* %lv.1 + call void @use.i64(i64 %lv.2) + br label %exit + +exit: + %a.cast = bitcast i64* %a to i8* + call void @llvm.lifetime.start.p0i8(i64 8, i8* %a.cast) + store i64 99, i64* %a + call void @clobber() + call void @llvm.memset.p0i8.i64(i8* %a.cast, i8 0, i64 8, i1 false) + %l = load i64, i64* %a + ret i64 %l +} + +define i32 @test_not_captured_both_paths_1(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_both_paths_1( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[THEN]] ], [ [[IN_LV_2]], [[ELSE]] ] +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %else + +then: + store i32 99, i32* %a, align 4 + call void @escape_writeonly(i32* %a) + br label %exit + +else: + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ 0, %then ], [ %in.lv.2, %else ] + call void @clobber() + ret i32 %p +} + +define i32 @test_not_captured_both_paths_2(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_both_paths_2( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[IN_LV_2]], [[THEN]] ], [ 0, [[ELSE]] ] +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %else + +then: + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @escape_writeonly(i32* %a) + br label %exit + +else: + store i32 99, i32* %a, align 4 + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ %in.lv.2, %then ], [ 0, %else ] + call void @clobber() + ret i32 %p +} + +define i32 @test_captured_before_store_both_paths_2(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_captured_before_store_both_paths_2( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[IN_LV_2]], [[THEN]] ], [ 0, [[ELSE]] ] +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %else + +then: + call void @escape_writeonly(i32* %a) + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + br label %exit + +else: + call void @escape_writeonly(i32* %a) + store i32 99, i32* %a, align 4 + br label %exit + +exit: + %p = phi i32 [ %in.lv.2, %then ], [ 0, %else ] + call void @clobber() + ret i32 %p +} + + +declare noalias i32* @alloc() nounwind + +define i32 @test_not_captured_before_load_same_bb_noalias_call(i32** %in.ptr) { +; CHECK-LABEL: @test_not_captured_before_load_same_bb_noalias_call( +; CHECK-NEXT: [[A:%.*]] = call i32* @alloc() +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %a = call i32* @alloc() + store i32 55, i32* %a + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @escape_and_clobber(i32* %a) + ret i32 %in.lv.2 +} + +define i32 @test_not_captured_before_load_same_bb_noalias_arg(i32** %in.ptr, i32* noalias %a) { +; CHECK-LABEL: @test_not_captured_before_load_same_bb_noalias_arg( +; CHECK-NEXT: store i32 55, i32* [[A:%.*]], align 4 +; CHECK-NEXT: [[IN_LV_1:%.*]] = load i32*, i32** [[IN_PTR:%.*]], align 2 +; CHECK-NEXT: [[IN_LV_2:%.*]] = load i32, i32* [[IN_LV_1]], align 2 +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + store i32 55, i32* %a + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @escape_and_clobber(i32* %a) + ret i32 %in.lv.2 +}