代码拉取完成,页面将自动刷新
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
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。