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
1181 lines
42 KiB
LLVM
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
|
|
}
|