This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Fill more delay slots in conditional returns
- From: Steven Bosscher <stevenb dot gcc at gmail dot com>
- To: Eric Botcazou <ebotcazou at adacore dot com>
- Cc: Jeff Law <law at redhat dot com>, gcc-patches at gcc dot gnu dot org
- Date: Tue, 9 Apr 2013 18:31:17 +0200
- Subject: Re: Fill more delay slots in conditional returns
- References: <1769120 dot Os7kk4Zj9I at polaris> <2198501 dot fcZ53kPIeV at polaris> <515A49B4 dot 3090700 at redhat dot com> <2373459 dot H4ikUyDJrc at polaris>
On Tue, Apr 9, 2013 at 6:15 PM, Eric Botcazou wrote:
>> If you wanted to get ambitious, rewriting reorg.c to compute and use
>> dependency links to drive its candidate selection instead of the insane
>> tracking code it uses would be a huge step forward, both in terms of
>> cleanliness. It'd also help compile-time performance; we do a lot of
>> work to track resources that would be totally unnecessary.
>
> Yes, I agree that it's quite convoluted but, as Steven already said, rewriting
> it to use a more modern framework is hard because of SEQUENCEs and, frankly, I
> have neither the real incentive nor the time to start such an endeavor.
I've actually picked up the idea again. This is just last week-end's
work so don't expect much of it yet ;-)
But I'm near the point where I want to see if I can actually make it
fill some slots from the containing basic block and pushing it through
verify_flow_info somehow.
After that, the hard parts: branches and annulling.
Ciao!
Steven
Index: reorg.c
===================================================================
--- reorg.c (revision 197610)
+++ reorg.c (working copy)
@@ -3847,6 +3847,10 @@
free (uid_to_ruid);
crtl->dbr_scheduled_p = true;
}
+
+#include "sched-deps-graph.c"
+#include "sched-dbr.c"
+
#endif /* DELAY_SLOTS */
static bool
@@ -3865,6 +3869,7 @@
rest_of_handle_delay_slots (void)
{
#ifdef DELAY_SLOTS
+ fill_delay_slots ();
dbr_schedule (get_insns ());
#endif
return 0;
#include "sched-int.h"
/* ??? That means dbr_schedule would come to depend on INSN_SCHEDULING?! */
//#ifdef INSN_SCHEDULING
/* Bah, sched-deps needs this. That's a bug, but what the heck... */
static struct haifa_sched_info sched_dbr_info =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL, NULL,
NULL, NULL,
0, 0,
NULL, NULL, NULL, NULL,
NULL, NULL,
0
};
static struct sched_deps_info_def dbr_sched_deps_info =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
0, 0, 0
};
static struct common_sched_info_def dbr_common_sched_info;
static void
fill_delay_slots_from_bb (basic_block bb)
{
rtx head, tail;
struct deps_desc tmp_deps;
/* Compute dependencies. */
get_ebb_head_tail (bb, bb, &head, &tail);
init_deps_global ();
init_deps (&tmp_deps, false);
sched_analyze (&tmp_deps, head, tail);
free_deps (&tmp_deps);
finish_deps_global ();
/* Print dependency information. */
if (dump_file && sched_dump)
{
fprintf (sched_dump, ";; --------------- forward dependences: ------------ \n");
fprintf (sched_dump, "\n;; --- DBR Dependences --- for bb%d \n", bb->index);
debug_dependencies (head, tail);
}
print_dependencies_graph (stderr, cfun, bb);
rtx insn;
FOR_BB_INSNS (bb, insn)
{
if (! NONDEBUG_INSN_P (insn)
|| (GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER))
continue;
INSN_FROM_TARGET_P (insn) = 0;
if (JUMP_P (insn))
INSN_ANNULLED_BRANCH_P (insn) = 0;
int slots_to_fill = num_delay_slots (insn);
if (slots_to_fill > 0)
{
int flags;
if (JUMP_P (insn))
flags = get_jump_flags (insn, JUMP_LABEL (insn));
else
flags = get_jump_flags (insn, NULL_RTX);
fprintf (stderr,
"// insn %d has %d delay slots to fill\n",
INSN_UID (insn), slots_to_fill);
for (rtx cand_insn = PREV_INSN (insn);
cand_insn != BB_HEAD (bb);
cand_insn = PREV_INSN (cand_insn))
{
sd_iterator_def sd_it;
dep_t dep;
int n_forw_deps = 0;
bool cand_feeds_call_insn = false;
bool cand_deps_cross_insn = false;
/* TRIAL must be a CALL_INSN or INSN. Skip USE and CLOBBER. */
if (! NONDEBUG_INSN_P (cand_insn)
|| (GET_CODE (PATTERN (cand_insn)) == USE
|| GET_CODE (PATTERN (cand_insn)) == CLOBBER))
continue;
if (! eligible_for_delay (insn, 0, cand_insn, flags))
{
fprintf (stderr,
"//\tinsn %d not eligible for delay slots of insn %d\n",
INSN_UID (cand_insn), INSN_UID (insn));
continue;
}
rtx set = single_set (cand_insn);
if (! set || multiple_sets (cand_insn))
continue;
FOR_EACH_DEP (cand_insn, SD_LIST_FORW, sd_it, dep)
{
n_forw_deps++;
if (DF_INSN_LUID (insn) < DF_INSN_LUID (DEP_CON (dep)))
cand_deps_cross_insn = true;
else if (DF_INSN_LUID (insn) == DF_INSN_LUID (DEP_CON (dep))
&& CALL_P (insn) && df_reg_used (insn, SET_DEST (set)))
cand_feeds_call_insn = true;
else // not a deps leaf, not a call arg setter
{
fprintf (stderr,
"//\tinsn %d is not suitable, blocked by insn %d\n",
INSN_UID (cand_insn), INSN_UID (DEP_CON (dep)));
n_forw_deps = -1;
break;
}
}
if (n_forw_deps < 0)
continue;
if (n_forw_deps == 0)
{
fprintf (stderr,
"//\tinsn %d is an obvious candidate, dependencies leaf\n",
INSN_UID (cand_insn));
fprintf (stderr,
"\tfn_%d_insn_uid_%d:e -> fn_%d_insn_uid_%d:e "
"[style=\"dotted\",color=\"green\",constraint=false];\n",
cfun->funcdef_no, INSN_UID (cand_insn),
cfun->funcdef_no, INSN_UID (insn));
}
else if (cand_feeds_call_insn && cand_deps_cross_insn)
{
fprintf (stderr,
"//\tinsn %d may be suitable, feeds branching insn and dependencies cross over insn\n",
INSN_UID (cand_insn));
fprintf (stderr,
"\tfn_%d_insn_uid_%d:e -> fn_%d_insn_uid_%d:e "
"[style=\"dotted\",color=\"red\",constraint=false];\n",
cfun->funcdef_no, INSN_UID (cand_insn),
cfun->funcdef_no, INSN_UID (insn));
}
else if (cand_feeds_call_insn)
{
fprintf (stderr,
"//\tinsn %d is a candidate, sets call arg register\n",
INSN_UID (cand_insn));
fprintf (stderr,
"\tfn_%d_insn_uid_%d:e -> fn_%d_insn_uid_%d:e "
"[style=\"dotted\",color=\"red\",constraint=false];\n",
cfun->funcdef_no, INSN_UID (cand_insn),
cfun->funcdef_no, INSN_UID (insn));
}
else if (cand_deps_cross_insn)
{
fprintf (stderr,
"//\tinsn %d may be suitable, dependencies cross over insn\n",
INSN_UID (cand_insn));
fprintf (stderr,
"\tfn_%d_insn_uid_%d:e -> fn_%d_insn_uid_%d:e "
"[style=\"dotted\",color=\"red\",constraint=false];\n",
cfun->funcdef_no, INSN_UID (cand_insn),
cfun->funcdef_no, INSN_UID (insn));
}
}
}
}
/* Free dependencies. */
sched_free_deps (head, tail, false);
}
/* The main entry point in this file. */
static void
fill_delay_slots (void)
{
basic_block bb;
/* Set up the various scheduler hooks. */
memcpy (&dbr_common_sched_info, &haifa_common_sched_info,
sizeof (dbr_common_sched_info));
common_sched_info = &dbr_common_sched_info;
sched_deps_info = &dbr_sched_deps_info;
current_sched_info = &sched_dbr_info;
compute_bb_for_insn ();
df_analyze ();
haifa_sched_init ();
/* Try to fill delay slots with insns from the same basic block as
the one that contains the insns with the delay slots. */
start_dependencies_graph_dump (stderr);
FOR_EACH_BB (bb)
{
if (bb->flags & BB_DISABLE_SCHEDULE)
continue;
fill_delay_slots_from_bb (bb);
}
end_dependencies_graph_dump (stderr);
free_bb_for_insn ();
haifa_sched_finish ();
}
/* Output routines for graphical representation of scheduler dependencies.
Copyright (C) 2013 Free Software Foundation, Inc.
Contributed by Steven Bosscher, 2012.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "pointer-set.h"
#include "dumpfile.h"
#include "pretty-print.h"
#include "sched-int.h"
/* Return a pretty-print buffer for output to file FP. */
static pretty_printer *
init_deps_pretty_print (FILE *fp)
{
static bool initialized = false;
static pretty_printer graph_slim_pp;
if (! initialized)
{
pp_construct (&graph_slim_pp, /*prefix=*/NULL, /*linewidth=*/0);
initialized = true;
}
else
gcc_assert (! pp_last_position_in_text (&graph_slim_pp));
graph_slim_pp.buffer->stream = fp;
return &graph_slim_pp;
}
static void
mark_transitive_deps (sd_list_types_def list_type, rtx insn, bitmap transitive_deps)
{
sd_iterator_def sd_it;
dep_t dep;
FOR_EACH_DEP (insn, list_type, sd_it, dep)
{
rtx dep_insn = (list_type == SD_LIST_FORW) ? DEP_CON (dep) : DEP_PRO (dep);
if (bitmap_set_bit (transitive_deps, INSN_UID (dep_insn)))
mark_transitive_deps (list_type, dep_insn, transitive_deps);
}
}
/* Draw all forward dependence edges for a region belonging to the function FUN
containing REGION_INSNS. */
static void
draw_dependence_edges (pretty_printer *pp, struct function *fun, vec<rtx> ®ion_insns)
{
bitmap transitive_deps = BITMAP_ALLOC (NULL);
unsigned i;
rtx insn;
FOR_EACH_VEC_ELT (region_insns, i, insn)
{
sd_iterator_def sd_it;
dep_t dep;
bitmap_clear (transitive_deps);
FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
mark_transitive_deps (SD_LIST_FORW, DEP_CON (dep), transitive_deps);
FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
if (! bitmap_bit_p (transitive_deps, INSN_UID (DEP_CON (dep))))
pp_printf (pp,
"\tfn_%d_insn_uid_%d:s -> fn_%d_insn_uid_%d:n "
"[style=\"solid,bold\",color=\"black\",weight=%d];\n",
fun->funcdef_no, INSN_UID (insn),
fun->funcdef_no, INSN_UID (DEP_CON (dep)),
1 + (DEP_COST (dep) > 0 ? 100 * DEP_COST (dep) : 0));
// bitmap_clear (transitive_deps);
// FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
// mark_transitive_deps (SD_LIST_BACK, DEP_PRO (dep), transitive_deps);
// FOR_EACH_DEP (insn, SD_LIST_BACK, sd_it, dep)
// if (! bitmap_bit_p (transitive_deps, INSN_UID (DEP_PRO (dep))))
// pp_printf (pp,
// "\tfn_%d_insn_uid_%d:n -> fn_%d_insn_uid_%d:s "
// "[style=\"dotted\",color=\"red\",constraint=false];\n",
// fun->funcdef_no, INSN_UID (insn),
// fun->funcdef_no, INSN_UID (DEP_PRO (dep)));
}
BITMAP_FREE (transitive_deps);
pp_flush (pp);
}
/* Draw all insns for a region of function FUN containing REGION_INSNS. */
static void
draw_dependence_nodes (pretty_printer *pp, struct function *fun, vec<rtx> ®ion_insns)
{
const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
static int region_no = 1;
unsigned i;
rtx insn;
pp_printf (pp,
"\tsubgraph cluster_%d_%d {\n"
"\tstyle=\"filled\";\n"
"\tcolor=\"darkgreen\";\n"
"\tfillcolor=\"%s\";\n"
"\tlabel=\"region %d\";\n"
"\tlabeljust=l;\n"
"\tpenwidth=2;\n",
fun->funcdef_no, region_no,
fillcolors[(region_no - 1) % 3],
region_no);
pp_write_text_to_stream (pp);
region_no++;
FOR_EACH_VEC_ELT (region_insns, i, insn)
{
pp_printf (pp,
"\tfn_%d_insn_uid_%d "
"[shape=\"record\",style=\"filled\",fillcolor=\"white\","
"label=\"{",
fun->funcdef_no, INSN_UID (insn));
pp_write_text_to_stream (pp);
print_insn (pp, insn, /*verbose=*/ 1);
pp_newline (pp);
pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
pp_string (pp, "}\"];\n\n");
pp_flush (pp);
}
pp_printf (pp, "\t}\n");
pp_flush (pp);
}
/* Print a graphical representation of the dependencies graph
for the region starting from FROM_BB. */
static void
print_dependencies_graph (FILE *outf, struct function *fun, basic_block bb)
{
pretty_printer *pp = init_deps_pretty_print (outf);
pp_printf (pp, "subgraph \"%s\" {\n"
"\tcolor=\"black\";\n"
"\tlabel=\"%s\";\n",
function_name (fun), function_name (fun));
vec<rtx> region_insns = vNULL;
// for (int bb = from_bb; bb < current_nr_blocks; bb++)
{
rtx insn, head, tail;
// get_ebb_head_tail (EBB_FIRST_BB (bb), EBB_LAST_BB (bb), &head, &tail);
get_ebb_head_tail (bb, bb, &head, &tail);
for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
if (NONDEBUG_INSN_P (insn))
region_insns.safe_push (insn);
}
draw_dependence_nodes (pp, fun, region_insns);
draw_dependence_edges (pp, fun, region_insns);
pp_printf (pp, "}\n");
pp_flush (pp);
}
/* Start the dump of a graph. */
static void
start_dependencies_graph_dump (FILE *outf)
{
pretty_printer *pp = init_deps_pretty_print (outf);
pp_flush (pp);
pp_string (pp, "digraph \"dependencies_graph\" {\n");
pp_string (pp, "overlap=false;\n");
pp_flush (pp);
}
/* End the dump of a graph. */
static void
end_dependencies_graph_dump (FILE *outf)
{
pretty_printer *pp = init_deps_pretty_print (outf);
pp_string (pp, "}\n");
pp_flush (pp);
}