From 05c120823b6893c1384835d47656125cdd751550 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Tue, 14 Sep 2021 17:16:32 +0100 Subject: [PATCH] [DSE] Add capture-before test cases with loads. Add a set of test cases where redundant stores may be removable, depending on whether a local allocation gets captured before performing a load. --- .../captures-before-load.ll | 799 ++++++++++++++++++ 1 file changed, 799 insertions(+) create mode 100644 llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll diff --git a/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll b/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll new file mode 100644 index 000000000000..ad8f6337de7d --- /dev/null +++ b/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll @@ -0,0 +1,799 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes='dse' -S %s | FileCheck %s + +declare void @escape_and_clobber(i32*) +declare void @escape_writeonly(i32*) writeonly +declare void @clobber() + +define i32 @test_not_captured_before_load_same_bb(i32** %in.ptr) { +; CHECK-LABEL: @test_not_captured_before_load_same_bb( +; 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: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %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 + 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_escape_unreachable_block(i32** %in.ptr) { +; CHECK-LABEL: @test_not_captured_before_load_same_bb_escape_unreachable_block( +; 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: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; CHECK: unreach: +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 0 +; + %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 + store i32 99, i32* %a, align 4 + call void @escape_and_clobber(i32* %a) + ret i32 %in.lv.2 + +unreach: + call void @escape_and_clobber(i32* %a) + ret i32 0 +} + +define i32 @test_captured_and_clobbered_after_load_same_bb_2(i32** %in.ptr) { +; 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: 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]] +; + %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 + call void @escape_and_clobber(i32* %a) + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_captured_after_load_same_bb_2_clobbered_later(i32** %in.ptr) { +; CHECK-LABEL: @test_captured_after_load_same_bb_2_clobbered_later( +; 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: call void @escape_writeonly(i32* [[A]]) +; 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 + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + call void @escape_writeonly(i32* %a) + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_captured_and_clobbered_before_load_same_bb_1(i32** %in.ptr) { +; CHECK-LABEL: @test_captured_and_clobbered_before_load_same_bb_1( +; 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: call void @escape_and_clobber(i32* [[A]]) +; 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 @clobber() +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + call void @escape_and_clobber(i32* %a) + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_captured_before_load_same_bb_1_clobbered_later(i32** %in.ptr) { +; CHECK-LABEL: @test_captured_before_load_same_bb_1_clobbered_later( +; 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: call void @escape_writeonly(i32* [[A]]) +; 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 @clobber() +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + call void @escape_writeonly(i32* %a) + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_captured_before_load_same_bb_2(i32** %in.ptr) { +; CHECK-LABEL: @test_captured_before_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: call void @escape_and_clobber(i32* [[A]]) +; 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 @clobber() +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + call void @escape_and_clobber(i32* %a) + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_not_captured_before_load_same_bb_clobber(i32** %in.ptr) { +; CHECK-LABEL: @test_not_captured_before_load_same_bb_clobber( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: call void @clobber() +; 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 = alloca i32, align 4 + store i32 55, i32* %a + call void @clobber() + %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_captured_before_load_same_bb(i32** %in.ptr) { +; CHECK-LABEL: @test_captured_before_load_same_bb( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(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: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %a = alloca i32, align 4 + store i32 55, i32* %a + call void @escape_and_clobber(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_captured_sibling_path_to_load_other_blocks_1(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_captured_sibling_path_to_load_other_blocks_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: 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: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[THEN]] ], [ [[IN_LV_2]], [[ELSE]] ] +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; 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) + 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 + br label %exit + +exit: + %p = phi i32 [ 0, %then ], [ %in.lv.2, %else ] + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %p +} + +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 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @escape_and_clobber(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: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[THEN]] ], [ [[IN_LV_2]], [[ELSE]] ] +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; 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: + br label %exit + +else: + call void @escape_and_clobber(i32* %a) + %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: + %p = phi i32 [ 0, %then ], [ %in.lv.2, %else ] + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %p +} + +define i32 @test_captured_before_load_other_blocks_4(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_captured_before_load_other_blocks_4( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 55, i32* [[A]], align 4 +; 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: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]] +; CHECK: then: +; 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]], [[ENTRY:%.*]] ] +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; +entry: + %a = alloca i32, align 4 + store i32 55, i32* %a + 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 + br i1 %c.1, label %then, label %exit + +then: + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ 0, %then ], [ %in.lv.2, %entry ] + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %p +} + +define i32 @test_captured_before_load_other_blocks_5(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_captured_before_load_other_blocks_5( +; CHECK-NEXT: entry: +; 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 [[EXIT:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; 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 @clobber() +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; +entry: + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %exit + +then: + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %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 @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_captured_before_load_other_blocks_6(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_captured_before_load_other_blocks_6( +; CHECK-NEXT: entry: +; 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 [[EXIT:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; 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: call void @clobber() +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; +entry: + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %exit + +then: + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %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) + call void @clobber() + ret i32 %in.lv.2 +} + +define i32 @test_not_captured_before_load_other_blocks_1(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_1( +; 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: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %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 + store i32 99, i32* %a, align 4 + br i1 %c.1, label %then, label %else + +then: + br label %exit + +else: + br label %exit + +exit: + call void @escape_and_clobber(i32* %a) + ret i32 %in.lv.2 +} + +define i32 @test_not_captured_before_load_other_blocks_2(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_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: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %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 + store i32 99, i32* %a, align 4 + br i1 %c.1, label %then, label %else + +then: + call void @escape_and_clobber(i32* %a) + br label %exit + +else: + call void @escape_and_clobber(i32* %a) + br label %exit + +exit: + ret i32 %in.lv.2 +} + +define i32 @test_not_captured_before_load_other_blocks_3(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_3( +; 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: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[IN_LV_2]] +; + %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 + store i32 99, i32* %a, align 4 + br i1 %c.1, label %then, label %else + +then: + call void @escape_and_clobber(i32* %a) + br label %exit + +else: + br label %exit + +exit: + ret i32 %in.lv.2 +} + +define i32 @test_not_captured_before_load_other_blocks_4(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_4( +; 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: 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: 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: store i32 99, i32* [[A]], align 4 +; 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: + 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 + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ 0, %then ], [ %in.lv.2, %else ] + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %p +} + +define i32 @test_not_captured_before_load_other_blocks_5(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_5( +; CHECK-NEXT: entry: +; 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 [[EXIT:%.*]] +; 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: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[IN_LV_2]], [[THEN]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; +entry: + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %exit + +then: + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ %in.lv.2, %then ], [ 0, %entry ] + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %p +} + +define i32 @test_not_captured_before_load_other_blocks_6(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_6( +; CHECK-NEXT: entry: +; 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 [[EXIT:%.*]] +; 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: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[IN_LV_2]], [[THEN]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; +entry: + %a = alloca i32, align 4 + store i32 55, i32* %a + br i1 %c.1, label %then, label %exit + +then: + %in.lv.1 = load i32* , i32** %in.ptr, align 2 + %in.lv.2 = load i32 , i32* %in.lv.1, align 2 + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ %in.lv.2, %then ], [ 0, %entry ] + store i32 99, i32* %a, align 4 + call void @escape_writeonly(i32* %a) + call void @clobber() + ret i32 %p +} + +define i32 @test_not_captured_before_load_other_blocks_7(i32** %in.ptr, i1 %c.1) { +; CHECK-LABEL: @test_not_captured_before_load_other_blocks_7( +; CHECK-NEXT: entry: +; 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: call void @escape_writeonly(i32* [[A]]) +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]] +; CHECK: then: +; 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]], [[ENTRY:%.*]] ] +; CHECK-NEXT: store i32 99, i32* [[A]], align 4 +; CHECK-NEXT: call void @clobber() +; CHECK-NEXT: ret i32 [[P]] +; +entry: + %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 + call void @escape_writeonly(i32* %a) + br i1 %c.1, label %then, label %exit + +then: + call void @escape_writeonly(i32* %a) + br label %exit + +exit: + %p = phi i32 [ 0, %then ], [ %in.lv.2, %entry ] + store i32 99, i32* %a, align 4 + call void @clobber() + ret i32 %p +} + +define i32 @test_not_captured_before_load_same_bb_but_read(i32** %in.ptr) { +; CHECK-LABEL: @test_not_captured_before_load_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: [[LV:%.*]] = load i32, i32* [[A]], 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 + %lv = load i32, i32* %a + 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 +; 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: 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]] +; + %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 + 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 +} + +define i32 @test_captured_in_loop(i32** %in.ptr, 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: 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]] +; + %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 + 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 +} + +declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) + +@global = external global [10 x i16]* + +define void @test_memset_not_captured_before_load() { +; CHECK-LABEL: @test_memset_not_captured_before_load( +; CHECK-NEXT: [[A:%.*]] = alloca [2 x i32], align 4 +; CHECK-NEXT: [[CAST_A:%.*]] = bitcast [2 x i32]* [[A]] to i8* +; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, i8* [[CAST_A]], i32 4 +; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 1 [[TMP1]], i8 0, i32 4, i1 false) +; CHECK-NEXT: [[LV_1:%.*]] = load [10 x i16]*, [10 x i16]** @global, align 8 +; CHECK-NEXT: [[GEP_A_0:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[A]], i32 0, i32 0 +; CHECK-NEXT: store i32 1, i32* [[GEP_A_0]], align 4 +; CHECK-NEXT: [[GEP_LV:%.*]] = getelementptr inbounds [10 x i16], [10 x i16]* [[LV_1]], i64 0, i32 1 +; CHECK-NEXT: [[LV_2:%.*]] = load i16, i16* [[GEP_LV]], align 2 +; CHECK-NEXT: [[EXT_LV_2:%.*]] = zext i16 [[LV_2]] to i32 +; CHECK-NEXT: [[GEP_A_1:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[A]], i32 0, i32 1 +; CHECK-NEXT: store i32 [[EXT_LV_2]], i32* [[GEP_A_1]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[GEP_A_0]]) +; CHECK-NEXT: ret void +; + %a = alloca [2 x i32], align 4 + %cast.a = bitcast [2 x i32]* %a to i8* + call void @llvm.memset.p0i8.i32(i8* %cast.a, i8 0, i32 8, i1 false) + %lv.1 = load [10 x i16]*, [10 x i16]** @global, align 8 + %gep.a.0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i32 0, i32 0 + store i32 1, i32* %gep.a.0, align 4 + %gep.lv = getelementptr inbounds [10 x i16], [10 x i16]* %lv.1, i64 0, i32 1 + %lv.2 = load i16, i16* %gep.lv, align 2 + %ext.lv.2 = zext i16 %lv.2 to i32 + %gep.a.1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i32 0, i32 1 + store i32 %ext.lv.2, i32* %gep.a.1, align 4 + call void @escape_and_clobber(i32* %gep.a.0) + ret void +} + +define void @test_test_not_captured_before_load(i1 %c.1) { +; CHECK-LABEL: @test_test_not_captured_before_load( +; CHECK-NEXT: bb: +; CHECK-NEXT: [[A:%.*]] = alloca [2 x i32], align 4 +; CHECK-NEXT: [[CAST_A:%.*]] = bitcast [2 x i32]* [[A]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[CAST_A]], i8 0, i32 8, i1 false) +; CHECK-NEXT: [[LV_1:%.*]] = load [10 x i16]*, [10 x i16]** @global, align 8 +; CHECK-NEXT: [[GEP_LV:%.*]] = getelementptr inbounds [10 x i16], [10 x i16]* [[LV_1]], i64 0, i32 1 +; CHECK-NEXT: [[LV_2:%.*]] = load i16, i16* [[GEP_LV]], align 2 +; CHECK-NEXT: [[GEP_A_0:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[A]], i32 0, i32 0 +; CHECK-NEXT: store i32 1, i32* [[GEP_A_0]], align 4 +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]] +; CHECK: then: +; CHECK-NEXT: call void @escape_and_clobber(i32* [[GEP_A_0]]) +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: else: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[EXT_LV_2:%.*]] = zext i16 [[LV_2]] to i32 +; CHECK-NEXT: [[GEP_A_1:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[A]], i32 0, i32 1 +; CHECK-NEXT: store i32 [[EXT_LV_2]], i32* [[GEP_A_1]], align 4 +; CHECK-NEXT: call void @escape_and_clobber(i32* [[GEP_A_0]]) +; CHECK-NEXT: ret void +; +bb: + %a = alloca [2 x i32], align 4 + %cast.a = bitcast [2 x i32]* %a to i8* + call void @llvm.memset.p0i8.i32(i8* %cast.a, i8 0, i32 8, i1 false) + %lv.1 = load [10 x i16]*, [10 x i16]** @global, align 8 + %gep.lv = getelementptr inbounds [10 x i16], [10 x i16]* %lv.1, i64 0, i32 1 + %lv.2 = load i16, i16* %gep.lv, align 2 + %gep.a.0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i32 0, i32 0 + store i32 1, i32* %gep.a.0, align 4 + br i1 %c.1, label %then, label %else + +then: + call void @escape_and_clobber(i32* %gep.a.0) + br label %exit + +else: + br label %exit + +exit: + %ext.lv.2 = zext i16 %lv.2 to i32 + %gep.a.1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i32 0, i32 1 + store i32 %ext.lv.2, i32* %gep.a.1, align 4 + call void @escape_and_clobber(i32* %gep.a.0) + ret void +}