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 > >
