1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -inline-threshold=0 -always-inline -S | FileCheck %s
3; RUN: opt < %s -passes=always-inline -S | FileCheck %s
4
5declare i8* @foo(i8*) argmemonly nounwind
6
7define i8* @callee(i8 *%p) alwaysinline {
8; CHECK-LABEL: @callee(
9; CHECK-NEXT:    [[R:%.*]] = call i8* @foo(i8* noalias [[P:%.*]])
10; CHECK-NEXT:    ret i8* [[R]]
11;
12  %r = call i8* @foo(i8* noalias %p)
13  ret i8* %r
14}
15
16define i8* @caller(i8* %ptr, i64 %x) {
17; CHECK-LABEL: @caller(
18; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
19; CHECK-NEXT:    [[R_I:%.*]] = call nonnull i8* @foo(i8* noalias [[GEP]])
20; CHECK-NEXT:    ret i8* [[R_I]]
21;
22  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
23  %p = call nonnull i8* @callee(i8* %gep)
24  ret i8* %p
25}
26
27declare void @llvm.experimental.guard(i1,...)
28; Cannot add nonnull attribute to foo
29; because the guard is a throwing call
30define internal i8* @callee_with_throwable(i8* %p) alwaysinline {
31  %r = call i8* @foo(i8* %p)
32  %cond = icmp ne i8* %r, null
33  call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
34  ret i8* %r
35}
36
37declare i8* @bar(i8*) readonly nounwind
38; Here also we cannot add nonnull attribute to the call bar.
39define internal i8* @callee_with_explicit_control_flow(i8* %p) alwaysinline {
40  %r = call i8* @bar(i8* %p)
41  %cond = icmp ne i8* %r, null
42  br i1 %cond, label %ret, label %orig
43
44ret:
45  ret i8* %r
46
47orig:
48  ret i8* %p
49}
50
51define i8* @caller2(i8* %ptr, i64 %x, i1 %cond) {
52; CHECK-LABEL: @caller2(
53; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
54; CHECK-NEXT:    [[R_I:%.*]] = call i8* @foo(i8* [[GEP]])
55; CHECK-NEXT:    [[COND_I:%.*]] = icmp ne i8* [[R_I]], null
56; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_I]]) [ "deopt"() ]
57; CHECK-NEXT:    [[R_I1:%.*]] = call i8* @bar(i8* [[GEP]])
58; CHECK-NEXT:    [[COND_I2:%.*]] = icmp ne i8* [[R_I1]], null
59; CHECK-NEXT:    br i1 [[COND_I2]], label [[RET_I:%.*]], label [[ORIG_I:%.*]]
60; CHECK:       ret.i:
61; CHECK-NEXT:    br label [[CALLEE_WITH_EXPLICIT_CONTROL_FLOW_EXIT:%.*]]
62; CHECK:       orig.i:
63; CHECK-NEXT:    br label [[CALLEE_WITH_EXPLICIT_CONTROL_FLOW_EXIT]]
64; CHECK:       callee_with_explicit_control_flow.exit:
65; CHECK-NEXT:    [[Q3:%.*]] = phi i8* [ [[R_I1]], [[RET_I]] ], [ [[GEP]], [[ORIG_I]] ]
66; CHECK-NEXT:    br i1 [[COND:%.*]], label [[PRET:%.*]], label [[QRET:%.*]]
67; CHECK:       pret:
68; CHECK-NEXT:    ret i8* [[R_I]]
69; CHECK:       qret:
70; CHECK-NEXT:    ret i8* [[Q3]]
71;
72  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
73  %p = call nonnull i8* @callee_with_throwable(i8* %gep)
74  %q = call nonnull i8* @callee_with_explicit_control_flow(i8* %gep)
75  br i1 %cond, label %pret, label %qret
76
77pret:
78  ret i8* %p
79
80qret:
81  ret i8* %q
82}
83
84define internal i8* @callee3(i8 *%p) alwaysinline {
85  %r = call noalias i8* @foo(i8* %p)
86  ret i8* %r
87}
88
89; add the deref attribute to the existing attributes on foo.
90define i8* @caller3(i8* %ptr, i64 %x) {
91; CHECK-LABEL: @caller3(
92; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
93; CHECK-NEXT:    [[R_I:%.*]] = call noalias dereferenceable_or_null(12) i8* @foo(i8* [[GEP]])
94; CHECK-NEXT:    ret i8* [[R_I]]
95;
96  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
97  %p = call dereferenceable_or_null(12) i8* @callee3(i8* %gep)
98  ret i8* %p
99}
100
101declare i8* @inf_loop_call(i8*) nounwind
102; We cannot propagate attributes to foo because we do not know whether inf_loop_call
103; will return execution.
104define internal i8* @callee_with_sideeffect_callsite(i8* %p) alwaysinline {
105  %r = call i8* @foo(i8* %p)
106  %v = call i8* @inf_loop_call(i8* %p)
107  ret i8* %r
108}
109
110; do not add deref attribute to foo
111define i8* @test4(i8* %ptr, i64 %x) {
112; CHECK-LABEL: @test4(
113; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
114; CHECK-NEXT:    [[R_I:%.*]] = call i8* @foo(i8* [[GEP]])
115; CHECK-NEXT:    [[V_I:%.*]] = call i8* @inf_loop_call(i8* [[GEP]])
116; CHECK-NEXT:    ret i8* [[R_I]]
117;
118  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
119  %p = call dereferenceable_or_null(12) i8* @callee_with_sideeffect_callsite(i8* %gep)
120  ret i8* %p
121}
122
123declare i8* @baz(i8*) nounwind readonly
124define internal i8* @callee5(i8* %p) alwaysinline {
125  %r = call i8* @foo(i8* %p)
126  %v = call i8* @baz(i8* %p)
127  ret i8* %r
128}
129
130; add the deref attribute to foo.
131define i8* @test5(i8* %ptr, i64 %x) {
132; CHECK-LABEL: @test5(
133; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
134; CHECK-NEXT:    [[R_I:%.*]] = call dereferenceable_or_null(12) i8* @foo(i8* [[GEP]])
135; CHECK-NEXT:    [[V_I:%.*]] = call i8* @baz(i8* [[GEP]])
136; CHECK-NEXT:    ret i8* [[R_I]]
137;
138  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
139  %s = call dereferenceable_or_null(12) i8* @callee5(i8* %gep)
140  ret i8* %s
141}
142
143; deref attributes have different values on the callee and the call feeding into
144; the return.
145; AttrBuilder chooses the already existing value and does not overwrite it.
146define internal i8* @callee6(i8* %p) alwaysinline {
147  %r = call dereferenceable_or_null(16) i8* @foo(i8* %p)
148  %v = call i8* @baz(i8* %p)
149  ret i8* %r
150}
151
152
153define i8* @test6(i8* %ptr, i64 %x) {
154; CHECK-LABEL: @test6(
155; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
156; CHECK-NEXT:    [[R_I:%.*]] = call dereferenceable_or_null(16) i8* @foo(i8* [[GEP]])
157; CHECK-NEXT:    [[V_I:%.*]] = call i8* @baz(i8* [[GEP]])
158; CHECK-NEXT:    ret i8* [[R_I]]
159;
160  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
161  %s = call dereferenceable_or_null(12) i8* @callee6(i8* %gep)
162  ret i8* %s
163}
164
165; We add the attributes from the callee to both the calls below.
166define internal i8* @callee7(i8 *%ptr, i1 %cond) alwaysinline {
167  br i1 %cond, label %pass, label %fail
168
169pass:
170  %r = call i8* @foo(i8* noalias %ptr)
171  ret i8* %r
172
173fail:
174  %s = call i8* @baz(i8* %ptr)
175  ret i8* %s
176}
177
178define void @test7(i8* %ptr, i64 %x, i1 %cond) {
179; CHECK-LABEL: @test7(
180; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
181; CHECK-NEXT:    br i1 [[COND:%.*]], label [[PASS_I:%.*]], label [[FAIL_I:%.*]]
182; CHECK:       pass.i:
183; CHECK-NEXT:    [[R_I:%.*]] = call nonnull i8* @foo(i8* noalias [[GEP]])
184; CHECK-NEXT:    br label [[CALLEE7_EXIT:%.*]]
185; CHECK:       fail.i:
186; CHECK-NEXT:    [[S_I:%.*]] = call nonnull i8* @baz(i8* [[GEP]])
187; CHECK-NEXT:    br label [[CALLEE7_EXIT]]
188; CHECK:       callee7.exit:
189; CHECK-NEXT:    [[T1:%.*]] = phi i8* [ [[R_I]], [[PASS_I]] ], [ [[S_I]], [[FAIL_I]] ]
190; CHECK-NEXT:    call void @snort(i8* [[T1]])
191; CHECK-NEXT:    ret void
192;
193
194  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
195  %t = call nonnull i8* @callee7(i8* %gep, i1 %cond)
196  call void @snort(i8* %t)
197  ret void
198}
199declare void @snort(i8*)
200
201declare i32 @intrinsic(i8*) nounwind argmemonly
202
203define internal i32 @callee8(i8* %ptr) alwaysinline {
204  %r = call i32 @intrinsic(i8* noalias %ptr)
205  ret i32 %r
206}
207
208
209; signext is an attribute specific to the target ABI and not the
210; callee/callsite.
211; We cannot propagate that attribute to another call since it can be invalid at
212; that call.
213define i32 @test8(i8* %ptr, i64 %x) {
214; CHECK-LABEL: @test8(
215; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, i8* [[PTR:%.*]], i64 [[X:%.*]]
216; CHECK-NEXT:    [[R_I:%.*]] = call i32 @intrinsic(i8* noalias [[GEP]])
217; CHECK-NEXT:    ret i32 [[R_I]]
218;
219
220  %gep = getelementptr inbounds i8, i8* %ptr, i64 %x
221  %t = call signext i32 @callee8(i8* %gep)
222  ret i32 %t
223}
224