Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / Inline / ret_attr_update.ll
blob7004b5795125d14207487d03c5bb6323e114c1fe
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -inline-threshold=0 -passes=always-inline -S | FileCheck %s
3 ; RUN: opt < %s -passes=always-inline -S | FileCheck %s
5 declare ptr @foo(ptr) nounwind willreturn
7 define ptr @callee(ptr %p) alwaysinline {
8 ; CHECK-LABEL: @callee(
9 ; CHECK-NEXT:    [[R:%.*]] = call ptr @foo(ptr noalias [[P:%.*]])
10 ; CHECK-NEXT:    ret ptr [[R]]
12   %r = call ptr @foo(ptr noalias %p)
13   ret ptr %r
16 define ptr @caller(ptr %ptr, i64 %x) {
17 ; CHECK-LABEL: @caller(
18 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
19 ; CHECK-NEXT:    [[R_I:%.*]] = call nonnull ptr @foo(ptr noalias [[GEP]])
20 ; CHECK-NEXT:    ret ptr [[R_I]]
22   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
23   %p = call nonnull ptr @callee(ptr %gep)
24   ret ptr %p
27 declare void @llvm.experimental.guard(i1,...)
28 ; Cannot add nonnull attribute to foo
29 ; because the guard is a throwing call
30 define internal ptr @callee_with_throwable(ptr %p) alwaysinline {
31   %r = call ptr @foo(ptr %p)
32   %cond = icmp ne ptr %r, null
33   call void (i1, ...) @llvm.experimental.guard(i1 %cond) [ "deopt"() ]
34   ret ptr %r
37 declare ptr @bar(ptr) readonly nounwind
38 ; Here also we cannot add nonnull attribute to the call bar.
39 define internal ptr @callee_with_explicit_control_flow(ptr %p) alwaysinline {
40   %r = call ptr @bar(ptr %p)
41   %cond = icmp ne ptr %r, null
42   br i1 %cond, label %ret, label %orig
44 ret:
45   ret ptr %r
47 orig:
48   ret ptr %p
51 define ptr @caller2(ptr %ptr, i64 %x, i1 %cond) {
52 ; CHECK-LABEL: @caller2(
53 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
54 ; CHECK-NEXT:    [[R_I:%.*]] = call ptr @foo(ptr [[GEP]])
55 ; CHECK-NEXT:    [[COND_I:%.*]] = icmp ne ptr [[R_I]], null
56 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[COND_I]]) [ "deopt"() ]
57 ; CHECK-NEXT:    [[R_I1:%.*]] = call ptr @bar(ptr [[GEP]])
58 ; CHECK-NEXT:    [[COND_I2:%.*]] = icmp ne ptr [[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 ptr [ [[R_I1]], [[RET_I]] ], [ [[GEP]], [[ORIG_I]] ]
66 ; CHECK-NEXT:    br i1 [[COND:%.*]], label [[PRET:%.*]], label [[QRET:%.*]]
67 ; CHECK:       pret:
68 ; CHECK-NEXT:    ret ptr [[R_I]]
69 ; CHECK:       qret:
70 ; CHECK-NEXT:    ret ptr [[Q3]]
72   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
73   %p = call nonnull ptr @callee_with_throwable(ptr %gep)
74   %q = call nonnull ptr @callee_with_explicit_control_flow(ptr %gep)
75   br i1 %cond, label %pret, label %qret
77 pret:
78   ret ptr %p
80 qret:
81   ret ptr %q
84 define internal ptr @callee3(ptr %p) alwaysinline {
85   %r = call noalias ptr @foo(ptr %p)
86   ret ptr %r
89 ; add the deref attribute to the existing attributes on foo.
90 define ptr @caller3(ptr %ptr, i64 %x) {
91 ; CHECK-LABEL: @caller3(
92 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
93 ; CHECK-NEXT:    [[R_I:%.*]] = call noalias dereferenceable_or_null(12) ptr @foo(ptr [[GEP]])
94 ; CHECK-NEXT:    ret ptr [[R_I]]
96   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
97   %p = call dereferenceable_or_null(12) ptr @callee3(ptr %gep)
98   ret ptr %p
101 declare ptr @inf_loop_call(ptr) nounwind
102 ; We cannot propagate attributes to foo because we do not know whether inf_loop_call
103 ; will return execution.
104 define internal ptr @callee_with_sideeffect_callsite(ptr %p) alwaysinline {
105   %r = call ptr @foo(ptr %p)
106   %v = call ptr @inf_loop_call(ptr %p)
107   ret ptr %r
110 ; do not add deref attribute to foo
111 define ptr @test4(ptr %ptr, i64 %x) {
112 ; CHECK-LABEL: @test4(
113 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
114 ; CHECK-NEXT:    [[R_I:%.*]] = call ptr @foo(ptr [[GEP]])
115 ; CHECK-NEXT:    [[V_I:%.*]] = call ptr @inf_loop_call(ptr [[GEP]])
116 ; CHECK-NEXT:    ret ptr [[R_I]]
118   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
119   %p = call dereferenceable_or_null(12) ptr @callee_with_sideeffect_callsite(ptr %gep)
120   ret ptr %p
123 declare ptr @baz(ptr) nounwind willreturn
124 define internal ptr @callee5(ptr %p) alwaysinline {
125   %r = call ptr @foo(ptr %p)
126   %v = call ptr @baz(ptr %p)
127   ret ptr %r
130 ; add the deref attribute to foo.
131 define ptr @test5(ptr %ptr, i64 %x) {
132 ; CHECK-LABEL: @test5(
133 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
134 ; CHECK-NEXT:    [[R_I:%.*]] = call dereferenceable_or_null(12) ptr @foo(ptr [[GEP]])
135 ; CHECK-NEXT:    [[V_I:%.*]] = call ptr @baz(ptr [[GEP]])
136 ; CHECK-NEXT:    ret ptr [[R_I]]
138   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
139   %s = call dereferenceable_or_null(12) ptr @callee5(ptr %gep)
140   ret ptr %s
143 ; deref attributes have different values on the callee and the call feeding into
144 ; the return.
145 ; AttrBuilder overwrites the existing value.
146 define internal ptr @callee6(ptr %p) alwaysinline {
147   %r = call dereferenceable_or_null(16) ptr @foo(ptr %p)
148   %v = call ptr @baz(ptr %p)
149   ret ptr %r
153 define ptr @test6(ptr %ptr, i64 %x) {
154 ; CHECK-LABEL: @test6(
155 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
156 ; CHECK-NEXT:    [[R_I:%.*]] = call dereferenceable_or_null(16) ptr @foo(ptr [[GEP]])
157 ; CHECK-NEXT:    [[V_I:%.*]] = call ptr @baz(ptr [[GEP]])
158 ; CHECK-NEXT:    ret ptr [[R_I]]
160   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
161   %s = call dereferenceable_or_null(12) ptr @callee6(ptr %gep)
162   ret ptr %s
165 ; We add the attributes from the callee to both the calls below.
166 define internal ptr @callee7(ptr %ptr, i1 %cond) alwaysinline {
167   br i1 %cond, label %pass, label %fail
169 pass:
170   %r = call ptr @foo(ptr noalias %ptr)
171   ret ptr %r
173 fail:
174   %s = call ptr @baz(ptr %ptr)
175   ret ptr %s
178 define void @test7(ptr %ptr, i64 %x, i1 %cond) {
179 ; CHECK-LABEL: @test7(
180 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[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 ptr @foo(ptr noalias [[GEP]])
184 ; CHECK-NEXT:    br label [[CALLEE7_EXIT:%.*]]
185 ; CHECK:       fail.i:
186 ; CHECK-NEXT:    [[S_I:%.*]] = call nonnull ptr @baz(ptr [[GEP]])
187 ; CHECK-NEXT:    br label [[CALLEE7_EXIT]]
188 ; CHECK:       callee7.exit:
189 ; CHECK-NEXT:    [[T1:%.*]] = phi ptr [ [[R_I]], [[PASS_I]] ], [ [[S_I]], [[FAIL_I]] ]
190 ; CHECK-NEXT:    call void @snort(ptr [[T1]])
191 ; CHECK-NEXT:    ret void
194   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
195   %t = call nonnull ptr @callee7(ptr %gep, i1 %cond)
196   call void @snort(ptr %t)
197   ret void
199 declare void @snort(ptr)
201 declare i32 @intrinsic(ptr) nounwind argmemonly
203 define internal i32 @callee8(ptr %ptr) alwaysinline {
204   %r = call i32 @intrinsic(ptr noalias %ptr)
205   ret i32 %r
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.
213 define i32 @test8(ptr %ptr, i64 %x) {
214 ; CHECK-LABEL: @test8(
215 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i64 [[X:%.*]]
216 ; CHECK-NEXT:    [[R_I:%.*]] = call i32 @intrinsic(ptr noalias [[GEP]])
217 ; CHECK-NEXT:    ret i32 [[R_I]]
220   %gep = getelementptr inbounds i8, ptr %ptr, i64 %x
221   %t = call signext i32 @callee8(ptr %gep)
222   ret i32 %t