1 // RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +bf16 \
2 // RUN: -disable-O0-optnone -Werror -emit-llvm -o - %s \
3 // RUN: | opt -S -passes=mem2reg \
4 // RUN: | opt -S -passes=inline \
9 extern int normal_callee();
11 // == FUNCTION DECLARATIONS ==
13 int streaming_decl(void) __arm_streaming
;
14 int streaming_compatible_decl(void) __arm_streaming_compatible
;
15 int shared_za_decl(void) __arm_inout("za");
16 int preserves_za_decl(void) __arm_preserves("za");
17 int private_za_decl(void);
19 // == FUNCTION DEFINITIONS ==
21 // CHECK-LABEL: @streaming_caller()
22 // CHECK-SAME: #[[SM_ENABLED:[0-9]+]]
23 // CHECK: call i32 @normal_callee()
25 int streaming_caller() __arm_streaming
{
26 return normal_callee();
29 // CHECK: declare i32 @normal_callee() #[[NORMAL_DECL:[0-9]+]]
32 // CHECK-LABEL: @streaming_callee()
33 // CHECK-SAME: #[[SM_ENABLED]]
34 // CHECK: call i32 @streaming_decl() #[[SM_ENABLED_CALL:[0-9]+]]
36 int streaming_callee() __arm_streaming
{
37 return streaming_decl();
40 // CHECK: declare i32 @streaming_decl() #[[SM_ENABLED_DECL:[0-9]+]]
42 // CHECK-LABEL: @streaming_compatible_caller()
43 // CHECK-SAME: #[[SM_COMPATIBLE:[0-9]+]]
44 // CHECK: call i32 @normal_callee()
46 int streaming_compatible_caller() __arm_streaming_compatible
{
47 return normal_callee();
50 // CHECK-LABEL: @streaming_compatible_callee()
51 // CHECK-SAME: #[[SM_COMPATIBLE]]
52 // CHECK: call i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_CALL:[0-9]+]]
54 int streaming_compatible_callee() __arm_streaming_compatible
{
55 return streaming_compatible_decl();
58 // CHECK: declare i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_DECL:[0-9]+]]
60 // CHECK-LABEL: @locally_streaming_caller()
61 // CHECK-SAME: #[[SM_BODY:[0-9]+]]
62 // CHECK: call i32 @normal_callee()
64 __arm_locally_streaming
int locally_streaming_caller() {
65 return normal_callee();
68 // CHECK-LABEL: @locally_streaming_callee()
69 // CHECK-SAME: #[[SM_BODY]]
70 // CHECK: call i32 @locally_streaming_caller() #[[SM_BODY_CALL:[0-9]+]]
72 __arm_locally_streaming
int locally_streaming_callee() {
73 return locally_streaming_caller();
77 // CHECK-LABEL: @shared_za_caller()
78 // CHECK-SAME: #[[ZA_SHARED:[0-9]+]]
79 // CHECK: call i32 @normal_callee()
81 int shared_za_caller() __arm_inout("za") {
82 return normal_callee();
85 // CHECK-LABEL: @shared_za_callee()
86 // CHECK-SAME: #[[ZA_SHARED]]
87 // CHECK: call i32 @shared_za_decl() #[[ZA_SHARED_CALL:[0-9]+]]
89 int shared_za_callee() __arm_inout("za") {
90 return shared_za_decl();
93 // CHECK: declare i32 @shared_za_decl() #[[ZA_SHARED_DECL:[0-9]+]]
96 // CHECK-LABEL: @preserves_za_caller()
97 // CHECK-SAME: #[[ZA_PRESERVED:[0-9]+]]
98 // CHECK: call i32 @normal_callee()
100 int preserves_za_caller() __arm_preserves("za") {
101 return normal_callee();
104 // CHECK-LABEL: @preserves_za_callee()
105 // CHECK-SAME: #[[ZA_PRESERVED]]
106 // CHECK: call i32 @preserves_za_decl() #[[ZA_PRESERVED_CALL:[0-9]+]]
108 int preserves_za_callee() __arm_preserves("za") {
109 return preserves_za_decl();
112 // CHECK: declare i32 @preserves_za_decl() #[[ZA_PRESERVED_DECL:[0-9]+]]
115 // CHECK-LABEL: @new_za_caller()
116 // CHECK-SAME: #[[ZA_NEW:[0-9]+]]
117 // CHECK: call i32 @normal_callee()
119 __arm_new("za") int new_za_caller() {
120 return normal_callee();
123 // CHECK-LABEL: @new_za_callee()
124 // CHECK-SAME: #[[ZA_NEW]]
125 // CHECK: call i32 @private_za_decl()
127 __arm_new("za") int new_za_callee() {
128 return private_za_decl();
131 // CHECK: declare i32 @private_za_decl()
134 // Ensure that the attributes are correctly propagated to function types
135 // and also to callsites.
136 typedef void (*s_ptrty
) (int, int) __arm_streaming
;
137 typedef void (*sc_ptrty
) (int, int) __arm_streaming_compatible
;
138 typedef void (*sz_ptrty
) (int, int) __arm_inout("za");
139 typedef void (*pz_ptrty
) (int, int) __arm_preserves("za");
141 // CHECK-LABEL: @test_streaming_ptrty(
142 // CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]
143 // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]
145 void test_streaming_ptrty(s_ptrty f
, int x
, int y
) { return f(x
, y
); }
146 // CHECK-LABEL: @test_streaming_compatible_ptrty(
147 // CHECK-SAME: #[[NORMAL_DEF]]
148 // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_COMPATIBLE_CALL]]
150 void test_streaming_compatible_ptrty(sc_ptrty f
, int x
, int y
) { return f(x
, y
); }
151 // CHECK-LABEL: @test_shared_za(
152 // CHECK-SAME: #[[ZA_SHARED]]
153 // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_SHARED_CALL]]
155 void test_shared_za(sz_ptrty f
, int x
, int y
) __arm_inout("za") { return f(x
, y
); }
156 // CHECK-LABEL: @test_preserved_za(
157 // CHECK-SAME: #[[ZA_SHARED]]
158 // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_PRESERVED_CALL]]
160 void test_preserved_za(pz_ptrty f
, int x
, int y
) __arm_inout("za") { return f(x
, y
); }
162 // CHECK-LABEL: @test_indirect_streaming_ptrty(
163 // CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]
164 // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]
166 typedef s_ptrty
**indirect_s_ptrty
;
167 void test_indirect_streaming_ptrty(indirect_s_ptrty fptr
, int x
, int y
) { return (**fptr
)(x
, y
); }
171 // Test that having the attribute in different places (on declaration and on type)
172 // both results in the attribute being applied to the type.
175 // CHECK-LABEL: @_Z24test_same_type_streamingv(
176 // CHECK: call void @_Z10streaming1v() #[[SM_ENABLED_CALL]]
177 // CHECK: call void @_Z10streaming2v() #[[SM_ENABLED_CALL]]
178 // CHECK: call void @_Z20same_type_streaming1v() #[[SM_ENABLED_CALL]]
179 // CHECK: call void @_Z20same_type_streaming2v() #[[SM_ENABLED_CALL]]
182 // CHECK: declare void @_Z10streaming1v() #[[SM_ENABLED_DECL]]
183 // CHECK: declare void @_Z10streaming2v() #[[SM_ENABLED_DECL]]
184 // CHECK: declare void @_Z20same_type_streaming1v() #[[SM_ENABLED_DECL]]
185 // CHECK: declare void @_Z20same_type_streaming2v() #[[SM_ENABLED_DECL]]
186 void streaming1(void) __arm_streaming
;
187 void streaming2() __arm_streaming
;
188 decltype(streaming1
) same_type_streaming1
;
189 decltype(streaming2
) same_type_streaming2
;
190 void test_same_type_streaming() {
193 same_type_streaming1();
194 same_type_streaming2();
198 // Test overloading; the attribute is not required for overloaded types and
199 // does not apply if not specified.
202 // CHECK-LABEL: @_Z12overloadedfni(
203 // CHECK-SAME: #[[SM_ENABLED]]
204 int overloadedfn(int x
) __arm_streaming
{ return x
; }
205 // CHECK-LABEL: @_Z12overloadedfnf(
206 // CHECK-SAME: #[[NORMAL_DEF]]
208 float overloadedfn(float x
) { return x
; }
209 // CHECK-LABEL: @_Z13test_overloadi(
210 // CHECK-SAME: #[[NORMAL_DEF]]
212 int test_overload(int x
) { return overloadedfn(x
); }
213 // CHECK-LABEL: @_Z13test_overloadf(
214 // CHECK-SAME: #[[NORMAL_DEF]]
216 float test_overload(float x
) { return overloadedfn(x
); }
218 // CHECK-LABEL: @_Z11test_lambdai(
219 // CHECK-SAME: #[[NORMAL_DEF]]
220 // CHECK: call noundef i32 @"_ZZ11test_lambdaiENK3$_0clEi"({{.*}}) #[[SM_ENABLED_CALL]]
222 // CHECK: @"_ZZ11test_lambdaiENK3$_0clEi"(
223 // CHECK-SAME: #[[SM_ENABLED]]
224 int test_lambda(int x
) {
225 auto F
= [](int x
) __arm_streaming
{ return x
; };
229 // CHECK-LABEL: @_Z27test_template_instantiationv(
230 // CHECK-SAME: #[[NORMAL_DEF]]
231 // CHECK: call noundef i32 @_Z15template_functyIiET_S0_(i32 noundef 12) #[[SM_ENABLED_CALL]]
233 // CHECK: @_Z15template_functyIiET_S0_(
234 // CHECK-SAME: #[[SM_ENABLED]]
235 template <typename Ty
>
236 Ty
template_functy(Ty x
) __arm_streaming
{ return x
; }
237 int test_template_instantiation() { return template_functy(12); }
240 // Test that arm_locally_streaming is inherited by future redeclarations,
241 // even when they don't specify the attribute.
244 // CHECK: define {{.*}} @_Z25locally_streaming_inheritv(
245 // CHECK-SAME: #[[SM_BODY]]
246 __arm_locally_streaming
void locally_streaming_inherit();
247 void locally_streaming_inherit() {
251 // Test that the attributes are propagated properly to calls
252 // when using a variadic template as indirection.
253 __attribute__((always_inline
))
254 int call() { return 0; }
256 template <typename T
, typename
... Other
>
257 __attribute__((always_inline
))
258 int call(T f
, Other
... other
) __arm_inout("za") {
259 return f() + call(other
...);
262 // CHECK: {{.*}} @_Z22test_variadic_templatev(
263 // CHECK: call {{.*}} i32 @normal_callee() #[[NOUNWIND_CALL:[0-9]+]]
264 // CHECK-NEXT: call {{.*}} i32 @streaming_decl() #[[NOUNWIND_SM_ENABLED_CALL:[0-9]+]]
265 // CHECK-NEXT: call {{.*}} i32 @streaming_compatible_decl() #[[NOUNWIND_SM_COMPATIBLE_CALL:[0-9]+]]
266 // CHECK-NEXT: call {{.*}} i32 @shared_za_decl() #[[NOUNWIND_ZA_SHARED_CALL:[0-9]+]]
267 // CHECK-NEXT: call {{.*}} i32 @preserves_za_decl() #[[NOUNWIND_ZA_PRESERVED_CALL:[0-9]+]]
268 // CHECK-NEXT: add nsw
269 // CHECK-NEXT: add nsw
270 // CHECK-NEXT: add nsw
271 // CHECK-NEXT: add nsw
273 int test_variadic_template() __arm_inout("za") {
274 return call(normal_callee
,
276 streaming_compatible_decl
,
281 // CHECK: attributes #[[SM_ENABLED]] = { mustprogress noinline nounwind "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
282 // CHECK: attributes #[[NORMAL_DECL]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
283 // CHECK: attributes #[[SM_ENABLED_DECL]] = { "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
284 // CHECK: attributes #[[SM_COMPATIBLE]] = { mustprogress noinline nounwind "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
285 // CHECK: attributes #[[SM_COMPATIBLE_DECL]] = { "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
286 // CHECK: attributes #[[SM_BODY]] = { mustprogress noinline nounwind "aarch64_pstate_sm_body" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
287 // CHECK: attributes #[[ZA_SHARED]] = { mustprogress noinline nounwind "aarch64_inout_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
288 // CHECK: attributes #[[ZA_SHARED_DECL]] = { "aarch64_inout_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
289 // CHECK: attributes #[[ZA_PRESERVED]] = { mustprogress noinline nounwind "aarch64_preserves_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
290 // CHECK: attributes #[[ZA_PRESERVED_DECL]] = { "aarch64_preserves_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
291 // CHECK: attributes #[[ZA_NEW]] = { mustprogress noinline nounwind "aarch64_new_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
292 // CHECK: attributes #[[NORMAL_DEF]] = { mustprogress noinline nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
293 // CHECK: attributes #[[SM_ENABLED_CALL]] = { "aarch64_pstate_sm_enabled" }
294 // CHECK: attributes #[[SM_COMPATIBLE_CALL]] = { "aarch64_pstate_sm_compatible" }
295 // CHECK: attributes #[[SM_BODY_CALL]] = { "aarch64_pstate_sm_body" }
296 // CHECK: attributes #[[ZA_SHARED_CALL]] = { "aarch64_inout_za" }
297 // CHECK: attributes #[[ZA_PRESERVED_CALL]] = { "aarch64_preserves_za" }
298 // CHECK: attributes #[[NOUNWIND_CALL]] = { nounwind }
299 // CHECK: attributes #[[NOUNWIND_SM_ENABLED_CALL]] = { nounwind "aarch64_pstate_sm_enabled" }
300 // CHECK: attributes #[[NOUNWIND_SM_COMPATIBLE_CALL]] = { nounwind "aarch64_pstate_sm_compatible" }
301 // CHECK: attributes #[[NOUNWIND_ZA_SHARED_CALL]] = { nounwind "aarch64_inout_za" }
302 // CHECK: attributes #[[NOUNWIND_ZA_PRESERVED_CALL]] = { nounwind "aarch64_preserves_za" }