https://gcc.gnu.org/g:d3726407bde51b93deef248863192b3c9e09c9ae

commit r17-5816-gd3726407bde51b93deef248863192b3c9e09c9ae
Author: Kito Cheng <[email protected]>
Date:   Wed Sep 2 20:24:22 2026 +0800

    RISC-V: Mangle the ABI tag of a standard calling convention variant
    
    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.
    
    [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:
    
            * 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_abi_tag_present_p): New function.
            (riscv_insert_attributes): New function.
            (TARGET_INSERT_ATTRIBUTES): Define.
    
    gcc/testsuite/ChangeLog:
    
            * g++.target/riscv/mangle-vls-cc.C: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                      | 108 ++++++++++++++++++++++---
 gcc/testsuite/g++.target/riscv/mangle-vls-cc.C |  63 +++++++++++++++
 2 files changed, 160 insertions(+), 11 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 517e4f995775..960ab7ae8311 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -8184,30 +8184,40 @@ 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)
@@ -8216,7 +8226,80 @@ riscv_vls_cc_function_abi (const_tree fntype, bool 
check_only)
              "riscv_vls_cc");
 
   tree args = TREE_VALUE (attr);
-  return riscv_get_vls_cc_attr (args);
+  return riscv_get_vls_cc_attr (args, check_only);
+}
+
+/* Return true if ATTRS already carries the ABI tag TAG.  */
+
+static bool
+riscv_abi_tag_present_p (tree attrs, const char *tag)
+{
+  for (tree a = lookup_attribute ("abi_tag", attrs); a;
+       a = lookup_attribute ("abi_tag", TREE_CHAIN (a)))
+    for (tree v = TREE_VALUE (a); v; v = TREE_CHAIN (v))
+      {
+       tree s = TREE_VALUE (v);
+       if (s && TREE_CODE (s) == STRING_CST
+           && strcmp (TREE_STRING_POINTER (s), tag) == 0)
+         return true;
+      }
+  return false;
+}
+
+/* Implement TARGET_INSERT_ATTRIBUTES.  The psABI tags a function using the
+   fixed-length vector calling convention with riscv_vls_cc_<ABI_VLEN>.  The
+   hook runs from decl_attributes before ATTRIBUTES is applied, so the
+   convention is looked for there as well as on the type and on the decl.  */
+
+static void
+riscv_insert_attributes (tree node, tree *attributes)
+{
+  if (!lang_GNU_CXX () || TREE_CODE (node) != FUNCTION_DECL)
+    return;
+
+  tree attr = riscv_lookup_vls_cc_attribute (*attributes);
+  if (!attr && TREE_TYPE (node))
+    attr = riscv_lookup_vls_cc_attribute (TYPE_ATTRIBUTES (TREE_TYPE (node)));
+  if (!attr)
+    attr = riscv_lookup_vls_cc_attribute (DECL_ATTRIBUTES (node));
+  if (!attr)
+    return;
+
+  riscv_cc cc = riscv_get_vls_cc_attr (TREE_VALUE (attr),
+                                      /* check_only */ true);
+  if (!riscv_vls_cc_p (cc))
+    return;
+
+  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));
+
+  if (riscv_abi_tag_present_p (*attributes, tag)
+      || riscv_abi_tag_present_p (DECL_ATTRIBUTES (node), tag))
+    return;
+
+  tree str = build_string (len + 1, tag);
+  /* check_abi_tag_args insists on a real narrow string literal type.  */
+  TREE_TYPE (str) = build_array_type (char_type_node,
+                                     build_index_type (size_int (len)));
+
+  tree existing = lookup_attribute ("abi_tag", *attributes);
+  if (existing)
+    {
+      /* The list may be shared with other decls, so copy before touching it.  
*/
+      tree copy = copy_list (*attributes);
+      tree slot = lookup_attribute ("abi_tag", copy);
+      TREE_VALUE (slot) = chainon (copy_list (TREE_VALUE (slot)),
+                                  build_tree_list (NULL_TREE, str));
+      *attributes = copy;
+    }
+  else
+    /* Attach it directly instead of through ATTRIBUTES: decl_attributes would
+       run handle_abi_tag_attribute, which rejects an extern "C" declaration,
+       and riscv_vls_cc on one is valid today.  */
+    DECL_ATTRIBUTES (node) = tree_cons (get_identifier ("abi_tag"),
+                                       build_tree_list (NULL_TREE, str),
+                                       DECL_ATTRIBUTES (node));
 }
 
 /* Implementation of TARGET_FNTYPE_ABI, but one extra parameter `check_only`
@@ -17312,6 +17395,9 @@ riscv_memtag_tag_bitsize ()
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE riscv_mangle_type
 
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES riscv_insert_attributes
+
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P riscv_scalar_mode_supported_p
 
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 000000000000..849debce4f95
--- /dev/null
+++ b/gcc/testsuite/g++.target/riscv/mangle-vls-cc.C
@@ -0,0 +1,63 @@
+/* { 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);
+
+template <typename T> __attribute__((riscv_vls_cc(128))) void tpl_nodep () {}
+template void tpl_nodep<int> ();
+
+/* extern "C" has no mangling, so no tag, but it still has to compile.  */
+extern "C" __attribute__((riscv_vls_cc(128))) void cfn () {}
+
+/* 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 "_Z3tplIiEvT_:" } } */
+/* { dg-final { scan-assembler "_Z9tpl_nodepB16riscv_vls_cc_128IiEvv:" } } */
+/* { dg-final { scan-assembler "_Z9vector_ccv:" } } */
+/* { dg-final { scan-assembler "_Z5plainv:" } } */
+/* { dg-final { scan-assembler "\ncfn:" } } */

Reply via email to