From: Kyrylo Tkachov <[email protected]>
reg_last_in_use does not record every reg_last entry that contains a list.
The debug-insn path adds uses and then clears reg_pending_uses before the
normal update of reg_last_in_use. The control-use path also adds lists
without updating reg_last_in_use. free_deps only walks reg_last_in_use, so
these INSN_LIST nodes are not returned to the recycler.
Add a teardown-only reg_last_dirty regset for these entries. Merge it into
reg_last_in_use in free_deps, then release all lists in the existing loop.
Do not use reg_last_dirty for dependence generation. Adding these entries
to reg_last_in_use during analysis would make barrier handling create new
anti-dependences for debug uses and control dependences for control uses.
Add a selftest that puts a use list and a control-use list in a dirty-only
entry. It calls free_deps and verifies that the INSN_LIST recycler returns
both nodes. Ignoring the dirty-only entry makes this selftest fail.
Bootstrapped and regtested on aarch64-none-linux-gnu and x86_64-linux.
gcc/ChangeLog:
* sched-int.h (struct deps_desc): Add reg_last_dirty.
* sched-deps.cc: Include selftest.h.
(sched_analyze_insn): Record debug-insn uses and control uses in
reg_last_dirty.
(init_deps): Initialize reg_last_dirty.
(free_deps): Merge reg_last_dirty into reg_last_in_use for teardown,
then clear it.
(selftest::test_dirty_reg_last_release): New.
(selftest::sched_deps_cc_tests): New. Provide an empty definition
when INSN_SCHEDULING is not defined.
* selftest-run-tests.cc (selftest::run_tests): Call
sched_deps_cc_tests.
* selftest.h (selftest::sched_deps_cc_tests): Declare.
Signed-off-by: Kyrylo Tkachov <[email protected]>
---
gcc/sched-deps.cc | 81 +++++++++++++++++++++++++++++++++++++++
gcc/sched-int.h | 6 +++
gcc/selftest-run-tests.cc | 1 +
gcc/selftest.h | 1 +
4 files changed, 89 insertions(+)
diff --git a/gcc/sched-deps.cc b/gcc/sched-deps.cc
index 23f3545b54c..3a170d87b7e 100644
--- a/gcc/sched-deps.cc
+++ b/gcc/sched-deps.cc
@@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "sched-int.h"
#include "cselib.h"
#include "function-abi.h"
+#include "selftest.h"
#ifdef INSN_SCHEDULING
@@ -3115,6 +3116,8 @@ sched_analyze_insn (class deps_desc *deps, rtx x, rtx_insn *insn)
if (!deps->readonly)
reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
}
+ if (!deps->readonly)
+ IOR_REG_SET (&deps->reg_last_dirty, reg_pending_uses);
CLEAR_REG_SET (reg_pending_uses);
/* Quite often, a debug insn will refer to stuff in the
@@ -3306,6 +3309,7 @@ sched_analyze_insn (class deps_desc *deps, rtx x, rtx_insn *insn)
reg_last->control_uses
= alloc_INSN_LIST (insn, reg_last->control_uses);
}
+ IOR_REG_SET (&deps->reg_last_dirty, reg_pending_control_uses);
}
}
@@ -3941,6 +3945,7 @@ init_deps (class deps_desc *deps, bool lazy_reg_last)
else
deps->reg_last = XCNEWVEC (struct deps_reg, max_reg);
INIT_REG_SET (&deps->reg_last_in_use);
+ INIT_REG_SET (&deps->reg_last_dirty);
deps->pending_read_insns = 0;
deps->pending_read_mems = 0;
@@ -3999,6 +4004,11 @@ free_deps (class deps_desc *deps)
free_EXPR_LIST_list (&deps->pending_write_mems);
free_INSN_LIST_list (&deps->last_pending_memory_flush);
+ /* Teardown only: fold the entries recorded solely in reg_last_dirty into the
+ live set, so that one loop releases everything. free_deps creates no
+ dependences, so this merge cannot add one. */
+ IOR_REG_SET (&deps->reg_last_in_use, &deps->reg_last_dirty);
+
/* Without the EXECUTE_IF_SET, this loop is executed max_reg * nr_regions
times. For a testcase with 42000 regs and 8000 small basic blocks,
this loop accounted for nearly 60% (84 sec) of the total -O2 runtime. */
@@ -4017,6 +4027,7 @@ free_deps (class deps_desc *deps)
free_INSN_LIST_list (®_last->clobbers);
}
CLEAR_REG_SET (&deps->reg_last_in_use);
+ CLEAR_REG_SET (&deps->reg_last_dirty);
/* As we initialize reg_last lazily, it is possible that we didn't allocate
it at all. */
@@ -5023,4 +5034,74 @@ find_modifiable_mems (rtx_insn *head, rtx_insn *tail)
success_in_block);
}
+#if CHECKING_P
+
+namespace selftest {
+
+/* Verify that free_deps releases entries recorded only in reg_last_dirty. */
+
+static void
+test_dirty_reg_last_release ()
+{
+ bitmap_obstack test_obstack;
+ bitmap_obstack_initialize (&test_obstack);
+
+ deps_desc deps = {};
+ deps.max_reg = 2;
+ deps.reg_last = XCNEWVEC (deps_reg, deps.max_reg);
+ bitmap_initialize (&deps.reg_last_in_use, &test_obstack);
+ bitmap_initialize (&deps.reg_last_dirty, &test_obstack);
+
+ rtx_insn_list *uses = alloc_INSN_LIST (NULL_RTX, NULL_RTX);
+ rtx_insn_list *control_uses = alloc_INSN_LIST (NULL_RTX, NULL_RTX);
+ deps.reg_last[1].uses = uses;
+ deps.reg_last[1].control_uses = control_uses;
+ SET_REGNO_REG_SET (&deps.reg_last_dirty, 1);
+
+ common_sched_info_def sched_info = {};
+ sched_info.sched_pass_id = SCHED_RGN_PASS;
+ common_sched_info_def *saved_common_sched_info = common_sched_info;
+ common_sched_info = &sched_info;
+ free_deps (&deps);
+ common_sched_info = saved_common_sched_info;
+
+ ASSERT_EQ (0, deps.max_reg);
+ ASSERT_EQ (NULL, deps.reg_last);
+
+ rtx_insn_list *first = alloc_INSN_LIST (NULL_RTX, NULL_RTX);
+ rtx_insn_list *second = alloc_INSN_LIST (NULL_RTX, NULL_RTX);
+ ASSERT_TRUE ((first == control_uses && second == uses)
+ || (first == uses && second == control_uses));
+ free_INSN_LIST_list (&first);
+ free_INSN_LIST_list (&second);
+
+ sched_deps_finish ();
+ bitmap_obstack_release (&test_obstack);
+}
+
+/* Run the sched-deps.cc selftests. */
+
+void
+sched_deps_cc_tests ()
+{
+ test_dirty_reg_last_release ();
+}
+
+} // namespace selftest
+
+#endif
+
#endif /* INSN_SCHEDULING */
+
+#if CHECKING_P && !defined (INSN_SCHEDULING)
+
+namespace selftest {
+
+void
+sched_deps_cc_tests ()
+{
+}
+
+} // namespace selftest
+
+#endif
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 4e7553329df..0c7c05abcf2 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -567,6 +567,12 @@ public:
in reg_last[N].{uses,sets,clobbers}. */
regset_head reg_last_in_use;
+ /* Element N is set for each register whose reg_last[N] was written on a
+ path that does not record it in reg_last_in_use, namely debug insn uses
+ and control uses. Used only to release those lists in free_deps; it
+ takes no part in dependence generation. */
+ regset_head reg_last_dirty;
+
/* Shows the last value of reg_pending_barrier associated with the insn. */
enum reg_pending_barrier_mode last_reg_pending_barrier;
diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
index e39a94f8688..1d21b8751b4 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -114,6 +114,7 @@ selftest::run_tests ()
/* This one relies on most of the above. */
function_tests_cc_tests ();
+ sched_deps_cc_tests ();
/* Run any target-specific selftests. */
if (targetm.run_target_selftests)
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 8891d0b7b6f..f2e2b49fc20 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -255,6 +255,7 @@ extern void read_rtl_function_cc_tests ();
extern void relation_tests ();
extern void rtl_tests_cc_tests ();
extern void sbitmap_cc_tests ();
+extern void sched_deps_cc_tests ();
extern void selftest_cc_tests ();
extern void simple_diagnostic_path_cc_tests ();
extern void simplify_rtx_cc_tests ();
--
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.