r351629 - Emit !callback metadata and introduce the callback attribute
Chandler Carruth via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 22 02:50:18 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>
> +
> +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"
>
I really don't like this pattern of including from one directory of the
test suite to the others.
For example, we use a distributed build system and it makes it nearly
impossible to determine what the inputs are to a test.
But beyond this, I think it would be very confusing in the C-only test case
to have to be aware of this strange re-use here. Plus, the -verify behavior
seems quite surprising here....
Generally, I would just directly write the test case you want here rather
than trying to share code. It seems likely to cause more confusion than the
factoring is worth in practice. Especially given that you need to use
macros to "fix" things between the two. Much simpler to just write the code
IMO.
> +#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"
>
Same as above.
> +};
> +
> +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/3e8db4e3/attachment-0001.html>
More information about the cfe-commits
mailing list