* config/frv/frv.h (PREDICATE_CODES): Add CONST to
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>
PR target/19537
extern void frv_expand_fdpic_call (rtx *, bool, bool);
extern rtx frv_gen_GPsym2reg (rtx, 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
REG < REGNO (X) + HARD_REGNO_NREGS (REGNO (X), GET_MODE (X)); \
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. */
typedef struct frv_tmp_reg_struct
{
static int frv_default_flags_for_cpu (void);
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_const_unspec_p (rtx, struct frv_unspec *);
static void frv_print_operand_memory_reference_reg
(FILE *, rtx);
static void frv_print_operand_memory_reference (FILE *, rtx, int);
static void frv_frame_access_standard_regs (enum frv_stack_op,
frv_stack_t *);
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 enum machine_mode frv_matching_accg_mode (enum machine_mode);
static rtx frv_read_argument (tree *);
/* Return true if X is a valid relocation unspec. If it is, fill in UNSPEC
appropriately. */
-static FRV_INLINE bool
+bool
frv_const_unspec_p (rtx x, struct frv_unspec *unspec)
{
if (GET_CODE (x) == CONST)
/* Return 1 if operand is a valid FRV address. CONDEXEC_P is true if
the operand is used by a predicated instruction. */
-static int
+int
frv_legitimate_memory_operand (rtx op, enum machine_mode mode, int condexec_p)
{
return ((GET_MODE (op) == mode || mode == VOIDmode)
c = gen_call_fdpicdi (picreg, const0_rtx, lr);
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;
-}
\f
-/* Return 1 is OP is a memory operand, or will be turned into one by
- reload. */
-
-int
-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. */
+/* 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. */
-int
-gpr_or_int12_operand (rtx op, enum machine_mode mode)
+static bool
+frv_function_symbol_referenced_p (rtx x)
{
- if (GET_CODE (op) == CONST_INT)
- return IN_RANGE_P (INTVAL (op), -2048, 2047);
+ const char *format;
+ int length;
+ int j;
- if (got12_operand (op, mode))
- return true;
+ if (GET_CODE (x) == SYMBOL_REF)
+ return SYMBOL_REF_FUNCTION_P (x);
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return FALSE;
+ length = GET_RTX_LENGTH (GET_CODE (x));
+ 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)
- 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. */
-
-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;
+ switch (format[j])
+ {
+ case 'e':
+ if (frv_function_symbol_referenced_p (XEXP (x, j)))
+ return TRUE;
+ break;
- if (GET_CODE (op) == SUBREG)
- {
- if (GET_CODE (SUBREG_REG (op)) != REG)
- return register_operand (op, mode);
+ 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;
- 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 1 if operand is a register or 6 bit signed immediate. */
-
-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. */
+/* Return true if the memory operand is one that can be conditionally
+ executed. */
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)
- return FALSE;
-
- return IN_RANGE_P (INTVAL (op), -2048, 2047);
-}
-
-/* Return 1 if operand is a 6 bit signed immediate. */
+ enum machine_mode op_mode = GET_MODE (op);
+ rtx addr;
-int
-int6_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != CONST_INT)
+ if (mode != VOIDmode && op_mode != mode)
return FALSE;
- return IN_RANGE_P (INTVAL (op), -32, 31);
-}
-
-/* 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))
+ switch (op_mode)
{
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);
+ return FALSE;
- 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);
- }
+ case QImode:
+ case HImode:
+ case SImode:
+ case SFmode:
break;
}
- return FALSE;
-}
-
-/* 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)
+ if (GET_CODE (op) != MEM)
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);
-}
-
\f
/* 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. */
\f
/* 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
a jump-table should have. */
#define CASE_VECTOR_MODE SImode
;; )
;;
+(include "predicates.md")
\f
;; ::::::::::::::::::::
;; ::
--- /dev/null
+;; 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);
+})