The RISC-V psABI[1] says a function using a standard calling convention variant 
has
to append an extra ABI tag to its mangled name, following the "ABI tags"
rule of the Itanium C++ ABI.  The only variant listed so far is the
fixed-length vector calling convention, whose tag is
riscv_vls_cc_<ABI_VLEN>:

```c
__attribute__((riscv_vls_cc(128))) void foo();
```

now mangles as _Z3fooB16riscv_vls_cc_128v.

The C++ mangler cannot know about target attributes, so we adds a target
hook, TARGET_CXX_IMPLICIT_ABI_TAGS, that hands back extra tags for a decl.

NOTE: I tried to not adding the new hook by attaching abi_tag attribute,
however I tried to doing that on TARGET_INSERT_ATTRIBUTES and
doing some hack way on TARGET_ATTRIBUTE_TABLE during adding calling
convention attribute, but both are no work well.

[1] "Name Mangling for Standard Calling Convention Variant" in
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc

gcc/ChangeLog:

        * target.def (TARGET_CXX_IMPLICIT_ABI_TAGS): New hook.
        * doc/tm.texi.in (TARGET_CXX_IMPLICIT_ABI_TAGS): Document it.
        * doc/tm.texi: Regenerate.
        * config/riscv/riscv.cc (riscv_get_vls_cc_attr): Let CHECK_ONLY
        suppress the diagnostic only, not the validity test.
        (riscv_lookup_vls_cc_attribute): New function.
        (riscv_vls_cc_function_abi): Use it, and take the arguments from
        the attribute that was found.
        (riscv_cxx_implicit_abi_tags): New function.
        (TARGET_CXX_IMPLICIT_ABI_TAGS): Define.

gcc/cp/ChangeLog:

        * mangle.cc (write_unqualified_name): Write the ABI tags the
        target asks for.

gcc/testsuite/ChangeLog:

        * g++.target/riscv/mangle-vls-cc.C: New test.
---
 gcc/config/riscv/riscv.cc                     | 64 +++++++++++++++----
 gcc/cp/mangle.cc                              |  7 ++
 gcc/doc/tm.texi                               |  8 +++
 gcc/doc/tm.texi.in                            |  2 +
 gcc/target.def                                | 10 +++
 .../g++.target/riscv/mangle-vls-cc.C          | 55 ++++++++++++++++
 6 files changed, 134 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/riscv/mangle-vls-cc.C

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index b9e6d2fa42c..00c5e62d6b7 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -8135,39 +8135,48 @@ riscv_get_vls_cc_attr (const_tree args, bool check_only 
= false)
        abi_vlen = TREE_INT_CST_LOW (vlen_arg);
     }
 
-  if (!riscv_valid_abi_vlen_vls_cc_p (abi_vlen) && !check_only)
+  if (!riscv_valid_abi_vlen_vls_cc_p (abi_vlen))
     {
-      error_at (input_location,
-               "unsupported %<ABI_VLEN%> value %d for %qs attribute; "
-               "%<ABI_VLEN%> must be in the range [32, 16384] and must be "
-               "a power of 2",
-               abi_vlen, "riscv_vls_cc");
+      if (!check_only)
+       error_at (input_location,
+                 "unsupported %<ABI_VLEN%> value %d for %qs attribute; "
+                 "%<ABI_VLEN%> must be in the range [32, 16384] and must be "
+                 "a power of 2",
+                 abi_vlen, "riscv_vls_cc");
       return RISCV_CC_UNKNOWN;
     }
 
   return riscv_get_riscv_cc_by_abi_vlen (abi_vlen);
 }
 
+/* Return the vls_cc attribute in ATTRS, either spelling, or NULL_TREE.  */
+
+static tree
+riscv_lookup_vls_cc_attribute (tree attrs)
+{
+  tree attr = lookup_attribute ("vls_cc", attrs);
+  if (!attr)
+    attr = lookup_attribute ("riscv_vls_cc", attrs);
+  return attr;
+}
+
 /* Return true if FUNC is a riscv_vector_cc function.
    For more details please reference the below link.
    https://github.com/riscv-non-isa/riscv-c-api-doc/pull/67 */
 static riscv_cc
 riscv_vls_cc_function_abi (const_tree fntype, bool check_only)
 {
-  tree attr = TYPE_ATTRIBUTES (fntype);
-  bool vls_cc_p = lookup_attribute ("vls_cc", attr) != NULL_TREE
-                 || lookup_attribute ("riscv_vls_cc", attr) != NULL_TREE;
+  tree attr = riscv_lookup_vls_cc_attribute (TYPE_ATTRIBUTES (fntype));
 
-  if (!vls_cc_p)
+  if (!attr)
     return RISCV_CC_UNKNOWN;
 
   if (!TARGET_VECTOR && !check_only)
     error_at (input_location,
              "function attribute %qs requires the vector ISA extension",
              "riscv_vls_cc");
-
   tree args = TREE_VALUE (attr);
-  return riscv_get_vls_cc_attr (args);
+  return riscv_get_vls_cc_attr (args, check_only);
 }
 
 /* Implementation of TARGET_FNTYPE_ABI, but one extra parameter `check_only`
@@ -8203,6 +8212,34 @@ riscv_fntype_abi (const_tree fntype)
   return riscv_fntype_abi_1 (fntype, /* check_only */true);
 }
 
+/* Implement TARGET_CXX_IMPLICIT_ABI_TAGS.  The psABI tags a function using the
+   fixed-length vector calling convention with riscv_vls_cc_<ABI_VLEN>.  */
+
+static tree
+riscv_cxx_implicit_abi_tags (const_tree decl)
+{
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    return NULL_TREE;
+
+  /* On a template the attribute only reaches the type at instantiation.  */
+  tree attr
+    = riscv_lookup_vls_cc_attribute (TYPE_ATTRIBUTES (TREE_TYPE (decl)));
+  if (!attr)
+    attr = riscv_lookup_vls_cc_attribute (DECL_ATTRIBUTES (decl));
+  if (!attr)
+    return NULL_TREE;
+
+  riscv_cc cc = riscv_get_vls_cc_attr (TREE_VALUE (attr),
+                                      /* check_only */ true);
+  if (!riscv_vls_cc_p (cc))
+    return NULL_TREE;
+
+  char tag[sizeof ("riscv_vls_cc_") + 3 * sizeof (unsigned int)];
+  int len = snprintf (tag, sizeof (tag), "riscv_vls_cc_%u",
+                     riscv_get_cc_abi_vlen (cc));
+  return build_tree_list (NULL_TREE, build_string (len + 1, tag));
+}
+
 /* Handle an attribute requiring a FUNCTION_DECL;
    arguments as in struct attribute_spec.handler.  */
 static tree
@@ -17164,6 +17201,9 @@ riscv_memtag_tag_bitsize ()
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE riscv_mangle_type
 
+#undef TARGET_CXX_IMPLICIT_ABI_TAGS
+#define TARGET_CXX_IMPLICIT_ABI_TAGS riscv_cxx_implicit_abi_tags
+
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P riscv_scalar_mode_supported_p
 
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index bdd62611c5b..6436a5b4760 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -1668,6 +1668,13 @@ write_unqualified_name (tree decl)
        if (!abi_check (11))
          tags = chainon (mtags, tags);
       }
+  /* A template-id is mangled from its template, so ask about the pattern.  */
+  tree tdecl = decl;
+  if (TREE_CODE (tdecl) == TEMPLATE_DECL)
+    tdecl = DECL_TEMPLATE_RESULT (tdecl);
+  if (tdecl)
+    if (tree itags = targetm.cxx.implicit_abi_tags (tdecl))
+      tags = chainon (itags, tags);
   write_abi_tags (tags);
 }
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 2613b95775b..4a800907657 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11367,6 +11367,14 @@ visibility or perform any other required target 
modifications).
 Return target-specific mangling context of @var{decl} or @code{NULL_TREE}.
 @end deftypefn
 
+@deftypefn {Target Hook} tree TARGET_CXX_IMPLICIT_ABI_TAGS (const_tree 
@var{decl})
+Return a freshly built @code{TREE_LIST} of ABI tags that the C++ mangler
+must add to the name of @var{decl} on top of the tags from its
+@code{abi_tag} attribute, or @code{NULL_TREE}.  Each @code{TREE_VALUE} is a
+@code{STRING_CST} holding one tag.  A target needs this when its psABI asks
+for an ABI tag on functions that use a calling convention variant.
+@end deftypefn
+
 @node D Language and ABI
 @section D ABI parameters
 @cindex parameters, d abi
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 0d2a76ec6b0..e565fd74ef5 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -7298,6 +7298,8 @@ floating-point support; they are not included in this 
mechanism.
 
 @hook TARGET_CXX_DECL_MANGLING_CONTEXT
 
+@hook TARGET_CXX_IMPLICIT_ABI_TAGS
+
 @node D Language and ABI
 @section D ABI parameters
 @cindex parameters, d abi
diff --git a/gcc/target.def b/gcc/target.def
index bf2825e991d..b896918811e 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6798,6 +6798,16 @@ DEFHOOK
  tree, (const_tree decl),
  hook_tree_const_tree_null)
 
+DEFHOOK
+(implicit_abi_tags,
+ "Return a freshly built @code{TREE_LIST} of ABI tags that the C++ mangler\n\
+must add to the name of @var{decl} on top of the tags from its\n\
+@code{abi_tag} attribute, or @code{NULL_TREE}.  Each @code{TREE_VALUE} is a\n\
+@code{STRING_CST} holding one tag.  A target needs this when its psABI asks\n\
+for an ABI tag on functions that use a calling convention variant.",
+ tree, (const_tree decl),
+ hook_tree_const_tree_null)
+
 HOOK_VECTOR_END (cxx)
 
 /* Functions and data for emulated TLS support.  */
diff --git a/gcc/testsuite/g++.target/riscv/mangle-vls-cc.C 
b/gcc/testsuite/g++.target/riscv/mangle-vls-cc.C
new file mode 100644
index 00000000000..1dda4266a0c
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/mangle-vls-cc.C
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d" } */
+
+/* The psABI asks a function using a standard calling convention variant to
+   append an ABI tag to its mangled name.  */
+
+__attribute__((riscv_vls_cc)) void default_vls_cc () {}
+
+__attribute__((riscv_vls_cc(32))) void vlen_32 () {}
+
+__attribute__((riscv_vls_cc(128))) void vlen_128 () {}
+
+__attribute__((riscv_vls_cc(16384))) void vlen_16384 () {}
+
+namespace v64 { __attribute__((riscv_vls_cc(64))) void f () {} }
+namespace v512 { __attribute__((riscv_vls_cc(512))) void f () {} }
+
+typedef void vls_fn_t (void) __attribute__((riscv_vls_cc(256)));
+vls_fn_t from_typedef;
+void from_typedef () {}
+
+__attribute__((abi_tag("user"))) __attribute__((riscv_vls_cc(128)))
+void tagged () {}
+
+__attribute__((abi_tag("user", "abc"), riscv_vls_cc(128)))
+void tagged2 () {}
+
+namespace ns {
+  struct S {
+    __attribute__((riscv_vls_cc(128))) void member () {}
+  };
+  void instantiate () { S ().member (); }
+}
+
+template <typename T> __attribute__((riscv_vls_cc(128))) void tpl (T) {}
+template void tpl<int> (int);
+
+/* The VLA vector calling convention variant has no ABI tag.  */
+__attribute__((riscv_vector_cc)) void vector_cc () {}
+
+void plain () {}
+
+/* { dg-final { scan-assembler "_Z14default_vls_ccB16riscv_vls_cc_128v:" } } */
+/* { dg-final { scan-assembler "_Z7vlen_32B15riscv_vls_cc_32v:" } } */
+/* { dg-final { scan-assembler "_Z8vlen_128B16riscv_vls_cc_128v:" } } */
+/* { dg-final { scan-assembler "_Z10vlen_16384B18riscv_vls_cc_16384v:" } } */
+/* { dg-final { scan-assembler "_ZN3v641fB15riscv_vls_cc_64Ev:" } } */
+/* { dg-final { scan-assembler "_ZN4v5121fB16riscv_vls_cc_512Ev:" } } */
+/* { dg-final { scan-assembler "_Z12from_typedefB16riscv_vls_cc_256v:" } } */
+/* { dg-final { scan-assembler "_Z6taggedB16riscv_vls_cc_128B4userv:" } } */
+/* { dg-final { scan-assembler "_Z7tagged2B3abcB16riscv_vls_cc_128B4userv:" } 
} */
+/* { dg-final { scan-assembler "_ZN2ns1S6memberB16riscv_vls_cc_128Ev:" } } */
+/* { dg-final { scan-assembler "_Z3tplB16riscv_vls_cc_128IiEvT_:" } } */
+/* { dg-final { scan-assembler "_Z9vector_ccv:" } } */
+/* { dg-final { scan-assembler "_Z5plainv:" } } */
-- 
2.54.0

Reply via email to