Support the btf_decl_tag and btf_type_tag attributes in BTF by creating
and emitting BTF_KIND_DECL_TAG and BTF_KIND_TYPE_TAG records,
respectively, for them.

Some care is required when -gprune-btf is in effect to avoid emitting
decl or type tags for declarations or types which have been pruned and
will not be emitted in BTF.

gcc/
        * btfout.cc (get_btf_kind): Handle DECL_TAG and TYPE_TAG kinds.
        (btf_calc_num_vbytes): Likewise.
        (btf_asm_type): Likewise.
        (output_asm_btf_vlen_bytes): Likewise.
        (output_btf_tags): New.
        (btf_output): Call it here.
        (btf_add_used_type): Replace with simple wrapper around...
        (btf_add_used_type_1): ...the implementation.  Handle
        BTF_KIND_DECL_TAG and BTF_KIND_TYPE_TAG.
        (btf_add_vars): Update btf_add_used_type call.
        (btf_assign_tag_ids): New.
        (btf_mark_type_used): Update btf_add_used_type call.
        (btf_collect_pruned_types): Likewise.  Handle type and decl tags.
        (btf_finish): Call btf_assign_tag_ids.

gcc/testsuite/
        * gcc.dg/debug/btf/btf-decl-tag-1.c: New test.
        * gcc.dg/debug/btf/btf-decl-tag-2.c: New test.
        * gcc.dg/debug/btf/btf-decl-tag-3.c: New test.
        * gcc.dg/debug/btf/btf-decl-tag-4.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-1.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-2.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-3.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-4.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-5.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-6.c: New test.
        * gcc.dg/debug/btf/btf-type-tag-c2x-1.c: New test.

include/
        * btf.h (BTF_KIND_DECL_TAG, BTF_KIND_TYPE_TAG) New defines.
        (struct btf_decl_tag): New.
---
 gcc/btfout.cc                                 | 171 +++++++++++++++---
 .../gcc.dg/debug/btf/btf-decl-tag-1.c         |  14 ++
 .../gcc.dg/debug/btf/btf-decl-tag-2.c         |  22 +++
 .../gcc.dg/debug/btf/btf-decl-tag-3.c         |  22 +++
 .../gcc.dg/debug/btf/btf-decl-tag-4.c         |  34 ++++
 .../gcc.dg/debug/btf/btf-type-tag-1.c         |  27 +++
 .../gcc.dg/debug/btf/btf-type-tag-2.c         |  15 ++
 .../gcc.dg/debug/btf/btf-type-tag-3.c         |  21 +++
 .../gcc.dg/debug/btf/btf-type-tag-4.c         |  25 +++
 .../gcc.dg/debug/btf/btf-type-tag-5.c         |  35 ++++
 .../gcc.dg/debug/btf/btf-type-tag-6.c         |  15 ++
 .../gcc.dg/debug/btf/btf-type-tag-c2x-1.c     |  23 +++
 include/btf.h                                 |  14 ++
 13 files changed, 414 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c

diff --git a/gcc/btfout.cc b/gcc/btfout.cc
index ff7ea42a961..c00e0c98015 100644
--- a/gcc/btfout.cc
+++ b/gcc/btfout.cc
@@ -141,6 +141,8 @@ get_btf_kind (uint32_t ctf_kind)
     case CTF_K_VOLATILE: return BTF_KIND_VOLATILE;
     case CTF_K_CONST:    return BTF_KIND_CONST;
     case CTF_K_RESTRICT: return BTF_KIND_RESTRICT;
+    case CTF_K_DECL_TAG: return BTF_KIND_DECL_TAG;
+    case CTF_K_TYPE_TAG: return BTF_KIND_TYPE_TAG;
     default:;
     }
   return BTF_KIND_UNKN;
@@ -217,6 +219,7 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
     case BTF_KIND_CONST:
     case BTF_KIND_RESTRICT:
     case BTF_KIND_FUNC:
+    case BTF_KIND_TYPE_TAG:
     /* These kinds have no vlen data.  */
       break;
 
@@ -256,6 +259,10 @@ btf_calc_num_vbytes (ctf_dtdef_ref dtd)
       vlen_bytes += vlen * sizeof (struct btf_var_secinfo);
       break;
 
+    case BTF_KIND_DECL_TAG:
+      vlen_bytes += sizeof (struct btf_decl_tag);
+      break;
+
     default:
       break;
     }
@@ -452,6 +459,20 @@ btf_asm_type (ctf_dtdef_ref dtd)
         and should write 0.  */
       dw2_asm_output_data (4, 0, "(unused)");
       return;
+    case BTF_KIND_DECL_TAG:
+      {
+       if (dtd->ref_type)
+         break;
+       else if (dtd->dtd_u.dtu_tag.ref_var)
+         {
+           /* ref_type is NULL for decl tag attached to a variable.  */
+           ctf_dvdef_ref dvd = dtd->dtd_u.dtu_tag.ref_var;
+           dw2_asm_output_data (4, dvd->dvd_id,
+                                "btt_type: (BTF_KIND_VAR '%s')",
+                                dvd->dvd_name);
+           return;
+         }
+      }
     default:
       break;
     }
@@ -801,6 +822,12 @@ output_asm_btf_vlen_bytes (ctf_container_ref ctfc, 
ctf_dtdef_ref dtd)
         at this point.  */
       gcc_unreachable ();
 
+    case BTF_KIND_DECL_TAG:
+      dw2_asm_output_data (4, dtd->dtd_u.dtu_tag.component_idx,
+                          "component_idx=%d",
+                          dtd->dtd_u.dtu_tag.component_idx);
+      break;
+
     default:
       /* All other BTF type kinds have no variable length data.  */
       break;
@@ -851,6 +878,20 @@ output_btf_func_types (void)
     btf_asm_func_type (ref);
 }
 
+static void
+output_btf_tags (ctf_container_ref ctfc)
+{
+  /* If pruning, tags which are not pruned have already been added to
+     the used list and output by output_btf_types.  */
+  if (debug_prune_btf)
+    return;
+
+  ctf_dtdef_ref dtd;
+  unsigned i;
+  FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
+    output_asm_btf_type (ctfc, dtd);
+}
+
 /* Output all BTF_KIND_DATASEC records.  */
 
 static void
@@ -869,6 +910,7 @@ btf_output (ctf_container_ref ctfc)
   output_btf_types (ctfc);
   output_btf_vars (ctfc);
   output_btf_func_types ();
+  output_btf_tags (ctfc);
   output_btf_datasec_types ();
   output_btf_strs (ctfc);
 }
@@ -985,7 +1027,8 @@ static vec<struct btf_fixup> fixups;
    is created and emitted.  This vector stores them.  */
 static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
 
-/* Recursively add type DTD and any types it references to the used set.
+/* Implementation of btf_add_used_type.
+   Recursively add type DTD and any types it references to the used set.
    Return a type that should be used for references to DTD - usually DTD 
itself,
    but may be NULL if DTD corresponds to a type which will not be emitted.
    CHECK_PTR is true if one of the predecessors in recursive calls is a struct
@@ -996,8 +1039,8 @@ static GTY (()) vec<ctf_dtdef_ref, va_gc> *forwards;
    CREATE_FIXUPS is false.  */
 
 static ctf_dtdef_ref
-btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
-                  bool check_ptr, bool seen_ptr, bool create_fixups)
+btf_add_used_type_1 (ctf_container_ref ctfc, ctf_dtdef_ref dtd,
+                    bool check_ptr, bool seen_ptr, bool create_fixups)
 {
   if (dtd == NULL)
     return NULL;
@@ -1029,8 +1072,9 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref 
dtd,
                  fixups.unordered_remove (i);
 
              /* Add the concrete base type.  */
-             dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, check_ptr,
-                                                seen_ptr, create_fixups);
+             dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type,
+                                                  check_ptr, seen_ptr,
+                                                  create_fixups);
              return dtd;
            }
        default:
@@ -1044,8 +1088,8 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref 
dtd,
         the reference to the bitfield.  The slice type won't be emitted,
         but we need the information in it when writing out the bitfield
         encoding.  */
-      btf_add_used_type (ctfc, dtd->dtd_u.dtu_slice.cts_type,
-                        check_ptr, seen_ptr, create_fixups);
+      btf_add_used_type_1 (ctfc, dtd->dtd_u.dtu_slice.cts_type,
+                          check_ptr, seen_ptr, create_fixups);
       return dtd;
     }
 
@@ -1069,7 +1113,11 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref 
dtd,
     case BTF_KIND_INT:
     case BTF_KIND_FLOAT:
     case BTF_KIND_FWD:
-      /* Leaf kinds which do not refer to any other types.  */
+    case BTF_KIND_DECL_TAG:
+      /* Leaf kinds which do not refer to any other types.
+        BTF_KIND_DECL_TAG is a special case: we treat it as though it does not
+        refer to any other types, since we only want the DECL_TAG to be added
+        if the type to which it refers has already been added.  */
       break;
 
     case BTF_KIND_FUNC:
@@ -1082,6 +1130,7 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref 
dtd,
     case BTF_KIND_CONST:
     case BTF_KIND_VOLATILE:
     case BTF_KIND_RESTRICT:
+    case BTF_KIND_TYPE_TAG:
       {
        /* These type kinds refer to exactly one other type.  */
        if (check_ptr && !seen_ptr)
@@ -1106,18 +1155,18 @@ btf_add_used_type (ctf_container_ref ctfc, 
ctf_dtdef_ref dtd,
          }
 
        /* Add the type to which this type refers.  */
-       dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, check_ptr,
-                                          seen_ptr, create_fixups);
+       dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type, check_ptr,
+                                            seen_ptr, create_fixups);
        break;
       }
     case BTF_KIND_ARRAY:
       {
        /* Add element and index types.  */
        ctf_arinfo_t *arr = &(dtd->dtd_u.dtu_arr);
-       arr->ctr_contents = btf_add_used_type (ctfc, arr->ctr_contents, false,
-                                              false, create_fixups);
-       arr->ctr_index = btf_add_used_type (ctfc, arr->ctr_index, false, false,
-                                           create_fixups);
+       arr->ctr_contents = btf_add_used_type_1 (ctfc, arr->ctr_contents,
+                                                false, false, create_fixups);
+       arr->ctr_index = btf_add_used_type_1 (ctfc, arr->ctr_index, false,
+                                             false, create_fixups);
        break;
       }
     case BTF_KIND_STRUCT:
@@ -1133,8 +1182,8 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref 
dtd,
            /* Add member type for struct/union members.  For enums, only the
               enumerator names are needed.  */
            if (kind == BTF_KIND_STRUCT || kind == BTF_KIND_UNION)
-             dmd->dmd_type = btf_add_used_type (ctfc, dmd->dmd_type, true,
-                                                false, create_fixups);
+             dmd->dmd_type = btf_add_used_type_1 (ctfc, dmd->dmd_type, true,
+                                                  false, create_fixups);
            ctf_add_string (ctfc, dmd->dmd_name, &(dmd->dmd_name_offset),
                            CTF_STRTAB);
          }
@@ -1143,16 +1192,17 @@ btf_add_used_type (ctf_container_ref ctfc, 
ctf_dtdef_ref dtd,
     case BTF_KIND_FUNC_PROTO:
       {
        /* Add return type.  */
-       dtd->ref_type = btf_add_used_type (ctfc, dtd->ref_type, false, false,
-                                          create_fixups);
+       dtd->ref_type = btf_add_used_type_1 (ctfc, dtd->ref_type, false, false,
+                                            create_fixups);
 
        /* Add arg types.  */
        ctf_func_arg_t * farg;
        for (farg = dtd->dtd_u.dtu_argv;
             farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg))
          {
-           farg->farg_type = btf_add_used_type (ctfc, farg->farg_type, false,
-                                                false, create_fixups);
+           farg->farg_type = btf_add_used_type_1 (ctfc, farg->farg_type,
+                                                  false, false,
+                                                  create_fixups);
            /* Note: argument names are stored in the auxilliary string table,
               since CTF does not include arg names.  That table has not been
               cleared, so no need to re-add argument names here.  */
@@ -1166,6 +1216,16 @@ btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref 
dtd,
   return dtd;
 }
 
+/* Recursively add type DTD and any types it references to the used set.
+   Return a type that should be used for references to DTD - usually DTD 
itself,
+   but may be NULL if DTD corresponds to a type which will not be emitted.  */
+
+static ctf_dtdef_ref
+btf_add_used_type (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
+{
+  return btf_add_used_type_1 (ctfc, dtd, false, false, true);
+}
+
 /* Initial entry point of BTF generation, called at early_finish () after
    CTF information has possibly been output.  Translate all CTF information
    to BTF, and do any processing that must be done early, such as creating
@@ -1402,7 +1462,7 @@ btf_add_vars (ctf_container_ref ctfc)
              ctf_dmdef_t *dmd;
              for (dmd = dtd->dtd_u.dtu_members;
                   dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd))
-               btf_add_used_type (ctfc, dmd->dmd_type, false, false, true);
+               btf_add_used_type (ctfc, dmd->dmd_type);
            }
        }
     }
@@ -1488,6 +1548,45 @@ btf_assign_var_ids (ctf_container_ref ctfc)
     }
 }
 
+/* Assign BTF IDs for type and decl tags and account for their size.  */
+
+static void
+btf_assign_tag_ids (ctf_container_ref ctfc)
+{
+  /* Both decl and type tags may be pruned if the types/decls to which they
+     refer are pruned.  This is handled in btf_collect_pruned_types, and
+     through that process they have also been assigned ids already.  */
+  if (debug_prune_btf)
+    return;
+
+  size_t num_tags = vec_safe_length (ctfc->ctfc_tags);
+  if (num_tags == 0)
+    return;
+
+  unsigned int i;
+  ctf_dtdef_ref dtd;
+  FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
+    {
+      /* Assign BTF id.  */
+      ctf_id_t id = ctfc->ctfc_nextid++;
+      gcc_assert (id <= BTF_MAX_TYPE);
+      dtd->dtd_type = id;
+
+      /* Tags on functions will have a ref_type pointing to the
+        FUNC_PROTO, we want them to point the FUNC record instead.  */
+      ctf_dtdef_ref *pdtd = NULL;
+      if (dtd->ref_type && (pdtd = func_map->get (dtd->ref_type)) != NULL)
+       dtd->ref_type = *pdtd;
+
+      /* Strings for tags are stored in the auxilliary strtab, which is
+        concatenated after the regular strtab.  ctti_name only accounts
+        for offset in the auxiliary strtab until this point.  */
+      dtd->dtd_data.ctti_name += ctfc_get_strtab_len (ctfc, CTF_STRTAB);
+      ctfc->ctfc_num_types++;
+      ctfc->ctfc_num_vlen_bytes += btf_calc_num_vbytes (dtd);
+    }
+}
+
 /* Assign BTF IDs for datasec records and account for their size.  */
 
 static void
@@ -1522,7 +1621,7 @@ btf_mark_type_used (tree t)
   if (!dtd)
     return;
 
-  btf_add_used_type (ctfc, dtd, false, false, true);
+  btf_add_used_type (ctfc, dtd);
 }
 
 /* Callback used for assembling the only-used-types list.  Note that this is
@@ -1549,7 +1648,7 @@ btf_collect_pruned_types (ctf_container_ref ctfc)
   size_t i;
   FOR_EACH_VEC_ELT (*funcs, i, dtd)
     {
-      btf_add_used_type (ctfc, dtd->ref_type, false, false, true);
+      btf_add_used_type (ctfc, dtd->ref_type);
       ctf_add_string (ctfc, dtd->dtd_name, &(dtd->dtd_data.ctti_name),
                      CTF_STRTAB);
     }
@@ -1558,10 +1657,33 @@ btf_collect_pruned_types (ctf_container_ref ctfc)
   for (i = 0; i < ctfc->ctfc_vars_list_count; i++)
     {
       ctf_dvdef_ref dvd = ctfc->ctfc_vars_list[i];
-      btf_add_used_type (ctfc, dvd->dvd_type, false, false, true);
+      btf_add_used_type (ctfc, dvd->dvd_type);
       ctf_add_string (ctfc, dvd->dvd_name, &(dvd->dvd_name_offset), 
CTF_STRTAB);
     }
 
+  /* Used type tags will be added by recursive btf_add_used_type calls above.
+     For decl tags, scan the list and only add those decl tags whose referent
+     types are marked as used.  We may have pruned a struct type with members
+     annotated by a decl tag.  */
+  FOR_EACH_VEC_ELT (*ctfc->ctfc_tags, i, dtd)
+    {
+      /* Only add decl tags whose referent types have not been pruned.
+        Variables are never pruned, so decl tags on variables are always
+        used.  */
+      if (btf_dtd_kind (dtd) == BTF_KIND_DECL_TAG
+         && ((dtd->ref_type && btf_used_types->contains (dtd->ref_type))
+             || (dtd->dtd_u.dtu_tag.ref_var)))
+       btf_add_used_type (ctfc, dtd);
+
+      /* Tags on functions or function args will have a ref_type pointing to 
the
+        FUNC_PROTO, we want them to point the FUNC record instead.  */
+      ctf_dtdef_ref *pdtd = NULL;
+      if (dtd->ref_type
+         && btf_used_types->contains (dtd->ref_type)
+         && (pdtd = func_map->get (dtd->ref_type)) != NULL)
+       dtd->ref_type = *pdtd;
+    }
+
   /* Process fixups.  If the base type was never added, create a forward for it
      and adjust the reference to point to that.  If it was added, then nothing
      needs to change.  */
@@ -1634,6 +1756,7 @@ btf_finish (void)
 
   btf_assign_var_ids (tu_ctfc);
   btf_assign_func_ids (tu_ctfc);
+  btf_assign_tag_ids (tu_ctfc);
   btf_assign_datasec_ids (tu_ctfc);
 
   /* Finally, write out the complete .BTF section.  */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c
new file mode 100644
index 00000000000..c933d84b497
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-1.c
@@ -0,0 +1,14 @@
+/* Test simple BTF decl tag generation for variables.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("decl1")))
+#define __tag2 __attribute__((btf_decl_tag ("decl2")))
+#define __tag3 __attribute__((btf_decl_tag ("decl3")))
+
+int x __tag1 __tag2;
+int y __tag1;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
'x'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
'x'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
'y'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c
new file mode 100644
index 00000000000..c4f09ca839c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-2.c
@@ -0,0 +1,22 @@
+/* Test BTF decl tag generation for structs.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("decl1")))
+#define __tag2 __attribute__((btf_decl_tag ("decl2")))
+#define __tag3 __attribute__((btf_decl_tag ("decl3")))
+
+struct Foo {
+  int a;
+  int b __tag3 __tag2;
+  char *z __tag1;
+};
+
+struct Foo f __tag1 __tag2;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
'Foo'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=2" 1} } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
'f'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
'f'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c
new file mode 100644
index 00000000000..7eb8a93ec12
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-3.c
@@ -0,0 +1,22 @@
+/* Test BTF decl tag generation for functions and function args.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_decl_tag ("decl1")))
+#define __tag2 __attribute__((btf_decl_tag ("decl2")))
+#define __tag3 __attribute__((btf_decl_tag ("decl3")))
+
+int __tag1 __tag2 func (int arg_a __tag3 __tag1, int arg_b __tag2)
+{
+  return arg_a * arg_b;
+}
+
+int foo (int x) {
+  return func (x, x + 1);
+}
+
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c
new file mode 100644
index 00000000000..a9022375529
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-decl-tag-4.c
@@ -0,0 +1,34 @@
+/* Test BTF decl tag generation with BTF pruning.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -gprune-btf -dA" } */
+
+#define __decl1 __attribute__((btf_decl_tag ("decl1")))
+#define __decl2 __attribute__((btf_decl_tag ("decl2")))
+#define __decl3 __attribute__((btf_decl_tag ("decl3")))
+
+struct S {
+  /* This tag on S.v shall not be emitted, because struct S is pruned and
+     replaced with a FWD, which does not hold any member info.  */
+  int v __decl3;
+  int w;
+};
+
+struct T {
+  int a;
+  struct S *s __decl1;
+  int c __decl2;
+};
+
+struct T t __decl1;
+
+int __decl1 func (struct T *t __decl2)
+{
+  return t->a + t->c;
+}
+
+/* { dg-final { scan-assembler-not " BTF_KIND_DECL_TAG 'decl3'" } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
'T'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT 
'T'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=2" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VAR 
't'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=-1" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_DECL_TAG 
'decl2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_FUNC 
'func'\\)\[\\r\\n\]+\[^\\r\\n\]*component_idx=0" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c
new file mode 100644
index 00000000000..750add9d923
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-1.c
@@ -0,0 +1,27 @@
+/* Test simple generation of BTF type tags.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+int __tag1 __tag2 x;
+int __tag1 y;
+
+struct Foo {
+  char a;
+  int b;
+};
+
+struct Foo * __tag1 __tag3 f;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'x'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1} } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'y'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler " BTF_KIND_TYPE_TAG 
'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" } } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'f'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type3'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c
new file mode 100644
index 00000000000..31b6b779727
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-2.c
@@ -0,0 +1,15 @@
+/* Test BTF type tag generation with cv-quals.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+/* var (a) -> const -> tag2 -> tag1 -> int  */
+const int __tag1 __tag2 a;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'a'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST ''\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c
new file mode 100644
index 00000000000..c6523830f07
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-3.c
@@ -0,0 +1,21 @@
+/* Test BTF type tag generation with typedefs.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+typedef const int foo;
+typedef int __tag1 bar;
+
+foo __tag2 x;
+const bar y;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'x'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'foo'\\)" 1 } } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'y'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPEDEF 'bar'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPEDEF 
'bar'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c
new file mode 100644
index 00000000000..1fb97232242
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-4.c
@@ -0,0 +1,25 @@
+/* Test BTF type tag generation with BTF pruning.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -gprune-btf -dA" } */
+
+#define __tag1 __attribute__((btf_type_tag("type1")))
+#define __tag2 __attribute__((btf_type_tag("type2")))
+#define __tag3 __attribute__((btf_type_tag("type3")))
+
+struct S {
+  int v ;
+  /* This tag on S.w shall not be emitted because struct S is pruned.  */
+  int __tag3 w;
+};
+
+struct T {
+  int __tag1 a;
+  struct S * __tag2 s;
+  int c;
+};
+
+struct T t;
+
+/* { dg-final { scan-assembler-not " BTF_KIND_TYPE_TAG 'type3'" } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
new file mode 100644
index 00000000000..d8551381152
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-5.c
@@ -0,0 +1,35 @@
+/* Test type tags applied to struct, union, enum types.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+enum E
+{
+  ONE,
+  TWO,
+  THREE,
+} __attribute__((btf_type_tag ("v1")));
+
+volatile enum E volatile_e;
+enum E plain_e;
+
+struct S
+{
+  int x;
+  char y;
+} __attribute__((btf_type_tag ("v2")));
+
+typedef struct S Stu;
+const Stu s;
+
+union U
+{
+  unsigned long ul;
+  unsigned char bytes[8];
+} __attribute__((btf_type_tag ("v3")));
+
+typedef const union U Uni;
+Uni u;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'v1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_ENUM" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'v2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'v3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_UNION" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
new file mode 100644
index 00000000000..f1511d57150
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-6.c
@@ -0,0 +1,15 @@
+/* Test type tags applied to struct typedefs.  */
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+typedef struct  __attribute__((btf_type_tag ("_s_tag"), btf_type_tag ("td")))
+{
+  int a;
+  int b;
+  int c;
+} Foo_Struct;
+
+Foo_Struct __attribute__((btf_type_tag ("_instance"))) f; /* { dg-warning 
"ignoring attributes applied to 'struct <anonymous>' after definition" } */
+
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'td'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG" 1} } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'_s_tag'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_STRUCT" 1} } */
diff --git a/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c 
b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c
new file mode 100644
index 00000000000..c5c915486e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/btf/btf-type-tag-c2x-1.c
@@ -0,0 +1,23 @@
+/* Test BTF type tag generation using C2x standard attribute syntax.
+   Note: in more complicated cases the __attribute__ syntax causes BTF type 
tags
+   to "slide around" in defined, but often unexpected ways.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O0 -gbtf -dA" } */
+
+#define __tag1 [[gnu::btf_type_tag ("type1")]]
+#define __tag2 [[gnu::btf_type_tag ("type2")]]
+#define __tag3 [[gnu::btf_type_tag ("type3")]]
+
+/* var (z) -> const -> tag2 -> tag3 -> ptr -> tag2 -> ptr -> volatile -> tag1 
-> int */
+volatile int __tag1 * __tag2 * __tag3 __tag2 const z;
+
+/* { dg-final { scan-assembler-times " BTF_KIND_VAR 
'z'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_CONST" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_CONST 
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type3'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type3'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type2'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type2'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_PTR" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_PTR 
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_VOLATILE" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_VOLATILE 
''(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_TYPE_TAG 'type1'\\)" 1 } } */
+/* { dg-final { scan-assembler-times " BTF_KIND_TYPE_TAG 
'type1'(\[\\r\\n\]+\[^\\r\\n\]*){2}\\(BTF_KIND_INT" 1 } } */
diff --git a/include/btf.h b/include/btf.h
index 994d02dcfb3..d20ede23fb3 100644
--- a/include/btf.h
+++ b/include/btf.h
@@ -114,6 +114,8 @@ struct btf_type
 #define BTF_KIND_VAR           14      /* Variable.  */
 #define BTF_KIND_DATASEC       15      /* Section such as .bss or .data.  */
 #define BTF_KIND_FLOAT         16      /* Floating point.  */
+#define BTF_KIND_DECL_TAG      17      /* Declaration tag.  */
+#define BTF_KIND_TYPE_TAG      18      /* Type tag.  */
 #define BTF_KIND_ENUM64        19      /* Enumeration up to 64 bits.  */
 #define BTF_KIND_MAX           BTF_KIND_ENUM64
 #define NR_BTF_KINDS           (BTF_KIND_MAX + 1)
@@ -227,6 +229,18 @@ struct btf_enum64
   uint32_t val_hi32;   /* high 32-bit value for a 64-bit value Enumerator */
 };
 
+/* BTF_KIND_DECL_TAG is followed by a single struct btf_decl_tag, which
+   describes the item to which the tag applies:
+   - If component_idx == (uint32_t) -1, then the tag applies to item referred
+     to by the type_id.
+   - Otherwise, the tag applies to the struct or union member, or function
+     argument of the type referred to by type_id with the 0-based index
+     given by component_idx.  */
+struct btf_decl_tag
+{
+  uint32_t component_idx;
+};
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.45.2


Reply via email to