parent
3a6e78aded
commit
42495ca044
|
@ -1471,17 +1471,31 @@ try_combine (i3, i2, i1)
|
|||
&& asm_noperands (newpat) < 0)
|
||||
{
|
||||
rtx m_split, *split;
|
||||
rtx ni2dest = i2dest;
|
||||
|
||||
/* See if the MD file can split NEWPAT. If it can't, see if letting it
|
||||
use I2DEST as a scratch register will help. */
|
||||
use I2DEST as a scratch register will help. In the latter case,
|
||||
convert I2DEST to the mode of the source of NEWPAT if we can. */
|
||||
|
||||
m_split = split_insns (newpat, i3);
|
||||
if (m_split == 0)
|
||||
m_split = split_insns (gen_rtx (PARALLEL, VOIDmode,
|
||||
gen_rtvec (2, newpat,
|
||||
gen_rtx (CLOBBER, VOIDmode,
|
||||
i2dest))),
|
||||
i3);
|
||||
{
|
||||
/* If I2DEST is a hard register or the only use of a pseudo,
|
||||
we can change its mode. */
|
||||
if (GET_MODE (SET_DEST (newpat)) != GET_MODE (i2dest)
|
||||
&& (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
|
||||
|| (reg_n_sets[REGNO (i2dest)] == 1 && ! added_sets_2
|
||||
&& ! REG_USERVAR_P (i2dest))))
|
||||
ni2dest = gen_rtx (REG, GET_MODE (SET_DEST (newpat)),
|
||||
REGNO (i2dest));
|
||||
|
||||
m_split = split_insns (gen_rtx (PARALLEL, VOIDmode,
|
||||
gen_rtvec (2, newpat,
|
||||
gen_rtx (CLOBBER,
|
||||
VOIDmode,
|
||||
ni2dest))),
|
||||
i3);
|
||||
}
|
||||
|
||||
if (m_split && GET_CODE (m_split) == SEQUENCE
|
||||
&& XVECLEN (m_split, 0) == 2
|
||||
|
@ -1492,6 +1506,13 @@ try_combine (i3, i2, i1)
|
|||
newi2pat = PATTERN (XVECEXP (m_split, 0, 0));
|
||||
newpat = PATTERN (XVECEXP (m_split, 0, 1));
|
||||
|
||||
/* In case we changed the mode of I2DEST, replace it in the
|
||||
pseudo-register table here. We can't do it above in case this
|
||||
code doesn't get executed and we do a split the other way. */
|
||||
|
||||
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
|
||||
SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
|
||||
|
||||
i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
|
||||
if (i2_code_number >= 0)
|
||||
insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
|
||||
|
@ -2945,6 +2966,18 @@ subst (x, from, to, in_dest, unique_copy)
|
|||
- INTVAL (XEXP (XEXP (x, 1), 1)) - 1);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
/* If we are adding two things that have no bits in common, convert
|
||||
the addition into an IOR. This will often be further simplified,
|
||||
for example in cases like ((a & 1) + (a & 2)), which can
|
||||
become a & 3. */
|
||||
|
||||
if ((significant_bits (XEXP (x, 0), mode)
|
||||
& significant_bits (XEXP (x, 1), mode)) == 0)
|
||||
{
|
||||
x = gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
|
||||
goto restart;
|
||||
}
|
||||
break;
|
||||
|
||||
case MULT:
|
||||
|
@ -4194,8 +4227,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
|
|||
We try, as much as possible, to re-use rtl expressions to save memory.
|
||||
|
||||
IN_CODE says what kind of expression we are processing. Normally, it is
|
||||
SET. In a memory address (inside a MEM or PLUS, the latter being a
|
||||
kludge), it is MEM. When processing the arguments of a comparison
|
||||
SET. In a memory address (inside a MEM, PLUS or minus, the latter two
|
||||
being kludges), it is MEM. When processing the arguments of a comparison
|
||||
or a COMPARE against zero, it is COMPARE. */
|
||||
|
||||
static rtx
|
||||
|
@ -4215,7 +4248,7 @@ make_compound_operation (x, in_code)
|
|||
address, we stay there. If we have a comparison, set to COMPARE,
|
||||
but once inside, go back to our default of SET. */
|
||||
|
||||
next_code = (code == MEM || code == PLUS ? MEM
|
||||
next_code = (code == MEM || code == PLUS || code == MINUS ? MEM
|
||||
: ((code == COMPARE || GET_RTX_CLASS (code) == '<')
|
||||
&& XEXP (x, 1) == const0_rtx) ? COMPARE
|
||||
: in_code == COMPARE ? SET : in_code);
|
||||
|
|
169
gcc/cse.c
169
gcc/cse.c
|
@ -2451,8 +2451,9 @@ find_best_addr (insn, loc)
|
|||
&& validate_change (insn, loc, fold_rtx (addr, insn), 0))
|
||||
addr = *loc;
|
||||
|
||||
/* If this address is not in the hash table, we can't do any better.
|
||||
Also, ignore if volatile. */
|
||||
/* If this address is not in the hash table, we can't look for equivalences
|
||||
of the whole address. Also, ignore if volatile. */
|
||||
|
||||
do_not_record = 0;
|
||||
hash_code = HASH (addr, Pmode);
|
||||
addr_volatile = do_not_record;
|
||||
|
@ -2465,56 +2466,138 @@ find_best_addr (insn, loc)
|
|||
|
||||
elt = lookup (addr, hash_code, Pmode);
|
||||
|
||||
if (elt == 0)
|
||||
return;
|
||||
|
||||
#ifndef ADDRESS_COST
|
||||
our_cost = elt->cost;
|
||||
|
||||
/* Find the lowest cost below ours that works. */
|
||||
for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
|
||||
if (elt->cost < our_cost
|
||||
&& (GET_CODE (elt->exp) == REG || exp_equiv_p (elt->exp, elt->exp, 1, 0))
|
||||
&& validate_change (insn, loc, canon_reg (copy_rtx (elt->exp), 0), 0))
|
||||
return;
|
||||
if (elt)
|
||||
{
|
||||
our_cost = elt->cost;
|
||||
|
||||
/* Find the lowest cost below ours that works. */
|
||||
for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
|
||||
if (elt->cost < our_cost
|
||||
&& (GET_CODE (elt->exp) == REG
|
||||
|| exp_equiv_p (elt->exp, elt->exp, 1, 0))
|
||||
&& validate_change (insn, loc,
|
||||
canon_reg (copy_rtx (elt->exp), 0), 0))
|
||||
return;
|
||||
}
|
||||
#else
|
||||
|
||||
/* We need to find the best (under the criteria documented above) entry in
|
||||
the class that is valid. We use the `flag' field to indicate choices
|
||||
that were invalid and iterate until we can't find a better one that
|
||||
hasn't already been tried. */
|
||||
|
||||
for (p = elt->first_same_value; p; p = p->next_same_value)
|
||||
p->flag = 0;
|
||||
|
||||
while (found_better)
|
||||
if (elt)
|
||||
{
|
||||
int best_addr_cost = ADDRESS_COST (*loc);
|
||||
int best_rtx_cost = (elt->cost + 1) >> 1;
|
||||
struct table_elt *best_elt = elt;
|
||||
/* We need to find the best (under the criteria documented above) entry
|
||||
in the class that is valid. We use the `flag' field to indicate
|
||||
choices that were invalid and iterate until we can't find a better
|
||||
one that hasn't already been tried. */
|
||||
|
||||
found_better = 0;
|
||||
for (p = elt->first_same_value; p; p = p->next_same_value)
|
||||
if (! p->flag
|
||||
&& (GET_CODE (p->exp) == REG || exp_equiv_p (p->exp, p->exp, 1, 0))
|
||||
&& (ADDRESS_COST (p->exp) < best_addr_cost
|
||||
|| (ADDRESS_COST (p->exp) == best_addr_cost
|
||||
&& (p->cost + 1) >> 1 > best_rtx_cost)))
|
||||
{
|
||||
found_better = 1;
|
||||
best_addr_cost = ADDRESS_COST (p->exp);
|
||||
best_rtx_cost = (p->cost + 1) >> 1;
|
||||
best_elt = p;
|
||||
}
|
||||
p->flag = 0;
|
||||
|
||||
if (found_better)
|
||||
while (found_better)
|
||||
{
|
||||
if (validate_change (insn, loc,
|
||||
canon_reg (copy_rtx (best_elt->exp), 0), 0))
|
||||
return;
|
||||
else
|
||||
best_elt->flag = 1;
|
||||
int best_addr_cost = ADDRESS_COST (*loc);
|
||||
int best_rtx_cost = (elt->cost + 1) >> 1;
|
||||
struct table_elt *best_elt = elt;
|
||||
|
||||
found_better = 0;
|
||||
for (p = elt->first_same_value; p; p = p->next_same_value)
|
||||
if (! p->flag
|
||||
&& (GET_CODE (p->exp) == REG
|
||||
|| exp_equiv_p (p->exp, p->exp, 1, 0))
|
||||
&& (ADDRESS_COST (p->exp) < best_addr_cost
|
||||
|| (ADDRESS_COST (p->exp) == best_addr_cost
|
||||
&& (p->cost + 1) >> 1 > best_rtx_cost)))
|
||||
{
|
||||
found_better = 1;
|
||||
best_addr_cost = ADDRESS_COST (p->exp);
|
||||
best_rtx_cost = (p->cost + 1) >> 1;
|
||||
best_elt = p;
|
||||
}
|
||||
|
||||
if (found_better)
|
||||
{
|
||||
if (validate_change (insn, loc,
|
||||
canon_reg (copy_rtx (best_elt->exp), 0), 0))
|
||||
return;
|
||||
else
|
||||
best_elt->flag = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the address is a binary operation with the first operand a register
|
||||
and the second a constant, do the same as above, but looking for
|
||||
equivalences of the register. Then try to simplify before checking for
|
||||
the best address to use. This catches a few cases: First is when we
|
||||
have REG+const and the register is another REG+const. We can often merge
|
||||
the constants and eliminate one insn and one register. It may also be
|
||||
that a machine has a cheap REG+REG+const. Finally, this improves the
|
||||
code on the Alpha for unaligned byte stores. */
|
||||
|
||||
if (flag_expensive_optimizations
|
||||
&& (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
|
||||
|| GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
|
||||
&& GET_CODE (XEXP (*loc, 0)) == REG
|
||||
&& GET_CODE (XEXP (*loc, 1)) == CONST_INT)
|
||||
{
|
||||
rtx c = XEXP (*loc, 1);
|
||||
|
||||
do_not_record = 0;
|
||||
hash_code = HASH (XEXP (*loc, 0), Pmode);
|
||||
do_not_record = save_do_not_record;
|
||||
hash_arg_in_memory = save_hash_arg_in_memory;
|
||||
hash_arg_in_struct = save_hash_arg_in_struct;
|
||||
|
||||
elt = lookup (XEXP (*loc, 0), hash_code, Pmode);
|
||||
if (elt == 0)
|
||||
return;
|
||||
|
||||
/* We need to find the best (under the criteria documented above) entry
|
||||
in the class that is valid. We use the `flag' field to indicate
|
||||
choices that were invalid and iterate until we can't find a better
|
||||
one that hasn't already been tried. */
|
||||
|
||||
for (p = elt->first_same_value; p; p = p->next_same_value)
|
||||
p->flag = 0;
|
||||
|
||||
while (found_better)
|
||||
{
|
||||
int best_addr_cost = ADDRESS_COST (*loc);
|
||||
int best_rtx_cost = (COST (*loc) + 1) >> 1;
|
||||
struct table_elt *best_elt = elt;
|
||||
rtx best_rtx = *loc;
|
||||
|
||||
found_better = 0;
|
||||
for (p = elt->first_same_value; p; p = p->next_same_value)
|
||||
if (! p->flag
|
||||
&& (GET_CODE (p->exp) == REG
|
||||
|| exp_equiv_p (p->exp, p->exp, 1, 0)))
|
||||
{
|
||||
rtx new = simplify_binary_operation (GET_CODE (*loc), Pmode,
|
||||
p->exp, c);
|
||||
|
||||
if (new == 0)
|
||||
new = gen_rtx (GET_CODE (*loc), Pmode, p->exp, c);
|
||||
|
||||
if ((ADDRESS_COST (new) < best_addr_cost
|
||||
|| (ADDRESS_COST (new) == best_addr_cost
|
||||
&& (COST (new) + 1) >> 1 > best_rtx_cost)))
|
||||
{
|
||||
found_better = 1;
|
||||
best_addr_cost = ADDRESS_COST (new);
|
||||
best_rtx_cost = (COST (new) + 1) >> 1;
|
||||
best_elt = p;
|
||||
best_rtx = new;
|
||||
}
|
||||
}
|
||||
|
||||
if (found_better)
|
||||
{
|
||||
if (validate_change (insn, loc,
|
||||
canon_reg (copy_rtx (best_rtx), 0), 0))
|
||||
return;
|
||||
else
|
||||
best_elt->flag = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2134,7 +2134,6 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
|
|||
|
||||
#if BYTES_BIG_ENDIAN
|
||||
lbitpos = lnbitsize - lbitsize - lbitpos;
|
||||
rbitpos = rnbitsize - rbitsize - rbitpos;
|
||||
#endif
|
||||
|
||||
/* Make the mask to be used against the extracted field. */
|
||||
|
|
|
@ -846,6 +846,7 @@ gen_split (split)
|
|||
mybzero (d->strict_low, sizeof strict_low);
|
||||
|
||||
d->n_dups = 0;
|
||||
d->n_alternatives = 0;
|
||||
d->template = 0;
|
||||
d->outfun = 0;
|
||||
d->n_alternatives = 0;
|
||||
|
|
39
gcc/stmt.c
39
gcc/stmt.c
|
@ -2546,16 +2546,35 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
|
|||
#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
|
||||
if (fixed_regs[ARG_POINTER_REGNUM])
|
||||
{
|
||||
/* Now restore our arg pointer from the address at which it was saved
|
||||
in our stack frame.
|
||||
If there hasn't be space allocated for it yet, make some now. */
|
||||
if (arg_pointer_save_area == 0)
|
||||
arg_pointer_save_area
|
||||
= assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
|
||||
emit_move_insn (virtual_incoming_args_rtx,
|
||||
/* We need a pseudo here,
|
||||
or else instantiate_virtual_regs_1 complains. */
|
||||
copy_to_reg (arg_pointer_save_area));
|
||||
#ifdef ELIMINABLE_REGS
|
||||
/* If the argument pointer can be eliminated in favor of the
|
||||
frame pointer, we don't need to restore it. We assume here
|
||||
that if such an elimination is present, it can always be used.
|
||||
This is the case on all known machines; if we don't make this
|
||||
assumption, we do unnecessary saving on many machines. */
|
||||
static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
|
||||
if (elim_regs[i].from == ARG_POINTER_REGNUM
|
||||
&& elim_regs[i].to == FRAME_POINTER_REGNUM)
|
||||
break;
|
||||
|
||||
if (i == sizeof elim_regs / sizeof elim_regs [0])
|
||||
#endif
|
||||
{
|
||||
/* Now restore our arg pointer from the address at which it
|
||||
was saved in our stack frame.
|
||||
If there hasn't be space allocated for it yet, make
|
||||
some now. */
|
||||
if (arg_pointer_save_area == 0)
|
||||
arg_pointer_save_area
|
||||
= assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
|
||||
emit_move_insn (virtual_incoming_args_rtx,
|
||||
/* We need a pseudo here, or else
|
||||
instantiate_virtual_regs_1 complains. */
|
||||
copy_to_reg (arg_pointer_save_area));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue