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

Reply via email to