xref: /llvm-project/llvm/test/Transforms/Sink/call.ll (revision a198d2041e8a5c9520d3df59887ca3c744b15d82)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=sink -S | FileCheck %s
3
4declare i32 @f_load_global() nounwind willreturn readonly
5declare i32 @f_load_global_throwable() willreturn readonly
6declare i32 @f_load_global_may_not_return() nounwind readonly
7declare i32 @f_load_arg(ptr) nounwind willreturn readonly argmemonly
8declare void @f_store_global(i32) nounwind willreturn
9declare void @f_store_arg(ptr) nounwind willreturn argmemonly
10declare void @f_readonly_arg(ptr readonly, ptr) nounwind willreturn argmemonly
11declare i32 @f_readnone(i32) nounwind willreturn readnone
12
13@A = external global i32
14@B = external global i32
15
16; Sink readonly call if no stores are in the way.
17;
18define i32 @test_sink_no_stores(i1 %z) {
19; CHECK-LABEL: @test_sink_no_stores(
20; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
21; CHECK:       true:
22; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_global()
23; CHECK-NEXT:    ret i32 [[L]]
24; CHECK:       false:
25; CHECK-NEXT:    ret i32 0
26;
27  %l = call i32 @f_load_global()
28  br i1 %z, label %true, label %false
29true:
30  ret i32 %l
31false:
32  ret i32 0
33}
34
35define i32 @test_throwable_no_stores(i1 %z) {
36; CHECK-LABEL: @test_throwable_no_stores(
37; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_global_throwable()
38; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
39; CHECK:       true:
40; CHECK-NEXT:    ret i32 [[L]]
41; CHECK:       false:
42; CHECK-NEXT:    ret i32 0
43;
44  %l = call i32 @f_load_global_throwable()
45  br i1 %z, label %true, label %false
46true:
47  ret i32 %l
48false:
49  ret i32 0
50}
51
52define i32 @test_may_not_return_no_stores(i1 %z) {
53; CHECK-LABEL: @test_may_not_return_no_stores(
54; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_global_may_not_return()
55; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
56; CHECK:       true:
57; CHECK-NEXT:    ret i32 [[L]]
58; CHECK:       false:
59; CHECK-NEXT:    ret i32 0
60;
61  %l = call i32 @f_load_global_may_not_return()
62  br i1 %z, label %true, label %false
63true:
64  ret i32 %l
65false:
66  ret i32 0
67}
68
69define i32 @test_sink_argmem_store(i1 %z) {
70; CHECK-LABEL: @test_sink_argmem_store(
71; CHECK-NEXT:    store i32 0, ptr @B, align 4
72; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
73; CHECK:       true:
74; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_arg(ptr @A)
75; CHECK-NEXT:    ret i32 [[L]]
76; CHECK:       false:
77; CHECK-NEXT:    ret i32 0
78;
79  %l = call i32 @f_load_arg(ptr @A)
80  store i32 0, ptr @B
81  br i1 %z, label %true, label %false
82true:
83  ret i32 %l
84false:
85  ret i32 0
86}
87
88define i32 @test_sink_argmem_call(i1 %z) {
89; CHECK-LABEL: @test_sink_argmem_call(
90; CHECK-NEXT:    call void @f_store_arg(ptr @B)
91; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
92; CHECK:       true:
93; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_arg(ptr @A)
94; CHECK-NEXT:    ret i32 [[L]]
95; CHECK:       false:
96; CHECK-NEXT:    ret i32 0
97;
98  %l = call i32 @f_load_arg(ptr @A)
99  call void @f_store_arg(ptr @B)
100  br i1 %z, label %true, label %false
101true:
102  ret i32 %l
103false:
104  ret i32 0
105}
106
107define i32 @test_sink_argmem_multiple(i1 %z) {
108; CHECK-LABEL: @test_sink_argmem_multiple(
109; CHECK-NEXT:    call void @f_readonly_arg(ptr @A, ptr @B)
110; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
111; CHECK:       true:
112; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_arg(ptr @A)
113; CHECK-NEXT:    ret i32 [[L]]
114; CHECK:       false:
115; CHECK-NEXT:    ret i32 0
116;
117  %l = call i32 @f_load_arg(ptr @A)
118  call void @f_readonly_arg(ptr @A, ptr @B)
119  br i1 %z, label %true, label %false
120true:
121  ret i32 %l
122false:
123  ret i32 0
124}
125
126; But don't sink if there is a store.
127define i32 @test_nosink_store(i1 %z) {
128; CHECK-LABEL: @test_nosink_store(
129; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_global()
130; CHECK-NEXT:    store i32 0, ptr @A, align 4
131; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
132; CHECK:       true:
133; CHECK-NEXT:    ret i32 [[L]]
134; CHECK:       false:
135; CHECK-NEXT:    ret i32 0
136;
137  %l = call i32 @f_load_global()
138  store i32 0, ptr @A
139  br i1 %z, label %true, label %false
140true:
141  ret i32 %l
142false:
143  ret i32 0
144}
145
146define i32 @test_nosink_call(i1 %z) {
147; CHECK-LABEL: @test_nosink_call(
148; CHECK-NEXT:    [[L:%.*]] = call i32 @f_load_global()
149; CHECK-NEXT:    call void @f_store_global(i32 0)
150; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
151; CHECK:       true:
152; CHECK-NEXT:    ret i32 [[L]]
153; CHECK:       false:
154; CHECK-NEXT:    ret i32 0
155;
156  %l = call i32 @f_load_global()
157  call void @f_store_global(i32 0)
158  br i1 %z, label %true, label %false
159true:
160  ret i32 %l
161false:
162  ret i32 0
163}
164
165; readnone calls are sunk across stores.
166define i32 @test_sink_readnone(i1 %z) {
167; CHECK-LABEL: @test_sink_readnone(
168; CHECK-NEXT:    store i32 0, ptr @A, align 4
169; CHECK-NEXT:    br i1 [[Z:%.*]], label [[TRUE:%.*]], label [[FALSE:%.*]]
170; CHECK:       true:
171; CHECK-NEXT:    [[L:%.*]] = call i32 @f_readnone(i32 0)
172; CHECK-NEXT:    ret i32 [[L]]
173; CHECK:       false:
174; CHECK-NEXT:    ret i32 0
175;
176  %l = call i32 @f_readnone(i32 0)
177  store i32 0, ptr @A
178  br i1 %z, label %true, label %false
179true:
180  ret i32 %l
181false:
182  ret i32 0
183}
184