Commit 6d26dc3b by Kazu Hirata Committed by Kazu Hirata

frv-protos.h: Add a prototype to frv_legitimate_memory_operand and frv_const_unspec_p.

	* config/frv/frv-protos.h: Add a prototype to
	frv_legitimate_memory_operand and frv_const_unspec_p.
	(frv_unspec): Move from frv.c.
	* config/frv/frv.c (frv_unspec): Move to frv-protos.h.
	(frv_const_unspec_p, frv_legitimate_memory_operand_): Export.
	(ldd_address_operand, fdpic_fptr_operand, frv_load_operand,
	gpr_or_fpr_operand, gpr_or_int12_operand,
	gpr_fpr_or_int12_operand, fpr_or_int6_operand,
	gpr_or_int10_operand, gpr_or_int_operand, int12_operand,
	int6_operand, int5_operand, uint5_operand, uint4_operand,
	uint1_operand, int_2word_operand, uint16_operand,
	upper_int16_operand, integer_register_operand,
	gpr_no_subreg_operand, fpr_operand, even_reg_operand,
	odd_reg_operand, even_gpr_operand, odd_gpr_operand,
	quad_fpr_operand, even_fpr_operand, odd_fpr_operand,
	dbl_memory_one_insn_operand, dbl_memory_two_insn_operand,
	move_destination_operand, movcc_fp_destination_operand,
	frv_function_symbol_referenced_p, move_source_operand,
	condexec_dest_operand, condexec_source_operand,
	reg_or_0_operand, lr_operand, fdpic_operand, got12_operand,
	const_unspec_operand, gpr_or_memory_operand,
	gpr_or_memory_operand_with_scratch, fpr_or_memory_operand,
	icc_operand, fcc_operand, cc_operand, icr_operand,
	fcr_operand, cr_operand, call_operand, sibcall_operand,
	symbolic_operand, relational_operator,
	integer_relational_operator, float_relational_operator,
	ccr_eqne_operator, minmax_operator,
	condexec_si_binary_operator, condexec_si_media_operator,
	condexec_si_divide_operator, condexec_si_unary_operator,
	condexec_sf_conv_operator, condexec_sf_add_operator,
	condexec_memory_operand, intop_compare_operator, acc_operand,
	even_acc_operand, quad_acc_operand, accg_operand: Move to
	predicates.md.
	* config/frv/frv.h (PREDICATE_CODES): Remove.
	* config/frv/frv.md: Include predicates.md.
	* config/frv/predicates.md: New.

From-SVN: r97577
parent 2f84c996
...@@ -3,6 +3,43 @@ ...@@ -3,6 +3,43 @@
* config/frv/frv.h (PREDICATE_CODES): Add CONST to * config/frv/frv.h (PREDICATE_CODES): Add CONST to
gpr_or_int12_operand. gpr_or_int12_operand.
* config/frv/frv-protos.h: Add a prototype to
frv_legitimate_memory_operand and frv_const_unspec_p.
(frv_unspec): Move from frv.c.
* config/frv/frv.c (frv_unspec): Move to frv-protos.h.
(frv_const_unspec_p, frv_legitimate_memory_operand_): Export.
(ldd_address_operand, fdpic_fptr_operand, frv_load_operand,
gpr_or_fpr_operand, gpr_or_int12_operand,
gpr_fpr_or_int12_operand, fpr_or_int6_operand,
gpr_or_int10_operand, gpr_or_int_operand, int12_operand,
int6_operand, int5_operand, uint5_operand, uint4_operand,
uint1_operand, int_2word_operand, uint16_operand,
upper_int16_operand, integer_register_operand,
gpr_no_subreg_operand, fpr_operand, even_reg_operand,
odd_reg_operand, even_gpr_operand, odd_gpr_operand,
quad_fpr_operand, even_fpr_operand, odd_fpr_operand,
dbl_memory_one_insn_operand, dbl_memory_two_insn_operand,
move_destination_operand, movcc_fp_destination_operand,
frv_function_symbol_referenced_p, move_source_operand,
condexec_dest_operand, condexec_source_operand,
reg_or_0_operand, lr_operand, fdpic_operand, got12_operand,
const_unspec_operand, gpr_or_memory_operand,
gpr_or_memory_operand_with_scratch, fpr_or_memory_operand,
icc_operand, fcc_operand, cc_operand, icr_operand,
fcr_operand, cr_operand, call_operand, sibcall_operand,
symbolic_operand, relational_operator,
integer_relational_operator, float_relational_operator,
ccr_eqne_operator, minmax_operator,
condexec_si_binary_operator, condexec_si_media_operator,
condexec_si_divide_operator, condexec_si_unary_operator,
condexec_sf_conv_operator, condexec_sf_add_operator,
condexec_memory_operand, intop_compare_operator, acc_operand,
even_acc_operand, quad_acc_operand, accg_operand: Move to
predicates.md.
* config/frv/frv.h (PREDICATE_CODES): Remove.
* config/frv/frv.md: Include predicates.md.
* config/frv/predicates.md: New.
2004-04-04 Richard Sandiford <rsandifo@redhat.com> 2004-04-04 Richard Sandiford <rsandifo@redhat.com>
PR target/19537 PR target/19537
......
...@@ -205,5 +205,18 @@ extern rtx frv_matching_accg_for_acc (rtx); ...@@ -205,5 +205,18 @@ extern rtx frv_matching_accg_for_acc (rtx);
extern void frv_expand_fdpic_call (rtx *, bool, bool); extern void frv_expand_fdpic_call (rtx *, bool, bool);
extern rtx frv_gen_GPsym2reg (rtx, rtx); extern rtx frv_gen_GPsym2reg (rtx, rtx);
extern void frv_output_dwarf_dtprel (FILE *, int, rtx); extern void frv_output_dwarf_dtprel (FILE *, int, rtx);
extern int frv_legitimate_memory_operand (rtx, enum machine_mode, int);
/* Information about a relocation unspec. SYMBOL is the relocation symbol
(a SYMBOL_REF or LABEL_REF), RELOC is the type of relocation and OFFSET
is the constant addend. */
struct frv_unspec {
rtx symbol;
int reloc;
HOST_WIDE_INT offset;
};
extern bool frv_const_unspec_p (rtx, struct frv_unspec *);
#endif #endif
...@@ -123,15 +123,6 @@ static unsigned int frv_num_nops; ...@@ -123,15 +123,6 @@ static unsigned int frv_num_nops;
REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \ REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \
REG++) REG++)
/* Information about a relocation unspec. SYMBOL is the relocation symbol
(a SYMBOL_REF or LABEL_REF), RELOC is the type of relocation and OFFSET
is the constant addend. */
struct frv_unspec {
rtx symbol;
int reloc;
HOST_WIDE_INT offset;
};
/* Temporary register allocation support structure. */ /* Temporary register allocation support structure. */
typedef struct frv_tmp_reg_struct typedef struct frv_tmp_reg_struct
{ {
...@@ -256,7 +247,6 @@ static bool frv_handle_option (size_t, const char *, int); ...@@ -256,7 +247,6 @@ static bool frv_handle_option (size_t, const char *, int);
static int frv_default_flags_for_cpu (void); static int frv_default_flags_for_cpu (void);
static int frv_string_begins_with (tree, const char *); static int frv_string_begins_with (tree, const char *);
static FRV_INLINE bool frv_small_data_reloc_p (rtx, int); static FRV_INLINE bool frv_small_data_reloc_p (rtx, int);
static FRV_INLINE bool frv_const_unspec_p (rtx, struct frv_unspec *);
static void frv_print_operand_memory_reference_reg static void frv_print_operand_memory_reference_reg
(FILE *, rtx); (FILE *, rtx);
static void frv_print_operand_memory_reference (FILE *, rtx, int); static void frv_print_operand_memory_reference (FILE *, rtx, int);
...@@ -280,7 +270,6 @@ static void frv_frame_access_multi (frv_frame_accessor_t*, ...@@ -280,7 +270,6 @@ static void frv_frame_access_multi (frv_frame_accessor_t*,
static void frv_frame_access_standard_regs (enum frv_stack_op, static void frv_frame_access_standard_regs (enum frv_stack_op,
frv_stack_t *); frv_stack_t *);
static struct machine_function *frv_init_machine_status (void); static struct machine_function *frv_init_machine_status (void);
static int frv_legitimate_memory_operand (rtx, enum machine_mode, int);
static rtx frv_int_to_acc (enum insn_code, int, rtx); static rtx frv_int_to_acc (enum insn_code, int, rtx);
static enum machine_mode frv_matching_accg_mode (enum machine_mode); static enum machine_mode frv_matching_accg_mode (enum machine_mode);
static rtx frv_read_argument (tree *); static rtx frv_read_argument (tree *);
...@@ -468,7 +457,7 @@ frv_small_data_reloc_p (rtx symbol, int reloc) ...@@ -468,7 +457,7 @@ frv_small_data_reloc_p (rtx symbol, int reloc)
/* Return true if X is a valid relocation unspec. If it is, fill in UNSPEC /* Return true if X is a valid relocation unspec. If it is, fill in UNSPEC
appropriately. */ appropriately. */
static FRV_INLINE bool bool
frv_const_unspec_p (rtx x, struct frv_unspec *unspec) frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
{ {
if (GET_CODE (x) == CONST) if (GET_CODE (x) == CONST)
...@@ -3715,7 +3704,7 @@ frv_find_base_term (rtx x) ...@@ -3715,7 +3704,7 @@ frv_find_base_term (rtx x)
/* Return 1 if operand is a valid FRV address. CONDEXEC_P is true if /* Return 1 if operand is a valid FRV address. CONDEXEC_P is true if
the operand is used by a predicated instruction. */ the operand is used by a predicated instruction. */
static int int
frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p) frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
{ {
return ((GET_MODE (op) == mode || mode == VOIDmode) return ((GET_MODE (op) == mode || mode == VOIDmode)
...@@ -3805,1607 +3794,84 @@ frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall) ...@@ -3805,1607 +3794,84 @@ frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall)
c = gen_call_fdpicdi (picreg, const0_rtx, lr); c = gen_call_fdpicdi (picreg, const0_rtx, lr);
emit_call_insn (c); emit_call_insn (c);
} }
/* An address operand that may use a pair of registers, an addressing
mode that we reject in general. */
int
ldd_address_operand (rtx x, enum machine_mode mode)
{
if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode)
return FALSE;
return frv_legitimate_address_p (DImode, x, reload_completed, FALSE, TRUE);
}
int
fdpic_fptr_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
}
/* Return 1 is OP is a memory operand, or will be turned into one by /* Look for a SYMBOL_REF of a function in an rtx. We always want to
reload. */ process these separately from any offsets, such that we add any
offsets to the function descriptor (the actual pointer), not to the
int function address. */
frv_load_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (reload_in_progress)
{
rtx tmp = op;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
op = reg_equiv_memory_loc[REGNO (tmp)];
}
return op && memory_operand (op, mode);
}
/* Return 1 if operand is a GPR register or a FPR register. */
int
gpr_or_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
return FALSE;
}
/* Return 1 if operand is a GPR register or 12 bit signed immediate. */
int static bool
gpr_or_int12_operand (rtx op, enum machine_mode mode) frv_function_symbol_referenced_p (rtx x)
{ {
if (GET_CODE (op) == CONST_INT) const char *format;
return IN_RANGE_P (INTVAL (op), -2048, 2047); int length;
int j;
if (got12_operand (op, mode)) if (GET_CODE (x) == SYMBOL_REF)
return true; return SYMBOL_REF_FUNCTION_P (x);
if (GET_MODE (op) != mode && mode != VOIDmode) length = GET_RTX_LENGTH (GET_CODE (x));
return FALSE; format = GET_RTX_FORMAT (GET_CODE (x));
if (GET_CODE (op) == SUBREG) for (j = 0; j < length; ++j)
{ {
if (GET_CODE (SUBREG_REG (op)) != REG) switch (format[j])
return register_operand (op, mode); {
case 'e':
op = SUBREG_REG (op); if (frv_function_symbol_referenced_p (XEXP (x, j)))
} return TRUE;
break;
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
/* Return 1 if operand is a GPR register, or a FPR register, or a 12 bit
signed immediate. */
int
gpr_fpr_or_int12_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG) case 'V':
{ case 'E':
if (GET_CODE (SUBREG_REG (op)) != REG) if (XVEC (x, j) != 0)
return register_operand (op, mode); {
int k;
for (k = 0; k < XVECLEN (x, j); ++k)
if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
return TRUE;
}
break;
op = SUBREG_REG (op); default:
/* Nothing to do. */
break;
}
} }
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
return FALSE; return FALSE;
} }
/* Return 1 if operand is a register or 6 bit signed immediate. */ /* Return true if the memory operand is one that can be conditionally
executed. */
int
fpr_or_int6_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -32, 31);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return FPR_OR_PSEUDO_P (REGNO (op));
}
/* Return 1 if operand is a register or 10 bit signed immediate. */
int
gpr_or_int10_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -512, 511);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
/* Return 1 if operand is a register or an integer immediate. */
int
gpr_or_int_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == CONST_INT)
return TRUE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
/* Return 1 if operand is a 12 bit signed immediate. */
int int
int12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) condexec_memory_operand (rtx op, enum machine_mode mode)
{ {
if (GET_CODE (op) != CONST_INT) enum machine_mode op_mode = GET_MODE (op);
return FALSE; rtx addr;
return IN_RANGE_P (INTVAL (op), -2048, 2047);
}
/* Return 1 if operand is a 6 bit signed immediate. */
int if (mode != VOIDmode && op_mode != mode)
int6_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE; return FALSE;
return IN_RANGE_P (INTVAL (op), -32, 31); switch (op_mode)
}
/* Return 1 if operand is a 5 bit signed immediate. */
int
int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), -16, 15);
}
/* Return 1 if operand is a 5 bit unsigned immediate. */
int
uint5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 31);
}
/* Return 1 if operand is a 4 bit unsigned immediate. */
int
uint4_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 15);
}
/* Return 1 if operand is a 1 bit unsigned immediate (0 or 1). */
int
uint1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 1);
}
/* Return 1 if operand is an integer constant that takes 2 instructions
to load up and can be split into sethi/setlo instructions.. */
int
int_2word_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
HOST_WIDE_INT value;
REAL_VALUE_TYPE rv;
long l;
switch (GET_CODE (op))
{ {
default: default:
break; return FALSE;
case LABEL_REF:
if (TARGET_FDPIC)
return FALSE;
return (flag_pic == 0);
case CONST:
if (flag_pic || TARGET_FDPIC)
return FALSE;
op = XEXP (op, 0);
if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
op = XEXP (op, 0);
return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
case SYMBOL_REF:
if (TARGET_FDPIC)
return FALSE;
/* small data references are already 1 word */
return (flag_pic == 0) && (! SYMBOL_REF_SMALL_P (op));
case CONST_INT:
return ! IN_RANGE_P (INTVAL (op), -32768, 32767);
case CONST_DOUBLE: case QImode:
if (GET_MODE (op) == SFmode) case HImode:
{ case SImode:
REAL_VALUE_FROM_CONST_DOUBLE (rv, op); case SFmode:
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
value = l;
return ! IN_RANGE_P (value, -32768, 32767);
}
else if (GET_MODE (op) == VOIDmode)
{
value = CONST_DOUBLE_LOW (op);
return ! IN_RANGE_P (value, -32768, 32767);
}
break; break;
} }
return FALSE; if (GET_CODE (op) != MEM)
}
/* Return 1 if operand is a 16 bit unsigned immediate. */
int
uint16_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), 0, 0xffff);
}
/* Return 1 if operand is an integer constant with the bottom 16 bits
clear. */
int
upper_int16_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return ((INTVAL (op) & 0xffff) == 0);
}
/* Return true if operand is a GPR register. */
int
integer_register_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
}
/* Return true if operand is a GPR register. Do not allow SUBREG's
here, in order to prevent a combine bug. */
int
gpr_no_subreg_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE; return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op)); addr = XEXP (op, 0);
return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
} }
/* Return true if operand is a FPR register. */
int
fpr_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return FPR_OR_PSEUDO_P (REGNO (op));
}
/* Return true if operand is an even GPR or FPR register. */
int
even_reg_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (GPR_P (regno))
return (((regno - GPR_FIRST) & 1) == 0);
if (FPR_P (regno))
return (((regno - FPR_FIRST) & 1) == 0);
return FALSE;
}
/* Return true if operand is an odd GPR register. */
int
odd_reg_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
/* Assume that reload will give us an even register. */
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (GPR_P (regno))
return (((regno - GPR_FIRST) & 1) != 0);
if (FPR_P (regno))
return (((regno - FPR_FIRST) & 1) != 0);
return FALSE;
}
/* Return true if operand is an even GPR register. */
int
even_gpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! GPR_P (regno))
return FALSE;
return (((regno - GPR_FIRST) & 1) == 0);
}
/* Return true if operand is an odd GPR register. */
int
odd_gpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
/* Assume that reload will give us an even register. */
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (! GPR_P (regno))
return FALSE;
return (((regno - GPR_FIRST) & 1) != 0);
}
/* Return true if operand is a quad aligned FPR register. */
int
quad_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 3) == 0);
}
/* Return true if operand is an even FPR register. */
int
even_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 1) == 0);
}
/* Return true if operand is an odd FPR register. */
int
odd_fpr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
/* Assume that reload will give us an even register. */
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 1) != 0);
}
/* Return true if operand is a 2 word memory address that can be loaded in one
instruction to load or store. We assume the stack and frame pointers are
suitably aligned, and variables in the small data area. FIXME -- at some we
should recognize other globals and statics. We can't assume that any old
pointer is aligned, given that arguments could be passed on an odd word on
the stack and the address taken and passed through to another function. */
int
dbl_memory_one_insn_operand (rtx op, enum machine_mode mode)
{
rtx addr;
rtx addr_reg;
if (! TARGET_DWORD)
return FALSE;
if (GET_CODE (op) != MEM)
return FALSE;
if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
return FALSE;
addr = XEXP (op, 0);
if (GET_CODE (addr) == REG)
addr_reg = addr;
else if (GET_CODE (addr) == PLUS)
{
rtx addr0 = XEXP (addr, 0);
rtx addr1 = XEXP (addr, 1);
if (GET_CODE (addr0) != REG)
return FALSE;
if (got12_operand (addr1, VOIDmode))
return TRUE;
if (GET_CODE (addr1) != CONST_INT)
return FALSE;
if ((INTVAL (addr1) & 7) != 0)
return FALSE;
addr_reg = addr0;
}
else
return FALSE;
if (addr_reg == frame_pointer_rtx || addr_reg == stack_pointer_rtx)
return TRUE;
return FALSE;
}
/* Return true if operand is a 2 word memory address that needs to
use two instructions to load or store. */
int
dbl_memory_two_insn_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return FALSE;
if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
return FALSE;
if (! TARGET_DWORD)
return TRUE;
return ! dbl_memory_one_insn_operand (op, mode);
}
/* Return true if operand is something that can be an output for a move
operation. */
int
move_destination_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, FALSE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, FALSE);
}
return FALSE;
}
/* Return true if we the operand is a valid destination for a movcc_fp
instruction. This means rejecting fcc_operands, since we need
scratch registers to write to them. */
int
movcc_fp_destination_operand (rtx op, enum machine_mode mode)
{
if (fcc_operand (op, mode))
return FALSE;
return move_destination_operand (op, mode);
}
/* Look for a SYMBOL_REF of a function in an rtx. We always want to
process these separately from any offsets, such that we add any
offsets to the function descriptor (the actual pointer), not to the
function address. */
static bool
frv_function_symbol_referenced_p (rtx x)
{
const char *format;
int length;
int j;
if (GET_CODE (x) == SYMBOL_REF)
return SYMBOL_REF_FUNCTION_P (x);
length = GET_RTX_LENGTH (GET_CODE (x));
format = GET_RTX_FORMAT (GET_CODE (x));
for (j = 0; j < length; ++j)
{
switch (format[j])
{
case 'e':
if (frv_function_symbol_referenced_p (XEXP (x, j)))
return TRUE;
break;
case 'V':
case 'E':
if (XVEC (x, j) != 0)
{
int k;
for (k = 0; k < XVECLEN (x, j); ++k)
if (frv_function_symbol_referenced_p (XVECEXP (x, j, k)))
return TRUE;
}
break;
default:
/* Nothing to do. */
break;
}
}
return FALSE;
}
/* Return true if operand is something that can be an input for a move
operation. */
int
move_source_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case CONST_INT:
case CONST_DOUBLE:
return immediate_operand (op, mode);
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, FALSE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, FALSE);
}
return FALSE;
}
/* Return true if operand is something that can be an output for a conditional
move operation. */
int
condexec_dest_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, TRUE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, TRUE);
}
return FALSE;
}
/* Return true if operand is something that can be an input for a conditional
move operation. */
int
condexec_source_operand (rtx op, enum machine_mode mode)
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case CONST_INT:
case CONST_DOUBLE:
return ZERO_P (op);
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, TRUE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, TRUE);
}
return FALSE;
}
/* Return true if operand is a register of any flavor or a 0 of the
appropriate type. */
int
reg_or_0_operand (rtx op, enum machine_mode mode)
{
switch (GET_CODE (op))
{
default:
break;
case REG:
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return register_operand (op, mode);
case CONST_INT:
case CONST_DOUBLE:
return ZERO_P (op);
}
return FALSE;
}
/* Return true if operand is the link register. */
int
lr_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != REG)
return FALSE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (REGNO (op) != LR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
}
/* Return true if operand is the uClinux PIC register. */
int
fdpic_operand (rtx op, enum machine_mode mode)
{
if (!TARGET_FDPIC)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
}
int
got12_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
struct frv_unspec unspec;
if (frv_const_unspec_p (op, &unspec))
switch (unspec.reloc)
{
case R_FRV_GOT12:
case R_FRV_GOTOFF12:
case R_FRV_FUNCDESC_GOT12:
case R_FRV_FUNCDESC_GOTOFF12:
case R_FRV_GPREL12:
case R_FRV_TLSMOFF12:
return true;
}
return false;
}
/* Return true if OP is a valid const-unspec expression. */
int
const_unspec_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
struct frv_unspec unspec;
return frv_const_unspec_p (op, &unspec);
}
/* Return true if operand is a gpr register or a valid memory operand. */
int
gpr_or_memory_operand (rtx op, enum machine_mode mode)
{
return (integer_register_operand (op, mode)
|| frv_legitimate_memory_operand (op, mode, FALSE));
}
/* Return true if operand is a gpr register, a valid memory operand,
or a memory operand that can be made valid using an additional gpr
register. */
int
gpr_or_memory_operand_with_scratch (rtx op, enum machine_mode mode)
{
rtx addr;
if (gpr_or_memory_operand (op, mode))
return TRUE;
if (GET_CODE (op) != MEM)
return FALSE;
if (GET_MODE (op) != mode)
return FALSE;
addr = XEXP (op, 0);
if (GET_CODE (addr) != PLUS)
return FALSE;
if (!integer_register_operand (XEXP (addr, 0), Pmode))
return FALSE;
if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
return FALSE;
return TRUE;
}
/* Return true if operand is a fpr register or a valid memory operation. */
int
fpr_or_memory_operand (rtx op, enum machine_mode mode)
{
return (fpr_operand (op, mode)
|| frv_legitimate_memory_operand (op, mode, FALSE));
}
/* Return true if operand is an icc register. */
int
icc_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return ICC_OR_PSEUDO_P (regno);
}
/* Return true if operand is an fcc register. */
int
fcc_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return FCC_OR_PSEUDO_P (regno);
}
/* Return true if operand is either an fcc or icc register. */
int
cc_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (CC_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
}
/* Return true if operand is an integer CCR register. */
int
icr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return ICR_OR_PSEUDO_P (regno);
}
/* Return true if operand is an fcc register. */
int
fcr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return FCR_OR_PSEUDO_P (regno);
}
/* Return true if operand is either an fcc or icc register. */
int
cr_operand (rtx op, enum machine_mode mode)
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (CR_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
}
/* Return true if operand is a memory reference suitable for a call. */
int
call_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
return FALSE;
if (GET_CODE (op) == SYMBOL_REF)
return !TARGET_LONG_CALLS || SYMBOL_REF_LOCAL_P (op);
/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
never occur anyway), but prevents reload from not handling the case
properly of a call through a pointer on a function that calls
vfork/setjmp, etc. due to the need to flush all of the registers to stack. */
return gpr_or_int12_operand (op, mode);
}
/* Return true if operand is a memory reference suitable for a sibcall. */
int
sibcall_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
return FALSE;
/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
never occur anyway), but prevents reload from not handling the case
properly of a call through a pointer on a function that calls
vfork/setjmp, etc. due to the need to flush all of the registers to stack. */
return gpr_or_int12_operand (op, mode);
}
/* Returns 1 if OP is either a SYMBOL_REF or a constant. */
int
symbolic_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code c = GET_CODE (op);
if (c == CONST)
{
/* Allow (const:SI (plus:SI (symbol_ref) (const_int))). */
return GET_MODE (op) == SImode
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT;
}
return c == SYMBOL_REF || c == CONST_INT;
}
/* Return true if operator is a kind of relational operator. */
int
relational_operator (rtx op, enum machine_mode mode)
{
return (integer_relational_operator (op, mode)
|| float_relational_operator (op, mode));
}
/* Return true if OP is a relational operator suitable for CCmode,
CC_UNSmode or CC_NZmode. */
int
integer_relational_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
/* The allowable relations depend on the mode of the ICC register. */
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ:
case NE:
case LT:
case GE:
return (GET_MODE (XEXP (op, 0)) == CC_NZmode
|| GET_MODE (XEXP (op, 0)) == CCmode);
case LE:
case GT:
return GET_MODE (XEXP (op, 0)) == CCmode;
case GTU:
case GEU:
case LTU:
case LEU:
return (GET_MODE (XEXP (op, 0)) == CC_NZmode
|| GET_MODE (XEXP (op, 0)) == CC_UNSmode);
}
}
/* Return true if operator is a floating point relational operator. */
int
float_relational_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ: case NE:
case LE: case LT:
case GE: case GT:
#if 0
case UEQ: case UNE:
case ULE: case ULT:
case UGE: case UGT:
case ORDERED:
case UNORDERED:
#endif
return GET_MODE (XEXP (op, 0)) == CC_FPmode;
}
}
/* Return true if operator is EQ/NE of a conditional execution register. */
int
ccr_eqne_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
rtx op0;
rtx op1;
int regno;
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ:
case NE:
break;
}
op1 = XEXP (op, 1);
if (op1 != const0_rtx)
return FALSE;
op0 = XEXP (op, 0);
if (GET_CODE (op0) != REG)
return FALSE;
regno = REGNO (op0);
if (op_mode == CC_CCRmode && CR_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
}
/* Return true if operator is a minimum or maximum operator (both signed and
unsigned). */
int
minmax_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case SMIN:
case SMAX:
case UMIN:
case UMAX:
break;
}
if (! integer_register_operand (XEXP (op, 0), mode))
return FALSE;
if (! gpr_or_int10_operand (XEXP (op, 1), mode))
return FALSE;
return TRUE;
}
/* Return true if operator is an integer binary operator that can executed
conditionally and takes 1 cycle. */
int
condexec_si_binary_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
return TRUE;
}
}
/* Return true if operator is an integer binary operator that can be
executed conditionally by a media instruction. */
int
condexec_si_media_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case AND:
case IOR:
case XOR:
return TRUE;
}
}
/* Return true if operator is an integer division operator that can executed
conditionally. */
int
condexec_si_divide_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case DIV:
case UDIV:
return TRUE;
}
}
/* Return true if operator is an integer unary operator that can executed
conditionally. */
int
condexec_si_unary_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case NEG:
case NOT:
return TRUE;
}
}
/* Return true if operator is a conversion-type expression that can be
evaluated conditionally by floating-point instructions. */
int
condexec_sf_conv_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case NEG:
case ABS:
return TRUE;
}
}
/* Return true if operator is an addition or subtraction expression.
Such expressions can be evaluated conditionally by floating-point
instructions. */
int
condexec_sf_add_operator (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
return TRUE;
}
}
/* Return true if the memory operand is one that can be conditionally
executed. */
int
condexec_memory_operand (rtx op, enum machine_mode mode)
{
enum machine_mode op_mode = GET_MODE (op);
rtx addr;
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (op_mode)
{
default:
return FALSE;
case QImode:
case HImode:
case SImode:
case SFmode:
break;
}
if (GET_CODE (op) != MEM)
return FALSE;
addr = XEXP (op, 0);
return frv_legitimate_address_p (mode, addr, reload_completed, TRUE, FALSE);
}
/* Return true if OP is an integer binary operator that can be combined
with a (set ... (compare:CC_NZ ...)) pattern. */
int
intop_compare_operator (rtx op, enum machine_mode mode)
{
if (mode != VOIDmode && GET_MODE (op) != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFTRT:
case LSHIFTRT:
return GET_MODE (op) == SImode;
}
}
/* Return 1 if operand is a valid ACC register number. */
int
acc_operand (rtx op, enum machine_mode mode)
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& REG_P (op) && ACC_P (REGNO (op))
&& ((REGNO (op) - ACC_FIRST) & ~ACC_MASK) == 0);
}
/* Return 1 if operand is a valid even ACC register number. */
int
even_acc_operand (rtx op, enum machine_mode mode)
{
return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 1) == 0;
}
/* Return 1 if operand is zero or four. */
int
quad_acc_operand (rtx op, enum machine_mode mode)
{
return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0;
}
/* Return 1 if operand is a valid ACCG register number. */
int
accg_operand (rtx op, enum machine_mode mode)
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& REG_P (op) && ACCG_P (REGNO (op))
&& ((REGNO (op) - ACCG_FIRST) & ~ACC_MASK) == 0);
}
/* Return true if the bare return instruction can be used outside of the /* Return true if the bare return instruction can be used outside of the
epilog code. For frv, we only do it if there was no stack allocation. */ epilog code. For frv, we only do it if there was no stack allocation. */
......
...@@ -2758,104 +2758,6 @@ do { \ ...@@ -2758,104 +2758,6 @@ do { \
/* Miscellaneous Parameters. */ /* Miscellaneous Parameters. */
/* Define this if you have defined special-purpose predicates in the file
`MACHINE.c'. This macro is called within an initializer of an array of
structures. The first field in the structure is the name of a predicate and
the second field is an array of rtl codes. For each predicate, list all rtl
codes that can be in expressions matched by the predicate. The list should
have a trailing comma. Here is an example of two entries in the list for a
typical RISC machine:
#define PREDICATE_CODES \
{"gen_reg_rtx_operand", {SUBREG, REG}}, \
{"reg_or_short_cint_operand", {SUBREG, REG, CONST_INT}},
Defining this macro does not affect the generated code (however, incorrect
definitions that omit an rtl code that may be matched by the predicate can
cause the compiler to malfunction). Instead, it allows the table built by
`genrecog' to be more compact and efficient, thus speeding up the compiler.
The most important predicates to include in the list specified by this macro
are thoses used in the most insn patterns. */
#define PREDICATE_CODES \
{ "integer_register_operand", { REG, SUBREG }}, \
{ "frv_load_operand", { REG, SUBREG, MEM }}, \
{ "gpr_no_subreg_operand", { REG }}, \
{ "gpr_or_fpr_operand", { REG, SUBREG }}, \
{ "gpr_or_int12_operand", { REG, SUBREG, CONST_INT, CONST }}, \
{ "gpr_fpr_or_int12_operand", { REG, SUBREG, CONST_INT }}, \
{ "gpr_or_int10_operand", { REG, SUBREG, CONST_INT }}, \
{ "gpr_or_int_operand", { REG, SUBREG, CONST_INT }}, \
{ "move_source_operand", { REG, SUBREG, CONST_INT, MEM, \
CONST_DOUBLE, CONST, \
SYMBOL_REF, LABEL_REF }}, \
{ "move_destination_operand", { REG, SUBREG, MEM }}, \
{ "movcc_fp_destination_operand", { REG, SUBREG, MEM }}, \
{ "condexec_source_operand", { REG, SUBREG, CONST_INT, MEM, \
CONST_DOUBLE }}, \
{ "condexec_dest_operand", { REG, SUBREG, MEM }}, \
{ "reg_or_0_operand", { REG, SUBREG, CONST_INT }}, \
{ "lr_operand", { REG }}, \
{ "gpr_or_memory_operand", { REG, SUBREG, MEM }}, \
{ "gpr_or_memory_operand_with_scratch", { REG, SUBREG, MEM }}, \
{ "fpr_or_memory_operand", { REG, SUBREG, MEM }}, \
{ "int12_operand", { CONST_INT }}, \
{ "int_2word_operand", { CONST_INT, CONST_DOUBLE, \
SYMBOL_REF, LABEL_REF, CONST }}, \
{ "fdpic_operand", { REG }}, \
{ "fdpic_fptr_operand", { REG }}, \
{ "ldd_address_operand", { REG, SUBREG, PLUS }}, \
{ "got12_operand", { CONST }}, \
{ "const_unspec_operand", { CONST }}, \
{ "icc_operand", { REG }}, \
{ "fcc_operand", { REG }}, \
{ "cc_operand", { REG }}, \
{ "icr_operand", { REG }}, \
{ "fcr_operand", { REG }}, \
{ "cr_operand", { REG }}, \
{ "fpr_operand", { REG, SUBREG }}, \
{ "even_reg_operand", { REG, SUBREG }}, \
{ "odd_reg_operand", { REG, SUBREG }}, \
{ "even_gpr_operand", { REG, SUBREG }}, \
{ "odd_gpr_operand", { REG, SUBREG }}, \
{ "quad_fpr_operand", { REG, SUBREG }}, \
{ "even_fpr_operand", { REG, SUBREG }}, \
{ "odd_fpr_operand", { REG, SUBREG }}, \
{ "dbl_memory_one_insn_operand", { MEM }}, \
{ "dbl_memory_two_insn_operand", { MEM }}, \
{ "call_operand", { REG, SUBREG, CONST_INT, \
CONST, SYMBOL_REF }}, \
{ "sibcall_operand", { REG, SUBREG, CONST_INT, \
CONST }}, \
{ "upper_int16_operand", { CONST_INT }}, \
{ "uint16_operand", { CONST_INT }}, \
{ "symbolic_operand", { SYMBOL_REF, CONST_INT }}, \
{ "relational_operator", { EQ, NE, LE, LT, GE, GT, \
LEU, LTU, GEU, GTU }}, \
{ "integer_relational_operator", { EQ, NE, LE, LT, GE, GT, \
LEU, LTU, GEU, GTU }}, \
{ "float_relational_operator", { EQ, NE, LE, LT, GE, GT }}, \
{ "ccr_eqne_operator", { EQ, NE }}, \
{ "minmax_operator", { SMIN, SMAX, UMIN, UMAX }}, \
{ "condexec_si_binary_operator", { PLUS, MINUS, AND, IOR, XOR, \
ASHIFT, ASHIFTRT, LSHIFTRT }}, \
{ "condexec_si_media_operator", { AND, IOR, XOR }}, \
{ "condexec_si_divide_operator", { DIV, UDIV }}, \
{ "condexec_si_unary_operator", { NOT, NEG }}, \
{ "condexec_sf_add_operator", { PLUS, MINUS }}, \
{ "condexec_sf_conv_operator", { ABS, NEG }}, \
{ "intop_compare_operator", { PLUS, MINUS, AND, IOR, XOR, \
ASHIFT, ASHIFTRT, LSHIFTRT }}, \
{ "fpr_or_int6_operand", { REG, SUBREG, CONST_INT }}, \
{ "int6_operand", { CONST_INT }}, \
{ "int5_operand", { CONST_INT }}, \
{ "uint5_operand", { CONST_INT }}, \
{ "uint4_operand", { CONST_INT }}, \
{ "uint1_operand", { CONST_INT }}, \
{ "acc_operand", { REG, SUBREG }}, \
{ "even_acc_operand", { REG, SUBREG }}, \
{ "quad_acc_operand", { REG, SUBREG }}, \
{ "accg_operand", { REG, SUBREG }},
/* An alias for a machine mode name. This is the machine mode that elements of /* An alias for a machine mode name. This is the machine mode that elements of
a jump-table should have. */ a jump-table should have. */
#define CASE_VECTOR_MODE SImode #define CASE_VECTOR_MODE SImode
......
...@@ -1504,6 +1504,7 @@ ...@@ -1504,6 +1504,7 @@
;; ) ;; )
;; ;;
(include "predicates.md")
;; :::::::::::::::::::: ;; ::::::::::::::::::::
;; :: ;; ::
......
;; Predicate definitions for Frv.
;; Copyright (C) 2005 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
;; GCC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; GCC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GCC; see the file COPYING. If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;; Return true if operand is a GPR register.
(define_predicate "integer_register_operand"
(match_code "reg,subreg")
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
})
;; Return 1 is OP is a memory operand, or will be turned into one by
;; reload.
(define_predicate "frv_load_operand"
(match_code "reg,subreg,mem")
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (reload_in_progress)
{
rtx tmp = op;
if (GET_CODE (tmp) == SUBREG)
tmp = SUBREG_REG (tmp);
if (GET_CODE (tmp) == REG
&& REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
op = reg_equiv_memory_loc[REGNO (tmp)];
}
return op && memory_operand (op, mode);
})
;; Return true if operand is a GPR register. Do not allow SUBREG's
;; here, in order to prevent a combine bug.
(define_predicate "gpr_no_subreg_operand"
(match_code "reg")
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
})
;; Return 1 if operand is a GPR register or a FPR register.
(define_predicate "gpr_or_fpr_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
return FALSE;
})
;; Return 1 if operand is a GPR register or 12 bit signed immediate.
(define_predicate "gpr_or_int12_operand"
(match_code "reg,subreg,const_int,const")
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
if (got12_operand (op, mode))
return true;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
})
;; Return 1 if operand is a GPR register, or a FPR register, or a 12
;; bit signed immediate.
(define_predicate "gpr_fpr_or_int12_operand"
(match_code "reg,subreg,const_int")
{
int regno;
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -2048, 2047);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
return FALSE;
})
;; Return 1 if operand is a register or 10 bit signed immediate.
(define_predicate "gpr_or_int10_operand"
(match_code "reg,subreg,const_int")
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -512, 511);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
})
;; Return 1 if operand is a register or an integer immediate.
(define_predicate "gpr_or_int_operand"
(match_code "reg,subreg,const_int")
{
if (GET_CODE (op) == CONST_INT)
return TRUE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return GPR_OR_PSEUDO_P (REGNO (op));
})
;; Return true if operand is something that can be an input for a move
;; operation.
(define_predicate "move_source_operand"
(match_code "reg,subreg,const_int,mem,const_double,const,symbol_ref,label_ref")
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case CONST_INT:
case CONST_DOUBLE:
return immediate_operand (op, mode);
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, FALSE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, FALSE);
}
return FALSE;
})
;; Return true if operand is something that can be an output for a
;; move operation.
(define_predicate "move_destination_operand"
(match_code "reg,subreg,mem")
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, FALSE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, FALSE);
}
return FALSE;
})
;; Return true if we the operand is a valid destination for a movcc_fp
;; instruction. This means rejecting fcc_operands, since we need
;; scratch registers to write to them.
(define_predicate "movcc_fp_destination_operand"
(match_code "reg,subreg,mem")
{
if (fcc_operand (op, mode))
return FALSE;
return move_destination_operand (op, mode);
})
;; Return true if operand is something that can be an input for a
;; conditional move operation.
(define_predicate "condexec_source_operand"
(match_code "reg,subreg,const_int,mem,const_double")
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case CONST_INT:
case CONST_DOUBLE:
return ZERO_P (op);
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, TRUE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, TRUE);
}
return FALSE;
})
;; Return true if operand is something that can be an output for a
;; conditional move operation.
(define_predicate "condexec_dest_operand"
(match_code "reg,subreg,mem")
{
rtx subreg;
enum rtx_code code;
switch (GET_CODE (op))
{
default:
break;
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
subreg = SUBREG_REG (op);
code = GET_CODE (subreg);
if (code == MEM)
return frv_legitimate_address_p (mode, XEXP (subreg, 0),
reload_completed, TRUE, FALSE);
return (code == REG);
case REG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return TRUE;
case MEM:
return frv_legitimate_memory_operand (op, mode, TRUE);
}
return FALSE;
})
;; Return true if operand is a register of any flavor or a 0 of the
;; appropriate type.
(define_predicate "reg_or_0_operand"
(match_code "reg,subreg,const_int")
{
switch (GET_CODE (op))
{
default:
break;
case REG:
case SUBREG:
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
return register_operand (op, mode);
case CONST_INT:
case CONST_DOUBLE:
return ZERO_P (op);
}
return FALSE;
})
;; Return true if operand is the link register.
(define_predicate "lr_operand"
(match_code "reg")
{
if (GET_CODE (op) != REG)
return FALSE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (REGNO (op) != LR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
})
;; Return true if operand is a gpr register or a valid memory operand.
(define_predicate "gpr_or_memory_operand"
(match_code "reg,subreg,mem")
{
return (integer_register_operand (op, mode)
|| frv_legitimate_memory_operand (op, mode, FALSE));
})
;; Return true if operand is a gpr register, a valid memory operand,
;; or a memory operand that can be made valid using an additional gpr
;; register.
(define_predicate "gpr_or_memory_operand_with_scratch"
(match_code "reg,subreg,mem")
{
rtx addr;
if (gpr_or_memory_operand (op, mode))
return TRUE;
if (GET_CODE (op) != MEM)
return FALSE;
if (GET_MODE (op) != mode)
return FALSE;
addr = XEXP (op, 0);
if (GET_CODE (addr) != PLUS)
return FALSE;
if (!integer_register_operand (XEXP (addr, 0), Pmode))
return FALSE;
if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
return FALSE;
return TRUE;
})
;; Return true if operand is a fpr register or a valid memory
;; operation.
(define_predicate "fpr_or_memory_operand"
(match_code "reg,subreg,mem")
{
return (fpr_operand (op, mode)
|| frv_legitimate_memory_operand (op, mode, FALSE));
})
;; Return 1 if operand is a 12 bit signed immediate.
(define_predicate "int12_operand"
(match_code "const_int")
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), -2048, 2047);
})
;; Return 1 if operand is an integer constant that takes 2
;; instructions to load up and can be split into sethi/setlo
;; instructions..
(define_predicate "int_2word_operand"
(match_code "const_int,const_double,symbol_ref,label_ref,const")
{
HOST_WIDE_INT value;
REAL_VALUE_TYPE rv;
long l;
switch (GET_CODE (op))
{
default:
break;
case LABEL_REF:
if (TARGET_FDPIC)
return FALSE;
return (flag_pic == 0);
case CONST:
if (flag_pic || TARGET_FDPIC)
return FALSE;
op = XEXP (op, 0);
if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
op = XEXP (op, 0);
return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;
case SYMBOL_REF:
if (TARGET_FDPIC)
return FALSE;
/* small data references are already 1 word */
return (flag_pic == 0) && (! SYMBOL_REF_SMALL_P (op));
case CONST_INT:
return ! IN_RANGE_P (INTVAL (op), -32768, 32767);
case CONST_DOUBLE:
if (GET_MODE (op) == SFmode)
{
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
value = l;
return ! IN_RANGE_P (value, -32768, 32767);
}
else if (GET_MODE (op) == VOIDmode)
{
value = CONST_DOUBLE_LOW (op);
return ! IN_RANGE_P (value, -32768, 32767);
}
break;
}
return FALSE;
})
;; Return true if operand is the uClinux PIC register.
(define_predicate "fdpic_operand"
(match_code "reg")
{
if (!TARGET_FDPIC)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
})
;; TODO: Add a comment here.
(define_predicate "fdpic_fptr_operand"
(match_code "reg")
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER)
return FALSE;
return TRUE;
})
;; An address operand that may use a pair of registers, an addressing
;; mode that we reject in general.
(define_predicate "ldd_address_operand"
(match_code "reg,subreg,plus")
{
if (GET_MODE (op) != mode && GET_MODE (op) != VOIDmode)
return FALSE;
return frv_legitimate_address_p (DImode, op, reload_completed, FALSE, TRUE);
})
;; TODO: Add a comment here.
(define_predicate "got12_operand"
(match_code "const")
{
struct frv_unspec unspec;
if (frv_const_unspec_p (op, &unspec))
switch (unspec.reloc)
{
case R_FRV_GOT12:
case R_FRV_GOTOFF12:
case R_FRV_FUNCDESC_GOT12:
case R_FRV_FUNCDESC_GOTOFF12:
case R_FRV_GPREL12:
case R_FRV_TLSMOFF12:
return true;
}
return false;
})
;; Return true if OP is a valid const-unspec expression.
(define_predicate "const_unspec_operand"
(match_code "const")
{
struct frv_unspec unspec;
return frv_const_unspec_p (op, &unspec);
})
;; Return true if operand is an icc register.
(define_predicate "icc_operand"
(match_code "reg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return ICC_OR_PSEUDO_P (regno);
})
;; Return true if operand is an fcc register.
(define_predicate "fcc_operand"
(match_code "reg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return FCC_OR_PSEUDO_P (regno);
})
;; Return true if operand is either an fcc or icc register.
(define_predicate "cc_operand"
(match_code "reg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (CC_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
})
;; Return true if operand is an integer CCR register.
(define_predicate "icr_operand"
(match_code "reg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return ICR_OR_PSEUDO_P (regno);
})
;; Return true if operand is an fcc register.
(define_predicate "fcr_operand"
(match_code "reg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
return FCR_OR_PSEUDO_P (regno);
})
;; Return true if operand is either an fcc or icc register.
(define_predicate "cr_operand"
(match_code "reg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (CR_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
})
;; Return true if operand is a FPR register.
(define_predicate "fpr_operand"
(match_code "reg,subreg")
{
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return FPR_OR_PSEUDO_P (REGNO (op));
})
;; Return true if operand is an even GPR or FPR register.
(define_predicate "even_reg_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (GPR_P (regno))
return (((regno - GPR_FIRST) & 1) == 0);
if (FPR_P (regno))
return (((regno - FPR_FIRST) & 1) == 0);
return FALSE;
})
;; Return true if operand is an odd GPR register.
(define_predicate "odd_reg_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
/* Assume that reload will give us an even register. */
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (GPR_P (regno))
return (((regno - GPR_FIRST) & 1) != 0);
if (FPR_P (regno))
return (((regno - FPR_FIRST) & 1) != 0);
return FALSE;
})
;; Return true if operand is an even GPR register.
(define_predicate "even_gpr_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! GPR_P (regno))
return FALSE;
return (((regno - GPR_FIRST) & 1) == 0);
})
;; Return true if operand is an odd GPR register.
(define_predicate "odd_gpr_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
/* Assume that reload will give us an even register. */
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (! GPR_P (regno))
return FALSE;
return (((regno - GPR_FIRST) & 1) != 0);
})
;; Return true if operand is a quad aligned FPR register.
(define_predicate "quad_fpr_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 3) == 0);
})
;; Return true if operand is an even FPR register.
(define_predicate "even_fpr_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
if (regno >= FIRST_PSEUDO_REGISTER)
return TRUE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 1) == 0);
})
;; Return true if operand is an odd FPR register.
(define_predicate "odd_fpr_operand"
(match_code "reg,subreg")
{
int regno;
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
regno = REGNO (op);
/* Assume that reload will give us an even register. */
if (regno >= FIRST_PSEUDO_REGISTER)
return FALSE;
if (! FPR_P (regno))
return FALSE;
return (((regno - FPR_FIRST) & 1) != 0);
})
;; Return true if operand is a 2 word memory address that can be
;; loaded in one instruction to load or store. We assume the stack
;; and frame pointers are suitably aligned, and variables in the small
;; data area. FIXME -- at some we should recognize other globals and
;; statics. We can't assume that any old pointer is aligned, given
;; that arguments could be passed on an odd word on the stack and the
;; address taken and passed through to another function.
(define_predicate "dbl_memory_one_insn_operand"
(match_code "mem")
{
rtx addr;
rtx addr_reg;
if (! TARGET_DWORD)
return FALSE;
if (GET_CODE (op) != MEM)
return FALSE;
if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
return FALSE;
addr = XEXP (op, 0);
if (GET_CODE (addr) == REG)
addr_reg = addr;
else if (GET_CODE (addr) == PLUS)
{
rtx addr0 = XEXP (addr, 0);
rtx addr1 = XEXP (addr, 1);
if (GET_CODE (addr0) != REG)
return FALSE;
if (got12_operand (addr1, VOIDmode))
return TRUE;
if (GET_CODE (addr1) != CONST_INT)
return FALSE;
if ((INTVAL (addr1) & 7) != 0)
return FALSE;
addr_reg = addr0;
}
else
return FALSE;
if (addr_reg == frame_pointer_rtx || addr_reg == stack_pointer_rtx)
return TRUE;
return FALSE;
})
;; Return true if operand is a 2 word memory address that needs to use
;; two instructions to load or store.
(define_predicate "dbl_memory_two_insn_operand"
(match_code "mem")
{
if (GET_CODE (op) != MEM)
return FALSE;
if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD)
return FALSE;
if (! TARGET_DWORD)
return TRUE;
return ! dbl_memory_one_insn_operand (op, mode);
})
;; Return true if operand is a memory reference suitable for a call.
(define_predicate "call_operand"
(match_code "reg,subreg,const_int,const,symbol_ref")
{
if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
return FALSE;
if (GET_CODE (op) == SYMBOL_REF)
return !TARGET_LONG_CALLS || SYMBOL_REF_LOCAL_P (op);
/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
never occur anyway), but prevents reload from not handling the case
properly of a call through a pointer on a function that calls
vfork/setjmp, etc. due to the need to flush all of the registers to stack. */
return gpr_or_int12_operand (op, mode);
})
;; Return true if operand is a memory reference suitable for a
;; sibcall.
(define_predicate "sibcall_operand"
(match_code "reg,subreg,const_int,const")
{
if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT)
return FALSE;
/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should
never occur anyway), but prevents reload from not handling the case
properly of a call through a pointer on a function that calls
vfork/setjmp, etc. due to the need to flush all of the registers to stack. */
return gpr_or_int12_operand (op, mode);
})
;; Return 1 if operand is an integer constant with the bottom 16 bits
;; clear.
(define_predicate "upper_int16_operand"
(match_code "const_int")
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return ((INTVAL (op) & 0xffff) == 0);
})
;; Return 1 if operand is a 16 bit unsigned immediate.
(define_predicate "uint16_operand"
(match_code "const_int")
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), 0, 0xffff);
})
;; Returns 1 if OP is either a SYMBOL_REF or a constant.
(define_predicate "symbolic_operand"
(match_code "symbol_ref,const_int")
{
enum rtx_code c = GET_CODE (op);
if (c == CONST)
{
/* Allow (const:SI (plus:SI (symbol_ref) (const_int))). */
return GET_MODE (op) == SImode
&& GET_CODE (XEXP (op, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT;
}
return c == SYMBOL_REF || c == CONST_INT;
})
;; Return true if operator is a kind of relational operator.
(define_predicate "relational_operator"
(match_code "eq,ne,le,lt,ge,gt,leu,ltu,geu,gtu")
{
return (integer_relational_operator (op, mode)
|| float_relational_operator (op, mode));
})
;; Return true if OP is a relational operator suitable for CCmode,
;; CC_UNSmode or CC_NZmode.
(define_predicate "integer_relational_operator"
(match_code "eq,ne,le,lt,ge,gt,leu,ltu,geu,gtu")
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
/* The allowable relations depend on the mode of the ICC register. */
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ:
case NE:
case LT:
case GE:
return (GET_MODE (XEXP (op, 0)) == CC_NZmode
|| GET_MODE (XEXP (op, 0)) == CCmode);
case LE:
case GT:
return GET_MODE (XEXP (op, 0)) == CCmode;
case GTU:
case GEU:
case LTU:
case LEU:
return (GET_MODE (XEXP (op, 0)) == CC_NZmode
|| GET_MODE (XEXP (op, 0)) == CC_UNSmode);
}
})
;; Return true if operator is a floating point relational operator.
(define_predicate "float_relational_operator"
(match_code "eq,ne,le,lt,ge,gt")
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ: case NE:
case LE: case LT:
case GE: case GT:
#if 0
case UEQ: case UNE:
case ULE: case ULT:
case UGE: case UGT:
case ORDERED:
case UNORDERED:
#endif
return GET_MODE (XEXP (op, 0)) == CC_FPmode;
}
})
;; Return true if operator is EQ/NE of a conditional execution
;; register.
(define_predicate "ccr_eqne_operator"
(match_code "eq,ne")
{
enum machine_mode op_mode = GET_MODE (op);
rtx op0;
rtx op1;
int regno;
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case EQ:
case NE:
break;
}
op1 = XEXP (op, 1);
if (op1 != const0_rtx)
return FALSE;
op0 = XEXP (op, 0);
if (GET_CODE (op0) != REG)
return FALSE;
regno = REGNO (op0);
if (op_mode == CC_CCRmode && CR_OR_PSEUDO_P (regno))
return TRUE;
return FALSE;
})
;; Return true if operator is a minimum or maximum operator (both
;; signed and unsigned).
(define_predicate "minmax_operator"
(match_code "smin,smax,umin,umax")
{
if (mode != VOIDmode && mode != GET_MODE (op))
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case SMIN:
case SMAX:
case UMIN:
case UMAX:
break;
}
if (! integer_register_operand (XEXP (op, 0), mode))
return FALSE;
if (! gpr_or_int10_operand (XEXP (op, 1), mode))
return FALSE;
return TRUE;
})
;; Return true if operator is an integer binary operator that can
;; executed conditionally and takes 1 cycle.
(define_predicate "condexec_si_binary_operator"
(match_code "plus,minus,and,ior,xor,ashift,ashiftrt,lshiftrt")
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
return TRUE;
}
})
;; Return true if operator is an integer binary operator that can be
;; executed conditionally by a media instruction.
(define_predicate "condexec_si_media_operator"
(match_code "and,ior,xor")
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case AND:
case IOR:
case XOR:
return TRUE;
}
})
;; Return true if operator is an integer division operator that can
;; executed conditionally.
(define_predicate "condexec_si_divide_operator"
(match_code "div,udiv")
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case DIV:
case UDIV:
return TRUE;
}
})
;; Return true if operator is an integer unary operator that can
;; executed conditionally.
(define_predicate "condexec_si_unary_operator"
(match_code "not,neg")
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case NEG:
case NOT:
return TRUE;
}
})
;; Return true if operator is an addition or subtraction
;; expression. Such expressions can be evaluated conditionally by
;; floating-point instructions.
(define_predicate "condexec_sf_add_operator"
(match_code "plus,minus")
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
return TRUE;
}
})
;; Return true if operator is a conversion-type expression that can be
;; evaluated conditionally by floating-point instructions.
(define_predicate "condexec_sf_conv_operator"
(match_code "abs,neg")
{
enum machine_mode op_mode = GET_MODE (op);
if (mode != VOIDmode && op_mode != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case NEG:
case ABS:
return TRUE;
}
})
;; Return true if OP is an integer binary operator that can be
;; combined with a (set ... (compare:CC_NZ ...)) pattern.
(define_predicate "intop_compare_operator"
(match_code "plus,minus,and,ior,xor,ashift,ashiftrt,lshiftrt")
{
if (mode != VOIDmode && GET_MODE (op) != mode)
return FALSE;
switch (GET_CODE (op))
{
default:
return FALSE;
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFTRT:
case LSHIFTRT:
return GET_MODE (op) == SImode;
}
})
;; Return 1 if operand is a register or 6 bit signed immediate.
(define_predicate "fpr_or_int6_operand"
(match_code "reg,subreg,const_int")
{
if (GET_CODE (op) == CONST_INT)
return IN_RANGE_P (INTVAL (op), -32, 31);
if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) != REG)
return register_operand (op, mode);
op = SUBREG_REG (op);
}
if (GET_CODE (op) != REG)
return FALSE;
return FPR_OR_PSEUDO_P (REGNO (op));
})
;; Return 1 if operand is a 6 bit signed immediate.
(define_predicate "int6_operand"
(match_code "const_int")
{
if (GET_CODE (op) != CONST_INT)
return FALSE;
return IN_RANGE_P (INTVAL (op), -32, 31);
})
;; Return 1 if operand is a 5 bit signed immediate.
(define_predicate "int5_operand"
(match_code "const_int")
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), -16, 15);
})
;; Return 1 if operand is a 5 bit unsigned immediate.
(define_predicate "uint5_operand"
(match_code "const_int")
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 31);
})
;; Return 1 if operand is a 4 bit unsigned immediate.
(define_predicate "uint4_operand"
(match_code "const_int")
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 15);
})
;; Return 1 if operand is a 1 bit unsigned immediate (0 or 1).
(define_predicate "uint1_operand"
(match_code "const_int")
{
return GET_CODE (op) == CONST_INT && IN_RANGE_P (INTVAL (op), 0, 1);
})
;; Return 1 if operand is a valid ACC register number.
(define_predicate "acc_operand"
(match_code "reg,subreg")
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& REG_P (op) && ACC_P (REGNO (op))
&& ((REGNO (op) - ACC_FIRST) & ~ACC_MASK) == 0);
})
;; Return 1 if operand is a valid even ACC register number.
(define_predicate "even_acc_operand"
(match_code "reg,subreg")
{
return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 1) == 0;
})
;; Return 1 if operand is zero or four.
(define_predicate "quad_acc_operand"
(match_code "reg,subreg")
{
return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0;
})
;; Return 1 if operand is a valid ACCG register number.
(define_predicate "accg_operand"
(match_code "reg,subreg")
{
return ((mode == VOIDmode || mode == GET_MODE (op))
&& REG_P (op) && ACCG_P (REGNO (op))
&& ((REGNO (op) - ACCG_FIRST) & ~ACC_MASK) == 0);
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment