/* 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, 2006, 2007
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GCC.
#include "basic-block.h"
#include "output.h"
#include "reload.h"
+#include "target.h"
#include "timevar.h"
#include "tree-pass.h"
#include "df.h"
#endif
#endif
-static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx);
+#ifndef HAVE_ATTR_enabled
+static inline bool
+get_attr_enabled (rtx insn ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+#endif
+
+static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx, bool);
static void validate_replace_src_1 (rtx *, void *);
static rtx split_insn (rtx);
This should be 0 if you are generating rtl, such as if you are calling
the functions in optabs.c and expmed.c (most of the time).
This should be 1 if all valid insns need to be recognized,
- such as in regclass.c and final.c and reload.c.
+ such as in reginfo.c and final.c and reload.c.
init_recog and init_recog_no_volatile are responsible for setting this. */
if (noperands == 0)
return 1;
- operands = alloca (noperands * sizeof (rtx));
- constraints = alloca (noperands * sizeof (char *));
+ operands = XALLOCAVEC (rtx, noperands);
+ constraints = XALLOCAVEC (const char *, noperands);
decode_asm_operands (x, operands, NULL, constraints, NULL, NULL);
const char *c = constraints[i];
if (c[0] == '%')
c++;
- if (ISDIGIT ((unsigned char) c[0]) && c[1] == '\0')
- c = constraints[c[0] - '0'];
-
- if (! asm_operand_ok (operands[i], c))
+ if (! asm_operand_ok (operands[i], c, constraints))
return 0;
}
static int num_changes = 0;
/* Validate a proposed change to OBJECT. LOC is the location in the rtl
- at which NEW will be placed. If OBJECT is zero, no validation is done,
+ at which NEW_RTX will be placed. If OBJECT is zero, no validation is done,
the change is simply made.
Two types of objects are supported: If OBJECT is a MEM, memory_address_p
Otherwise, perform the change and return 1. */
static bool
-validate_change_1 (rtx object, rtx *loc, rtx new, bool in_group, bool unshare)
+validate_change_1 (rtx object, rtx *loc, rtx new_rtx, bool in_group, bool unshare)
{
rtx old = *loc;
- if (old == new || rtx_equal_p (old, new))
+ if (old == new_rtx || rtx_equal_p (old, new_rtx))
return 1;
gcc_assert (in_group != 0 || num_changes == 0);
- *loc = new;
+ *loc = new_rtx;
/* Save the information describing this change. */
if (num_changes >= changes_allocated)
else
changes_allocated *= 2;
- changes = xrealloc (changes, sizeof (change_t) * changes_allocated);
+ changes = XRESIZEVEC (change_t, changes, changes_allocated);
}
changes[num_changes].object = object;
UNSHARE to false. */
bool
-validate_change (rtx object, rtx *loc, rtx new, bool in_group)
+validate_change (rtx object, rtx *loc, rtx new_rtx, bool in_group)
{
- return validate_change_1 (object, loc, new, in_group, false);
+ return validate_change_1 (object, loc, new_rtx, in_group, false);
}
/* Wrapper for validate_change_1 without the UNSHARE argument defaulting
UNSHARE to true. */
bool
-validate_unshare_change (rtx object, rtx *loc, rtx new, bool in_group)
+validate_unshare_change (rtx object, rtx *loc, rtx new_rtx, bool in_group)
{
- return validate_change_1 (object, loc, new, in_group, true);
+ return validate_change_1 (object, loc, new_rtx, in_group, true);
}
if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
break;
}
+ else if (REG_P (changes[i].old)
+ && asm_noperands (PATTERN (object)) > 0
+ && REG_EXPR (changes[i].old) != NULL_TREE
+ && DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (changes[i].old))
+ && DECL_REGISTER (REG_EXPR (changes[i].old)))
+ {
+ /* Don't allow changes of hard register operands to inline
+ assemblies if they have been defined as register asm ("x"). */
+ break;
+ }
else if (insn_invalid_p (object))
{
rtx pat = PATTERN (object);
if (changes[i].unshare)
*changes[i].loc = copy_rtx (*changes[i].loc);
- /* Avoid unnecesary rescaning when multiple changes to same instruction
+ /* Avoid unnecessary rescanning when multiple changes to same instruction
are made. */
if (object)
{
num_changes = num;
}
-/* Replace every occurrence of FROM in X with TO. Mark each change with
- validate_change passing OBJECT. */
+/* A subroutine of validate_replace_rtx_1 that tries to simplify the resulting
+ rtx. */
static void
-validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object)
+simplify_while_replacing (rtx *loc, rtx to, rtx object,
+ enum machine_mode op0_mode)
{
- int i, j;
- const char *fmt;
rtx x = *loc;
- enum rtx_code code;
- enum machine_mode op0_mode = VOIDmode;
- int prev_changes = num_changes;
- rtx new;
-
- if (!x)
- return;
-
- code = GET_CODE (x);
- fmt = GET_RTX_FORMAT (code);
- if (fmt[0] == 'e')
- op0_mode = GET_MODE (XEXP (x, 0));
-
- /* X matches FROM if it is the same rtx or they are both referring to the
- same register in the same mode. Avoid calling rtx_equal_p unless the
- operands look similar. */
-
- if (x == from
- || (REG_P (x) && REG_P (from)
- && GET_MODE (x) == GET_MODE (from)
- && REGNO (x) == REGNO (from))
- || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from)
- && rtx_equal_p (x, from)))
- {
- validate_unshare_change (object, loc, to, 1);
- return;
- }
-
- /* Call ourself recursively to perform the replacements.
- We must not replace inside already replaced expression, otherwise we
- get infinite recursion for replacements like (reg X)->(subreg (reg X))
- done by regmove, so we must special case shared ASM_OPERANDS. */
-
- if (GET_CODE (x) == PARALLEL)
- {
- for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
- {
- if (j && GET_CODE (XVECEXP (x, 0, j)) == SET
- && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS)
- {
- /* Verify that operands are really shared. */
- 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);
- }
- else
- validate_replace_rtx_1 (&XVECEXP (x, 0, j), from, to, object);
- }
- }
- else
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
- }
-
- /* If we didn't substitute, there is nothing more to do. */
- if (num_changes == prev_changes)
- return;
-
- /* Allow substituted expression to have different mode. This is used by
- regmove to change mode of pseudo register. */
- if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode)
- op0_mode = GET_MODE (XEXP (x, 0));
-
- /* Do changes needed to keep rtx consistent. Don't do any other
- simplifications, as it is not our job. */
+ enum rtx_code code = GET_CODE (x);
+ rtx new_rtx;
if (SWAPPABLE_OPERANDS_P (x)
&& swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
{
- validate_change (object, loc,
- gen_rtx_fmt_ee (COMMUTATIVE_ARITH_P (x) ? code
- : swap_condition (code),
- GET_MODE (x), XEXP (x, 1),
- XEXP (x, 0)), 1);
+ validate_unshare_change (object, loc,
+ gen_rtx_fmt_ee (COMMUTATIVE_ARITH_P (x) ? code
+ : swap_condition (code),
+ GET_MODE (x), XEXP (x, 1),
+ XEXP (x, 0)), 1);
x = *loc;
code = GET_CODE (x);
}
simplify_gen_binary to try to simplify it.
??? We may want later to remove this, once simplification is
separated from this function. */
- if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
+ if (CONST_INT_P (XEXP (x, 1)) && XEXP (x, 1) == to)
validate_change (object, loc,
simplify_gen_binary
(PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
break;
case MINUS:
- if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ if (CONST_INT_P (XEXP (x, 1))
|| GET_CODE (XEXP (x, 1)) == CONST_DOUBLE)
validate_change (object, loc,
simplify_gen_binary
case SIGN_EXTEND:
if (GET_MODE (XEXP (x, 0)) == VOIDmode)
{
- new = simplify_gen_unary (code, GET_MODE (x), XEXP (x, 0),
+ new_rtx = simplify_gen_unary (code, GET_MODE (x), XEXP (x, 0),
op0_mode);
/* If any of the above failed, substitute in something that
we know won't be recognized. */
- if (!new)
- new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
- validate_change (object, loc, new, 1);
+ if (!new_rtx)
+ new_rtx = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+ validate_change (object, loc, new_rtx, 1);
}
break;
case SUBREG:
/* All subregs possible to simplify should be simplified. */
- new = simplify_subreg (GET_MODE (x), SUBREG_REG (x), op0_mode,
+ new_rtx = simplify_subreg (GET_MODE (x), SUBREG_REG (x), op0_mode,
SUBREG_BYTE (x));
/* Subregs of VOIDmode operands are incorrect. */
- if (!new && GET_MODE (SUBREG_REG (x)) == VOIDmode)
- new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
- if (new)
- validate_change (object, loc, new, 1);
+ if (!new_rtx && GET_MODE (SUBREG_REG (x)) == VOIDmode)
+ new_rtx = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+ if (new_rtx)
+ validate_change (object, loc, new_rtx, 1);
break;
case ZERO_EXTRACT:
case SIGN_EXTRACT:
happen, we might just fail in some cases). */
if (MEM_P (XEXP (x, 0))
- && GET_CODE (XEXP (x, 1)) == CONST_INT
- && GET_CODE (XEXP (x, 2)) == CONST_INT
+ && CONST_INT_P (XEXP (x, 1))
+ && CONST_INT_P (XEXP (x, 2))
&& !mode_dependent_address_p (XEXP (XEXP (x, 0), 0))
&& !MEM_VOLATILE_P (XEXP (x, 0)))
{
}
}
+/* Replace every occurrence of FROM in X with TO. Mark each change with
+ validate_change passing OBJECT. */
+
+static void
+validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
+ bool simplify)
+{
+ int i, j;
+ const char *fmt;
+ rtx x = *loc;
+ enum rtx_code code;
+ enum machine_mode op0_mode = VOIDmode;
+ int prev_changes = num_changes;
+
+ if (!x)
+ return;
+
+ code = GET_CODE (x);
+ fmt = GET_RTX_FORMAT (code);
+ if (fmt[0] == 'e')
+ op0_mode = GET_MODE (XEXP (x, 0));
+
+ /* X matches FROM if it is the same rtx or they are both referring to the
+ same register in the same mode. Avoid calling rtx_equal_p unless the
+ operands look similar. */
+
+ if (x == from
+ || (REG_P (x) && REG_P (from)
+ && GET_MODE (x) == GET_MODE (from)
+ && REGNO (x) == REGNO (from))
+ || (GET_CODE (x) == GET_CODE (from) && GET_MODE (x) == GET_MODE (from)
+ && rtx_equal_p (x, from)))
+ {
+ validate_unshare_change (object, loc, to, 1);
+ return;
+ }
+
+ /* Call ourself recursively to perform the replacements.
+ We must not replace inside already replaced expression, otherwise we
+ get infinite recursion for replacements like (reg X)->(subreg (reg X))
+ done by regmove, so we must special case shared ASM_OPERANDS. */
+
+ if (GET_CODE (x) == PARALLEL)
+ {
+ for (j = XVECLEN (x, 0) - 1; j >= 0; j--)
+ {
+ if (j && GET_CODE (XVECEXP (x, 0, j)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (x, 0, j))) == ASM_OPERANDS)
+ {
+ /* Verify that operands are really shared. */
+ 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, simplify);
+ }
+ else
+ validate_replace_rtx_1 (&XVECEXP (x, 0, j), from, to, object,
+ simplify);
+ }
+ }
+ else
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ validate_replace_rtx_1 (&XEXP (x, i), from, to, object, simplify);
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object,
+ simplify);
+ }
+
+ /* If we didn't substitute, there is nothing more to do. */
+ if (num_changes == prev_changes)
+ return;
+
+ /* Allow substituted expression to have different mode. This is used by
+ regmove to change mode of pseudo register. */
+ if (fmt[0] == 'e' && GET_MODE (XEXP (x, 0)) != VOIDmode)
+ op0_mode = GET_MODE (XEXP (x, 0));
+
+ /* Do changes needed to keep rtx consistent. Don't do any other
+ simplifications, as it is not our job. */
+ if (simplify)
+ simplify_while_replacing (loc, to, object, op0_mode);
+}
+
+/* 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, true);
+ 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. */
int
validate_replace_rtx (rtx from, rtx to, rtx insn)
{
- validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
+ validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true);
return apply_change_group ();
}
+/* Try replacing every occurrence of FROM in WHERE with TO. Assume that WHERE
+ is a part of INSN. After all changes have been made, validate by seeing if
+ INSN is still valid.
+ validate_replace_rtx (from, to, insn) is equivalent to
+ validate_replace_rtx_part (from, to, &PATTERN (insn), insn). */
+
+int
+validate_replace_rtx_part (rtx from, rtx to, rtx *where, rtx insn)
+{
+ validate_replace_rtx_1 (where, from, to, insn, true);
+ return apply_change_group ();
+}
+
+/* Same as above, but do not simplify rtx afterwards. */
+int
+validate_replace_rtx_part_nosimplify (rtx from, rtx to, rtx *where,
+ rtx insn)
+{
+ validate_replace_rtx_1 (where, from, to, insn, false);
+ return apply_change_group ();
+
+}
+
/* Try replacing every occurrence of FROM in INSN with TO. */
void
validate_replace_rtx_group (rtx from, rtx to, rtx insn)
{
- validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
+ validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true);
}
/* Function called by note_uses to replace used subexpressions. */
struct validate_replace_src_data *d
= (struct validate_replace_src_data *) data;
- validate_replace_rtx_1 (x, d->from, d->to, d->insn);
+ validate_replace_rtx_1 (x, d->from, d->to, d->insn, true);
}
/* Try replacing every occurrence of FROM in INSN with TO, avoiding
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
int
const_int_operand (rtx op, enum machine_mode mode)
{
- if (GET_CODE (op) != CONST_INT)
+ if (!CONST_INT_P (op))
return 0;
if (mode != VOIDmode
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
- return ((GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)
+ return ((GET_CODE (op) == CONST_DOUBLE || CONST_INT_P (op))
&& (mode == VOIDmode || GET_MODE (op) == mode
|| GET_MODE (op) == VOIDmode));
}
&& GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
return 0;
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& mode != VOIDmode
&& trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
return 0;
if (GET_CODE (op) != PRE_MODIFY
|| GET_CODE (XEXP (op, 1)) != PLUS
|| XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
- || GET_CODE (XEXP (XEXP (op, 1), 1)) != CONST_INT
+ || !CONST_INT_P (XEXP (XEXP (op, 1), 1))
#ifdef STACK_GROWS_DOWNWARD
|| INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
#else
int
memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr)
{
+#ifdef GO_IF_LEGITIMATE_ADDRESS
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
return 0;
win:
return 1;
+#else
+ return targetm.legitimate_address_p (mode, addr, 0);
+#endif
}
/* Return 1 if OP is a valid memory reference with mode MODE,
return ((offset == 0 && general_operand (XEXP (inner, 0), Pmode))
|| (GET_CODE (XEXP (inner, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (inner, 0), 1)) == CONST_INT
+ && CONST_INT_P (XEXP (XEXP (inner, 0), 1))
&& INTVAL (XEXP (XEXP (inner, 0), 1)) == -offset
&& general_operand (XEXP (XEXP (inner, 0), 0), Pmode)));
}
&& general_operand (XEXP (op, 0), Pmode));
}
+/* Return 1 if this is an ordered comparison operator (not including
+ ORDERED and UNORDERED). */
+
+int
+ordered_comparison_operator (rtx op, enum machine_mode mode)
+{
+ if (mode != VOIDmode && GET_MODE (op) != mode)
+ return false;
+ switch (GET_CODE (op))
+ {
+ case EQ:
+ case NE:
+ case LT:
+ case LTU:
+ case LE:
+ case LEU:
+ case GT:
+ case GTU:
+ case GE:
+ case GEU:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Return 1 if this is a comparison operator. This allows the use of
MATCH_OPERATOR to recognize all the branch insns. */
Otherwise return -1. */
int
-asm_noperands (rtx body)
+asm_noperands (const_rtx body)
{
switch (GET_CODE (body))
{
}
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
- }
+ *loc = ASM_OPERANDS_SOURCE_LOCATION (asmop);
return ASM_OPERANDS_TEMPLATE (asmop);
}
Return > 0 if ok, = 0 if bad, < 0 if inconclusive. */
int
-asm_operand_ok (rtx op, const char *constraint)
+asm_operand_ok (rtx op, const char *constraint, const char **constraints)
{
int result = 0;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- /* For best results, our caller should have given us the
- proper matching constraint, but we can't actually fail
- the check if they didn't. Indicate that results are
- inconclusive. */
- do
- constraint++;
- while (ISDIGIT (*constraint));
- if (! result)
- result = -1;
+ /* If caller provided constraints pointer, look up
+ the maching constraint. Otherwise, our caller should have
+ given us the proper matching constraint, but we can't
+ actually fail the check if they didn't. Indicate that
+ results are inconclusive. */
+ if (constraints)
+ {
+ char *end;
+ unsigned long match;
+
+ match = strtoul (constraint, &end, 10);
+ if (!result)
+ result = asm_operand_ok (op, constraints[match], NULL);
+ constraint = (const char *) end;
+ }
+ else
+ {
+ do
+ constraint++;
+ while (ISDIGIT (*constraint));
+ if (! result)
+ result = -1;
+ }
continue;
case 'p':
result = 1;
break;
- case 'm':
+ case TARGET_MEM_CONSTRAINT:
case 'V': /* non-offsettable */
if (memory_operand (op, VOIDmode))
result = 1;
break;
case 's':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
break;
break;
case 'n':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
result = 1;
break;
case 'I':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
result = 1;
break;
case 'J':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
result = 1;
break;
case 'K':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
result = 1;
break;
case 'L':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
result = 1;
break;
case 'M':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
result = 1;
break;
case 'N':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
result = 1;
break;
case 'O':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
result = 1;
break;
case 'P':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
result = 1;
break;
result = 1;
}
#ifdef EXTRA_CONSTRAINT_STR
+ else if (EXTRA_MEMORY_CONSTRAINT (c, constraint))
+ /* Every memory operand can be reloaded to fit. */
+ result = result || memory_operand (op, VOIDmode);
+ else if (EXTRA_ADDRESS_CONSTRAINT (c, constraint))
+ /* Every address operand can be reloaded to fit. */
+ result = result || address_operand (op, VOIDmode);
else if (EXTRA_CONSTRAINT_STR (op, c, constraint))
result = 1;
- else if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
- /* Every memory operand can be reloaded to fit. */
- && memory_operand (op, VOIDmode))
- result = 1;
- else if (EXTRA_ADDRESS_CONSTRAINT (c, constraint)
- /* Every address operand can be reloaded to fit. */
- && address_operand (op, VOIDmode))
- result = 1;
#endif
break;
}
int noperands;
rtx body = PATTERN (insn);
- recog_data.insn = NULL;
recog_data.n_operands = 0;
recog_data.n_alternatives = 0;
recog_data.n_dups = 0;
- which_alternative = -1;
switch (GET_CODE (body))
{
: OP_IN);
gcc_assert (recog_data.n_alternatives <= MAX_RECOG_ALTERNATIVES);
+
+ if (INSN_CODE (insn) < 0)
+ for (i = 0; i < recog_data.n_alternatives; i++)
+ recog_data.alternative_enabled_p[i] = true;
+ else
+ {
+ recog_data.insn = insn;
+ for (i = 0; i < recog_data.n_alternatives; i++)
+ {
+ which_alternative = i;
+ recog_data.alternative_enabled_p[i] = get_attr_enabled (insn);
+ }
+ }
+
+ recog_data.insn = NULL;
+ which_alternative = -1;
}
/* After calling extract_insn, you can use this function to extract some
op_alt[j].matches = -1;
op_alt[j].matched = -1;
+ if (!recog_data.alternative_enabled_p[j])
+ {
+ p = skip_alternative (p);
+ continue;
+ }
+
if (*p == '\0' || *p == ',')
{
op_alt[j].anything_ok = 1;
}
continue;
- case 'm':
+ case TARGET_MEM_CONSTRAINT:
op_alt[j].memory_ok = 1;
break;
case '<':
struct funny_match
{
- int this, other;
+ int this_op, other;
};
int
int lose = 0;
funny_match_index = 0;
+ if (!recog_data.alternative_enabled_p[which_alternative])
+ {
+ int i;
+
+ for (i = 0; i < recog_data.n_operands; i++)
+ constraints[i] = skip_alternative (constraints[i]);
+
+ which_alternative++;
+ continue;
+ }
+
for (opno = 0; opno < recog_data.n_operands; opno++)
{
rtx op = recog_data.operand[opno];
output op is the one that will be printed. */
if (val == 2 && strict > 0)
{
- funny_match[funny_match_index].this = opno;
+ funny_match[funny_match_index].this_op = opno;
funny_match[funny_match_index++].other = match;
}
}
win = 1;
break;
- case 'm':
+ case TARGET_MEM_CONSTRAINT:
/* Memory operands must be valid, to the extent
required by STRICT. */
if (MEM_P (op))
break;
case 's':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
break;
break;
case 'n':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
win = 1;
case 'N':
case 'O':
case 'P':
- if (GET_CODE (op) == CONST_INT
+ if (CONST_INT_P (op)
&& CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
win = 1;
break;
while (--funny_match_index >= 0)
{
recog_data.operand[funny_match[funny_match_index].other]
- = recog_data.operand[funny_match[funny_match_index].this];
+ = recog_data.operand[funny_match[funny_match_index].this_op];
}
return 1;
/* Split insns here to get max fine-grain parallelism. */
rtx first = PREV_INSN (insn);
rtx last = try_split (PATTERN (insn), insn, 1);
+ rtx insn_set, last_set, note;
if (last == insn)
return NULL_RTX;
+ /* If the original instruction was a single set that was known to be
+ equivalent to a constant, see if we can say the same about the last
+ instruction in the split sequence. The two instructions must set
+ the same destination. */
+ insn_set = single_set (insn);
+ if (insn_set)
+ {
+ last_set = single_set (last);
+ if (last_set && rtx_equal_p (SET_DEST (last_set), SET_DEST (insn_set)))
+ {
+ note = find_reg_equal_equiv_note (insn);
+ if (note && CONSTANT_P (XEXP (note, 0)))
+ set_unique_reg_note (last, REG_EQUAL, XEXP (note, 0));
+ else if (CONSTANT_P (SET_SRC (insn_set)))
+ set_unique_reg_note (last, REG_EQUAL, SET_SRC (insn_set));
+ }
+ }
+
/* try_split returns the NOTE that INSN became. */
SET_INSN_DELETED (insn);
first = NEXT_INSN (first);
}
}
+
return last;
}
rtx insn, next;
bool finish = false;
+ rtl_profile_for_bb (bb);
for (insn = BB_HEAD (bb); !finish ; insn = next)
{
/* Can't use `next_real_insn' because that might go across
/* Don't split no-op move insns. These should silently
disappear later in final. Splitting such insns would
- break the code that handles REG_NO_CONFLICT blocks. */
+ break the code that handles LIBCALL blocks. */
if (set && set_noop_p (set))
{
/* Nops get in the way while scheduling, so delete them
}
}
+ default_rtl_profile ();
if (changed)
find_many_sub_basic_blocks (blocks);
{
/* Don't split no-op move insns. These should silently
disappear later in final. Splitting such insns would
- break the code that handles REG_NO_CONFLICT blocks. */
+ break the code that handles LIBCALL blocks. */
rtx set = single_set (insn);
if (set && set_noop_p (set))
{
/* Don't allocate fixed registers. */
if (fixed_regs[regno])
continue;
+ /* Don't allocate global registers. */
+ if (global_regs[regno])
+ continue;
/* Make sure the register is of the right class. */
if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno))
continue;
/* And that we don't create an extra save/restore. */
if (! call_used_regs[regno] && ! df_regs_ever_live_p (regno))
continue;
+ if (! targetm.hard_regno_scratch_ok (regno))
+ continue;
+
/* And we don't clobber traceback for noreturn functions. */
if ((regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM)
&& (! reload_completed || frame_pointer_needed))
return NULL_RTX;
}
+/* Forget all currently tracked instructions, only remember current
+ LIVE regset. */
+
+static void
+peep2_reinit_state (regset live)
+{
+ int i;
+
+ /* 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;
+
+ COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
+}
+
/* Perform the peephole2 optimization pass. */
static void
FOR_EACH_BB_REVERSE (bb)
{
- /* 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;
+ rtl_profile_for_bb (bb);
/* Start up propagation. */
bitmap_copy (live, DF_LR_OUT (bb));
- df_simulate_artificial_refs_at_end (bb, live);
- bitmap_copy (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
+ df_simulate_initialize_backwards (bb, live);
+ peep2_reinit_state (live);
for (insn = BB_END (bb); ; insn = prev)
{
prev = PREV_INSN (insn);
if (INSN_P (insn))
{
- rtx try, before_try, x;
+ rtx attempt, before_try, x;
int match_len;
rtx note;
bool was_call = false;
/* 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;
+ peep2_reinit_state (live);
+ attempt = NULL;
}
else
/* Match the peephole. */
- try = peephole2_insns (PATTERN (insn), insn, &match_len);
+ attempt = peephole2_insns (PATTERN (insn), insn, &match_len);
- if (try != NULL)
+ if (attempt != NULL)
{
/* If we are splitting a CALL_INSN, look for the CALL_INSN
in SEQ and copy our CALL_INSN_FUNCTION_USAGE and other
continue;
was_call = true;
- new_insn = try;
+ new_insn = attempt;
while (new_insn != NULL_RTX)
{
if (CALL_P (new_insn))
{
case REG_NORETURN:
case REG_SETJMP:
- REG_NOTES (new_insn)
- = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
- XEXP (note, 0),
- REG_NOTES (new_insn));
+ add_reg_note (new_insn, REG_NOTE_KIND (note),
+ XEXP (note, 0));
+ break;
default:
/* Discard all other reg notes. */
break;
REG_EH_REGION, NULL_RTX);
/* Replace the old sequence with the new. */
- try = emit_insn_after_setloc (try, peep2_insn_data[i].insn,
- INSN_LOCATOR (peep2_insn_data[i].insn));
+ attempt = emit_insn_after_setloc (attempt,
+ peep2_insn_data[i].insn,
+ INSN_LOCATOR (peep2_insn_data[i].insn));
before_try = PREV_INSN (insn);
delete_insn_chain (insn, peep2_insn_data[i].insn, false);
if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
break;
- for (x = try ; x != before_try ; x = PREV_INSN (x))
+ for (x = attempt ; x != before_try ; x = PREV_INSN (x))
if (CALL_P (x)
|| (flag_non_call_exceptions
&& may_trap_p (PATTERN (x))
&& !find_reg_note (x, REG_EH_REGION, NULL)))
{
if (note)
- REG_NOTES (x)
- = gen_rtx_EXPR_LIST (REG_EH_REGION,
- XEXP (note, 0),
- REG_NOTES (x));
+ add_reg_note (x, REG_EH_REGION, XEXP (note, 0));
if (x != BB_END (bb) && eh_edge)
{
bitmap_copy (live, peep2_insn_data[i].live_before);
/* Update life information for the new sequence. */
- x = try;
+ x = attempt;
do
{
if (INSN_P (x))
/* 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))
+ for (x = attempt; x != before_try; x = PREV_INSN (x))
if (JUMP_P (x))
{
do_rebuild_jump_labels = true;
}
}
+ default_rtl_profile ();
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
BITMAP_FREE (peep2_insn_data[i].live_before);
BITMAP_FREE (live);
return 0;
}
-struct tree_opt_pass pass_peephole2 =
+struct rtl_opt_pass pass_peephole2 =
{
+ {
+ RTL_PASS,
"peephole2", /* name */
gate_handle_peephole2, /* gate */
rest_of_handle_peephole2, /* execute */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_df_finish |
- TODO_dump_func, /* todo_flags_finish */
- 'z' /* letter */
+ TODO_df_finish | TODO_verify_rtl_sharing |
+ TODO_dump_func /* todo_flags_finish */
+ }
};
static unsigned int
return 0;
}
-struct tree_opt_pass pass_split_all_insns =
+struct rtl_opt_pass pass_split_all_insns =
{
+ {
+ RTL_PASS,
"split1", /* name */
NULL, /* gate */
rest_of_handle_split_all_insns, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
static unsigned int
return 0;
}
-struct tree_opt_pass pass_split_after_reload =
+struct rtl_opt_pass pass_split_after_reload =
{
+ {
+ RTL_PASS,
"split2", /* name */
NULL, /* gate */
rest_of_handle_split_after_reload, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
static bool
return 0;
}
-struct tree_opt_pass pass_split_before_regstack =
+struct rtl_opt_pass pass_split_before_regstack =
{
+ {
+ RTL_PASS,
"split3", /* name */
gate_handle_split_before_regstack, /* gate */
rest_of_handle_split_before_regstack, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
static bool
return 0;
}
-struct tree_opt_pass pass_split_before_sched2 =
+struct rtl_opt_pass pass_split_before_sched2 =
{
+ {
+ RTL_PASS,
"split4", /* name */
gate_handle_split_before_sched2, /* gate */
rest_of_handle_split_before_sched2, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_verify_flow |
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
/* The placement of the splitting that we do for shorten_branches
#endif
}
-struct tree_opt_pass pass_split_for_shorten_branches =
+struct rtl_opt_pass pass_split_for_shorten_branches =
{
+ {
+ RTL_PASS,
"split5", /* name */
gate_do_final_split, /* gate */
split_all_insns_noflow, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */
+ }
};
-
-