sdesmalen updated this revision to Diff 528366.
sdesmalen retitled this revision from "[Clang][AArch64] Add ACLE attributes for
SME." to "[Clang][AArch64] Add/implement ACLE keywords for SME.".
sdesmalen edited the summary of this revision.
sdesmalen added a comment.
- Rebased patch after patch to add RegularKeyword attributes (D148702
<https://reviews.llvm.org/D148702>) landed
- Split off the request to reduce the size of FunctionTypeExtraBitfields (and
use alignment of the struct to pointer type) to a new patch: D152140
<https://reviews.llvm.org/D152140>
- Added test to ensure that the serialization of type attributes is
exported/imported to/from modules, see
clang/test/Modules/aarch64-sme-keywords.cppm
- Added some new tests for template instantiation and function overloading with
SME attributes:
void normal_func(void) {}
void streaming_func(void) __arm_streaming {}
template<typename T> int test_templated_f(T);
template<> constexpr int test_templated_f<void(*)(void)>(void(*)(void)) {
return 1; }
template<> constexpr int
test_templated_f<void(*)(void)__arm_streaming>(void(*)(void)__arm_streaming) {
return 2; }
static_assert(test_templated_f(&normal_func) == 1, "Instantiated to wrong
function");
static_assert(test_templated_f(&streaming_func) == 2, "Instantiated to wrong
function");
and
// expected-cpp-error@+2 {{'__arm_streaming' only applies to function types;
type here is 'int'}}
// expected-error@+1 {{'__arm_streaming' only applies to function types; type
here is 'int'}}
int invalid_type_for_attribute __arm_streaming;
// Test overloads
constexpr int overload(void f(void)) { return 1; }
constexpr int overload(void f(void) __arm_streaming) { return 2; }
static_assert(overload(&normal_func) == 1, "Overloaded to wrong function");
static_assert(overload(&streaming_func) == 2, "Overloaded to wrong function");
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D127762/new/
https://reviews.llvm.org/D127762
Files:
clang/include/clang/AST/Type.h
clang/include/clang/AST/TypeProperties.td
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/AST/Type.cpp
clang/lib/AST/TypePrinter.cpp
clang/lib/CodeGen/CGCall.cpp
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Sema/SemaType.cpp
clang/test/AST/ast-dump-sme-attributes.cpp
clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp
clang/test/Modules/aarch64-sme-keywords.cppm
clang/test/Sema/aarch64-sme-func-attrs.c
Index: clang/test/Sema/aarch64-sme-func-attrs.c
===================================================================
--- /dev/null
+++ clang/test/Sema/aarch64-sme-func-attrs.c
@@ -0,0 +1,229 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -fsyntax-only -verify=expected-cpp -x c++ %s
+
+// Valid attributes
+
+void sme_arm_streaming(void) __arm_streaming;
+void sme_arm_streaming_compatible(void) __arm_streaming_compatible;
+
+__arm_new_za void sme_arm_new_za(void) {}
+void sme_arm_shared_za(void) __arm_shared_za;
+void sme_arm_preserves_za(void) __arm_preserves_za;
+
+__arm_new_za void sme_arm_streaming_new_za(void) __arm_streaming {}
+void sme_arm_streaming_shared_za(void) __arm_streaming __arm_shared_za;
+void sme_arm_streaming_preserves_za(void) __arm_streaming __arm_preserves_za;
+
+__arm_new_za void sme_arm_sc_new_za(void) __arm_streaming_compatible {}
+void sme_arm_sc_shared_za(void) __arm_streaming_compatible __arm_shared_za;
+void sme_arm_sc_preserves_za(void) __arm_streaming_compatible __arm_preserves_za;
+
+void sme_arm_shared_preserves_za(void) __arm_shared_za __arm_preserves_za;
+
+__arm_locally_streaming void sme_arm_locally_streaming(void) { }
+__arm_locally_streaming void sme_arm_streaming_and_locally_streaming(void) __arm_streaming { }
+__arm_locally_streaming void sme_arm_streaming_and_streaming_compatible(void) __arm_streaming_compatible { }
+
+__arm_locally_streaming __arm_new_za void sme_arm_ls_new_za(void) { }
+__arm_locally_streaming void sme_arm_ls_shared_za(void) __arm_shared_za { }
+__arm_locally_streaming void sme_arm_ls_preserves_za(void) __arm_preserves_za { }
+
+// Valid attributes on function pointers
+
+void streaming_ptr(void) __arm_streaming;
+typedef void (*fptrty1) (void) __arm_streaming;
+fptrty1 call_streaming_func() { return streaming_ptr; }
+
+void streaming_compatible_ptr(void) __arm_streaming_compatible;
+typedef void (*fptrty2) (void) __arm_streaming_compatible;
+fptrty2 call_sc_func() { return streaming_compatible_ptr; }
+
+void shared_za_ptr(void) __arm_shared_za;
+typedef void (*fptrty3) (void) __arm_shared_za;
+fptrty3 call_shared_za_func() { return shared_za_ptr; }
+
+void preserves_za_ptr(void) __arm_preserves_za;
+typedef void (*fptrty4) (void) __arm_preserves_za;
+fptrty4 call_preserve_za_func() { return preserves_za_ptr; }
+
+void shared_preserves_za_ptr(void) __arm_shared_za __arm_preserves_za;
+typedef void (*fptrty5) (void) __arm_shared_za __arm_preserves_za;
+fptrty5 call_shared_preserve_za_func() { return shared_preserves_za_ptr; }
+
+typedef void (*fptrty6) (void);
+fptrty6 cast_nza_func_to_normal() { return sme_arm_new_za; }
+fptrty6 cast_ls_func_to_normal() { return sme_arm_locally_streaming; }
+
+// FIXME: Add invalid function pointer assignments such as assigning:
+// 1. A streaming compatible function to a normal function pointer,
+// 2. A locally streaming function to a streaming function pointer,
+// etc.
+
+// Invalid attributes
+
+// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
+// expected-cpp-note@+3 {{conflicting attribute is here}}
+// expected-error@+2 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
+// expected-note@+1 {{conflicting attribute is here}}
+void streaming_mode(void) __arm_streaming __arm_streaming_compatible;
+
+// expected-cpp-error@+4 {{'__arm_streaming' and '__arm_streaming_compatible' are not compatible}}
+// expected-cpp-note@+3 {{conflicting attribute is here}}
+// expected-error@+2 {{'__arm_streaming' and '__arm_streaming_compatible' are not compatible}}
+// expected-note@+1 {{conflicting attribute is here}}
+void streaming_compatible(void) __arm_streaming_compatible __arm_streaming;
+
+// expected-cpp-error@+2 {{'__arm_new_za' and '__arm_shared_za' are not compatible}}
+// expected-error@+1 {{'__arm_new_za' and '__arm_shared_za' are not compatible}}
+__arm_new_za void new_shared_za(void) __arm_shared_za {}
+
+// expected-cpp-error@+2 {{'__arm_new_za' and '__arm_preserves_za' are not compatible}}
+// expected-error@+1 {{'__arm_new_za' and '__arm_preserves_za' are not compatible}}
+__arm_new_za void new_preserves_za(void) __arm_preserves_za {}
+
+// Invalid attributes on function pointers
+
+// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
+// expected-cpp-note@+3 {{conflicting attribute is here}}
+// expected-error@+2 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
+// expected-note@+1 {{conflicting attribute is here}}
+void streaming_ptr_invalid(void) __arm_streaming __arm_streaming_compatible;
+// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
+// expected-cpp-note@+3 {{conflicting attribute is here}}
+// expected-error@+2 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}}
+// expected-note@+1 {{conflicting attribute is here}}
+typedef void (*fptrty7) (void) __arm_streaming __arm_streaming_compatible;
+fptrty7 invalid_streaming_func() { return streaming_ptr_invalid; }
+
+// expected-warning@+2 {{'__arm_streaming' only applies to non-K&R-style functions}}
+// expected-error@+1 {{'__arm_streaming' only applies to function types; type here is 'void ()'}}
+void function_no_prototype() __arm_streaming;
+
+//
+// Check for incorrect conversions of function pointers with the attributes
+//
+
+typedef void (*n_ptrty) (void);
+typedef void (*s_ptrty) (void) __arm_streaming;
+s_ptrty return_valid_streaming_fptr(s_ptrty f) { return f; }
+
+// expected-cpp-error@+2 {{cannot initialize return object of type 's_ptrty' (aka 'void (*)() __arm_streaming') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}}
+// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 's_ptrty' (aka 'void (*)(void) __arm_streaming')}}
+s_ptrty return_invalid_fptr_streaming_normal(n_ptrty f) { return f; }
+// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 's_ptrty' (aka 'void (*)() __arm_streaming')}}
+// expected-error@+1 {{incompatible function pointer types returning 's_ptrty' (aka 'void (*)(void) __arm_streaming') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}}
+n_ptrty return_invalid_fptr_normal_streaming(s_ptrty f) { return f; }
+
+// Test an instance where the result type is not a prototyped function, such that we still get a diagnostic.
+typedef void (*nonproto_n_ptrty) ();
+// expected-cpp-error@+2 {{cannot initialize return object of type 'nonproto_n_ptrty' (aka 'void (*)()') with an lvalue of type 's_ptrty' (aka 'void (*)() __arm_streaming')}}
+// expected-error@+1 {{incompatible function pointer types returning 's_ptrty' (aka 'void (*)(void) __arm_streaming') from a function with result type 'nonproto_n_ptrty' (aka 'void (*)()')}}
+nonproto_n_ptrty return_invalid_fptr_streaming_nonprotonormal(s_ptrty f) { return f; }
+
+typedef void (*sc_ptrty) (void) __arm_streaming_compatible;
+sc_ptrty return_valid_streaming_compatible_fptr(sc_ptrty f) { return f; }
+
+// expected-cpp-error@+2 {{cannot initialize return object of type 'sc_ptrty' (aka 'void (*)() __arm_streaming_compatible') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}}
+// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'sc_ptrty' (aka 'void (*)(void) __arm_streaming_compatible')}}
+sc_ptrty return_invalid_fptr_streaming_compatible_normal(n_ptrty f) { return f; }
+// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'sc_ptrty' (aka 'void (*)() __arm_streaming_compatible')}}
+// expected-error@+1 {{incompatible function pointer types returning 'sc_ptrty' (aka 'void (*)(void) __arm_streaming_compatible') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}}
+n_ptrty return_invalid_fptr_normal_streaming_compatible(sc_ptrty f) { return f; }
+
+typedef void (*sz_ptrty) (void) __arm_shared_za;
+sz_ptrty return_valid_shared_za_fptr(sz_ptrty f) { return f; }
+
+
+// expected-cpp-error@+2 {{cannot initialize return object of type 'sz_ptrty' (aka 'void (*)() __arm_shared_za') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}}
+// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'sz_ptrty' (aka 'void (*)(void) __arm_shared_za')}}
+sz_ptrty return_invalid_fptr_shared_za_normal(n_ptrty f) { return f; }
+// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'sz_ptrty' (aka 'void (*)() __arm_shared_za')}}
+// expected-error@+1 {{incompatible function pointer types returning 'sz_ptrty' (aka 'void (*)(void) __arm_shared_za') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}}
+n_ptrty return_invalid_fptr_normal_shared_za(sz_ptrty f) { return f; }
+
+typedef void (*pz_ptrty) (void) __arm_preserves_za;
+pz_ptrty return_valid_preserves_za_fptr(pz_ptrty f) { return f; }
+
+// expected-cpp-error@+2 {{cannot initialize return object of type 'pz_ptrty' (aka 'void (*)() __arm_preserves_za') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}}
+// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'pz_ptrty' (aka 'void (*)(void) __arm_preserves_za')}}
+pz_ptrty return_invalid_fptr_preserves_za_normal(n_ptrty f) { return f; }
+// No diagnostics, the preserves_za hint should be dropped silently.
+n_ptrty return_invalid_fptr_normal_preserves_za(pz_ptrty f) { return f; }
+
+// Test template instantiations
+#ifdef __cplusplus
+template <typename T> T templated(T x) __arm_streaming { return x; }
+template <> int templated<int>(int x) __arm_streaming { return x + 1; }
+template <> float templated<float>(float x) __arm_streaming { return x + 2; }
+// expected-cpp-error@+2 {{explicit instantiation of 'templated' does not refer to a function template, variable template, member function, member class, or static data member}}
+// expected-cpp-note@-4 {{candidate template ignored: could not match 'short (short) __arm_streaming' against 'short (short)'}}
+template short templated<short>(short);
+#endif
+
+// Conflicting attributes on redeclarations
+
+// expected-error@+5 {{function declared ''void (void) __arm_streaming_compatible'' was previously declared ''void (void) __arm_streaming'' with different SME function attributes}}
+// expected-note@+3 {{previous declaration is here}}
+// expected-cpp-error@+3 {{function declared ''void () __arm_streaming_compatible'' was previously declared ''void () __arm_streaming'' with different SME function attributes}}
+// expected-cpp-note@+1 {{previous declaration is here}}
+void redecl(void) __arm_streaming;
+void redecl(void) __arm_streaming_compatible { }
+
+// expected-error@+5 {{function declared ''void (void) __arm_shared_za'' was previously declared ''void (void) __arm_shared_za __arm_preserves_za'' with different SME function attributes}}
+// expected-note@+3 {{previous declaration is here}}
+// expected-cpp-error@+3 {{function declared ''void () __arm_shared_za'' was previously declared ''void () __arm_shared_za __arm_preserves_za'' with different SME function attributes}}
+// expected-cpp-note@+1 {{previous declaration is here}}
+void redecl_nopreserve_za(void) __arm_shared_za __arm_preserves_za;
+void redecl_nopreserve_za(void) __arm_shared_za{ }
+
+#ifdef __cplusplus
+struct S {
+ virtual void shared_za_memberfn(void) __arm_shared_za;
+};
+
+struct S2 : public S {
+// expected-cpp-error@+2 {{virtual function 'shared_za_memberfn' has different attributes ('void ()') than the function it overrides (which has 'void () __arm_shared_za')}}
+// expected-cpp-note@-5 {{overridden virtual function is here}}
+ __arm_new_za void shared_za_memberfn(void) override {}
+};
+
+// Check that the attribute propagates through template instantiations.
+template <typename Ty>
+struct S3 {
+ static constexpr int value = 0;
+};
+
+template <>
+struct S3<void (*)()> {
+ static constexpr int value = 1;
+};
+
+template <>
+struct S3<void (* __arm_streaming)()> {
+ static constexpr int value = 2;
+};
+
+void normal_func(void) {}
+void streaming_func(void) __arm_streaming {}
+
+static_assert(S3<decltype(+normal_func)>::value == 1, "why are we picking the wrong specialization?");
+static_assert(S3<decltype(+streaming_func)>::value == 2, "why are we picking the wrong specialization?");
+
+template<typename T> int test_templated_f(T);
+template<> constexpr int test_templated_f<void(*)(void)>(void(*)(void)) { return 1; }
+template<> constexpr int test_templated_f<void(*)(void)__arm_streaming>(void(*)(void)__arm_streaming) { return 2; }
+
+static_assert(test_templated_f(&normal_func) == 1, "Instantiated to wrong function");
+static_assert(test_templated_f(&streaming_func) == 2, "Instantiated to wrong function");
+
+// expected-cpp-error@+2 {{'__arm_streaming' only applies to function types; type here is 'int'}}
+// expected-error@+1 {{'__arm_streaming' only applies to function types; type here is 'int'}}
+int invalid_type_for_attribute __arm_streaming;
+
+// Test overloads
+constexpr int overload(void f(void)) { return 1; }
+constexpr int overload(void f(void) __arm_streaming) { return 2; }
+static_assert(overload(&normal_func) == 1, "Overloaded to wrong function");
+static_assert(overload(&streaming_func) == 2, "Overloaded to wrong function");
+
+#endif // ifdef __cplusplus
Index: clang/test/Modules/aarch64-sme-keywords.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/aarch64-sme-keywords.cppm
@@ -0,0 +1,65 @@
+// REQUIRES: aarch64-registered-target
+//
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 -triple aarch64 -target-feature +sme %t/A.cppm -emit-module-interface -o %t/A.pcm
+// RUN: %clang_cc1 -std=c++20 -triple aarch64 -target-feature +sme -fprebuilt-module-path=%t -I%t %t/Use.cpp -emit-llvm
+// RUN: cat %t/Use.ll | FileCheck %s
+
+//--- A.cppm
+module;
+export module A;
+
+export void f_streaming(void) __arm_streaming { }
+export void f_streaming_compatible(void) __arm_streaming_compatible { }
+export void f_shared_za(void) __arm_shared_za { }
+export void f_preserves_za(void) __arm_preserves_za { }
+
+//--- Use.cpp
+// expected-no-diagnostics
+import A;
+
+// CHECK: define dso_local void @_Z18f_shared_za_callerv() #[[SHARED_ZA_DEF:[0-9]+]] {
+// CHECK: entry:
+// CHECK: call void @_ZW1A11f_shared_zav() #[[SHARED_ZA_USE:[0-9]+]]
+// CHECK: call void @_ZW1A14f_preserves_zav() #[[PRESERVES_ZA_USE:[0-9]+]]
+// CHECK: ret void
+// CHECK: }
+//
+// CHECK:declare void @_ZW1A11f_shared_zav() #[[SHARED_ZA_DECL:[0-9]+]]
+//
+// CHECK:declare void @_ZW1A14f_preserves_zav() #[[PRESERVES_ZA_DECL:[0-9]+]]
+//
+// CHECK:; Function Attrs: mustprogress noinline nounwind optnone
+// CHECK:define dso_local void @_Z21f_nonstreaming_callerv() #[[NORMAL_DEF:[0-9]+]] {
+// CHECK:entry:
+// CHECK: call void @_ZW1A11f_streamingv() #[[STREAMING_USE:[0-9]+]]
+// CHECK: call void @_ZW1A22f_streaming_compatiblev() #[[STREAMING_COMPATIBLE_USE:[0-9]+]]
+// CHECK: ret void
+// CHECK:}
+//
+// CHECK:declare void @_ZW1A11f_streamingv() #[[STREAMING_DECL:[0-9]+]]
+//
+// CHECK:declare void @_ZW1A22f_streaming_compatiblev() #[[STREAMING_COMPATIBLE_DECL:[0-9]+]]
+//
+// CHECK-DAG: attributes #[[SHARED_ZA_DEF]] = {{{.*}} "aarch64_pstate_za_shared" {{.*}}}
+// CHECK-DAG: attributes #[[SHARED_ZA_DECL]] = {{{.*}} "aarch64_pstate_za_shared" {{.*}}}
+// CHECK-DAG: attributes #[[PRESERVES_ZA_DECL]] = {{{.*}} "aarch64_pstate_za_preserved" {{.*}}}
+// CHECK-DAG: attributes #[[NORMAL_DEF]] = {{{.*}}}
+// CHECK-DAG: attributes #[[STREAMING_DECL]] = {{{.*}} "aarch64_pstate_sm_enabled" {{.*}}}
+// CHECK-DAG: attributes #[[STREAMING_COMPATIBLE_DECL]] = {{{.*}} "aarch64_pstate_sm_compatible" {{.*}}}
+// CHECK-DAG: attributes #[[SHARED_ZA_USE]] = { "aarch64_pstate_za_shared" }
+// CHECK-DAG: attributes #[[PRESERVES_ZA_USE]] = { "aarch64_pstate_za_preserved" }
+// CHECK-DAG: attributes #[[STREAMING_USE]] = { "aarch64_pstate_sm_enabled" }
+// CHECK-DAG: attributes #[[STREAMING_COMPATIBLE_USE]] = { "aarch64_pstate_sm_compatible" }
+
+void f_shared_za_caller(void) __arm_shared_za {
+ f_shared_za();
+ f_preserves_za();
+}
+
+void f_nonstreaming_caller(void) {
+ f_streaming();
+ f_streaming_compatible();
+}
Index: clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp
@@ -0,0 +1,264 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \
+// RUN: -S -O0 -Werror -emit-llvm -o - %s | FileCheck %s
+
+extern "C" {
+
+extern int normal_callee();
+
+// == FUNCTION DECLARATIONS ==
+
+int streaming_decl(void) __arm_streaming;
+int streaming_compatible_decl(void) __arm_streaming_compatible;
+int shared_za_decl(void) __arm_shared_za;
+int preserves_za_decl(void) __arm_preserves_za;
+int private_za_decl(void);
+
+// == FUNCTION DEFINITIONS ==
+
+// CHECK-LABEL: @streaming_caller()
+// CHECK-SAME: #[[SM_ENABLED:[0-9]+]]
+// CHECK: call i32 @normal_callee()
+//
+ int streaming_caller() __arm_streaming {
+ return normal_callee();
+}
+
+// CHECK: declare i32 @normal_callee() #[[NORMAL_DECL:[0-9]+]]
+
+
+// CHECK-LABEL: @streaming_callee()
+// CHECK-SAME: #[[SM_ENABLED]]
+// CHECK: call i32 @streaming_decl() #[[SM_ENABLED_CALL:[0-9]+]]
+//
+ int streaming_callee() __arm_streaming {
+ return streaming_decl();
+}
+
+// CHECK: declare i32 @streaming_decl() #[[SM_ENABLED_DECL:[0-9]+]]
+
+// CHECK-LABEL: @streaming_compatible_caller()
+// CHECK-SAME: #[[SM_COMPATIBLE:[0-9]+]]
+// CHECK: call i32 @normal_callee()
+//
+ int streaming_compatible_caller() __arm_streaming_compatible {
+ return normal_callee();
+}
+
+// CHECK-LABEL: @streaming_compatible_callee()
+// CHECK-SAME: #[[SM_COMPATIBLE]]
+// CHECK: call i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_CALL:[0-9]+]]
+//
+ int streaming_compatible_callee() __arm_streaming_compatible {
+ return streaming_compatible_decl();
+}
+
+// CHECK: declare i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_DECL:[0-9]+]]
+
+// CHECK-LABEL: @locally_streaming_caller()
+// CHECK-SAME: #[[SM_BODY:[0-9]+]]
+// CHECK: call i32 @normal_callee()
+//
+__arm_locally_streaming int locally_streaming_caller() {
+ return normal_callee();
+}
+
+// CHECK-LABEL: @locally_streaming_callee()
+// CHECK-SAME: #[[SM_BODY]]
+// CHECK: call i32 @locally_streaming_caller() #[[SM_BODY_CALL:[0-9]+]]
+//
+__arm_locally_streaming int locally_streaming_callee() {
+ return locally_streaming_caller();
+}
+
+
+// CHECK-LABEL: @shared_za_caller()
+// CHECK-SAME: #[[ZA_SHARED:[0-9]+]]
+// CHECK: call i32 @normal_callee()
+//
+ int shared_za_caller() __arm_shared_za {
+ return normal_callee();
+}
+
+// CHECK-LABEL: @shared_za_callee()
+// CHECK-SAME: #[[ZA_SHARED]]
+// CHECK: call i32 @shared_za_decl() #[[ZA_SHARED_CALL:[0-9]+]]
+//
+ int shared_za_callee() __arm_shared_za {
+ return shared_za_decl();
+}
+
+// CHECK: declare i32 @shared_za_decl() #[[ZA_SHARED_DECL:[0-9]+]]
+
+
+// CHECK-LABEL: @preserves_za_caller()
+// CHECK-SAME: #[[ZA_PRESERVED:[0-9]+]]
+// CHECK: call i32 @normal_callee()
+//
+ int preserves_za_caller() __arm_preserves_za {
+ return normal_callee();
+}
+
+// CHECK-LABEL: @preserves_za_callee()
+// CHECK-SAME: #[[ZA_PRESERVED]]
+// CHECK: call i32 @preserves_za_decl() #[[ZA_PRESERVED_CALL:[0-9]+]]
+//
+ int preserves_za_callee() __arm_preserves_za {
+ return preserves_za_decl();
+}
+
+// CHECK: declare i32 @preserves_za_decl() #[[ZA_PRESERVED_DECL:[0-9]+]]
+
+
+// CHECK-LABEL: @new_za_caller()
+// CHECK-SAME: #[[ZA_NEW:[0-9]+]]
+// CHECK: call i32 @normal_callee()
+//
+__arm_new_za int new_za_caller() {
+ return normal_callee();
+}
+
+// CHECK-LABEL: @new_za_callee()
+// CHECK-SAME: #[[ZA_NEW]]
+// CHECK: call i32 @private_za_decl()
+//
+__arm_new_za int new_za_callee() {
+ return private_za_decl();
+}
+
+// CHECK: declare i32 @private_za_decl()
+
+
+// Ensure that the attributes are correctly propagated to function types
+// and also to callsites.
+typedef void (*s_ptrty) (int, int) __arm_streaming;
+typedef void (*sc_ptrty) (int, int) __arm_streaming_compatible;
+typedef void (*sz_ptrty) (int, int) __arm_shared_za;
+typedef void (*pz_ptrty) (int, int) __arm_preserves_za;
+
+// CHECK-LABEL: @test_streaming_ptrty(
+// CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]
+// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]
+//
+void test_streaming_ptrty(s_ptrty f, int x, int y) { return f(x, y); }
+// CHECK-LABEL: @test_streaming_compatible_ptrty(
+// CHECK-SAME: #[[NORMAL_DEF]]
+// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_COMPATIBLE_CALL]]
+//
+void test_streaming_compatible_ptrty(sc_ptrty f, int x, int y) { return f(x, y); }
+// CHECK-LABEL: @test_shared_za(
+// CHECK-SAME: #[[ZA_SHARED]]
+// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_SHARED_CALL]]
+//
+void test_shared_za(sz_ptrty f, int x, int y) __arm_shared_za { return f(x, y); }
+// CHECK-LABEL: @test_preserved_za(
+// CHECK-SAME: #[[ZA_SHARED]]
+// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_PRESERVED_CALL]]
+//
+void test_preserved_za(pz_ptrty f, int x, int y) __arm_shared_za { return f(x, y); }
+
+// CHECK-LABEL: @test_indirect_streaming_ptrty(
+// CHECK-SAME: #[[NORMAL_DEF:[0-9]+]]
+// CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[SM_ENABLED_CALL]]
+//
+typedef s_ptrty **indirect_s_ptrty;
+void test_indirect_streaming_ptrty(indirect_s_ptrty fptr, int x, int y) { return (**fptr)(x, y); }
+} // extern "C"
+
+//
+// Test that having the attribute in different places (on declaration and on type)
+// both results in the attribute being applied to the type.
+//
+
+// CHECK-LABEL: @_Z24test_same_type_streamingv(
+// CHECK: call void @_Z10streaming1v() #[[SM_ENABLED_CALL]]
+// CHECK: call void @_Z10streaming2v() #[[SM_ENABLED_CALL]]
+// CHECK: call void @_Z20same_type_streaming1v() #[[SM_ENABLED_CALL]]
+// CHECK: call void @_Z20same_type_streaming2v() #[[SM_ENABLED_CALL]]
+// CHECK: ret void
+// CHECK: }
+// CHECK: declare void @_Z10streaming1v() #[[SM_ENABLED_DECL]]
+// CHECK: declare void @_Z10streaming2v() #[[SM_ENABLED_DECL]]
+// CHECK: declare void @_Z20same_type_streaming1v() #[[SM_ENABLED_DECL]]
+// CHECK: declare void @_Z20same_type_streaming2v() #[[SM_ENABLED_DECL]]
+void streaming1(void) __arm_streaming;
+void streaming2() __arm_streaming;
+decltype(streaming1) same_type_streaming1;
+decltype(streaming2) same_type_streaming2;
+void test_same_type_streaming() {
+ streaming1();
+ streaming2();
+ same_type_streaming1();
+ same_type_streaming2();
+}
+
+//
+// Test overloading; the attribute is not required for overloaded types and
+// does not apply if not specified.
+//
+
+// CHECK-LABEL: @_Z12overloadedfni(
+// CHECK-SAME: #[[SM_ENABLED]]
+int overloadedfn(int x) __arm_streaming { return x; }
+// CHECK-LABEL: @_Z12overloadedfnf(
+// CHECK-SAME: #[[NORMAL_DEF]]
+//
+float overloadedfn(float x) { return x; }
+// CHECK-LABEL: @_Z13test_overloadi(
+// CHECK-SAME: #[[NORMAL_DEF]]
+//
+int test_overload(int x) { return overloadedfn(x); }
+// CHECK-LABEL: @_Z13test_overloadf(
+// CHECK-SAME: #[[NORMAL_DEF]]
+//
+float test_overload(float x) { return overloadedfn(x); }
+
+// CHECK-LABEL: @_Z11test_lambdai(
+// CHECK-SAME: #[[NORMAL_DEF]]
+// CHECK: call noundef i32 @"_ZZ11test_lambdaiENK3$_0clEi"({{.*}}) #[[SM_ENABLED_CALL]]
+//
+// CHECK: @"_ZZ11test_lambdaiENK3$_0clEi"(
+// CHECK-SAME: #[[SM_ENABLED]]
+int test_lambda(int x) {
+ auto F = [](int x) __arm_streaming { return x; };
+ return F(x);
+}
+
+// CHECK-LABEL: @_Z27test_template_instantiationv(
+// CHECK-SAME: #[[NORMAL_DEF]]
+// CHECK: call noundef i32 @_Z15template_functyIiET_S0_(i32 noundef 12) #[[SM_ENABLED_CALL]]
+//
+// CHECK: @_Z15template_functyIiET_S0_(
+// CHECK-SAME: #[[SM_ENABLED]]
+template <typename Ty>
+Ty template_functy(Ty x) __arm_streaming { return x; }
+int test_template_instantiation() { return template_functy(12); }
+
+//
+// Test that arm_locally_streaming is inherited by future redeclarations,
+// even when they don't specify the attribute.
+//
+
+// CHECK: define {{.*}} @_Z25locally_streaming_inheritv(
+// CHECK-SAME: #[[SM_BODY]]
+__arm_locally_streaming void locally_streaming_inherit();
+void locally_streaming_inherit() {
+ streaming_decl();
+}
+
+// CHECK: attributes #[[SM_ENABLED]] = { mustprogress noinline nounwind optnone "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[NORMAL_DECL]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[SM_ENABLED_DECL]] = { "aarch64_pstate_sm_enabled" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[SM_COMPATIBLE]] = { mustprogress noinline nounwind optnone "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[SM_COMPATIBLE_DECL]] = { "aarch64_pstate_sm_compatible" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[SM_BODY]] = { mustprogress noinline nounwind optnone "aarch64_pstate_sm_body" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[ZA_SHARED]] = { mustprogress noinline nounwind optnone "aarch64_pstate_za_shared" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[ZA_SHARED_DECL]] = { "aarch64_pstate_za_shared" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[ZA_PRESERVED]] = { mustprogress noinline nounwind optnone "aarch64_pstate_za_preserved" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[ZA_PRESERVED_DECL]] = { "aarch64_pstate_za_preserved" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[ZA_NEW]] = { mustprogress noinline nounwind optnone "aarch64_pstate_za_new" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[NORMAL_DEF]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme" }
+// CHECK: attributes #[[SM_ENABLED_CALL]] = { "aarch64_pstate_sm_enabled" }
+// CHECK: attributes #[[SM_COMPATIBLE_CALL]] = { "aarch64_pstate_sm_compatible" }
+// CHECK: attributes #[[SM_BODY_CALL]] = { "aarch64_pstate_sm_body" }
+// CHECK: attributes #[[ZA_SHARED_CALL]] = { "aarch64_pstate_za_shared" }
+// CHECK: attributes #[[ZA_PRESERVED_CALL]] = { "aarch64_pstate_za_preserved" }
Index: clang/test/AST/ast-dump-sme-attributes.cpp
===================================================================
--- /dev/null
+++ clang/test/AST/ast-dump-sme-attributes.cpp
@@ -0,0 +1,66 @@
+// Test without serialization:
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -std=c++2a -ast-dump -ast-dump-filter Foo %s | FileCheck -strict-whitespace %s
+
+// Test with serialization:
+// RUN: %clang_cc1 -std=c++20 -triple aarch64 -target-feature +sme -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++20 -triple aarch64 -target-feature +sme -include-pch %t -ast-dump-all -ast-dump-filter Foo /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
+// RUN: | FileCheck --strict-whitespace %s
+
+struct Foo {
+// CHECK: |-CXXRecordDecl {{.*}} implicit struct Foo
+// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_streaming 'void () __arm_streaming'
+// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_streaming_compatible 'void () __arm_streaming_compatible'
+// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_locally_streaming 'void ()'
+// CHECK-NEXT: | `-ArmLocallyStreamingAttr
+// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_shared_za 'void () __arm_shared_za'
+// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_new_za 'void ()'
+// CHECK-NEXT: | `-ArmNewZAAttr
+// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_preserves_za 'void () __arm_preserves_za'
+ void f_streaming() __arm_streaming;
+ void f_streaming_compatible() __arm_streaming_compatible;
+ __arm_locally_streaming void f_locally_streaming();
+ void f_shared_za() __arm_shared_za;
+ __arm_new_za void f_new_za();
+ void f_preserves_za() __arm_preserves_za;
+
+
+// CHECK: |-CXXMethodDecl {{.*}} test_lambda 'int (int)' implicit-inline
+// CHECK: `-CompoundStmt
+// CHECK-NEXT: |-DeclStmt
+// CHECK-NEXT: | `-VarDecl
+// CHECK-NEXT: | `-LambdaExpr
+// CHECK-NEXT: | |-CXXRecordDecl
+// CHECK: | | |-CXXMethodDecl {{.*}} used constexpr operator() 'int (int) __arm_streaming const' inline
+// CHECK: | | |-CXXConversionDecl {{.*}} implicit constexpr operator int (*)(int) __arm_streaming 'int (*() const noexcept)(int) __arm_streaming' inline
+// CHECK: | | |-CXXMethodDecl {{.*}} implicit __invoke 'int (int) __arm_streaming' static inline
+// CHECK: `-ReturnStmt
+// CHECK: `-CXXOperatorCallExpr
+// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int) __arm_streaming const' <FunctionToPointerDecay>
+// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int) __arm_streaming const' lvalue CXXMethod {{.*}} 'operator()' 'int (int) __arm_streaming const'
+ int test_lambda(int x) {
+ auto F = [](int x) __arm_streaming { return x; };
+ return F(x);
+ }
+
+// CHECK: |-TypedefDecl {{.*}} referenced s_ptrty 'void (*)(int, int) __arm_streaming'
+// CHECK-NEXT: | `-PointerType {{.*}} 'void (*)(int, int) __arm_streaming'
+// CHECK-NEXT: | `-ParenType {{.*}} 'void (int, int) __arm_streaming' sugar
+// CHECK-NEXT: | `-FunctionProtoType {{.*}} 'void (int, int) __arm_streaming' cdecl
+ typedef void (*s_ptrty) (int, int) __arm_streaming;
+
+// CHECK: `-CXXMethodDecl {{.*}} test_streaming_ptrty 'void (s_ptrty, int, int)' implicit-inline
+// CHECK-NEXT: |-ParmVarDecl {{.*}} used f 's_ptrty':'void (*)(int, int) __arm_streaming'
+// CHECK-NEXT: |-ParmVarDecl {{.*}} used x 'int'
+// CHECK-NEXT: |-ParmVarDecl {{.*}} used y 'int'
+// CHECK: `-CompoundStmt
+// CHECK-NEXT: `-ReturnStmt
+// CHECK-NEXT: `-CallExpr
+// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 's_ptrty':'void (*)(int, int) __arm_streaming' <LValueToRValue>
+// CHECK-NEXT: | `-DeclRefExpr {{.*}} 's_ptrty':'void (*)(int, int) __arm_streaming' lvalue ParmVar {{.*}} 'f' 's_ptrty':'void (*)(int, int) __arm_streaming'
+// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int'
+// CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'y' 'int'
+ void test_streaming_ptrty(s_ptrty f, int x, int y) { return f(x, y); };
+};
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -128,7 +128,6 @@
case ParsedAttr::AT_VectorCall: \
case ParsedAttr::AT_AArch64VectorPcs: \
case ParsedAttr::AT_AArch64SVEPcs: \
- case ParsedAttr::AT_ArmStreaming: \
case ParsedAttr::AT_AMDGPUKernelCall: \
case ParsedAttr::AT_MSABI: \
case ParsedAttr::AT_SysVABI: \
@@ -143,6 +142,10 @@
case ParsedAttr::AT_NoReturn: \
case ParsedAttr::AT_Regparm: \
case ParsedAttr::AT_CmseNSCall: \
+ case ParsedAttr::AT_ArmStreaming: \
+ case ParsedAttr::AT_ArmStreamingCompatible: \
+ case ParsedAttr::AT_ArmSharedZA: \
+ case ParsedAttr::AT_ArmPreservesZA: \
case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \
case ParsedAttr::AT_AnyX86NoCfCheck: \
CALLING_CONV_ATTRS_CASELIST
@@ -7747,6 +7750,26 @@
llvm_unreachable("unexpected attribute kind!");
}
+static bool checkMutualExclusion(TypeProcessingState &state,
+ const FunctionProtoType::ExtProtoInfo &EPI,
+ ParsedAttr &Attr,
+ AttributeCommonInfo::Kind OtherKind) {
+ auto OtherAttr = std::find_if(
+ state.getCurrentAttributes().begin(), state.getCurrentAttributes().end(),
+ [OtherKind](const ParsedAttr &A) { return A.getKind() == OtherKind; });
+ if (OtherAttr == state.getCurrentAttributes().end() || OtherAttr->isInvalid())
+ return false;
+
+ Sema &S = state.getSema();
+ S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
+ << *OtherAttr << Attr
+ << (OtherAttr->isRegularKeywordAttribute() ||
+ Attr.isRegularKeywordAttribute());
+ S.Diag(OtherAttr->getLoc(), diag::note_conflicting_attribute);
+ Attr.setInvalid();
+ return true;
+}
+
/// Process an individual function attribute. Returns true to
/// indicate that the attribute was handled, false if it wasn't.
static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
@@ -7876,6 +7899,55 @@
return true;
}
+ if (attr.getKind() == ParsedAttr::AT_ArmStreaming ||
+ attr.getKind() == ParsedAttr::AT_ArmStreamingCompatible ||
+ attr.getKind() == ParsedAttr::AT_ArmSharedZA ||
+ attr.getKind() == ParsedAttr::AT_ArmPreservesZA){
+ if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr))
+ return true;
+
+ if (!unwrapped.isFunctionType())
+ return false;
+
+ const FunctionProtoType *FnTy = unwrapped.get()->getAs<FunctionProtoType>();
+ if (!FnTy) {
+ // SME ACLE attributes are not supported on K&R-style unprototyped C
+ // functions.
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
+ attr << attr.isRegularKeywordAttribute() << ExpectedFunctionWithProtoType;
+ attr.setInvalid();
+ return false;
+ }
+
+ FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
+ switch (attr.getKind()) {
+ case ParsedAttr::AT_ArmStreaming:
+ if (checkMutualExclusion(state, EPI, attr,
+ ParsedAttr::AT_ArmStreamingCompatible))
+ return true;
+ EPI.setArmSMEAttribute(FunctionType::SME_PStateSMEnabledMask);
+ break;
+ case ParsedAttr::AT_ArmStreamingCompatible:
+ if (checkMutualExclusion(state, EPI, attr, ParsedAttr::AT_ArmStreaming))
+ return true;
+ EPI.setArmSMEAttribute(FunctionType::SME_PStateSMCompatibleMask);
+ break;
+ case ParsedAttr::AT_ArmSharedZA:
+ EPI.setArmSMEAttribute(FunctionType::SME_PStateZASharedMask);
+ break;
+ case ParsedAttr::AT_ArmPreservesZA:
+ EPI.setArmSMEAttribute(FunctionType::SME_PStateZAPreservedMask);
+ break;
+ default:
+ llvm_unreachable("Unsupported attribute");
+ }
+
+ QualType newtype = S.Context.getFunctionType(FnTy->getReturnType(),
+ FnTy->getParamTypes(), EPI);
+ type = unwrapped.wrap(S, newtype->getAs<FunctionType>());
+ return true;
+ }
+
if (attr.getKind() == ParsedAttr::AT_NoThrow) {
// Delay if this is not a function type.
if (!unwrapped.isFunctionType())
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -1686,6 +1686,26 @@
Changed = true;
}
+ // Drop the 'arm_preserves_za' if not present in the target type (we can do
+ // that because it is merely a hint).
+ if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
+ FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo();
+ if (ExtInfo.AArch64SMEAttributes &
+ FunctionType::SME_PStateZAPreservedMask) {
+ unsigned ToFlags = 0;
+ if (const auto *ToFPT = dyn_cast<FunctionProtoType>(ToFn))
+ ToFlags = ToFPT->getExtProtoInfo().AArch64SMEAttributes;
+ if (!(ToFlags & FunctionType::SME_PStateZAPreservedMask)) {
+ ExtInfo.setArmSMEAttribute(FunctionType::SME_PStateZAPreservedMask,
+ false);
+ QualType QT = Context.getFunctionType(
+ FromFPT->getReturnType(), FromFPT->getParamTypes(), ExtInfo);
+ FromFn = QT->getAs<FunctionType>();
+ Changed = true;
+ }
+ }
+ }
+
// Drop 'noexcept' if not present in target type.
if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
const auto *ToFPT = cast<FunctionProtoType>(ToFn);
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -9542,6 +9542,30 @@
ColonLoc, result, VK, OK);
}
+// Check that the SME attributes for PSTATE.ZA and PSTATE.SM are compatible.
+bool Sema::IsInvalidSMECallConversion(QualType FromType, QualType ToType) {
+ unsigned FromAttributes = 0, ToAttributes = 0;
+ if (const auto *FromFn =
+ dyn_cast<FunctionProtoType>(Context.getCanonicalType(FromType)))
+ FromAttributes =
+ FromFn->getAArch64SMEAttributes() & FunctionType::SME_AttributeMask;
+ if (const auto *ToFn =
+ dyn_cast<FunctionProtoType>(Context.getCanonicalType(ToType)))
+ ToAttributes =
+ ToFn->getAArch64SMEAttributes() & FunctionType::SME_AttributeMask;
+
+ if (FromAttributes == ToAttributes)
+ return false;
+
+ // Make an exception for preserves_za, which can be dropped because it's
+ // only a hint.
+ unsigned Changed = FromAttributes ^ ToAttributes;
+ bool DropsPreservesZA =
+ Changed == FunctionType::SME_PStateZAPreservedMask &&
+ (ToAttributes & FunctionType::SME_PStateZAPreservedMask);
+ return !DropsPreservesZA;
+}
+
// Check if we have a conversion between incompatible cmse function pointer
// types, that is, a conversion between a function pointer with the
// cmse_nonsecure_call attribute and one without.
@@ -9708,6 +9732,8 @@
return Sema::IncompatibleFunctionPointer;
if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans))
return Sema::IncompatibleFunctionPointer;
+ if (S.IsInvalidSMECallConversion(ltrans, rtrans))
+ return Sema::IncompatibleFunctionPointer;
return ConvTy;
}
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -17687,6 +17687,14 @@
}
}
+ // SME attributes must match when overriding a function declaration.
+ if (IsInvalidSMECallConversion(Old->getType(), New->getType())) {
+ Diag(New->getLocation(), diag::err_conflicting_overriding_attributes)
+ << New << New->getType() << Old->getType();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
// Virtual overrides must have the same code_seg.
const auto *OldCSA = Old->getAttr<CodeSegAttr>();
const auto *NewCSA = New->getAttr<CodeSegAttr>();
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -5349,9 +5349,6 @@
case ParsedAttr::AT_AArch64SVEPcs:
CC = CC_AArch64SVEPCS;
break;
- case ParsedAttr::AT_ArmStreaming:
- CC = CC_C; // FIXME: placeholder until real SME support is added.
- break;
case ParsedAttr::AT_AMDGPUKernelCall:
CC = CC_AMDGPUKernelCall;
break;
@@ -9439,6 +9436,29 @@
handleArmBuiltinAliasAttr(S, D, AL);
break;
+ case ParsedAttr::AT_ArmLocallyStreaming:
+ handleSimpleAttribute<ArmLocallyStreamingAttr>(S, D, AL);
+ break;
+
+ case ParsedAttr::AT_ArmNewZA:
+ if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
+ if (FPT->getAArch64SMEAttributes() &
+ FunctionType::SME_PStateZASharedMask) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << "'__arm_shared_za'" << true;
+ AL.setInvalid();
+ }
+ if (FPT->getAArch64SMEAttributes() &
+ FunctionType::SME_PStateZAPreservedMask) {
+ S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
+ << AL << "'__arm_preserves_za'" << true;
+ AL.setInvalid();
+ }
+ if (AL.isInvalid())
+ return;
+ }
+ handleSimpleAttribute<ArmNewZAAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_AcquireHandle:
handleAcquireHandleAttr(S, D, AL);
break;
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -3755,6 +3755,15 @@
}
}
+ // It is not allowed to redeclare an SME function with different SME
+ // attributes.
+ if (IsInvalidSMECallConversion(Old->getType(), New->getType())) {
+ Diag(New->getLocation(), diag::err_sme_attr_mismatch)
+ << New->getType() << Old->getType();
+ Diag(OldLocation, diag::note_previous_declaration);
+ return true;
+ }
+
// If a function is first declared with a calling convention, but is later
// declared or defined without one, all following decls assume the calling
// convention of the first.
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -2070,6 +2070,16 @@
return;
}
+ // We only need to handle the 'arm_locally_streaming' attribute as a
+ // special case here (as opposed to e.g. 'arm_streaming'), because it
+ // is not set from the prototype, but rather from the definition.
+ // The same holds for 'arm_new_za'.
+ if (D->hasAttr<ArmLocallyStreamingAttr>())
+ B.addAttribute("aarch64_pstate_sm_body");
+
+ if (D->hasAttr<ArmNewZAAttr>())
+ B.addAttribute("aarch64_pstate_za_new");
+
// Track whether we need to add the optnone LLVM attribute,
// starting with the default for this optimization level.
bool ShouldAddOptNone =
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1768,6 +1768,15 @@
if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) &&
FPT->isNothrow())
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+
+ if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask)
+ FuncAttrs.addAttribute("aarch64_pstate_sm_enabled");
+ if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask)
+ FuncAttrs.addAttribute("aarch64_pstate_sm_compatible");
+ if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask)
+ FuncAttrs.addAttribute("aarch64_pstate_za_shared");
+ if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask)
+ FuncAttrs.addAttribute("aarch64_pstate_za_preserved");
}
static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,
@@ -2368,6 +2377,12 @@
llvm::toStringRef(CodeGenOpts.UniformWGSize));
}
}
+
+ if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>())
+ FuncAttrs.addAttribute("aarch64_pstate_sm_body");
+
+ if (TargetDecl->hasAttr<ArmNewZAAttr>())
+ FuncAttrs.addAttribute("aarch64_pstate_za_new");
}
// Attach "no-builtins" attributes to:
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ clang/lib/AST/TypePrinter.cpp
@@ -938,6 +938,21 @@
FunctionType::ExtInfo Info = T->getExtInfo();
+ if ((T->getAArch64SMEAttributes() &
+ FunctionType::SME_PStateSMCompatibleMask) &&
+ !InsideCCAttribute)
+ OS << " __arm_streaming_compatible";
+ if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask) &&
+ !InsideCCAttribute)
+ OS << " __arm_streaming";
+ if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask) &&
+ !InsideCCAttribute)
+ OS << " __arm_shared_za";
+ if ((T->getAArch64SMEAttributes() &
+ FunctionType::SME_PStateZAPreservedMask) &&
+ !InsideCCAttribute)
+ OS << " __arm_preserves_za";
+
printFunctionAfter(Info, OS);
if (!T->getMethodQuals().empty())
@@ -1761,6 +1776,18 @@
OS << "__arm_streaming";
return;
}
+ if (T->getAttrKind() == attr::ArmStreamingCompatible) {
+ OS << "__arm_streaming_compatible";
+ return;
+ }
+ if (T->getAttrKind() == attr::ArmSharedZA) {
+ OS << "__arm_shared_za";
+ return;
+ }
+ if (T->getAttrKind() == attr::ArmPreservesZA) {
+ OS << "__arm_preserves_za";
+ return;
+ }
OS << " __attribute__((";
switch (T->getAttrKind()) {
@@ -1803,6 +1830,9 @@
case attr::AnnotateType:
case attr::WebAssemblyFuncref:
case attr::ArmStreaming:
+ case attr::ArmStreamingCompatible:
+ case attr::ArmSharedZA:
+ case attr::ArmPreservesZA:
llvm_unreachable("This attribute should have been handled already");
case attr::NSReturnsRetained:
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -3368,6 +3368,12 @@
argSlot[i] = params[i];
}
+ // Propagate the SME ACLE attributes.
+ if (epi.AArch64SMEAttributes != SME_NormalFunction) {
+ auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>();
+ ExtraBits.setAArch64SMEAttributes(epi.AArch64SMEAttributes);
+ }
+
// Fill in the exception type array if present.
if (getExceptionSpecType() == EST_Dynamic) {
auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>();
@@ -3561,6 +3567,8 @@
for (unsigned i = 0; i != NumParams; ++i)
ID.AddInteger(epi.ExtParameterInfos[i].getOpaqueValue());
}
+ ID.AddInteger(epi.AArch64SMEAttributes);
+
epi.ExtInfo.Profile(ID);
ID.AddBoolean(epi.HasTrailingReturn);
}
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -7022,6 +7022,8 @@
NestedNameSpecInfo &IdInfo,
bool EnteringContext);
+ bool IsInvalidSMECallConversion(QualType FromType, QualType ToType);
+
/// The parser has parsed a nested-name-specifier
/// 'template[opt] template-name < template-args >::'.
///
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2015,6 +2015,10 @@
"than the function it overrides}1,2">;
def note_overridden_virtual_function : Note<
"overridden virtual function is here">;
+def err_conflicting_overriding_attributes : Error<
+ "virtual function %0 has different attributes "
+ "%diff{($) than the function it overrides (which has $)|"
+ "than the function it overrides}1,2">;
def err_conflicting_overriding_cc_attributes : Error<
"virtual function %0 has different calling convention attributes "
"%diff{($) than the function it overrides (which has calling convention $)|"
@@ -3583,6 +3587,9 @@
"the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">;
def err_attribute_vecreturn_only_pod_record : Error<
"the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">;
+def err_sme_attr_mismatch : Error<
+ "function declared '%0' was previously declared '%1'"
+ " with different SME function attributes">;
def err_cconv_change : Error<
"function declared '%0' here was previously declared "
"%select{'%2'|without calling convention}1">;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -6554,9 +6554,6 @@
def ArmSmeStreamingDocs : Documentation {
let Category = DocCatType;
let Content = [{
-.. Note:: This attribute has not been implemented yet, but once it is
- implemented, it will behave as described below.
-
The ``__arm_streaming`` keyword is only available on AArch64 targets.
It applies to function types and specifies that the function has a
âstreaming interfaceâ. This means that:
@@ -6588,6 +6585,146 @@
}];
}
+def ArmSmeStreamingCompatibleDocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+The ``__arm_streaming_compatible`` keyword is only available on AArch64 targets.
+It applies to function types and specifies that the function has a
+âstreaming compatible interfaceâ. This means that:
+
+* the function requires the Scalable Matrix Extension (SME)
+
+* the function may be entered in either normal mode (PSTATE.SM=0) or
+ in streaming mode (PSTATE.SM=1).
+
+* the function must return in the same mode in which it entered the function.
+
+* the code executed in the function is compatible with either mode.
+
+* the function does not have a K&R-style unprototyped function type.
+
+See `Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)
+<https://github.com/ARM-software/abi-aa>`_ for more details about
+streaming-compatible functions.
+
+Clang manages PSTATE.SM automatically; it is not the source code's
+responsibility to do this. Clang will ensure that the generated code in
+streaming-compatible functions is valid in either mode (PSTATE.SM=0 or
+PSTATE.SM=1). For example, if an ``__arm_streaming_compatible`` function calls a
+normal function, Clang generates code to temporarily switch out of streaming
+mode before calling the function and switch back to streaming-mode on return if
+``PSTATE.SM`` is ``1`` on entry of the caller. If ``PSTATE.SM`` is ``0`` on
+entry to the ``__arm_streaming_compatible`` function, the call will be executed
+without changing modes.
+
+``__arm_streaming_compatible`` can appear anywhere that a standard ``[[â¦]]``
+type attribute can appear.
+
+See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
+for more details about this extension, and for other related SME features.
+ }];
+}
+
+def ArmSmeSharedZADocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+The ``__arm_shared_za`` keyword is only available on AArch64 targets.
+It applies to function types and specifies that the function shares
+ZA state with its caller. This means that:
+
+* the function requires the Scalable Matrix Extension (SME)
+
+* the function enters with ZA in an active state.
+
+* the function returns with ZA in an active state for normal returns.
+
+* the function does not have a K&R-style unprototyped function type.
+
+See `Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)
+<https://github.com/ARM-software/abi-aa>`_ for more details about shared-ZA
+functions.
+
+``__arm_shared_za`` can appear anywhere that a standard ``[[â¦]]``
+type attribute can appear.
+
+See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
+for more details about this extension, and for other related SME features.
+ }];
+}
+
+def ArmSmePreservesZADocs : Documentation {
+ let Category = DocCatType;
+ let Content = [{
+The ``__arm_preserves_za`` keyword is only available on AArch64 targets.
+It applies to function types and specifies that the function does not
+modify ZA state.
+
+``__arm_preserves_za`` can appear anywhere that a standard ``[[â¦]]``
+type attribute can appear, however the keyword does not apply to functions
+having a K&R-style unprototyped function type.
+
+See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
+for more details about this extension, and for other related SME features.
+ }];
+}
+
+
+def ArmSmeLocallyStreamingDocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``__arm_locally_streaming`` keyword is only available on AArch64 targets.
+It applies to function declarations and specifies that all the statements in the
+function are executed in streaming mode. This means that:
+
+* the function requires the Scalable Matrix Extension (SME)
+
+* the program automatically puts the machine into streaming mode before
+ executing the statements and automatically restores the previous mode
+ afterwards.
+
+Clang manages PSTATE.SM automatically; it is not the source code's
+responsibility to do this. For example, Clang will emit code to enable
+streaming mode at the start of the function, and disable streaming mode
+at the end of the function.
+
+``__arm_locally_streaming`` can appear anywhere that a standard ``[[â¦]]``
+declaration attribute can appear.
+
+See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
+for more details about this extension, and for other related SME features.
+ }];
+}
+
+def ArmSmeNewZADocs : Documentation {
+ let Category = DocCatFunction;
+ let Content = [{
+The ``__arm_new_za`` keyword is only available on AArch64 targets.
+It applies to function declarations and specifies that the function will be set
+up with a fresh ZA context.
+
+This means that:
+
+* the function requires the Scalable Matrix Extension (SME)
+
+* the function will commit any lazy-saves if available.
+
+* the function will create a new ZA context and enable PSTATE.ZA.
+
+* the function will disable PSTATE.ZA (by setting it to 0) before returning.
+
+For ``__arm_new_za`` functions Clang will set up the ZA context automatically
+on entry to the function, and disable it before returning. For example, if ZA is
+in a dormant state Clang will generate the code to commit a lazy-save and set up
+a new ZA state before executing user code.
+
+``__arm_new_za`` can appear anywhere that a standard ``[[â¦]]`` declaration
+attribute can appear.
+
+See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
+for more details about this extension, and for other related SME features.
+ }];
+}
+
def AlwaysInlineDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2443,6 +2443,39 @@
let Documentation = [ArmSmeStreamingDocs];
}
+def ArmStreamingCompatible : TypeAttr, TargetSpecificAttr<TargetAArch64SME> {
+ let Spellings = [RegularKeyword<"__arm_streaming_compatible">];
+ let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+ let Documentation = [ArmSmeStreamingCompatibleDocs];
+}
+
+def ArmSharedZA : TypeAttr, TargetSpecificAttr<TargetAArch64SME> {
+ let Spellings = [RegularKeyword<"__arm_shared_za">];
+ let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+ let Documentation = [ArmSmeSharedZADocs];
+}
+
+def ArmPreservesZA : TypeAttr, TargetSpecificAttr<TargetAArch64SME> {
+ let Spellings = [RegularKeyword<"__arm_preserves_za">];
+ let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
+ let Documentation = [ArmSmePreservesZADocs];
+}
+
+def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64SME> {
+ let Spellings = [RegularKeyword<"__arm_locally_streaming">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [ArmSmeLocallyStreamingDocs];
+}
+
+def ArmNewZA : InheritableAttr, TargetSpecificAttr<TargetAArch64SME> {
+ let Spellings = [RegularKeyword<"__arm_new_za">];
+ let Subjects = SubjectList<[Function], ErrorDiag>;
+ let Documentation = [ArmSmeNewZADocs];
+}
+def : MutualExclusions<[ArmNewZA, ArmSharedZA]>;
+def : MutualExclusions<[ArmNewZA, ArmPreservesZA]>;
+
+
def Pure : InheritableAttr {
let Spellings = [GCC<"pure">];
let Documentation = [Undocumented];
Index: clang/include/clang/AST/TypeProperties.td
===================================================================
--- clang/include/clang/AST/TypeProperties.td
+++ clang/include/clang/AST/TypeProperties.td
@@ -323,6 +323,9 @@
? node->getExtParameterInfos()
: llvm::ArrayRef<FunctionProtoType::ExtParameterInfo>() }];
}
+ def : Property<"AArch64SMEAttributes", UInt32> {
+ let Read = [{ node->getAArch64SMEAttributes() }];
+ }
def : Creator<[{
auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm,
@@ -338,6 +341,7 @@
epi.ExceptionSpec = exceptionSpecifier;
epi.ExtParameterInfos =
extParameterInfo.empty() ? nullptr : extParameterInfo.data();
+ epi.AArch64SMEAttributes = AArch64SMEAttributes;
return ctx.getFunctionType(returnType, parameters, epi);
}]>;
}
Index: clang/include/clang/AST/Type.h
===================================================================
--- clang/include/clang/AST/Type.h
+++ clang/include/clang/AST/Type.h
@@ -3946,6 +3946,19 @@
/// because TrailingObjects cannot handle repeated types.
struct ExceptionType { QualType Type; };
+ /// The AArch64 SME ACLE (Arm C/C++ Language Extensions) define a number
+ /// of function type attributes that can be set on function types, including
+ /// function pointers.
+ enum AArch64SMETypeAttributes : unsigned {
+ SME_NormalFunction = 0,
+ SME_PStateSMEnabledMask = 1 << 0,
+ SME_PStateSMCompatibleMask = 1 << 1,
+ SME_PStateZASharedMask = 1 << 2,
+ SME_PStateZAPreservedMask = 1 << 3,
+ SME_AttributeMask = 255 // We only support maximum 8 bits because of the
+ // bitmask in FunctionTypeExtraBitfields.
+ };
+
/// A simple holder for various uncommon bits which do not fit in
/// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
/// alignment of subsequent objects in TrailingObjects.
@@ -3955,14 +3968,26 @@
/// [implimits] 8 bits would be enough here.
unsigned NumExceptionType : 16;
+ /// Any AArch64 SME ACLE type attributes that need to be propagated
+ /// on declarations and function pointers.
+ unsigned AArch64SMEAttributes : 8;
+
public:
- FunctionTypeExtraBitfields() : NumExceptionType(0) {}
+ FunctionTypeExtraBitfields()
+ : NumExceptionType(0), AArch64SMEAttributes(SME_NormalFunction) {}
void setNumExceptionType(unsigned N) {
assert(N < 65536 && "Not enough bits to encode exceptions");
NumExceptionType = N;
}
unsigned getNumExceptionType() const { return NumExceptionType; }
+
+ void setAArch64SMEAttributes(unsigned Attrs) {
+ assert(Attrs <= SME_AttributeMask &&
+ "Not enough bits to encode SME attributes");
+ AArch64SMEAttributes = Attrs;
+ }
+ unsigned getAArch64SMEAttributes() const { return AArch64SMEAttributes; }
};
protected:
@@ -4143,16 +4168,20 @@
FunctionType::ExtInfo ExtInfo;
bool Variadic : 1;
bool HasTrailingReturn : 1;
+ unsigned AArch64SMEAttributes : 8;
Qualifiers TypeQuals;
RefQualifierKind RefQualifier = RQ_None;
ExceptionSpecInfo ExceptionSpec;
const ExtParameterInfo *ExtParameterInfos = nullptr;
SourceLocation EllipsisLoc;
- ExtProtoInfo() : Variadic(false), HasTrailingReturn(false) {}
+ ExtProtoInfo()
+ : Variadic(false), HasTrailingReturn(false),
+ AArch64SMEAttributes(SME_NormalFunction) {}
ExtProtoInfo(CallingConv CC)
- : ExtInfo(CC), Variadic(false), HasTrailingReturn(false) {}
+ : ExtInfo(CC), Variadic(false), HasTrailingReturn(false),
+ AArch64SMEAttributes(SME_NormalFunction) {}
ExtProtoInfo withExceptionSpec(const ExceptionSpecInfo &ESI) {
ExtProtoInfo Result(*this);
@@ -4161,7 +4190,16 @@
}
bool requiresFunctionProtoTypeExtraBitfields() const {
- return ExceptionSpec.Type == EST_Dynamic;
+ return ExceptionSpec.Type == EST_Dynamic ||
+ AArch64SMEAttributes != SME_NormalFunction;
+ }
+
+ void setArmSMEAttribute(AArch64SMETypeAttributes Kind, bool Enable = true) {
+ if (Enable)
+ AArch64SMEAttributes |= Kind;
+ else
+ AArch64SMEAttributes =
+ (AArch64SMEAttributes ^ Kind) & AArch64SMEAttributes;
}
};
@@ -4288,6 +4326,7 @@
EPI.TypeQuals = getMethodQuals();
EPI.RefQualifier = getRefQualifier();
EPI.ExtParameterInfos = getExtParameterInfosOrNull();
+ EPI.AArch64SMEAttributes = getAArch64SMEAttributes();
return EPI;
}
@@ -4469,6 +4508,15 @@
return getTrailingObjects<ExtParameterInfo>();
}
+ /// Return a bitmask describing the SME attributes on the function type, see
+ /// AArch64SMETypeAttributes for their values.
+ unsigned getAArch64SMEAttributes() const {
+ if (!hasExtraBitfields())
+ return SME_NormalFunction;
+ return getTrailingObjects<FunctionTypeExtraBitfields>()
+ ->getAArch64SMEAttributes();
+ }
+
ExtParameterInfo getExtParameterInfo(unsigned I) const {
assert(I < getNumParams() && "parameter index out of range");
if (hasExtParameterInfos())
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits