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:" } } */
