NOTE: I added a new hook TARGET_CXX_IMPLICIT_ABI_TAGS to C++ FE in this
patch, so cc Jason and Nathon.

On Thu, Aug 27, 2026 at 4:10 PM Kito Cheng <[email protected]> wrote:

> 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