From 6d26dc3b6b153f89f0086c23b6584a556ce68556 Mon Sep 17 00:00:00 2001 From: Kazu Hirata <kazu@cs.umass.edu> Date: Mon, 4 Apr 2005 21:53:22 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 37 + gcc/config/frv/frv-protos.h | 13 + gcc/config/frv/frv.c | 1636 ++-------------------------------- gcc/config/frv/frv.h | 98 -- gcc/config/frv/frv.md | 1 + gcc/config/frv/predicates.md | 1550 ++++++++++++++++++++++++++++++++ 6 files changed, 1652 insertions(+), 1683 deletions(-) create mode 100644 gcc/config/frv/predicates.md diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f7e21e705aff..63fbd069d364 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -3,6 +3,43 @@ * 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 diff --git a/gcc/config/frv/frv-protos.h b/gcc/config/frv/frv-protos.h index 23bb792ed89e..89107a022edc 100644 --- a/gcc/config/frv/frv-protos.h +++ b/gcc/config/frv/frv-protos.h @@ -205,5 +205,18 @@ extern rtx frv_matching_accg_for_acc (rtx); 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 diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c index b75826c4daf5..f867159c6391 100644 --- a/gcc/config/frv/frv.c +++ b/gcc/config/frv/frv.c @@ -123,15 +123,6 @@ static unsigned int frv_num_nops; 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 { @@ -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_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); @@ -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, 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 *); @@ -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 appropriately. */ -static FRV_INLINE bool +bool frv_const_unspec_p (rtx x, struct frv_unspec *unspec) { if (GET_CODE (x) == CONST) @@ -3715,7 +3704,7 @@ frv_find_base_term (rtx x) /* 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) @@ -3805,1607 +3794,84 @@ frv_expand_fdpic_call (rtx *operands, bool ret_value, bool sibcall) 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; -} -/* 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); -} - /* 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. */ diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h index 1cd416d0732b..9961758f611a 100644 --- a/gcc/config/frv/frv.h +++ b/gcc/config/frv/frv.h @@ -2758,104 +2758,6 @@ do { \ /* 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 diff --git a/gcc/config/frv/frv.md b/gcc/config/frv/frv.md index a81bc8b940eb..3770b790afa6 100644 --- a/gcc/config/frv/frv.md +++ b/gcc/config/frv/frv.md @@ -1504,6 +1504,7 @@ ;; ) ;; +(include "predicates.md") ;; :::::::::::::::::::: ;; :: diff --git a/gcc/config/frv/predicates.md b/gcc/config/frv/predicates.md new file mode 100644 index 000000000000..656b6950170b --- /dev/null +++ b/gcc/config/frv/predicates.md @@ -0,0 +1,1550 @@ +;; 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); +}) -- GitLab