[v3,8/8] Improve logging of scheduler dependency analysis context
Commit Message
Scheduler dependency analysis uses two main data structures:
1. reg_pending_* data contains effects of INSN on the register file,
which is then incorporated into ...
2. deps_desc object, which contains commulative information about all
instructions processed from deps_desc object's initialization.
This patch adds debug dumping of (2).
Dependency analysis contexts (aka deps_desc objects) are huge, but
each instruction affects only a small amount of data in these objects.
Therefore, it is most useful to dump differential information
compared to the dependency state after previous instruction.
gcc/ChangeLog:
* sched-deps.cc (reset_deps, dump_rtx_insn_list)
(rtx_insn_list_same_p): New helper functions.
(dump_deps_desc_diff): New function to dump dependency information.
(sched_analysis_prev_deps): New static variable.
(sched_analyze_insn): Dump dependency information.
(init_deps_global, finish_deps_global): Handle sched_analysis_prev_deps.
* sched-int.h (struct deps_reg): Update comments.
* sched-rgn.cc (concat_insn_list, concat_expr_list): Update comments.
---
gcc/sched-deps.cc | 197 ++++++++++++++++++++++++++++++++++++++++++++++
gcc/sched-int.h | 9 ++-
gcc/sched-rgn.cc | 5 ++
3 files changed, 210 insertions(+), 1 deletion(-)
Comments
Dear scheduler maintainers,
Gentle ping. This patch improves debugging output, it does not touch
scheduling logic.
On Wed, 22 Nov 2023 at 15:15, Maxim Kuvyrkov <maxim.kuvyrkov@linaro.org>
wrote:
> Scheduler dependency analysis uses two main data structures:
> 1. reg_pending_* data contains effects of INSN on the register file,
> which is then incorporated into ...
> 2. deps_desc object, which contains commulative information about all
> instructions processed from deps_desc object's initialization.
>
> This patch adds debug dumping of (2).
>
> Dependency analysis contexts (aka deps_desc objects) are huge, but
> each instruction affects only a small amount of data in these objects.
> Therefore, it is most useful to dump differential information
> compared to the dependency state after previous instruction.
>
> gcc/ChangeLog:
>
> * sched-deps.cc (reset_deps, dump_rtx_insn_list)
> (rtx_insn_list_same_p): New helper functions.
> (dump_deps_desc_diff): New function to dump dependency information.
> (sched_analysis_prev_deps): New static variable.
> (sched_analyze_insn): Dump dependency information.
> (init_deps_global, finish_deps_global): Handle
> sched_analysis_prev_deps.
> * sched-int.h (struct deps_reg): Update comments.
> * sched-rgn.cc (concat_insn_list, concat_expr_list): Update
> comments.
> ---
> gcc/sched-deps.cc | 197 ++++++++++++++++++++++++++++++++++++++++++++++
> gcc/sched-int.h | 9 ++-
> gcc/sched-rgn.cc | 5 ++
> 3 files changed, 210 insertions(+), 1 deletion(-)
>
> diff --git a/gcc/sched-deps.cc b/gcc/sched-deps.cc
> index f9290c82fd2..edca9927e23 100644
> --- a/gcc/sched-deps.cc
> +++ b/gcc/sched-deps.cc
> @@ -1677,6 +1677,15 @@ delete_all_dependences (rtx_insn *insn)
> sd_delete_dep (sd_it);
> }
>
> +/* Re-initialize existing dependency context DEPS to be a copy of FROM.
> */
> +static void
> +reset_deps (class deps_desc *deps, class deps_desc *from)
> +{
> + free_deps (deps);
> + init_deps (deps, false);
> + deps_join (deps, from);
> +}
> +
> /* All insns in a scheduling group except the first should only have
> dependencies on the previous insn in the group. So we find the
> first instruction in the scheduling group by walking the dependence
> @@ -2960,6 +2969,177 @@ dump_reg_pending_data (FILE *file, rtx_insn *insn)
> }
> }
>
> +/* Dump rtx_insn_list LIST.
> + Consider moving to lists.cc if there are users outside of
> sched-deps.cc. */
> +static void
> +dump_rtx_insn_list (FILE *file, rtx_insn_list *list)
> +{
> + for (; list; list = list->next ())
> + fprintf (file, " %d", INSN_UID (list->insn ()));
> +}
> +
> +/* Return TRUE if lists A and B have same elements in the same order. */
> +static bool
> +rtx_insn_list_same_p (rtx_insn_list *a, rtx_insn_list *b)
> +{
> + for (; a && b; a = a->next (), b = b->next ())
> + if (a->insn () != b->insn ())
> + return false;
> +
> + if (a || b)
> + return false;
> +
> + return true;
> +}
> +
> +/* Dump parts of DEPS that are different from PREV.
> + Dumping all information from dependency context produces huge
> + hard-to-analize logs; differential dumping is way more managable. */
> +static void
> +dump_deps_desc_diff (FILE *file, class deps_desc *deps, class deps_desc
> *prev)
> +{
> + /* Each "paragraph" is a single line of output. */
> +
> + /* Note on param_max_pending_list_length:
> + During normal dependency analysis various lists should not exceed
> this
> + limit. Searching for "!!!" in scheduler logs can point to potential
> bugs
> + or poorly-handled corner-cases. */
> +
> + if (!rtx_insn_list_same_p (deps->pending_read_insns,
> + prev->pending_read_insns))
> + {
> + fprintf (file, ";; deps pending mem reads length(%d):",
> + deps->pending_read_list_length);
> + if ((deps->pending_read_list_length +
> deps->pending_write_list_length)
> + >= param_max_pending_list_length)
> + fprintf (file, "%d insns!!!", deps->pending_read_list_length);
> + else
> + dump_rtx_insn_list (file, deps->pending_read_insns);
> + fprintf (file, "\n");
> + }
> +
> + if (!rtx_insn_list_same_p (deps->pending_write_insns,
> + prev->pending_write_insns))
> + {
> + fprintf (file, ";; deps pending mem writes length(%d):",
> + deps->pending_write_list_length);
> + if ((deps->pending_read_list_length +
> deps->pending_write_list_length)
> + >= param_max_pending_list_length)
> + fprintf (file, "%d insns!!!", deps->pending_write_list_length);
> + else
> + dump_rtx_insn_list (file, deps->pending_write_insns);
> + fprintf (file, "\n");
> + }
> +
> + if (!rtx_insn_list_same_p (deps->pending_jump_insns,
> + prev->pending_jump_insns))
> + {
> + fprintf (file, ";; deps pending jump length(%d):",
> + deps->pending_flush_length);
> + if (deps->pending_flush_length >= param_max_pending_list_length)
> + fprintf (file, "%d insns!!!", deps->pending_flush_length);
> + else
> + dump_rtx_insn_list (file, deps->pending_jump_insns);
> + fprintf (file, "\n");
> + }
> +
> + fprintf (file, ";; last");
> + if (!rtx_insn_list_same_p (deps->last_pending_memory_flush,
> + prev->last_pending_memory_flush))
> + {
> + fprintf (file, " memory_flush(");
> + dump_rtx_insn_list (file, deps->last_pending_memory_flush);
> + fprintf (file, ")");
> + }
> + if (!rtx_insn_list_same_p (deps->last_function_call,
> + prev->last_function_call))
> + {
> + fprintf (file, " call(");
> + dump_rtx_insn_list (file, deps->last_function_call);
> + fprintf (file, ")");
> + }
> + if (!rtx_insn_list_same_p (deps->last_function_call_may_noreturn,
> + prev->last_function_call_may_noreturn))
> + {
> + fprintf (file, " noreturn(");
> + dump_rtx_insn_list (file, deps->last_function_call_may_noreturn);
> + fprintf (file, ")");
> + }
> + fprintf (file, "\n");
> +
> + fprintf (file, ";; sched_before_next");
> + if (!rtx_insn_list_same_p (deps->sched_before_next_call,
> + prev->sched_before_next_call))
> + {
> + fprintf (file, " call(");
> + dump_rtx_insn_list (file, deps->sched_before_next_call);
> + fprintf (file, ")");
> + }
> + if (!rtx_insn_list_same_p (deps->sched_before_next_jump,
> + prev->sched_before_next_jump))
> + {
> + fprintf (file, " jump(");
> + dump_rtx_insn_list (file, deps->sched_before_next_jump);
> + fprintf (file, ")");
> + }
> + fprintf (file, " in_post_call_group_p(%d)\n",
> deps->in_post_call_group_p);
> +
> + fprintf (file, ";; last_debug_insn(%d) last_args_size(%d)
> last_prologue(",
> + deps->last_debug_insn ? INSN_UID (deps->last_debug_insn) : -1,
> + deps->last_args_size ? INSN_UID (deps->last_args_size) : -1);
> + dump_rtx_insn_list (file, deps->last_prologue);
> + fprintf (file, ") last_epilogue(");
> + dump_rtx_insn_list (file, deps->last_epilogue);
> + fprintf (file, ") last_logue_was_epilogue(%d)\n",
> + deps->last_logue_was_epilogue);
> +
> + int i;
> +
> + gcc_assert (deps->max_reg == prev->max_reg);
> + for (i = 0; i < deps->max_reg; ++i)
> + {
> + struct deps_reg *reg_last = &deps->reg_last[i];
> + struct deps_reg *reg_prev = &prev->reg_last[i];
> +
> + if (rtx_insn_list_same_p (reg_last->uses, reg_prev->uses)
> + && rtx_insn_list_same_p (reg_last->sets, reg_prev->sets)
> + && rtx_insn_list_same_p (reg_last->implicit_sets,
> + reg_prev->implicit_sets)
> + && rtx_insn_list_same_p (reg_last->control_uses,
> + reg_prev->control_uses)
> + && rtx_insn_list_same_p (reg_last->clobbers,
> + reg_prev->clobbers))
> + continue;
> +
> + fprintf (file, ";; reg %u: uses(", i);
> + if (reg_last->uses_length >= param_max_pending_list_length)
> + fprintf (file, "%d insns!!!", reg_last->uses_length);
> + else
> + dump_rtx_insn_list (file, reg_last->uses);
> + if (reg_last->clobbers_length >= param_max_pending_list_length)
> + {
> + fprintf (file, ") clobbers(");
> + fprintf (file, "%d insns!!!", reg_last->clobbers_length);
> + }
> + else
> + {
> + fprintf (file, ") sets(");
> + dump_rtx_insn_list (file, reg_last->sets);
> + fprintf (file, ") implicit_sets(");
> + dump_rtx_insn_list (file, reg_last->implicit_sets);
> + fprintf (file, ") control_uses(");
> + dump_rtx_insn_list (file, reg_last->control_uses);
> + fprintf (file, ") clobbers(");
> + dump_rtx_insn_list (file, reg_last->clobbers);
> + }
> + fprintf (file, ")\n");
> + }
> +}
> +
> +/* Dependency analysis state before current insn.
> + Used by dump_deps_desc_diff(). */
> +static class deps_desc *sched_analysis_prev_deps;
> +
> /* Analyze an INSN with pattern X to find all dependencies.
> This analysis uses two main data structures:
> 1. reg_pending_* data contains effects of INSN on the register file,
> @@ -3627,6 +3807,16 @@ sched_analyze_insn (class deps_desc *deps, rtx x,
> rtx_insn *insn)
> deps->last_logue_was_epilogue = true;
> }
> }
> +
> + if (sched_verbose >= 8)
> + {
> + dump_deps_desc_diff (sched_dump, deps, sched_analysis_prev_deps);
> + reset_deps (sched_analysis_prev_deps, deps);
> + fprintf (sched_dump, ";; ");
> + dump_lists (sched_dump, insn, SD_LIST_BACK,
> + DUMP_LISTS_ALL | DUMP_DEP_PRO);
> + fprintf (sched_dump, "\n");
> + }
> }
>
> /* Return TRUE if INSN might not always return normally (e.g. call exit,
> @@ -4305,6 +4495,9 @@ init_deps_global (void)
> sched_deps_info->note_mem_dep = haifa_note_mem_dep;
> sched_deps_info->note_dep = haifa_note_dep;
> }
> +
> + sched_analysis_prev_deps = XNEW (class deps_desc);
> + init_deps (sched_analysis_prev_deps, false);
> }
>
> /* Free everything used by the dependency analysis code. */
> @@ -4316,6 +4509,10 @@ finish_deps_global (void)
> FREE_REG_SET (reg_pending_clobbers);
> FREE_REG_SET (reg_pending_uses);
> FREE_REG_SET (reg_pending_control_uses);
> +
> + free_deps (sched_analysis_prev_deps);
> + free (sched_analysis_prev_deps);
> + sched_analysis_prev_deps = NULL;
> }
>
> /* Estimate the weakness of dependence between MEM1 and MEM2. */
> diff --git a/gcc/sched-int.h b/gcc/sched-int.h
> index 64a2f0bcff9..8a3109ce86e 100644
> --- a/gcc/sched-int.h
> +++ b/gcc/sched-int.h
> @@ -455,7 +455,9 @@ struct deps_reg
> int clobbers_length;
> };
>
> -/* Describe state of dependencies used during sched_analyze phase. */
> +/* Describe state of dependencies used during sched_analyze phase.
> + Please consider updating sched-deps.cc:dump_deps_desc_diff() when
> adding
> + new fields. */
> class deps_desc
> {
> public:
> @@ -499,6 +501,11 @@ public:
> large lists. */
> int pending_flush_length;
>
> + /* Below are lists (and not just a single instructions) to allow
> inter-block
> + dependency analysis. Each block
> + may add a single insn to below lists, but when merging dependency
> + analysis context from multiple predecessor blocks, we may get a
> list. */
> +
> /* The last insn upon which all memory references must depend.
> This is an insn which flushed the pending lists, creating a
> dependency
> between it and all previously pending memory references. This
> creates
> diff --git a/gcc/sched-rgn.cc b/gcc/sched-rgn.cc
> index da3ec0458ff..72f0a2de66e 100644
> --- a/gcc/sched-rgn.cc
> +++ b/gcc/sched-rgn.cc
> @@ -2590,6 +2590,10 @@ static rtx_insn_list *
> concat_insn_list (rtx_insn_list *copy, rtx_insn_list *old)
> {
> if (!old)
> + /* concat_*_LIST() will return a reversed copy of COPY. Working with
> + reversed copies would complicate dependency dumping in
> + dump_deps_desc_diff(), which internally uses reset_deps() and
> + deps_join(). Therefore, use copy_INSN_LIST() when OLD is NULL. */
> return copy_INSN_LIST (copy);
> return concat_INSN_LIST (copy, old);
> }
> @@ -2599,6 +2603,7 @@ static rtx_expr_list *
> concat_expr_list (rtx_expr_list *copy, rtx_expr_list *old)
> {
> if (!old)
> + /* See comment in concat_insn_list() above. */
> return copy_EXPR_LIST (copy);
> return concat_EXPR_LIST (copy, old);
> }
> --
> 2.34.1
>
>
@@ -1677,6 +1677,15 @@ delete_all_dependences (rtx_insn *insn)
sd_delete_dep (sd_it);
}
+/* Re-initialize existing dependency context DEPS to be a copy of FROM. */
+static void
+reset_deps (class deps_desc *deps, class deps_desc *from)
+{
+ free_deps (deps);
+ init_deps (deps, false);
+ deps_join (deps, from);
+}
+
/* All insns in a scheduling group except the first should only have
dependencies on the previous insn in the group. So we find the
first instruction in the scheduling group by walking the dependence
@@ -2960,6 +2969,177 @@ dump_reg_pending_data (FILE *file, rtx_insn *insn)
}
}
+/* Dump rtx_insn_list LIST.
+ Consider moving to lists.cc if there are users outside of sched-deps.cc. */
+static void
+dump_rtx_insn_list (FILE *file, rtx_insn_list *list)
+{
+ for (; list; list = list->next ())
+ fprintf (file, " %d", INSN_UID (list->insn ()));
+}
+
+/* Return TRUE if lists A and B have same elements in the same order. */
+static bool
+rtx_insn_list_same_p (rtx_insn_list *a, rtx_insn_list *b)
+{
+ for (; a && b; a = a->next (), b = b->next ())
+ if (a->insn () != b->insn ())
+ return false;
+
+ if (a || b)
+ return false;
+
+ return true;
+}
+
+/* Dump parts of DEPS that are different from PREV.
+ Dumping all information from dependency context produces huge
+ hard-to-analize logs; differential dumping is way more managable. */
+static void
+dump_deps_desc_diff (FILE *file, class deps_desc *deps, class deps_desc *prev)
+{
+ /* Each "paragraph" is a single line of output. */
+
+ /* Note on param_max_pending_list_length:
+ During normal dependency analysis various lists should not exceed this
+ limit. Searching for "!!!" in scheduler logs can point to potential bugs
+ or poorly-handled corner-cases. */
+
+ if (!rtx_insn_list_same_p (deps->pending_read_insns,
+ prev->pending_read_insns))
+ {
+ fprintf (file, ";; deps pending mem reads length(%d):",
+ deps->pending_read_list_length);
+ if ((deps->pending_read_list_length + deps->pending_write_list_length)
+ >= param_max_pending_list_length)
+ fprintf (file, "%d insns!!!", deps->pending_read_list_length);
+ else
+ dump_rtx_insn_list (file, deps->pending_read_insns);
+ fprintf (file, "\n");
+ }
+
+ if (!rtx_insn_list_same_p (deps->pending_write_insns,
+ prev->pending_write_insns))
+ {
+ fprintf (file, ";; deps pending mem writes length(%d):",
+ deps->pending_write_list_length);
+ if ((deps->pending_read_list_length + deps->pending_write_list_length)
+ >= param_max_pending_list_length)
+ fprintf (file, "%d insns!!!", deps->pending_write_list_length);
+ else
+ dump_rtx_insn_list (file, deps->pending_write_insns);
+ fprintf (file, "\n");
+ }
+
+ if (!rtx_insn_list_same_p (deps->pending_jump_insns,
+ prev->pending_jump_insns))
+ {
+ fprintf (file, ";; deps pending jump length(%d):",
+ deps->pending_flush_length);
+ if (deps->pending_flush_length >= param_max_pending_list_length)
+ fprintf (file, "%d insns!!!", deps->pending_flush_length);
+ else
+ dump_rtx_insn_list (file, deps->pending_jump_insns);
+ fprintf (file, "\n");
+ }
+
+ fprintf (file, ";; last");
+ if (!rtx_insn_list_same_p (deps->last_pending_memory_flush,
+ prev->last_pending_memory_flush))
+ {
+ fprintf (file, " memory_flush(");
+ dump_rtx_insn_list (file, deps->last_pending_memory_flush);
+ fprintf (file, ")");
+ }
+ if (!rtx_insn_list_same_p (deps->last_function_call,
+ prev->last_function_call))
+ {
+ fprintf (file, " call(");
+ dump_rtx_insn_list (file, deps->last_function_call);
+ fprintf (file, ")");
+ }
+ if (!rtx_insn_list_same_p (deps->last_function_call_may_noreturn,
+ prev->last_function_call_may_noreturn))
+ {
+ fprintf (file, " noreturn(");
+ dump_rtx_insn_list (file, deps->last_function_call_may_noreturn);
+ fprintf (file, ")");
+ }
+ fprintf (file, "\n");
+
+ fprintf (file, ";; sched_before_next");
+ if (!rtx_insn_list_same_p (deps->sched_before_next_call,
+ prev->sched_before_next_call))
+ {
+ fprintf (file, " call(");
+ dump_rtx_insn_list (file, deps->sched_before_next_call);
+ fprintf (file, ")");
+ }
+ if (!rtx_insn_list_same_p (deps->sched_before_next_jump,
+ prev->sched_before_next_jump))
+ {
+ fprintf (file, " jump(");
+ dump_rtx_insn_list (file, deps->sched_before_next_jump);
+ fprintf (file, ")");
+ }
+ fprintf (file, " in_post_call_group_p(%d)\n", deps->in_post_call_group_p);
+
+ fprintf (file, ";; last_debug_insn(%d) last_args_size(%d) last_prologue(",
+ deps->last_debug_insn ? INSN_UID (deps->last_debug_insn) : -1,
+ deps->last_args_size ? INSN_UID (deps->last_args_size) : -1);
+ dump_rtx_insn_list (file, deps->last_prologue);
+ fprintf (file, ") last_epilogue(");
+ dump_rtx_insn_list (file, deps->last_epilogue);
+ fprintf (file, ") last_logue_was_epilogue(%d)\n",
+ deps->last_logue_was_epilogue);
+
+ int i;
+
+ gcc_assert (deps->max_reg == prev->max_reg);
+ for (i = 0; i < deps->max_reg; ++i)
+ {
+ struct deps_reg *reg_last = &deps->reg_last[i];
+ struct deps_reg *reg_prev = &prev->reg_last[i];
+
+ if (rtx_insn_list_same_p (reg_last->uses, reg_prev->uses)
+ && rtx_insn_list_same_p (reg_last->sets, reg_prev->sets)
+ && rtx_insn_list_same_p (reg_last->implicit_sets,
+ reg_prev->implicit_sets)
+ && rtx_insn_list_same_p (reg_last->control_uses,
+ reg_prev->control_uses)
+ && rtx_insn_list_same_p (reg_last->clobbers,
+ reg_prev->clobbers))
+ continue;
+
+ fprintf (file, ";; reg %u: uses(", i);
+ if (reg_last->uses_length >= param_max_pending_list_length)
+ fprintf (file, "%d insns!!!", reg_last->uses_length);
+ else
+ dump_rtx_insn_list (file, reg_last->uses);
+ if (reg_last->clobbers_length >= param_max_pending_list_length)
+ {
+ fprintf (file, ") clobbers(");
+ fprintf (file, "%d insns!!!", reg_last->clobbers_length);
+ }
+ else
+ {
+ fprintf (file, ") sets(");
+ dump_rtx_insn_list (file, reg_last->sets);
+ fprintf (file, ") implicit_sets(");
+ dump_rtx_insn_list (file, reg_last->implicit_sets);
+ fprintf (file, ") control_uses(");
+ dump_rtx_insn_list (file, reg_last->control_uses);
+ fprintf (file, ") clobbers(");
+ dump_rtx_insn_list (file, reg_last->clobbers);
+ }
+ fprintf (file, ")\n");
+ }
+}
+
+/* Dependency analysis state before current insn.
+ Used by dump_deps_desc_diff(). */
+static class deps_desc *sched_analysis_prev_deps;
+
/* Analyze an INSN with pattern X to find all dependencies.
This analysis uses two main data structures:
1. reg_pending_* data contains effects of INSN on the register file,
@@ -3627,6 +3807,16 @@ sched_analyze_insn (class deps_desc *deps, rtx x, rtx_insn *insn)
deps->last_logue_was_epilogue = true;
}
}
+
+ if (sched_verbose >= 8)
+ {
+ dump_deps_desc_diff (sched_dump, deps, sched_analysis_prev_deps);
+ reset_deps (sched_analysis_prev_deps, deps);
+ fprintf (sched_dump, ";; ");
+ dump_lists (sched_dump, insn, SD_LIST_BACK,
+ DUMP_LISTS_ALL | DUMP_DEP_PRO);
+ fprintf (sched_dump, "\n");
+ }
}
/* Return TRUE if INSN might not always return normally (e.g. call exit,
@@ -4305,6 +4495,9 @@ init_deps_global (void)
sched_deps_info->note_mem_dep = haifa_note_mem_dep;
sched_deps_info->note_dep = haifa_note_dep;
}
+
+ sched_analysis_prev_deps = XNEW (class deps_desc);
+ init_deps (sched_analysis_prev_deps, false);
}
/* Free everything used by the dependency analysis code. */
@@ -4316,6 +4509,10 @@ finish_deps_global (void)
FREE_REG_SET (reg_pending_clobbers);
FREE_REG_SET (reg_pending_uses);
FREE_REG_SET (reg_pending_control_uses);
+
+ free_deps (sched_analysis_prev_deps);
+ free (sched_analysis_prev_deps);
+ sched_analysis_prev_deps = NULL;
}
/* Estimate the weakness of dependence between MEM1 and MEM2. */
@@ -455,7 +455,9 @@ struct deps_reg
int clobbers_length;
};
-/* Describe state of dependencies used during sched_analyze phase. */
+/* Describe state of dependencies used during sched_analyze phase.
+ Please consider updating sched-deps.cc:dump_deps_desc_diff() when adding
+ new fields. */
class deps_desc
{
public:
@@ -499,6 +501,11 @@ public:
large lists. */
int pending_flush_length;
+ /* Below are lists (and not just a single instructions) to allow inter-block
+ dependency analysis. Each block
+ may add a single insn to below lists, but when merging dependency
+ analysis context from multiple predecessor blocks, we may get a list. */
+
/* The last insn upon which all memory references must depend.
This is an insn which flushed the pending lists, creating a dependency
between it and all previously pending memory references. This creates
@@ -2590,6 +2590,10 @@ static rtx_insn_list *
concat_insn_list (rtx_insn_list *copy, rtx_insn_list *old)
{
if (!old)
+ /* concat_*_LIST() will return a reversed copy of COPY. Working with
+ reversed copies would complicate dependency dumping in
+ dump_deps_desc_diff(), which internally uses reset_deps() and
+ deps_join(). Therefore, use copy_INSN_LIST() when OLD is NULL. */
return copy_INSN_LIST (copy);
return concat_INSN_LIST (copy, old);
}
@@ -2599,6 +2603,7 @@ static rtx_expr_list *
concat_expr_list (rtx_expr_list *copy, rtx_expr_list *old)
{
if (!old)
+ /* See comment in concat_insn_list() above. */
return copy_EXPR_LIST (copy);
return concat_EXPR_LIST (copy, old);
}