tianshilei1992 created this revision. Herald added subscribers: dexonsmith, okura, kuter, hiraditya. Herald added a reviewer: aaron.ballman. tianshilei1992 requested review of this revision. Herald added a reviewer: jdoerfert. Herald added a reviewer: jdoerfert. Herald added a reviewer: sstefan1. Herald added subscribers: llvm-commits, cfe-commits, bbn, sstefan1. Herald added a reviewer: baziotis. Herald added projects: clang, LLVM.
Current `!callback` metadata assumes that arguments of callback function are encoded in broker function arguments, as the following example shows: void callback(int, float, double); void broker(void(*cb)(int, float, double), int, float, double); We call the argument encoding as "flatten mode". However, it is not always the case. For some programming model, such as CUDA and OpenMP offloading, arguments are "stacked": void callback(int *, float *, double *); void broker(void(*cb)(int *, float *, double *), void **args, size_t size) { // ... cb(args[0], args[1], args[2]); } Let's call this encode as "stacked mode" (a more approporiate name is welcomed). Current `!callback` metadata cannot handle this case very well. In fact, we can establish connection between callback function arguments and `args` passed to the broker function via the use chain of `args`. For example, before we call the broker function, we need to construct `args` by setting its every element. In this way, we can know which pointer eventually corresponds to which callback function argument. In order to do that, we need to tell apart the two different parameter encoding modes. In this patch, the `!callback` metadata is updated in the following way: 1. The first operand is an `i64` value, representing parameter encoding mode. 0 is "flatten mode", and 1 is "stacked mode". 2. The second operand is the callback function index, same as the previous first operand. 3. The next one or more operands are still parameter encoding with a little difference. If the encoding mode is 0, it is same as current way. If the mode is 1, there must only be two operands: one is the index of the base pointer (e.g. the index of `void **args` above), and the second is the index of its size (e.g. the index of `size_t size` above). 4. The last operand is still for the variadic arguments. The 3rd pointer above is not covered by this patch for now. It's probably worth another patch. This patch only add the support for encoding mode, so an extra `i64 0` should be added everywhere, and for now it can only be 0. The update of documents will be covered by this patch as well, which will be done soon. P.S. People might argue in CUDA or OpenMP offloading, the broker function actually doesn't accept a callback function pointer. It's usually a global symbol which can be used to find the entry kernel function during the runtime. More important, the kernel function (or "callback" function) cannot be seen in the host module at all. What's the point of doing this? Yes, that's true for now. We're working on the heterogenous module, which basically will "merge" (or "link") kernel moduel and host module together. In this way, we can optimize them with the information from both host and kernel size. We can bridge the kernel function and broker function via the global symbol somehow to make the kernel function a "virtual" callback function. Although pointers in `void **args` will not be used by the kernel function directly (as shown in the example above), the real arguments passed to the kernel function are 1:1 mapped from pointers in `args`. Therefore the correspondence still exists. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D98134 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/CodeGen/CodeGenModule.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/test/CodeGen/attr-callback.c clang/test/CodeGen/callback_annotated.c clang/test/CodeGen/callback_openmp.c clang/test/CodeGenCXX/attr-callback.cpp clang/test/OpenMP/parallel_codegen.cpp clang/test/Sema/attr-callback-broken.c clang/test/Sema/attr-callback.c clang/test/SemaCXX/attr-callback.cpp llvm/include/llvm/IR/AbstractCallSite.h llvm/include/llvm/IR/MDBuilder.h llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp llvm/lib/IR/AbstractCallSite.cpp llvm/lib/IR/MDBuilder.cpp llvm/test/Analysis/CallGraph/callback-calls.ll llvm/test/Analysis/CallGraph/ignore-callback-uses.ll llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll llvm/test/Transforms/Attributor/callbacks.ll llvm/test/Transforms/Attributor/noundef.ll llvm/test/Transforms/OpenMP/parallel_deletion.ll llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll llvm/test/Transforms/OpenMP/parallel_region_merging.ll llvm/unittests/IR/AbstractCallSiteTest.cpp llvm/unittests/IR/LegacyPassManagerTest.cpp
Index: llvm/unittests/IR/LegacyPassManagerTest.cpp =================================================================== --- llvm/unittests/IR/LegacyPassManagerTest.cpp +++ llvm/unittests/IR/LegacyPassManagerTest.cpp @@ -768,7 +768,7 @@ "}\n" "\n" "!0 = !{!1}\n" - "!1 = !{i64 0, i64 1, i1 false}"; + "!1 = !{i64 0, i64 0, i64 1, i1 false}"; SMDiagnostic Err; std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Context); Index: llvm/unittests/IR/AbstractCallSiteTest.cpp =================================================================== --- llvm/unittests/IR/AbstractCallSiteTest.cpp +++ llvm/unittests/IR/AbstractCallSiteTest.cpp @@ -36,7 +36,7 @@ "}\n" "declare !callback !0 void @broker(i32, void (i8*, ...)*, ...)\n" "!0 = !{!1}\n" - "!1 = !{i64 1, i64 -1, i1 true}"; + "!1 = !{i64 0, i64 1, i64 -1, i1 true}"; std::unique_ptr<Module> M = parseIR(C, IR); ASSERT_TRUE(M); Index: llvm/test/Transforms/OpenMP/parallel_region_merging.ll =================================================================== --- llvm/test/Transforms/OpenMP/parallel_region_merging.ll +++ llvm/test/Transforms/OpenMP/parallel_region_merging.ll @@ -786,7 +786,7 @@ !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{!2} -!2 = !{i64 2, i64 -1, i64 -1, i1 true} +!2 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} ; CHECK-LABEL: define {{[^@]+}}@merge ; CHECK-SAME: (i32 [[A:%.*]]) local_unnamed_addr { ; CHECK-NEXT: entry: Index: llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll =================================================================== --- llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll +++ llvm/test/Transforms/OpenMP/parallel_deletion_remarks.ll @@ -96,7 +96,7 @@ !21 = !DILocation(line: 14, column: 1, scope: !15) !22 = !DILocation(line: 16, column: 1, scope: !15) !23 = !{!24} -!24 = !{i64 2, i64 -1, i64 -1, i1 true} +!24 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} !25 = distinct !DISubprogram(name: ".omp_outlined.", scope: !1, file: !1, line: 9, type: !26, scopeLine: 9, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !33) !26 = !DISubroutineType(types: !27) !27 = !{null, !28, !28} Index: llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll =================================================================== --- llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll +++ llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll @@ -9,7 +9,7 @@ ; CHECK: CS<None> calls function 'd' ; ; CHECK: Call graph node for function: '.omp_outlined..0'<<{{.*}}>> #uses=1 -; +; ; CHECK: Call graph node for function: '.omp_outlined..1'<<{{.*}}>> #uses=3 ; CHECK: CS<{{.*}}> calls function 'd' ; @@ -89,4 +89,4 @@ !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{!"clang version 11.0.0"} !2 = !{!3} -!3 = !{i64 2, i64 -1, i64 -1, i1 true} +!3 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} Index: llvm/test/Transforms/OpenMP/parallel_deletion.ll =================================================================== --- llvm/test/Transforms/OpenMP/parallel_deletion.ll +++ llvm/test/Transforms/OpenMP/parallel_deletion.ll @@ -442,7 +442,7 @@ !0 = !{i32 1, !"wchar_size", i32 4} !1 = !{!"clang"} !2 = !{!3} -!3 = !{i64 2, i64 -1, i64 -1, i1 true} +!3 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} !4 = !{!5, !5, i64 0} !5 = !{!"int", !6, i64 0} !6 = !{!"omnipotent char", !7, i64 0} Index: llvm/test/Transforms/Attributor/noundef.ll =================================================================== --- llvm/test/Transforms/Attributor/noundef.ll +++ llvm/test/Transforms/Attributor/noundef.ll @@ -122,5 +122,5 @@ } declare !callback !0 void @callback_broker(void (i8*)*, i8*) -!1 = !{i64 0, i64 1, i1 false} +!1 = !{i64 0, i64 0, i64 1, i1 false} !0 = !{!1} Index: llvm/test/Transforms/Attributor/callbacks.ll =================================================================== --- llvm/test/Transforms/Attributor/callbacks.ll +++ llvm/test/Transforms/Attributor/callbacks.ll @@ -417,4 +417,4 @@ declare !callback !0 void @t3_callback_broker(i32* nocapture , i32* nocapture , void (i32*, i32*, ...)* nocapture, ...) !0 = !{!1} -!1 = !{i64 2, i64 -1, i64 -1, i1 true} +!1 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} Index: llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/thread_local_acs.ll @@ -67,5 +67,5 @@ declare !callback !0 dso_local void @broker(i32*, i32 (i32*, i32*)*, i32*) -!1 = !{i64 1, i64 0, i64 2, i1 false} +!1 = !{i64 0, i64 1, i64 0, i64 2, i1 false} !0 = !{!1} Index: llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll @@ -134,5 +134,5 @@ ret i8* %arg } -!1 = !{i64 2, i64 3, i1 false} +!1 = !{i64 0, i64 2, i64 3, i1 false} !0 = !{!1} Index: llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll @@ -285,5 +285,5 @@ declare !callback !0 dso_local void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) -!1 = !{i64 2, i64 -1, i64 -1, i1 true} +!1 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} !0 = !{!1} Index: llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll =================================================================== --- llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll +++ llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll @@ -146,7 +146,7 @@ declare !callback !3 void @broker(i32 (i32)*, i32 (i32)*, i32 (i32)*, i32, i32) -!0 = !{i64 0, i64 3, i1 false} -!1 = !{i64 1, i64 4, i1 false} -!2 = !{i64 2, i64 3, i1 false} +!0 = !{i64 0, i64 0, i64 3, i1 false} +!1 = !{i64 0, i64 1, i64 4, i1 false} +!2 = !{i64 0, i64 2, i64 3, i1 false} !3 = !{!0, !2, !1} Index: llvm/test/Analysis/CallGraph/ignore-callback-uses.ll =================================================================== --- llvm/test/Analysis/CallGraph/ignore-callback-uses.ll +++ llvm/test/Analysis/CallGraph/ignore-callback-uses.ll @@ -48,4 +48,4 @@ declare !callback !2 void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) #2 !2 = !{!3} -!3 = !{i64 2, i64 -1, i64 -1, i1 true} +!3 = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} Index: llvm/test/Analysis/CallGraph/callback-calls.ll =================================================================== --- llvm/test/Analysis/CallGraph/callback-calls.ll +++ llvm/test/Analysis/CallGraph/callback-calls.ll @@ -17,4 +17,4 @@ declare !callback !0 void @broker(void (i32*)*, i32*) !0 = !{!1} -!1 = !{i64 0, i64 1, i1 false} +!1 = !{i64 0, i64 0, i64 1, i1 false} Index: llvm/lib/IR/MDBuilder.cpp =================================================================== --- llvm/lib/IR/MDBuilder.cpp +++ llvm/lib/IR/MDBuilder.cpp @@ -104,12 +104,14 @@ return MDNode::get(Context, Ops); } -MDNode *MDBuilder::createCallbackEncoding(unsigned CalleeArgNo, +MDNode *MDBuilder::createCallbackEncoding(unsigned EncodeMode, + unsigned CalleeArgNo, ArrayRef<int> Arguments, bool VarArgArePassed) { SmallVector<Metadata *, 4> Ops; Type *Int64 = Type::getInt64Ty(Context); + Ops.push_back(createConstant(ConstantInt::get(Int64, EncodeMode))); Ops.push_back(createConstant(ConstantInt::get(Int64, CalleeArgNo))); for (int ArgNo : Arguments) Index: llvm/lib/IR/AbstractCallSite.cpp =================================================================== --- llvm/lib/IR/AbstractCallSite.cpp +++ llvm/lib/IR/AbstractCallSite.cpp @@ -44,7 +44,7 @@ for (const MDOperand &Op : CallbackMD->operands()) { MDNode *OpMD = cast<MDNode>(Op.get()); - auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); + auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(1)); uint64_t CBCalleeIdx = cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); if (CBCalleeIdx < CB.arg_size()) @@ -102,7 +102,7 @@ MDNode *CallbackEncMD = nullptr; for (const MDOperand &Op : CallbackMD->operands()) { MDNode *OpMD = cast<MDNode>(Op.get()); - auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(0)); + auto *CBCalleeIdxAsCM = cast<ConstantAsMetadata>(OpMD->getOperand(1)); uint64_t CBCalleeIdx = cast<ConstantInt>(CBCalleeIdxAsCM->getValue())->getZExtValue(); if (CBCalleeIdx != UseIdx) @@ -119,11 +119,13 @@ NumCallbackCallSites++; - assert(CallbackEncMD->getNumOperands() >= 2 && "Incomplete !callback metadata"); + assert(CallbackEncMD->getNumOperands() >= 3 && + "Incomplete !callback metadata"); unsigned NumCallOperands = CB->getNumArgOperands(); - // Skip the var-arg flag at the end when reading the metadata. - for (unsigned u = 0, e = CallbackEncMD->getNumOperands() - 1; u < e; u++) { + // Skip the var-arg flag at the end and mode at the beginning when reading the + // metadata. + for (unsigned u = 1, e = CallbackEncMD->getNumOperands() - 1; u < e; u++) { Metadata *OpAsM = CallbackEncMD->getOperand(u).get(); auto *OpAsCM = cast<ConstantAsMetadata>(OpAsM); assert(OpAsCM->getType()->isIntegerTy(64) && @@ -151,4 +153,16 @@ // Add all variadic arguments at the end. for (unsigned u = Callee->arg_size(); u < NumCallOperands; u++) CI.ParameterEncoding.push_back(u); + + Metadata *EncodingModeAsM = CallbackEncMD->getOperand(0).get(); + auto *EncodingModeAsCM = cast<ConstantAsMetadata>(EncodingModeAsM); + assert(EncodingModeAsCM->getType()->isIntegerTy(64) && + "Malformed !callback metadata parameter encoding mode"); + int64_t EncodingMode = + cast<ConstantInt>(EncodingModeAsCM->getValue())->getSExtValue(); + assert((EncodingMode == CallbackInfo::ParameterEncodingModeTy::FLATTEN || + EncodingMode == CallbackInfo::ParameterEncodingModeTy::STACK) && + "Unnown !callback metadata parameter encoding mode"); + CI.ParameterEncodingMode = + static_cast<CallbackInfo::ParameterEncodingModeTy>(EncodingMode); } Index: llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp =================================================================== --- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -94,10 +94,10 @@ // - The first two arguments of the callback callee are unknown (-1). // - All variadic arguments to the runtime function are passed to the // callback callee. - Fn->addMetadata( - LLVMContext::MD_callback, - *MDNode::get(Ctx, {MDB.createCallbackEncoding( - 2, {-1, -1}, /* VarArgsArePassed */ true)})); + Fn->addMetadata(LLVMContext::MD_callback, + *MDNode::get(Ctx, {MDB.createCallbackEncoding( + 0, 2, {-1, -1}, + /* VarArgsArePassed */ true)})); } } @@ -596,7 +596,7 @@ F->addMetadata( llvm::LLVMContext::MD_callback, *llvm::MDNode::get( - Ctx, {MDB.createCallbackEncoding(2, {-1, -1}, + Ctx, {MDB.createCallbackEncoding(0, 2, {-1, -1}, /* VarArgsArePassed */ true)})); } } Index: llvm/include/llvm/IR/MDBuilder.h =================================================================== --- llvm/include/llvm/IR/MDBuilder.h +++ llvm/include/llvm/IR/MDBuilder.h @@ -102,7 +102,8 @@ //===------------------------------------------------------------------===// /// Return metadata describing a callback (see llvm::AbstractCallSite). - MDNode *createCallbackEncoding(unsigned CalleeArgNo, ArrayRef<int> Arguments, + MDNode *createCallbackEncoding(unsigned EncodeMode, unsigned CalleeArgNo, + ArrayRef<int> Arguments, bool VarArgsArePassed); /// Merge the new callback encoding \p NewCB into \p ExistingCallbacks. Index: llvm/include/llvm/IR/AbstractCallSite.h =================================================================== --- llvm/include/llvm/IR/AbstractCallSite.h +++ llvm/include/llvm/IR/AbstractCallSite.h @@ -52,6 +52,10 @@ /// The encoding of a callback with regards to the underlying instruction. struct CallbackInfo { + enum ParameterEncodingModeTy : int64_t { + FLATTEN = 0, + STACK = 1 + }; /// For direct/indirect calls the parameter encoding is empty. If it is not, /// the abstract call site represents a callback. In that case, the first @@ -65,7 +69,7 @@ /// unknown values that are passed to the callee. using ParameterEncodingTy = SmallVector<int, 0>; ParameterEncodingTy ParameterEncoding; - + ParameterEncodingModeTy ParameterEncodingMode; }; private: Index: clang/test/SemaCXX/attr-callback.cpp =================================================================== --- clang/test/SemaCXX/attr-callback.cpp +++ clang/test/SemaCXX/attr-callback.cpp @@ -9,26 +9,26 @@ 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(0, 1))) void no_args_2(void (*callback)(void)); + __attribute__((callback(0, callback))) void no_args_3(void (*callback)(void)) {} - __attribute__((callback(1, 0))) virtual void + __attribute__((callback(0, 1, 0))) virtual void this_tr(void (*callback)(Base *)); - __attribute__((callback(1, this, __, this))) virtual void + __attribute__((callback(0, 1, this, __, this))) virtual void this_unknown_this(void (*callback)(Base *, Base *, Base *)); - __attribute__((callback(1))) virtual void + __attribute__((callback(0, 1))) virtual void virtual_1(void (*callback)(void)); - __attribute__((callback(callback))) virtual void + __attribute__((callback(0, callback))) virtual void virtual_2(void (*callback)(void)); - __attribute__((callback(1))) virtual void + __attribute__((callback(0, 1))) virtual void virtual_3(void (*callback)(void)); }; -__attribute__((callback(1))) void +__attribute__((callback(0, 1))) void Base::no_args_1(void (*callback)(void)) { } @@ -37,10 +37,10 @@ struct Derived_1 : public Base { - __attribute__((callback(1, 0))) virtual void + __attribute__((callback(0, 1, 0))) virtual void this_tr(void (*callback)(Base *)) override; - __attribute__((callback(1))) virtual void + __attribute__((callback(0, 1))) virtual void virtual_1(void (*callback)(void)) override {} virtual void @@ -49,7 +49,7 @@ struct Derived_2 : public Base { - __attribute__((callback(callback))) virtual void + __attribute__((callback(0, callback))) virtual void virtual_1(void (*callback)(void)) override; virtual void @@ -61,7 +61,7 @@ void Derived_2::virtual_1(void (*callback)(void)) {} -__attribute__((callback(1))) void +__attribute__((callback(0, 1))) void Derived_2::virtual_2(void (*callback)(void)) {} void Derived_2::virtual_3(void (*callback)(void)) {} Index: clang/test/Sema/attr-callback.c =================================================================== --- clang/test/Sema/attr-callback.c +++ clang/test/Sema/attr-callback.c @@ -2,13 +2,13 @@ // 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(0, 1))) void no_args(void (*callback)(void)); +__attribute__((callback(0, 1, 2, 3))) void args_1(void (*callback)(int, double), int a, double b); +__attribute__((callback(0, 2, 3, 3))) void args_2(int a, void (*callback)(double, double), double b); +__attribute__((callback(0, 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); +__attribute__((callback(0, callback))) void no_argsb(void (*callback)(void)); +__attribute__((callback(0, callback, a, 3))) void args_1b(void (*callback)(int, double), int a, double b); +__attribute__((callback(0, callback, b, b))) void args_2b(int a, void (*callback)(double, double), double b); +__attribute__((callback(0, 2, __, __))) void args_3b(int a, void (*callback)(double, double), double b); +__attribute__((callback(0, callback, -1, __))) void args_3c(int a, void (*callback)(double, double), double b); Index: clang/test/Sema/attr-callback-broken.c =================================================================== --- clang/test/Sema/attr-callback-broken.c +++ clang/test/Sema/attr-callback-broken.c @@ -1,75 +1,76 @@ // 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())) void no_encoding_mode(void (*callback)(void)); // expected-error {{'callback' attribute specifies no parameter encoding mode}} +__attribute__((callback(0))) 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(0, 1, 1))) void too_many_args_1(void (*callback)(void)) {} // expected-error {{'callback' attribute requires exactly 2 arguments}} +__attribute__((callback(0, 1, -1))) void too_many_args_2(double (*callback)(void)); // expected-error {{'callback' attribute requires exactly 2 arguments}} +__attribute__((callback(0, 1, 2, 2))) void too_many_args_3(void (*callback)(int), int); // expected-error {{'callback' attribute requires exactly 3 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(0, 1, 2))) void too_few_args_1(void (*callback)(int, int), int); // expected-error {{'callback' attribute requires exactly 4 arguments}} +__attribute__((callback(0, 1))) void too_few_args_2(int (*callback)(int)); // expected-error {{'callback' attribute requires exactly 3 arguments}} +__attribute__((callback(0, 1, -1))) void too_few_args_3(void (*callback)(int, int)) {} // expected-error {{'callback' attribute requires exactly 4 arguments}} -__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(0, -1))) void oob_args_1(void (*callback)(void)); // expected-error {{'callback' attribute specifies invalid callback callee}} +__attribute__((callback(0, 2))) void oob_args_2(int *(*callback)(void)) {} // expected-error {{'callback' attribute parameter 2 is out of bounds}} +__attribute__((callback(0, 1, 3))) void oob_args_3(short (*callback)(int), int); // expected-error {{'callback' attribute parameter 3 is out of bounds}} +__attribute__((callback(0, -2, 2))) void oob_args_4(void *(*callback)(int), int); // expected-error {{'callback' attribute parameter 2 is out of bounds}} +__attribute__((callback(0, 1, -2))) void oob_args_5(void *(*callback)(int), int); // expected-error {{'callback' attribute parameter 3 is out of bounds}} +__attribute__((callback(0, 1, 2))) void oob_args_6(void *(*callback)(int), ...); // expected-error {{'callback' attribute parameter 3 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}} +__attribute__((callback(0, 1))) __attribute__((callback(0, 1))) void multiple_cb_1(void (*callback)(void)); // expected-error {{multiple 'callback' attributes specified}} +__attribute__((callback(0, 1))) __attribute__((callback(0, 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}} +__attribute__((callback(0, 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'}} +__attribute__((callback(0, 0))) void oob_args_0(void (*callback)(void)); // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}} +__attribute__((callback(0, 1, 0))) void no_this_1(void *(*callback)(void *)); // expected-error {{'callback' argument at position 3 references unavailable implicit 'this'}} +__attribute__((callback(0, 1, 0))) void no_this_2(void *(*callback)(int, void *)); // expected-error {{'callback' argument at position 3 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(0, 1, -1))) void vararg_cb_1(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute callee may not be variadic}} +__attribute__((callback(0, 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(0, 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 3 arguments}} +__attribute__((callback(0, 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 5 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(0, 1, -1, 1))) void self_arg_1(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute requires exactly 3 arguments}} +__attribute__((callback(0, 1, -1, 1, -1, -1, 1))) void self_arg_2(void (*callback)(int, ...)); // expected-error {{'callback' attribute requires exactly 3 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(0, cb))) void unknown_name1(void (*callback)(void)) {} // expected-error {{'callback' attribute argument 'cb' is not a known function parameter}} +__attribute__((callback(0, 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(0, callback, 1))) void too_many_args_1b(void (*callback)(void)) {} // expected-error {{'callback' attribute requires exactly 2 arguments}} +__attribute__((callback(0, callback, __))) void too_many_args_2b(double (*callback)(void)); // expected-error {{'callback' attribute requires exactly 2 arguments}} +__attribute__((callback(0, callback, 2, 2))) void too_many_args_3b(void (*callback)(int), int); // expected-error {{'callback' attribute requires exactly 3 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(0, callback, a))) void too_few_args_1b(void (*callback)(int, int), int a); // expected-error {{'callback' attribute requires exactly 4 arguments}} +__attribute__((callback(0, callback))) void too_few_args_2b(int (*callback)(int)); // expected-error {{'callback' attribute requires exactly 3 arguments}} +__attribute__((callback(0, callback, __))) void too_few_args_3b(void (*callback)(int, int)) {} // expected-error {{'callback' attribute requires exactly 4 arguments}} -__attribute__((callback(__))) void oob_args_1b(void (*callback)(void)); // expected-error {{'callback' attribute specifies invalid callback callee}} +__attribute__((callback(0, __))) 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}} +__attribute__((callback(0, callback))) __attribute__((callback(0, callback))) void multiple_cb_1b(void (*callback)(void)); // expected-error {{multiple 'callback' attributes specified}} +__attribute__((callback(0, 1))) __attribute__((callback(0, 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}} +__attribute__((callback(0, 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'}} +__attribute__((callback(0, this))) void oob_args_0b(void (*callback)(void)); // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}} +__attribute__((callback(0, 1, this))) void no_this_1b(void *(*callback)(void *)); // expected-error {{'callback' argument at position 3 references unavailable implicit 'this'}} +__attribute__((callback(0, 1, this))) void no_this_2b(void *(*callback)(int, void *)); // expected-error {{'callback' argument at position 3 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(0, callback, __))) void vararg_cb_1b(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute callee may not be variadic}} +__attribute__((callback(0, 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(0, callback, __, callback, a, b, c, __))) void varargs_1b(void (*callback)(int, ...), int a, float b, double c) {} // expected-error {{'callback' attribute requires exactly 3 arguments}} +__attribute__((callback(0, 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 5 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}} +__attribute__((callback(0, 1, __, callback))) void self_arg_1b(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute requires exactly 3 arguments}} +__attribute__((callback(0, callback, __, callback, __, __, callback))) void self_arg_2b(void (*callback)(int, ...)); // expected-error {{'callback' attribute requires exactly 3 arguments}} Index: clang/test/OpenMP/parallel_codegen.cpp =================================================================== --- clang/test/OpenMP/parallel_codegen.cpp +++ clang/test/OpenMP/parallel_codegen.cpp @@ -182,5 +182,5 @@ // ALL: attributes #[[FN_ATTRS]] = {{.+}} nounwind // ALL-DEBUG: attributes #[[FN_ATTRS]] = {{.+}} nounwind // ALL: ![[cbid]] = !{![[cbidb:[0-9]+]]} -// ALL: ![[cbidb]] = !{i64 2, i64 -1, i64 -1, i1 true} +// ALL: ![[cbidb]] = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} #endif Index: clang/test/CodeGenCXX/attr-callback.cpp =================================================================== --- clang/test/CodeGenCXX/attr-callback.cpp +++ clang/test/CodeGenCXX/attr-callback.cpp @@ -3,28 +3,28 @@ 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)); + __attribute__((callback(0, 1))) void no_args_2(void (*callback1)(void), void (*callback2)(void)); + __attribute__((callback(0, 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 + __attribute__((callback(0, 1))) virtual void virtual_1(void (*callback)(void)); - __attribute__((callback(callback, this, __, this))) virtual void + __attribute__((callback(0, 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 +__attribute__((callback(0, 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)) { +__attribute__((callback(0, 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)) { +__attribute__((callback(0, 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]+]] @@ -32,7 +32,7 @@ } struct Derived_1 : public Base { - __attribute__((callback(1))) virtual void + __attribute__((callback(0, 1))) virtual void virtual_1(void (*callback)(void)) override; }; @@ -48,8 +48,8 @@ void Derived_2::virtual_1(void (*callback)(void)) {} // CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]} -// CHECK-DAG: ![[cid0b]] = !{i64 1, i1 false} +// CHECK-DAG: ![[cid0b]] = !{i64 0, i64 1, i1 false} // CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]} -// CHECK-DAG: ![[cid1b]] = !{i64 2, i1 false} +// CHECK-DAG: ![[cid1b]] = !{i64 0, i64 2, i1 false} // CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]} -// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 0, i64 -1, i64 0, i1 false} +// CHECK-DAG: ![[cid2b]] = !{i64 0, i64 1, i64 0, i64 -1, i64 0, i1 false} Index: clang/test/CodeGen/callback_openmp.c =================================================================== --- clang/test/CodeGen/callback_openmp.c +++ clang/test/CodeGen/callback_openmp.c @@ -3,7 +3,7 @@ // 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} +// CHECK: ![[cidb]] = !{i64 0, i64 2, i64 -1, i64 -1, i1 true} void work1(int, int); void work2(int, int); Index: clang/test/CodeGen/callback_annotated.c =================================================================== --- clang/test/CodeGen/callback_annotated.c +++ clang/test/CodeGen/callback_annotated.c @@ -1,30 +1,30 @@ // RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -fno-experimental-new-pass-manager %s -emit-llvm -o - -disable-llvm-optzns | FileCheck %s --check-prefix=RUN1 // RUN1-DAG: @broker0({{[^#]*#[0-9]+}} !callback ![[cid0:[0-9]+]] -__attribute__((callback(1, 2))) void *broker0(void *(*callee)(void *), void *payload) { +__attribute__((callback(0, 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 *)) { +__attribute__((callback(0, 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)); +__attribute__((callback(0, 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); +__attribute__((callback(0, 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); +__attribute__((callback(0, 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); +__attribute__((callback(0, 4, d, 5, 2))) void *broker5(int, int, int, int (*callee)(int, int, int), int d); static void *VoidPtr2VoidPtr(void *payload) { return payload; @@ -44,14 +44,14 @@ } // RUN1-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]} -// RUN1-DAG: ![[cid0b]] = !{i64 0, i64 1, i1 false} +// RUN1-DAG: ![[cid0b]] = !{i64 0, i64 0, i64 1, i1 false} // RUN1-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]} -// RUN1-DAG: ![[cid1b]] = !{i64 1, i64 0, i1 false} +// RUN1-DAG: ![[cid1b]] = !{i64 0, i64 1, i64 0, i1 false} // RUN1-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]} -// RUN1-DAG: ![[cid2b]] = !{i64 0, i1 false} +// RUN1-DAG: ![[cid2b]] = !{i64 0, 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: ![[cid3b]] = !{i64 0, 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: ![[cid4b]] = !{i64 0, 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} +// RUN1-DAG: ![[cid5b]] = !{i64 0, i64 3, i64 4, i64 4, i64 1, i1 false} Index: clang/test/CodeGen/attr-callback.c =================================================================== --- clang/test/CodeGen/attr-callback.c +++ clang/test/CodeGen/attr-callback.c @@ -3,26 +3,26 @@ void cb0(void); // CHECK-DAG: !callback ![[cid0:[0-9]+]] void @no_args -__attribute__((callback(1))) void no_args(void (*callback)(void)); +__attribute__((callback(0, 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); } +__attribute__((callback(0, 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); +__attribute__((callback(0, 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); +__attribute__((callback(0, 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); } +__attribute__((callback(0, 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); } +__attribute__((callback(0, 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: ![[cid0b]] = !{i64 0, i64 0, i1 false} // CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]} -// CHECK-DAG: ![[cid1b]] = !{i64 0, i64 1, i64 2, i1 false} +// CHECK-DAG: ![[cid1b]] = !{i64 0, 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: ![[cid2b]] = !{i64 0, 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} +// CHECK-DAG: ![[cid3b]] = !{i64 0, i64 1, i64 -1, i64 -1, i1 false} Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -3555,8 +3555,15 @@ /// 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. + // The parameter encoding mode is mandatory. if (AL.getNumArgs() == 0) { + S.Diag(AL.getLoc(), diag::err_callback_attribute_no_encoding_mode) + << AL.getRange(); + return; + } + + // The index that identifies the callback callee is mandatory. + if (AL.getNumArgs() == 1) { S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee) << AL.getRange(); return; @@ -3618,7 +3625,7 @@ llvm_unreachable("Unexpected ParsedAttr argument type!"); } - if (ArgIdx == 0 && !HasImplicitThisParam) { + if (ArgIdx == 0 && I != 0 && !HasImplicitThisParam) { S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available) << (I + 1) << SR; return; @@ -3632,7 +3639,9 @@ EncodingIndices.push_back(ArgIdx); } - int CalleeIdx = EncodingIndices.front(); + assert(EncodingIndices.size() >= 2); + + int CalleeIdx = EncodingIndices[1]; // Check if the callee index is proper, thus not "this" and not "unknown". // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam" // is false and positive if "HasImplicitThisParam" is true. @@ -3665,15 +3674,9 @@ 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) { + if (CalleeFnProtoType->getNumParams() != EncodingIndices.size() - 2) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) - << AL << (unsigned)(EncodingIndices.size() - 1); + << AL << (unsigned)(CalleeFnProtoType->getNumParams() + 2); return; } Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -2126,19 +2126,23 @@ if (const auto *CB = FD->getAttr<CallbackAttr>()) { // Annotate the callback behavior as metadata: + // - The callback argument encoding mode (as argument number) // - 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)})); + // The payload indices are all but the first two in the encoding. The first + // identifies the callback argument encoding mode, and the second represents + // the callback callee. + int EncodingMode = *CB->encoding_begin(); + int CalleeIdx = *(CB->encoding_begin() + 1); + ArrayRef<int> PayloadIndices(CB->encoding_begin() + 2, CB->encoding_end()); + F->addMetadata( + llvm::LLVMContext::MD_callback, + *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding( + EncodingMode, CalleeIdx, PayloadIndices, + /* VarArgsArePassed */ false)})); } } Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2936,6 +2936,8 @@ "string">; def err_callback_attribute_no_callee : Error< "'callback' attribute specifies no callback callee">; +def err_callback_attribute_no_encoding_mode : Error< + "'callback' attribute specifies no parameter encoding mode">; def err_callback_attribute_invalid_callee : Error< "'callback' attribute specifies invalid callback callee">; def err_callback_attribute_multiple : Error<
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits