[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
This commit is contained in:
Simon Tatham 2019-09-02 15:35:09 +01:00
parent e0ef4ebe2f
commit 7c11da0cfd
7 changed files with 95 additions and 4 deletions

View File

@ -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">];

View File

@ -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.
}];
}

View File

@ -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 - "

View File

@ -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))

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;