Flow fixes for cond_exec on ia64

From-SVN: r38380
This commit is contained in:
Bernd Schmidt 2000-12-19 16:52:23 +00:00 committed by Bernd Schmidt
parent 6a69653af2
commit 288c2c9e63
2 changed files with 244 additions and 102 deletions

View File

@ -1,3 +1,16 @@
2000-12-19 Bernd Schmidt <bernds@redhat.co.uk>
* flow.c (ior_reg_cond, nand_reg_cond, not_reg_cond): Rewrite
to use different representation. All callers changed.
(and_reg_cond): Renamed from nand_reg_cond; caller changed.
(init_propagate_block_info): Don't test flags to determine
whether to compute conditional lifetimes.
Adjust code for new representation of conditional lifetimes.
(mark_regno_cond_dead): Similar adjustment.
(free_reg_cond_life_info): Similar adjustment.
(elim_reg_cond): New function.
(flush_reg_cond_1): Use it.
2000-12-19 Catherine Moore <clm@redhat.com>
* reload1.c (reload_combine): Take multi-hard-regs into account

View File

@ -392,9 +392,10 @@ static void free_reg_cond_life_info PARAMS ((splay_tree_value));
static int flush_reg_cond_reg_1 PARAMS ((splay_tree_node, void *));
static void flush_reg_cond_reg PARAMS ((struct propagate_block_info *,
int));
static rtx ior_reg_cond PARAMS ((rtx, rtx));
static rtx elim_reg_cond PARAMS ((rtx, unsigned int));
static rtx ior_reg_cond PARAMS ((rtx, rtx, int));
static rtx not_reg_cond PARAMS ((rtx));
static rtx nand_reg_cond PARAMS ((rtx, rtx));
static rtx and_reg_cond PARAMS ((rtx, rtx, int));
#endif
#ifdef AUTO_INC_DEC
static void attempt_auto_inc PARAMS ((struct propagate_block_info *,
@ -3894,8 +3895,7 @@ init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
/* If this block ends in a conditional branch, for each register live
from one side of the branch and not the other, record the register
as conditionally dead. */
if ((flags & (PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE))
&& GET_CODE (bb->end) == JUMP_INSN
if (GET_CODE (bb->end) == JUMP_INSN
&& any_condjump_p (bb->end))
{
regset_head diff_head;
@ -3969,7 +3969,7 @@ init_propagate_block_info (bb, live, local_set, cond_local_set, flags)
cond = cond_false;
else
cond = cond_true;
rcli->condition = alloc_EXPR_LIST (0, cond, NULL_RTX);
rcli->condition = cond;
splay_tree_insert (pbi->reg_cond_dead, i,
(splay_tree_value) rcli);
@ -4898,7 +4898,7 @@ mark_regno_cond_dead (pbi, regno, cond)
Record the current condition as the condition under
which it is dead. */
rcli = (struct reg_cond_life_info *) xmalloc (sizeof (*rcli));
rcli->condition = alloc_EXPR_LIST (0, cond, NULL_RTX);
rcli->condition = cond;
splay_tree_insert (pbi->reg_cond_dead, regno,
(splay_tree_value) rcli);
@ -4913,7 +4913,7 @@ mark_regno_cond_dead (pbi, regno, cond)
Add the new condition to the old. */
rcli = (struct reg_cond_life_info *) node->value;
ncond = rcli->condition;
ncond = ior_reg_cond (ncond, cond);
ncond = ior_reg_cond (ncond, cond, 1);
/* If the register is now unconditionally dead,
remove the entry in the splay_tree. */
@ -4941,7 +4941,6 @@ free_reg_cond_life_info (value)
splay_tree_value value;
{
struct reg_cond_life_info *rcli = (struct reg_cond_life_info *) value;
free_EXPR_LIST_list (&rcli->condition);
free (rcli);
}
@ -4955,36 +4954,26 @@ flush_reg_cond_reg_1 (node, data)
struct reg_cond_life_info *rcli;
int *xdata = (int *) data;
unsigned int regno = xdata[0];
rtx c, *prev;
/* Don't need to search if last flushed value was farther on in
the in-order traversal. */
if (xdata[1] >= (int) node->key)
return 0;
/* Splice out portions of the expression that refer to regno. */
rcli = (struct reg_cond_life_info *) node->value;
c = *(prev = &rcli->condition);
while (c)
{
if (regno == REGNO (XEXP (XEXP (c, 0), 0)))
{
rtx next = XEXP (c, 1);
free_EXPR_LIST_node (c);
c = *prev = next;
}
else
c = *(prev = &XEXP (c, 1));
}
rcli->condition = elim_reg_cond (rcli->condition, regno);
/* If the entire condition is now NULL, signal the node to be removed. */
if (! rcli->condition)
/* If the entire condition is now false, signal the node to be removed. */
if (rcli->condition == const0_rtx)
{
xdata[1] = node->key;
return -1;
}
else
return 0;
else if (rcli->condition == const1_rtx)
abort ();
return 0;
}
/* Flush all (sub) expressions referring to REGNO from REG_COND_LIVE. */
@ -5005,47 +4994,90 @@ flush_reg_cond_reg (pbi, regno)
CLEAR_REGNO_REG_SET (pbi->reg_cond_reg, regno);
}
/* Logical arithmetic on predicate conditions. IOR, NOT and NAND.
We actually use EXPR_LIST to chain the sub-expressions together
instead of IOR because it's easier to manipulate and we have
the lists.c functions to reuse nodes.
Return a new rtl expression as appropriate. */
/* Logical arithmetic on predicate conditions. IOR, NOT and AND.
For ior/and, the ADD flag determines whether we want to add the new
condition X to the old one unconditionally. If it is zero, we will
only return a new expression if X allows us to simplify part of
OLD, otherwise we return OLD unchanged to the caller.
If ADD is nonzero, we will return a new condition in all cases. The
toplevel caller of one of these functions should always pass 1 for
ADD. */
static rtx
ior_reg_cond (old, x)
ior_reg_cond (old, x, add)
rtx old, x;
int add;
{
enum rtx_code x_code;
rtx x_reg;
rtx c;
rtx op0, op1;
/* We expect these conditions to be of the form (eq reg 0). */
x_code = GET_CODE (x);
if (GET_RTX_CLASS (x_code) != '<'
|| GET_CODE (x_reg = XEXP (x, 0)) != REG
|| XEXP (x, 1) != const0_rtx)
abort ();
/* Search the expression for an existing sub-expression of X_REG. */
for (c = old; c; c = XEXP (c, 1))
switch (GET_CODE (old))
{
rtx y = XEXP (c, 0);
if (REGNO (XEXP (y, 0)) == REGNO (x_reg))
case IOR:
op0 = ior_reg_cond (XEXP (old, 0), x, 0);
op1 = ior_reg_cond (XEXP (old, 1), x, 0);
if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
{
/* If we find X already present in OLD, we need do nothing. */
if (GET_CODE (y) == x_code)
return old;
/* If we find X being a compliment of a condition in OLD,
then the entire condition is true. */
if (GET_CODE (y) == reverse_condition (x_code))
if (op0 == const0_rtx)
return op1;
if (op1 == const0_rtx)
return op0;
if (op0 == const1_rtx || op1 == const1_rtx)
return const1_rtx;
if (op0 == XEXP (old, 0))
op0 = gen_rtx_IOR (0, op0, x);
else
op1 = gen_rtx_IOR (0, op1, x);
return gen_rtx_IOR (0, op0, op1);
}
}
if (! add)
return old;
return gen_rtx_IOR (0, old, x);
/* Otherwise just add to the chain. */
return alloc_EXPR_LIST (0, x, old);
case AND:
op0 = ior_reg_cond (XEXP (old, 0), x, 0);
op1 = ior_reg_cond (XEXP (old, 1), x, 0);
if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
{
if (op0 == const1_rtx)
return op1;
if (op1 == const1_rtx)
return op0;
if (op0 == const0_rtx || op1 == const0_rtx)
return const0_rtx;
if (op0 == XEXP (old, 0))
op0 = gen_rtx_IOR (0, op0, x);
else
op1 = gen_rtx_IOR (0, op1, x);
return gen_rtx_AND (0, op0, op1);
}
if (! add)
return old;
return gen_rtx_IOR (0, old, x);
case NOT:
op0 = and_reg_cond (XEXP (old, 0), not_reg_cond (x), 0);
if (op0 != XEXP (old, 0))
return not_reg_cond (op0);
if (! add)
return old;
return gen_rtx_IOR (0, old, x);
case EQ:
case NE:
if ((GET_CODE (x) == EQ || GET_CODE (x) == NE)
&& GET_CODE (x) != GET_CODE (old)
&& REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
return const1_rtx;
if (GET_CODE (x) == GET_CODE (old)
&& REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
return old;
if (! add)
return old;
return gen_rtx_IOR (0, old, x);
default:
abort ();
}
}
static rtx
@ -5053,63 +5085,160 @@ not_reg_cond (x)
rtx x;
{
enum rtx_code x_code;
rtx x_reg;
/* We expect these conditions to be of the form (eq reg 0). */
if (x == const0_rtx)
return const1_rtx;
else if (x == const1_rtx)
return const0_rtx;
x_code = GET_CODE (x);
if (GET_RTX_CLASS (x_code) != '<'
|| GET_CODE (x_reg = XEXP (x, 0)) != REG
|| XEXP (x, 1) != const0_rtx)
abort ();
if (x_code == NOT)
return XEXP (x, 0);
if (GET_RTX_CLASS (x_code) == '<'
&& GET_CODE (XEXP (x, 0)) == REG)
{
if (XEXP (x, 1) != const0_rtx)
abort ();
return alloc_EXPR_LIST (0, gen_rtx_fmt_ee (reverse_condition (x_code),
VOIDmode, x_reg, const0_rtx),
NULL_RTX);
return gen_rtx_fmt_ee (reverse_condition (x_code),
VOIDmode, XEXP (x, 0), const0_rtx);
}
return gen_rtx_NOT (0, x);
}
static rtx
nand_reg_cond (old, x)
and_reg_cond (old, x, add)
rtx old, x;
int add;
{
enum rtx_code x_code;
rtx x_reg;
rtx c, *prev;
rtx op0, op1;
/* We expect these conditions to be of the form (eq reg 0). */
x_code = GET_CODE (x);
if (GET_RTX_CLASS (x_code) != '<'
|| GET_CODE (x_reg = XEXP (x, 0)) != REG
|| XEXP (x, 1) != const0_rtx)
abort ();
/* Search the expression for an existing sub-expression of X_REG. */
for (c = *(prev = &old); c; c = *(prev = &XEXP (c, 1)))
switch (GET_CODE (old))
{
rtx y = XEXP (c, 0);
if (REGNO (XEXP (y, 0)) == REGNO (x_reg))
case IOR:
op0 = and_reg_cond (XEXP (old, 0), x, 0);
op1 = and_reg_cond (XEXP (old, 1), x, 0);
if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
{
/* If we find X already present in OLD, then we need to
splice it out. */
if (GET_CODE (y) == x_code)
{
*prev = XEXP (c, 1);
free_EXPR_LIST_node (c);
return old ? old : const0_rtx;
}
/* If we find X being a compliment of a condition in OLD,
then we need do nothing. */
if (GET_CODE (y) == reverse_condition (x_code))
return old;
if (op0 == const0_rtx)
return op1;
if (op1 == const0_rtx)
return op0;
if (op0 == const1_rtx || op1 == const1_rtx)
return const1_rtx;
if (op0 == XEXP (old, 0))
op0 = gen_rtx_AND (0, op0, x);
else
op1 = gen_rtx_AND (0, op1, x);
return gen_rtx_IOR (0, op0, op1);
}
}
if (! add)
return old;
return gen_rtx_AND (0, old, x);
/* Otherwise, by implication, the register in question is now live for
the inverse of the condition X. */
return alloc_EXPR_LIST (0, gen_rtx_fmt_ee (reverse_condition (x_code),
VOIDmode, x_reg, const0_rtx),
old);
case AND:
op0 = and_reg_cond (XEXP (old, 0), x, 0);
op1 = and_reg_cond (XEXP (old, 1), x, 0);
if (op0 != XEXP (old, 0) || op1 != XEXP (old, 1))
{
if (op0 == const1_rtx)
return op1;
if (op1 == const1_rtx)
return op0;
if (op0 == const0_rtx || op1 == const0_rtx)
return const0_rtx;
if (op0 == XEXP (old, 0))
op0 = gen_rtx_AND (0, op0, x);
else
op1 = gen_rtx_AND (0, op1, x);
return gen_rtx_AND (0, op0, op1);
}
if (! add)
return old;
return gen_rtx_AND (0, old, x);
case NOT:
op0 = ior_reg_cond (XEXP (old, 0), not_reg_cond (x), 0);
if (op0 != XEXP (old, 0))
return not_reg_cond (op0);
if (! add)
return old;
return gen_rtx_AND (0, old, x);
case EQ:
case NE:
if ((GET_CODE (x) == EQ || GET_CODE (x) == NE)
&& GET_CODE (x) != GET_CODE (old)
&& REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
return const0_rtx;
if (GET_CODE (x) == GET_CODE (old)
&& REGNO (XEXP (x, 0)) == REGNO (XEXP (old, 0)))
return old;
if (! add)
return old;
return gen_rtx_AND (0, old, x);
default:
abort ();
}
}
/* Given a condition X, remove references to reg REGNO and return the
new condition. The removal will be done so that all conditions
involving REGNO are considered to evaluate to false. This function
is used when the value of REGNO changes. */
static rtx
elim_reg_cond (x, regno)
rtx x;
unsigned int regno;
{
rtx op0, op1;
switch (GET_CODE (x))
{
case AND:
op0 = elim_reg_cond (XEXP (x, 0), regno);
op1 = elim_reg_cond (XEXP (x, 1), regno);
if (op0 == const0_rtx || op1 == const0_rtx)
return const0_rtx;
if (op0 == const1_rtx)
return op1;
if (op1 == const1_rtx)
return op0;
if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
return x;
return gen_rtx_AND (0, op0, op1);
case IOR:
op0 = elim_reg_cond (XEXP (x, 0), regno);
op1 = elim_reg_cond (XEXP (x, 1), regno);
if (op0 == const1_rtx || op1 == const1_rtx)
return const1_rtx;
if (op0 == const0_rtx)
return op1;
if (op1 == const0_rtx)
return op0;
if (op0 == XEXP (x, 0) && op1 == XEXP (x, 1))
return x;
return gen_rtx_IOR (0, op0, op1);
case NOT:
op0 = elim_reg_cond (XEXP (x, 0), regno);
if (op0 == const0_rtx)
return const1_rtx;
if (op0 == const1_rtx)
return const0_rtx;
if (op0 != XEXP (x, 0))
return not_reg_cond (op0);
return x;
case EQ:
case NE:
if (REGNO (XEXP (x, 0)) == regno)
return const0_rtx;
return x;
default:
abort ();
}
}
#endif /* HAVE_conditional_execution */
@ -5513,7 +5642,7 @@ mark_used_reg (pbi, reg, cond, insn)
Subtract the new life cond from the old death cond. */
rcli = (struct reg_cond_life_info *) node->value;
ncond = rcli->condition;
ncond = nand_reg_cond (ncond, cond);
ncond = and_reg_cond (ncond, not_reg_cond (cond), 1);
/* If the register is now unconditionally live, remove the
entry in the splay_tree. */