summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Tatham <simon.tatham@arm.com>2019-09-02 15:35:09 +0100
committerSimon Tatham <simon.tatham@arm.com>2019-10-24 16:33:13 +0100
commit7c11da0cfd3396150c13657a2217f2044f314734 (patch)
treed202eada24717419b3c87193179e78a098a2932e
parente0ef4ebe2f6ac3523ee25081b36c114c0f0ea695 (diff)
downloadbcm5719-llvm-7c11da0cfd3396150c13657a2217f2044f314734.tar.gz
bcm5719-llvm-7c11da0cfd3396150c13657a2217f2044f314734.zip
[clang] New __attribute__((__clang_arm_mve_alias)).
This allows you to declare a function with a name of your choice (say `foo`), but have clang treat it as if it were a builtin function (say `__builtin_foo`), by writing static __inline__ __attribute__((__clang_arm_mve_alias(__builtin_foo))) int foo(args); I'm intending to use this for the ACLE intrinsics for MVE, which have to be polymorphic on their argument types and also need to be implemented by builtins. To avoid having to implement the polymorphism with several layers of nested _Generic and make error reporting hideous, I want to make all the user-facing intrinsics correspond directly to clang builtins, so that after clang resolves __attribute__((overloadable)) polymorphism it's already holding the right BuiltinID for the intrinsic it selected. However, this commit itself just introduces the new attribute, and doesn't use it for anything. To avoid unanticipated side effects if this attribute is used to make aliases to other builtins, there's a restriction mechanism: only (BuiltinID, alias) pairs that are approved by the function ArmMveAliasValid() will be permitted. At present, that function doesn't permit anything, because the Tablegen that will generate its list of valid pairs isn't yet implemented. So the only test of this facility is one that checks that an unapproved builtin _can't_ be aliased. Reviewers: dmgreen, miyuki, ostannard Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D67159
-rw-r--r--clang/include/clang/Basic/Attr.td7
-rw-r--r--clang/include/clang/Basic/AttrDocs.td22
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/lib/AST/Decl.cpp16
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp29
-rw-r--r--clang/test/Misc/pragma-attribute-supported-attributes-list.test1
-rw-r--r--clang/test/Sema/arm-mve-alias-attribute.c22
7 files changed, 95 insertions, 4 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index c3a2ee325df..4557a614d36 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -594,6 +594,13 @@ def Alias : Attr {
let Documentation = [Undocumented];
}
+def ArmMveAlias : InheritableAttr, TargetSpecificAttr<TargetARM> {
+ 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
index 114a9856c5f..6e79d0bb363 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -4391,3 +4391,25 @@ When the Owner's lifetime ends, it will consider the Pointer to be dangling.
}];
}
+
+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/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f7b98bb9ea8..0b669324589 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6430,6 +6430,8 @@ def warn_objc_unsafe_perform_selector : Warning<
InGroup<DiagGroup<"objc-unsafe-perform-selector">>;
def note_objc_unsafe_perform_selector_method_declared_here : Note<
"method %0 that returns %1 declared here">;
+def err_attribute_arm_mve_alias : Error<
+ "'__clang_arm_mve_alias' attribute can only be applied to an ARM MVE builtin">;
def warn_setter_getter_impl_required : Warning<
"property %0 requires method %1 to be defined - "
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index dae4af8bb24..66446626c2e 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3115,10 +3115,17 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// 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<ArmMveAliasAttr>()) {
+ BuiltinID = AMAA->getBuiltinName()->getBuiltinID();
+ } else {
+ if (!getIdentifier())
+ return 0;
+
+ BuiltinID = getIdentifier()->getBuiltinID();
+ }
- unsigned BuiltinID = getIdentifier()->getBuiltinID();
if (!BuiltinID)
return 0;
@@ -3142,7 +3149,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
// If the function is marked "overloadable", it has a different mangled name
// and is not the C library function.
- if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>())
+ if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() &&
+ !hasAttr<ArmMveAliasAttr>())
return 0;
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index b2be6245a81..cebb1c642b9 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
@@ -4830,6 +4831,30 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
}
+static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) {
+ // FIXME: this will be filled in by Tablegen which isn't written yet
+ return false;
+}
+
+static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
+ << AL << 1 << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
+ unsigned BuiltinID = Ident->getBuiltinID();
+
+ if (!ArmMveAliasValid(BuiltinID,
+ cast<FunctionDecl>(D)->getIdentifier()->getName())) {
+ S.Diag(AL.getLoc(), diag::err_attribute_arm_mve_alias);
+ return;
+ }
+
+ D->addAttr(::new (S.Context) ArmMveAliasAttr(S.Context, AL, Ident));
+}
+
//===----------------------------------------------------------------------===//
// Checker-specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -7160,6 +7185,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
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
index 311ba1a857b..25802bd73c5 100644
--- 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
index 00000000000..c2f526df490
--- /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))) // expected-error {{'__clang_arm_mve_alias' attribute can only be applied to an ARM MVE builtin}}
+void nop(void);
+
+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;
OpenPOWER on IntegriCloud