[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:
parent
e0ef4ebe2f
commit
7c11da0cfd
|
@ -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">];
|
||||
|
|
|
@ -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.
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -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 - "
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue