Commit d8edf83d by Revital Eres Committed by Revital Eres

SMS: Support instructions with REG_INC_NOTE

From-SVN: r179381
parent 442b891d
2011-09-30 Revital Eres <revital.eres@linaro.org> 2011-09-30 Revital Eres <revital.eres@linaro.org>
* ddg.c (autoinc_var_is_used_p): New function.
(create_ddg_dep_from_intra_loop_link,
add_cross_iteration_register_deps): Call it.
* ddg.h (autoinc_var_is_used_p): Declare.
* modulo-sched.c (generate_reg_moves): Call autoinc_var_is_used_p.
(sms_schedule): Handle instructions with REG_INC.
2011-09-30 Revital Eres <revital.eres@linaro.org>
* modulo-sched.c (generate_reg_moves): Skip instructions that * modulo-sched.c (generate_reg_moves): Skip instructions that
do not set a register and verify no regmoves are created for do not set a register and verify no regmoves are created for
!single_set instructions. !single_set instructions.
...@@ -145,6 +145,27 @@ mem_access_insn_p (rtx insn) ...@@ -145,6 +145,27 @@ mem_access_insn_p (rtx insn)
return rtx_mem_access_p (PATTERN (insn)); return rtx_mem_access_p (PATTERN (insn));
} }
/* Return true if DEF_INSN contains address being auto-inc or auto-dec
which is used in USE_INSN. Otherwise return false. The result is
being used to decide whether to remove the edge between def_insn and
use_insn when -fmodulo-sched-allow-regmoves is set. This function
doesn't need to consider the specific address register; no reg_moves
will be allowed for any life range defined by def_insn and used
by use_insn, if use_insn uses an address register auto-inc'ed by
def_insn. */
bool
autoinc_var_is_used_p (rtx def_insn, rtx use_insn)
{
rtx note;
for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_INC
&& reg_referenced_p (XEXP (note, 0), PATTERN (use_insn)))
return true;
return false;
}
/* Computes the dependence parameters (latency, distance etc.), creates /* Computes the dependence parameters (latency, distance etc.), creates
a ddg_edge and adds it to the given DDG. */ a ddg_edge and adds it to the given DDG. */
static void static void
...@@ -173,10 +194,15 @@ create_ddg_dep_from_intra_loop_link (ddg_ptr g, ddg_node_ptr src_node, ...@@ -173,10 +194,15 @@ create_ddg_dep_from_intra_loop_link (ddg_ptr g, ddg_node_ptr src_node,
compensate for that by generating reg-moves based on the life-range compensate for that by generating reg-moves based on the life-range
analysis. The anti-deps that will be deleted are the ones which analysis. The anti-deps that will be deleted are the ones which
have true-deps edges in the opposite direction (in other words have true-deps edges in the opposite direction (in other words
the kernel has only one def of the relevant register). TODO: the kernel has only one def of the relevant register).
support the removal of all anti-deps edges, i.e. including those If the address that is being auto-inc or auto-dec in DEST_NODE
is used in SRC_NODE then do not remove the edge to make sure
reg-moves will not be created for this address.
TODO: support the removal of all anti-deps edges, i.e. including those
whose register has multiple defs in the loop. */ whose register has multiple defs in the loop. */
if (flag_modulo_sched_allow_regmoves && (t == ANTI_DEP && dt == REG_DEP)) if (flag_modulo_sched_allow_regmoves
&& (t == ANTI_DEP && dt == REG_DEP)
&& !autoinc_var_is_used_p (dest_node->insn, src_node->insn))
{ {
rtx set; rtx set;
...@@ -302,10 +328,14 @@ add_cross_iteration_register_deps (ddg_ptr g, df_ref last_def) ...@@ -302,10 +328,14 @@ add_cross_iteration_register_deps (ddg_ptr g, df_ref last_def)
gcc_assert (first_def_node); gcc_assert (first_def_node);
/* Always create the edge if the use node is a branch in /* Always create the edge if the use node is a branch in
order to prevent the creation of reg-moves. */ order to prevent the creation of reg-moves.
If the address that is being auto-inc or auto-dec in LAST_DEF
is used in USE_INSN then do not remove the edge to make sure
reg-moves will not be created for that address. */
if (DF_REF_ID (last_def) != DF_REF_ID (first_def) if (DF_REF_ID (last_def) != DF_REF_ID (first_def)
|| !flag_modulo_sched_allow_regmoves || !flag_modulo_sched_allow_regmoves
|| JUMP_P (use_node->insn)) || JUMP_P (use_node->insn)
|| autoinc_var_is_used_p (DF_REF_INSN (last_def), use_insn))
create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP, create_ddg_dep_no_link (g, use_node, first_def_node, ANTI_DEP,
REG_DEP, 1); REG_DEP, 1);
......
...@@ -186,4 +186,6 @@ void free_ddg_all_sccs (ddg_all_sccs_ptr); ...@@ -186,4 +186,6 @@ void free_ddg_all_sccs (ddg_all_sccs_ptr);
int find_nodes_on_paths (sbitmap result, ddg_ptr, sbitmap from, sbitmap to); int find_nodes_on_paths (sbitmap result, ddg_ptr, sbitmap from, sbitmap to);
int longest_simple_path (ddg_ptr, int from, int to, sbitmap via); int longest_simple_path (ddg_ptr, int from, int to, sbitmap via);
bool autoinc_var_is_used_p (rtx, rtx);
#endif /* GCC_DDG_H */ #endif /* GCC_DDG_H */
...@@ -506,6 +506,10 @@ generate_reg_moves (partial_schedule_ptr ps, bool rescan) ...@@ -506,6 +506,10 @@ generate_reg_moves (partial_schedule_ptr ps, bool rescan)
we assume no regmoves are generated as the doloop we assume no regmoves are generated as the doloop
instructions are tied to the branch with an edge. */ instructions are tied to the branch with an edge. */
gcc_assert (set); gcc_assert (set);
/* If the instruction contains auto-inc register then
validate that the regmov is being generated for the
target regsiter rather then the inc'ed register. */
gcc_assert (!autoinc_var_is_used_p (u->insn, e->dest->insn));
} }
nreg_moves = MAX (nreg_moves, nreg_moves4e); nreg_moves = MAX (nreg_moves, nreg_moves4e);
...@@ -1281,12 +1285,10 @@ sms_schedule (void) ...@@ -1281,12 +1285,10 @@ sms_schedule (void)
continue; continue;
} }
/* Don't handle BBs with calls or barriers or auto-increment insns /* Don't handle BBs with calls or barriers
(to avoid creating invalid reg-moves for the auto-increment insns),
or !single_set with the exception of instructions that include or !single_set with the exception of instructions that include
count_reg---these instructions are part of the control part count_reg---these instructions are part of the control part
that do-loop recognizes. that do-loop recognizes.
??? Should handle auto-increment insns.
??? Should handle insns defining subregs. */ ??? Should handle insns defining subregs. */
for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn)) for (insn = head; insn != NEXT_INSN (tail); insn = NEXT_INSN (insn))
{ {
...@@ -1297,7 +1299,6 @@ sms_schedule (void) ...@@ -1297,7 +1299,6 @@ sms_schedule (void)
|| (NONDEBUG_INSN_P (insn) && !JUMP_P (insn) || (NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE
&& !reg_mentioned_p (count_reg, insn)) && !reg_mentioned_p (count_reg, insn))
|| (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
|| (INSN_P (insn) && (set = single_set (insn)) || (INSN_P (insn) && (set = single_set (insn))
&& GET_CODE (SET_DEST (set)) == SUBREG)) && GET_CODE (SET_DEST (set)) == SUBREG))
break; break;
...@@ -1311,8 +1312,6 @@ sms_schedule (void) ...@@ -1311,8 +1312,6 @@ sms_schedule (void)
fprintf (dump_file, "SMS loop-with-call\n"); fprintf (dump_file, "SMS loop-with-call\n");
else if (BARRIER_P (insn)) else if (BARRIER_P (insn))
fprintf (dump_file, "SMS loop-with-barrier\n"); fprintf (dump_file, "SMS loop-with-barrier\n");
else if (FIND_REG_INC_NOTE (insn, NULL_RTX) != 0)
fprintf (dump_file, "SMS reg inc\n");
else if ((NONDEBUG_INSN_P (insn) && !JUMP_P (insn) else if ((NONDEBUG_INSN_P (insn) && !JUMP_P (insn)
&& !single_set (insn) && GET_CODE (PATTERN (insn)) != USE)) && !single_set (insn) && GET_CODE (PATTERN (insn)) != USE))
fprintf (dump_file, "SMS loop-with-not-single-set\n"); fprintf (dump_file, "SMS loop-with-not-single-set\n");
......
2011-09-30 Revital Eres <revital.eres@linaro.org>
* gcc.dg/sms-10.c: New file
2011-09-30 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org> 2011-09-30 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
* gcc.target/arm/pr50099.c: New test. * gcc.target/arm/pr50099.c: New test.
......
/* { dg-do run } */
/* { dg-options "-O2 -fmodulo-sched -fmodulo-sched-allow-regmoves -fdump-rtl-sms" } */
typedef __SIZE_TYPE__ size_t;
extern void *malloc (size_t);
extern void free (void *);
extern void abort (void);
struct regstat_n_sets_and_refs_t
{
int sets;
int refs;
};
struct regstat_n_sets_and_refs_t *regstat_n_sets_and_refs;
struct df_reg_info
{
unsigned int n_refs;
};
struct df_d
{
struct df_reg_info **def_regs;
struct df_reg_info **use_regs;
};
struct df_d *df;
static inline int
REG_N_SETS (int regno)
{
return regstat_n_sets_and_refs[regno].sets;
}
__attribute__ ((noinline))
int max_reg_num (void)
{
return 100;
}
__attribute__ ((noinline))
void regstat_init_n_sets_and_refs (void)
{
unsigned int i;
unsigned int max_regno = max_reg_num ();
for (i = 0; i < max_regno; i++)
{
(regstat_n_sets_and_refs[i].sets = (df->def_regs[(i)]->n_refs));
(regstat_n_sets_and_refs[i].refs =
(df->use_regs[(i)]->n_refs) + REG_N_SETS (i));
}
}
int a_sets[100] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86,
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
};
int a_refs[100] =
{ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76,
78, 80, 82,
84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116,
118, 120,
122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150,
152, 154, 156,
158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186,
188, 190, 192,
194, 196, 198
};
int
main ()
{
struct df_reg_info *b[100], *c[100];
struct df_d df1;
size_t s = sizeof (struct df_reg_info);
struct regstat_n_sets_and_refs_t a[100];
df = &df1;
regstat_n_sets_and_refs = a;
int i;
for (i = 0; i < 100; i++)
{
b[i] = (struct df_reg_info *) malloc (s);
b[i]->n_refs = i;
c[i] = (struct df_reg_info *) malloc (s);
c[i]->n_refs = i;
}
df1.def_regs = b;
df1.use_regs = c;
regstat_init_n_sets_and_refs ();
for (i = 0; i < 100; i++)
if ((a[i].sets != a_sets[i]) || (a[i].refs != a_refs[i]))
abort ();
for (i = 0; i < 100; i++)
{
free (b[i]);
free (c[i]);
}
return 0;
}
/* { dg-final { scan-rtl-dump-times "SMS succeeded" 1 "sms" { target powerpc*-*-* } } } */
/* { dg-final { cleanup-rtl-dump "sms" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment