You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "hard-reg-set.h"
#include "recog.h"
#include "regs.h"
+#include "addresses.h"
#include "expr.h"
#include "function.h"
#include "flags.h"
#include "basic-block.h"
#include "output.h"
#include "reload.h"
+#include "timevar.h"
+#include "tree-pass.h"
#ifndef STACK_PUSH_CODE
#ifdef STACK_GROWS_DOWNWARD
return apply_change_group ();
}
+
/* 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. */
d.insn = insn;
note_uses (&PATTERN (insn), validate_replace_src_1, &d);
}
+
+/* Try simplify INSN.
+ Invoke simplify_rtx () on every SET_SRC and SET_DEST inside the INSN's
+ pattern and return true if something was simplified. */
+
+bool
+validate_simplify_insn (rtx insn)
+{
+ int i;
+ rtx pat = NULL;
+ rtx newpat = NULL;
+
+ pat = PATTERN (insn);
+
+ if (GET_CODE (pat) == SET)
+ {
+ newpat = simplify_rtx (SET_SRC (pat));
+ if (newpat && !rtx_equal_p (SET_SRC (pat), newpat))
+ validate_change (insn, &SET_SRC (pat), newpat, 1);
+ newpat = simplify_rtx (SET_DEST (pat));
+ if (newpat && !rtx_equal_p (SET_DEST (pat), newpat))
+ validate_change (insn, &SET_DEST (pat), newpat, 1);
+ }
+ else if (GET_CODE (pat) == PARALLEL)
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx s = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
+ {
+ newpat = simplify_rtx (SET_SRC (s));
+ if (newpat && !rtx_equal_p (SET_SRC (s), newpat))
+ validate_change (insn, &SET_SRC (s), newpat, 1);
+ newpat = simplify_rtx (SET_DEST (s));
+ if (newpat && !rtx_equal_p (SET_DEST (s), newpat))
+ validate_change (insn, &SET_DEST (s), newpat, 1);
+ }
+ }
+ return ((num_changes_pending () > 0) && (apply_change_group () > 0));
+}
\f
#ifdef HAVE_cc0
/* Return 1 if the insn using CC0 set by INSN does not contain
/* 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;
peep2_current = MAX_INSNS_PER_PEEP2;
/* Start up propagation. */
- COPY_REG_SET (live, bb->global_live_at_end);
+ COPY_REG_SET (live, bb->il.rtl->global_live_at_end);
COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
#ifdef HAVE_conditional_execution
/* 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);
/* 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,
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (bb->il.rtl->global_live_at_start, live,
0, j, rsi)
{
do_global_life_update = true;
return true;
}
+\f
+static bool
+gate_handle_peephole2 (void)
+{
+ return (optimize > 0 && flag_peephole2);
+}
+
+static unsigned int
+rest_of_handle_peephole2 (void)
+{
+#ifdef HAVE_peephole2
+ peephole2_optimize ();
+#endif
+ return 0;
+}
+
+struct tree_opt_pass pass_peephole2 =
+{
+ "peephole2", /* name */
+ gate_handle_peephole2, /* gate */
+ rest_of_handle_peephole2, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_PEEPHOLE2, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 'z' /* letter */
+};
+
+static unsigned int
+rest_of_handle_split_all_insns (void)
+{
+ split_all_insns (1);
+ return 0;
+}
+
+struct tree_opt_pass pass_split_all_insns =
+{
+ "split1", /* name */
+ NULL, /* gate */
+ rest_of_handle_split_all_insns, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+/* The placement of the splitting that we do for shorten_branches
+ depends on whether regstack is used by the target or not. */
+static bool
+gate_do_final_split (void)
+{
+#if defined (HAVE_ATTR_length) && !defined (STACK_REGS)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+struct tree_opt_pass pass_split_for_shorten_branches =
+{
+ "split3", /* name */
+ gate_do_final_split, /* gate */
+ split_all_insns_noflow, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_SHORTEN_BRANCH, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};
+
+
+static bool
+gate_handle_split_before_regstack (void)
+{
+#if defined (HAVE_ATTR_length) && defined (STACK_REGS)
+ /* If flow2 creates new instructions which need splitting
+ and scheduling after reload is not done, they might not be
+ split until final which doesn't allow splitting
+ if HAVE_ATTR_length. */
+# ifdef INSN_SCHEDULING
+ return (optimize && !flag_schedule_insns_after_reload);
+# else
+ return (optimize);
+# endif
+#else
+ return 0;
+#endif
+}
+
+struct tree_opt_pass pass_split_before_regstack =
+{
+ "split2", /* name */
+ gate_handle_split_before_regstack, /* gate */
+ rest_of_handle_split_all_insns, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_SHORTEN_BRANCH, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};