/* 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, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
+#include "tree.h"
#include "rtl-error.h"
#include "tm_p.h"
#include "insn-config.h"
#include "recog.h"
#include "regs.h"
#include "addresses.h"
-#include "expr.h"
#include "function.h"
+#include "rtl.h"
#include "flags.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
#include "basic-block.h"
#include "reload.h"
#include "target.h"
#include "df.h"
#include "insn-codes.h"
-#ifndef STACK_PUSH_CODE
-#ifdef STACK_GROWS_DOWNWARD
-#define STACK_PUSH_CODE PRE_DEC
-#else
-#define STACK_PUSH_CODE PRE_INC
-#endif
-#endif
-
#ifndef STACK_POP_CODE
-#ifdef STACK_GROWS_DOWNWARD
+#if STACK_GROWS_DOWNWARD
#define STACK_POP_CODE POST_INC
#else
#define STACK_POP_CODE POST_DEC
#endif
#endif
-static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx, bool);
+static void validate_replace_rtx_1 (rtx *, rtx, rtx, rtx_insn *, bool);
static void validate_replace_src_1 (rtx *, void *);
-static rtx split_insn (rtx);
+static rtx_insn *split_insn (rtx_insn *);
+
+struct target_recog default_target_recog;
+#if SWITCHABLE_TARGET
+struct target_recog *this_target_recog = &default_target_recog;
+#endif
/* Nonzero means allow operands to be volatile.
This should be 0 if you are generating rtl, such as if you are calling
int volatile_ok;
-struct recog_data recog_data;
+struct recog_data_d recog_data;
-/* Contains a vector of operand_alternative structures for every operand.
+/* Contains a vector of operand_alternative structures, such that
+ operand OP of alternative A is at index A * n_operands + OP.
Set up by preprocess_constraints. */
-struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
+const operand_alternative *recog_op_alt;
+
+/* Used to provide recog_op_alt for asms. */
+static operand_alternative asm_op_alt[MAX_RECOG_OPERANDS
+ * MAX_RECOG_ALTERNATIVES];
/* On return from `constrain_operands', indicate which alternative
was satisfied. */
if (reload_completed)
{
/* ??? Doh! We've not got the wrapping insn. Cook one up. */
- extract_insn (make_insn_raw (x));
- constrain_operands (1);
+ rtx_insn *insn = make_insn_raw (x);
+ extract_insn (insn);
+ constrain_operands (1, get_enabled_alternatives (insn));
return which_alternative >= 0;
}
Return true if anything was changed. */
bool
-canonicalize_change_group (rtx insn, rtx x)
+canonicalize_change_group (rtx_insn *insn, rtx x)
{
if (COMMUTATIVE_P (x)
&& swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
Otherwise the changes will take effect immediately. */
int
-insn_invalid_p (rtx insn, bool in_group)
+insn_invalid_p (rtx_insn *insn, bool in_group)
{
rtx pat = PATTERN (insn);
int num_clobbers = 0;
clobbers. */
int icode = recog (pat, insn,
(GET_CODE (pat) == SET
- && ! reload_completed && ! reload_in_progress)
+ && ! reload_completed
+ && ! reload_in_progress)
? &num_clobbers : 0);
int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
{
extract_insn (insn);
- if (! constrain_operands (1))
+ if (! constrain_operands (1, get_preferred_alternatives (insn)))
return 1;
}
MEM_ADDR_SPACE (object)))
break;
}
- else if (REG_P (changes[i].old)
+ else if (/* changes[i].old might be zero, e.g. when putting a
+ REG_FRAME_RELATED_EXPR into a previously empty list. */
+ changes[i].old
+ && 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))
}
else if (DEBUG_INSN_P (object))
continue;
- else if (insn_invalid_p (object, true))
+ else if (insn_invalid_p (as_a <rtx_insn *> (object), true))
{
rtx pat = PATTERN (object);
if (object)
{
if (object != last_object && last_object && INSN_P (last_object))
- df_insn_rescan (last_object);
+ df_insn_rescan (as_a <rtx_insn *> (last_object));
last_object = object;
}
}
if (last_object && INSN_P (last_object))
- df_insn_rescan (last_object);
+ df_insn_rescan (as_a <rtx_insn *> (last_object));
num_changes = 0;
}
rtx. */
static void
-simplify_while_replacing (rtx *loc, rtx to, rtx object,
- enum machine_mode op0_mode)
+simplify_while_replacing (rtx *loc, rtx to, rtx_insn *object,
+ machine_mode op0_mode)
{
rtx x = *loc;
enum rtx_code code = GET_CODE (x);
- rtx new_rtx;
+ rtx new_rtx = NULL_RTX;
if (SWAPPABLE_OPERANDS_P (x)
&& swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
code = GET_CODE (x);
}
+ /* Canonicalize arithmetics with all constant operands. */
+ switch (GET_RTX_CLASS (code))
+ {
+ case RTX_UNARY:
+ if (CONSTANT_P (XEXP (x, 0)))
+ new_rtx = simplify_unary_operation (code, GET_MODE (x), XEXP (x, 0),
+ op0_mode);
+ break;
+ case RTX_COMM_ARITH:
+ case RTX_BIN_ARITH:
+ if (CONSTANT_P (XEXP (x, 0)) && CONSTANT_P (XEXP (x, 1)))
+ new_rtx = simplify_binary_operation (code, GET_MODE (x), XEXP (x, 0),
+ XEXP (x, 1));
+ break;
+ case RTX_COMPARE:
+ case RTX_COMM_COMPARE:
+ if (CONSTANT_P (XEXP (x, 0)) && CONSTANT_P (XEXP (x, 1)))
+ new_rtx = simplify_relational_operation (code, GET_MODE (x), op0_mode,
+ XEXP (x, 0), XEXP (x, 1));
+ break;
+ default:
+ break;
+ }
+ if (new_rtx)
+ {
+ validate_change (object, loc, new_rtx, 1);
+ return;
+ }
+
switch (code)
{
case PLUS:
MEM_ADDR_SPACE (XEXP (x, 0)))
&& !MEM_VOLATILE_P (XEXP (x, 0)))
{
- enum machine_mode wanted_mode = VOIDmode;
- enum machine_mode is_mode = GET_MODE (XEXP (x, 0));
+ machine_mode wanted_mode = VOIDmode;
+ machine_mode is_mode = GET_MODE (XEXP (x, 0));
int pos = INTVAL (XEXP (x, 2));
if (GET_CODE (x) == ZERO_EXTRACT && HAVE_extzv)
validate_change passing OBJECT. */
static void
-validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
+validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx_insn *object,
bool simplify)
{
int i, j;
const char *fmt;
rtx x = *loc;
enum rtx_code code;
- enum machine_mode op0_mode = VOIDmode;
+ machine_mode op0_mode = VOIDmode;
int prev_changes = num_changes;
if (!x)
/* 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. */
+ so we must special case shared ASM_OPERANDS. */
if (GET_CODE (x) == PARALLEL)
{
if (num_changes == prev_changes)
return;
+ /* ??? The regmove is no more, so is this aberration still necessary? */
/* 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)
if INSN is still valid. */
int
-validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc)
+validate_replace_rtx_subexp (rtx from, rtx to, rtx_insn *insn, rtx *loc)
{
validate_replace_rtx_1 (loc, from, to, insn, true);
return apply_change_group ();
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 (rtx from, rtx to, rtx_insn *insn)
{
validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true);
return apply_change_group ();
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_part (rtx from, rtx to, rtx *where, rtx_insn *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)
+ rtx_insn *insn)
{
validate_replace_rtx_1 (where, from, to, insn, false);
return apply_change_group ();
will replace in REG_EQUAL and REG_EQUIV notes. */
void
-validate_replace_rtx_group (rtx from, rtx to, rtx insn)
+validate_replace_rtx_group (rtx from, rtx to, rtx_insn *insn)
{
rtx note;
validate_replace_rtx_1 (&PATTERN (insn), from, to, insn, true);
{
rtx from; /* Old RTX */
rtx to; /* New RTX */
- rtx insn; /* Insn in which substitution is occurring. */
+ rtx_insn *insn; /* Insn in which substitution is occurring. */
};
static void
SET_DESTs. */
void
-validate_replace_src_group (rtx from, rtx to, rtx insn)
+validate_replace_src_group (rtx from, rtx to, rtx_insn *insn)
{
struct validate_replace_src_data d;
pattern and return true if something was simplified. */
bool
-validate_simplify_insn (rtx insn)
+validate_simplify_insn (rtx_insn *insn)
{
int i;
rtx pat = NULL;
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
any ordered tests applied to the condition codes.
EQ and NE tests do not count. */
int
-next_insn_tests_no_inequality (rtx insn)
+next_insn_tests_no_inequality (rtx_insn *insn)
{
- rtx next = next_cc0_user (insn);
+ rtx_insn *next = next_cc0_user (insn);
/* If there is no next insn, we have to take the conservative choice. */
if (next == 0)
return (INSN_P (next)
&& ! inequality_comparisons_p (PATTERN (next)));
}
-#endif
\f
/* Return 1 if OP is a valid general operand for machine mode MODE.
This is either a register reference, a memory reference,
expressions in the machine description. */
int
-general_operand (rtx op, enum machine_mode mode)
+general_operand (rtx op, machine_mode mode)
{
enum rtx_code code = GET_CODE (op);
&& MEM_P (sub))
return 0;
+#ifdef CANNOT_CHANGE_MODE_CLASS
+ if (REG_P (sub)
+ && REGNO (sub) < FIRST_PSEUDO_REGISTER
+ && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
+ && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT
+ /* LRA can generate some invalid SUBREGS just for matched
+ operand reload presentation. LRA needs to treat them as
+ valid. */
+ && ! LRA_SUBREG_P (op))
+ return 0;
+#endif
+
/* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally
create such rtl, and we must reject it. */
if (SCALAR_FLOAT_MODE_P (GET_MODE (op))
if (! volatile_ok && MEM_VOLATILE_P (op))
return 0;
- /* Use the mem's mode, since it will be reloaded thus. */
- if (memory_address_addr_space_p (GET_MODE (op), y, MEM_ADDR_SPACE (op)))
+ /* Use the mem's mode, since it will be reloaded thus. LRA can
+ generate move insn with invalid addresses which is made valid
+ and efficiently calculated by LRA through further numerous
+ transformations. */
+ if (lra_in_progress
+ || memory_address_addr_space_p (GET_MODE (op), y, MEM_ADDR_SPACE (op)))
return 1;
}
expressions in the machine description. */
int
-address_operand (rtx op, enum machine_mode mode)
+address_operand (rtx op, machine_mode mode)
{
return memory_address_p (mode, op);
}
expressions in the machine description. */
int
-register_operand (rtx op, enum machine_mode mode)
+register_operand (rtx op, machine_mode mode)
{
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
if (GET_CODE (op) == SUBREG)
{
rtx sub = SUBREG_REG (op);
(Ideally, (SUBREG (MEM)...) should not exist after reload,
but currently it does result from (SUBREG (REG)...) where the
reg went on the stack.) */
- if (! reload_completed && MEM_P (sub))
- return general_operand (op, mode);
-
-#ifdef CANNOT_CHANGE_MODE_CLASS
- if (REG_P (sub)
- && REGNO (sub) < FIRST_PSEUDO_REGISTER
- && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
- && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
- && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT)
+ if (!REG_P (sub) && (reload_completed || !MEM_P (sub)))
return 0;
-#endif
-
- /* FLOAT_MODE subregs can't be paradoxical. Combine will occasionally
- create such rtl, and we must reject it. */
- if (SCALAR_FLOAT_MODE_P (GET_MODE (op))
- /* LRA can use subreg to store a floating point value in an
- integer mode. Although the floating point and the
- integer modes need the same number of hard registers, the
- size of floating point mode can be less than the integer
- mode. */
- && ! lra_in_progress
- && GET_MODE_SIZE (GET_MODE (op)) > GET_MODE_SIZE (GET_MODE (sub)))
- return 0;
-
- op = sub;
}
-
- return (REG_P (op)
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || in_hard_reg_set_p (operand_reg_set,
- GET_MODE (op), REGNO (op))));
+ else if (!REG_P (op))
+ return 0;
+ return general_operand (op, mode);
}
/* Return 1 for a register in Pmode; ignore the tested mode. */
int
-pmode_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+pmode_register_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
{
return register_operand (op, Pmode);
}
or a hard register. */
int
-scratch_operand (rtx op, enum machine_mode mode)
+scratch_operand (rtx op, machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return 0;
return (GET_CODE (op) == SCRATCH
|| (REG_P (op)
- && (lra_in_progress || REGNO (op) < FIRST_PSEUDO_REGISTER)));
+ && (lra_in_progress
+ || (REGNO (op) < FIRST_PSEUDO_REGISTER
+ && REGNO_REG_CLASS (REGNO (op)) != NO_REGS))));
}
/* Return 1 if OP is a valid immediate operand for mode MODE.
expressions in the machine description. */
int
-immediate_operand (rtx op, enum machine_mode mode)
+immediate_operand (rtx op, machine_mode mode)
{
/* Don't accept CONST_INT or anything similar
if the caller wants something floating. */
: mode, op));
}
-/* Returns 1 if OP is an operand that is a CONST_INT. */
+/* Returns 1 if OP is an operand that is a CONST_INT of mode MODE. */
int
-const_int_operand (rtx op, enum machine_mode mode)
+const_int_operand (rtx op, machine_mode mode)
{
if (!CONST_INT_P (op))
return 0;
return 1;
}
+#if TARGET_SUPPORTS_WIDE_INT
+/* Returns 1 if OP is an operand that is a CONST_INT or CONST_WIDE_INT
+ of mode MODE. */
+int
+const_scalar_int_operand (rtx op, machine_mode mode)
+{
+ if (!CONST_SCALAR_INT_P (op))
+ return 0;
+
+ if (CONST_INT_P (op))
+ return const_int_operand (op, mode);
+
+ if (mode != VOIDmode)
+ {
+ int prec = GET_MODE_PRECISION (mode);
+ int bitsize = GET_MODE_BITSIZE (mode);
+
+ if (CONST_WIDE_INT_NUNITS (op) * HOST_BITS_PER_WIDE_INT > bitsize)
+ return 0;
+
+ if (prec == bitsize)
+ return 1;
+ else
+ {
+ /* Multiword partial int. */
+ HOST_WIDE_INT x
+ = CONST_WIDE_INT_ELT (op, CONST_WIDE_INT_NUNITS (op) - 1);
+ return (sext_hwi (x, prec & (HOST_BITS_PER_WIDE_INT - 1)) == x);
+ }
+ }
+ return 1;
+}
+
/* Returns 1 if OP is an operand that is a constant integer or constant
- floating-point number. */
+ floating-point number of MODE. */
int
-const_double_operand (rtx op, enum machine_mode mode)
+const_double_operand (rtx op, machine_mode mode)
+{
+ return (GET_CODE (op) == CONST_DOUBLE)
+ && (GET_MODE (op) == mode || mode == VOIDmode);
+}
+#else
+/* Returns 1 if OP is an operand that is a constant integer or constant
+ floating-point number of MODE. */
+
+int
+const_double_operand (rtx op, machine_mode mode)
{
/* Don't accept CONST_INT or anything similar
if the caller wants something floating. */
&& (mode == VOIDmode || GET_MODE (op) == mode
|| GET_MODE (op) == VOIDmode));
}
-
-/* Return 1 if OP is a general operand that is not an immediate operand. */
+#endif
+/* Return 1 if OP is a general operand that is not an immediate
+ operand of mode MODE. */
int
-nonimmediate_operand (rtx op, enum machine_mode mode)
+nonimmediate_operand (rtx op, machine_mode mode)
{
return (general_operand (op, mode) && ! CONSTANT_P (op));
}
/* Return 1 if OP is a register reference or immediate value of mode MODE. */
int
-nonmemory_operand (rtx op, enum machine_mode mode)
+nonmemory_operand (rtx op, machine_mode mode)
{
if (CONSTANT_P (op))
return immediate_operand (op, mode);
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_CODE (op) == SUBREG)
- {
- /* Before reload, we can allow (SUBREG (MEM...)) as a register operand
- because it is guaranteed to be reloaded into one.
- Just make sure the MEM is valid in itself.
- (Ideally, (SUBREG (MEM)...) should not exist after reload,
- but currently it does result from (SUBREG (REG)...) where the
- reg went on the stack.) */
- if (! reload_completed && MEM_P (SUBREG_REG (op)))
- return general_operand (op, mode);
- op = SUBREG_REG (op);
- }
-
- return (REG_P (op)
- && (REGNO (op) >= FIRST_PSEUDO_REGISTER
- || in_hard_reg_set_p (operand_reg_set,
- GET_MODE (op), REGNO (op))));
+ return register_operand (op, mode);
}
/* Return 1 if OP is a valid operand that stands for pushing a
expressions in the machine description. */
int
-push_operand (rtx op, enum machine_mode mode)
+push_operand (rtx op, machine_mode mode)
{
unsigned int rounded_size = GET_MODE_SIZE (mode);
|| GET_CODE (XEXP (op, 1)) != PLUS
|| XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
|| !CONST_INT_P (XEXP (XEXP (op, 1), 1))
-#ifdef STACK_GROWS_DOWNWARD
- || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
-#else
- || INTVAL (XEXP (XEXP (op, 1), 1)) != (int) rounded_size
-#endif
- )
+ || INTVAL (XEXP (XEXP (op, 1), 1))
+ != ((STACK_GROWS_DOWNWARD ? -1 : 1) * (int) rounded_size))
return 0;
}
expressions in the machine description. */
int
-pop_operand (rtx op, enum machine_mode mode)
+pop_operand (rtx op, machine_mode mode)
{
if (!MEM_P (op))
return 0;
for mode MODE in address space AS. */
int
-memory_address_addr_space_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+memory_address_addr_space_p (machine_mode mode ATTRIBUTE_UNUSED,
rtx addr, addr_space_t as)
{
#ifdef GO_IF_LEGITIMATE_ADDRESS
expressions in the machine description. */
int
-memory_operand (rtx op, enum machine_mode mode)
+memory_operand (rtx op, machine_mode mode)
{
rtx inner;
that is, a memory reference whose address is a general_operand. */
int
-indirect_operand (rtx op, enum machine_mode mode)
+indirect_operand (rtx op, machine_mode mode)
{
/* Before reload, a SUBREG isn't in memory (see memory_operand, above). */
if (! reload_completed
ORDERED and UNORDERED). */
int
-ordered_comparison_operator (rtx op, enum machine_mode mode)
+ordered_comparison_operator (rtx op, machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != mode)
return false;
MATCH_OPERATOR to recognize all the branch insns. */
int
-comparison_operator (rtx op, enum machine_mode mode)
+comparison_operator (rtx op, machine_mode mode)
{
return ((mode == VOIDmode || GET_MODE (op) == mode)
&& COMPARISON_P (op));
const char *
decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
- const char **constraints, enum machine_mode *modes,
+ const char **constraints, machine_mode *modes,
location_t *loc)
{
int nbase = 0, n, i;
return ASM_OPERANDS_TEMPLATE (asmop);
}
+/* Parse inline assembly string STRING and determine which operands are
+ referenced by % markers. For the first NOPERANDS operands, set USED[I]
+ to true if operand I is referenced.
+
+ This is intended to distinguish barrier-like asms such as:
+
+ asm ("" : "=m" (...));
+
+ from real references such as:
+
+ asm ("sw\t$0, %0" : "=m" (...)); */
+
+void
+get_referenced_operands (const char *string, bool *used,
+ unsigned int noperands)
+{
+ memset (used, 0, sizeof (bool) * noperands);
+ const char *p = string;
+ while (*p)
+ switch (*p)
+ {
+ case '%':
+ p += 1;
+ /* A letter followed by a digit indicates an operand number. */
+ if (ISALPHA (p[0]) && ISDIGIT (p[1]))
+ p += 1;
+ if (ISDIGIT (*p))
+ {
+ char *endptr;
+ unsigned long opnum = strtoul (p, &endptr, 10);
+ if (endptr != p && opnum < noperands)
+ used[opnum] = true;
+ p = endptr;
+ }
+ else
+ p += 1;
+ break;
+
+ default:
+ p++;
+ break;
+ }
+}
+
/* Check if an asm_operand matches its constraints.
Return > 0 if ok, = 0 if bad, < 0 if inconclusive. */
while (*constraint)
{
+ enum constraint_num cn;
char c = *constraint;
int len;
switch (c)
case ',':
constraint++;
continue;
- case '=':
- case '+':
- case '*':
- case '%':
- case '!':
- case '#':
- case '&':
- case '?':
- break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* If caller provided constraints pointer, look up
- the maching constraint. Otherwise, our caller should have
+ the matching 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. */
}
continue;
- case 'p':
- if (address_operand (op, VOIDmode))
- result = 1;
- break;
-
- case TARGET_MEM_CONSTRAINT:
- case 'V': /* non-offsettable */
- if (memory_operand (op, VOIDmode))
- result = 1;
- break;
+ /* The rest of the compiler assumes that reloading the address
+ of a MEM into a register will make it fit an 'o' constraint.
+ That is, if it sees a MEM operand for an 'o' constraint,
+ it assumes that (mem (base-reg)) will fit.
+ That assumption fails on targets that don't have offsettable
+ addresses at all. We therefore need to treat 'o' asm
+ constraints as a special case and only accept operands that
+ are already offsettable, thus proving that at least one
+ offsettable address exists. */
case 'o': /* offsettable */
if (offsettable_nonstrict_memref_p (op))
result = 1;
break;
- case '<':
- /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed to exist,
- excepting those that expand_call created. Further, on some
- machines which do not have generalized auto inc/dec, an inc/dec
- is not a memory_operand.
-
- Match any memory and hope things are resolved after reload. */
-
- if (MEM_P (op)
- && (1
- || GET_CODE (XEXP (op, 0)) == PRE_DEC
- || GET_CODE (XEXP (op, 0)) == POST_DEC))
+ case 'g':
+ if (general_operand (op, VOIDmode))
result = 1;
-#ifdef AUTO_INC_DEC
- incdec_ok = true;
-#endif
break;
- case '>':
- if (MEM_P (op)
- && (1
- || GET_CODE (XEXP (op, 0)) == PRE_INC
- || GET_CODE (XEXP (op, 0)) == POST_INC))
- result = 1;
#ifdef AUTO_INC_DEC
+ case '<':
+ case '>':
+ /* ??? Before auto-inc-dec, auto inc/dec insns are not supposed
+ to exist, excepting those that expand_call created. Further,
+ on some machines which do not have generalized auto inc/dec,
+ an inc/dec is not a memory_operand.
+
+ Match any memory and hope things are resolved after reload. */
incdec_ok = true;
#endif
- break;
-
- case 'E':
- case 'F':
- if (CONST_DOUBLE_AS_FLOAT_P (op)
- || (GET_CODE (op) == CONST_VECTOR
- && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
- result = 1;
- break;
-
- case 'G':
- if (CONST_DOUBLE_AS_FLOAT_P (op)
- && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', constraint))
- result = 1;
- break;
- case 'H':
- if (CONST_DOUBLE_AS_FLOAT_P (op)
- && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'H', constraint))
- result = 1;
- break;
-
- case 's':
- if (CONST_SCALAR_INT_P (op))
- break;
- /* Fall through. */
-
- case 'i':
- if (CONSTANT_P (op) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
- result = 1;
- break;
-
- case 'n':
- if (CONST_SCALAR_INT_P (op))
- result = 1;
- break;
+ default:
+ cn = lookup_constraint (constraint);
+ switch (get_constraint_type (cn))
+ {
+ case CT_REGISTER:
+ if (!result
+ && reg_class_for_constraint (cn) != NO_REGS
+ && GET_MODE (op) != BLKmode
+ && register_operand (op, VOIDmode))
+ result = 1;
+ break;
- case 'I':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
- result = 1;
- break;
- case 'J':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
- result = 1;
- break;
- case 'K':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
- result = 1;
- break;
- case 'L':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
- result = 1;
- break;
- case 'M':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
- result = 1;
- break;
- case 'N':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
- result = 1;
- break;
- case 'O':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
- result = 1;
- break;
- case 'P':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
- result = 1;
- break;
+ case CT_CONST_INT:
+ if (!result
+ && CONST_INT_P (op)
+ && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+ result = 1;
+ break;
- case 'X':
- result = 1;
- break;
+ case CT_MEMORY:
+ /* Every memory operand can be reloaded to fit. */
+ result = result || memory_operand (op, VOIDmode);
+ break;
- case 'g':
- if (general_operand (op, VOIDmode))
- result = 1;
- break;
+ case CT_ADDRESS:
+ /* Every address operand can be reloaded to fit. */
+ result = result || address_operand (op, VOIDmode);
+ break;
- default:
- /* For all other letters, we first check for a register class,
- otherwise it is an EXTRA_CONSTRAINT. */
- if (REG_CLASS_FROM_CONSTRAINT (c, constraint) != NO_REGS)
- {
- case 'r':
- if (GET_MODE (op) == BLKmode)
- break;
- if (register_operand (op, VOIDmode))
- result = 1;
+ case CT_FIXED_FORM:
+ result = result || constraint_satisfied_p (op, cn);
+ break;
}
-#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;
-#endif
break;
}
len = CONSTRAINT_LEN (c, constraint);
for the sake of use in reload.c. */
int
-offsettable_address_addr_space_p (int strictp, enum machine_mode mode, rtx y,
+offsettable_address_addr_space_p (int strictp, machine_mode mode, rtx y,
addr_space_t as)
{
enum rtx_code ycode = GET_CODE (y);
rtx z;
rtx y1 = y;
rtx *y2;
- int (*addressp) (enum machine_mode, rtx, addr_space_t) =
+ int (*addressp) (machine_mode, rtx, addr_space_t) =
(strictp ? strict_memory_address_addr_space_p
: memory_address_addr_space_p);
unsigned int mode_sz = GET_MODE_SIZE (mode);
-#ifdef POINTERS_EXTEND_UNSIGNED
- enum machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
-#endif
if (CONSTANT_ADDRESS_P (y))
return 1;
if (mode_dependent_address_p (y, as))
return 0;
+ machine_mode address_mode = GET_MODE (y);
+ if (address_mode == VOIDmode)
+ address_mode = targetm.addr_space.address_mode (as);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ machine_mode pointer_mode = targetm.addr_space.pointer_mode (as);
+#endif
+
/* ??? How much offset does an offsettable BLKmode reference need?
Clearly that depends on the situation in which it's being used.
However, the current situation in which we test 0xffffffff is
int good;
y1 = *y2;
- *y2 = plus_constant (GET_MODE (y), *y2, mode_sz - 1);
+ *y2 = plus_constant (address_mode, *y2, mode_sz - 1);
/* Use QImode because an odd displacement may be automatically invalid
for any wider mode. But it should be valid for a single byte. */
good = (*addressp) (QImode, y, as);
if (GET_CODE (y) == LO_SUM
&& mode != BLKmode
&& mode_sz <= GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT)
- z = gen_rtx_LO_SUM (GET_MODE (y), XEXP (y, 0),
- plus_constant (GET_MODE (y), XEXP (y, 1),
+ z = gen_rtx_LO_SUM (address_mode, XEXP (y, 0),
+ plus_constant (address_mode, XEXP (y, 1),
mode_sz - 1));
#ifdef POINTERS_EXTEND_UNSIGNED
/* Likewise for a ZERO_EXTEND from pointer_mode. */
else if (POINTERS_EXTEND_UNSIGNED > 0
&& GET_CODE (y) == ZERO_EXTEND
&& GET_MODE (XEXP (y, 0)) == pointer_mode)
- z = gen_rtx_ZERO_EXTEND (GET_MODE (y),
+ z = gen_rtx_ZERO_EXTEND (address_mode,
plus_constant (pointer_mode, XEXP (y, 0),
mode_sz - 1));
#endif
else
- z = plus_constant (GET_MODE (y), y, mode_sz - 1);
+ z = plus_constant (address_mode, y, mode_sz - 1);
/* Use QImode because an odd displacement may be automatically invalid
for any wider mode. But it should be valid for a single byte. */
return targetm.mode_dependent_address_p (addr, addrspace);
}
\f
+/* Return true if boolean attribute ATTR is supported. */
+
+static bool
+have_bool_attr (bool_attr attr)
+{
+ switch (attr)
+ {
+ case BA_ENABLED:
+ return HAVE_ATTR_enabled;
+ case BA_PREFERRED_FOR_SIZE:
+ return HAVE_ATTR_enabled || HAVE_ATTR_preferred_for_size;
+ case BA_PREFERRED_FOR_SPEED:
+ return HAVE_ATTR_enabled || HAVE_ATTR_preferred_for_speed;
+ }
+ gcc_unreachable ();
+}
+
+/* Return the value of ATTR for instruction INSN. */
+
+static bool
+get_bool_attr (rtx_insn *insn, bool_attr attr)
+{
+ switch (attr)
+ {
+ case BA_ENABLED:
+ return get_attr_enabled (insn);
+ case BA_PREFERRED_FOR_SIZE:
+ return get_attr_enabled (insn) && get_attr_preferred_for_size (insn);
+ case BA_PREFERRED_FOR_SPEED:
+ return get_attr_enabled (insn) && get_attr_preferred_for_speed (insn);
+ }
+ gcc_unreachable ();
+}
+
+/* Like get_bool_attr_mask, but don't use the cache. */
+
+static alternative_mask
+get_bool_attr_mask_uncached (rtx_insn *insn, bool_attr attr)
+{
+ /* Temporarily install enough information for get_attr_<foo> to assume
+ that the insn operands are already cached. As above, the attribute
+ mustn't depend on the values of operands, so we don't provide their
+ real values here. */
+ rtx_insn *old_insn = recog_data.insn;
+ int old_alternative = which_alternative;
+
+ recog_data.insn = insn;
+ alternative_mask mask = ALL_ALTERNATIVES;
+ int n_alternatives = insn_data[INSN_CODE (insn)].n_alternatives;
+ for (int i = 0; i < n_alternatives; i++)
+ {
+ which_alternative = i;
+ if (!get_bool_attr (insn, attr))
+ mask &= ~ALTERNATIVE_BIT (i);
+ }
+
+ recog_data.insn = old_insn;
+ which_alternative = old_alternative;
+ return mask;
+}
+
+/* Return the mask of operand alternatives that are allowed for INSN
+ by boolean attribute ATTR. This mask depends only on INSN and on
+ the current target; it does not depend on things like the values of
+ operands. */
+
+static alternative_mask
+get_bool_attr_mask (rtx_insn *insn, bool_attr attr)
+{
+ /* Quick exit for asms and for targets that don't use these attributes. */
+ int code = INSN_CODE (insn);
+ if (code < 0 || !have_bool_attr (attr))
+ return ALL_ALTERNATIVES;
+
+ /* Calling get_attr_<foo> can be expensive, so cache the mask
+ for speed. */
+ if (!this_target_recog->x_bool_attr_masks[code][attr])
+ this_target_recog->x_bool_attr_masks[code][attr]
+ = get_bool_attr_mask_uncached (insn, attr);
+ return this_target_recog->x_bool_attr_masks[code][attr];
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+ target. */
+
+alternative_mask
+get_enabled_alternatives (rtx_insn *insn)
+{
+ return get_bool_attr_mask (insn, BA_ENABLED);
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+ target and are preferred for the current size/speed optimization
+ choice. */
+
+alternative_mask
+get_preferred_alternatives (rtx_insn *insn)
+{
+ if (optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn)))
+ return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+ else
+ return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+}
+
+/* Return the set of alternatives of INSN that are allowed by the current
+ target and are preferred for the size/speed optimization choice
+ associated with BB. Passing a separate BB is useful if INSN has not
+ been emitted yet or if we are considering moving it to a different
+ block. */
+
+alternative_mask
+get_preferred_alternatives (rtx_insn *insn, basic_block bb)
+{
+ if (optimize_bb_for_speed_p (bb))
+ return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SPEED);
+ else
+ return get_bool_attr_mask (insn, BA_PREFERRED_FOR_SIZE);
+}
+
+/* Assert that the cached boolean attributes for INSN are still accurate.
+ The backend is required to define these attributes in a way that only
+ depends on the current target (rather than operands, compiler phase,
+ etc.). */
+
+bool
+check_bool_attrs (rtx_insn *insn)
+{
+ int code = INSN_CODE (insn);
+ if (code >= 0)
+ for (int i = 0; i <= BA_LAST; ++i)
+ {
+ enum bool_attr attr = (enum bool_attr) i;
+ if (this_target_recog->x_bool_attr_masks[code][attr])
+ gcc_assert (this_target_recog->x_bool_attr_masks[code][attr]
+ == get_bool_attr_mask_uncached (insn, attr));
+ }
+ return true;
+}
+
/* Like extract_insn, but save insn extracted and don't extract again, when
called again for the same insn expecting that recog_data still contain the
valid information. This is used primary by gen_attr infrastructure that
often does extract insn again and again. */
void
-extract_insn_cached (rtx insn)
+extract_insn_cached (rtx_insn *insn)
{
if (recog_data.insn == insn && INSN_CODE (insn) >= 0)
return;
recog_data.insn = insn;
}
+/* Do uncached extract_insn, constrain_operands and complain about failures.
+ This should be used when extracting a pre-existing constrained instruction
+ if the caller wants to know which alternative was chosen. */
+void
+extract_constrain_insn (rtx_insn *insn)
+{
+ extract_insn (insn);
+ if (!constrain_operands (reload_completed, get_enabled_alternatives (insn)))
+ fatal_insn_not_found (insn);
+}
+
/* Do cached extract_insn, constrain_operands and complain about failures.
Used by insn_attrtab. */
void
-extract_constrain_insn_cached (rtx insn)
+extract_constrain_insn_cached (rtx_insn *insn)
{
extract_insn_cached (insn);
if (which_alternative == -1
- && !constrain_operands (reload_completed))
+ && !constrain_operands (reload_completed,
+ get_enabled_alternatives (insn)))
fatal_insn_not_found (insn);
}
-/* Do cached constrain_operands and complain about failures. */
+/* Do cached constrain_operands on INSN and complain about failures. */
int
-constrain_operands_cached (int strict)
+constrain_operands_cached (rtx_insn *insn, int strict)
{
if (which_alternative == -1)
- return constrain_operands (strict);
+ return constrain_operands (strict, get_enabled_alternatives (insn));
else
return 1;
}
/* Analyze INSN and fill in recog_data. */
void
-extract_insn (rtx insn)
+extract_insn (rtx_insn *insn)
{
int i;
int icode;
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]
- = HAVE_ATTR_enabled ? get_attr_enabled (insn) : 1;
- }
- }
-
recog_data.insn = NULL;
which_alternative = -1;
}
-/* After calling extract_insn, you can use this function to extract some
- information from the constraint strings into a more usable form.
- The collected data is stored in recog_op_alt. */
+/* Fill in OP_ALT_BASE for an instruction that has N_OPERANDS operands,
+ N_ALTERNATIVES alternatives and constraint strings CONSTRAINTS.
+ OP_ALT_BASE has N_ALTERNATIVES * N_OPERANDS entries and CONSTRAINTS
+ has N_OPERANDS entries. */
+
void
-preprocess_constraints (void)
+preprocess_constraints (int n_operands, int n_alternatives,
+ const char **constraints,
+ operand_alternative *op_alt_base)
{
- int i;
-
- for (i = 0; i < recog_data.n_operands; i++)
- memset (recog_op_alt[i], 0, (recog_data.n_alternatives
- * sizeof (struct operand_alternative)));
-
- for (i = 0; i < recog_data.n_operands; i++)
+ for (int i = 0; i < n_operands; i++)
{
int j;
struct operand_alternative *op_alt;
- const char *p = recog_data.constraints[i];
+ const char *p = constraints[i];
- op_alt = recog_op_alt[i];
+ op_alt = op_alt_base;
- for (j = 0; j < recog_data.n_alternatives; j++)
+ for (j = 0; j < n_alternatives; j++, op_alt += n_operands)
{
- op_alt[j].cl = NO_REGS;
- op_alt[j].constraint = p;
- op_alt[j].matches = -1;
- op_alt[j].matched = -1;
-
- if (!recog_data.alternative_enabled_p[j])
- {
- p = skip_alternative (p);
- continue;
- }
+ op_alt[i].cl = NO_REGS;
+ op_alt[i].constraint = p;
+ op_alt[i].matches = -1;
+ op_alt[i].matched = -1;
if (*p == '\0' || *p == ',')
{
- op_alt[j].anything_ok = 1;
+ op_alt[i].anything_ok = 1;
continue;
}
switch (c)
{
- case '=': case '+': case '*': case '%':
- case 'E': case 'F': case 'G': case 'H':
- case 's': case 'i': case 'n':
- case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'P':
- /* These don't say anything we care about. */
- break;
-
case '?':
- op_alt[j].reject += 6;
+ op_alt[i].reject += 6;
break;
case '!':
- op_alt[j].reject += 600;
+ op_alt[i].reject += 600;
break;
case '&':
- op_alt[j].earlyclobber = 1;
+ op_alt[i].earlyclobber = 1;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
char *end;
- op_alt[j].matches = strtoul (p, &end, 10);
- recog_op_alt[op_alt[j].matches][j].matched = i;
+ op_alt[i].matches = strtoul (p, &end, 10);
+ op_alt[op_alt[i].matches].matched = i;
p = end;
}
continue;
- case TARGET_MEM_CONSTRAINT:
- op_alt[j].memory_ok = 1;
- break;
- case '<':
- op_alt[j].decmem_ok = 1;
- break;
- case '>':
- op_alt[j].incmem_ok = 1;
- break;
- case 'V':
- op_alt[j].nonoffmem_ok = 1;
- break;
- case 'o':
- op_alt[j].offmem_ok = 1;
- break;
case 'X':
- op_alt[j].anything_ok = 1;
- break;
-
- case 'p':
- op_alt[j].is_address = 1;
- op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
- [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
- ADDRESS, SCRATCH)];
+ op_alt[i].anything_ok = 1;
break;
case 'g':
- case 'r':
- op_alt[j].cl =
- reg_class_subunion[(int) op_alt[j].cl][(int) GENERAL_REGS];
+ op_alt[i].cl =
+ reg_class_subunion[(int) op_alt[i].cl][(int) GENERAL_REGS];
break;
default:
- if (EXTRA_MEMORY_CONSTRAINT (c, p))
+ enum constraint_num cn = lookup_constraint (p);
+ enum reg_class cl;
+ switch (get_constraint_type (cn))
{
- op_alt[j].memory_ok = 1;
+ case CT_REGISTER:
+ cl = reg_class_for_constraint (cn);
+ if (cl != NO_REGS)
+ op_alt[i].cl = reg_class_subunion[op_alt[i].cl][cl];
break;
- }
- if (EXTRA_ADDRESS_CONSTRAINT (c, p))
- {
- op_alt[j].is_address = 1;
- op_alt[j].cl
+
+ case CT_CONST_INT:
+ break;
+
+ case CT_MEMORY:
+ op_alt[i].memory_ok = 1;
+ break;
+
+ case CT_ADDRESS:
+ op_alt[i].is_address = 1;
+ op_alt[i].cl
= (reg_class_subunion
- [(int) op_alt[j].cl]
+ [(int) op_alt[i].cl]
[(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
ADDRESS, SCRATCH)]);
break;
- }
- op_alt[j].cl
- = (reg_class_subunion
- [(int) op_alt[j].cl]
- [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
+ case CT_FIXED_FORM:
+ break;
+ }
break;
}
p += CONSTRAINT_LEN (c, p);
}
}
+/* Return an array of operand_alternative instructions for
+ instruction ICODE. */
+
+const operand_alternative *
+preprocess_insn_constraints (int icode)
+{
+ gcc_checking_assert (IN_RANGE (icode, 0, LAST_INSN_CODE));
+ if (this_target_recog->x_op_alt[icode])
+ return this_target_recog->x_op_alt[icode];
+
+ int n_operands = insn_data[icode].n_operands;
+ if (n_operands == 0)
+ return 0;
+ /* Always provide at least one alternative so that which_op_alt ()
+ works correctly. If the instruction has 0 alternatives (i.e. all
+ constraint strings are empty) then each operand in this alternative
+ will have anything_ok set. */
+ int n_alternatives = MAX (insn_data[icode].n_alternatives, 1);
+ int n_entries = n_operands * n_alternatives;
+
+ operand_alternative *op_alt = XCNEWVEC (operand_alternative, n_entries);
+ const char **constraints = XALLOCAVEC (const char *, n_operands);
+
+ for (int i = 0; i < n_operands; ++i)
+ constraints[i] = insn_data[icode].operand[i].constraint;
+ preprocess_constraints (n_operands, n_alternatives, constraints, op_alt);
+
+ this_target_recog->x_op_alt[icode] = op_alt;
+ return op_alt;
+}
+
+/* After calling extract_insn, you can use this function to extract some
+ information from the constraint strings into a more usable form.
+ The collected data is stored in recog_op_alt. */
+
+void
+preprocess_constraints (rtx_insn *insn)
+{
+ int icode = INSN_CODE (insn);
+ if (icode >= 0)
+ recog_op_alt = preprocess_insn_constraints (icode);
+ else
+ {
+ int n_operands = recog_data.n_operands;
+ int n_alternatives = recog_data.n_alternatives;
+ int n_entries = n_operands * n_alternatives;
+ memset (asm_op_alt, 0, n_entries * sizeof (operand_alternative));
+ preprocess_constraints (n_operands, n_alternatives,
+ recog_data.constraints, asm_op_alt);
+ recog_op_alt = asm_op_alt;
+ }
+}
+
/* Check the operands of an insn against the insn's operand constraints
- and return 1 if they are valid.
+ and return 1 if they match any of the alternatives in ALTERNATIVES.
+
The information about the insn's operands, constraints, operand modes
etc. is obtained from the global variables set up by extract_insn.
};
int
-constrain_operands (int strict)
+constrain_operands (int strict, alternative_mask alternatives)
{
const char *constraints[MAX_RECOG_OPERANDS];
int matching_operands[MAX_RECOG_OPERANDS];
int lose = 0;
funny_match_index = 0;
- if (!recog_data.alternative_enabled_p[which_alternative])
+ if (!TEST_BIT (alternatives, which_alternative))
{
int i;
for (opno = 0; opno < recog_data.n_operands; opno++)
{
rtx op = recog_data.operand[opno];
- enum machine_mode mode = GET_MODE (op);
+ machine_mode mode = GET_MODE (op);
const char *p = constraints[opno];
int offset = 0;
int win = 0;
c = '\0';
break;
- case '?': case '!': case '*': case '%':
- case '=': case '+':
- break;
-
case '#':
/* Ignore rest of this alternative as far as
constraint checking is concerned. */
win = 1;
break;
- case 'X':
- /* This is used for a MATCH_SCRATCH in the cases when
- we don't actually need anything. So anything goes
- any time. */
- win = 1;
- break;
-
- case TARGET_MEM_CONSTRAINT:
- /* Memory operands must be valid, to the extent
- required by STRICT. */
- if (MEM_P (op))
- {
- if (strict > 0
- && !strict_memory_address_addr_space_p
- (GET_MODE (op), XEXP (op, 0),
- MEM_ADDR_SPACE (op)))
- break;
- if (strict == 0
- && !memory_address_addr_space_p
- (GET_MODE (op), XEXP (op, 0),
- MEM_ADDR_SPACE (op)))
- break;
- win = 1;
- }
- /* Before reload, accept what reload can turn into mem. */
- else if (strict < 0 && CONSTANT_P (op))
- win = 1;
- /* During reload, accept a pseudo */
- else if (reload_in_progress && REG_P (op)
- && REGNO (op) >= FIRST_PSEUDO_REGISTER)
- win = 1;
- break;
-
- case '<':
- if (MEM_P (op)
- && (GET_CODE (XEXP (op, 0)) == PRE_DEC
- || GET_CODE (XEXP (op, 0)) == POST_DEC))
- win = 1;
- break;
-
- case '>':
- if (MEM_P (op)
- && (GET_CODE (XEXP (op, 0)) == PRE_INC
- || GET_CODE (XEXP (op, 0)) == POST_INC))
- win = 1;
- break;
-
- case 'E':
- case 'F':
- if (CONST_DOUBLE_AS_FLOAT_P (op)
- || (GET_CODE (op) == CONST_VECTOR
- && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
- win = 1;
- break;
-
- case 'G':
- case 'H':
- if (CONST_DOUBLE_AS_FLOAT_P (op)
- && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
- win = 1;
- break;
-
- case 's':
- if (CONST_SCALAR_INT_P (op))
- break;
- case 'i':
- if (CONSTANT_P (op))
- win = 1;
- break;
-
- case 'n':
- if (CONST_SCALAR_INT_P (op))
- win = 1;
- break;
-
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
- win = 1;
- break;
-
- case 'V':
- if (MEM_P (op)
- && ((strict > 0 && ! offsettable_memref_p (op))
- || (strict < 0
- && !(CONSTANT_P (op) || MEM_P (op)))
- || (reload_in_progress
- && !(REG_P (op)
- && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
- win = 1;
- break;
-
- case 'o':
- if ((strict > 0 && offsettable_memref_p (op))
- || (strict == 0 && offsettable_nonstrict_memref_p (op))
- /* Before reload, accept what reload can handle. */
- || (strict < 0
- && (CONSTANT_P (op) || MEM_P (op)))
- /* During reload, accept a pseudo */
- || (reload_in_progress && REG_P (op)
- && REGNO (op) >= FIRST_PSEUDO_REGISTER))
- win = 1;
- break;
-
default:
{
- enum reg_class cl;
-
- cl = (c == 'r'
- ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
+ enum constraint_num cn = lookup_constraint (p);
+ enum reg_class cl = reg_class_for_constraint (cn);
if (cl != NO_REGS)
{
if (strict < 0
&& reg_fits_class_p (op, cl, offset, mode)))
win = 1;
}
-#ifdef EXTRA_CONSTRAINT_STR
- else if (EXTRA_CONSTRAINT_STR (op, c, p))
+
+ else if (constraint_satisfied_p (op, cn))
win = 1;
- else if (EXTRA_MEMORY_CONSTRAINT (c, p)
+ else if (insn_extra_memory_constraint (cn)
/* Every memory operand can be reloaded to fit. */
&& ((strict < 0 && MEM_P (op))
/* Before reload, accept what reload can turn
- into mem. */
+ into a mem. */
|| (strict < 0 && CONSTANT_P (op))
+ /* Before reload, accept a pseudo,
+ since LRA can turn it into a mem. */
+ || (strict < 0 && targetm.lra_p () && REG_P (op)
+ && REGNO (op) >= FIRST_PSEUDO_REGISTER)
/* During reload, accept a pseudo */
|| (reload_in_progress && REG_P (op)
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)))
win = 1;
- else if (EXTRA_ADDRESS_CONSTRAINT (c, p)
+ else if (insn_extra_address_constraint (cn)
/* Every address operand can be reloaded to fit. */
&& strict < 0)
win = 1;
&& REGNO (op) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (op)] < 0
&& reg_equiv_mem (REGNO (op)) != 0
- && EXTRA_CONSTRAINT_STR
- (reg_equiv_mem (REGNO (op)), c, p))
+ && constraint_satisfied_p
+ (reg_equiv_mem (REGNO (op)), cn))
win = 1;
-#endif
break;
}
}
/* If we are about to reject this, but we are not to test strictly,
try a very loose test. Only return failure if it fails also. */
if (strict == 0)
- return constrain_operands (-1);
+ return constrain_operands (-1, alternatives);
else
return 0;
}
bool
reg_fits_class_p (const_rtx operand, reg_class_t cl, int offset,
- enum machine_mode mode)
+ machine_mode mode)
{
unsigned int regno = REGNO (operand);
split_all_insns_noflow. Return last insn in the sequence if successful,
or NULL if unsuccessful. */
-static rtx
-split_insn (rtx insn)
+static rtx_insn *
+split_insn (rtx_insn *insn)
{
/* Split insns here to get max fine-grain parallelism. */
- rtx first = PREV_INSN (insn);
- rtx last = try_split (PATTERN (insn), insn, 1);
+ rtx_insn *first = PREV_INSN (insn);
+ rtx_insn *last = try_split (PATTERN (insn), insn, 1);
rtx insn_set, last_set, note;
if (last == insn)
- return NULL_RTX;
+ return NULL;
/* 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
bool changed;
basic_block bb;
- blocks = sbitmap_alloc (last_basic_block);
+ blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (blocks);
changed = false;
- FOR_EACH_BB_REVERSE (bb)
+ FOR_EACH_BB_REVERSE_FN (bb, cfun)
{
- rtx insn, next;
+ rtx_insn *insn, *next;
bool finish = false;
rtl_profile_for_bb (bb);
unsigned int
split_all_insns_noflow (void)
{
- rtx next, insn;
+ rtx_insn *next, *insn;
for (insn = get_insns (); insn; insn = next)
{
#ifdef HAVE_peephole2
struct peep2_insn_data
{
- rtx insn;
+ rtx_insn *insn;
regset live_before;
};
/* 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
- DF_LIVE_OUT for the block. */
-#define PEEP2_EOB pc_rtx
+/* A marker indicating the last insn of the block. The live_before regset
+ for this element is correct, indicating DF_LIVE_OUT for the block. */
+#define PEEP2_EOB invalid_insn_rtx
/* Wrap N to fit into the peep2_insn_data buffer. */
does not exist. Used by the recognizer to find the next insn to match
in a multi-insn pattern. */
-rtx
+rtx_insn *
peep2_next_insn (int n)
{
gcc_assert (n <= peep2_current_count);
int
peep2_reg_dead_p (int ofs, rtx reg)
{
- int regno, n;
-
gcc_assert (ofs < MAX_INSNS_PER_PEEP2 + 1);
ofs = peep2_buf_position (peep2_current + ofs);
gcc_assert (peep2_insn_data[ofs].insn != NULL_RTX);
- regno = REGNO (reg);
- n = hard_regno_nregs[regno][GET_MODE (reg)];
- while (--n >= 0)
- if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno + n))
+ unsigned int end_regno = END_REGNO (reg);
+ for (unsigned int regno = REGNO (reg); regno < end_regno; ++regno)
+ if (REGNO_REG_SET_P (peep2_insn_data[ofs].live_before, regno))
return 0;
return 1;
}
+/* Regno offset to be used in the register search. */
+static int search_ofs;
+
/* Try to find a hard register of mode MODE, matching the register class in
CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
remains available until the end of LAST_INSN. LAST_INSN may be NULL_RTX,
rtx
peep2_find_free_register (int from, int to, const char *class_str,
- enum machine_mode mode, HARD_REG_SET *reg_set)
+ machine_mode mode, HARD_REG_SET *reg_set)
{
- static int search_ofs;
enum reg_class cl;
HARD_REG_SET live;
- df_ref *def_rec;
+ df_ref def;
int i;
gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
/* Don't use registers set or clobbered by the insn. */
- for (def_rec = DF_INSN_DEFS (peep2_insn_data[from].insn);
- *def_rec; def_rec++)
- SET_HARD_REG_BIT (live, DF_REF_REGNO (*def_rec));
+ FOR_EACH_INSN_DEF (def, peep2_insn_data[from].insn)
+ SET_HARD_REG_BIT (live, DF_REF_REGNO (def));
from = peep2_buf_position (from + 1);
}
- cl = (class_str[0] == 'r' ? GENERAL_REGS
- : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
+ cl = reg_class_for_constraint (lookup_constraint (class_str));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
regno = raw_regno;
#endif
- /* 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 can support the mode we need. */
+ /* Can it support the mode we need? */
if (! HARD_REGNO_MODE_OK (regno, mode))
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))
- continue;
success = 1;
- for (j = hard_regno_nregs[regno][mode] - 1; j >= 0; j--)
+ for (j = 0; success && j < hard_regno_nregs[regno][mode]; j++)
{
+ /* Don't allocate fixed registers. */
+ if (fixed_regs[regno + j])
+ {
+ success = 0;
+ break;
+ }
+ /* Don't allocate global registers. */
+ if (global_regs[regno + j])
+ {
+ success = 0;
+ break;
+ }
+ /* Make sure the register is of the right class. */
+ if (! TEST_HARD_REG_BIT (reg_class_contents[cl], regno + j))
+ {
+ success = 0;
+ break;
+ }
+ /* And that we don't create an extra save/restore. */
+ if (! call_used_regs[regno + j] && ! df_regs_ever_live_p (regno + j))
+ {
+ success = 0;
+ break;
+ }
+
+ if (! targetm.hard_regno_scratch_ok (regno + j))
+ {
+ success = 0;
+ break;
+ }
+
+ /* And we don't clobber traceback for noreturn functions. */
+ if ((regno + j == FRAME_POINTER_REGNUM
+ || regno + j == HARD_FRAME_POINTER_REGNUM)
+ && (! reload_completed || frame_pointer_needed))
+ {
+ success = 0;
+ break;
+ }
+
if (TEST_HARD_REG_BIT (*reg_set, regno + j)
|| TEST_HARD_REG_BIT (live, regno + j))
{
break;
}
}
+
if (success)
{
add_to_hard_reg_set (reg_set, mode, regno);
/* 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_insn_data[i].insn = NULL;
peep2_current_count = 0;
/* Indicate that the last slot contains live_after data. */
replacing them with ATTEMPT. Returns the last insn emitted, or NULL
if the replacement is rejected. */
-static rtx
-peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
+static rtx_insn *
+peep2_attempt (basic_block bb, rtx_insn *insn, int match_len, rtx_insn *attempt)
{
int i;
- rtx last, eh_note, as_note, before_try, x;
- rtx old_insn, new_insn;
+ rtx_insn *last, *before_try, *x;
+ rtx eh_note, as_note;
+ rtx_insn *old_insn;
+ rtx_insn *new_insn;
bool was_call = false;
/* If we are splitting an RTX_FRAME_RELATED_P insn, do not allow it to
CALL_INSN_FUNCTION_USAGE (new_insn)
= CALL_INSN_FUNCTION_USAGE (old_insn);
+ SIBLING_CALL_P (new_insn) = SIBLING_CALL_P (old_insn);
for (note = REG_NOTES (old_insn);
note;
eh_note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
/* Replace the old sequence with the new. */
+ rtx_insn *peepinsn = peep2_insn_data[i].insn;
last = emit_insn_after_setloc (attempt,
peep2_insn_data[i].insn,
- INSN_LOCATION (peep2_insn_data[i].insn));
+ INSN_LOCATION (peepinsn));
before_try = PREV_INSN (insn);
delete_insn_chain (insn, peep2_insn_data[i].insn, false);
matched, and which now need to be replaced in the buffer. */
static void
-peep2_update_life (basic_block bb, int match_len, rtx last, rtx prev)
+peep2_update_life (basic_block bb, int match_len, rtx_insn *last,
+ rtx_insn *prev)
{
int i = peep2_buf_position (peep2_current + match_len + 1);
- rtx x;
+ rtx_insn *x;
regset_head live;
INIT_REG_SET (&live);
add more instructions to the buffer. */
static bool
-peep2_fill_buffer (basic_block bb, rtx insn, regset live)
+peep2_fill_buffer (basic_block bb, rtx_insn *insn, regset live)
{
int pos;
static void
peephole2_optimize (void)
{
- rtx insn;
+ rtx_insn *insn;
bitmap live;
int i;
basic_block bb;
/* Initialize the regsets we're going to use. */
for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
peep2_insn_data[i].live_before = BITMAP_ALLOC (®_obstack);
+ search_ofs = 0;
live = BITMAP_ALLOC (®_obstack);
- FOR_EACH_BB_REVERSE (bb)
+ FOR_EACH_BB_REVERSE_FN (bb, cfun)
{
bool past_end = false;
int pos;
insn = BB_HEAD (bb);
for (;;)
{
- rtx attempt, head;
+ rtx_insn *attempt, *head;
int match_len;
if (!past_end && !NONDEBUG_INSN_P (insn))
attempt = peephole2_insns (PATTERN (head), head, &match_len);
if (attempt != NULL)
{
- rtx last = peep2_attempt (bb, head, match_len, attempt);
+ rtx_insn *last = peep2_attempt (bb, head, match_len, attempt);
if (last)
{
peep2_update_life (bb, match_len, last, PREV_INSN (attempt));
BITMAP_FREE (live);
if (peep2_do_rebuild_jump_labels)
rebuild_jump_labels (get_insns ());
+ if (peep2_do_cleanup_cfg)
+ cleanup_cfg (CLEANUP_CFG_CHANGED);
}
#endif /* HAVE_peephole2 */
must be either a single_set or a PARALLEL with SETs inside. */
int
-store_data_bypass_p (rtx out_insn, rtx in_insn)
+store_data_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
{
rtx out_set, in_set;
rtx out_pat, in_pat;
of insn categorization may be any JUMP or CALL insn. */
int
-if_test_bypass_p (rtx out_insn, rtx in_insn)
+if_test_bypass_p (rtx_insn *out_insn, rtx_insn *in_insn)
{
rtx out_set, in_set;
return true;
}
\f
-static bool
-gate_handle_peephole2 (void)
-{
- return (optimize > 0 && flag_peephole2);
-}
-
static unsigned int
rest_of_handle_peephole2 (void)
{
return 0;
}
-struct rtl_opt_pass pass_peephole2 =
-{
- {
- RTL_PASS,
- "peephole2", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- 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_df_finish | TODO_verify_rtl_sharing |
- 0 /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_peephole2 =
+{
+ RTL_PASS, /* type */
+ "peephole2", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_PEEPHOLE2, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_df_finish, /* todo_flags_finish */
};
-static unsigned int
-rest_of_handle_split_all_insns (void)
+class pass_peephole2 : public rtl_opt_pass
{
- split_all_insns ();
- return 0;
+public:
+ pass_peephole2 (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_peephole2, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ /* The epiphany backend creates a second instance of this pass, so we need
+ a clone method. */
+ opt_pass * clone () { return new pass_peephole2 (m_ctxt); }
+ virtual bool gate (function *) { return (optimize > 0 && flag_peephole2); }
+ virtual unsigned int execute (function *)
+ {
+ return rest_of_handle_peephole2 ();
+ }
+
+}; // class pass_peephole2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_peephole2 (gcc::context *ctxt)
+{
+ return new pass_peephole2 (ctxt);
}
-struct rtl_opt_pass pass_split_all_insns =
-{
- {
- RTL_PASS,
- "split1", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- NULL, /* gate */
- rest_of_handle_split_all_insns, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_all_insns =
+{
+ RTL_PASS, /* type */
+ "split1", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
+class pass_split_all_insns : public rtl_opt_pass
+{
+public:
+ pass_split_all_insns (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_split_all_insns, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ /* The epiphany backend creates a second instance of this pass, so
+ we need a clone method. */
+ opt_pass * clone () { return new pass_split_all_insns (m_ctxt); }
+ virtual unsigned int execute (function *)
+ {
+ split_all_insns ();
+ return 0;
+ }
+
+}; // class pass_split_all_insns
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_all_insns (gcc::context *ctxt)
+{
+ return new pass_split_all_insns (ctxt);
+}
+
static unsigned int
rest_of_handle_split_after_reload (void)
{
return 0;
}
-struct rtl_opt_pass pass_split_after_reload =
-{
- {
- RTL_PASS,
- "split2", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- NULL, /* gate */
- rest_of_handle_split_after_reload, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_after_reload =
+{
+ RTL_PASS, /* type */
+ "split2", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
-static bool
-gate_handle_split_before_regstack (void)
+class pass_split_after_reload : public rtl_opt_pass
+{
+public:
+ pass_split_after_reload (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_split_after_reload, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual unsigned int execute (function *)
+ {
+ return rest_of_handle_split_after_reload ();
+ }
+
+}; // class pass_split_after_reload
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_after_reload (gcc::context *ctxt)
+{
+ return new pass_split_after_reload (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_split_before_regstack =
+{
+ RTL_PASS, /* type */
+ "split3", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_split_before_regstack : public rtl_opt_pass
+{
+public:
+ pass_split_before_regstack (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_split_before_regstack, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *);
+ virtual unsigned int execute (function *)
+ {
+ split_all_insns ();
+ return 0;
+ }
+
+}; // class pass_split_before_regstack
+
+bool
+pass_split_before_regstack::gate (function *)
{
#if HAVE_ATTR_length && defined (STACK_REGS)
/* If flow2 creates new instructions which need splitting
#endif
}
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_before_regstack (gcc::context *ctxt)
+{
+ return new pass_split_before_regstack (ctxt);
+}
+
static unsigned int
-rest_of_handle_split_before_regstack (void)
+rest_of_handle_split_before_sched2 (void)
{
+#ifdef INSN_SCHEDULING
split_all_insns ();
+#endif
return 0;
}
-struct rtl_opt_pass pass_split_before_regstack =
-{
- {
- RTL_PASS,
- "split3", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- gate_handle_split_before_regstack, /* gate */
- rest_of_handle_split_before_regstack, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0 /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_before_sched2 =
+{
+ RTL_PASS, /* type */
+ "split4", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
-static bool
-gate_handle_split_before_sched2 (void)
+class pass_split_before_sched2 : public rtl_opt_pass
{
+public:
+ pass_split_before_sched2 (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_split_before_sched2, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
#ifdef INSN_SCHEDULING
- return optimize > 0 && flag_schedule_insns_after_reload;
+ return optimize > 0 && flag_schedule_insns_after_reload;
#else
- return 0;
+ return false;
#endif
-}
+ }
-static unsigned int
-rest_of_handle_split_before_sched2 (void)
+ virtual unsigned int execute (function *)
+ {
+ return rest_of_handle_split_before_sched2 ();
+ }
+
+}; // class pass_split_before_sched2
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_before_sched2 (gcc::context *ctxt)
{
-#ifdef INSN_SCHEDULING
- split_all_insns ();
-#endif
- return 0;
+ return new pass_split_before_sched2 (ctxt);
}
-struct rtl_opt_pass pass_split_before_sched2 =
-{
- {
- RTL_PASS,
- "split4", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- gate_handle_split_before_sched2, /* gate */
- rest_of_handle_split_before_sched2, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_verify_flow /* todo_flags_finish */
- }
+namespace {
+
+const pass_data pass_data_split_for_shorten_branches =
+{
+ RTL_PASS, /* type */
+ "split5", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
};
-/* 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)
+class pass_split_for_shorten_branches : public rtl_opt_pass
{
+public:
+ pass_split_for_shorten_branches (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_split_for_shorten_branches, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ /* The placement of the splitting that we do for shorten_branches
+ depends on whether regstack is used by the target or not. */
#if HAVE_ATTR_length && !defined (STACK_REGS)
- return 1;
+ return true;
#else
- return 0;
+ return false;
#endif
+ }
+
+ virtual unsigned int execute (function *)
+ {
+ return split_all_insns_noflow ();
+ }
+
+}; // class pass_split_for_shorten_branches
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_split_for_shorten_branches (gcc::context *ctxt)
+{
+ return new pass_split_for_shorten_branches (ctxt);
}
-struct rtl_opt_pass pass_split_for_shorten_branches =
-{
- {
- RTL_PASS,
- "split5", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- gate_do_final_split, /* gate */
- split_all_insns_noflow, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_verify_rtl_sharing /* todo_flags_finish */
- }
-};
+/* (Re)initialize the target information after a change in target. */
+
+void
+recog_init ()
+{
+ /* The information is zero-initialized, so we don't need to do anything
+ first time round. */
+ if (!this_target_recog->x_initialized)
+ {
+ this_target_recog->x_initialized = true;
+ return;
+ }
+ memset (this_target_recog->x_bool_attr_masks, 0,
+ sizeof (this_target_recog->x_bool_attr_masks));
+ for (int i = 0; i < LAST_INSN_CODE; ++i)
+ if (this_target_recog->x_op_alt[i])
+ {
+ free (this_target_recog->x_op_alt[i]);
+ this_target_recog->x_op_alt[i] = 0;
+ }
+}