#include "hard-reg-set.h"
#include "recog.h"
#include "regs.h"
+#include "addresses.h"
#include "expr.h"
#include "function.h"
#include "flags.h"
}
-/* Function to be passed to for_each_rtx to test whether a piece of
- RTL contains any mem/v. */
-static int
-volatile_mem_p (rtx *x, void *data ATTRIBUTE_UNUSED)
-{
- return (MEM_P (*x) && MEM_VOLATILE_P (*x));
-}
-
-/* Same as validate_change, but doesn't support groups, and it accepts
- volatile mems if they're already present in the original insn. */
-
-int
-validate_change_maybe_volatile (rtx object, rtx *loc, rtx new)
-{
- int result;
-
- if (validate_change (object, loc, new, 0))
- return 1;
-
- if (volatile_ok
- /* If there isn't a volatile MEM, there's nothing we can do. */
- || !for_each_rtx (&PATTERN (object), volatile_mem_p, 0)
- /* Make sure we're not adding or removing volatile MEMs. */
- || for_each_rtx (loc, volatile_mem_p, 0)
- || for_each_rtx (&new, volatile_mem_p, 0)
- || !insn_invalid_p (object))
- return 0;
-
- volatile_ok = 1;
-
- gcc_assert (!insn_invalid_p (object));
-
- result = validate_change (object, loc, new, 0);
-
- volatile_ok = 0;
-
- return result;
-}
-
/* This subroutine of apply_change_group verifies whether the changes to INSN
were valid; i.e. whether INSN can still be recognized. */
/* Tentatively apply the changes numbered NUM and up.
Return 1 if all changes are valid, zero otherwise. */
-static int
+int
verify_changes (int num)
{
int i;
}
}
-/* Try replacing every occurrence of FROM in subexpression LOC of INSN
- with TO. After all changes have been made, validate by seeing
- if INSN is still valid. */
-
-int
-validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc)
-{
- validate_replace_rtx_1 (loc, from, to, insn);
- return apply_change_group ();
-}
-
/* Try replacing every occurrence of FROM in INSN with TO. After all
changes have been made, validate by seeing if INSN is still valid. */
/* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally
create such rtl, and we must reject it. */
- if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ if (SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
return 0;
/* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally
create such rtl, and we must reject it. */
- if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ if (SCALAR_FLOAT_MODE_P (GET_MODE (op))
&& GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
return 0;
extract_insn (insn);
recog_data.insn = insn;
}
+
/* Do cached extract_insn, constrain_operands and complain about failures.
Used by insn_attrtab. */
void
&& !constrain_operands (reload_completed))
fatal_insn_not_found (insn);
}
+
/* Do cached constrain_operands and complain about failures. */
int
constrain_operands_cached (int strict)
case 'p':
op_alt[j].is_address = 1;
op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
- [(int) MODE_BASE_REG_CLASS (VOIDmode)];
+ [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
break;
case 'g':
op_alt[j].cl
= (reg_class_subunion
[(int) op_alt[j].cl]
- [(int) MODE_BASE_REG_CLASS (VOIDmode)]);
+ [(int) base_reg_class (VOIDmode, ADDRESS,
+ SCRATCH)]);
break;
}
break;
/* No need to check general_operand again;
- it was done in insn-recog.c. */
+ it was done in insn-recog.c. Well, except that reload
+ doesn't check the validity of its replacements, but
+ that should only matter when there's a bug. */
case 'g':
/* Anything goes unless it is a REG and really has a hard reg
but the hard reg is not in the class GENERAL_REGS. */
- if (strict < 0
- || GENERAL_REGS == ALL_REGS
- || !REG_P (op)
- || (reload_in_progress
- && REGNO (op) >= FIRST_PSEUDO_REGISTER)
- || reg_fits_class_p (op, GENERAL_REGS, offset, mode))
+ if (REG_P (op))
+ {
+ if (strict < 0
+ || GENERAL_REGS == ALL_REGS
+ || (reload_in_progress
+ && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ || reg_fits_class_p (op, GENERAL_REGS, offset, mode))
+ win = 1;
+ }
+ else if (strict < 0 || general_operand (op, mode))
win = 1;
break;
enum machine_mode mode)
{
int regno = REGNO (operand);
+
+ if (cl == NO_REGS)
+ return 0;
+
if (regno < FIRST_PSEUDO_REGISTER
&& TEST_HARD_REG_BIT (reg_class_contents[(int) cl],
regno + offset))
/* Same as split_all_insns, but do not expect CFG to be available.
Used by machine dependent reorg passes. */
-void
+unsigned int
split_all_insns_noflow (void)
{
rtx next, insn;
split_insn (insn);
}
}
+ return 0;
}
\f
#ifdef HAVE_peephole2
static struct peep2_insn_data peep2_insn_data[MAX_INSNS_PER_PEEP2 + 1];
static int peep2_current;
+/* The number of instructions available to match a peep2. */
+int peep2_current_count;
/* A non-insn marker indicating the last insn of the block.
The live_before regset for this element is correct, indicating
rtx
peep2_next_insn (int n)
{
- gcc_assert (n < MAX_INSNS_PER_PEEP2 + 1);
+ gcc_assert (n <= peep2_current_count);
n += peep2_current;
if (n >= MAX_INSNS_PER_PEEP2 + 1)
n -= MAX_INSNS_PER_PEEP2 + 1;
- if (peep2_insn_data[n].insn == PEEP2_EOB)
- return NULL_RTX;
return peep2_insn_data[n].insn;
}
/* Perform the peephole2 optimization pass. */
-void
-peephole2_optimize (FILE *dump_file ATTRIBUTE_UNUSED)
+static void
+peephole2_optimize (void)
{
rtx insn, prev;
regset live;
/* Indicate that all slots except the last holds invalid data. */
for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
peep2_insn_data[i].insn = NULL_RTX;
+ peep2_current_count = 0;
/* Indicate that the last slot contains live_after data. */
peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB;
/* Record this insn. */
if (--peep2_current < 0)
peep2_current = MAX_INSNS_PER_PEEP2;
+ if (peep2_current_count < MAX_INSNS_PER_PEEP2
+ && peep2_insn_data[peep2_current].insn == NULL_RTX)
+ peep2_current_count++;
peep2_insn_data[peep2_current].insn = insn;
propagate_one_insn (pbi, insn);
COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
- /* Match the peephole. */
- try = peephole2_insns (PATTERN (insn), insn, &match_len);
+ if (RTX_FRAME_RELATED_P (insn))
+ {
+ /* If an insn has RTX_FRAME_RELATED_P set, peephole
+ substitution would lose the
+ REG_FRAME_RELATED_EXPR that is attached. */
+ peep2_current_count = 0;
+ try = NULL;
+ }
+ else
+ /* Match the peephole. */
+ try = peephole2_insns (PATTERN (insn), insn, &match_len);
+
if (try != NULL)
{
/* If we are splitting a CALL_INSN, look for the CALL_INSN
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
peep2_insn_data[i].insn = NULL_RTX;
peep2_insn_data[peep2_current].insn = PEEP2_EOB;
+ peep2_current_count = 0;
#else
/* Back up lifetime information past the end of the
newly created sequence. */
{
if (--i < 0)
i = MAX_INSNS_PER_PEEP2;
+ if (peep2_current_count < MAX_INSNS_PER_PEEP2
+ && peep2_insn_data[i].insn == NULL_RTX)
+ peep2_current_count++;
peep2_insn_data[i].insn = x;
propagate_one_insn (pbi, x);
COPY_REG_SET (peep2_insn_data[i].live_before, live);
return (optimize > 0 && flag_peephole2);
}
-static void
+static unsigned int
rest_of_handle_peephole2 (void)
{
#ifdef HAVE_peephole2
- peephole2_optimize (dump_file);
+ peephole2_optimize ();
#endif
+ return 0;
}
struct tree_opt_pass pass_peephole2 =
'z' /* letter */
};
-static void
+static unsigned int
rest_of_handle_split_all_insns (void)
{
split_all_insns (1);
+ return 0;
}
struct tree_opt_pass pass_split_all_insns =
{
- NULL, /* name */
+ "split1", /* name */
NULL, /* gate */
rest_of_handle_split_all_insns, /* execute */
NULL, /* sub */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
struct tree_opt_pass pass_split_for_shorten_branches =
{
- NULL, /* name */
+ "split3", /* name */
gate_do_final_split, /* gate */
split_all_insns_noflow, /* execute */
NULL, /* sub */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};
struct tree_opt_pass pass_split_before_regstack =
{
- NULL, /* name */
+ "split2", /* name */
gate_handle_split_before_regstack, /* gate */
rest_of_handle_split_all_insns, /* execute */
NULL, /* sub */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
+ TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};