Projects
openEuler:24.03:SP1:Everything
gcc
_service:tar_scm:0304-Add-multi-version-lto-sym...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0304-Add-multi-version-lto-symbol-parse-cross-lto-units-i.patch of Package gcc
From f81a5b294711e3a420fe66702f0d9221332271c4 Mon Sep 17 00:00:00 2001 From: h00564365 <huangxiaoquan1@huawei.com> Date: Wed, 13 Nov 2024 17:18:01 +0800 Subject: [PATCH 2/2] Add multi-version lto symbol parse, cross lto units ipa-inline extension, and lto compression algorithm specified. --- gcc/common.opt | 20 +++ gcc/config/aarch64/aarch64.cc | 41 ++++++ gcc/doc/tm.texi | 6 + gcc/doc/tm.texi.in | 2 + gcc/ipa-inline.cc | 141 ++++++++++++++++++- gcc/lto-compress.cc | 6 +- gcc/lto-section-in.cc | 5 + gcc/lto-streamer-out.cc | 7 +- gcc/lto-wrapper.cc | 4 + gcc/optc-save-gen.awk | 57 ++++++++ gcc/opth-gen.awk | 3 + gcc/opts.cc | 46 ++++++ gcc/target.def | 10 ++ gcc/testsuite/gcc.dg/lto/binary-inline-1_0.c | 15 ++ gcc/testsuite/gcc.dg/lto/binary-inline-1_1.c | 6 + gcc/testsuite/gcc.dg/lto/binary-inline-2_0.c | 15 ++ gcc/testsuite/gcc.dg/lto/binary-inline-2_1.c | 5 + gcc/testsuite/gcc.dg/lto/binary-inline-3_0.c | 15 ++ gcc/testsuite/gcc.dg/lto/binary-inline-3_1.c | 10 ++ gcc/tree-streamer-in.cc | 58 +++++++- lto-plugin/lto-plugin.c | 83 +++++++++++ 21 files changed, 547 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/lto/binary-inline-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/binary-inline-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/binary-inline-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/binary-inline-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/binary-inline-3_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/binary-inline-3_1.c diff --git a/gcc/common.opt b/gcc/common.opt index be5fcc681..78cfc333a 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1928,6 +1928,21 @@ finline-atomics Common Var(flag_inline_atomics) Init(1) Optimization Inline __atomic operations when a lock free instruction sequence is available. +fmulti-version-lib= +Common Joined Var(multi_version_lib_string) +Use specify LTO stream in mode for specified target (object or lib). If there +are multiple target files, use commas (,) to separate them and without spaces. + +finline-force +Common Var(flag_inline_force) Init(0) Optimization +Force perform ipa inline when march options are incompatible between functions. + +finline-force= +Common Joined Var(force_inline_targets_string) +Force perform ipa inline specified target(object or lib) when march options are +incompatible between functions. If there are multiple target files, use commas +(,) to separate them and without spaces. + fcf-protection Common RejectNegative Alias(fcf-protection=,full) @@ -2168,6 +2183,11 @@ flto-partition= Common Joined RejectNegative Enum(lto_partition_model) Var(flag_lto_partition) Init(LTO_PARTITION_BALANCED) Specify the algorithm to partition symbols and vars at linktime. +flto-compression-algorithm= +Common Joined Var(lto_compression_algorithm) +-flto-compression-algorithm=<format> Generate lto compression in zlib/zstd +format <format>. + ; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h. flto-compression-level= Common Joined RejectNegative UInteger Var(flag_lto_compression_level) Init(-1) IntegerRange(0, 19) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 025a3c478..f095f17aa 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -20829,6 +20829,44 @@ aarch64_option_print (FILE *file, int indent, struct cl_target_option *ptr) arch->name, extension.c_str ()); } +/* Implement TARGET_OPTION_PRINT_DIFF. */ + +static void +aarch64_option_print_diff (FILE *file, int indent, + struct cl_target_option *ptr1, + struct cl_target_option *ptr2) +{ + const char *const cpu1 + = aarch64_get_tune_cpu (ptr1->x_selected_tune)->name; + const struct processor *arch1 = aarch64_get_arch (ptr1->x_selected_arch); + std::string extension1 + = aarch64_get_extension_string_for_isa_flags (ptr1->x_aarch64_isa_flags, + arch1->flags); + + const char *const cpu2 + = aarch64_get_tune_cpu (ptr2->x_selected_tune)->name; + const struct processor *arch2 = aarch64_get_arch (ptr2->x_selected_arch); + std::string extension2 + = aarch64_get_extension_string_for_isa_flags (ptr2->x_aarch64_isa_flags, + arch2->flags); + + if (cpu1 != cpu2 && (!cpu1 || !cpu2 || strcmp (cpu1, cpu2))) + fprintf (file, "%*s%s (%s/%s)\n", indent, "", + "cpu", cpu1 ? cpu1 : "(null)", cpu2 ? cpu2 : "(null)"); + + if (arch1->name != arch2->name + && (!arch1->name || !arch2->name || strcmp (arch1->name, arch2->name))) + fprintf (file, "%*s%s (%s/%s)\n", indent, "", + "arch", arch1->name ? arch1->name : "(null)", + arch2->name ? arch2->name : "(null)"); + + if (extension1 != extension2) + fprintf (file, "%*s%s (%s/%s)\n", indent, "", + "extension", + extension1.empty () ? "(null)" : extension1.c_str (), + extension2.empty () ? "(null)" : extension2.c_str ()); +} + static GTY(()) tree aarch64_previous_fndecl; void @@ -31161,6 +31199,9 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_OPTION_PRINT #define TARGET_OPTION_PRINT aarch64_option_print +#undef TARGET_OPTION_PRINT_DIFF +#define TARGET_OPTION_PRINT_DIFF aarch64_option_print_diff + #undef TARGET_OPTION_VALID_ATTRIBUTE_P #define TARGET_OPTION_VALID_ATTRIBUTE_P aarch64_option_valid_attribute_p diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 1e96521e6..50bbbbc42 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -10589,6 +10589,12 @@ information in the @code{struct cl_target_option} structure for function-specific options. @end deftypefn +@deftypefn {Target Hook} void TARGET_OPTION_PRINT_DIFF (FILE *@var{file}, int @var{indent}, struct cl_target_option *@var{ptr1}, struct cl_target_option *@var{ptr2}) +This hook is called to print diff additional target-specific +information in the ptr1 and ptr2 @code{struct cl_target_option} structure for +function-specific options. +@end deftypefn + @deftypefn {Target Hook} bool TARGET_OPTION_PRAGMA_PARSE (tree @var{args}, tree @var{pop_target}) This target hook parses the options for @code{#pragma GCC target}, which sets the target-specific options for functions that occur later in the diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 2dd515659..cfda60304 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -6985,6 +6985,8 @@ on this implementation detail. @hook TARGET_OPTION_PRINT +@hook TARGET_OPTION_PRINT_DIFF + @hook TARGET_OPTION_PRAGMA_PARSE @hook TARGET_OPTION_OVERRIDE diff --git a/gcc/ipa-inline.cc b/gcc/ipa-inline.cc index f8bb072c4..8d5cc9a84 100644 --- a/gcc/ipa-inline.cc +++ b/gcc/ipa-inline.cc @@ -90,6 +90,8 @@ along with GCC; see the file COPYING3. If not see the need for offline copy of the function. */ #include "config.h" +#define INCLUDE_SET +#define INCLUDE_STRING #include "system.h" #include "coretypes.h" #include "backend.h" @@ -127,6 +129,7 @@ typedef fibonacci_node <sreal, cgraph_edge> edge_heap_node_t; static int overall_size; static profile_count max_count; static profile_count spec_rem; +static std::set<std::string> force_inline_targets; /* Return false when inlining edge E would lead to violating limits on function unit growth or stack usage growth. @@ -222,6 +225,38 @@ caller_growth_limits (struct cgraph_edge *e) return true; } +/* Warn and prompt the user, and output only once for the file pair where + the function is located. */ + +static void +prompt_inline_failed_target_option_reason (struct cgraph_edge *e) +{ + static std::set<std::pair<void*, void*>> address_pair_set; + if (e->inline_failed == CIF_TARGET_OPTION_MISMATCH + && !cl_target_option_eq_major (target_opts_for_fn (e->caller->decl), + target_opts_for_fn (e->callee->ultimate_alias_target ()->decl)) + && e->caller->lto_file_data + && e->callee->ultimate_alias_target ()->lto_file_data) + { + std::pair<void*, void*> addr_pair + = std::make_pair (&e->caller->lto_file_data, + &e->callee->ultimate_alias_target ()->lto_file_data); + if (address_pair_set.find (addr_pair) != address_pair_set.end ()) + return; + + address_pair_set.insert (addr_pair); + warning (0, "LTO objects caller in: %s, callee in: %s, not inlinable: %s." + " Try to use -finline-force=callee_object_or_lib_name to force " + "inline", e->caller->lto_file_data->file_name, + e->callee->ultimate_alias_target ()->lto_file_data->file_name, + cgraph_inline_failed_string (CIF_TARGET_OPTION_MISMATCH)); + + cl_target_option_print_diff + (stderr, 2, target_opts_for_fn (e->caller->decl), + target_opts_for_fn (e->callee->ultimate_alias_target ()->decl)); + } +} + /* Dump info about why inlining has failed. */ static void @@ -254,6 +289,8 @@ report_inline_failed_reason (struct cgraph_edge *e) (dump_file, 2, opts_for_fn (e->caller->decl), opts_for_fn (e->callee->ultimate_alias_target ()->decl)); } + + prompt_inline_failed_target_option_reason (e); } /* Decide whether sanitizer-related attributes allow inlining. */ @@ -310,6 +347,77 @@ sanitize_attrs_match_for_inline_p (const_tree caller, const_tree callee) (opts_for_fn (caller->decl)->x_##flag \ != opts_for_fn (callee->decl)->x_##flag) +/* find related node that has lto_file_data. */ + +static cgraph_node * +find_related_node_lto_file_data (cgraph_node *node) +{ + cgraph_node *cur = node; + + while (cur->clone_of) + { + /* Switch to original node, for example xxx.constprop.x function. */ + cur = cur->clone_of; + if (cur->lto_file_data) + return cur; + + /* Find the lto_file_data information of referring. */ + struct ipa_ref *ref = NULL; + for (int i = 0; cur->iterate_referring (i, ref); i++) + { + struct cgraph_node *cnode = dyn_cast <cgraph_node *> (ref->referring); + if (cnode && cnode->lto_file_data) + return cnode; + } + } + + return NULL; +} + +/* Determines whether to force inline or force inline only the specified + object. Use for 3 inline extensions: + 1) CIF_TARGET_OPTION_MISMATCH: cancel the restriction that the target options + of different compilation units are different. + 2) CIF_OVERWRITABLE: indicates that the function is available, which is + similar to the "inline" keyword indication. + 3) CIF_OPTIMIZATION_MISMATCH: cancel the check in the case of fp_expressions, + which is similar to the "always_inline" attribute. + */ + +static bool +can_force_inline_p (cgraph_node *callee) +{ + if (!in_lto_p) + return false; + if (flag_inline_force) + return true; + if (force_inline_targets_string) + { + cgraph_node * node = callee; + std::string name = ""; + if (callee->ultimate_alias_target () == NULL + || callee->ultimate_alias_target ()->lto_file_data == NULL) + { + node = find_related_node_lto_file_data (callee); + if (node && node->lto_file_data) + name = node->lto_file_data->file_name; + } + else + name = node->ultimate_alias_target ()->lto_file_data->file_name; + while (!name.empty () && name.back () == '/') + name.erase (name.length () - 1); + if (name.empty ()) + return false; + size_t last_slash_pos = name.find_last_of ('/'); + if (last_slash_pos != std::string::npos + && last_slash_pos != name.length () - 1) + name = name.substr (last_slash_pos + 1); + if (force_inline_targets.find (name) != force_inline_targets.end ()) + return true; + } + return false; +} + /* Decide if we can inline the edge and possibly update inline_failed reason. We check whether inlining is possible at all and whether @@ -352,7 +460,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, e->inline_failed = CIF_USES_COMDAT_LOCAL; inlinable = false; } - else if (avail <= AVAIL_INTERPOSABLE) + else if (avail <= AVAIL_INTERPOSABLE && !can_force_inline_p (callee)) { e->inline_failed = CIF_OVERWRITABLE; inlinable = false; @@ -378,8 +486,8 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, inlinable = false; } /* Check compatibility of target optimization options. */ - else if (!targetm.target_option.can_inline_p (caller->decl, - callee->decl)) + else if (!can_force_inline_p (callee) + && !targetm.target_option.can_inline_p (caller->decl, callee->decl)) { e->inline_failed = CIF_TARGET_OPTION_MISMATCH; inlinable = false; @@ -495,7 +603,8 @@ can_inline_edge_by_limits_p (struct cgraph_edge *e, bool report, bool always_inline = (DECL_DISREGARD_INLINE_LIMITS (callee->decl) && lookup_attribute ("always_inline", - DECL_ATTRIBUTES (callee->decl))); + DECL_ATTRIBUTES (callee->decl))) + || can_force_inline_p (callee); ipa_fn_summary *caller_info = ipa_fn_summaries->get (caller); ipa_fn_summary *callee_info = ipa_fn_summaries->get (callee); @@ -2652,6 +2761,27 @@ flatten_remove_node_hook (struct cgraph_node *node, void *data) removed->add (node); } +/* Parse string that specify forced inlining, separated by commas. */ + +static void +parse_force_inline_targets_string (const char* s) +{ + std::string target_string (s); + std::string delim = ","; + size_t start = 0; + size_t end = target_string.find (delim); + if (target_string.substr (start, end - start) == "") + return; + + while (end != std::string::npos) + { + force_inline_targets.insert (target_string.substr (start, end - start)); + start = end + delim.size (); + end = target_string.find (delim, start); + } + force_inline_targets.insert (target_string.substr (start, end - start)); +} + /* Decide on the inlining. We do so in the topological order to avoid expenses on updating data structures. */ @@ -2665,6 +2795,9 @@ ipa_inline (void) int cold; bool remove_functions = false; + if (force_inline_targets_string) + parse_force_inline_targets_string (force_inline_targets_string); + order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count); if (dump_file) diff --git a/gcc/lto-compress.cc b/gcc/lto-compress.cc index 27f0992a8..f9d0722a9 100644 --- a/gcc/lto-compress.cc +++ b/gcc/lto-compress.cc @@ -305,7 +305,11 @@ void lto_end_compression (struct lto_compression_stream *stream) { #ifdef HAVE_ZSTD_H - lto_compression_zstd (stream); + if (lto_compression_algorithm + && strcmp (lto_compression_algorithm, "zstd") == 0) + lto_compression_zstd (stream); + else + lto_compression_zlib (stream); #else lto_compression_zlib (stream); #endif diff --git a/gcc/lto-section-in.cc b/gcc/lto-section-in.cc index ba87c7276..947f8eb15 100644 --- a/gcc/lto-section-in.cc +++ b/gcc/lto-section-in.cc @@ -448,6 +448,11 @@ lto_free_function_in_decl_state_for_node (symtab_node *node) lto_free_function_in_decl_state (*slot); node->lto_file_data->function_decl_states->clear_slot (slot); } + + /* In force inline case, keep lto file path information. */ + if (in_lto_p && (flag_inline_force || force_inline_targets_string)) + return; + node->lto_file_data = NULL; } diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index 471f35c31..a574f0f1e 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -2666,7 +2666,12 @@ produce_lto_section () free (section_name); #ifdef HAVE_ZSTD_H - lto_compression compression = ZSTD; + lto_compression compression = ZLIB; + if (lto_compression_algorithm + && strcmp (lto_compression_algorithm, "zstd") == 0) + compression = ZSTD; + else + compression = ZLIB; #else lto_compression compression = ZLIB; #endif diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc index 155ccce57..2b1994652 100644 --- a/gcc/lto-wrapper.cc +++ b/gcc/lto-wrapper.cc @@ -491,6 +491,8 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options, || decoded_options[j].opt_index == OPT_fpic) { /* -fno-pic in one unit implies -fno-pic everywhere. */ + /* The -fno-pic adjustment here should provide some information hints, + but may affect the use case test of deja. */ if (decoded_options[j].value == 0) j++; /* If we have no pic option or merge in -fno-pic, we still may turn @@ -534,6 +536,8 @@ merge_and_complain (vec<cl_decoded_option> &decoded_options, || decoded_options[j].opt_index == OPT_fpie) { /* -fno-pie in one unit implies -fno-pie everywhere. */ + /* The -fno-pie adjustment here should provide some information hints, + but may affect the use case test of deja. */ if (decoded_options[j].value == 0) j++; /* If we have no pie option or merge in -fno-pie, we still preserve diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk index 7c012dd4e..94b85b331 100644 --- a/gcc/optc-save-gen.awk +++ b/gcc/optc-save-gen.awk @@ -1043,6 +1043,10 @@ for (i = 0; i < n_target_string; i++) { print ""; } +print ""; +print " if (targetm.target_option.print_diff)"; +print " targetm.target_option.print_diff (file, indent, ptr1, ptr2);"; + print "}"; print ""; @@ -1160,6 +1164,59 @@ print " return true;"; print "}"; +print ""; +print "/* Compare two target major options. */"; +print "bool"; +print "cl_target_option_eq_major (struct cl_target_option const *ptr1 ATTRIBUTE_UNUSED,"; +print " struct cl_target_option const *ptr2 ATTRIBUTE_UNUSED)"; +print "{"; +n_target_val_major = 0; + +for (i = 0; i < n_target_save; i++) { + var = target_save_decl[i]; + sub (" *=.*", "", var); + name = var; + type = var; + sub("^.*[ *]", "", name) + sub(" *" name "$", "", type) + if (target_save_decl[i] ~ "^const char \\*+[_" alnum "]+$") + continue; + if (target_save_decl[i] ~ " .*\\[.+\\]+$") + continue; + + var_target_val_major[n_target_val_major++] = name; +} +if (have_save) { + for (i = 0; i < n_opts; i++) { + if (flag_set_p("Save", flags[i])) { + name = var_name(flags[i]) + if(name == "") + name = "target_flags"; + + if(name in var_list_seen) + continue; + + var_list_seen[name]++; + otype = var_type_struct(flags[i]) + if (otype ~ "^const char \\**$") + continue; + var_target_val_major[n_target_val_major++] = "x_" name; + } + } +} else { + var_target_val_major[n_target_val_major++] = "x_target_flags"; +} + +for (i = 0; i < n_target_val_major; i++) { + name = var_target_val_major[i] + print " if (ptr1->" name" != ptr2->" name ")"; + print " return false;"; +} + +print " return true;"; + +print "}"; + print ""; print "/* Hash target options */"; print "hashval_t"; diff --git a/gcc/opth-gen.awk b/gcc/opth-gen.awk index 8bba8ec45..cb016e85d 100644 --- a/gcc/opth-gen.awk +++ b/gcc/opth-gen.awk @@ -330,6 +330,9 @@ print ""; print "/* Compare two target option variables from a structure. */"; print "extern bool cl_target_option_eq (const struct cl_target_option *, const struct cl_target_option *);"; print ""; +print "/* Compare two target major option variables from a structure. */"; +print "extern bool cl_target_option_eq_major (const struct cl_target_option *, const struct cl_target_option *);"; +print ""; print "/* Free heap memory used by target option variables. */"; print "extern void cl_target_option_free (struct cl_target_option *);"; print ""; diff --git a/gcc/opts.cc b/gcc/opts.cc index d97f6079f..d9de8747c 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -2611,6 +2611,32 @@ print_help (struct gcc_options *opts, unsigned int lang_mask, lang_mask); } +/* Checks whether the input forced inline string complies with the + restriction. */ + +void +check_force_inline_targets_string (const char *arg, location_t loc) +{ + const int MAX_FORCE_INLINE_TARGET_LEN = 10000; + const int MAX_NUM_TARGET = 100; + __SIZE_TYPE__ length = strlen (arg); + int target_num = 1; + if (length > MAX_FORCE_INLINE_TARGET_LEN) + error_at (loc, + "input string exceeds %d characters to %<-finline_force=%> " + "option: %qs", MAX_FORCE_INLINE_TARGET_LEN, arg); + for (__SIZE_TYPE__ i = 0; i < length; i++) + { + if (arg[i] == ',') + { + target_num++; + if (target_num > MAX_NUM_TARGET) + error_at (loc, "input target exceeds %d to %<-finline_force=%> " + "option: %qs", MAX_NUM_TARGET, arg); + } + } +} + /* Handle target- and language-independent options. Return zero to generate an "unknown option" message. Only options that need extra handling need to be listed here; if you simply want @@ -2952,6 +2978,14 @@ common_handle_option (struct gcc_options *opts, value / 2); break; + case OPT_finline_force: + opts->x_force_inline_targets_string = value ? "" : NULL; + break; + + case OPT_finline_force_: + check_force_inline_targets_string (arg, loc); + break; + case OPT_finstrument_functions_exclude_function_list_: add_comma_separated_to_vector (&opts->x_flag_instrument_functions_exclude_functions, arg); @@ -3226,6 +3260,18 @@ common_handle_option (struct gcc_options *opts, "unrecognized argument to %<-flto=%> option: %qs", arg); break; + case OPT_flto_compression_algorithm_: + if (atoi (arg) == 0 + && strcmp (arg, "zlib") != 0 +#ifdef HAVE_ZSTD_H + && strcmp (arg, "zstd") != 0 +#endif + ) + error_at (loc, + "unrecognized argument to %<-flto-compression-algorithm=%> " + "option: %qs", arg); + break; + case OPT_w: dc->dc_inhibit_warnings = true; break; diff --git a/gcc/target.def b/gcc/target.def index 7183f363d..142858fa3 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -6644,6 +6644,16 @@ information in the @code{struct cl_target_option} structure for\n\ function-specific options.", void, (FILE *file, int indent, struct cl_target_option *ptr), NULL) +/* Function to print any extra target state from the target options + structure. */ +DEFHOOK +(print_diff, + "This hook is called to print diff additional target-specific\n\ +information in the ptr1 and ptr2 @code{struct cl_target_option} structure for\n\ +function-specific options.", + void, (FILE *file, int indent, struct cl_target_option *ptr1, + struct cl_target_option *ptr2), NULL) + /* Function to parse arguments to be validated for #pragma target, and to change the state if the options are valid. If the first argument is NULL, the second argument specifies the default options to use. Return diff --git a/gcc/testsuite/gcc.dg/lto/binary-inline-1_0.c b/gcc/testsuite/gcc.dg/lto/binary-inline-1_0.c new file mode 100644 index 000000000..0b5cd5953 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/binary-inline-1_0.c @@ -0,0 +1,15 @@ +/* { dg-lto-do link } */ +/* { dg-require-effective-target shared } */ +/* { dg-extra-ld-options {-shared -finline-force=c_lto_binary-inline-1_1.o} } */ +/* { dg-lto-options {{-O3 -flto -march=armv8.2-a -fdump-ipa-inline-details}} } */ + +extern double multi_op(float x); + +double func_a (float x) +{ + double res = 0; + res = multi_op (x); + return res; +} + +/* { dg-final { scan-wpa-ipa-dump "Inlined 1 calls" "inline" } } */ diff --git a/gcc/testsuite/gcc.dg/lto/binary-inline-1_1.c b/gcc/testsuite/gcc.dg/lto/binary-inline-1_1.c new file mode 100644 index 000000000..8181384b7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/binary-inline-1_1.c @@ -0,0 +1,6 @@ +/* { dg-options "-march=armv8.3-a+sve+f64mm+crc+crypto+fp16+i8mm+simd" } */ + +double multi_op (float x) +{ + return x * 2 + 10; +} diff --git a/gcc/testsuite/gcc.dg/lto/binary-inline-2_0.c b/gcc/testsuite/gcc.dg/lto/binary-inline-2_0.c new file mode 100644 index 000000000..e873937d3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/binary-inline-2_0.c @@ -0,0 +1,15 @@ +/* { dg-lto-do link } */ +/* { dg-require-effective-target shared } */ +/* { dg-extra-ld-options {-shared -finline-force=c_lto_binary-inline-2_1.o} } */ +/* { dg-lto-options {{-O3 -flto -fPIC -fdump-ipa-inline-details}} } */ + +extern double multi_op(float x); + +double func_a (float x) +{ + double res = 0; + res = multi_op (x); + return res; +} + +/* { dg-final { scan-wpa-ipa-dump "Inlined 1 calls" "inline" } } */ diff --git a/gcc/testsuite/gcc.dg/lto/binary-inline-2_1.c b/gcc/testsuite/gcc.dg/lto/binary-inline-2_1.c new file mode 100644 index 000000000..dc7c4fd9f --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/binary-inline-2_1.c @@ -0,0 +1,5 @@ + +double multi_op (float x) +{ + return x * 2 + 10; +} diff --git a/gcc/testsuite/gcc.dg/lto/binary-inline-3_0.c b/gcc/testsuite/gcc.dg/lto/binary-inline-3_0.c new file mode 100644 index 000000000..c78ba066d --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/binary-inline-3_0.c @@ -0,0 +1,15 @@ +/* { dg-lto-do link } */ +/* { dg-require-effective-target shared } */ +/* { dg-extra-ld-options {-shared -finline-force=c_lto_binary-inline-3_1.o} } */ +/* { dg-lto-options {{-O3 -flto -fdump-ipa-inline-details}} } */ + +extern double multi_op(double x); + +double func_a (double x) +{ + double res = 0; + res = multi_op (x); + return res; +} + +/* { dg-final { scan-wpa-ipa-dump "Inlined 1 calls" "inline" } } */ diff --git a/gcc/testsuite/gcc.dg/lto/binary-inline-3_1.c b/gcc/testsuite/gcc.dg/lto/binary-inline-3_1.c new file mode 100644 index 000000000..8b505fa0c --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/binary-inline-3_1.c @@ -0,0 +1,10 @@ +/* { dg-options "-O2 -fno-math-errno" } */ + +#include <math.h> + +double multi_op (double x) +{ + double a = 0; + a = sqrt (x); + return a * 2 + 10; +} diff --git a/gcc/tree-streamer-in.cc b/gcc/tree-streamer-in.cc index a35a810f4..79f819ad8 100644 --- a/gcc/tree-streamer-in.cc +++ b/gcc/tree-streamer-in.cc @@ -20,6 +20,9 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#include <cstdio> +#define INCLUDE_SET +#define INCLUDE_STRING #include "system.h" #include "coretypes.h" #include "backend.h" @@ -36,6 +39,47 @@ along with GCC; see the file COPYING3. If not see #include "asan.h" #include "opts.h" +/* Parse string that specify forced inlining, separated by commas. */ +static std::set<std::string> multi_version_libs; +static void +parse_multi_version_lib_string (const char* s) +{ + std::string target_string (s); + std::string delim = ","; + size_t start = 0; + size_t end = target_string.find (delim); + if (target_string.substr (start, end - start) == "") + return; + + while (end != std::string::npos) + { + multi_version_libs.insert (target_string.substr (start, end - start)); + start = end + delim.size (); + end = target_string.find (delim, start); + } + multi_version_libs.insert (target_string.substr (start, end - start)); +} + +static bool +target_lib_p (std::string name) +{ + if (multi_version_libs.empty () && multi_version_lib_string) + parse_multi_version_lib_string (multi_version_lib_string); + if (multi_version_lib_string) + { + while (!name.empty () && name.back () == '/') + name.erase (name.length () - 1); + if (name.empty ()) + return false; + size_t last_slash_pos = name.find_last_of ('/'); + if (last_slash_pos != std::string::npos + && last_slash_pos != name.length () - 1) + name = name.substr (last_slash_pos + 1); + if (multi_version_libs.find (name) != multi_version_libs.end ()) + return true; + } + return false; +} /* Read a STRING_CST from the string table in DATA_IN using input block IB. */ @@ -555,7 +599,12 @@ streamer_read_tree_bitfields (class lto_input_block *ib, unpack_ts_translation_unit_decl_value_fields (data_in, &bp, expr); if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION)) - cl_optimization_stream_in (data_in, &bp, TREE_OPTIMIZATION (expr)); + { + if (target_lib_p (data_in->file_data->file_name)) + cl_optimization_stream_in_prev (data_in, &bp, TREE_OPTIMIZATION (expr)); + else + cl_optimization_stream_in (data_in, &bp, TREE_OPTIMIZATION (expr)); + } if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR)) { @@ -569,7 +618,12 @@ streamer_read_tree_bitfields (class lto_input_block *ib, #ifndef ACCEL_COMPILER if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)) { - cl_target_option_stream_in (data_in, &bp, TREE_TARGET_OPTION (expr)); + if (target_lib_p (data_in->file_data->file_name)) + cl_target_option_stream_in_prev ( + data_in, &bp, TREE_TARGET_OPTION (expr)); + else + cl_target_option_stream_in (data_in, &bp, TREE_TARGET_OPTION (expr)); + if (targetm.target_option.post_stream_in) targetm.target_option.post_stream_in (TREE_TARGET_OPTION (expr)); } diff --git a/lto-plugin/lto-plugin.c b/lto-plugin/lto-plugin.c index 33d49571d..b3301a8a4 100644 --- a/lto-plugin/lto-plugin.c +++ b/lto-plugin/lto-plugin.c @@ -89,6 +89,10 @@ along with this program; see the file COPYING3. If not see #define LTO_SEGMENT_NAME "__GNU_LTO" +#define GCC_major_version 12 +#define LTO_major_version GCC_major_version +#define LTO_minor_version 0 + /* Return true if STR string starts with PREFIX. */ static inline bool @@ -118,6 +122,18 @@ struct plugin_symtab unsigned long long id; }; +/* Structure that represents LTO ELF section with information + about the format. */ + +struct lto_section +{ + int16_t major_version; + int16_t minor_version; + unsigned char slim_object; + unsigned char _padding; + uint16_t flags; +}; + /* Encapsulates object file data during symbol scan. */ struct plugin_objfile { @@ -126,6 +142,7 @@ struct plugin_objfile simple_object_read *objfile; struct plugin_symtab *out; const struct ld_plugin_input_file *file; + struct lto_section version; }; /* All that we have to remember about a file. */ @@ -216,6 +233,8 @@ static int gold_version = -1; (in fact, only first letter of style arg is checked.) */ static enum symbol_style sym_style = ss_none; +static bool multi_version_lto_parse = false; + static void check_1 (int gate, enum ld_plugin_level level, const char *text) { @@ -1078,6 +1097,59 @@ err: return 0; } +/* Process version section of an object file. */ + +static int +process_lto_version (void *data, const char *name, off_t offset, off_t length) +{ + struct plugin_objfile *obj = (struct plugin_objfile *)data; + char *s; + char *secdatastart, *secdata; + + if (!startswith (name, ".gnu.lto_.lto")) + return 1; + + s = strrchr (name, '.'); + if (s) + sscanf (s, ".%" PRI_LL "x", &obj->out->id); + secdata = secdatastart = xmalloc (length); + offset += obj->file->offset; + if (offset != lseek (obj->file->fd, offset, SEEK_SET)) + goto err; + + do + { + ssize_t got = read (obj->file->fd, secdata, length); + if (got == 0) + break; + else if (got > 0) + { + secdata += got; + length -= got; + } + else if (errno != EINTR) + goto err; + } + while (length > 0); + if (length > 0) + goto err; + + struct lto_section *lto_info = (struct lto_section *)secdatastart; + obj->version = *lto_info; + + obj->found++; + free (secdatastart); + return 1; + +err: + if (message) + message (LDPL_FATAL, "%s: corrupt object file", obj->file->name); + /* Force claim_file_handler to abandon this file. */ + obj->found = 0; + free (secdatastart); + return 0; +} + /* Process one section of an object file. */ static int @@ -1223,6 +1295,15 @@ claim_file_handler (const struct ld_plugin_input_file *file, int *claimed) if (obj.found == 0 && obj.offload == 0) goto err; + if (multi_version_lto_parse) + { + simple_object_find_sections (obj.objfile, process_lto_version, &obj, + &err); + if (obj.version.major_version != LTO_major_version + || obj.version.minor_version != LTO_minor_version) + goto err; + } + if (obj.found > 1) resolve_conflicts (<o_file.symtab, <o_file.conflicts); @@ -1366,6 +1447,8 @@ process_option (const char *option) } else if (startswith (option, "-ltrans-objects=")) ltrans_objects = xstrdup (option + strlen ("-ltrans-objects=")); + else if (strcmp (option, "-multi-version-lto-parse") == 0) + multi_version_lto_parse = true; else { int size; -- 2.25.1
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2