r351629 - Emit !callback metadata and introduce the callback attribute
Chandler Carruth via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 22 02:52:28 PST 2019
On Sat, Jan 19, 2019 at 2:18 AM Johannes Doerfert via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: jdoerfert
> Date: Fri Jan 18 21:36:54 2019
> New Revision: 351629
>
> URL: http://llvm.org/viewvc/llvm-project?rev=351629&view=rev
> Log:
> Emit !callback metadata and introduce the callback attribute
>
> With commit r351627, LLVM gained the ability to apply (existing) IPO
> optimizations on indirections through callbacks, or transitive calls.
> The general idea is that we use an abstraction to hide the middle man
> and represent the callback call in the context of the initial caller.
> It is described in more detail in the commit message of the LLVM patch
> r351627, the llvm::AbstractCallSite class description, and the
> language reference section on callback-metadata.
>
> This commit enables clang to emit !callback metadata that is
> understood by LLVM. It does so in three different cases:
> 1) For known broker functions declarations that are directly
> generated, e.g., __kmpc_fork_call for the OpenMP pragma parallel.
> 2) For known broker functions that are identified by their name and
> source location through the builtin detection, e.g.,
> pthread_create from the POSIX thread API.
> 3) For user annotated functions that carry the "callback(callee, ...)"
> attribute. The attribute has to include the name, or index, of
> the callback callee and how the passed arguments can be
> identified (as many as the callback callee has). See the callback
> attribute documentation for detailed information.
>
> Differential Revision: https://reviews.llvm.org/D55483
>
> Added:
> cfe/trunk/test/CodeGen/attr-callback.c
> cfe/trunk/test/CodeGen/callback_annotated.c
> cfe/trunk/test/CodeGen/callback_openmp.c
> cfe/trunk/test/CodeGen/callback_pthread_create.c
> cfe/trunk/test/CodeGenCXX/attr-callback.cpp
> cfe/trunk/test/Sema/attr-callback-broken.c
> cfe/trunk/test/Sema/attr-callback.c
> cfe/trunk/test/SemaCXX/attr-callback-broken.cpp
> cfe/trunk/test/SemaCXX/attr-callback.cpp
> Modified:
> cfe/trunk/include/clang/AST/ASTContext.h
> cfe/trunk/include/clang/Basic/Attr.td
> cfe/trunk/include/clang/Basic/AttrDocs.td
> cfe/trunk/include/clang/Basic/Builtins.def
> cfe/trunk/include/clang/Basic/Builtins.h
> cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> cfe/trunk/lib/AST/ASTContext.cpp
> cfe/trunk/lib/Basic/Builtins.cpp
> cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
> cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> cfe/trunk/lib/Parse/ParseDecl.cpp
> cfe/trunk/lib/Sema/SemaDecl.cpp
> cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> cfe/trunk/test/Analysis/retain-release.m
> cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> cfe/trunk/test/OpenMP/parallel_codegen.cpp
> cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jan 18 21:36:54 2019
> @@ -2003,6 +2003,9 @@ public:
> /// No error
> GE_None,
>
> + /// Missing a type
> + GE_Missing_type,
> +
> /// Missing a type from <stdio.h>
> GE_Missing_stdio,
>
>
> Modified: cfe/trunk/include/clang/Basic/Attr.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Attr.td (original)
> +++ cfe/trunk/include/clang/Basic/Attr.td Fri Jan 18 21:36:54 2019
> @@ -190,6 +190,9 @@ class VariadicIdentifierArgument<string
> // Like VariadicUnsignedArgument except values are ParamIdx.
> class VariadicParamIdxArgument<string name> : Argument<name, 1>;
>
> +// A list of identifiers matching parameters or ParamIdx indices.
> +class VariadicParamOrParamIdxArgument<string name> : Argument<name, 1>;
> +
> // Like VariadicParamIdxArgument but for a single function parameter
> index.
> class ParamIdxArgument<string name, bit opt = 0> : Argument<name, opt>;
>
> @@ -1210,6 +1213,13 @@ def FormatArg : InheritableAttr {
> let Documentation = [Undocumented];
> }
>
> +def Callback : InheritableAttr {
> + let Spellings = [Clang<"callback">];
> + let Args = [VariadicParamOrParamIdxArgument<"Encoding">];
> + let Subjects = SubjectList<[Function]>;
> + let Documentation = [CallbackDocs];
> +}
> +
> def GNUInline : InheritableAttr {
> let Spellings = [GCC<"gnu_inline">];
> let Subjects = SubjectList<[Function]>;
>
> Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
> +++ cfe/trunk/include/clang/Basic/AttrDocs.td Fri Jan 18 21:36:54 2019
> @@ -3781,6 +3781,55 @@ it rather documents the programmer's int
> }];
> }
>
> +def CallbackDocs : Documentation {
> + let Category = DocCatVariable;
> + let Content = [{
> +The ``callback`` attribute specifies that the annotated function may
> invoke the
> +specified callback zero or more times. The callback, as well as the passed
> +arguments, are identified by their parameter name or position (starting
> with
> +1!) in the annotated function. The first position in the attribute
> identifies
> +the callback callee, the following positions declare describe its
> arguments.
> +The callback callee is required to be callable with the number, and
> order, of
> +the specified arguments. The index `0`, or the identifier `this`, is used
> to
> +represent an implicit "this" pointer in class methods. If there is no
> implicit
> +"this" pointer it shall not be referenced. The index '-1', or the name
> "__",
> +represents an unknown callback callee argument. This can be a value which
> is
> +not present in the declared parameter list, or one that is, but is
> potentially
> +inspected, captured, or modified. Parameter names and indices can be
> mixed in
> +the callback attribute.
> +
> +The ``callback`` attribute, which is directly translated to ``callback``
> +metadata <http://llvm.org/docs/LangRef.html#callback-metadata>, make the
> +connection between the call to the annotated function and the callback
> callee.
> +This can enable interprocedural optimizations which were otherwise
> impossible.
> +If a function parameter is mentioned in the ``callback`` attribute,
> through its
> +position, it is undefined if that parameter is used for anything other
> than the
> +actual callback. Inspected, captured, or modified parameters shall not be
> +listed in the ``callback`` metadata.
> +
> +Example encodings for the callback performed by `pthread_create` are shown
> +below. The explicit attribute annotation indicates that the third
> parameter
> +(`start_routine`) is called zero or more times by the `pthread_create`
> function,
> +and that the fourth parameter (`arg`) is passed along. Note that the
> callback
> +behavior of `pthread_create` is automatically recognized by Clang. In
> addition,
> +the declarations of `__kmpc_fork_teams` and `__kmpc_fork_call`, generated
> for
> +`#pragma omp target teams` and `#pragma omp parallel`, respectively, are
> also
> +automatically recognized as broker functions. Further functions might be
> added
> +in the future.
> +
> + .. code-block:: c
> +
> + __attribute__((callback (start_routine, arg)))
> + int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
> + void *(*start_routine) (void *), void *arg);
> +
> + __attribute__((callback (3, 4)))
> + int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
> + void *(*start_routine) (void *), void *arg);
> +
> + }];
> +}
> +
> def GnuInlineDocs : Documentation {
> let Category = DocCatFunction;
> let Content = [{
>
> Modified: cfe/trunk/include/clang/Basic/Builtins.def
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Builtins.def (original)
> +++ cfe/trunk/include/clang/Basic/Builtins.def Fri Jan 18 21:36:54 2019
> @@ -93,6 +93,8 @@
> // j -> returns_twice (like setjmp)
> // u -> arguments are not evaluated for their side-effects
> // V:N: -> requires vectors of at least N bits to be legal
> +// C<N,M_0,...,M_k> -> callback behavior: argument N is called with
> argument
> +// M_0, ..., M_k as payload
> // FIXME: gcc has nonnull
>
> #if defined(BUILTIN) && !defined(LIBBUILTIN)
> @@ -960,6 +962,9 @@ LIBBUILTIN(strncasecmp, "icC*cC*z", "f",
> // POSIX unistd.h
> LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_GNU_LANGUAGES)
> LIBBUILTIN(vfork, "p", "fj", "unistd.h", ALL_LANGUAGES)
> +// POSIX pthread.h
> +LIBBUILTIN(pthread_create, "", "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES)
> +
> // POSIX setjmp.h
>
> LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES)
>
> Modified: cfe/trunk/include/clang/Basic/Builtins.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.h?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Builtins.h (original)
> +++ cfe/trunk/include/clang/Basic/Builtins.h Fri Jan 18 21:36:54 2019
> @@ -194,6 +194,12 @@ public:
> /// argument and whether this function as a va_list argument.
> bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
>
> + /// Determine whether this builtin has callback behavior (see
> + /// llvm::AbstractCallSites for details). If so, add the index to the
> + /// callback callee argument and the callback payload arguments.
> + bool performsCallback(unsigned ID,
> + llvm::SmallVectorImpl<int> &Encoding) const;
> +
> /// Return true if this function has no side effects and doesn't
> /// read memory, except for possibly errno.
> ///
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 18
> 21:36:54 2019
> @@ -2578,6 +2578,20 @@ def err_format_attribute_result_not : Er
> def err_format_attribute_implicit_this_format_string : Error<
> "format attribute cannot specify the implicit this argument as the
> format "
> "string">;
> +def err_callback_attribute_no_callee : Error<
> + "'callback' attribute specifies no callback callee">;
> +def err_callback_attribute_invalid_callee : Error<
> + "'callback' attribute specifies invalid callback callee">;
> +def err_callback_attribute_multiple : Error<
> + "multiple 'callback' attributes specified">;
> +def err_callback_attribute_argument_unknown : Error<
> + "'callback' attribute argument %0 is not a known function parameter">;
> +def err_callback_callee_no_function_type : Error<
> + "'callback' attribute callee does not have function type">;
> +def err_callback_callee_is_variadic : Error<
> + "'callback' attribute callee may not be variadic">;
> +def err_callback_implicit_this_not_available : Error<
> + "'callback' argument at position %0 references unavailable implicit
> 'this'">;
> def err_init_method_bad_return_type : Error<
> "init methods must return an object pointer type, not %0">;
> def err_attribute_invalid_size : Error<
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jan 18 21:36:54 2019
> @@ -9518,6 +9518,10 @@ QualType ASTContext::GetBuiltinType(unsi
> GetBuiltinTypeError &Error,
> unsigned *IntegerConstantArgs) const {
> const char *TypeStr = BuiltinInfo.getTypeString(Id);
> + if (TypeStr[0] == '\0') {
> + Error = GE_Missing_type;
> + return {};
> + }
>
> SmallVector<QualType, 8> ArgTypes;
>
>
> Modified: cfe/trunk/lib/Basic/Builtins.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Builtins.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Basic/Builtins.cpp (original)
> +++ cfe/trunk/lib/Basic/Builtins.cpp Fri Jan 18 21:36:54 2019
> @@ -156,6 +156,33 @@ bool Builtin::Context::isScanfLike(unsig
> return isLike(ID, FormatIdx, HasVAListArg, "sS");
> }
>
> +bool Builtin::Context::performsCallback(unsigned ID,
> + SmallVectorImpl<int> &Encoding)
> const {
> + const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C');
> + if (!CalleePos)
> + return false;
> +
> + ++CalleePos;
> + assert(*CalleePos == '<' &&
> + "Callback callee specifier must be followed by a '<'");
> + ++CalleePos;
> +
> + char *EndPos;
> + int CalleeIdx = ::strtol(CalleePos, &EndPos, 10);
> + assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");
> + Encoding.push_back(CalleeIdx);
> +
> + while (*EndPos == ',') {
> + const char *PayloadPos = EndPos + 1;
> +
> + int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10);
> + Encoding.push_back(PayloadIdx);
> + }
> +
> + assert(*EndPos == '>' && "Callback callee specifier must end with a
> '>'");
> + return true;
> +}
> +
> bool Builtin::Context::canBeRedeclared(unsigned ID) const {
> return ID == Builtin::NotBuiltin ||
> ID == Builtin::BI__va_start ||
>
> Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Fri Jan 18 21:36:54 2019
> @@ -1677,6 +1677,22 @@ CGOpenMPRuntime::createRuntimeFunction(u
> auto *FnTy =
> llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/
> true);
> RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
> + if (auto *F = dyn_cast<llvm::Function>(RTLFn)) {
> + if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {
> + llvm::LLVMContext &Ctx = F->getContext();
> + llvm::MDBuilder MDB(Ctx);
> + // Annotate the callback behavior of the __kmpc_fork_call:
> + // - The callback callee is argument number 2 (microtask).
> + // - The first two arguments of the callback callee are unknown
> (-1).
> + // - All variadic arguments to the __kmpc_fork_call are passed
> to the
> + // callback callee.
> + F->addMetadata(
> + llvm::LLVMContext::MD_callback,
> + *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
> + 2, {-1, -1},
> + /* VarArgsArePassed */ true)}));
> + }
> + }
> break;
> }
> case OMPRTL__kmpc_global_thread_num: {
> @@ -2084,6 +2100,22 @@ CGOpenMPRuntime::createRuntimeFunction(u
> auto *FnTy =
> llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/
> true);
> RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_teams");
> + if (auto *F = dyn_cast<llvm::Function>(RTLFn)) {
> + if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {
> + llvm::LLVMContext &Ctx = F->getContext();
> + llvm::MDBuilder MDB(Ctx);
> + // Annotate the callback behavior of the __kmpc_fork_teams:
> + // - The callback callee is argument number 2 (microtask).
> + // - The first two arguments of the callback callee are unknown
> (-1).
> + // - All variadic arguments to the __kmpc_fork_teams are passed
> to the
> + // callback callee.
> + F->addMetadata(
> + llvm::LLVMContext::MD_callback,
> + *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
> + 2, {-1, -1},
> + /* VarArgsArePassed */ true)}));
> + }
> + }
> break;
> }
> case OMPRTL__kmpc_taskloop: {
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jan 18 21:36:54 2019
> @@ -1603,6 +1603,23 @@ void CodeGenModule::SetFunctionAttribute
>
> if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
> getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
> +
> + if (const auto *CB = FD->getAttr<CallbackAttr>()) {
> + // Annotate the callback behavior as metadata:
> + // - The callback callee (as argument number).
> + // - The callback payloads (as argument numbers).
> + llvm::LLVMContext &Ctx = F->getContext();
> + llvm::MDBuilder MDB(Ctx);
> +
> + // The payload indices are all but the first one in the encoding. The
> first
> + // identifies the callback callee.
> + int CalleeIdx = *CB->encoding_begin();
> + ArrayRef<int> PayloadIndices(CB->encoding_begin() + 1,
> CB->encoding_end());
> + F->addMetadata(llvm::LLVMContext::MD_callback,
> + *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
> + CalleeIdx, PayloadIndices,
> + /* VarArgsArePassed */
> false)}));
> + }
> }
>
> void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Jan 18 21:36:54 2019
> @@ -223,6 +223,15 @@ static bool attributeHasVariadicIdentifi
> #undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST
> }
>
> +/// Determine whether the given attribute treats kw_this as an identifier.
> +static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo
> &II) {
> +#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
> + return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
> +#include "clang/Parse/AttrParserStringSwitches.inc"
> + .Default(false);
> +#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST
> +}
> +
> /// Determine whether the given attribute parses a type argument.
> static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {
> #define CLANG_ATTR_TYPE_ARG_LIST
> @@ -287,6 +296,12 @@ unsigned Parser::ParseAttributeArgsCommo
> // Ignore the left paren location for now.
> ConsumeParen();
>
> + bool ChangeKWThisToIdent =
> attributeTreatsKeywordThisAsIdentifier(*AttrName);
> +
> + // Interpret "kw_this" as an identifier if the attributed requests it.
> + if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
> + Tok.setKind(tok::identifier);
> +
> ArgsVector ArgExprs;
> if (Tok.is(tok::identifier)) {
> // If this attribute wants an 'identifier' argument, make it so.
> @@ -314,6 +329,10 @@ unsigned Parser::ParseAttributeArgsCommo
>
> // Parse the non-empty comma-separated list of expressions.
> do {
> + // Interpret "kw_this" as an identifier if the attributed requests
> it.
> + if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
> + Tok.setKind(tok::identifier);
> +
> ExprResult ArgExpr;
> if (Tok.is(tok::identifier) &&
> attributeHasVariadicIdentifierArg(*AttrName)) {
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 18 21:36:54 2019
> @@ -1927,10 +1927,13 @@ static void LookupPredefedObjCSuperType(
> Context.setObjCSuperType(Context.getTagDeclType(TD));
> }
>
> -static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) {
> +static StringRef getHeaderName(Builtin::Context &BuiltinInfo, unsigned ID,
> + ASTContext::GetBuiltinTypeError Error) {
> switch (Error) {
> case ASTContext::GE_None:
> return "";
> + case ASTContext::GE_Missing_type:
> + return BuiltinInfo.getHeaderName(ID);
> case ASTContext::GE_Missing_stdio:
> return "stdio.h";
> case ASTContext::GE_Missing_setjmp:
> @@ -1955,7 +1958,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(Ide
> if (Error) {
> if (ForRedeclaration)
> Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
> - << getHeaderName(Error) << Context.BuiltinInfo.getName(ID);
> + << getHeaderName(Context.BuiltinInfo, ID, Error)
> + << Context.BuiltinInfo.getName(ID);
> return nullptr;
> }
>
> @@ -13580,6 +13584,13 @@ void Sema::AddKnownFunctionAttributes(Fu
> FD->getLocation()));
> }
>
> + // Handle automatically recognized callbacks.
> + SmallVector<int, 4> Encoding;
> + if (!FD->hasAttr<CallbackAttr>() &&
> + Context.BuiltinInfo.performsCallback(BuiltinID, Encoding))
> + FD->addAttr(CallbackAttr::CreateImplicit(
> + Context, Encoding.data(), Encoding.size(), FD->getLocation()));
> +
> // Mark const if we don't care about errno and that is the only thing
> // preventing the function from being const. This allows IRgen to use
> LLVM
> // intrinsics for such functions.
>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jan 18 21:36:54 2019
> @@ -3480,6 +3480,144 @@ static void handleFormatAttr(Sema &S, De
> D->addAttr(NewAttr);
> }
>
> +/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...)))
> attributes.
> +static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
> + // The index that identifies the callback callee is mandatory.
> + if (AL.getNumArgs() == 0) {
> + S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee)
> + << AL.getRange();
> + return;
> + }
> +
> + bool HasImplicitThisParam = isInstanceMethod(D);
> + int32_t NumArgs = getFunctionOrMethodNumParams(D);
> +
> + FunctionDecl *FD = D->getAsFunction();
> + assert(FD && "Expected a function declaration!");
> +
> + llvm::StringMap<int> NameIdxMapping;
> + NameIdxMapping["__"] = -1;
> +
> + NameIdxMapping["this"] = 0;
> +
> + int Idx = 1;
> + for (const ParmVarDecl *PVD : FD->parameters())
> + NameIdxMapping[PVD->getName()] = Idx++;
> +
> + auto UnknownName = NameIdxMapping.end();
> +
> + SmallVector<int, 8> EncodingIndices;
> + for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) {
> + SourceRange SR;
> + int32_t ArgIdx;
> +
> + if (AL.isArgIdent(I)) {
> + IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
> + auto It = NameIdxMapping.find(IdLoc->Ident->getName());
> + if (It == UnknownName) {
> + S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)
> + << IdLoc->Ident << IdLoc->Loc;
> + return;
> + }
> +
> + SR = SourceRange(IdLoc->Loc);
> + ArgIdx = It->second;
> + } else if (AL.isArgExpr(I)) {
> + Expr *IdxExpr = AL.getArgAsExpr(I);
> +
> + // If the expression is not parseable as an int32_t we have a
> problem.
> + if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
> + false)) {
> + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
> + << AL << (I + 1) << IdxExpr->getSourceRange();
> + return;
> + }
> +
> + // Check oob, excluding the special values, 0 and -1.
> + if (ArgIdx < -1 || ArgIdx > NumArgs) {
> + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
> + << AL << (I + 1) << IdxExpr->getSourceRange();
> + return;
> + }
> +
> + SR = IdxExpr->getSourceRange();
> + } else {
> + llvm_unreachable("Unexpected ParsedAttr argument type!");
> + }
> +
> + if (ArgIdx == 0 && !HasImplicitThisParam) {
> + S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available)
> + << (I + 1) << SR;
> + return;
> + }
> +
> + // Adjust for the case we do not have an implicit "this" parameter.
> In this
> + // case we decrease all positive values by 1 to get LLVM argument
> indices.
> + if (!HasImplicitThisParam && ArgIdx > 0)
> + ArgIdx -= 1;
> +
> + EncodingIndices.push_back(ArgIdx);
> + }
> +
> + int CalleeIdx = EncodingIndices.front();
> + // Check if the callee index is proper, thus not "this" and not
> "unknown".
> + if (CalleeIdx < HasImplicitThisParam) {
> + S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee)
> + << AL.getRange();
> + return;
> + }
> +
> + // Get the callee type, note the index adjustment as the AST doesn't
> contain
> + // the this type (which the callee cannot reference anyway!).
> + const Type *CalleeType =
> + getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam)
> + .getTypePtr();
> + if (!CalleeType || !CalleeType->isFunctionPointerType()) {
> + S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
> + << AL.getRange();
> + return;
> + }
> +
> + const Type *CalleeFnType =
> + CalleeType->getPointeeType()->getUnqualifiedDesugaredType();
> +
> + // TODO: Check the type of the callee arguments.
> +
> + const auto *CalleeFnProtoType =
> dyn_cast<FunctionProtoType>(CalleeFnType);
> + if (!CalleeFnProtoType) {
> + S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
> + << AL.getRange();
> + return;
> + }
> +
> + if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) {
> + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
> + << AL << (unsigned)(EncodingIndices.size() - 1);
> + return;
> + }
> +
> + if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {
> + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
> + << AL << (unsigned)(EncodingIndices.size() - 1);
> + return;
> + }
> +
> + if (CalleeFnProtoType->isVariadic()) {
> + S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) <<
> AL.getRange();
> + return;
> + }
> +
> + // Do not allow multiple callback attributes.
> + if (D->hasAttr<CallbackAttr>()) {
> + S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) <<
> AL.getRange();
> + return;
> + }
> +
> + D->addAttr(::new (S.Context) CallbackAttr(
> + AL.getRange(), S.Context, EncodingIndices.data(),
> EncodingIndices.size(),
> + AL.getAttributeSpellingListIndex()));
> +}
> +
> static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr
> &AL) {
> // Try to find the underlying union declaration.
> RecordDecl *RD = nullptr;
> @@ -6451,6 +6589,9 @@ static void ProcessDeclAttribute(Sema &S
> case ParsedAttr::AT_FormatArg:
> handleFormatArgAttr(S, D, AL);
> break;
> + case ParsedAttr::AT_Callback:
> + handleCallbackAttr(S, D, AL);
> + break;
> case ParsedAttr::AT_CUDAGlobal:
> handleGlobalAttr(S, D, AL);
> break;
>
> Modified: cfe/trunk/test/Analysis/retain-release.m
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Analysis/retain-release.m (original)
> +++ cfe/trunk/test/Analysis/retain-release.m Fri Jan 18 21:36:54 2019
> @@ -2,7 +2,7 @@
> // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
> // RUN: -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
> // RUN:
> -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\
> -// RUN: -analyzer-checker=debug.ExprInspection -fblocks -verify %s\
> +// RUN: -analyzer-checker=debug.ExprInspection -fblocks
> -verify=expected,C %s\
> // RUN: -Wno-objc-root-class -analyzer-output=plist -o %t.objc.plist
> // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
> // RUN: -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
> @@ -1202,7 +1202,7 @@ typedef __darwin_pthread_attr_t pthread_
> typedef unsigned long __darwin_pthread_key_t;
> typedef __darwin_pthread_key_t pthread_key_t;
>
> -int pthread_create(pthread_t *, const pthread_attr_t *,
> +int pthread_create(pthread_t *, const pthread_attr_t *, //
> C-warning{{declaration of built-in function 'pthread_create' requires
> inclusion of the header <pthread.h>}}
> void *(*)(void *), void *);
>
> int pthread_setspecific(pthread_key_t key, const void *value);
>
> Added: cfe/trunk/test/CodeGen/attr-callback.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attr-callback.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/attr-callback.c (added)
> +++ cfe/trunk/test/CodeGen/attr-callback.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,28 @@
> +// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - |
> FileCheck %s
> +
> +void cb0(void);
> +
> +// CHECK-DAG: !callback ![[cid0:[0-9]+]] void @no_args
> +__attribute__((callback(1))) void no_args(void (*callback)(void));
> +
> +// CHECK-DAG: @args_1({{[^#]*#[0-9]+}} !callback ![[cid1:[0-9]+]]
> +__attribute__((callback(1, 2, 3))) void args_1(void (*callback)(int,
> double), int a, double b) { no_args(cb0); }
> +
> +// CHECK-DAG: !callback ![[cid2:[0-9]+]] void @args_2a
> +__attribute__((callback(2, 3, 3))) void args_2a(int a, void
> (*callback)(double, double), double b);
> +// CHECK-DAG: !callback ![[cid2]] void @args_2b
> +__attribute__((callback(callback, b, b))) void args_2b(int a, void
> (*callback)(double, double), double b);
> +
> +// CHECK-DAG: void @args_3a({{[^#]*#[0-9]+}} !callback ![[cid3:[0-9]+]]
> +__attribute__((callback(2, -1, -1))) void args_3a(int a, void
> (*callback)(double, double), double b) { args_2a(a, callback, b); }
> +// CHECK-DAG: void @args_3b({{[^#]*#[0-9]+}} !callback ![[cid3]]
> +__attribute__((callback(callback, __, __))) void args_3b(int a, void
> (*callback)(double, double), double b) { args_2b(a, callback, b); }
> +
> +// CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}
> +// CHECK-DAG: ![[cid0b]] = !{i64 0, i1 false}
> +// CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}
> +// CHECK-DAG: ![[cid1b]] = !{i64 0, i64 1, i64 2, i1 false}
> +// CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}
> +// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 2, i64 2, i1 false}
> +// CHECK-DAG: ![[cid3]] = !{![[cid3b:[0-9]+]]}
> +// CHECK-DAG: ![[cid3b]] = !{i64 1, i64 -1, i64 -1, i1 false}
>
> Added: cfe/trunk/test/CodeGen/callback_annotated.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_annotated.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/callback_annotated.c (added)
> +++ cfe/trunk/test/CodeGen/callback_annotated.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,73 @@
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s
> -emit-llvm -o - | FileCheck %s --check-prefix=RUN1
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s
> -emit-llvm -o - | FileCheck %s --check-prefix=RUN2
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s
> -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s
> +
> +// RUN1-DAG: @broker0({{[^#]*#[0-9]+}} !callback ![[cid0:[0-9]+]]
> +__attribute__((callback(1, 2))) void *broker0(void *(*callee)(void *),
> void *payload) {
> + return callee(payload);
> +}
> +
> +// RUN1-DAG: @broker1({{[^#]*#[0-9]+}} !callback ![[cid1:[0-9]+]]
> +__attribute__((callback(callee, payload))) void *broker1(void *payload,
> void *(*callee)(void *)) {
> + return broker0(callee, payload);
> +}
> +
> +void *broker2(void (*callee)(void));
> +
> +// RUN1-DAG: declare !callback ![[cid2:[0-9]+]] i8* @broker2
> +__attribute__((callback(callee))) void *broker2(void (*callee)(void));
> +
> +void *broker2(void (*callee)(void));
> +
> +// RUN1-DAG: declare !callback ![[cid3:[0-9]+]] i8* @broker3
> +__attribute__((callback(4, 1, 2, c))) void *broker3(int, int, int c, int
> (*callee)(int, int, int), int);
> +
> +// RUN1-DAG: declare !callback ![[cid4:[0-9]+]] i8* @broker4
> +__attribute__((callback(4, -1, a, __))) void *broker4(int a, int, int,
> int (*callee)(int, int, int), int);
> +
> +// RUN1-DAG: declare !callback ![[cid5:[0-9]+]] i8* @broker5
> +__attribute__((callback(4, d, 5, 2))) void *broker5(int, int, int, int
> (*callee)(int, int, int), int d);
> +
> +static void *VoidPtr2VoidPtr(void *payload) {
> + // RUN2: ret i8* %payload
> + // IPCP: ret i8* null
> + return payload;
> +}
> +
> +static int ThreeInt2Int(int a, int b, int c) {
> + // RUN2: define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c)
> + // RUN2-NEXT: entry:
> + // RUN2-NEXT: %mul = mul nsw i32 %b, %a
> + // RUN2-NEXT: %add = add nsw i32 %mul, %c
> + // RUN2-NEXT: ret i32 %add
> +
> + // IPCP: define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c)
> + // IPCP-NEXT: entry:
> + // IPCP-NEXT: %mul = mul nsw i32 4, %a
> + // IPCP-NEXT: %add = add nsw i32 %mul, %c
> + // IPCP-NEXT: ret i32 %add
> +
> + return a * b + c;
> +}
> +
> +void foo() {
> + broker0(VoidPtr2VoidPtr, 0l);
> + broker1(0l, VoidPtr2VoidPtr);
> + broker2(foo);
> + broker3(1, 4, 5, ThreeInt2Int, 1);
> + broker4(4, 2, 7, ThreeInt2Int, 0);
> + broker5(8, 0, 3, ThreeInt2Int, 4);
> +}
> +
> +// RUN1-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}
> +// RUN1-DAG: ![[cid0b]] = !{i64 0, i64 1, i1 false}
> +// RUN1-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}
> +// RUN1-DAG: ![[cid1b]] = !{i64 1, i64 0, i1 false}
> +// RUN1-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}
> +// RUN1-DAG: ![[cid2b]] = !{i64 0, i1 false}
> +// RUN1-DAG: ![[cid3]] = !{![[cid3b:[0-9]+]]}
> +// RUN1-DAG: ![[cid3b]] = !{i64 3, i64 0, i64 1, i64 2, i1 false}
> +// RUN1-DAG: ![[cid4]] = !{![[cid4b:[0-9]+]]}
> +// RUN1-DAG: ![[cid4b]] = !{i64 3, i64 -1, i64 0, i64 -1, i1 false}
> +// RUN1-DAG: ![[cid5]] = !{![[cid5b:[0-9]+]]}
> +// RUN1-DAG: ![[cid5b]] = !{i64 3, i64 4, i64 4, i64 1, i1 false}
>
> Added: cfe/trunk/test/CodeGen/callback_openmp.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_openmp.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/callback_openmp.c (added)
> +++ cfe/trunk/test/CodeGen/callback_openmp.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,28 @@
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s
> -emit-llvm -o - | FileCheck %s
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s
> -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s
> +
> +// CHECK: declare !callback ![[cid:[0-9]+]] void @__kmpc_fork_call
> +// CHECK: declare !callback ![[cid]] void @__kmpc_fork_teams
> +// CHECK: ![[cid]] = !{![[cidb:[0-9]+]]}
> +// CHECK: ![[cidb]] = !{i64 2, i64 -1, i64 -1, i1 true}
> +
> +void work1(int, int);
> +void work2(int, int);
> +void work12(int, int);
> +
> +void foo(int q) {
> + int p = 2;
> +
> + #pragma omp parallel firstprivate(q, p)
> + work1(p, q);
> +// IPCP: call void @work1(i32 2, i32 %{{[._a-zA-Z0-9]*}})
> +
> + #pragma omp parallel for firstprivate(p, q)
> + for (int i = 0; i < q; i++)
> + work2(i, p);
> +// IPCP: call void @work2(i32 %{{[._a-zA-Z0-9]*}}, i32 2)
> +
> + #pragma omp target teams firstprivate(p)
> + work12(p, p);
> +// IPCP: call void @work12(i32 2, i32 2)
> +}
>
> Added: cfe/trunk/test/CodeGen/callback_pthread_create.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_pthread_create.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/callback_pthread_create.c (added)
> +++ cfe/trunk/test/CodeGen/callback_pthread_create.c Fri Jan 18 21:36:54
> 2019
> @@ -0,0 +1,32 @@
> +// RUN: %clang -O1 %s -S -c -emit-llvm -o - | FileCheck %s
> +// RUN: %clang -O1 %s -S -c -emit-llvm -o - | opt -ipconstprop -S |
> FileCheck --check-prefix=IPCP %s
> +
> +// CHECK: declare !callback ![[cid:[0-9]+]] dso_local i32 @pthread_create
> +// CHECK: ![[cid]] = !{![[cidb:[0-9]+]]}
> +// CHECK: ![[cidb]] = !{i64 2, i64 3, i1 false}
> +
> +#include <pthread.h>
Another thing I notecide is that this code assumes the system has
`pthread.h` -- what about systems without it? I mean, you can disable the
test, but it seems bad to lose test coverage just because of that.
I would much prefer that you provide your own stub `pthread.h` in the
Inputs/... tree of the test suite and use that to test this in a portable
way.
-Chandler
> +
> +const int GlobalVar = 0;
> +
> +static void *callee0(void *payload) {
> +// IPCP: define internal i8* @callee0
> +// IPCP-NEXT: entry:
> +// IPCP-NEXT: ret i8* null
> + return payload;
> +}
> +
> +static void *callee1(void *payload) {
> +// IPCP: define internal i8* @callee1
> +// IPCP-NEXT: entry:
> +// IPCP-NEXT: ret i8* bitcast (i32* @GlobalVar to i8*)
> + return payload;
> +}
> +
> +void foo() {
> + pthread_t MyFirstThread;
> + pthread_create(&MyFirstThread, NULL, callee0, NULL);
> +
> + pthread_t MySecondThread;
> + pthread_create(&MySecondThread, NULL, callee1, (void *)&GlobalVar);
> +}
>
> Added: cfe/trunk/test/CodeGenCXX/attr-callback.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-callback.cpp?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/attr-callback.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/attr-callback.cpp Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,55 @@
> +// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - |
> FileCheck %s
> +
> +struct Base {
> +
> + void no_args_1(void (*callback)(void));
> + __attribute__((callback(1))) void no_args_2(void (*callback1)(void),
> void (*callback2)(void));
> + __attribute__((callback(callback1))) void no_args_3(void
> (*callback1)(void), void (*callback2)(void));
> +
> + // TODO: There should probably be a warning or even an error for
> different
> + // callbacks on the same method.
> + __attribute__((callback(1))) virtual void
> + virtual_1(void (*callback)(void));
> +
> + __attribute__((callback(callback, this, __, this))) virtual void
> + this_unknown_this(void (*callback)(Base *, Base *, Base *));
> +};
> +
> +// CHECK-DAG: define void
> @_ZN4Base9no_args_1EPFvvE({{[^!]*!callback}} ![[cid0:[0-9]+]]
> +__attribute__((callback(1))) void
> +Base::no_args_1(void (*callback)(void)) {
> +}
> +
> +// CHECK-DAG: define void
> @_ZN4Base9no_args_2EPFvvES1_({{[^!]*!callback}} ![[cid1:[0-9]+]]
> +__attribute__((callback(2))) void Base::no_args_2(void
> (*callback1)(void), void (*callback2)(void)) {
> +}
> +// CHECK-DAG: define void
> @_ZN4Base9no_args_3EPFvvES1_({{[^!]*!callback}} ![[cid1]]
> +__attribute__((callback(callback2))) void Base::no_args_3(void
> (*callback1)(void), void (*callback2)(void)) {
> +}
> +
> +// CHECK-DAG: define void
> @_ZN4Base17this_unknown_thisEPFvPS_S0_S0_E({{[^!]*!callback}}
> ![[cid2:[0-9]+]]
> +void Base::this_unknown_this(void (*callback)(Base *, Base *, Base *)) {
> +}
> +
> +struct Derived_1 : public Base {
> + __attribute__((callback(1))) virtual void
> + virtual_1(void (*callback)(void)) override;
> +};
> +
> +// CHECK-DAG: define void
> @_ZN9Derived_19virtual_1EPFvvE({{[^!]*!callback}} ![[cid0]]
> +void Derived_1::virtual_1(void (*callback)(void)) {}
> +
> +struct Derived_2 : public Base {
> + void virtual_1(void (*callback)(void)) override;
> +};
> +
> +// CHECK-DAG: define void @_ZN9Derived_29virtual_1EPFvvE
> +// CHECK-NOT: !callback
> +void Derived_2::virtual_1(void (*callback)(void)) {}
> +
> +// CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}
> +// CHECK-DAG: ![[cid0b]] = !{i64 1, i1 false}
> +// CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}
> +// CHECK-DAG: ![[cid1b]] = !{i64 2, i1 false}
> +// CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}
> +// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 0, i64 -1, i64 0, i1 false}
>
> Modified:
> cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> (original)
> +++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test
> Fri Jan 18 21:36:54 2019
> @@ -32,6 +32,7 @@
> // CHECK-NEXT: CUDAShared (SubjectMatchRule_variable)
> // CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)
> // CHECK-NEXT: CallableWhen (SubjectMatchRule_function_is_member)
> +// CHECK-NEXT: Callback (SubjectMatchRule_function)
> // CHECK-NEXT: Capability (SubjectMatchRule_record,
> SubjectMatchRule_type_alias)
> // CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter,
> SubjectMatchRule_objc_method, SubjectMatchRule_function)
> // CHECK-NEXT: Cold (SubjectMatchRule_function)
>
> Modified: cfe/trunk/test/OpenMP/parallel_codegen.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_codegen.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/OpenMP/parallel_codegen.cpp (original)
> +++ cfe/trunk/test/OpenMP/parallel_codegen.cpp Fri Jan 18 21:36:54 2019
> @@ -82,9 +82,9 @@ int main (int argc, char **argv) {
> // CHECK-DEBUG-NEXT: }
>
> // CHECK-DAG: define linkonce_odr {{.*}}void [[FOO]]({{i32[ ]?[a-z]*}}
> %argc)
> -// CHECK-DAG: declare {{.*}}void @__kmpc_fork_call(%struct.ident_t*, i32,
> void (i32*, i32*, ...)*, ...)
> +// CHECK-DAG: declare !callback ![[cbid:[0-9]+]] {{.*}}void
> @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
> // CHECK-DEBUG-DAG: define linkonce_odr void [[FOO]](i32 %argc)
> -// CHECK-DEBUG-DAG: declare void @__kmpc_fork_call(%struct.ident_t*, i32,
> void (i32*, i32*, ...)*, ...)
> +// CHECK-DEBUG-DAG: declare !callback ![[cbid:[0-9]+]] void
> @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
> // CHECK-DEBUG-DAG: define internal void [[OMP_OUTLINED]](i32*
> noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]],
> i32* {{.+}} [[VLA_ADDR:%[^)]+]])
> // CHECK-DEBUG-DAG: call void [[OMP_OUTLINED_DEBUG]]
>
> @@ -131,5 +131,6 @@ int main (int argc, char **argv) {
>
> // CHECK: attributes #[[FN_ATTRS]] = {{.+}} nounwind
> // CHECK-DEBUG: attributes #[[FN_ATTRS]] = {{.+}} nounwind
> -
> +// CHECK: ![[cbid]] = !{![[cbidb:[0-9]+]]}
> +// CHECK: ![[cbidb]] = !{i64 2, i64 -1, i64 -1, i1 true}
> #endif
>
> Added: cfe/trunk/test/Sema/attr-callback-broken.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback-broken.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Sema/attr-callback-broken.c (added)
> +++ cfe/trunk/test/Sema/attr-callback-broken.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,75 @@
> +// RUN: %clang_cc1 %s -verify -fsyntax-only
> +
> +__attribute__((callback())) void no_callee(void (*callback)(void)); //
> expected-error {{'callback' attribute specifies no callback callee}}
> +
> +__attribute__((callback(1, 1))) void too_many_args_1(void
> (*callback)(void)) {} // expected-error {{'callback' attribute takes
> one argument}}
> +__attribute__((callback(1, -1))) void too_many_args_2(double
> (*callback)(void)); // expected-error {{'callback' attribute takes one
> argument}}
> +__attribute__((callback(1, 2, 2))) void too_many_args_3(void
> (*callback)(int), int); // expected-error {{'callback' attribute requires
> exactly 2 arguments}}
> +
> +__attribute__((callback(1, 2))) void too_few_args_1(void (*callback)(int,
> int), int); // expected-error {{'callback' attribute takes one argument}}
> +__attribute__((callback(1))) void too_few_args_2(int (*callback)(int));
> // expected-error {{'callback' attribute takes no arguments}}
> +__attribute__((callback(1, -1))) void too_few_args_3(void
> (*callback)(int, int)) {} // expected-error {{'callback' attribute takes
> one argument}}
> +
> +__attribute__((callback(-1))) void oob_args_1(void (*callback)(void));
> // expected-error {{'callback' attribute specifies invalid callback
> callee}}
> +__attribute__((callback(2))) void oob_args_2(int *(*callback)(void)) {}
> // expected-error {{'callback' attribute parameter 1 is out of
> bounds}}
> +__attribute__((callback(1, 3))) void oob_args_3(short (*callback)(int),
> int); // expected-error {{'callback' attribute parameter 2 is out of
> bounds}}
> +__attribute__((callback(-2, 2))) void oob_args_4(void *(*callback)(int),
> int); // expected-error {{'callback' attribute parameter 1 is out of
> bounds}}
> +__attribute__((callback(1, -2))) void oob_args_5(void *(*callback)(int),
> int); // expected-error {{'callback' attribute parameter 2 is out of
> bounds}}
> +__attribute__((callback(1, 2))) void oob_args_6(void *(*callback)(int),
> ...); // expected-error {{'callback' attribute parameter 2 is out of
> bounds}}
> +
> +__attribute__((callback(1))) __attribute__((callback(1))) void
> multiple_cb_1(void (*callback)(void)); //
> expected-error {{multiple 'callback' attributes specified}}
> +__attribute__((callback(1))) __attribute__((callback(2))) void
> multiple_cb_2(void (*callback1)(void), void (*callback2)(void)); //
> expected-error {{multiple 'callback' attributes specified}}
> +
> +#ifdef HAS_THIS
> +__attribute__((callback(0))) void oob_args_0(void (*callback)(void)); //
> expected-error {{'callback' attribute specifies invalid callback callee}}
> +#else
> +__attribute__((callback(0))) void oob_args_0(void (*callback)(void));
> // expected-error {{'callback' argument at position 1
> references unavailable implicit 'this'}}
> +__attribute__((callback(1, 0))) void no_this_1(void *(*callback)(void
> *)); // expected-error {{'callback' argument at position 2
> references unavailable implicit 'this'}}
> +__attribute__((callback(1, 0))) void no_this_2(void *(*callback)(int,
> void *)); // expected-error {{'callback' argument at position 2
> references unavailable implicit 'this'}}
> +#endif
> +
> +// We could allow the following declarations if we at some point need to:
> +
> +__attribute__((callback(1, -1))) void vararg_cb_1(void (*callback)(int,
> ...)) {} // expected-error {{'callback' attribute callee may not be
> variadic}}
> +__attribute__((callback(1, 1))) void vararg_cb_2(void (*callback)(int,
> ...), int a); // expected-error {{'callback' attribute callee may not be
> variadic}}
> +
> +__attribute__((callback(1, -1, 1, 2, 3, 4, -1))) void varargs_1(void
> (*callback)(int, ...), int a, float b, double c) {} //
> expected-error {{'callback' attribute requires exactly 6 arguments}}
> +__attribute__((callback(1, -1, 4, 2, 3, 4, -1))) void varargs_2(void
> (*callback)(void *, double, int, ...), int a, float b, double c); //
> expected-error {{'callback' attribute requires exactly 6 arguments}}
> +
> +__attribute__((callback(1, -1, 1))) void self_arg_1(void (*callback)(int,
> ...)) {} // expected-error {{'callback' attribute requires exactly
> 2 arguments}}
> +__attribute__((callback(1, -1, 1, -1, -1, 1))) void self_arg_2(void
> (*callback)(int, ...)); // expected-error {{'callback' attribute requires
> exactly 5 arguments}}
> +
> +__attribute__((callback(cb))) void unknown_name1(void (*callback)(void))
> {} // expected-error {{'callback' attribute argument 'cb' is not a
> known function parameter}}
> +__attribute__((callback(cb, ab))) void unknown_name2(void (*cb)(int), int
> a) {} // expected-error {{'callback' attribute argument 'ab' is not a known
> function parameter}}
> +
> +__attribute__((callback(callback, 1))) void too_many_args_1b(void
> (*callback)(void)) {} // expected-error {{'callback' attribute takes
> one argument}}
> +__attribute__((callback(callback, __))) void too_many_args_2b(double
> (*callback)(void)); // expected-error {{'callback' attribute takes one
> argument}}
> +__attribute__((callback(callback, 2, 2))) void too_many_args_3b(void
> (*callback)(int), int); // expected-error {{'callback' attribute requires
> exactly 2 arguments}}
> +
> +__attribute__((callback(callback, a))) void too_few_args_1b(void
> (*callback)(int, int), int a); // expected-error {{'callback' attribute
> takes one argument}}
> +__attribute__((callback(callback))) void too_few_args_2b(int
> (*callback)(int)); // expected-error {{'callback' attribute
> takes no arguments}}
> +__attribute__((callback(callback, __))) void too_few_args_3b(void
> (*callback)(int, int)) {} // expected-error {{'callback' attribute
> takes one argument}}
> +
> +__attribute__((callback(__))) void oob_args_1b(void (*callback)(void));
> // expected-error {{'callback' attribute specifies invalid callback callee}}
> +
> +__attribute__((callback(callback))) __attribute__((callback(callback)))
> void multiple_cb_1b(void (*callback)(void)); //
> expected-error {{multiple 'callback' attributes specified}}
> +__attribute__((callback(1))) __attribute__((callback(callback2))) void
> multiple_cb_2b(void (*callback1)(void), void (*callback2)(void)); //
> expected-error {{multiple 'callback' attributes specified}}
> +
> +#ifdef HAS_THIS
> +__attribute__((callback(this))) void oob_args_0b(void (*callback)(void));
> // expected-error {{'callback' attribute specifies invalid callback callee}}
> +#else
> +__attribute__((callback(this))) void oob_args_0b(void
> (*callback)(void)); // expected-error {{'callback' argument at
> position 1 references unavailable implicit 'this'}}
> +__attribute__((callback(1, this))) void no_this_1b(void *(*callback)(void
> *)); // expected-error {{'callback' argument at position 2 references
> unavailable implicit 'this'}}
> +__attribute__((callback(1, this))) void no_this_2b(void *(*callback)(int,
> void *)); // expected-error {{'callback' argument at position 2 references
> unavailable implicit 'this'}}
> +#endif
> +
> +// We could allow the following declarations if we at some point need to:
> +
> +__attribute__((callback(callback, __))) void vararg_cb_1b(void
> (*callback)(int, ...)) {} // expected-error {{'callback' attribute callee
> may not be variadic}}
> +__attribute__((callback(1, a))) void vararg_cb_2b(void (*callback)(int,
> ...), int a); // expected-error {{'callback' attribute callee may not be
> variadic}}
> +
> +__attribute__((callback(callback, __, callback, a, b, c, __))) void
> varargs_1b(void (*callback)(int, ...), int a, float b, double c) {} //
> expected-error {{'callback' attribute requires exactly 6 arguments}}
> +__attribute__((callback(1, __, c, a, b, c, -1))) void varargs_2b(void
> (*callback)(void *, double, int, ...), int a, float b, double c); //
> expected-error {{'callback' attribute requires exactly 6 arguments}}
> +
> +__attribute__((callback(1, __, callback))) void self_arg_1b(void
> (*callback)(int, ...)) {} // expected-error
> {{'callback' attribute requires exactly 2 arguments}}
> +__attribute__((callback(callback, __, callback, __, __, callback))) void
> self_arg_2b(void (*callback)(int, ...)); // expected-error {{'callback'
> attribute requires exactly 5 arguments}}
>
> Added: cfe/trunk/test/Sema/attr-callback.c
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback.c?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/Sema/attr-callback.c (added)
> +++ cfe/trunk/test/Sema/attr-callback.c Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,14 @@
> +// RUN: %clang_cc1 %s -verify -fsyntax-only
> +
> +// expected-no-diagnostics
> +
> +__attribute__((callback(1))) void no_args(void (*callback)(void));
> +__attribute__((callback(1, 2, 3))) void args_1(void (*callback)(int,
> double), int a, double b);
> +__attribute__((callback(2, 3, 3))) void args_2(int a, void
> (*callback)(double, double), double b);
> +__attribute__((callback(2, -1, -1))) void args_3(int a, void
> (*callback)(double, double), double b);
> +
> +__attribute__((callback(callback))) void no_argsb(void (*callback)(void));
> +__attribute__((callback(callback, a, 3))) void args_1b(void
> (*callback)(int, double), int a, double b);
> +__attribute__((callback(callback, b, b))) void args_2b(int a, void
> (*callback)(double, double), double b);
> +__attribute__((callback(2, __, __))) void args_3b(int a, void
> (*callback)(double, double), double b);
> +__attribute__((callback(callback, -1, __))) void args_3c(int a, void
> (*callback)(double, double), double b);
>
> Added: cfe/trunk/test/SemaCXX/attr-callback-broken.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback-broken.cpp?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-callback-broken.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-callback-broken.cpp Fri Jan 18 21:36:54
> 2019
> @@ -0,0 +1,7 @@
> +// RUN: %clang_cc1 %s -verify -fsyntax-only
> +
> +class C_in_class {
> +#define HAS_THIS
> +#include "../Sema/attr-callback-broken.c"
> +#undef HAS_THIS
> +};
>
> Added: cfe/trunk/test/SemaCXX/attr-callback.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback.cpp?rev=351629&view=auto
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/attr-callback.cpp (added)
> +++ cfe/trunk/test/SemaCXX/attr-callback.cpp Fri Jan 18 21:36:54 2019
> @@ -0,0 +1,67 @@
> +// RUN: %clang_cc1 %s -verify -fsyntax-only
> +
> +// expected-no-diagnostics
> +
> +class C_in_class {
> +#include "../Sema/attr-callback.c"
> +};
> +
> +struct Base {
> +
> + void no_args_1(void (*callback)(void));
> + __attribute__((callback(1))) void no_args_2(void (*callback)(void));
> + __attribute__((callback(callback))) void no_args_3(void
> (*callback)(void)) {}
> +
> + __attribute__((callback(1, 0))) virtual void
> + this_tr(void (*callback)(Base *));
> +
> + __attribute__((callback(1, this, __, this))) virtual void
> + this_unknown_this(void (*callback)(Base *, Base *, Base *));
> +
> + __attribute__((callback(1))) virtual void
> + virtual_1(void (*callback)(void));
> +
> + __attribute__((callback(callback))) virtual void
> + virtual_2(void (*callback)(void));
> +
> + __attribute__((callback(1))) virtual void
> + virtual_3(void (*callback)(void));
> +};
> +
> +__attribute__((callback(1))) void
> +Base::no_args_1(void (*callback)(void)) {
> +}
> +
> +void Base::no_args_2(void (*callback)(void)) {
> +}
> +
> +struct Derived_1 : public Base {
> +
> + __attribute__((callback(1, 0))) virtual void
> + this_tr(void (*callback)(Base *)) override;
> +
> + __attribute__((callback(1))) virtual void
> + virtual_1(void (*callback)(void)) override {}
> +
> + virtual void
> + virtual_3(void (*callback)(void)) override {}
> +};
> +
> +struct Derived_2 : public Base {
> +
> + __attribute__((callback(callback))) virtual void
> + virtual_1(void (*callback)(void)) override;
> +
> + virtual void
> + virtual_2(void (*callback)(void)) override;
> +
> + virtual void
> + virtual_3(void (*callback)(void)) override;
> +};
> +
> +void Derived_2::virtual_1(void (*callback)(void)) {}
> +
> +__attribute__((callback(1))) void
> +Derived_2::virtual_2(void (*callback)(void)) {}
> +
> +void Derived_2::virtual_3(void (*callback)(void)) {}
>
> Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=351629&r1=351628&r2=351629&view=diff
>
> ==============================================================================
> --- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)
> +++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Jan 18 21:36:54 2019
> @@ -776,6 +776,11 @@ namespace {
> }
> };
>
> + struct VariadicParamOrParamIdxArgument : public VariadicArgument {
> + VariadicParamOrParamIdxArgument(const Record &Arg, StringRef Attr)
> + : VariadicArgument(Arg, Attr, "int") {}
> + };
> +
> // Unique the enums, but maintain the original declaration ordering.
> std::vector<StringRef>
> uniqueEnumsInOrder(const std::vector<StringRef> &enums) {
> @@ -1284,6 +1289,8 @@ createArgument(const Record &Arg, String
> Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
> else if (ArgName == "VariadicParamIdxArgument")
> Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr);
> + else if (ArgName == "VariadicParamOrParamIdxArgument")
> + Ptr = llvm::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr);
> else if (ArgName == "ParamIdxArgument")
> Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx");
> else if (ArgName == "VariadicIdentifierArgument")
> @@ -2117,6 +2124,7 @@ static bool isVariadicIdentifierArgument
> llvm::StringSwitch<bool>(
> Arg->getSuperClasses().back().first->getName())
> .Case("VariadicIdentifierArgument", true)
> + .Case("VariadicParamOrParamIdxArgument", true)
> .Default(false);
> }
>
> @@ -2159,6 +2167,34 @@ static void emitClangAttrIdentifierArgLi
> OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n";
> }
>
> +static bool keywordThisIsaIdentifierInArgument(const Record *Arg) {
> + return !Arg->getSuperClasses().empty() &&
> + llvm::StringSwitch<bool>(
> + Arg->getSuperClasses().back().first->getName())
> + .Case("VariadicParamOrParamIdxArgument", true)
> + .Default(false);
> +}
> +
> +static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,
> + raw_ostream &OS) {
> + OS << "#if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)\n";
> + std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
> + for (const auto *A : Attrs) {
> + // Determine whether the first argument is a variadic identifier.
> + std::vector<Record *> Args = A->getValueAsListOfDefs("Args");
> + if (Args.empty() || !keywordThisIsaIdentifierInArgument(Args[0]))
> + continue;
> +
> + // All these spellings take an identifier argument.
> + forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) {
> + OS << ".Case(\"" << S.name() << "\", "
> + << "true"
> + << ")\n";
> + });
> + }
> + OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";
> +}
> +
> namespace clang {
>
> // Emits the class definitions for attributes.
> @@ -3767,6 +3803,7 @@ void EmitClangAttrParserStringSwitches(R
> emitClangAttrArgContextList(Records, OS);
> emitClangAttrIdentifierArgList(Records, OS);
> emitClangAttrVariadicIdentifierArgList(Records, OS);
> + emitClangAttrThisIsaIdentifierArgList(Records, OS);
> emitClangAttrTypeArgList(Records, OS);
> emitClangAttrLateParsedList(Records, OS);
> }
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20190122/d298f765/attachment-0001.html>
More information about the cfe-commits
mailing list