/* Subroutines used by or related to instruction recognition.
Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
volatile_ok = 1;
}
-/* Try recognizing the instruction INSN,
- and return the code number that results.
- Remember the code so that repeated calls do not
- need to spend the time for actual rerecognition.
-
- This function is the normal interface to instruction recognition.
- The automatically-generated function `recog' is normally called
- through this one. (The only exception is in combine.c.) */
-
-int
-recog_memoized_1 (rtx insn)
-{
- if (INSN_CODE (insn) < 0)
- INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
- return INSN_CODE (insn);
-}
\f
/* Check that X is an insn-body for an `asm' with operands
and that the operands mentioned in it are legitimate. */
if (old == new || rtx_equal_p (old, new))
return 1;
- if (in_group == 0 && num_changes != 0)
- abort ();
+ gcc_assert (in_group != 0 || num_changes == 0);
*loc = new;
&& GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS)
{
/* Verify that operands are really shared. */
- if (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0))) !=
- ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, j))))
- abort ();
+ gcc_assert (ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (x, 0, 0)))
+ == ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP
+ (x, 0, j))));
validate_replace_rtx_1 (&SET_DEST (XVECEXP (x, 0, j)),
from, to, object);
}
if (next == 0)
return 0;
- return ((GET_CODE (next) == JUMP_INSN
- || GET_CODE (next) == INSN
- || GET_CODE (next) == CALL_INSN)
+ return (INSN_P (next)
&& ! inequality_comparisons_p (PATTERN (next)));
}
#endif
{
next = NEXT_INSN (insn);
if (next == 0
- || (GET_CODE (next) != INSN && GET_CODE (next) != JUMP_INSN))
+ || (!NONJUMP_INSN_P (next) && !JUMP_P (next)))
return 0;
result = find_single_use_1 (dest, &PATTERN (next));
return 0;
for (next = next_nonnote_insn (insn);
- next != 0 && GET_CODE (next) != CODE_LABEL;
+ next != 0 && !LABEL_P (next);
next = next_nonnote_insn (next))
if (INSN_P (next) && dead_or_set_p (next, dest))
{
if (CONSTANT_P (op))
return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
|| mode == VOIDmode)
-#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-#endif
&& LEGITIMATE_CONSTANT_P (op));
/* Except for certain constants with VOIDmode, already checked for,
#ifdef INSN_SCHEDULING
/* On machines that have insn scheduling, we want all memory
- reference to be explicit, so outlaw paradoxical SUBREGs. */
- if (MEM_P (sub)
+ reference to be explicit, so outlaw paradoxical SUBREGs.
+ However, we must allow them after reload so that they can
+ get cleaned up by cleanup_subreg_operands. */
+ if (!reload_completed && MEM_P (sub)
&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (sub)))
return 0;
#endif
return 0;
/* Use the mem's mode, since it will be reloaded thus. */
- mode = GET_MODE (op);
- GO_IF_LEGITIMATE_ADDRESS (mode, y, win);
+ if (memory_address_p (GET_MODE (op), y))
+ return 1;
}
return 0;
-
- win:
- return 1;
}
\f
/* Return 1 if OP is a valid memory address for a memory reference
return (CONSTANT_P (op)
&& (GET_MODE (op) == mode || mode == VOIDmode
|| GET_MODE (op) == VOIDmode)
-#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-#endif
&& LEGITIMATE_CONSTANT_P (op));
}
return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode
|| mode == VOIDmode)
-#ifdef LEGITIMATE_PIC_OPERAND_P
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-#endif
&& LEGITIMATE_CONSTANT_P (op));
}
int result = 0;
/* Use constrain_operands after reload. */
- if (reload_completed)
- abort ();
+ gcc_assert (!reload_completed);
while (*constraint)
{
/* Fall through. */
case 'i':
- if (CONSTANT_P (op)
-#ifdef LEGITIMATE_PIC_OPERAND_P
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
-#endif
- )
+ if (CONSTANT_P (op) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
result = 1;
break;
/* This insn is an `asm' with operands. */
/* expand_asm_operands makes sure there aren't too many operands. */
- if (noperands > MAX_RECOG_OPERANDS)
- abort ();
+ gcc_assert (noperands <= MAX_RECOG_OPERANDS);
/* Now get the operand values and constraints out of the insn. */
decode_asm_operands (body, recog_data.operand,
: recog_data.constraints[i][0] == '+' ? OP_INOUT
: OP_IN);
- if (recog_data.n_alternatives > MAX_RECOG_ALTERNATIVES)
- abort ();
+ gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES);
}
/* After calling extract_insn, you can use this function to extract some
for (j = 0; j < recog_data.n_alternatives; j++)
{
- op_alt[j].class = NO_REGS;
+ op_alt[j].cl = NO_REGS;
op_alt[j].constraint = p;
op_alt[j].matches = -1;
op_alt[j].matched = -1;
case 'p':
op_alt[j].is_address = 1;
- op_alt[j].class = reg_class_subunion[(int) op_alt[j].class]
+ op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
[(int) MODE_BASE_REG_CLASS (VOIDmode)];
break;
- case 'g': case 'r':
- op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) GENERAL_REGS];
+ case 'g':
+ case 'r':
+ op_alt[j].cl =
+ reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS];
break;
default:
if (EXTRA_ADDRESS_CONSTRAINT (c, p))
{
op_alt[j].is_address = 1;
- op_alt[j].class
+ op_alt[j].cl
= (reg_class_subunion
- [(int) op_alt[j].class]
+ [(int) op_alt[j].cl]
[(int) MODE_BASE_REG_CLASS (VOIDmode)]);
break;
}
- op_alt[j].class
+ op_alt[j].cl
= (reg_class_subunion
- [(int) op_alt[j].class]
+ [(int) op_alt[j].cl]
[(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
break;
}
do
{
+ int seen_earlyclobber_at = -1;
int opno;
int lose = 0;
funny_match_index = 0;
case '&':
earlyclobber[opno] = 1;
+ if (seen_earlyclobber_at < 0)
+ seen_earlyclobber_at = opno;
break;
case '0': case '1': case '2': case '3': case '4':
default:
{
- enum reg_class class;
+ enum reg_class cl;
- class = (c == 'r'
+ cl = (c == 'r'
? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
- if (class != NO_REGS)
+ if (cl != NO_REGS)
{
if (strict < 0
|| (strict == 0
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)
|| (strict == 0 && GET_CODE (op) == SCRATCH)
|| (REG_P (op)
- && reg_fits_class_p (op, class, offset, mode)))
+ && reg_fits_class_p (op, cl, offset, mode)))
win = 1;
}
#ifdef EXTRA_CONSTRAINT_STR
/* See if any earlyclobber operand conflicts with some other
operand. */
- if (strict > 0)
- for (eopno = 0; eopno < recog_data.n_operands; eopno++)
+ if (strict > 0 && seen_earlyclobber_at >= 0)
+ for (eopno = seen_earlyclobber_at;
+ eopno < recog_data.n_operands;
+ eopno++)
/* Ignore earlyclobber operands now in memory,
because we would often report failure when we have
two memory operands, one of which was formerly a REG. */
If REG occupies multiple hard regs, all of them must be in CLASS. */
int
-reg_fits_class_p (rtx operand, enum reg_class class, int offset,
+reg_fits_class_p (rtx operand, enum reg_class cl, int offset,
enum machine_mode mode)
{
int regno = REGNO (operand);
if (regno < FIRST_PSEUDO_REGISTER
- && TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ && TEST_HARD_REG_BIT (reg_class_contents[(int) cl],
regno + offset))
{
int sr;
regno += offset;
for (sr = hard_regno_nregs[regno][mode] - 1;
sr > 0; sr--)
- if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class],
+ if (! TEST_HARD_REG_BIT (reg_class_contents[(int) cl],
regno + sr))
break;
return sr == 0;
BB boundary we are interested in will be set to
previous one. */
- while (GET_CODE (last) == BARRIER)
+ while (BARRIER_P (last))
last = PREV_INSN (last);
SET_BIT (blocks, bb->index);
changed = true;
rtx
peep2_next_insn (int n)
{
- if (n >= MAX_INSNS_PER_PEEP2 + 1)
- abort ();
+ gcc_assert (n < MAX_INSNS_PER_PEEP2 + 1);
n += peep2_current;
if (n >= MAX_INSNS_PER_PEEP2 + 1)
int
peep2_regno_dead_p (int ofs, int regno)
{
- if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
- abort ();
+ gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
ofs += peep2_current;
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
ofs -= MAX_INSNS_PER_PEEP2 + 1;
- if (peep2_insn_data[ofs].insn == NULL_RTX)
- abort ();
+ gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
return ! REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno);
}
{
int regno, n;
- if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
- abort ();
+ gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
ofs += peep2_current;
if (ofs >= MAX_INSNS_PER_PEEP2 + 1)
ofs -= MAX_INSNS_PER_PEEP2 + 1;
- if (peep2_insn_data[ofs].insn == NULL_RTX)
- abort ();
+ gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
regno = REGNO (reg);
n = hard_regno_nregs[regno][GET_MODE (reg)];
enum machine_mode mode, HARD_REG_SET *reg_set)
{
static int search_ofs;
- enum reg_class class;
+ enum reg_class cl;
HARD_REG_SET live;
int i;
- if (from >= MAX_INSNS_PER_PEEP2 + 1 || to >= MAX_INSNS_PER_PEEP2 + 1)
- abort ();
+ gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
+ gcc_assert (to < MAX_INSNS_PER_PEEP2 + 1);
from += peep2_current;
if (from >= MAX_INSNS_PER_PEEP2 + 1)
if (to >= MAX_INSNS_PER_PEEP2 + 1)
to -= MAX_INSNS_PER_PEEP2 + 1;
- if (peep2_insn_data[from].insn == NULL_RTX)
- abort ();
+ gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
REG_SET_TO_HARD_REG_SET (live, peep2_insn_data[from].live_before);
while (from != to)
if (++from >= MAX_INSNS_PER_PEEP2 + 1)
from = 0;
- if (peep2_insn_data[from].insn == NULL_RTX)
- abort ();
+ gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
IOR_HARD_REG_SET (live, this_live);
}
- class = (class_str[0] == 'r' ? GENERAL_REGS
+ cl = (class_str[0] == 'r' ? GENERAL_REGS
: REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (fixed_regs[regno])
continue;
/* Make sure the register is of the right class. */
- if (! TEST_HARD_REG_BIT (reg_class_contents[class], regno))
+ if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno))
continue;
/* And can support the mode we need. */
if (! HARD_REGNO_MODE_OK (regno, mode))
void
peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
{
- regset_head rs_heads[MAX_INSNS_PER_PEEP2 + 2];
rtx insn, prev;
regset live;
int i;
bool changed;
#endif
bool do_cleanup_cfg = false;
+ bool do_global_life_update = false;
bool do_rebuild_jump_labels = false;
/* Initialize the regsets we're going to use. */
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
- peep2_insn_data[i].live_before = INITIALIZE_REG_SET (rs_heads[i]);
- live = INITIALIZE_REG_SET (rs_heads[i]);
+ peep2_insn_data[i].live_before = ALLOC_REG_SET (®_obstack);
+ live = ALLOC_REG_SET (®_obstack);
#ifdef HAVE_conditional_execution
blocks = sbitmap_alloc (last_basic_block);
FOR_EACH_BB_REVERSE (bb)
{
struct propagate_block_info *pbi;
+ reg_set_iterator rsi;
+ unsigned int j;
/* Indicate that all slots except the last holds invalid data. */
for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
if (j >= MAX_INSNS_PER_PEEP2 + 1)
j -= MAX_INSNS_PER_PEEP2 + 1;
old_insn = peep2_insn_data[j].insn;
- if (GET_CODE (old_insn) != CALL_INSN)
+ if (!CALL_P (old_insn))
continue;
was_call = true;
new_insn = try;
while (new_insn != NULL_RTX)
{
- if (GET_CODE (new_insn) == CALL_INSN)
+ if (CALL_P (new_insn))
break;
new_insn = NEXT_INSN (new_insn);
}
- if (new_insn == NULL_RTX)
- abort ();
+ gcc_assert (new_insn != NULL_RTX);
CALL_INSN_FUNCTION_USAGE (new_insn)
= CALL_INSN_FUNCTION_USAGE (old_insn);
if (j >= MAX_INSNS_PER_PEEP2 + 1)
j -= MAX_INSNS_PER_PEEP2 + 1;
old_insn = peep2_insn_data[j].insn;
- if (GET_CODE (old_insn) == CALL_INSN)
- abort ();
+ gcc_assert (!CALL_P (old_insn));
}
break;
}
if (note || (was_call && nonlocal_goto_handler_labels))
{
edge eh_edge;
+ edge_iterator ei;
- for (eh_edge = bb->succ; eh_edge
- ; eh_edge = eh_edge->succ_next)
+ FOR_EACH_EDGE (eh_edge, ei, bb->succs)
if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
break;
for (x = try ; x != before_try ; x = PREV_INSN (x))
- if (GET_CODE (x) == CALL_INSN
+ if (CALL_P (x)
|| (flag_non_call_exceptions
&& may_trap_p (PATTERN (x))
&& !find_reg_note (x, REG_EH_REGION, NULL)))
nfte = split_block (bb, x);
flags = (eh_edge->flags
& (EDGE_EH | EDGE_ABNORMAL));
- if (GET_CODE (x) == CALL_INSN)
+ if (CALL_P (x))
flags |= EDGE_ABNORMAL_CALL;
nehe = make_edge (nfte->src, eh_edge->dest,
flags);
/* If we generated a jump instruction, it won't have
JUMP_LABEL set. Recompute after we're done. */
for (x = try; x != before_try; x = PREV_INSN (x))
- if (GET_CODE (x) == JUMP_INSN)
+ if (JUMP_P (x))
{
do_rebuild_jump_labels = true;
break;
break;
}
+ /* Some peepholes can decide the don't need one or more of their
+ inputs. If this happens, local life update is not enough. */
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (bb->global_live_at_start, live,
+ 0, j, rsi)
+ {
+ do_global_life_update = true;
+ break;
+ }
+
free_propagate_block_info (pbi);
}
if (do_cleanup_cfg)
{
cleanup_cfg (0);
- update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
+ do_global_life_update = true;
}
+ if (do_global_life_update)
+ update_life_info (0, UPDATE_LIFE_GLOBAL_RM_NOTES, PROP_DEATH_NOTES);
#ifdef HAVE_conditional_execution
else
{
rtx out_set, in_set;
in_set = single_set (in_insn);
- if (! in_set)
- abort ();
+ gcc_assert (in_set);
if (!MEM_P (SET_DEST (in_set)))
return false;
int i;
out_pat = PATTERN (out_insn);
- if (GET_CODE (out_pat) != PARALLEL)
- abort ();
+ gcc_assert (GET_CODE (out_pat) == PARALLEL);
for (i = 0; i < XVECLEN (out_pat, 0); i++)
{
if (GET_CODE (exp) == CLOBBER)
continue;
- if (GET_CODE (exp) != SET)
- abort ();
+ gcc_assert (GET_CODE (exp) == SET);
if (reg_mentioned_p (SET_DEST (exp), SET_DEST (in_set)))
return false;
in_set = single_set (in_insn);
if (! in_set)
{
- if (GET_CODE (in_insn) == JUMP_INSN || GET_CODE (in_insn) == CALL_INSN)
- return false;
- abort ();
+ gcc_assert (JUMP_P (in_insn) || CALL_P (in_insn));
+ return false;
}
if (GET_CODE (SET_SRC (in_set)) != IF_THEN_ELSE)
int i;
out_pat = PATTERN (out_insn);
- if (GET_CODE (out_pat) != PARALLEL)
- abort ();
+ gcc_assert (GET_CODE (out_pat) == PARALLEL);
for (i = 0; i < XVECLEN (out_pat, 0); i++)
{
if (GET_CODE (exp) == CLOBBER)
continue;
- if (GET_CODE (exp) != SET)
- abort ();
+ gcc_assert (GET_CODE (exp) == SET);
if (reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 1))
|| reg_mentioned_p (SET_DEST (out_set), XEXP (in_set, 2)))