diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -594,6 +594,13 @@ let Documentation = [Undocumented]; } +def ArmMveAlias : InheritableAttr, TargetSpecificAttr { + let Spellings = [Clang<"__clang_arm_mve_alias">]; + let Args = [IdentifierArgument<"BuiltinName">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [ArmMveAliasDocs]; +} + def Aligned : InheritableAttr { let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">, Keyword<"_Alignas">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4391,3 +4391,25 @@ }]; } + +def ArmMveAliasDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +This attribute is used in the implementation of the ACLE intrinsics +for the Arm MVE instruction set. It allows the intrinsic functions to +be declared using the names defined in ACLE, and still be recognized +as clang builtins equivalent to the underlying name. For example, +``arm_mve.h`` declares the function ``vaddq_u32`` with +``__attribute__((__clang_arm_mve_alias(__builtin_arm_mve_vaddq_u32)))``, +and similarly, one of the type-overloaded declarations of ``vaddq`` +will have the same attribute. This ensures that both functions are +recognized as that clang builtin, and in the latter case, the choice +of which builtin to identify the function as can be deferred until +after overload resolution. + +This attribute can only be used to set up the aliases for the MVE +intrinsic functions; it is intended for use only inside ``arm_mve.h``, +and is not a general mechanism for declaring arbitrary aliases for +clang builtin functions. + }]; +} diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -511,4 +511,8 @@ InGroup, DefaultIgnore; def warn_unnecessary_packed : Warning< "packed attribute is unnecessary for %0">, InGroup, DefaultIgnore; + +def err_attribute_arm_mve_alias : Error< + "'__clang_arm_mve_alias' attribute can only be applied to an ARM MVE builtin">; + } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -46,6 +46,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Visibility.h" @@ -3099,6 +3100,11 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } +static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) { + // FIXME: this will be filled in by Tablegen which isn't written yet + return false; +} + /// Returns a value indicating whether this function corresponds to a builtin /// function. /// @@ -3113,10 +3119,24 @@ /// functions as their wrapped builtins. This shouldn't be done in general, but /// it's useful in Sema to diagnose calls to wrappers based on their semantics. unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { - if (!getIdentifier()) - return 0; + unsigned BuiltinID; + + if (const auto *AMAA = getAttr()) { + IdentifierInfo *II = AMAA->getBuiltinName(); + BuiltinID = II->getBuiltinID(); + + if (!ArmMveAliasValid(BuiltinID, getIdentifier()->getName())) { + getASTContext().getDiagnostics().Report( + getLocation(), diag::err_attribute_arm_mve_alias); + return 0; + } + } else { + if (!getIdentifier()) + return 0; + + BuiltinID = getIdentifier()->getBuiltinID(); + } - unsigned BuiltinID = getIdentifier()->getBuiltinID(); if (!BuiltinID) return 0; @@ -3140,7 +3160,8 @@ // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. - if (!ConsiderWrapperFunctions && hasAttr()) + if (!ConsiderWrapperFunctions && hasAttr() && + !hasAttr()) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4830,6 +4830,20 @@ XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex())); } +static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!checkAttributeNumArgs(S, AL, 1)) + return; + + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + D->addAttr(::new (S.Context) + ArmMveAliasAttr(S.Context, AL, AL.getArgAsIdent(0)->Ident)); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -7160,6 +7174,10 @@ case ParsedAttr::AT_MSAllocator: handleMSAllocatorAttr(S, D, AL); break; + + case ParsedAttr::AT_ArmMveAlias: + handleArmMveAliasAttr(S, D, AL); + break; } } diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -17,6 +17,7 @@ // CHECK-NEXT: Annotate () // CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType) // CHECK-NEXT: ArcWeakrefUnavailable (SubjectMatchRule_objc_interface) +// CHECK-NEXT: ArmMveAlias (SubjectMatchRule_function) // CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function) // CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) // CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function) diff --git a/clang/test/Sema/arm-mve-alias-attribute.c b/clang/test/Sema/arm-mve-alias-attribute.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/arm-mve-alias-attribute.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple armv8.1m.main-arm-none-eabi -verify -fsyntax-only %s + +static __inline__ __attribute__((__clang_arm_mve_alias(__builtin_arm_nop))) +void nop(void); // expected-error {{'__clang_arm_mve_alias' attribute can only be applied to an ARM MVE builtin}} + +static __inline__ __attribute__((__clang_arm_mve_alias)) // expected-error {{'__clang_arm_mve_alias' attribute takes one argument}} +void noparens(void); + +static __inline__ __attribute__((__clang_arm_mve_alias())) // expected-error {{'__clang_arm_mve_alias' attribute takes one argument}} +void emptyparens(void); + +static __inline__ __attribute__((__clang_arm_mve_alias("string literal"))) // expected-error {{'__clang_arm_mve_alias' attribute requires parameter 1 to be an identifier}} +void stringliteral(void); + +static __inline__ __attribute__((__clang_arm_mve_alias(1))) // expected-error {{'__clang_arm_mve_alias' attribute requires parameter 1 to be an identifier}} +void integer(void); + +static __inline__ __attribute__((__clang_arm_mve_alias(__builtin_arm_nop, 2))) // expected-error {{'__clang_arm_mve_alias' attribute takes one argument}} +void twoargs(void); + +static __attribute__((__clang_arm_mve_alias(__builtin_arm_nop))) // expected-error {{'__clang_arm_mve_alias' attribute only applies to functions}} +int variable;