Files
clang-p2996/llvm/test/Transforms/DeadStoreElimination/captures-before-load.ll
Nikita Popov ba664d9066 [AA] Move earliest escape tracking from DSE to AA
This is a followup to D109844 (and alternative to D109907), which
integrates the new "earliest escape" tracking into AliasAnalysis.
This is done by replacing the pre-existing context-free capture
cache in AAQueryInfo with a replaceable (virtual) object with two
implementations: The SimpleCaptureInfo implements the previous
behavior (check whether object is captured at all), while
EarliestEscapeInfo implements the new behavior from DSE.

This combines the "earliest escape" analysis with the full power of
BasicAA: It subsumes the call handling from D109907, considers a
wider range of escape sources, and works with AA recursion. The
compile-time cost is slightly higher than with D109907.

Differential Revision: https://reviews.llvm.org/D110368
2021-09-25 22:40:41 +02:00

1181 lines
42 KiB
LLVM

; 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: [[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: [[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: [[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: [[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: 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: call void @clobber()
; CHECK-NEXT: ret i32 [[IN_LV_2]]
;
%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
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: 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: 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_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: 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: 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
; 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: [[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: [[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: [[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: 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: 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: [[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_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
; 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: [[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: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[CAST_A]], i32 4
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* align 1 [[TMP0]], i8 0, i32 4, 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
}
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: [[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: [[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
}
define i32 @instruction_captures_multiple_objects(i32* %p.1, i32** %p.2, i32** %p.3, i1 %c) {
; CHECK-LABEL: @instruction_captures_multiple_objects(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_1:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[A_2:%.*]] = alloca i32, align 4
; CHECK-NEXT: store i32 0, i32* [[P_1:%.*]], align 8
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[ELSE:%.*]]
; CHECK: then:
; CHECK-NEXT: [[LV_2:%.*]] = load i32*, i32** [[P_2:%.*]], align 8
; CHECK-NEXT: [[LV_2_2:%.*]] = load i32, i32* [[LV_2]], align 4
; CHECK-NEXT: ret i32 [[LV_2_2]]
; CHECK: else:
; CHECK-NEXT: [[LV_3:%.*]] = load i32*, i32** [[P_3:%.*]], align 8
; CHECK-NEXT: [[LV_3_2:%.*]] = load i32, i32* [[LV_3]], align 4
; CHECK-NEXT: call void @capture_and_clobber_multiple(i32* [[A_1]], i32* [[A_2]])
; CHECK-NEXT: ret i32 [[LV_3_2]]
;
entry:
%a.1 = alloca i32
%a.2 = alloca i32
store i32 0, i32* %p.1, align 8
br i1 %c, label %then, label %else
then:
store i32 99, i32* %a.2, align 4
%lv.2 = load i32*, i32** %p.2
%lv.2.2 = load i32, i32* %lv.2
store i32 0, i32* %a.1, align 8
ret i32 %lv.2.2
else:
%lv.3 = load i32*, i32** %p.3
%lv.3.2 = load i32, i32* %lv.3
call void @capture_and_clobber_multiple(i32* %a.1, i32* %a.2)
ret i32 %lv.3.2
}
declare void @capture_and_clobber_multiple(i32*, i32*)
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
define i64 @earliest_escape_ptrtoint(i64** %p.1) {
; CHECK-LABEL: @earliest_escape_ptrtoint(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_1:%.*]] = alloca i64, align 8
; CHECK-NEXT: [[A_2:%.*]] = alloca i64, align 8
; CHECK-NEXT: [[LV_1:%.*]] = load i64*, i64** [[P_1:%.*]], align 8
; CHECK-NEXT: [[LV_2:%.*]] = load i64, i64* [[LV_1]], align 4
; CHECK-NEXT: store i64* [[A_1]], i64** [[P_1]], align 8
; CHECK-NEXT: [[A_2_CAST:%.*]] = bitcast i64* [[A_2]] to i8*
; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[A_2_CAST]])
; CHECK-NEXT: ret i64 [[LV_2]]
;
entry:
%a.1 = alloca i64
%a.2 = alloca i64
store i64 99, i64* %a.1
%lv.1 = load i64*, i64** %p.1
%lv.2 = load i64, i64* %lv.1
store i64* %a.1, i64** %p.1, align 8
%int = ptrtoint i64* %a.2 to i64
store i64 %int , i64* %a.2, align 8
%a.2.cast = bitcast i64* %a.2 to i8*
call void @llvm.lifetime.end.p0i8(i64 8, i8* %a.2.cast)
ret i64 %lv.2
}
define i32 @test_not_captured_before_load_of_ptrtoint(i64 %in) {
; CHECK-LABEL: @test_not_captured_before_load_of_ptrtoint(
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[IN_PTR:%.*]] = inttoptr i64 [[IN:%.*]] to i32*
; CHECK-NEXT: [[IN_PTR_LOAD:%.*]] = load i32, i32* [[IN_PTR]], align 4
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]])
; CHECK-NEXT: ret i32 [[IN_PTR_LOAD]]
;
%a = alloca i32, align 4
store i32 55, i32* %a
%in.ptr = inttoptr i64 %in to i32*
%in.ptr.load = load i32, i32* %in.ptr
store i32 99, i32* %a
call void @escape_and_clobber(i32* %a)
ret i32 %in.ptr.load
}
declare i32* @getptr()
define i32 @test_not_captured_before_load_of_call() {
; CHECK-LABEL: @test_not_captured_before_load_of_call(
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[IN_PTR:%.*]] = call i32* @getptr() #[[ATTR4:[0-9]+]]
; CHECK-NEXT: [[IN_PTR_LOAD:%.*]] = load i32, i32* [[IN_PTR]], align 4
; CHECK-NEXT: store i32 99, i32* [[A]], align 4
; CHECK-NEXT: call void @escape_and_clobber(i32* [[A]])
; CHECK-NEXT: ret i32 [[IN_PTR_LOAD]]
;
%a = alloca i32, align 4
store i32 55, i32* %a
%in.ptr = call i32* @getptr() readnone
%in.ptr.load = load i32, i32* %in.ptr
store i32 99, i32* %a
call void @escape_and_clobber(i32* %a)
ret i32 %in.ptr.load
}
define i32 @test_not_captured_multiple_objects(i1 %c, i32** %in.ptr) {
; CHECK-LABEL: @test_not_captured_multiple_objects(
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
; CHECK-NEXT: [[O:%.*]] = select i1 [[C:%.*]], i32* [[A]], i32* [[B]]
; 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* [[O]], align 4
; CHECK-NEXT: call void @escape_and_clobber(i32* [[O]])
; CHECK-NEXT: ret i32 [[IN_LV_2]]
;
%a = alloca i32, align 4
%b = alloca i32, align 4
%o = select i1 %c, i32* %a, i32* %b
store i32 55, i32* %o
%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* %o
call void @escape_and_clobber(i32* %o)
ret i32 %in.lv.2
}