/* 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, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
#include "hard-reg-set.h"
#include "recog.h"
#include "regs.h"
+#include "addresses.h"
#include "expr.h"
#include "function.h"
#include "flags.h"
operands = alloca (noperands * sizeof (rtx));
constraints = alloca (noperands * sizeof (char *));
- decode_asm_operands (x, operands, NULL, constraints, NULL);
+ decode_asm_operands (x, operands, NULL, constraints, NULL, NULL);
for (i = 0; i < noperands; i++)
{
return apply_change_group ();
}
+/* Keep X canonicalized if some changes have made it non-canonical; only
+ modifies the operands of X, not (for example) its code. Simplifications
+ are not the job of this routine.
-/* 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 true if anything was changed. */
+bool
+canonicalize_change_group (rtx insn, rtx x)
{
- 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;
+ if (COMMUTATIVE_P (x)
+ && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+ {
+ /* Oops, the caller has made X no longer canonical.
+ Let's redo the changes in the correct order. */
+ rtx tem = XEXP (x, 0);
+ validate_change (insn, &XEXP (x, 0), XEXP (x, 1), 1);
+ validate_change (insn, &XEXP (x, 1), tem, 1);
+ return true;
+ }
+ else
+ return false;
}
+
/* This subroutine of apply_change_group verifies whether the changes to INSN
were valid; i.e. whether INSN can still be recognized. */
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
const char *
decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
- const char **constraints, enum machine_mode *modes)
+ const char **constraints, enum machine_mode *modes,
+ location_t *loc)
{
int i;
int noperands;
- const char *template = 0;
+ rtx asmop = 0;
if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS)
{
- rtx asmop = SET_SRC (body);
+ asmop = SET_SRC (body);
/* Single output operand: BODY is (set OUTPUT (asm_operands ....)). */
noperands = ASM_OPERANDS_INPUT_LENGTH (asmop) + 1;
constraints[0] = ASM_OPERANDS_OUTPUT_CONSTRAINT (asmop);
if (modes)
modes[0] = GET_MODE (SET_DEST (body));
- template = ASM_OPERANDS_TEMPLATE (asmop);
}
else if (GET_CODE (body) == ASM_OPERANDS)
{
- rtx asmop = body;
+ asmop = body;
/* No output operands: BODY is (asm_operands ....). */
noperands = ASM_OPERANDS_INPUT_LENGTH (asmop);
if (modes)
modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i);
}
- template = ASM_OPERANDS_TEMPLATE (asmop);
}
else if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == SET
&& GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) == ASM_OPERANDS)
{
- rtx asmop = SET_SRC (XVECEXP (body, 0, 0));
int nparallel = XVECLEN (body, 0); /* Includes CLOBBERs. */
- int nin = ASM_OPERANDS_INPUT_LENGTH (asmop);
+ int nin;
int nout = 0; /* Does not include CLOBBERs. */
+ asmop = SET_SRC (XVECEXP (body, 0, 0));
+ nin = ASM_OPERANDS_INPUT_LENGTH (asmop);
+
/* At least one output, plus some CLOBBERs. */
/* The outputs are in the SETs.
if (modes)
modes[i + nout] = ASM_OPERANDS_INPUT_MODE (asmop, i);
}
-
- template = ASM_OPERANDS_TEMPLATE (asmop);
}
else if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)
{
/* No outputs, but some CLOBBERs. */
- rtx asmop = XVECEXP (body, 0, 0);
- int nin = ASM_OPERANDS_INPUT_LENGTH (asmop);
+ int nin;
+
+ asmop = XVECEXP (body, 0, 0);
+ nin = ASM_OPERANDS_INPUT_LENGTH (asmop);
for (i = 0; i < nin; i++)
{
modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i);
}
- template = ASM_OPERANDS_TEMPLATE (asmop);
}
- return template;
+ if (loc)
+ {
+#ifdef USE_MAPPED_LOCATION
+ *loc = ASM_OPERANDS_SOURCE_LOCATION (asmop);
+#else
+ loc->file = ASM_OPERANDS_SOURCE_FILE (asmop);
+ loc->line = ASM_OPERANDS_SOURCE_LINE (asmop);
+#endif
+ }
+
+ return ASM_OPERANDS_TEMPLATE (asmop);
}
/* Check if an asm_operand matches its constraints.
because the amount of the increment depends on the mode. */
int
-mode_dependent_address_p (rtx addr ATTRIBUTE_UNUSED /* Maybe used in GO_IF_MODE_DEPENDENT_ADDRESS. */)
-{
+mode_dependent_address_p (rtx addr)
+{
+ /* Auto-increment addressing with anything other than post_modify
+ or pre_modify always introduces a mode dependency. Catch such
+ cases now instead of deferring to the target. */
+ if (GET_CODE (addr) == PRE_INC
+ || GET_CODE (addr) == POST_INC
+ || GET_CODE (addr) == PRE_DEC
+ || GET_CODE (addr) == POST_DEC)
+ return 1;
+
GO_IF_MODE_DEPENDENT_ADDRESS (addr, win);
return 0;
/* Label `win' might (not) be used via GO_IF_MODE_DEPENDENT_ADDRESS. */
decode_asm_operands (body, recog_data.operand,
recog_data.operand_loc,
recog_data.constraints,
- recog_data.operand_mode);
+ recog_data.operand_mode, NULL);
if (noperands > 0)
{
const char *p = recog_data.constraints[0];
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;
}
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
/* Common predicates for use with define_bypass. */
/* True if the dependency between OUT_INSN and IN_INSN is on the store
- data not the address operand(s) of the store. IN_INSN must be
- single_set. OUT_INSN must be either a single_set or a PARALLEL with
- SETs inside. */
+ data not the address operand(s) of the store. IN_INSN and OUT_INSN
+ must be either a single_set or a PARALLEL with SETs inside. */
int
store_data_bypass_p (rtx out_insn, rtx in_insn)
{
rtx out_set, in_set;
+ rtx out_pat, in_pat;
+ rtx out_exp, in_exp;
+ int i, j;
in_set = single_set (in_insn);
- gcc_assert (in_set);
-
- if (!MEM_P (SET_DEST (in_set)))
- return false;
-
- out_set = single_set (out_insn);
- if (out_set)
+ if (in_set)
{
- if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_set)))
+ if (!MEM_P (SET_DEST (in_set)))
return false;
+
+ out_set = single_set (out_insn);
+ if (out_set)
+ {
+ if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_set)))
+ return false;
+ }
+ else
+ {
+ out_pat = PATTERN (out_insn);
+
+ if (GET_CODE (out_pat) != PARALLEL)
+ return false;
+
+ for (i = 0; i < XVECLEN (out_pat, 0); i++)
+ {
+ out_exp = XVECEXP (out_pat, 0, i);
+
+ if (GET_CODE (out_exp) == CLOBBER)
+ continue;
+
+ gcc_assert (GET_CODE (out_exp) == SET);
+
+ if (reg_mentioned_p (SET_DEST (out_exp), SET_DEST (in_set)))
+ return false;
+ }
+ }
}
else
{
- rtx out_pat;
- int i;
-
- out_pat = PATTERN (out_insn);
- gcc_assert (GET_CODE (out_pat) == PARALLEL);
+ in_pat = PATTERN (in_insn);
+ gcc_assert (GET_CODE (in_pat) == PARALLEL);
- for (i = 0; i < XVECLEN (out_pat, 0); i++)
+ for (i = 0; i < XVECLEN (in_pat, 0); i++)
{
- rtx exp = XVECEXP (out_pat, 0, i);
+ in_exp = XVECEXP (in_pat, 0, i);
- if (GET_CODE (exp) == CLOBBER)
+ if (GET_CODE (in_exp) == CLOBBER)
continue;
- gcc_assert (GET_CODE (exp) == SET);
+ gcc_assert (GET_CODE (in_exp) == SET);
- if (reg_mentioned_p (SET_DEST (exp), SET_DEST (in_set)))
+ if (!MEM_P (SET_DEST (in_exp)))
return false;
- }
+
+ out_set = single_set (out_insn);
+ if (out_set)
+ {
+ if (reg_mentioned_p (SET_DEST (out_set), SET_DEST (in_exp)))
+ return false;
+ }
+ else
+ {
+ out_pat = PATTERN (out_insn);
+ gcc_assert (GET_CODE (out_pat) == PARALLEL);
+
+ for (j = 0; j < XVECLEN (out_pat, 0); j++)
+ {
+ out_exp = XVECEXP (out_pat, 0, j);
+
+ if (GET_CODE (out_exp) == CLOBBER)
+ continue;
+
+ gcc_assert (GET_CODE (out_exp) == SET);
+
+ if (reg_mentioned_p (SET_DEST (out_exp), SET_DEST (in_exp)))
+ return false;
+ }
+ }
+ }
}
return true;
return (optimize > 0 && flag_peephole2);
}
-static void
+static unsigned int
rest_of_handle_peephole2 (void)
{
#ifdef HAVE_peephole2
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 =