328 lines · cpp
1// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \2// RUN: -disable-O0-optnone -Werror -emit-llvm -o - %s \3// RUN: | opt -S -passes=mem2reg \4// RUN: | opt -S -passes=inline \5// RUN: | FileCheck %s6 7extern "C" {8 9extern int normal_callee();10 11// == FUNCTION DECLARATIONS ==12 13int streaming_decl(void) __arm_streaming;14int streaming_compatible_decl(void) __arm_streaming_compatible;15int shared_za_decl(void) __arm_inout("za");16int preserves_za_decl(void) __arm_preserves("za");17int private_za_decl(void);18int agnostic_za_decl(void) __arm_agnostic("sme_za_state");19 20// == FUNCTION DEFINITIONS ==21 22// CHECK-LABEL: @streaming_caller()23// CHECK-SAME: #[[SM_ENABLED:[0-9]+]]24// CHECK: call i32 @normal_callee()25//26 int streaming_caller() __arm_streaming {27 return normal_callee();28}29 30// CHECK: declare i32 @normal_callee() #[[NORMAL_DECL:[0-9]+]]31 32 33// CHECK-LABEL: @streaming_callee()34// CHECK-SAME: #[[SM_ENABLED]]35// CHECK: call i32 @streaming_decl() #[[SM_ENABLED_CALL:[0-9]+]]36//37 int streaming_callee() __arm_streaming {38 return streaming_decl();39}40 41// CHECK: declare i32 @streaming_decl() #[[SM_ENABLED_DECL:[0-9]+]]42 43// CHECK-LABEL: @streaming_compatible_caller()44// CHECK-SAME: #[[SM_COMPATIBLE:[0-9]+]]45// CHECK: call i32 @normal_callee()46//47 int streaming_compatible_caller() __arm_streaming_compatible {48 return normal_callee();49}50 51// CHECK-LABEL: @streaming_compatible_callee()52// CHECK-SAME: #[[SM_COMPATIBLE]]53// CHECK: call i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_CALL:[0-9]+]]54//55 int streaming_compatible_callee() __arm_streaming_compatible {56 return streaming_compatible_decl();57}58 59// CHECK: declare i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_DECL:[0-9]+]]60 61// CHECK-LABEL: @locally_streaming_caller()62// CHECK-SAME: #[[SM_BODY:[0-9]+]]63// CHECK: call i32 @normal_callee()64//65__arm_locally_streaming int locally_streaming_caller() {66 return normal_callee();67}68 69// CHECK-LABEL: @locally_streaming_callee()70// CHECK-SAME: #[[SM_BODY]]71// CHECK: call i32 @locally_streaming_caller() #[[SM_BODY_CALL:[0-9]+]]72//73__arm_locally_streaming int locally_streaming_callee() {74 return locally_streaming_caller();75}76 77 78// CHECK-LABEL: @shared_za_caller()79// CHECK-SAME: #[[ZA_SHARED:[0-9]+]]80// CHECK: call i32 @normal_callee()81//82 int shared_za_caller() __arm_inout("za") {83 return normal_callee();84}85 86// CHECK-LABEL: @shared_za_callee()87// CHECK-SAME: #[[ZA_SHARED]]88// CHECK: call i32 @shared_za_decl() #[[ZA_SHARED_CALL:[0-9]+]]89//90 int shared_za_callee() __arm_inout("za") {91 return shared_za_decl();92}93 94// CHECK: declare i32 @shared_za_decl() #[[ZA_SHARED_DECL:[0-9]+]]95 96 97// CHECK-LABEL: @preserves_za_caller()98// CHECK-SAME: #[[ZA_PRESERVED:[0-9]+]]99// CHECK: call i32 @normal_callee()100//101 int preserves_za_caller() __arm_preserves("za") {102 return normal_callee();103}104 105// CHECK-LABEL: @preserves_za_callee()106// CHECK-SAME: #[[ZA_PRESERVED]]107// CHECK: call i32 @preserves_za_decl() #[[ZA_PRESERVED_CALL:[0-9]+]]108//109 int preserves_za_callee() __arm_preserves("za") {110 return preserves_za_decl();111}112 113// CHECK: declare i32 @preserves_za_decl() #[[ZA_PRESERVED_DECL:[0-9]+]]114 115 116// CHECK-LABEL: @new_za_caller()117// CHECK-SAME: #[[ZA_NEW:[0-9]+]]118// CHECK: call i32 @normal_callee()119//120__arm_new("za") int new_za_caller() {121 return normal_callee();122}123 124// CHECK-LABEL: @new_za_callee()125// CHECK-SAME: #[[ZA_NEW]]126// CHECK: call i32 @private_za_decl()127//128__arm_new("za") int new_za_callee() {129 return private_za_decl();130}131 132// CHECK: declare i32 @private_za_decl()133 134// CHECK-LABEL: @agnostic_za_caller()135// CHECK-SAME: #[[ZA_AGNOSTIC:[0-9]+]]136// CHECK: call i32 @normal_callee()137//138int agnostic_za_caller() __arm_agnostic("sme_za_state") {139 return normal_callee();140}141 142// CHECK-LABEL: @agnostic_za_callee()143// CHECK: call i32 @agnostic_za_decl() #[[ZA_AGNOSTIC_CALL:[0-9]+]]144//145int agnostic_za_callee() {146 return agnostic_za_decl();147}148 149// CHECK-LABEL: @agnostic_za_callee_live_za()150// CHECK: call i32 @agnostic_za_decl() #[[ZA_AGNOSTIC_CALL]]151//152int agnostic_za_callee_live_za() __arm_inout("za") {153 return agnostic_za_decl();154}155 156// Ensure that the attributes are correctly propagated to function types157// and also to callsites.158typedef void (*s_ptrty) (int, int) __arm_streaming;159typedef void (*sc_ptrty) (int, int) __arm_streaming_compatible;160typedef void (*sz_ptrty) (int, int) __arm_inout("za");161typedef void (*pz_ptrty) (int, int) __arm_preserves("za");162 163// CHECK-LABEL: @test_streaming_ptrty(164// CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]165// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]166//167void test_streaming_ptrty(s_ptrty f, int x, int y) { return f(x, y); }168// CHECK-LABEL: @test_streaming_compatible_ptrty(169// CHECK-SAME: #[[NORMAL_DEF]]170// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_COMPATIBLE_CALL]]171//172void test_streaming_compatible_ptrty(sc_ptrty f, int x, int y) { return f(x, y); }173// CHECK-LABEL: @test_shared_za(174// CHECK-SAME: #[[ZA_SHARED]]175// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_SHARED_CALL]]176//177void test_shared_za(sz_ptrty f, int x, int y) __arm_inout("za") { return f(x, y); }178// CHECK-LABEL: @test_preserved_za(179// CHECK-SAME: #[[ZA_SHARED]]180// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_PRESERVED_CALL]]181//182void test_preserved_za(pz_ptrty f, int x, int y) __arm_inout("za") { return f(x, y); }183 184// CHECK-LABEL: @test_indirect_streaming_ptrty(185// CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]186// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]187//188typedef s_ptrty **indirect_s_ptrty;189void test_indirect_streaming_ptrty(indirect_s_ptrty fptr, int x, int y) { return (**fptr)(x, y); }190} // extern "C"191 192//193// Test that having the attribute in different places (on declaration and on type)194// both results in the attribute being applied to the type.195//196 197// CHECK-LABEL: @_Z24test_same_type_streamingv(198// CHECK: call void @_Z10streaming1v() #[[SM_ENABLED_CALL]]199// CHECK: call void @_Z10streaming2v() #[[SM_ENABLED_CALL]]200// CHECK: call void @_Z20same_type_streaming1v() #[[SM_ENABLED_CALL]]201// CHECK: call void @_Z20same_type_streaming2v() #[[SM_ENABLED_CALL]]202// CHECK: ret void203// CHECK: }204// CHECK: declare void @_Z10streaming1v() #[[SM_ENABLED_DECL]]205// CHECK: declare void @_Z10streaming2v() #[[SM_ENABLED_DECL]]206// CHECK: declare void @_Z20same_type_streaming1v() #[[SM_ENABLED_DECL]]207// CHECK: declare void @_Z20same_type_streaming2v() #[[SM_ENABLED_DECL]]208void streaming1(void) __arm_streaming;209void streaming2() __arm_streaming;210decltype(streaming1) same_type_streaming1;211decltype(streaming2) same_type_streaming2;212void test_same_type_streaming() {213 streaming1();214 streaming2();215 same_type_streaming1();216 same_type_streaming2();217}218 219//220// Test overloading; the attribute is not required for overloaded types and221// does not apply if not specified.222//223 224// CHECK-LABEL: @_Z12overloadedfni(225// CHECK-SAME: #[[SM_ENABLED]]226int overloadedfn(int x) __arm_streaming { return x; }227// CHECK-LABEL: @_Z12overloadedfnf(228// CHECK-SAME: #[[NORMAL_DEF]]229//230float overloadedfn(float x) { return x; }231// CHECK-LABEL: @_Z13test_overloadi(232// CHECK-SAME: #[[NORMAL_DEF]]233//234int test_overload(int x) { return overloadedfn(x); }235// CHECK-LABEL: @_Z13test_overloadf(236// CHECK-SAME: #[[NORMAL_DEF]]237//238float test_overload(float x) { return overloadedfn(x); }239 240// CHECK-LABEL: @_Z11test_lambdai(241// CHECK-SAME: #[[NORMAL_DEF]]242// CHECK: call noundef i32 @"_ZZ11test_lambdaiENK3$_0clEi"({{.*}}) #[[SM_ENABLED_CALL]]243//244// CHECK: @"_ZZ11test_lambdaiENK3$_0clEi"(245// CHECK-SAME: #[[SM_ENABLED]]246int test_lambda(int x) {247 auto F = [](int x) __arm_streaming { return x; };248 return F(x);249}250 251// CHECK-LABEL: @_Z27test_template_instantiationv(252// CHECK-SAME: #[[NORMAL_DEF]]253// CHECK: call noundef i32 @_Z15template_functyIiET_S0_(i32 noundef 12) #[[SM_ENABLED_CALL]]254//255// CHECK: @_Z15template_functyIiET_S0_(256// CHECK-SAME: #[[SM_ENABLED]]257template <typename Ty>258Ty template_functy(Ty x) __arm_streaming { return x; }259int test_template_instantiation() { return template_functy(12); }260 261//262// Test that arm_locally_streaming is inherited by future redeclarations,263// even when they don't specify the attribute.264//265 266// CHECK: define {{.*}} @_Z25locally_streaming_inheritv(267// CHECK-SAME: #[[SM_BODY]]268__arm_locally_streaming void locally_streaming_inherit();269void locally_streaming_inherit() {270 streaming_decl();271}272 273// Test that the attributes are propagated properly to calls274// when using a variadic template as indirection.275__attribute__((always_inline))276int call() { return 0; }277 278template <typename T, typename... Other>279__attribute__((always_inline))280int call(T f, Other... other) __arm_inout("za") {281 return f() + call(other...);282}283 284// CHECK: {{.*}} @_Z22test_variadic_templatev(285// CHECK: call {{.*}} i32 @normal_callee() #[[NOUNWIND_CALL:[0-9]+]]286// CHECK-NEXT: call {{.*}} i32 @streaming_decl() #[[NOUNWIND_SM_ENABLED_CALL:[0-9]+]]287// CHECK-NEXT: call {{.*}} i32 @streaming_compatible_decl() #[[NOUNWIND_SM_COMPATIBLE_CALL:[0-9]+]]288// CHECK-NEXT: call {{.*}} i32 @shared_za_decl() #[[NOUNWIND_ZA_SHARED_CALL:[0-9]+]]289// CHECK-NEXT: call {{.*}} i32 @preserves_za_decl() #[[NOUNWIND_ZA_PRESERVED_CALL:[0-9]+]]290// CHECK-NEXT: add nsw291// CHECK-NEXT: add nsw292// CHECK-NEXT: add nsw293// CHECK-NEXT: add nsw294// CHECK-NEXT: ret295int test_variadic_template() __arm_inout("za") {296 return call(normal_callee,297 streaming_decl,298 streaming_compatible_decl,299 shared_za_decl,300 preserves_za_decl);301}302 303// CHECK: attributes #[[SM_ENABLED]] = { mustprogress noinline nounwind vscale_range(1,16) "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }304// CHECK: attributes #[[NORMAL_DECL]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }305// CHECK: attributes #[[SM_ENABLED_DECL]] = { "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }306// CHECK: attributes #[[SM_COMPATIBLE]] = { mustprogress noinline nounwind "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }307// CHECK: attributes #[[SM_COMPATIBLE_DECL]] = { "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }308// CHECK: attributes #[[SM_BODY]] = { mustprogress noinline nounwind vscale_range(1,16) "aarch64_pstate_sm_body" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }309// CHECK: attributes #[[ZA_SHARED]] = { mustprogress noinline nounwind "aarch64_inout_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }310// CHECK: attributes #[[ZA_SHARED_DECL]] = { "aarch64_inout_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }311// CHECK: attributes #[[ZA_PRESERVED]] = { mustprogress noinline nounwind "aarch64_preserves_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }312// CHECK: attributes #[[ZA_PRESERVED_DECL]] = { "aarch64_preserves_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }313// CHECK: attributes #[[ZA_NEW]] = { mustprogress noinline nounwind "aarch64_new_za" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }314// CHECK: attributes #[[ZA_AGNOSTIC]] = { mustprogress noinline nounwind "aarch64_za_state_agnostic" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }315// CHECK: attributes #[[NORMAL_DEF]] = { mustprogress noinline nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sme" }316// CHECK: attributes #[[SM_ENABLED_CALL]] = { "aarch64_pstate_sm_enabled" }317// CHECK: attributes #[[SM_COMPATIBLE_CALL]] = { "aarch64_pstate_sm_compatible" }318// CHECK: attributes #[[SM_BODY_CALL]] = { "aarch64_pstate_sm_body" }319// CHECK: attributes #[[ZA_SHARED_CALL]] = { "aarch64_inout_za" }320// CHECK: attributes #[[ZA_PRESERVED_CALL]] = { "aarch64_preserves_za" }321// CHECK: attributes #[[ZA_AGNOSTIC_CALL]] = { "aarch64_za_state_agnostic" }322// CHECK: attributes #[[NOUNWIND_CALL]] = { nounwind }323// CHECK: attributes #[[NOUNWIND_SM_ENABLED_CALL]] = { nounwind "aarch64_pstate_sm_enabled" }324// CHECK: attributes #[[NOUNWIND_SM_COMPATIBLE_CALL]] = { nounwind "aarch64_pstate_sm_compatible" }325// CHECK: attributes #[[NOUNWIND_ZA_SHARED_CALL]] = { nounwind "aarch64_inout_za" }326// CHECK: attributes #[[NOUNWIND_ZA_PRESERVED_CALL]] = { nounwind "aarch64_preserves_za" }327 328