Commit 37a0f8a5 by Richard Henderson Committed by Richard Henderson

sched-deps.c (reg_pending_uses_head): New.

        * sched-deps.c (reg_pending_uses_head): New.
        (reg_pending_barrier): Rename from reg_pending_sets_all.
        (find_insn_list): Don't mark inline.
        (find_insn_mem_list): Remove.
        (add_dependence_list, add_dependence_list_and_free): New.
        (flush_pending_lists): Replace only_write param with separate
        for_read and for_write parameters.  Update all callers.  Use
        add_dependence_list_and_free.
        (sched_analyze_1): Do not add reg dependencies here; just set
        the pending bits.  Use add_dependence_list.
        (sched_analyze_2): Likewise.
        (sched_analyze_insn): Replace schedule_barrier_found with
        reg_pending_barrier.  Add all dependencies for pending reg
        uses, sets, and clobbers.
        (sched_analyze): Don't add reg dependencies for calls, just
        set pending bits.  Use regs_invalidated_by_call.  Treat
        sched_before_next_call as a normal list, not a fake insn.
        (init_deps): No funny init for sched_before_next_call.
        (free_deps): Free pending mems lists.  Don't zero reg_last.
        (init_deps_global): Init reg_pending_uses.
        (finish_deps_global): Free it.
        * sched-int.h (deps): Make in_post_call_group_p boolean.  Update docs.
        (find_insn_mem_list): Remove.
        * sched-rgn.c (concat_INSN_LIST, concat_insn_mem_list): New.
        (propagate_deps): Use them.  Zero temp mem lists.

From-SVN: r49262
parent cea3bd3e
2002-01-26 Richard Henderson <rth@redhat.com> 2002-01-26 Richard Henderson <rth@redhat.com>
* sched-deps.c (reg_pending_uses_head): New.
(reg_pending_barrier): Rename from reg_pending_sets_all.
(find_insn_list): Don't mark inline.
(find_insn_mem_list): Remove.
(add_dependence_list, add_dependence_list_and_free): New.
(flush_pending_lists): Replace only_write param with separate
for_read and for_write parameters. Update all callers. Use
add_dependence_list_and_free.
(sched_analyze_1): Do not add reg dependencies here; just set
the pending bits. Use add_dependence_list.
(sched_analyze_2): Likewise.
(sched_analyze_insn): Replace schedule_barrier_found with
reg_pending_barrier. Add all dependencies for pending reg
uses, sets, and clobbers.
(sched_analyze): Don't add reg dependencies for calls, just
set pending bits. Use regs_invalidated_by_call. Treat
sched_before_next_call as a normal list, not a fake insn.
(init_deps): No funny init for sched_before_next_call.
(free_deps): Free pending mems lists. Don't zero reg_last.
(init_deps_global): Init reg_pending_uses.
(finish_deps_global): Free it.
* sched-int.h (deps): Make in_post_call_group_p boolean. Update docs.
(find_insn_mem_list): Remove.
* sched-rgn.c (concat_INSN_LIST, concat_insn_mem_list): New.
(propagate_deps): Use them. Zero temp mem lists.
2002-01-26 Richard Henderson <rth@redhat.com>
* Makefile.in (CRTSTUFF_CFLAGS): New. * Makefile.in (CRTSTUFF_CFLAGS): New.
(crtbegin.o, crtend.o, crtbeginS.o, crtendS.o, crtbeginT.o): Use it. (crtbegin.o, crtend.o, crtbeginS.o, crtendS.o, crtbeginT.o): Use it.
* config.gcc (alpha-linux, alpha-freebsd, alpha-netbsd): Use plain * config.gcc (alpha-linux, alpha-freebsd, alpha-netbsd): Use plain
......
...@@ -46,10 +46,12 @@ extern rtx *reg_known_value; ...@@ -46,10 +46,12 @@ extern rtx *reg_known_value;
static regset_head reg_pending_sets_head; static regset_head reg_pending_sets_head;
static regset_head reg_pending_clobbers_head; static regset_head reg_pending_clobbers_head;
static regset_head reg_pending_uses_head;
static regset reg_pending_sets; static regset reg_pending_sets;
static regset reg_pending_clobbers; static regset reg_pending_clobbers;
static int reg_pending_sets_all; static regset reg_pending_uses;
static bool reg_pending_barrier;
/* To speed up the test for duplicate dependency links we keep a /* To speed up the test for duplicate dependency links we keep a
record of dependencies created by add_dependence when the average record of dependencies created by add_dependence when the average
...@@ -77,10 +79,12 @@ static sbitmap *forward_dependency_cache; ...@@ -77,10 +79,12 @@ static sbitmap *forward_dependency_cache;
#endif #endif
static int deps_may_trap_p PARAMS ((rtx)); static int deps_may_trap_p PARAMS ((rtx));
static void add_dependence_list PARAMS ((rtx, rtx, enum reg_note));
static void add_dependence_list_and_free PARAMS ((rtx, rtx *, enum reg_note));
static void remove_dependence PARAMS ((rtx, rtx)); static void remove_dependence PARAMS ((rtx, rtx));
static void set_sched_group_p PARAMS ((rtx)); static void set_sched_group_p PARAMS ((rtx));
static void flush_pending_lists PARAMS ((struct deps *, rtx, int)); static void flush_pending_lists PARAMS ((struct deps *, rtx, int, int));
static void sched_analyze_1 PARAMS ((struct deps *, rtx, rtx)); static void sched_analyze_1 PARAMS ((struct deps *, rtx, rtx));
static void sched_analyze_2 PARAMS ((struct deps *, rtx, rtx)); static void sched_analyze_2 PARAMS ((struct deps *, rtx, rtx));
static void sched_analyze_insn PARAMS ((struct deps *, rtx, rtx, rtx)); static void sched_analyze_insn PARAMS ((struct deps *, rtx, rtx, rtx));
...@@ -107,7 +111,7 @@ deps_may_trap_p (mem) ...@@ -107,7 +111,7 @@ deps_may_trap_p (mem)
/* Return the INSN_LIST containing INSN in LIST, or NULL /* Return the INSN_LIST containing INSN in LIST, or NULL
if LIST does not contain INSN. */ if LIST does not contain INSN. */
HAIFA_INLINE rtx rtx
find_insn_list (insn, list) find_insn_list (insn, list)
rtx insn; rtx insn;
rtx list; rtx list;
...@@ -121,25 +125,6 @@ find_insn_list (insn, list) ...@@ -121,25 +125,6 @@ find_insn_list (insn, list)
return 0; return 0;
} }
/* Return 1 if the pair (insn, x) is found in (LIST, LIST1), or 0
otherwise. */
HAIFA_INLINE int
find_insn_mem_list (insn, x, list, list1)
rtx insn, x;
rtx list, list1;
{
while (list)
{
if (XEXP (list, 0) == insn
&& XEXP (list1, 0) == x)
return 1;
list = XEXP (list, 1);
list1 = XEXP (list1, 1);
}
return 0;
}
/* Find the condition under which INSN is executed. */ /* Find the condition under which INSN is executed. */
static rtx static rtx
...@@ -370,6 +355,34 @@ add_dependence (insn, elem, dep_type) ...@@ -370,6 +355,34 @@ add_dependence (insn, elem, dep_type)
#endif #endif
} }
/* A convenience wrapper to operate on an entire list. */
static void
add_dependence_list (insn, list, dep_type)
rtx insn, list;
enum reg_note dep_type;
{
for (; list; list = XEXP (list, 1))
add_dependence (insn, XEXP (list, 0), dep_type);
}
/* Similar, but free *LISTP at the same time. */
static void
add_dependence_list_and_free (insn, listp, dep_type)
rtx insn;
rtx *listp;
enum reg_note dep_type;
{
rtx list, next;
for (list = *listp, *listp = NULL; list ; list = next)
{
next = XEXP (list, 1);
add_dependence (insn, XEXP (list, 0), dep_type);
free_INSN_LIST_node (list);
}
}
/* Remove ELEM wrapped in an INSN_LIST from the LOG_LINKS /* Remove ELEM wrapped in an INSN_LIST from the LOG_LINKS
of INSN. Abort if not found. */ of INSN. Abort if not found. */
...@@ -505,51 +518,29 @@ add_insn_mem_dependence (deps, insn_list, mem_list, insn, mem) ...@@ -505,51 +518,29 @@ add_insn_mem_dependence (deps, insn_list, mem_list, insn, mem)
} }
/* Make a dependency between every memory reference on the pending lists /* Make a dependency between every memory reference on the pending lists
and INSN, thus flushing the pending lists. If ONLY_WRITE, don't flush and INSN, thus flushing the pending lists. FOR_READ is true if emitting
the read list. */ dependencies for a read operation, similarly with FOR_WRITE. */
static void static void
flush_pending_lists (deps, insn, only_write) flush_pending_lists (deps, insn, for_read, for_write)
struct deps *deps; struct deps *deps;
rtx insn; rtx insn;
int only_write; int for_read, for_write;
{ {
rtx u; if (for_write)
rtx link;
while (deps->pending_read_insns && ! only_write)
{ {
add_dependence (insn, XEXP (deps->pending_read_insns, 0), add_dependence_list_and_free (insn, &deps->pending_read_insns,
REG_DEP_ANTI); REG_DEP_ANTI);
free_EXPR_LIST_list (&deps->pending_read_mems);
link = deps->pending_read_insns;
deps->pending_read_insns = XEXP (deps->pending_read_insns, 1);
free_INSN_LIST_node (link);
link = deps->pending_read_mems;
deps->pending_read_mems = XEXP (deps->pending_read_mems, 1);
free_EXPR_LIST_node (link);
} }
while (deps->pending_write_insns)
{
add_dependence (insn, XEXP (deps->pending_write_insns, 0),
REG_DEP_ANTI);
link = deps->pending_write_insns;
deps->pending_write_insns = XEXP (deps->pending_write_insns, 1);
free_INSN_LIST_node (link);
link = deps->pending_write_mems; add_dependence_list_and_free (insn, &deps->pending_write_insns,
deps->pending_write_mems = XEXP (deps->pending_write_mems, 1); for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
free_EXPR_LIST_node (link); free_EXPR_LIST_list (&deps->pending_write_mems);
}
deps->pending_lists_length = 0; deps->pending_lists_length = 0;
/* last_pending_memory_flush is now a list of insns. */ add_dependence_list_and_free (insn, &deps->last_pending_memory_flush,
for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) for_read ? REG_DEP_ANTI : REG_DEP_OUTPUT);
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
free_INSN_LIST_list (&deps->last_pending_memory_flush);
deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX); deps->last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX);
deps->pending_flush_length = 1; deps->pending_flush_length = 1;
} }
...@@ -601,46 +592,22 @@ sched_analyze_1 (deps, x, insn) ...@@ -601,46 +592,22 @@ sched_analyze_1 (deps, x, insn)
if (GET_CODE (dest) == REG) if (GET_CODE (dest) == REG)
{ {
int i;
regno = REGNO (dest); regno = REGNO (dest);
/* A hard reg in a wide mode may really be multiple registers. /* A hard reg in a wide mode may really be multiple registers.
If so, mark all of them just like the first. */ If so, mark all of them just like the first. */
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
{ {
i = HARD_REGNO_NREGS (regno, GET_MODE (dest)); int i = HARD_REGNO_NREGS (regno, GET_MODE (dest));
while (--i >= 0)
{
int r = regno + i;
rtx u;
for (u = deps->reg_last[r].uses; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
for (u = deps->reg_last[r].sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT);
/* Clobbers need not be ordered with respect to one
another, but sets must be ordered with respect to a
pending clobber. */
if (code == SET) if (code == SET)
{ {
if (GET_CODE (PATTERN (insn)) != COND_EXEC) while (--i >= 0)
free_INSN_LIST_list (&deps->reg_last[r].uses); SET_REGNO_REG_SET (reg_pending_sets, regno + i);
for (u = deps->reg_last[r].clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT);
SET_REGNO_REG_SET (reg_pending_sets, r);
} }
else else
SET_REGNO_REG_SET (reg_pending_clobbers, r); {
while (--i >= 0)
/* Function calls clobber all call_used regs. */ SET_REGNO_REG_SET (reg_pending_clobbers, regno + i);
if (global_regs[r]
|| (code == SET
&& TEST_HARD_REG_BIT (regs_invalidated_by_call, r)))
for (u = deps->last_function_call; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
} }
} }
/* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that /* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that
...@@ -654,22 +621,8 @@ sched_analyze_1 (deps, x, insn) ...@@ -654,22 +621,8 @@ sched_analyze_1 (deps, x, insn)
} }
else else
{ {
rtx u;
for (u = deps->reg_last[regno].uses; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
for (u = deps->reg_last[regno].sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT);
if (code == SET) if (code == SET)
{
if (GET_CODE (PATTERN (insn)) != COND_EXEC)
free_INSN_LIST_list (&deps->reg_last[regno].uses);
for (u = deps->reg_last[regno].clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT);
SET_REGNO_REG_SET (reg_pending_sets, regno); SET_REGNO_REG_SET (reg_pending_sets, regno);
}
else else
SET_REGNO_REG_SET (reg_pending_clobbers, regno); SET_REGNO_REG_SET (reg_pending_clobbers, regno);
...@@ -683,10 +636,8 @@ sched_analyze_1 (deps, x, insn) ...@@ -683,10 +636,8 @@ sched_analyze_1 (deps, x, insn)
/* Don't let it cross a call after scheduling if it doesn't /* Don't let it cross a call after scheduling if it doesn't
already cross one. */ already cross one. */
if (REG_N_CALLS_CROSSED (regno) == 0) if (REG_N_CALLS_CROSSED (regno) == 0)
for (u = deps->last_function_call; u; u = XEXP (u, 1)) add_dependence_list (insn, deps->last_function_call, REG_DEP_ANTI);
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
} }
} }
else if (GET_CODE (dest) == MEM) else if (GET_CODE (dest) == MEM)
...@@ -708,11 +659,10 @@ sched_analyze_1 (deps, x, insn) ...@@ -708,11 +659,10 @@ sched_analyze_1 (deps, x, insn)
these lists get long. When compiling GCC with itself, these lists get long. When compiling GCC with itself,
this flush occurs 8 times for sparc, and 10 times for m88k using this flush occurs 8 times for sparc, and 10 times for m88k using
the default value of 32. */ the default value of 32. */
flush_pending_lists (deps, insn, 0); flush_pending_lists (deps, insn, false, true);
} }
else else
{ {
rtx u;
rtx pending, pending_mem; rtx pending, pending_mem;
pending = deps->pending_read_insns; pending = deps->pending_read_insns;
...@@ -737,8 +687,8 @@ sched_analyze_1 (deps, x, insn) ...@@ -737,8 +687,8 @@ sched_analyze_1 (deps, x, insn)
pending_mem = XEXP (pending_mem, 1); pending_mem = XEXP (pending_mem, 1);
} }
for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) add_dependence_list (insn, deps->last_pending_memory_flush,
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); REG_DEP_ANTI);
add_insn_mem_dependence (deps, &deps->pending_write_insns, add_insn_mem_dependence (deps, &deps->pending_write_insns,
&deps->pending_write_mems, insn, dest); &deps->pending_write_mems, insn, dest);
...@@ -790,32 +740,12 @@ sched_analyze_2 (deps, x, insn) ...@@ -790,32 +740,12 @@ sched_analyze_2 (deps, x, insn)
case REG: case REG:
{ {
rtx u;
int regno = REGNO (x); int regno = REGNO (x);
if (regno < FIRST_PSEUDO_REGISTER) if (regno < FIRST_PSEUDO_REGISTER)
{ {
int i; int i = HARD_REGNO_NREGS (regno, GET_MODE (x));
i = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--i >= 0) while (--i >= 0)
{ SET_REGNO_REG_SET (reg_pending_uses, regno + i);
int r = regno + i;
deps->reg_last[r].uses
= alloc_INSN_LIST (insn, deps->reg_last[r].uses);
SET_REGNO_REG_SET (&deps->reg_last_in_use, r);
for (u = deps->reg_last[r].sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
/* ??? This should never happen. */
for (u = deps->reg_last[r].clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
if (call_used_regs[r] || global_regs[r])
/* Function calls clobber all call_used regs. */
for (u = deps->last_function_call; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
}
} }
/* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that /* ??? Reload sometimes emits USEs and CLOBBERs of pseudos that
it does not reload. Ignore these as they have served their it does not reload. Ignore these as they have served their
...@@ -828,16 +758,7 @@ sched_analyze_2 (deps, x, insn) ...@@ -828,16 +758,7 @@ sched_analyze_2 (deps, x, insn)
} }
else else
{ {
deps->reg_last[regno].uses SET_REGNO_REG_SET (reg_pending_uses, regno);
= alloc_INSN_LIST (insn, deps->reg_last[regno].uses);
SET_REGNO_REG_SET (&deps->reg_last_in_use, regno);
for (u = deps->reg_last[regno].sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
/* ??? This should never happen. */
for (u = deps->reg_last[regno].clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
/* Pseudos that are REG_EQUIV to something may be replaced /* Pseudos that are REG_EQUIV to something may be replaced
by that during reloading. We need only add dependencies for by that during reloading. We need only add dependencies for
...@@ -851,8 +772,8 @@ sched_analyze_2 (deps, x, insn) ...@@ -851,8 +772,8 @@ sched_analyze_2 (deps, x, insn)
insn to the sched_before_next_call list so that it will still insn to the sched_before_next_call list so that it will still
not cross calls after scheduling. */ not cross calls after scheduling. */
if (REG_N_CALLS_CROSSED (regno) == 0) if (REG_N_CALLS_CROSSED (regno) == 0)
add_dependence (deps->sched_before_next_call, insn, deps->sched_before_next_call
REG_DEP_ANTI); = alloc_INSN_LIST (insn, deps->sched_before_next_call);
} }
return; return;
} }
...@@ -910,15 +831,13 @@ sched_analyze_2 (deps, x, insn) ...@@ -910,15 +831,13 @@ sched_analyze_2 (deps, x, insn)
/* Force pending stores to memory in case a trap handler needs them. */ /* Force pending stores to memory in case a trap handler needs them. */
case TRAP_IF: case TRAP_IF:
flush_pending_lists (deps, insn, 1); flush_pending_lists (deps, insn, true, false);
break; break;
case ASM_OPERANDS: case ASM_OPERANDS:
case ASM_INPUT: case ASM_INPUT:
case UNSPEC_VOLATILE: case UNSPEC_VOLATILE:
{ {
rtx u;
/* Traditional and volatile asm instructions must be considered to use /* Traditional and volatile asm instructions must be considered to use
and clobber all hard registers, all pseudo-registers and all of and clobber all hard registers, all pseudo-registers and all of
memory. So must TRAP_IF and UNSPEC_VOLATILE operations. memory. So must TRAP_IF and UNSPEC_VOLATILE operations.
...@@ -927,25 +846,7 @@ sched_analyze_2 (deps, x, insn) ...@@ -927,25 +846,7 @@ sched_analyze_2 (deps, x, insn)
mode. An insn should not be moved across this even if it only uses mode. An insn should not be moved across this even if it only uses
pseudo-regs because it might give an incorrectly rounded result. */ pseudo-regs because it might give an incorrectly rounded result. */
if (code != ASM_OPERANDS || MEM_VOLATILE_P (x)) if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
{ reg_pending_barrier = true;
for (i = 0; i < deps->max_reg; i++)
{
struct deps_reg *reg_last = &deps->reg_last[i];
for (u = reg_last->uses; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
for (u = reg_last->sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
for (u = reg_last->clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
if (GET_CODE (PATTERN (insn)) != COND_EXEC)
free_INSN_LIST_list (&reg_last->uses);
}
reg_pending_sets_all = 1;
flush_pending_lists (deps, insn, 0);
}
/* For all ASM_OPERANDS, we must traverse the vector of input operands. /* For all ASM_OPERANDS, we must traverse the vector of input operands.
We can not just fall through here since then we would be confused We can not just fall through here since then we would be confused
...@@ -1008,7 +909,6 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1008,7 +909,6 @@ sched_analyze_insn (deps, x, insn, loop_notes)
rtx loop_notes; rtx loop_notes;
{ {
RTX_CODE code = GET_CODE (x); RTX_CODE code = GET_CODE (x);
int schedule_barrier_found = 0;
rtx link; rtx link;
int i; int i;
...@@ -1057,7 +957,7 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1057,7 +957,7 @@ sched_analyze_insn (deps, x, insn, loop_notes)
sched_analyze_2 (deps, XEXP (link, 0), insn); sched_analyze_2 (deps, XEXP (link, 0), insn);
} }
if (find_reg_note (insn, REG_SETJMP, NULL)) if (find_reg_note (insn, REG_SETJMP, NULL))
schedule_barrier_found = 1; reg_pending_barrier = true;
} }
if (GET_CODE (insn) == JUMP_INSN) if (GET_CODE (insn) == JUMP_INSN)
...@@ -1065,23 +965,15 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1065,23 +965,15 @@ sched_analyze_insn (deps, x, insn, loop_notes)
rtx next; rtx next;
next = next_nonnote_insn (insn); next = next_nonnote_insn (insn);
if (next && GET_CODE (next) == BARRIER) if (next && GET_CODE (next) == BARRIER)
schedule_barrier_found = 1; reg_pending_barrier = true;
else else
{ {
rtx pending, pending_mem, u; rtx pending, pending_mem;
regset_head tmp; regset_head tmp;
INIT_REG_SET (&tmp); INIT_REG_SET (&tmp);
(*current_sched_info->compute_jump_reg_dependencies) (insn, &tmp); (*current_sched_info->compute_jump_reg_dependencies) (insn, &tmp);
EXECUTE_IF_SET_IN_REG_SET (&tmp, 0, i, IOR_REG_SET (reg_pending_uses, &tmp);
{
struct deps_reg *reg_last = &deps->reg_last[i];
for (u = reg_last->sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
});
CLEAR_REG_SET (&tmp); CLEAR_REG_SET (&tmp);
/* All memory writes and volatile reads must happen before the /* All memory writes and volatile reads must happen before the
...@@ -1107,8 +999,8 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1107,8 +999,8 @@ sched_analyze_insn (deps, x, insn, loop_notes)
pending_mem = XEXP (pending_mem, 1); pending_mem = XEXP (pending_mem, 1);
} }
for (u = deps->last_pending_memory_flush; u; u = XEXP (u, 1)) add_dependence_list (insn, deps->last_pending_memory_flush,
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); REG_DEP_ANTI);
} }
} }
...@@ -1130,7 +1022,7 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1130,7 +1022,7 @@ sched_analyze_insn (deps, x, insn, loop_notes)
|| INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_END || INTVAL (XEXP (link, 0)) == NOTE_INSN_LOOP_END
|| INTVAL (XEXP (link, 0)) == NOTE_INSN_EH_REGION_BEG || INTVAL (XEXP (link, 0)) == NOTE_INSN_EH_REGION_BEG
|| INTVAL (XEXP (link, 0)) == NOTE_INSN_EH_REGION_END) || INTVAL (XEXP (link, 0)) == NOTE_INSN_EH_REGION_END)
schedule_barrier_found = 1; reg_pending_barrier = true;
link = XEXP (link, 1); link = XEXP (link, 1);
} }
...@@ -1142,72 +1034,95 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1142,72 +1034,95 @@ sched_analyze_insn (deps, x, insn, loop_notes)
where block boundaries fall. This is mighty confusing elsewhere. where block boundaries fall. This is mighty confusing elsewhere.
Therefore, prevent such an instruction from being moved. */ Therefore, prevent such an instruction from being moved. */
if (can_throw_internal (insn)) if (can_throw_internal (insn))
schedule_barrier_found = 1; reg_pending_barrier = true;
/* Add dependencies if a scheduling barrier was found. */ /* Add dependencies if a scheduling barrier was found. */
if (schedule_barrier_found) if (reg_pending_barrier)
{ {
rtx u; if (GET_CODE (PATTERN (insn)) == COND_EXEC)
{
for (i = 0; i < deps->max_reg; i++) EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i,
{ {
struct deps_reg *reg_last = &deps->reg_last[i]; struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI);
for (u = reg_last->uses; u; u = XEXP (u, 1)) add_dependence_list (insn, reg_last->sets, 0);
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); add_dependence_list (insn, reg_last->clobbers, 0);
for (u = reg_last->sets; u; u = XEXP (u, 1)) });
add_dependence (insn, XEXP (u, 0), 0);
for (u = reg_last->clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
if (GET_CODE (PATTERN (insn)) != COND_EXEC)
free_INSN_LIST_list (&reg_last->uses);
} }
flush_pending_lists (deps, insn, 0); else
{
reg_pending_sets_all = 1; EXECUTE_IF_SET_IN_REG_SET (&deps->reg_last_in_use, 0, i,
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list_and_free (insn, &reg_last->uses,
REG_DEP_ANTI);
add_dependence_list_and_free (insn, &reg_last->sets, 0);
add_dependence_list_and_free (insn, &reg_last->clobbers, 0);
});
} }
/* Accumulate clobbers until the next set so that it will be output
dependent on all of them. At the next set we can clear the clobber
list, since subsequent sets will be output dependent on it. */
if (reg_pending_sets_all)
{
reg_pending_sets_all = 0;
for (i = 0; i < deps->max_reg; i++) for (i = 0; i < deps->max_reg; i++)
{ {
struct deps_reg *reg_last = &deps->reg_last[i]; struct deps_reg *reg_last = &deps->reg_last[i];
if (GET_CODE (PATTERN (insn)) != COND_EXEC)
{
free_INSN_LIST_list (&reg_last->sets);
free_INSN_LIST_list (&reg_last->clobbers);
}
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets); reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
SET_REGNO_REG_SET (&deps->reg_last_in_use, i); SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
} }
flush_pending_lists (deps, insn, true, true);
reg_pending_barrier = false;
} }
else else
{ {
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i, EXECUTE_IF_SET_IN_REG_SET (reg_pending_uses, 0, i,
{ {
struct deps_reg *reg_last = &deps->reg_last[i]; struct deps_reg *reg_last = &deps->reg_last[i];
if (GET_CODE (PATTERN (insn)) != COND_EXEC) add_dependence_list (insn, reg_last->sets, 0);
{ add_dependence_list (insn, reg_last->clobbers, 0);
free_INSN_LIST_list (&reg_last->sets); reg_last->uses = alloc_INSN_LIST (insn, reg_last->uses);
free_INSN_LIST_list (&reg_last->clobbers);
}
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
SET_REGNO_REG_SET (&deps->reg_last_in_use, i);
}); });
EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i, EXECUTE_IF_SET_IN_REG_SET (reg_pending_clobbers, 0, i,
{ {
struct deps_reg *reg_last = &deps->reg_last[i]; struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI);
reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers); reg_last->clobbers = alloc_INSN_LIST (insn, reg_last->clobbers);
SET_REGNO_REG_SET (&deps->reg_last_in_use, i); });
/* If the current insn is conditional, we can't free any
of the lists. */
if (GET_CODE (PATTERN (insn)) == COND_EXEC)
{
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i,
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list (insn, reg_last->sets, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->clobbers, REG_DEP_OUTPUT);
add_dependence_list (insn, reg_last->uses, REG_DEP_ANTI);
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
}); });
} }
CLEAR_REG_SET (reg_pending_sets); else
{
EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i,
{
struct deps_reg *reg_last = &deps->reg_last[i];
add_dependence_list_and_free (insn, &reg_last->sets,
REG_DEP_OUTPUT);
add_dependence_list_and_free (insn, &reg_last->clobbers,
REG_DEP_OUTPUT);
add_dependence_list_and_free (insn, &reg_last->uses,
REG_DEP_ANTI);
reg_last->sets = alloc_INSN_LIST (insn, reg_last->sets);
});
}
IOR_REG_SET (&deps->reg_last_in_use, reg_pending_uses);
IOR_REG_SET (&deps->reg_last_in_use, reg_pending_clobbers);
IOR_REG_SET (&deps->reg_last_in_use, reg_pending_sets);
}
CLEAR_REG_SET (reg_pending_uses);
CLEAR_REG_SET (reg_pending_clobbers); CLEAR_REG_SET (reg_pending_clobbers);
CLEAR_REG_SET (reg_pending_sets);
/* If a post-call group is still open, see if it should remain so. /* If a post-call group is still open, see if it should remain so.
This insn must be a simple move of a hard reg to a pseudo or This insn must be a simple move of a hard reg to a pseudo or
...@@ -1251,7 +1166,7 @@ sched_analyze_insn (deps, x, insn, loop_notes) ...@@ -1251,7 +1166,7 @@ sched_analyze_insn (deps, x, insn, loop_notes)
else else
{ {
end_call_group: end_call_group:
deps->in_post_call_group_p = 0; deps->in_post_call_group_p = false;
} }
} }
} }
...@@ -1265,7 +1180,6 @@ sched_analyze (deps, head, tail) ...@@ -1265,7 +1180,6 @@ sched_analyze (deps, head, tail)
rtx head, tail; rtx head, tail;
{ {
rtx insn; rtx insn;
rtx u;
rtx loop_notes = 0; rtx loop_notes = 0;
if (current_sched_info->use_cselib) if (current_sched_info->use_cselib)
...@@ -1287,7 +1201,7 @@ sched_analyze (deps, head, tail) ...@@ -1287,7 +1201,7 @@ sched_analyze (deps, head, tail)
{ {
/* Keep the list a reasonable size. */ /* Keep the list a reasonable size. */
if (deps->pending_flush_length++ > MAX_PENDING_LIST_LENGTH) if (deps->pending_flush_length++ > MAX_PENDING_LIST_LENGTH)
flush_pending_lists (deps, insn, 0); flush_pending_lists (deps, insn, true, true);
else else
deps->last_pending_memory_flush deps->last_pending_memory_flush
= alloc_INSN_LIST (insn, deps->last_pending_memory_flush); = alloc_INSN_LIST (insn, deps->last_pending_memory_flush);
...@@ -1297,7 +1211,6 @@ sched_analyze (deps, head, tail) ...@@ -1297,7 +1211,6 @@ sched_analyze (deps, head, tail)
} }
else if (GET_CODE (insn) == CALL_INSN) else if (GET_CODE (insn) == CALL_INSN)
{ {
rtx x;
int i; int i;
/* Clear out stale SCHED_GROUP_P. */ /* Clear out stale SCHED_GROUP_P. */
...@@ -1308,59 +1221,35 @@ sched_analyze (deps, head, tail) ...@@ -1308,59 +1221,35 @@ sched_analyze (deps, head, tail)
/* Clear out the stale LOG_LINKS from flow. */ /* Clear out the stale LOG_LINKS from flow. */
free_INSN_LIST_list (&LOG_LINKS (insn)); free_INSN_LIST_list (&LOG_LINKS (insn));
/* Any instruction using a hard register which may get clobbered
by a call needs to be marked as dependent on this call.
This prevents a use of a hard return reg from being moved
past a void call (i.e. it does not explicitly set the hard
return reg). */
/* If this call has REG_SETJMP, then assume that
all registers, not just hard registers, may be clobbered by this
call. */
/* Insn, being a CALL_INSN, magically depends on
`last_function_call' already. */
if (find_reg_note (insn, REG_SETJMP, NULL)) if (find_reg_note (insn, REG_SETJMP, NULL))
{ {
for (i = 0; i < deps->max_reg; i++) /* This is setjmp. Assume that all registers, not just
{ hard registers, may be clobbered by this call. */
struct deps_reg *reg_last = &deps->reg_last[i]; reg_pending_barrier = true;
for (u = reg_last->uses; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
for (u = reg_last->sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
for (u = reg_last->clobbers; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), 0);
free_INSN_LIST_list (&reg_last->uses);
}
reg_pending_sets_all = 1;
} }
else else
{ {
/* A call may read and modify global register variables.
Other call-clobbered hard regs may be clobbered. We
don't know what set of fixed registers might be used
by the function. It is certain that the stack pointer
is among them, but be conservative. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (call_used_regs[i] || global_regs[i]) if (global_regs[i])
{ {
for (u = deps->reg_last[i].uses; u; u = XEXP (u, 1)) SET_REGNO_REG_SET (reg_pending_sets, i);
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI); SET_REGNO_REG_SET (reg_pending_uses, i);
for (u = deps->reg_last[i].sets; u; u = XEXP (u, 1))
add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
SET_REGNO_REG_SET (reg_pending_clobbers, i);
} }
else if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
SET_REGNO_REG_SET (reg_pending_clobbers, i);
else if (fixed_regs[i])
SET_REGNO_REG_SET (reg_pending_uses, i);
} }
/* For each insn which shouldn't cross a call, add a dependence /* For each insn which shouldn't cross a call, add a dependence
between that insn and this call insn. */ between that insn and this call insn. */
x = LOG_LINKS (deps->sched_before_next_call); add_dependence_list_and_free (insn, &deps->sched_before_next_call,
while (x) REG_DEP_ANTI);
{
add_dependence (insn, XEXP (x, 0), REG_DEP_ANTI);
x = XEXP (x, 1);
}
free_INSN_LIST_list (&LOG_LINKS (deps->sched_before_next_call));
sched_analyze_insn (deps, PATTERN (insn), insn, loop_notes); sched_analyze_insn (deps, PATTERN (insn), insn, loop_notes);
loop_notes = 0; loop_notes = 0;
...@@ -1369,19 +1258,16 @@ sched_analyze (deps, head, tail) ...@@ -1369,19 +1258,16 @@ sched_analyze (deps, head, tail)
all pending reads and writes, and start new dependencies starting all pending reads and writes, and start new dependencies starting
from here. But only flush writes for constant calls (which may from here. But only flush writes for constant calls (which may
be passed a pointer to something we haven't written yet). */ be passed a pointer to something we haven't written yet). */
flush_pending_lists (deps, insn, CONST_OR_PURE_CALL_P (insn)); flush_pending_lists (deps, insn, true, !CONST_OR_PURE_CALL_P (insn));
/* Depend this function call (actually, the user of this /* Remember the last function call for limiting lifetimes. */
function call) on all hard register clobberage. */
/* last_function_call is now a list of insns. */
free_INSN_LIST_list (&deps->last_function_call); free_INSN_LIST_list (&deps->last_function_call);
deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX); deps->last_function_call = alloc_INSN_LIST (insn, NULL_RTX);
/* Before reload, begin a post-call group, so as to keep the /* Before reload, begin a post-call group, so as to keep the
lifetimes of hard registers correct. */ lifetimes of hard registers correct. */
if (! reload_completed) if (! reload_completed)
deps->in_post_call_group_p = 1; deps->in_post_call_group_p = true;
} }
/* See comments on reemit_notes as to why we do this. /* See comments on reemit_notes as to why we do this.
...@@ -1513,12 +1399,8 @@ init_deps (deps) ...@@ -1513,12 +1399,8 @@ init_deps (deps)
deps->pending_flush_length = 0; deps->pending_flush_length = 0;
deps->last_pending_memory_flush = 0; deps->last_pending_memory_flush = 0;
deps->last_function_call = 0; deps->last_function_call = 0;
deps->in_post_call_group_p = 0; deps->sched_before_next_call = 0;
deps->in_post_call_group_p = false;
deps->sched_before_next_call
= gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX,
NULL_RTX, 0, NULL_RTX, NULL_RTX);
LOG_LINKS (deps->sched_before_next_call) = 0;
} }
/* Free insn lists found in DEPS. */ /* Free insn lists found in DEPS. */
...@@ -1529,6 +1411,12 @@ free_deps (deps) ...@@ -1529,6 +1411,12 @@ free_deps (deps)
{ {
int i; int i;
free_INSN_LIST_list (&deps->pending_read_insns);
free_EXPR_LIST_list (&deps->pending_read_mems);
free_INSN_LIST_list (&deps->pending_write_insns);
free_EXPR_LIST_list (&deps->pending_write_mems);
free_INSN_LIST_list (&deps->last_pending_memory_flush);
/* Without the EXECUTE_IF_SET, this loop is executed max_reg * nr_regions /* Without the EXECUTE_IF_SET, this loop is executed max_reg * nr_regions
times. For a test case with 42000 regs and 8000 small basic blocks, times. For a test case with 42000 regs and 8000 small basic blocks,
this loop accounted for nearly 60% (84 sec) of the total -O2 runtime. */ this loop accounted for nearly 60% (84 sec) of the total -O2 runtime. */
...@@ -1542,7 +1430,6 @@ free_deps (deps) ...@@ -1542,7 +1430,6 @@ free_deps (deps)
CLEAR_REG_SET (&deps->reg_last_in_use); CLEAR_REG_SET (&deps->reg_last_in_use);
free (deps->reg_last); free (deps->reg_last);
deps->reg_last = NULL;
} }
/* If it is profitable to use them, initialize caches for tracking /* If it is profitable to use them, initialize caches for tracking
...@@ -1602,7 +1489,8 @@ init_deps_global () ...@@ -1602,7 +1489,8 @@ init_deps_global ()
{ {
reg_pending_sets = INITIALIZE_REG_SET (reg_pending_sets_head); reg_pending_sets = INITIALIZE_REG_SET (reg_pending_sets_head);
reg_pending_clobbers = INITIALIZE_REG_SET (reg_pending_clobbers_head); reg_pending_clobbers = INITIALIZE_REG_SET (reg_pending_clobbers_head);
reg_pending_sets_all = 0; reg_pending_uses = INITIALIZE_REG_SET (reg_pending_uses_head);
reg_pending_barrier = false;
} }
/* Free everything used by the dependency analysis code. */ /* Free everything used by the dependency analysis code. */
...@@ -1612,4 +1500,5 @@ finish_deps_global () ...@@ -1612,4 +1500,5 @@ finish_deps_global ()
{ {
FREE_REG_SET (reg_pending_sets); FREE_REG_SET (reg_pending_sets);
FREE_REG_SET (reg_pending_clobbers); FREE_REG_SET (reg_pending_clobbers);
FREE_REG_SET (reg_pending_uses);
} }
...@@ -68,19 +68,20 @@ struct deps ...@@ -68,19 +68,20 @@ struct deps
too large. */ too large. */
rtx last_pending_memory_flush; rtx last_pending_memory_flush;
/* The last function call we have seen. All hard regs, and, of course, /* A list of the last function calls we have seen. We use a list to
the last function call, must depend on this. */ represent last function calls from multiple predecessor blocks.
Used to prevent register lifetimes from expanding unnecessarily. */
rtx last_function_call; rtx last_function_call;
/* A list of insns which use a pseudo register that does not already
cross a call. We create dependencies between each of those insn
and the next call insn, to ensure that they won't cross a call after
scheduling is done. */
rtx sched_before_next_call;
/* Used to keep post-call psuedo/hard reg movements together with /* Used to keep post-call psuedo/hard reg movements together with
the call. */ the call. */
int in_post_call_group_p; bool in_post_call_group_p;
/* The LOG_LINKS field of this is a list of insns which use a pseudo
register that does not already cross a call. We create
dependencies between each of those insn and the next call insn,
to ensure that they won't cross a call after scheduling is done. */
rtx sched_before_next_call;
/* The maximum register number for the following arrays. Before reload /* The maximum register number for the following arrays. Before reload
this is max_reg_num; after reload it is FIRST_PSEUDO_REGISTER. */ this is max_reg_num; after reload it is FIRST_PSEUDO_REGISTER. */
...@@ -274,7 +275,6 @@ extern void free_deps PARAMS ((struct deps *)); ...@@ -274,7 +275,6 @@ extern void free_deps PARAMS ((struct deps *));
extern void init_deps_global PARAMS ((void)); extern void init_deps_global PARAMS ((void));
extern void finish_deps_global PARAMS ((void)); extern void finish_deps_global PARAMS ((void));
extern void compute_forward_dependences PARAMS ((rtx, rtx)); extern void compute_forward_dependences PARAMS ((rtx, rtx));
extern int find_insn_mem_list PARAMS ((rtx, rtx, rtx, rtx));
extern rtx find_insn_list PARAMS ((rtx, rtx)); extern rtx find_insn_list PARAMS ((rtx, rtx));
extern void init_dependency_caches PARAMS ((int)); extern void init_dependency_caches PARAMS ((int));
extern void free_dependency_caches PARAMS ((void)); extern void free_dependency_caches PARAMS ((void));
......
...@@ -300,6 +300,8 @@ void debug_dependencies PARAMS ((void)); ...@@ -300,6 +300,8 @@ void debug_dependencies PARAMS ((void));
static void init_regions PARAMS ((void)); static void init_regions PARAMS ((void));
static void schedule_region PARAMS ((int)); static void schedule_region PARAMS ((int));
static rtx concat_INSN_LIST PARAMS ((rtx, rtx));
static void concat_insn_mem_list PARAMS ((rtx, rtx, rtx *, rtx *));
static void propagate_deps PARAMS ((int, struct deps *)); static void propagate_deps PARAMS ((int, struct deps *));
static void free_pending_lists PARAMS ((void)); static void free_pending_lists PARAMS ((void));
...@@ -2299,8 +2301,7 @@ add_branch_dependences (head, tail) ...@@ -2299,8 +2301,7 @@ add_branch_dependences (head, tail)
{ {
if (GET_CODE (insn) != NOTE) if (GET_CODE (insn) != NOTE)
{ {
if (last != 0 if (last != 0 && !find_insn_list (insn, LOG_LINKS (last)))
&& !find_insn_list (insn, LOG_LINKS (last)))
{ {
add_dependence (last, insn, REG_DEP_ANTI); add_dependence (last, insn, REG_DEP_ANTI);
INSN_REF_COUNT (insn)++; INSN_REF_COUNT (insn)++;
...@@ -2356,37 +2357,57 @@ add_branch_dependences (head, tail) ...@@ -2356,37 +2357,57 @@ add_branch_dependences (head, tail)
static struct deps *bb_deps; static struct deps *bb_deps;
/* Duplicate the INSN_LIST elements of COPY and prepend them to OLD. */
static rtx
concat_INSN_LIST (copy, old)
rtx copy, old;
{
rtx new = old;
for (; copy ; copy = XEXP (copy, 1))
new = alloc_INSN_LIST (XEXP (copy, 0), new);
return new;
}
static void
concat_insn_mem_list (copy_insns, copy_mems, old_insns_p, old_mems_p)
rtx copy_insns, copy_mems;
rtx *old_insns_p, *old_mems_p;
{
rtx new_insns = *old_insns_p;
rtx new_mems = *old_mems_p;
while (copy_insns)
{
new_insns = alloc_INSN_LIST (XEXP (copy_insns, 0), new_insns);
new_mems = alloc_EXPR_LIST (VOIDmode, XEXP (copy_mems, 0), new_mems);
copy_insns = XEXP (copy_insns, 1);
copy_mems = XEXP (copy_mems, 1);
}
*old_insns_p = new_insns;
*old_mems_p = new_mems;
}
/* After computing the dependencies for block BB, propagate the dependencies /* After computing the dependencies for block BB, propagate the dependencies
found in TMP_DEPS to the successors of the block. */ found in TMP_DEPS to the successors of the block. */
static void static void
propagate_deps (bb, tmp_deps) propagate_deps (bb, pred_deps)
int bb; int bb;
struct deps *tmp_deps; struct deps *pred_deps;
{ {
int b = BB_TO_BLOCK (bb); int b = BB_TO_BLOCK (bb);
int e, first_edge; int e, first_edge;
int reg;
rtx link_insn, link_mem;
rtx u;
/* These lists should point to the right place, for correct
freeing later. */
bb_deps[bb].pending_read_insns = tmp_deps->pending_read_insns;
bb_deps[bb].pending_read_mems = tmp_deps->pending_read_mems;
bb_deps[bb].pending_write_insns = tmp_deps->pending_write_insns;
bb_deps[bb].pending_write_mems = tmp_deps->pending_write_mems;
/* bb's structures are inherited by its successors. */ /* bb's structures are inherited by its successors. */
first_edge = e = OUT_EDGES (b); first_edge = e = OUT_EDGES (b);
if (e <= 0) if (e > 0)
return;
do do
{ {
rtx x;
int b_succ = TO_BLOCK (e); int b_succ = TO_BLOCK (e);
int bb_succ = BLOCK_TO_BB (b_succ); int bb_succ = BLOCK_TO_BB (b_succ);
struct deps *succ_deps = bb_deps + bb_succ; struct deps *succ_deps = bb_deps + bb_succ;
int reg;
/* Only bbs "below" bb, in the same region, are interesting. */ /* Only bbs "below" bb, in the same region, are interesting. */
if (CONTAINING_RGN (b) != CONTAINING_RGN (b_succ) if (CONTAINING_RGN (b) != CONTAINING_RGN (b_succ)
...@@ -2397,84 +2418,61 @@ propagate_deps (bb, tmp_deps) ...@@ -2397,84 +2418,61 @@ propagate_deps (bb, tmp_deps)
} }
/* The reg_last lists are inherited by bb_succ. */ /* The reg_last lists are inherited by bb_succ. */
EXECUTE_IF_SET_IN_REG_SET (&tmp_deps->reg_last_in_use, 0, reg, EXECUTE_IF_SET_IN_REG_SET (&pred_deps->reg_last_in_use, 0, reg,
{ {
struct deps_reg *tmp_deps_reg = &tmp_deps->reg_last[reg]; struct deps_reg *pred_rl = &pred_deps->reg_last[reg];
struct deps_reg *succ_deps_reg = &succ_deps->reg_last[reg]; struct deps_reg *succ_rl = &succ_deps->reg_last[reg];
for (u = tmp_deps_reg->uses; u; u = XEXP (u, 1)) succ_rl->uses = concat_INSN_LIST (pred_rl->uses, succ_rl->uses);
if (! find_insn_list (XEXP (u, 0), succ_deps_reg->uses)) succ_rl->sets = concat_INSN_LIST (pred_rl->sets, succ_rl->sets);
succ_deps_reg->uses succ_rl->clobbers = concat_INSN_LIST (pred_rl->clobbers,
= alloc_INSN_LIST (XEXP (u, 0), succ_deps_reg->uses); succ_rl->clobbers);
for (u = tmp_deps_reg->sets; u; u = XEXP (u, 1))
if (! find_insn_list (XEXP (u, 0), succ_deps_reg->sets))
succ_deps_reg->sets
= alloc_INSN_LIST (XEXP (u, 0), succ_deps_reg->sets);
for (u = tmp_deps_reg->clobbers; u; u = XEXP (u, 1))
if (! find_insn_list (XEXP (u, 0), succ_deps_reg->clobbers))
succ_deps_reg->clobbers
= alloc_INSN_LIST (XEXP (u, 0), succ_deps_reg->clobbers);
}); });
IOR_REG_SET (&succ_deps->reg_last_in_use, &tmp_deps->reg_last_in_use); IOR_REG_SET (&succ_deps->reg_last_in_use, &pred_deps->reg_last_in_use);
/* Mem read/write lists are inherited by bb_succ. */ /* Mem read/write lists are inherited by bb_succ. */
link_insn = tmp_deps->pending_read_insns; concat_insn_mem_list (pred_deps->pending_read_insns,
link_mem = tmp_deps->pending_read_mems; pred_deps->pending_read_mems,
while (link_insn) &succ_deps->pending_read_insns,
{ &succ_deps->pending_read_mems);
if (!(find_insn_mem_list (XEXP (link_insn, 0), concat_insn_mem_list (pred_deps->pending_write_insns,
XEXP (link_mem, 0), pred_deps->pending_write_mems,
succ_deps->pending_read_insns,
succ_deps->pending_read_mems)))
add_insn_mem_dependence (succ_deps, &succ_deps->pending_read_insns,
&succ_deps->pending_read_mems,
XEXP (link_insn, 0), XEXP (link_mem, 0));
link_insn = XEXP (link_insn, 1);
link_mem = XEXP (link_mem, 1);
}
link_insn = tmp_deps->pending_write_insns;
link_mem = tmp_deps->pending_write_mems;
while (link_insn)
{
if (!(find_insn_mem_list (XEXP (link_insn, 0),
XEXP (link_mem, 0),
succ_deps->pending_write_insns,
succ_deps->pending_write_mems)))
add_insn_mem_dependence (succ_deps,
&succ_deps->pending_write_insns, &succ_deps->pending_write_insns,
&succ_deps->pending_write_mems, &succ_deps->pending_write_mems);
XEXP (link_insn, 0), XEXP (link_mem, 0));
link_insn = XEXP (link_insn, 1); succ_deps->last_pending_memory_flush
link_mem = XEXP (link_mem, 1); = concat_INSN_LIST (pred_deps->last_pending_memory_flush,
} succ_deps->last_pending_memory_flush);
succ_deps->pending_lists_length += pred_deps->pending_lists_length;
succ_deps->pending_flush_length += pred_deps->pending_flush_length;
/* last_function_call is inherited by bb_succ. */ /* last_function_call is inherited by bb_succ. */
for (u = tmp_deps->last_function_call; u; u = XEXP (u, 1))
if (! find_insn_list (XEXP (u, 0), succ_deps->last_function_call))
succ_deps->last_function_call succ_deps->last_function_call
= alloc_INSN_LIST (XEXP (u, 0), succ_deps->last_function_call); = concat_INSN_LIST (pred_deps->last_function_call,
succ_deps->last_function_call);
/* last_pending_memory_flush is inherited by bb_succ. */
for (u = tmp_deps->last_pending_memory_flush; u; u = XEXP (u, 1))
if (! find_insn_list (XEXP (u, 0),
succ_deps->last_pending_memory_flush))
succ_deps->last_pending_memory_flush
= alloc_INSN_LIST (XEXP (u, 0),
succ_deps->last_pending_memory_flush);
/* sched_before_next_call is inherited by bb_succ. */ /* sched_before_next_call is inherited by bb_succ. */
x = LOG_LINKS (tmp_deps->sched_before_next_call); succ_deps->sched_before_next_call
for (; x; x = XEXP (x, 1)) = concat_INSN_LIST (pred_deps->sched_before_next_call,
add_dependence (succ_deps->sched_before_next_call, succ_deps->sched_before_next_call);
XEXP (x, 0), REG_DEP_ANTI);
e = NEXT_OUT (e); e = NEXT_OUT (e);
} }
while (e != first_edge); while (e != first_edge);
/* These lists should point to the right place, for correct
freeing later. */
bb_deps[bb].pending_read_insns = pred_deps->pending_read_insns;
bb_deps[bb].pending_read_mems = pred_deps->pending_read_mems;
bb_deps[bb].pending_write_insns = pred_deps->pending_write_insns;
bb_deps[bb].pending_write_mems = pred_deps->pending_write_mems;
/* Can't allow these to be freed twice. */
pred_deps->pending_read_insns = 0;
pred_deps->pending_read_mems = 0;
pred_deps->pending_write_insns = 0;
pred_deps->pending_write_mems = 0;
} }
/* Compute backward dependences inside bb. In a multiple blocks region: /* Compute backward dependences inside bb. In a multiple blocks region:
......
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