&& 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
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);
- 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:
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
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);
&& 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;
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. */
+ if (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. */
- for (p = elt->first_same_value; p; p = p->next_same_value)
- p->flag = 0;
+ for (p = elt->first_same_value; p; p = p->next_same_value)
+ p->flag = 0;
- while (found_better)
+ while (found_better)
+ {
+ 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)
{
- int best_addr_cost = ADDRESS_COST (*loc);
- int best_rtx_cost = (elt->cost + 1) >> 1;
- struct table_elt *best_elt = elt;
+ 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. */
- 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 = (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
#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