1; RUN: opt < %s -basicaa -sink -S | FileCheck %s
2
3declare i32 @f_load_global() nounwind readonly
4declare i32 @f_load_arg(i32*) nounwind readonly argmemonly
5declare void @f_store_global(i32) nounwind
6declare void @f_store_arg(i32*) nounwind argmemonly
7declare void @f_readonly_arg(i32* readonly, i32*) nounwind argmemonly
8declare i32 @f_readnone(i32) nounwind readnone
9
10@A = external global i32
11@B = external global i32
12
13; Sink readonly call if no stores are in the way.
14;
15; CHECK-LABEL: @test_sink_no_stores(
16; CHECK: true:
17; CHECK-NEXT: %l = call i32 @f_load_global
18; CHECK-NEXT: ret i32 %l
19define i32 @test_sink_no_stores(i1 %z) {
20  %l = call i32 @f_load_global()
21  br i1 %z, label %true, label %false
22true:
23  ret i32 %l
24false:
25  ret i32 0
26}
27
28; CHECK-LABEL: @test_sink_argmem_store(
29; CHECK: true:
30; CHECK-NEXT: %l = call i32 @f_load_arg
31; CHECK-NEXT: ret i32 %l
32define i32 @test_sink_argmem_store(i1 %z) {
33  %l = call i32 @f_load_arg(i32* @A)
34  store i32 0, i32* @B
35  br i1 %z, label %true, label %false
36true:
37  ret i32 %l
38false:
39  ret i32 0
40}
41
42; CHECK-LABEL: @test_sink_argmem_call(
43; CHECK: true:
44; CHECK-NEXT: %l = call i32 @f_load_arg
45; CHECK-NEXT: ret i32 %l
46define i32 @test_sink_argmem_call(i1 %z) {
47  %l = call i32 @f_load_arg(i32* @A)
48  call void @f_store_arg(i32* @B)
49  br i1 %z, label %true, label %false
50true:
51  ret i32 %l
52false:
53  ret i32 0
54}
55
56; CHECK-LABEL: @test_sink_argmem_multiple(
57; CHECK: true:
58; CHECK-NEXT: %l = call i32 @f_load_arg
59; CHECK-NEXT: ret i32 %l
60define i32 @test_sink_argmem_multiple(i1 %z) {
61  %l = call i32 @f_load_arg(i32* @A)
62  call void @f_readonly_arg(i32* @A, i32* @B)
63  br i1 %z, label %true, label %false
64true:
65  ret i32 %l
66false:
67  ret i32 0
68}
69
70; But don't sink if there is a store.
71;
72; CHECK-LABEL: @test_nosink_store(
73; CHECK: call i32 @f_load_global
74; CHECK-NEXT: store i32
75define i32 @test_nosink_store(i1 %z) {
76  %l = call i32 @f_load_global()
77  store i32 0, i32* @A
78  br i1 %z, label %true, label %false
79true:
80  ret i32 %l
81false:
82  ret i32 0
83}
84
85; CHECK-LABEL: @test_nosink_call(
86; CHECK: call i32 @f_load_global
87; CHECK-NEXT: call void @f_store_global
88define i32 @test_nosink_call(i1 %z) {
89  %l = call i32 @f_load_global()
90  call void @f_store_global(i32 0)
91  br i1 %z, label %true, label %false
92true:
93  ret i32 %l
94false:
95  ret i32 0
96}
97
98; readnone calls are sunk across stores.
99;
100; CHECK-LABEL: @test_sink_readnone(
101; CHECK: true:
102; CHECK-NEXT: %l = call i32 @f_readnone(
103; CHECK-NEXT: ret i32 %l
104define i32 @test_sink_readnone(i1 %z) {
105  %l = call i32 @f_readnone(i32 0)
106  store i32 0, i32* @A
107  br i1 %z, label %true, label %false
108true:
109  ret i32 %l
110false:
111  ret i32 0
112}
113