On Mon, 25 May 2026, Kito Cheng wrote: > Hi Luis: > > Really happy to see you address this issue correctly :) > > I am not expert on the LTO part, but I would suggest you to split this > into two part: > 1) Implement a target hook to generalized the interface for target > specific data for LTO section > 2) Introduce APEX/RISC-V specific implementation > > I think introducing target specific on generic code is OK, but that > should introduce via adding new hook. > > cc Richard B. and Jan H. for more input on this since this is out of > RISC-V scope
Please give an overview of what APEX is and why LTO currently cannot handle it. Richard. > > Luis Silva <[email protected]> 於 2026年5月25日週一 下午10:26寫道: > > > > > This patch adds Link-Time Optimization support for APEX custom instructions > > by serializing pragma-registered builtin metadata across compilation units. > > > > Since APEX intrinsics are registered dynamically via #pragma intrinsic > > rather than predefined in the compiler, their metadata (name, mnemonic, > > opcode, format) must be explicitly streamed to survive LTO. The > > implementation adds a custom LTO section (LTO_section_riscv_apex) and > > hooks into the LTO write/read phases. > > > > During output (arcv_apex_lto_write_section), referenced APEX builtins are > > serialized to the LTO stream. During input (arcv_apex_lto_read_section), > > builtin metadata from all compilation units is deserialized and > > re-registered. > > The arcv_apex_lto_lookup_builtin function detects conflicting definitions > > across translation units and reports errors. > > > > However, LTO exposes a latent hash-equality inconsistency in fold-const.cc > > for BUILT_IN_MD and BUILT_IN_FRONTEND builtins: operand_equal_p considers > > two builtin FUNCTION_DECLs equal when they share DECL_BUILT_IN_CLASS and > > DECL_UNCHECKED_FUNCTION_CODE, but hash_operand only canonicalizes > > BUILT_IN_NORMAL builtins and falls back to hashing DECL_UID for other > > classes. When APEX builtins are re-registered across TUs with distinct > > FUNCTION_DECL nodes but identical builtin metadata, verify_hash_value > > asserts due to the hash/equality mismatch. > > > > This patch also fixes the issue by hashing non-BUILT_IN_NORMAL builtins > > using > > (DECL_BUILT_IN_CLASS, DECL_UNCHECKED_FUNCTION_CODE), matching what > > operand_equal_p compares. > > > > gcc/ChangeLog: > > > > * config/riscv/arcv-builtins.cc (arcv_apex_lto_lookup_builtin): New > > function to find existing builtin and detect conflicts. > > (arcv_apex_lto_register_builtin): New function to register builtin > > during LTO read, skipping duplicates and reporting conflicts. > > (arcv_apex_lto_write_section): New function to serialize referenced > > APEX builtins to LTO stream. > > (arcv_apex_lto_read_section): New function to deserialize and > > re-register APEX builtins from all LTO input files. > > * config/riscv/riscv-builtins.cc (riscv_builtin_decl): Remove > > RISCV_BUILTIN_APEX sorry diagnostic for LTO. > > * config/riscv/riscv.h (TARGET_RISCV_APEX): Define. > > * lto-section-in.cc (lto_section_name): Add "riscv.apex" section > > name. > > * lto-streamer-out.cc (produce_asm_for_decls): Call > > arcv_apex_lto_write_section. > > * lto-streamer.h (enum lto_section_type): Add > > LTO_section_riscv_apex. > > (arcv_apex_lto_write_section): Declare. > > (arcv_apex_lto_read_section): Declare. > > > > gcc/lto/ChangeLog: > > > > * lto-common.cc (read_cgraph_and_symbols): Call > > arcv_apex_lto_read_section after reading all input files. > > > > gcc/testsuite/ChangeLog: > > > > * gcc.target/riscv/apex/apex.exp: Add LTO test support. > > * gcc.target/riscv/apex/arcv-apex-lto-err1_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err1_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err2_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err2_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err3_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err3_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err4_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-err4_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test1_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test1_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test2_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test2_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test3_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test3_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test4_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test4_1.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test5_0.c: New test. > > * gcc.target/riscv/apex/arcv-apex-lto-test5_1.c: New test. > > > > Signed-off-by: Luis Silva <[email protected]> > > --- > > gcc/config/riscv/arcv-builtins.cc | 233 ++++++++++++++++++ > > gcc/config/riscv/riscv-builtins.cc | 8 +- > > gcc/config/riscv/riscv.h | 2 + > > gcc/fold-const.cc | 12 + > > gcc/lto-section-in.cc | 1 + > > gcc/lto-streamer-out.cc | 6 + > > gcc/lto-streamer.h | 6 + > > gcc/lto/lto-common.cc | 6 + > > gcc/testsuite/gcc.target/riscv/apex/apex.exp | 27 +- > > .../riscv/apex/arcv-apex-lto-err1_0.c | 16 ++ > > .../riscv/apex/arcv-apex-lto-err1_1.c | 9 + > > .../riscv/apex/arcv-apex-lto-err2_0.c | 17 ++ > > .../riscv/apex/arcv-apex-lto-err2_1.c | 9 + > > .../riscv/apex/arcv-apex-lto-err3_0.c | 17 ++ > > .../riscv/apex/arcv-apex-lto-err3_1.c | 9 + > > .../riscv/apex/arcv-apex-lto-err4_0.c | 19 ++ > > .../riscv/apex/arcv-apex-lto-err4_1.c | 9 + > > .../riscv/apex/arcv-apex-lto-test1_0.c | 49 ++++ > > .../riscv/apex/arcv-apex-lto-test1_1.c | 25 ++ > > .../riscv/apex/arcv-apex-lto-test2_0.c | 36 +++ > > .../riscv/apex/arcv-apex-lto-test2_1.c | 15 ++ > > .../riscv/apex/arcv-apex-lto-test3_0.c | 49 ++++ > > .../riscv/apex/arcv-apex-lto-test3_1.c | 25 ++ > > .../riscv/apex/arcv-apex-lto-test4_0.c | 25 ++ > > .../riscv/apex/arcv-apex-lto-test4_1.c | 12 + > > .../riscv/apex/arcv-apex-lto-test5_0.c | 52 ++++ > > .../riscv/apex/arcv-apex-lto-test5_1.c | 20 ++ > > 27 files changed, 708 insertions(+), 6 deletions(-) > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_1.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_0.c > > create mode 100644 > > gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_1.c > > > > diff --git a/gcc/config/riscv/arcv-builtins.cc > > b/gcc/config/riscv/arcv-builtins.cc > > index d8a633fe56c..fee8146ec6f 100644 > > --- a/gcc/config/riscv/arcv-builtins.cc > > +++ b/gcc/config/riscv/arcv-builtins.cc > > @@ -40,6 +40,10 @@ along with GCC; see the file COPYING3. If not see > > #include "backend.h" > > #include "gimple.h" > > #include "gimple-iterator.h" > > +#include "cgraph.h" > > +#include "lto-streamer.h" > > +#include "ipa-utils.h" > > +#include "data-streamer.h" > > > > /* Specifies how a built-in function should be converted into rtl. */ > > enum riscv_builtin_type { > > @@ -394,6 +398,235 @@ arcv_apex_register_builtin (tree fndecl, const char > > *fn_name, > > arcv_apex_emit_ext_directive (mnemonic, opcode, format_flags); > > } > > > > +/* Check if an APEX builtin with the given characteristics already exists. > > + Returns the index if found with matching parameters, -1 if not found, > > + or -2 if found but with conflicting parameters. */ > > + > > +static int > > +arcv_apex_lto_lookup_builtin (const char *fn_name, const char *mnemonic, > > + unsigned int opcode, unsigned int format_flags, > > + location_t loc) > > +{ > > + for (int i = 0; i < arcv_apex_builtin_index; i++) > > + { > > + const struct arcv_apex_builtin_description *d = > > &arcv_apex_builtins[i]; > > + > > + /* Skip if function name doesn't match. */ > > + if (strcmp (d->name, fn_name) != 0) > > + continue; > > + > > + /* Function name matches - validate all parameters. */ > > + bool mismatch = false; > > + > > + if (strcmp (d->mnemonic, mnemonic) != 0) > > + { > > + warning_at (loc, 0, "APEX builtin %qs already registered with " > > + "different mnemonic: %qs vs %qs", > > + fn_name, d->mnemonic, mnemonic); > > + mismatch = true; > > + } > > + > > + if (d->opcode != opcode) > > + { > > + warning_at (loc, 0, "APEX builtin %qs already registered with " > > + "different opcode: 0x%x vs 0x%x", > > + fn_name, d->opcode, opcode); > > + mismatch = true; > > + } > > + > > + if (d->format_flags != format_flags) > > + { > > + warning_at (loc, 0, "APEX builtin %qs already registered with " > > + "different instruction formats: 0x%x vs 0x%x", > > + fn_name, d->format_flags, format_flags); > > + mismatch = true; > > + } > > + > > + /* Return -2 for conflicting registration, or index if match. */ > > + return mismatch ? -2 : i; > > + } > > + > > + return -1; > > +} > > + > > +static void > > +arcv_apex_lto_register_builtin (const char *fn_name, const char *mnemonic, > > + unsigned int opcode, unsigned int > > format_flags, > > + bool emit_directive_p, tree fndecl) > > +{ > > + location_t loc = DECL_SOURCE_LOCATION (fndecl); > > + > > + int existing_idx = arcv_apex_lto_lookup_builtin (fn_name, mnemonic, > > opcode, > > + format_flags, loc); > > + > > + if (existing_idx == -2) > > + { > > + error_at (loc, "APEX builtin %qs has conflicting definitions across " > > + "compilation units", fn_name); > > + return; > > + } > > + > > + if (existing_idx >= 0) > > + { > > + fndecl->function_decl.function_code > > + = (existing_idx << RISCV_BUILTIN_SHIFT) + RISCV_BUILTIN_APEX; > > + return; > > + } > > + > > + gcc_assert (arcv_apex_builtin_index < arcv_apex_builtins_limit); > > + > > + enum riscv_builtin_type builtin_type > > + = (format_flags & APEX_VOID) ? RISCV_BUILTIN_DIRECT_NO_TARGET > > + : RISCV_BUILTIN_DIRECT; > > + > > + enum insn_code icode = arcv_apex_icode (format_flags); > > + > > + /* Store APEX insn information. */ > > + arcv_apex_builtins[arcv_apex_builtin_index] > > + = { icode, xstrdup (fn_name), xstrdup (mnemonic), opcode, > > + builtin_type, format_flags }; > > + > > + fndecl->function_decl.function_code > > + = (arcv_apex_builtin_index << RISCV_BUILTIN_SHIFT) + > > RISCV_BUILTIN_APEX; > > + > > + arcv_apex_builtin_index++; > > + > > + if (emit_directive_p) > > + arcv_apex_emit_ext_directive (mnemonic, opcode, format_flags); > > +} > > + > > +/* LTO serialization for APEX intrinsics. > > + > > + APEX intrinsics are registered dynamically via #pragma intrinsic, > > + so their metadata must be explicitly serialized to survive LTO. > > + See lto-streamer-out.cc (produce_asm_for_decls) and > > + lto/lto-common.cc (read_cgraph_and_symbols) for the call sites. */ > > + > > +/* Serialize all referenced APEX intrinsics to the LTO stream. */ > > + > > +void > > +arcv_apex_lto_write_section (void) > > +{ > > + if (arcv_apex_builtin_index == 0) > > + return; > > + > > + auto_vec<int> used_indices; > > + for (int i = 0; i < arcv_apex_builtin_index; i++) > > + { > > + const struct arcv_apex_builtin_description *d = > > &arcv_apex_builtins[i]; > > + gcc_assert (d->name); > > + > > + symtab_node *snode > > + = symtab_node::get_for_asmname (get_identifier (d->name)); > > + > > + if (snode && snode->referred_to_p ()) > > + used_indices.safe_push (i); > > + } > > + > > + if (used_indices.is_empty ()) > > + return; > > + > > + struct lto_simple_output_block *ob > > + = lto_create_simple_output_block (LTO_section_riscv_apex); > > + > > + if (!ob) > > + return; > > + > > + streamer_write_uhwi_stream (ob->main_stream, used_indices.length ()); > > + > > + for (unsigned int idx = 0; idx < used_indices.length (); idx++) > > + { > > + const struct arcv_apex_builtin_description *d > > + = &arcv_apex_builtins[used_indices[idx]]; > > + > > + gcc_assert (d->name && d->mnemonic); > > + > > + size_t name_len = strlen (d->name); > > + streamer_write_uhwi_stream (ob->main_stream, name_len); > > + for (size_t j = 0; j < name_len; j++) > > + streamer_write_char_stream (ob->main_stream, d->name[j]); > > + > > + size_t mnemonic_len = strlen (d->mnemonic); > > + streamer_write_uhwi_stream (ob->main_stream, mnemonic_len); > > + for (size_t j = 0; j < mnemonic_len; j++) > > + streamer_write_char_stream (ob->main_stream, d->mnemonic[j]); > > + > > + streamer_write_uhwi_stream (ob->main_stream, d->opcode); > > + streamer_write_uhwi_stream (ob->main_stream, d->format_flags); > > + } > > + > > + lto_destroy_simple_output_block (ob); > > +} > > + > > +/* Deserialize and re-register APEX intrinsics from all LTO input files. > > */ > > + > > +void > > +arcv_apex_lto_read_section (void) > > +{ > > + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); > > + struct lto_file_decl_data *file_data; > > + unsigned int j = 0; > > + > > + while ((file_data = file_data_vec[j++])) > > + { > > + const char *data; > > + size_t len; > > + class lto_input_block *ib > > + = lto_create_simple_input_block (file_data, LTO_section_riscv_apex, > > + &data, &len); > > + > > + if (!ib) > > + continue; > > + > > + unsigned int apex_count = streamer_read_uhwi (ib); > > + unsigned int registered_count = 0; > > + > > + for (unsigned int i = 0; i < apex_count; i++) > > + { > > + unsigned int fn_name_len = streamer_read_uhwi (ib); > > + char *fn_name = XNEWVEC (char, fn_name_len + 1); > > + for (unsigned int k = 0; k < fn_name_len; k++) > > + fn_name[k] = streamer_read_uchar (ib); > > + fn_name[fn_name_len] = '\0'; > > + > > + unsigned int mnemonic_len = streamer_read_uhwi (ib); > > + char *mnemonic = XNEWVEC (char, mnemonic_len + 1); > > + for (unsigned int k = 0; k < mnemonic_len; k++) > > + mnemonic[k] = streamer_read_uchar (ib); > > + mnemonic[mnemonic_len] = '\0'; > > + > > + unsigned int opcode = streamer_read_uhwi (ib); > > + unsigned int format_flags = streamer_read_uhwi (ib); > > + > > + symtab_node *snode > > + = symtab_node::get_for_asmname (get_identifier (fn_name)); > > + > > + cgraph_node *node = dyn_cast<cgraph_node *> (snode); > > + if (node) > > + { > > + tree fndecl = node->decl; > > + if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL) > > + { > > + arcv_apex_lto_register_builtin (fn_name, mnemonic, opcode, > > + format_flags, !flag_wpa, > > + fndecl); > > + registered_count++; > > + } > > + } > > + > > + XDELETEVEC (fn_name); > > + XDELETEVEC (mnemonic); > > + } > > + > > + if (registered_count != apex_count) > > + warning (0, "APEX LTO: expected %u intrinsics but registered %u", > > + apex_count, registered_count); > > + > > + lto_destroy_simple_input_block (file_data, LTO_section_riscv_apex, > > + ib, data, len); > > + } > > +} > > + > > /* Validate the immediate argument passed to an APEX intrinsic. > > Used during builtin expansion. */ > > > > diff --git a/gcc/config/riscv/riscv-builtins.cc > > b/gcc/config/riscv/riscv-builtins.cc > > index d58915799f1..5a189fc6014 100644 > > --- a/gcc/config/riscv/riscv-builtins.cc > > +++ b/gcc/config/riscv/riscv-builtins.cc > > @@ -317,10 +317,10 @@ riscv_builtin_decl (unsigned int code, bool > > initialize_p ATTRIBUTE_UNUSED) > > return riscv_vector::builtin_decl (subcode, initialize_p); > > > > case RISCV_BUILTIN_APEX: > > - /* APEX intrinsics are pragma-registered and don't have > > - persistent decls. */ > > - sorry ("APEX intrinsics are not supported with LTO yet"); > > - return error_mark_node; > > + /* Trick GCC to think that the function is defined. > > + The actual fndecl used is created after this > > + validation from the GIMPLE representation in LTO. */ > > + return integer_zero_node; > > } > > return error_mark_node; > > } > > diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h > > index f9a5bb02337..ca8f9090660 100644 > > --- a/gcc/config/riscv/riscv.h > > +++ b/gcc/config/riscv/riscv.h > > @@ -1349,6 +1349,8 @@ typedef enum { > > #ifndef RISCV_APEX_H > > #define RISCV_APEX_H > > > > +#define TARGET_RISCV_APEX 1 > > + > > /* APEX instruction format flags. */ > > enum apex_insn_format { > > APEX_NONE = 0, > > diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc > > index 352083e146b..f7e30c11f3d 100644 > > --- a/gcc/fold-const.cc > > +++ b/gcc/fold-const.cc > > @@ -4118,6 +4118,18 @@ operand_compare::hash_operand (const_tree t, > > inchash::hash &hstate, > > t = builtin_decl_explicit (DECL_FUNCTION_CODE (t)); > > code = TREE_CODE (t); > > } > > + /* For non-BUILT_IN_NORMAL builtins (e.g. BUILT_IN_MD), we cannot > > + canonicalize to a single representative decl, but we must still > > + hash consistently with operand_equal_p which compares by > > + built_in_class + function_code. Hash those fields instead of > > + DECL_UID so that distinct FUNCTION_DECLs (e.g. from different > > + LTO translation units) that compare equal also hash equal. */ > > + else if (fndecl_built_in_p (t)) > > + { > > + hstate.add_int (DECL_BUILT_IN_CLASS (t)); > > + hstate.add_hwi (DECL_UNCHECKED_FUNCTION_CODE (t)); > > + return; > > + } > > /* FALL THROUGH */ > > default: > > if (POLY_INT_CST_P (t)) > > diff --git a/gcc/lto-section-in.cc b/gcc/lto-section-in.cc > > index c57f84f02bd..892ce06bafd 100644 > > --- a/gcc/lto-section-in.cc > > +++ b/gcc/lto-section-in.cc > > @@ -57,6 +57,7 @@ const char *lto_section_name[LTO_N_SECTION_TYPES] = > > "ipa_sra", > > "odr_types", > > "ipa_modref", > > + "riscv_apex", > > }; > > > > /* Hooks so that the ipa passes can call into the lto front end to get > > diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc > > index 5338a952cb0..cc746e1c5aa 100644 > > --- a/gcc/lto-streamer-out.cc > > +++ b/gcc/lto-streamer-out.cc > > @@ -3474,6 +3474,12 @@ produce_asm_for_decls (void) > > /* Write command line opts. */ > > lto_write_options (); > > > > +#ifdef TARGET_RISCV_APEX > > + /* RISC-V APEX intrinsics are registered dynamically via pragmas and > > + need explicit serialization to survive LTO. See arcv-builtins.cc. */ > > + arcv_apex_lto_write_section (); > > +#endif > > + > > /* Deallocate memory and clean up. */ > > for (idx = 0; idx < num_fns; idx++) > > { > > diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h > > index f8aa8465b7c..8e86816ec0a 100644 > > --- a/gcc/lto-streamer.h > > +++ b/gcc/lto-streamer.h > > @@ -225,6 +225,7 @@ enum lto_section_type > > LTO_section_ipa_sra, > > LTO_section_odr_types, > > LTO_section_ipa_modref, > > + LTO_section_riscv_apex, > > LTO_N_SECTION_TYPES /* Must be last. */ > > }; > > > > @@ -966,6 +967,11 @@ void cl_optimization_stream_in (class data_in *, > > /* In lto-opts.cc. */ > > extern void lto_write_options (void); > > > > +#ifdef TARGET_RISCV_APEX > > +/* In config/riscv/arcv-builtins.cc. */ > > +extern void arcv_apex_lto_write_section (void); > > +extern void arcv_apex_lto_read_section (void); > > +#endif > > > > /* Statistics gathered during LTO, WPA and LTRANS. */ > > extern struct lto_stats_d lto_stats; > > diff --git a/gcc/lto/lto-common.cc b/gcc/lto/lto-common.cc > > index cc513b84ef1..50047bec95b 100644 > > --- a/gcc/lto/lto-common.cc > > +++ b/gcc/lto/lto-common.cc > > @@ -2970,6 +2970,12 @@ read_cgraph_and_symbols (unsigned nfiles, const char > > **fnames) > > else > > ipa_read_summaries (); > > > > +#ifdef TARGET_RISCV_APEX > > + /* RISC-V APEX intrinsics are registered dynamically via pragmas and > > + need explicit deserialization after LTO input. See arcv-builtins.cc. > > */ > > + arcv_apex_lto_read_section (); > > +#endif > > + > > ggc_grow (); > > > > for (i = 0; all_file_decl_data[i]; i++) > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/apex.exp > > b/gcc/testsuite/gcc.target/riscv/apex/apex.exp > > index 07a23718671..44e3acc2232 100644 > > --- a/gcc/testsuite/gcc.target/riscv/apex/apex.exp > > +++ b/gcc/testsuite/gcc.target/riscv/apex/apex.exp > > @@ -23,8 +23,31 @@ if ![istarget riscv*-*-*] then { > > > > # Load support libraries. > > load_lib gcc-dg.exp > > +load_lib standard.exp > > +load_lib lto.exp > > +load_lib scanltrans.exp > > > > -# Run tests. > > +# Run regular single-file tests. > > dg-init > > -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "" "" > > +set tests [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] > > +set non_lto_tests [list] > > +foreach test $tests { > > + if {![string match "*arcv-apex-lto-*" $test]} { > > + lappend non_lto_tests $test > > + } > > +} > > +dg-runtest $non_lto_tests "" "" > > dg-finish > > + > > +# Run multi-file LTO tests if supported. > > +if [check_effective_target_lto] { > > + lto_init no-mathlib > > + > > + foreach src [lsort [find $srcdir/$subdir arcv-apex-lto-*_0.c]] { > > + if [runtest_file_p $runtests $src] { > > + lto-execute $src "riscv_apex_lto" > > + } > > + } > > + > > + lto_finish > > +} > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_0.c > > new file mode 100644 > > index 00000000000..263eec7f545 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_0.c > > @@ -0,0 +1,16 @@ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 } } } */ > > + > > +int apex_conflict (int, int); > > +#pragma intrinsic (apex_conflict, "conflict", 50, "XS") > > + > > +extern int use_conflict (int, int); > > + > > +int > > +main (void) > > +{ > > + return apex_conflict (1, 2) + use_conflict (5, 10); > > +} > > + > > +/* { dg-lto-warning "APEX builtin 'apex_conflict' already registered with > > different opcode: 0x32 vs 0x33" "" { target *-*-* } 4 } */ > > +/* { dg-lto-error "APEX builtin 'apex_conflict' has conflicting > > definitions across compilation units" "" { target *-*-* } 4 } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_1.c > > new file mode 100644 > > index 00000000000..9ec7e518ccb > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err1_1.c > > @@ -0,0 +1,9 @@ > > + > > +int apex_conflict (int, int); > > +#pragma intrinsic (apex_conflict, "conflict", 51, "XS") /* Different > > opcode: 51 vs 50 */ > > + > > +int > > +use_conflict (int a, int b) > > +{ > > + return apex_conflict (a, b); > > +} > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_0.c > > new file mode 100644 > > index 00000000000..757419626dc > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_0.c > > @@ -0,0 +1,17 @@ > > +/* Test LTO error detection for instruction name mismatch */ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 } } } */ > > + > > +int apex_insn_mismatch (int, int); > > +#pragma intrinsic (apex_insn_mismatch, "insn_a", 100, "XD") > > + > > +extern int use_insn_mismatch (int, int); > > + > > +int > > +main (void) > > +{ > > + return apex_insn_mismatch (1, 2) + use_insn_mismatch (5, 10); > > +} > > + > > +/* { dg-lto-warning "APEX builtin 'apex_insn_mismatch' already registered > > with different mnemonic: 'insn_a' vs 'insn_b'" "" { target *-*-* } 5 } */ > > +/* { dg-lto-error "APEX builtin 'apex_insn_mismatch' has conflicting > > definitions across compilation units" "" { target *-*-* } 5 } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_1.c > > new file mode 100644 > > index 00000000000..7df812a4cd8 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err2_1.c > > @@ -0,0 +1,9 @@ > > + > > +int apex_insn_mismatch (int, int); > > +#pragma intrinsic (apex_insn_mismatch, "insn_b", 100, "XD") /* Different > > instruction name */ > > + > > +int > > +use_insn_mismatch (int a, int b) > > +{ > > + return apex_insn_mismatch (a, b); > > +} > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_0.c > > new file mode 100644 > > index 00000000000..b005b5525e2 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_0.c > > @@ -0,0 +1,17 @@ > > +/* Test LTO error detection for instruction format mismatch */ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 } } } */ > > + > > +int apex_format_mismatch (int, int); > > +#pragma intrinsic (apex_format_mismatch, "format_test", 20, "XS") > > + > > +extern int use_format_mismatch (int); > > + > > +int > > +main (void) > > +{ > > + return apex_format_mismatch (1, 2) + use_format_mismatch (5); > > +} > > + > > +/* { dg-lto-warning "APEX builtin 'apex_format_mismatch' already > > registered with different instruction formats: 0x2 vs 0x8" "" { target > > *-*-* } 5 } */ > > +/* { dg-lto-error "APEX builtin 'apex_format_mismatch' has conflicting > > definitions across compilation units" "" { target *-*-* } 5 } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_1.c > > new file mode 100644 > > index 00000000000..4efb805f31f > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err3_1.c > > @@ -0,0 +1,9 @@ > > + > > +int apex_format_mismatch (int, int); > > +#pragma intrinsic (apex_format_mismatch, "format_test", 20, "XC") /* > > Different format: XC vs XS */ > > + > > +int > > +use_format_mismatch (int a) > > +{ > > + return apex_format_mismatch (a, 10); > > +} > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_0.c > > new file mode 100644 > > index 00000000000..e9b3e8f742a > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_0.c > > @@ -0,0 +1,19 @@ > > +/* Test LTO error detection for multiple mismatches */ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 } } } */ > > + > > +int apex_multi_mismatch (int, int); > > +#pragma intrinsic (apex_multi_mismatch, "insn_original", 20, "XD") > > + > > +extern int use_multi_mismatch (int); > > + > > +int > > +main (void) > > +{ > > + return apex_multi_mismatch (1, 2) + use_multi_mismatch (5); > > +} > > + > > +/* { dg-lto-warning "APEX builtin 'apex_multi_mismatch' already registered > > with different mnemonic: 'insn_original' vs 'insn_different'" "" { target > > *-*-* } 5 } */ > > +/* { dg-lto-warning "APEX builtin 'apex_multi_mismatch' already registered > > with different opcode: 0x14 vs 0x15" "" { target *-*-* } 5 } */ > > +/* { dg-lto-warning "APEX builtin 'apex_multi_mismatch' already registered > > with different instruction formats: 0x1 vs 0x2" "" { target *-*-* } 5 } */ > > +/* { dg-lto-error "APEX builtin 'apex_multi_mismatch' has conflicting > > definitions across compilation units" "" { target *-*-* } 5 } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_1.c > > new file mode 100644 > > index 00000000000..1134e68e355 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-err4_1.c > > @@ -0,0 +1,9 @@ > > + > > +int apex_multi_mismatch (int, int); > > +#pragma intrinsic (apex_multi_mismatch, "insn_different", 21, "XS") /* > > All different */ > > + > > +int > > +use_multi_mismatch (int a) > > +{ > > + return apex_multi_mismatch (a, 10); > > +} > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_0.c > > new file mode 100644 > > index 00000000000..fb0ae276394 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_0.c > > @@ -0,0 +1,49 @@ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 -fdump-tree-optimized -save-temps } } } > > */ > > + > > +int func_apex_xd (int, int); > > +#pragma intrinsic (func_apex_xd, "insn_apex_xd", 50, "XD") > > + > > +int func_apex_xs (int, int); > > +#pragma intrinsic (func_apex_xs, "insn_apex_xs", 32, "XS") > > + > > +int func_apex_xi (int); > > +#pragma intrinsic (func_apex_xi, "insn_apex_xi", 20, "XI") > > + > > +int func_apex_xc (int, int); > > +#pragma intrinsic (func_apex_xc, "insn_apex_xc", 21, "XC") > > + > > +extern int foo (int); > > + > > +int > > +main (void) > > +{ > > + int x = func_apex_xd (1,2); > > + int y = func_apex_xs (x, 3); > > + int z = func_apex_xi (4); > > + int w = func_apex_xc (y, 5); > > + > > + return foo (y) + w + z; > > +} > > + > > +/* Verify that APEX intrinsic calls survive LTO optimization. */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xd" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xs" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xi" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xc" "optimized" } } */ > > + > > +/* Verify that the correct custom instructions are emitted in assembly. */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xd,50,XD" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xs,32,XS" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xi,20,XI" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xc,21,XC" } } */ > > + > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xd\\s+a\[0-9\]+,a\[0-9\]+,a\[0-9\]+" 2 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xs\\s+a\[0-9\]+,a\[0-9\]+,3" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times "insn_apex_xi\\s+a\[0-9\]+,4" > > 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xc\\s+a\[0-9\]+,a\[0-9\]+,5" 1 } } */ > > + > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xs\\s+a\[0-9\]+,a\[0-9\]+,8" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times "insn_apex_xi\\s+a\[0-9\]+,9" > > 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xc\\s+a\[0-9\]+,a\[0-9\]+,10" 1 } } */ > > + > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_1.c > > new file mode 100644 > > index 00000000000..e02a0cd5b1e > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test1_1.c > > @@ -0,0 +1,25 @@ > > + > > +int func_apex_xd (int, int); > > +#pragma intrinsic (func_apex_xd, "insn_apex_xd", 50, "XD") > > + > > +int func_apex_xs (int, int); > > +#pragma intrinsic (func_apex_xs, "insn_apex_xs", 32, "XS") > > + > > +int func_apex_xi (int); > > +#pragma intrinsic (func_apex_xi, "insn_apex_xi", 20, "XI") > > + > > +int func_apex_xc (int, int); > > +#pragma intrinsic (func_apex_xc, "insn_apex_xc", 21, "XC") > > + > > +extern int foo (int); > > + > > +int > > +foo (int val) > > +{ > > + int a = func_apex_xd (6, 7); > > + int b = func_apex_xs (val, 8); > > + int c = func_apex_xi (9); > > + int d = func_apex_xc (val, 10); > > + return a + b + c + d; > > +} > > + > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_0.c > > new file mode 100644 > > index 00000000000..c384a504425 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_0.c > > @@ -0,0 +1,36 @@ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 -fdump-tree-optimized -save-temps } } } > > */ > > + > > +int func_apex_xd (int, int); > > +#pragma intrinsic (func_apex_xd, "insn_apex_xd", 50, "XD") > > + > > +int func_apex_xs (int, int); > > +#pragma intrinsic (func_apex_xs, "insn_apex_xs", 32, "XS") > > + > > +extern int bar (int, int); > > + > > +int > > +main (void) > > +{ > > + int x = func_apex_xd (1, 2); > > + int y = func_apex_xs (x, 3); > > + > > + return bar (x, y); > > +} > > + > > +/* Verify that APEX intrinsic calls survive LTO optimization. */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xd" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xs" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xi" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xc" "optimized" } } */ > > + > > +/* Verify that the correct custom instructions are emitted in assembly. */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xd,50,XD" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xs,32,XS" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xc,21,XC" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xi,20,XI" } } */ > > + > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xd\\s+a\[0-9\]+,a\[0-9\]+,a\[0-9\]+" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xs\\s+a\[0-9\]+,a\[0-9\]+,3" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times "insn_apex_xi\\s+a\[0-9\]+,4" > > 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xc\\s+a\[0-9\]+,a\[0-9\]+,5" 1 } } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_1.c > > new file mode 100644 > > index 00000000000..493318bb53d > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test2_1.c > > @@ -0,0 +1,15 @@ > > + > > +int func_apex_xc (int, int); > > +#pragma intrinsic (func_apex_xc, "insn_apex_xc", 21, "XC") > > + > > +int func_apex_xi (int); > > +#pragma intrinsic (func_apex_xi, "insn_apex_xi", 20, "XI") > > + > > +int > > +bar (int a, int b) > > +{ > > + int c = func_apex_xi (4); > > + int d = func_apex_xc (a, 5); > > + return b + c + d; > > +} > > + > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_0.c > > new file mode 100644 > > index 00000000000..3d8de370c54 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_0.c > > @@ -0,0 +1,49 @@ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 -fdump-tree-optimized -save-temps } } } > > */ > > + > > +/* Pragma order in _0.c: XD, XS, XI, XC */ > > +int func_apex_xd (int, int); > > +#pragma intrinsic (func_apex_xd, "insn_apex_xd", 50, "XD") > > + > > +int func_apex_xs (int, int); > > +#pragma intrinsic (func_apex_xs, "insn_apex_xs", 32, "XS") > > + > > +int func_apex_xi (int); > > +#pragma intrinsic (func_apex_xi, "insn_apex_xi", 20, "XI") > > + > > +int func_apex_xc (int, int); > > +#pragma intrinsic (func_apex_xc, "insn_apex_xc", 21, "XC") > > + > > +extern int foo (int); > > + > > +int > > +main (void) > > +{ > > + int x = func_apex_xd (1, 2); > > + int y = func_apex_xs (x, 3); > > + int z = func_apex_xi (4); > > + int w = func_apex_xc (y, 5); > > + > > + return foo (y) + w + z; > > +} > > + > > +/* Verify that APEX intrinsic calls survive LTO optimization. */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xd" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xs" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xi" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xc" "optimized" } } */ > > + > > +/* Verify that the correct custom instructions are emitted in assembly. */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xd,50,XD" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xs,32,XS" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xi,20,XI" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xc,21,XC" } } */ > > + > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xd\\s+a\[0-9\]+,a\[0-9\]+,a\[0-9\]+" 2 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xs\\s+a\[0-9\]+,a\[0-9\]+,3" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times "insn_apex_xi\\s+a\[0-9\]+,4" > > 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xc\\s+a\[0-9\]+,a\[0-9\]+,5" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xs\\s+a\[0-9\]+,a\[0-9\]+,8" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times "insn_apex_xi\\s+a\[0-9\]+,9" > > 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xc\\s+a\[0-9\]+,a\[0-9\]+,10" 1 } } */ > > + > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_1.c > > new file mode 100644 > > index 00000000000..9401957a0f9 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test3_1.c > > @@ -0,0 +1,25 @@ > > + > > +int func_apex_xc (int, int); > > +#pragma intrinsic (func_apex_xc, "insn_apex_xc", 21, "XC") > > + > > +int func_apex_xi (int); > > +#pragma intrinsic (func_apex_xi, "insn_apex_xi", 20, "XI") > > + > > +int func_apex_xs (int, int); > > +#pragma intrinsic (func_apex_xs, "insn_apex_xs", 32, "XS") > > + > > +int func_apex_xd (int, int); > > +#pragma intrinsic (func_apex_xd, "insn_apex_xd", 50, "XD") > > + > > +extern int foo (int); > > + > > +int > > +foo (int val) > > +{ > > + int a = func_apex_xd (6, 7); > > + int b = func_apex_xs (val, 8); > > + int c = func_apex_xi (9); > > + int d = func_apex_xc (val, 10); > > + return a + b + c + d; > > +} > > + > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_0.c > > new file mode 100644 > > index 00000000000..bcd9f68765a > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_0.c > > @@ -0,0 +1,25 @@ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O0 -fdump-tree-optimized -save-temps } } } > > */ > > + > > +int func_apex_xc (int, int); > > +#pragma intrinsic (func_apex_xc, "insn_apex_xc", 1, "XC") > > + > > +extern int foo (int); > > + > > +int > > +main (void) > > +{ > > + int x = func_apex_xc (1, 2); > > + return foo (x); > > +} > > + > > +/* Verify that APEX intrinsic calls survive LTO optimization. */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xc" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_xs" "optimized" } } */ > > + > > +/* Verify that the correct custom instructions are emitted in assembly. */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xc,1,XC" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_xs,2,XS" } } */ > > + > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xc\\s+a\[0-9\]+,+a\[0-9\]+,2" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_xs\\s+a\[0-9\]+,a\[0-9\]+,3" 1 } } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_1.c > > new file mode 100644 > > index 00000000000..66757f6bbe5 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test4_1.c > > @@ -0,0 +1,12 @@ > > + > > +int func_apex_xs (int, int); > > +#pragma intrinsic (func_apex_xs, "insn_apex_xs", 2, "XS") > > + > > +extern int foo (int); > > + > > +int > > +foo (int val) > > +{ > > + return func_apex_xs (val, 3); > > +} > > + > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_0.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_0.c > > new file mode 100644 > > index 00000000000..ac522c3101c > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_0.c > > @@ -0,0 +1,52 @@ > > +/* { dg-lto-do link } */ > > +/* { dg-lto-options { { -flto -O2 -fdump-tree-optimized -save-temps } } } > > */ > > + > > +/* Test that intrinsics optimized away don't cause crashes during LTO. > > + This test registers multiple intrinsics but only uses some of them, > > + allowing the optimizer to remove the unused ones. */ > > + > > +int func_apex_used1 (int, int); > > +#pragma intrinsic (func_apex_used1, "insn_apex_used1", 1, "XC") > > + > > +int func_apex_unused (int, int); > > +#pragma intrinsic (func_apex_unused, "insn_apex_unused", 2, "XS") > > + > > +int func_apex_used2 (int, int); > > +#pragma intrinsic (func_apex_used2, "insn_apex_used2", 3, "XC") > > + > > +extern int bar (int); > > + > > +static int > > +func_apex_unused_helper (int a, int b) > > +{ > > + return func_apex_unused (a, b); > > +} > > + > > +int > > +main (void) > > +{ > > + /* Only use func_apex_used1 and func_apex_used2. > > + func_apex_unused should be optimized away. */ > > + int x = func_apex_used1 (5, 10); > > + int y = func_apex_used2 (x, 15); > > + return bar (y); > > +} > > + > > +/* Verify that only the used intrinsics appear in the optimized output. */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_used1" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_used2" "optimized" } } */ > > +/* { dg-final { scan-ltrans-tree-dump "func_apex_from_other" "optimized" } > > } */ > > + > > +/* Verify that the unused intrinsic is NOT in the optimized output. */ > > +/* { dg-final { scan-ltrans-tree-dump-not "func_apex_unused" "optimized" } > > } */ > > +/* { dg-final { scan-ltrans-tree-dump-not "func_apex_also_unused" > > "optimized" } } */ > > + > > +/* Verify that only used intrinsics have .extInstruction directives. */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_used1,1,XC" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_used2,3,XC" } } */ > > +/* { dg-final { scan-ltrans-assembler "\\.extInstruction > > insn_apex_from_other,4,XS" } } */ > > + > > +/* Verify the actual instruction usage in assembly. */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_used1\\s+a\[0-9\]+,a\[0-9\]+,10" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_used2\\s+a\[0-9\]+,a\[0-9\]+,15" 1 } } */ > > +/* { dg-final { scan-ltrans-assembler-times > > "insn_apex_from_other\\s+a\[0-9\]+,a\[0-9\]+,20" 1 } } */ > > diff --git a/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_1.c > > b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_1.c > > new file mode 100644 > > index 00000000000..9915f2306bf > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/riscv/apex/arcv-apex-lto-test5_1.c > > @@ -0,0 +1,20 @@ > > + > > +int func_apex_from_other (int, int); > > +#pragma intrinsic (func_apex_from_other, "insn_apex_from_other", 4, "XS") > > + > > +int func_apex_also_unused (int, int); > > +#pragma intrinsic (func_apex_also_unused, "insn_apex_also_unused", 5, "XC") > > + > > +static int > > +func_apex_also_unused_helper (int a, int b) > > +{ > > + return func_apex_also_unused (a, b); > > +} > > + > > +int > > +bar (int val) > > +{ > > + /* Only use func_apex_from_other. > > + func_apex_also_unused should be optimized away. */ > > + return func_apex_from_other (val, 20); > > +} > > -- > > 2.34.0 > > > -- Richard Biener <[email protected]> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Jochen Jaser, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)
