mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-23 11:44:41 +08:00
arm.md: Include predicates.md.
* arm.md: Include predicates.md. * predicates.md: New file. * arm.c (s_register_operand, arm_hard_register_operand) (arm_general_register_operand, f_register_operand, reg_or_int_operand) (arm_immediate_operand, arm_neg_immediate_operand) (arm_not_immediate_operand, arm_rhs_operand, arm_rhsm_operand) (arm_add_operand, arm_addimm_operand, arm_not_operand) (offsettable_memory_operand, alignable_memory_operand) (arm_reload_memory_operand, arm_float_rhs_operand) (arm_float_add_operand, vfp_compare_operand, arm_float_compare_operand) (index_operand, shiftable_operator, logical_binary_operator) (shift_operator, equality_operator, arm_comparison_operator) (minmax_operator, cc_register, dominant_cc_register) (arm_extendqisi_mem_op, power_of_two_operand, nonimmediate_di_operand) (di_operand, nonimmediate_soft_df_operand, soft_df_operand) (const_shift_operand, load_multiple_operation) (store_multiple_operation, multi_register_push, thumb_cmp_operand) (thumb_cmpneg_operand, thumb_cbrch_target_operand) (cirrus_register_operand, cirrus_fp_register) (cirrus_shift_const): Delete, replaced with equivalents in predicates.md. (shift_op): Handle ROTATE. * arm-protos.h: Delete declarations for above. * arm.h (PREDICATE_CODES, SPECIAL_MODE_PREDICATES): Delete. * t-arm (MD_INCLUDES): Add predicates.md. (s-preds): Depends on MD_INCLUDES. From-SVN: r86512
This commit is contained in:
parent
886ce862cb
commit
a657c98a58
@ -1,3 +1,32 @@
|
||||
2004-08-24 Richard Earnshaw <rearnsha@arm.com>
|
||||
|
||||
* arm.md: Include predicates.md.
|
||||
* predicates.md: New file.
|
||||
* arm.c (s_register_operand, arm_hard_register_operand)
|
||||
(arm_general_register_operand, f_register_operand, reg_or_int_operand)
|
||||
(arm_immediate_operand, arm_neg_immediate_operand)
|
||||
(arm_not_immediate_operand, arm_rhs_operand, arm_rhsm_operand)
|
||||
(arm_add_operand, arm_addimm_operand, arm_not_operand)
|
||||
(offsettable_memory_operand, alignable_memory_operand)
|
||||
(arm_reload_memory_operand, arm_float_rhs_operand)
|
||||
(arm_float_add_operand, vfp_compare_operand, arm_float_compare_operand)
|
||||
(index_operand, shiftable_operator, logical_binary_operator)
|
||||
(shift_operator, equality_operator, arm_comparison_operator)
|
||||
(minmax_operator, cc_register, dominant_cc_register)
|
||||
(arm_extendqisi_mem_op, power_of_two_operand, nonimmediate_di_operand)
|
||||
(di_operand, nonimmediate_soft_df_operand, soft_df_operand)
|
||||
(const_shift_operand, load_multiple_operation)
|
||||
(store_multiple_operation, multi_register_push, thumb_cmp_operand)
|
||||
(thumb_cmpneg_operand, thumb_cbrch_target_operand)
|
||||
(cirrus_register_operand, cirrus_fp_register)
|
||||
(cirrus_shift_const): Delete, replaced with equivalents in
|
||||
predicates.md.
|
||||
(shift_op): Handle ROTATE.
|
||||
* arm-protos.h: Delete declarations for above.
|
||||
* arm.h (PREDICATE_CODES, SPECIAL_MODE_PREDICATES): Delete.
|
||||
* t-arm (MD_INCLUDES): Add predicates.md.
|
||||
(s-preds): Depends on MD_INCLUDES.
|
||||
|
||||
2004-08-24 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* config/mips/mips.c (mips_gen_conditional_trap): Fix mode.
|
||||
|
@ -61,49 +61,8 @@ extern int arm_const_double_rtx (rtx);
|
||||
extern int neg_const_double_rtx_ok_for_fpa (rtx);
|
||||
extern enum reg_class vfp_secondary_reload_class (enum machine_mode, rtx);
|
||||
|
||||
/* Predicates. */
|
||||
extern int s_register_operand (rtx, enum machine_mode);
|
||||
extern int arm_hard_register_operand (rtx, enum machine_mode);
|
||||
extern int arm_general_register_operand (rtx, enum machine_mode);
|
||||
extern int f_register_operand (rtx, enum machine_mode);
|
||||
extern int reg_or_int_operand (rtx, enum machine_mode);
|
||||
extern int arm_reload_memory_operand (rtx, enum machine_mode);
|
||||
extern int arm_rhs_operand (rtx, enum machine_mode);
|
||||
extern int arm_rhsm_operand (rtx, enum machine_mode);
|
||||
extern int arm_add_operand (rtx, enum machine_mode);
|
||||
extern int arm_addimm_operand (rtx, enum machine_mode);
|
||||
extern int arm_not_operand (rtx, enum machine_mode);
|
||||
extern int arm_extendqisi_mem_op (rtx, enum machine_mode);
|
||||
extern int offsettable_memory_operand (rtx, enum machine_mode);
|
||||
extern int alignable_memory_operand (rtx, enum machine_mode);
|
||||
extern int arm_float_rhs_operand (rtx, enum machine_mode);
|
||||
extern int arm_float_add_operand (rtx, enum machine_mode);
|
||||
extern int power_of_two_operand (rtx, enum machine_mode);
|
||||
extern int nonimmediate_di_operand (rtx, enum machine_mode);
|
||||
extern int di_operand (rtx, enum machine_mode);
|
||||
extern int nonimmediate_soft_df_operand (rtx, enum machine_mode);
|
||||
extern int soft_df_operand (rtx, enum machine_mode);
|
||||
extern int index_operand (rtx, enum machine_mode);
|
||||
extern int const_shift_operand (rtx, enum machine_mode);
|
||||
extern int arm_comparison_operator (rtx, enum machine_mode);
|
||||
extern int shiftable_operator (rtx, enum machine_mode);
|
||||
extern int shift_operator (rtx, enum machine_mode);
|
||||
extern int equality_operator (rtx, enum machine_mode);
|
||||
extern int minmax_operator (rtx, enum machine_mode);
|
||||
extern int cc_register (rtx, enum machine_mode);
|
||||
extern int dominant_cc_register (rtx, enum machine_mode);
|
||||
extern int logical_binary_operator (rtx, enum machine_mode);
|
||||
extern int multi_register_push (rtx, enum machine_mode);
|
||||
extern int load_multiple_operation (rtx, enum machine_mode);
|
||||
extern int store_multiple_operation (rtx, enum machine_mode);
|
||||
extern int cirrus_fp_register (rtx, enum machine_mode);
|
||||
extern int cirrus_general_operand (rtx, enum machine_mode);
|
||||
extern int cirrus_register_operand (rtx, enum machine_mode);
|
||||
extern int cirrus_shift_const (rtx, enum machine_mode);
|
||||
extern int cirrus_memory_offset (rtx);
|
||||
extern int arm_coproc_mem_operand (rtx, bool);
|
||||
extern int vfp_compare_operand (rtx, enum machine_mode);
|
||||
extern int arm_float_compare_operand (rtx, enum machine_mode);
|
||||
extern int arm_no_early_store_addr_dep (rtx, rtx);
|
||||
extern int arm_no_early_alu_shift_dep (rtx, rtx);
|
||||
extern int arm_no_early_alu_shift_value_dep (rtx, rtx);
|
||||
@ -191,8 +150,6 @@ extern void thumb_final_prescan_insn (rtx);
|
||||
extern const char *thumb_load_double_from_address (rtx *);
|
||||
extern const char *thumb_output_move_mem_multiple (int, rtx *);
|
||||
extern void thumb_expand_movmemqi (rtx *);
|
||||
extern int thumb_cmp_operand (rtx, enum machine_mode);
|
||||
extern int thumb_cbrch_target_operand (rtx, enum machine_mode);
|
||||
extern rtx *thumb_legitimize_pic_address (rtx, enum machine_mode, rtx);
|
||||
extern int thumb_go_if_legitimate_address (enum machine_mode, rtx);
|
||||
extern rtx arm_return_addr (int, rtx);
|
||||
|
@ -4624,243 +4624,6 @@ neg_const_double_rtx_ok_for_fpa (rtx x)
|
||||
|
||||
/* Predicates for `match_operand' and `match_operator'. */
|
||||
|
||||
/* s_register_operand is the same as register_operand, but it doesn't accept
|
||||
(SUBREG (MEM)...).
|
||||
|
||||
This function exists because at the time it was put in it led to better
|
||||
code. SUBREG(MEM) always needs a reload in the places where
|
||||
s_register_operand is used, and this seemed to lead to excessive
|
||||
reloading. */
|
||||
int
|
||||
s_register_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return 0;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
/* We don't consider registers whose class is NO_REGS
|
||||
to be a register operand. */
|
||||
/* XXX might have to check for lo regs only for thumb ??? */
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
|
||||
}
|
||||
|
||||
/* A hard register operand (even before reload. */
|
||||
int
|
||||
arm_hard_register_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return 0;
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& REGNO (op) < FIRST_PSEUDO_REGISTER);
|
||||
}
|
||||
|
||||
/* An arm register operand. */
|
||||
int
|
||||
arm_general_register_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return 0;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) <= LAST_ARM_REGNUM
|
||||
|| REGNO (op) >= FIRST_PSEUDO_REGISTER));
|
||||
}
|
||||
|
||||
/* Only accept reg, subreg(reg), const_int. */
|
||||
int
|
||||
reg_or_int_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_CODE (op) == CONST_INT)
|
||||
return 1;
|
||||
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return 0;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
/* We don't consider registers whose class is NO_REGS
|
||||
to be a register operand. */
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
|
||||
}
|
||||
|
||||
/* Return 1 if OP is an item in memory, given that we are in reload. */
|
||||
int
|
||||
arm_reload_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
int regno = true_regnum (op);
|
||||
|
||||
return (!CONSTANT_P (op)
|
||||
&& (regno == -1
|
||||
|| (GET_CODE (op) == REG
|
||||
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)));
|
||||
}
|
||||
|
||||
/* Return TRUE for valid operands for the rhs of an ARM instruction. */
|
||||
int
|
||||
arm_rhs_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return (s_register_operand (op, mode)
|
||||
|| (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
|
||||
}
|
||||
|
||||
/* Return TRUE for valid operands for the
|
||||
rhs of an ARM instruction, or a load. */
|
||||
int
|
||||
arm_rhsm_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return (s_register_operand (op, mode)
|
||||
|| (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
|
||||
|| memory_operand (op, mode));
|
||||
}
|
||||
|
||||
/* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
|
||||
constant that is valid when negated. */
|
||||
int
|
||||
arm_add_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (TARGET_THUMB)
|
||||
return thumb_cmp_operand (op, mode);
|
||||
|
||||
return (s_register_operand (op, mode)
|
||||
|| (GET_CODE (op) == CONST_INT
|
||||
&& (const_ok_for_arm (INTVAL (op))
|
||||
|| const_ok_for_arm (-INTVAL (op)))));
|
||||
}
|
||||
|
||||
/* Return TRUE for valid ARM constants (or when valid if negated). */
|
||||
int
|
||||
arm_addimm_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return (GET_CODE (op) == CONST_INT
|
||||
&& (const_ok_for_arm (INTVAL (op))
|
||||
|| const_ok_for_arm (-INTVAL (op))));
|
||||
}
|
||||
|
||||
int
|
||||
arm_not_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return (s_register_operand (op, mode)
|
||||
|| (GET_CODE (op) == CONST_INT
|
||||
&& (const_ok_for_arm (INTVAL (op))
|
||||
|| const_ok_for_arm (~INTVAL (op)))));
|
||||
}
|
||||
|
||||
/* Return TRUE if the operand is a memory reference which contains an
|
||||
offsettable address. */
|
||||
int
|
||||
offsettable_memory_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (mode == VOIDmode)
|
||||
mode = GET_MODE (op);
|
||||
|
||||
return (mode == GET_MODE (op)
|
||||
&& GET_CODE (op) == MEM
|
||||
&& offsettable_address_p (reload_completed | reload_in_progress,
|
||||
mode, XEXP (op, 0)));
|
||||
}
|
||||
|
||||
/* Return TRUE if the operand is a memory reference which is, or can be
|
||||
made word aligned by adjusting the offset. */
|
||||
int
|
||||
alignable_memory_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
rtx reg;
|
||||
|
||||
if (mode == VOIDmode)
|
||||
mode = GET_MODE (op);
|
||||
|
||||
if (mode != GET_MODE (op) || GET_CODE (op) != MEM)
|
||||
return 0;
|
||||
|
||||
op = XEXP (op, 0);
|
||||
|
||||
return ((GET_CODE (reg = op) == REG
|
||||
|| (GET_CODE (op) == SUBREG
|
||||
&& GET_CODE (reg = SUBREG_REG (op)) == REG)
|
||||
|| (GET_CODE (op) == PLUS
|
||||
&& GET_CODE (XEXP (op, 1)) == CONST_INT
|
||||
&& (GET_CODE (reg = XEXP (op, 0)) == REG
|
||||
|| (GET_CODE (XEXP (op, 0)) == SUBREG
|
||||
&& GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
|
||||
&& REGNO_POINTER_ALIGN (REGNO (reg)) >= 32);
|
||||
}
|
||||
|
||||
/* Similar to s_register_operand, but does not allow hard integer
|
||||
registers. */
|
||||
int
|
||||
f_register_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return 0;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
/* We don't consider registers whose class is NO_REGS
|
||||
to be a register operand. */
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) == FPA_REGS));
|
||||
}
|
||||
|
||||
/* Return TRUE for valid operands for the rhs of an floating point insns.
|
||||
Allows regs or certain consts on FPA, just regs for everything else. */
|
||||
int
|
||||
arm_float_rhs_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return FALSE;
|
||||
|
||||
if (TARGET_FPA && GET_CODE (op) == CONST_DOUBLE)
|
||||
return arm_const_double_rtx (op);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int
|
||||
arm_float_add_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return FALSE;
|
||||
|
||||
if (TARGET_FPA && GET_CODE (op) == CONST_DOUBLE)
|
||||
return (arm_const_double_rtx (op)
|
||||
|| neg_const_double_rtx_ok_for_fpa (op));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* Return TRUE if OP is suitable for the rhs of a floating point comparison.
|
||||
Depends which fpu we are targeting. */
|
||||
|
||||
int
|
||||
arm_float_compare_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (TARGET_VFP)
|
||||
return vfp_compare_operand (op, mode);
|
||||
else
|
||||
return arm_float_rhs_operand (op, mode);
|
||||
}
|
||||
|
||||
|
||||
/* Return nonzero if OP is a valid Cirrus memory address pattern. */
|
||||
int
|
||||
cirrus_memory_offset (rtx op)
|
||||
@ -4898,55 +4661,6 @@ cirrus_memory_offset (rtx op)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
arm_extendqisi_mem_op (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (!memory_operand (op, mode))
|
||||
return 0;
|
||||
|
||||
return arm_legitimate_address_p (mode, XEXP (op, 0), SIGN_EXTEND, 0);
|
||||
}
|
||||
|
||||
/* Return nonzero if OP is a Cirrus or general register. */
|
||||
int
|
||||
cirrus_register_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
|
||||
|| REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
|
||||
}
|
||||
|
||||
/* Return nonzero if OP is a cirrus FP register. */
|
||||
int
|
||||
cirrus_fp_register (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (GET_MODE (op) != mode && mode != VOIDmode)
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
|
||||
}
|
||||
|
||||
/* Return nonzero if OP is a 6bit constant (0..63). */
|
||||
int
|
||||
cirrus_shift_const (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return (GET_CODE (op) == CONST_INT
|
||||
&& INTVAL (op) >= 0
|
||||
&& INTVAL (op) < 64);
|
||||
}
|
||||
|
||||
|
||||
/* Return TRUE if OP is a valid VFP memory address pattern.
|
||||
WB if true if writeback address modes are allowed. */
|
||||
|
||||
@ -5014,18 +4728,6 @@ arm_coproc_mem_operand (rtx op, bool wb)
|
||||
}
|
||||
|
||||
|
||||
/* Return TRUE if OP is a REG or constant zero. */
|
||||
int
|
||||
vfp_compare_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
return (GET_CODE (op) == CONST_DOUBLE
|
||||
&& arm_const_double_rtx (op));
|
||||
}
|
||||
|
||||
|
||||
/* Return GENERAL_REGS if a scratch register required to reload x to/from
|
||||
VFP registers. Otherwise return NO_REGS. */
|
||||
|
||||
@ -5211,262 +4913,6 @@ cirrus_reorg (rtx first)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return nonzero if OP is a constant power of two. */
|
||||
int
|
||||
power_of_two_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (GET_CODE (op) == CONST_INT)
|
||||
{
|
||||
HOST_WIDE_INT value = INTVAL (op);
|
||||
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Return TRUE for a valid operand of a DImode operation.
|
||||
Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
|
||||
Note that this disallows MEM(REG+REG), but allows
|
||||
MEM(PRE/POST_INC/DEC(REG)). */
|
||||
int
|
||||
di_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
switch (GET_CODE (op))
|
||||
{
|
||||
case CONST_DOUBLE:
|
||||
case CONST_INT:
|
||||
return TRUE;
|
||||
|
||||
case MEM:
|
||||
return memory_address_p (DImode, XEXP (op, 0));
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Like di_operand, but don't accept constants. */
|
||||
int
|
||||
nonimmediate_di_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
if (GET_CODE (op) == MEM)
|
||||
return memory_address_p (DImode, XEXP (op, 0));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Return TRUE for a valid operand of a DFmode operation when soft-float.
|
||||
Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
|
||||
Note that this disallows MEM(REG+REG), but allows
|
||||
MEM(PRE/POST_INC/DEC(REG)). */
|
||||
int
|
||||
soft_df_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
if (mode != VOIDmode && GET_MODE (op) != mode)
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG && CONSTANT_P (SUBREG_REG (op)))
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
switch (GET_CODE (op))
|
||||
{
|
||||
case CONST_DOUBLE:
|
||||
return TRUE;
|
||||
|
||||
case MEM:
|
||||
return memory_address_p (DFmode, XEXP (op, 0));
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Like soft_df_operand, but don't accept constants. */
|
||||
int
|
||||
nonimmediate_soft_df_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return TRUE;
|
||||
|
||||
if (mode != VOIDmode && GET_MODE (op) != mode)
|
||||
return FALSE;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
if (GET_CODE (op) == MEM)
|
||||
return memory_address_p (DFmode, XEXP (op, 0));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Return TRUE for valid index operands. */
|
||||
int
|
||||
index_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return (s_register_operand (op, mode)
|
||||
|| (immediate_operand (op, mode)
|
||||
&& (GET_CODE (op) != CONST_INT
|
||||
|| (INTVAL (op) < 4096 && INTVAL (op) > -4096))));
|
||||
}
|
||||
|
||||
/* Return TRUE for valid shifts by a constant. This also accepts any
|
||||
power of two on the (somewhat overly relaxed) assumption that the
|
||||
shift operator in this case was a mult. */
|
||||
int
|
||||
const_shift_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return (power_of_two_operand (op, mode)
|
||||
|| (immediate_operand (op, mode)
|
||||
&& (GET_CODE (op) != CONST_INT
|
||||
|| (INTVAL (op) < 32 && INTVAL (op) > 0))));
|
||||
}
|
||||
|
||||
/* Return TRUE for arithmetic operators which can be combined with a multiply
|
||||
(shift). */
|
||||
int
|
||||
shiftable_operator (rtx x, enum machine_mode mode)
|
||||
{
|
||||
enum rtx_code code;
|
||||
|
||||
if (GET_MODE (x) != mode)
|
||||
return FALSE;
|
||||
|
||||
code = GET_CODE (x);
|
||||
|
||||
return (code == PLUS || code == MINUS
|
||||
|| code == IOR || code == XOR || code == AND);
|
||||
}
|
||||
|
||||
/* Return TRUE for binary logical operators. */
|
||||
int
|
||||
logical_binary_operator (rtx x, enum machine_mode mode)
|
||||
{
|
||||
enum rtx_code code;
|
||||
|
||||
if (GET_MODE (x) != mode)
|
||||
return FALSE;
|
||||
|
||||
code = GET_CODE (x);
|
||||
|
||||
return (code == IOR || code == XOR || code == AND);
|
||||
}
|
||||
|
||||
/* Return TRUE for shift operators. */
|
||||
int
|
||||
shift_operator (rtx x,enum machine_mode mode)
|
||||
{
|
||||
enum rtx_code code;
|
||||
|
||||
if (GET_MODE (x) != mode)
|
||||
return FALSE;
|
||||
|
||||
code = GET_CODE (x);
|
||||
|
||||
if (code == MULT)
|
||||
return power_of_two_operand (XEXP (x, 1), mode);
|
||||
|
||||
return (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT
|
||||
|| code == ROTATERT);
|
||||
}
|
||||
|
||||
/* Return TRUE if x is EQ or NE. */
|
||||
int
|
||||
equality_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return GET_CODE (x) == EQ || GET_CODE (x) == NE;
|
||||
}
|
||||
|
||||
/* Return TRUE if x is a comparison operator other than LTGT or UNEQ. */
|
||||
int
|
||||
arm_comparison_operator (rtx x, enum machine_mode mode)
|
||||
{
|
||||
return (comparison_operator (x, mode)
|
||||
&& GET_CODE (x) != LTGT
|
||||
&& GET_CODE (x) != UNEQ);
|
||||
}
|
||||
|
||||
/* Return TRUE for SMIN SMAX UMIN UMAX operators. */
|
||||
int
|
||||
minmax_operator (rtx x, enum machine_mode mode)
|
||||
{
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
|
||||
if (GET_MODE (x) != mode)
|
||||
return FALSE;
|
||||
|
||||
return code == SMIN || code == SMAX || code == UMIN || code == UMAX;
|
||||
}
|
||||
|
||||
/* Return TRUE if this is the condition code register, if we aren't given
|
||||
a mode, accept any class CCmode register. */
|
||||
int
|
||||
cc_register (rtx x, enum machine_mode mode)
|
||||
{
|
||||
if (mode == VOIDmode)
|
||||
{
|
||||
mode = GET_MODE (x);
|
||||
|
||||
if (GET_MODE_CLASS (mode) != MODE_CC)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( GET_MODE (x) == mode
|
||||
&& GET_CODE (x) == REG
|
||||
&& REGNO (x) == CC_REGNUM)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Return TRUE if this is the condition code register, if we aren't given
|
||||
a mode, accept any class CCmode register which indicates a dominance
|
||||
expression. */
|
||||
int
|
||||
dominant_cc_register (rtx x, enum machine_mode mode)
|
||||
{
|
||||
if (mode == VOIDmode)
|
||||
{
|
||||
mode = GET_MODE (x);
|
||||
|
||||
if (GET_MODE_CLASS (mode) != MODE_CC)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (mode != CC_DNEmode && mode != CC_DEQmode
|
||||
&& mode != CC_DLEmode && mode != CC_DLTmode
|
||||
&& mode != CC_DGEmode && mode != CC_DGTmode
|
||||
&& mode != CC_DLEUmode && mode != CC_DLTUmode
|
||||
&& mode != CC_DGEUmode && mode != CC_DGTUmode)
|
||||
return FALSE;
|
||||
|
||||
return cc_register (x, mode);
|
||||
}
|
||||
|
||||
/* Return TRUE if X references a SYMBOL_REF. */
|
||||
int
|
||||
symbol_mentioned_p (rtx x)
|
||||
@ -5582,124 +5028,6 @@ adjacent_mem_locations (rtx a, rtx b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 if OP is a load multiple operation. It is known to be
|
||||
parallel and the first section will be tested. */
|
||||
int
|
||||
load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
HOST_WIDE_INT count = XVECLEN (op, 0);
|
||||
int dest_regno;
|
||||
rtx src_addr;
|
||||
HOST_WIDE_INT i = 1, base = 0;
|
||||
rtx elt;
|
||||
|
||||
if (count <= 1
|
||||
|| GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
return 0;
|
||||
|
||||
/* Check to see if this might be a write-back. */
|
||||
if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
|
||||
{
|
||||
i++;
|
||||
base = 1;
|
||||
|
||||
/* Now check it more carefully. */
|
||||
if (GET_CODE (SET_DEST (elt)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Perform a quick check so we don't blow up below. */
|
||||
if (count <= i
|
||||
|| GET_CODE (XVECEXP (op, 0, i - 1)) != SET
|
||||
|| GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
|
||||
|| GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
|
||||
return 0;
|
||||
|
||||
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
|
||||
src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
|
||||
|
||||
for (; i < count; i++)
|
||||
{
|
||||
elt = XVECEXP (op, 0, i);
|
||||
|
||||
if (GET_CODE (elt) != SET
|
||||
|| GET_CODE (SET_DEST (elt)) != REG
|
||||
|| GET_MODE (SET_DEST (elt)) != SImode
|
||||
|| REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
|
||||
|| GET_CODE (SET_SRC (elt)) != MEM
|
||||
|| GET_MODE (SET_SRC (elt)) != SImode
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
|
||||
|| !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|
||||
|| GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return 1 if OP is a store multiple operation. It is known to be
|
||||
parallel and the first section will be tested. */
|
||||
int
|
||||
store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
HOST_WIDE_INT count = XVECLEN (op, 0);
|
||||
int src_regno;
|
||||
rtx dest_addr;
|
||||
HOST_WIDE_INT i = 1, base = 0;
|
||||
rtx elt;
|
||||
|
||||
if (count <= 1
|
||||
|| GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
return 0;
|
||||
|
||||
/* Check to see if this might be a write-back. */
|
||||
if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
|
||||
{
|
||||
i++;
|
||||
base = 1;
|
||||
|
||||
/* Now check it more carefully. */
|
||||
if (GET_CODE (SET_DEST (elt)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Perform a quick check so we don't blow up below. */
|
||||
if (count <= i
|
||||
|| GET_CODE (XVECEXP (op, 0, i - 1)) != SET
|
||||
|| GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
|
||||
|| GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
|
||||
return 0;
|
||||
|
||||
src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
|
||||
dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
|
||||
|
||||
for (; i < count; i++)
|
||||
{
|
||||
elt = XVECEXP (op, 0, i);
|
||||
|
||||
if (GET_CODE (elt) != SET
|
||||
|| GET_CODE (SET_SRC (elt)) != REG
|
||||
|| GET_MODE (SET_SRC (elt)) != SImode
|
||||
|| REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
|
||||
|| GET_CODE (SET_DEST (elt)) != MEM
|
||||
|| GET_MODE (SET_DEST (elt)) != SImode
|
||||
|| GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
|
||||
|| !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
|
||||
|| GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
|
||||
HOST_WIDE_INT *load_offset)
|
||||
@ -6106,17 +5434,6 @@ emit_stm_seq (rtx *operands, int nops)
|
||||
return "";
|
||||
}
|
||||
|
||||
int
|
||||
multi_register_push (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (GET_CODE (op) != PARALLEL
|
||||
|| (GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
|| (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
|
||||
|| (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Routines for use in generating RTL. */
|
||||
|
||||
@ -9093,6 +8410,13 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
|
||||
mnem = "lsr";
|
||||
break;
|
||||
|
||||
case ROTATE:
|
||||
if (*amountp == -1)
|
||||
abort ();
|
||||
*amountp = 32 - *amountp;
|
||||
|
||||
/* Fall through. */
|
||||
|
||||
case ROTATERT:
|
||||
mnem = "ror";
|
||||
break;
|
||||
@ -14177,42 +13501,6 @@ thumb_expand_movmemqi (rtx *operands)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
thumb_cmp_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return ((GET_CODE (op) == CONST_INT
|
||||
&& INTVAL (op) < 256
|
||||
&& INTVAL (op) >= 0)
|
||||
|| s_register_operand (op, mode));
|
||||
}
|
||||
|
||||
int
|
||||
thumb_cmpneg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return (GET_CODE (op) == CONST_INT
|
||||
&& INTVAL (op) < 0
|
||||
&& INTVAL (op) > -256);
|
||||
}
|
||||
|
||||
/* Return TRUE if a result can be stored in OP without clobbering the
|
||||
condition code register. Prior to reload we only accept a
|
||||
register. After reload we have to be able to handle memory as
|
||||
well, since a pseudo may not get a hard reg and reload cannot
|
||||
handle output-reloads on jump insns.
|
||||
|
||||
We could possibly handle mem before reload as well, but that might
|
||||
complicate things with the need to handle increment
|
||||
side-effects. */
|
||||
|
||||
int
|
||||
thumb_cbrch_target_operand (rtx op, enum machine_mode mode)
|
||||
{
|
||||
return (s_register_operand (op, mode)
|
||||
|| ((reload_in_progress || reload_completed)
|
||||
&& memory_operand (op, mode)));
|
||||
}
|
||||
|
||||
/* Handle storing a half-word to memory during reload. */
|
||||
void
|
||||
thumb_reload_out_hi (rtx *operands)
|
||||
{
|
||||
|
@ -2594,57 +2594,6 @@ extern int making_const_table;
|
||||
: arm_gen_return_addr_mask ())
|
||||
|
||||
|
||||
/* Define the codes that are matched by predicates in arm.c */
|
||||
#define PREDICATE_CODES \
|
||||
{"s_register_operand", {SUBREG, REG}}, \
|
||||
{"arm_general_register_operand", {SUBREG, REG}}, \
|
||||
{"arm_hard_register_operand", {REG}}, \
|
||||
{"f_register_operand", {SUBREG, REG}}, \
|
||||
{"arm_add_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"arm_addimm_operand", {CONST_INT}}, \
|
||||
{"arm_float_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \
|
||||
{"arm_float_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \
|
||||
{"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"arm_not_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"index_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"thumb_cmp_operand", {SUBREG, REG, CONST_INT}}, \
|
||||
{"thumb_cmpneg_operand", {CONST_INT}}, \
|
||||
{"thumb_cbrch_target_operand", {SUBREG, REG, MEM}}, \
|
||||
{"offsettable_memory_operand", {MEM}}, \
|
||||
{"alignable_memory_operand", {MEM}}, \
|
||||
{"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \
|
||||
{"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \
|
||||
{"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \
|
||||
{"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \
|
||||
{"nonimmediate_di_operand", {SUBREG, REG, MEM}}, \
|
||||
{"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \
|
||||
{"nonimmediate_soft_df_operand", {SUBREG, REG, MEM}}, \
|
||||
{"load_multiple_operation", {PARALLEL}}, \
|
||||
{"store_multiple_operation", {PARALLEL}}, \
|
||||
{"equality_operator", {EQ, NE}}, \
|
||||
{"arm_comparison_operator", {EQ, NE, LE, LT, GE, GT, GEU, GTU, LEU, \
|
||||
LTU, UNORDERED, ORDERED, UNLT, UNLE, \
|
||||
UNGE, UNGT}}, \
|
||||
{"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \
|
||||
{"const_shift_operand", {CONST_INT}}, \
|
||||
{"multi_register_push", {PARALLEL}}, \
|
||||
{"cc_register", {REG}}, \
|
||||
{"logical_binary_operator", {AND, IOR, XOR}}, \
|
||||
{"cirrus_register_operand", {REG}}, \
|
||||
{"cirrus_fp_register", {REG}}, \
|
||||
{"cirrus_shift_const", {CONST_INT}}, \
|
||||
{"dominant_cc_register", {REG}}, \
|
||||
{"arm_float_compare_operand", {REG, CONST_DOUBLE}}, \
|
||||
{"vfp_compare_operand", {REG, CONST_DOUBLE}},
|
||||
|
||||
/* Define this if you have special predicates that know special things
|
||||
about modes. Genrecog will warn about certain forms of
|
||||
match_operand without a mode; if the operand predicate is listed in
|
||||
SPECIAL_MODE_PREDICATES, the warning will be suppressed. */
|
||||
#define SPECIAL_MODE_PREDICATES \
|
||||
"cc_register", "dominant_cc_register",
|
||||
|
||||
enum arm_builtins
|
||||
{
|
||||
ARM_BUILTIN_GETWCX,
|
||||
|
@ -286,6 +286,8 @@
|
||||
;; distant label. Only applicable to Thumb code.
|
||||
(define_attr "far_jump" "yes,no" (const_string "no"))
|
||||
|
||||
(include "predicates.md")
|
||||
|
||||
;;---------------------------------------------------------------------------
|
||||
;; Pipeline descriptions
|
||||
|
||||
|
470
gcc/config/arm/predicates.md
Normal file
470
gcc/config/arm/predicates.md
Normal file
@ -0,0 +1,470 @@
|
||||
;; Predicate definitions for ARM and Thumb
|
||||
;; Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
;; Contributed by ARM Ltd.
|
||||
|
||||
;; 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.
|
||||
|
||||
(define_predicate "s_register_operand"
|
||||
(match_code "reg,subreg")
|
||||
{
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
/* We don't consider registers whose class is NO_REGS
|
||||
to be a register operand. */
|
||||
/* XXX might have to check for lo regs only for thumb ??? */
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
|
||||
})
|
||||
|
||||
;; Any hard register.
|
||||
(define_predicate "arm_hard_register_operand"
|
||||
(match_code "reg")
|
||||
{
|
||||
return REGNO (op) < FIRST_PSEUDO_REGISTER;
|
||||
})
|
||||
|
||||
;; Any core register, or any pseudo. */
|
||||
(define_predicate "arm_general_register_operand"
|
||||
(match_code "reg,subreg")
|
||||
{
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) <= LAST_ARM_REGNUM
|
||||
|| REGNO (op) >= FIRST_PSEUDO_REGISTER));
|
||||
})
|
||||
|
||||
(define_predicate "f_register_operand"
|
||||
(match_code "reg,subreg")
|
||||
{
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
/* We don't consider registers whose class is NO_REGS
|
||||
to be a register operand. */
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) == FPA_REGS));
|
||||
})
|
||||
|
||||
;; Reg, subreg(reg) or const_int.
|
||||
(define_predicate "reg_or_int_operand"
|
||||
(ior (match_code "const_int")
|
||||
(match_operand 0 "s_register_operand")))
|
||||
|
||||
(define_predicate "arm_immediate_operand"
|
||||
(and (match_code "const_int")
|
||||
(match_test "const_ok_for_arm (INTVAL (op))")))
|
||||
|
||||
(define_predicate "arm_neg_immediate_operand"
|
||||
(and (match_code "const_int")
|
||||
(match_test "const_ok_for_arm (-INTVAL (op))")))
|
||||
|
||||
(define_predicate "arm_not_immediate_operand"
|
||||
(and (match_code "const_int")
|
||||
(match_test "const_ok_for_arm (~INTVAL (op))")))
|
||||
|
||||
;; Something valid on the RHS of an ARM data-processing instruction
|
||||
(define_predicate "arm_rhs_operand"
|
||||
(ior (match_operand 0 "s_register_operand")
|
||||
(match_operand 0 "arm_immediate_operand")))
|
||||
|
||||
(define_predicate "arm_rhsm_operand"
|
||||
(ior (match_operand 0 "arm_rhs_operand")
|
||||
(match_operand 0 "memory_operand")))
|
||||
|
||||
(define_predicate "arm_add_operand"
|
||||
(ior (match_operand 0 "arm_rhs_operand")
|
||||
(match_operand 0 "arm_neg_immediate_operand")))
|
||||
|
||||
(define_predicate "arm_addimm_operand"
|
||||
(ior (match_operand 0 "arm_immediate_operand")
|
||||
(match_operand 0 "arm_neg_immediate_operand")))
|
||||
|
||||
(define_predicate "arm_not_operand"
|
||||
(ior (match_operand 0 "arm_rhs_operand")
|
||||
(match_operand 0 "arm_not_immediate_operand")))
|
||||
|
||||
;; True if the operand is a memory reference which contains an
|
||||
;; offsettable address.
|
||||
(define_predicate "offsettable_memory_operand"
|
||||
(and (match_code "mem")
|
||||
(match_test
|
||||
"offsettable_address_p (reload_completed | reload_in_progress,
|
||||
mode, XEXP (op, 0))")))
|
||||
|
||||
;; True if the operand is a memory reference which is, or can be made,
|
||||
;; word aligned by adjusting the offset.
|
||||
(define_predicate "alignable_memory_operand"
|
||||
(match_code "mem")
|
||||
{
|
||||
rtx reg;
|
||||
|
||||
op = XEXP (op, 0);
|
||||
|
||||
return ((GET_CODE (reg = op) == REG
|
||||
|| (GET_CODE (op) == SUBREG
|
||||
&& GET_CODE (reg = SUBREG_REG (op)) == REG)
|
||||
|| (GET_CODE (op) == PLUS
|
||||
&& GET_CODE (XEXP (op, 1)) == CONST_INT
|
||||
&& (GET_CODE (reg = XEXP (op, 0)) == REG
|
||||
|| (GET_CODE (XEXP (op, 0)) == SUBREG
|
||||
&& GET_CODE (reg = SUBREG_REG (XEXP (op, 0))) == REG))))
|
||||
&& REGNO_POINTER_ALIGN (REGNO (reg)) >= 32);
|
||||
})
|
||||
|
||||
(define_predicate "arm_reload_memory_operand"
|
||||
(and (match_code "reg,subreg")
|
||||
(match_test "(!CONSTANT_P (op)
|
||||
&& (true_regnum(op) == -1
|
||||
|| (GET_CODE (op) == REG
|
||||
&& REGNO (op) >= FIRST_PSEUDO_REGISTER)))")))
|
||||
|
||||
;; True for valid operands for the rhs of an floating point insns.
|
||||
;; Allows regs or certain consts on FPA, just regs for everything else.
|
||||
(define_predicate "arm_float_rhs_operand"
|
||||
(ior (match_operand 0 "s_register_operand")
|
||||
(and (match_code "const_double")
|
||||
(match_test "TARGET_FPA && arm_const_double_rtx (op)"))))
|
||||
|
||||
(define_predicate "arm_float_add_operand"
|
||||
(ior (match_operand 0 "arm_float_rhs_operand")
|
||||
(and (match_code "const_double")
|
||||
(match_test "TARGET_FPA && neg_const_double_rtx_ok_for_fpa (op)"))))
|
||||
|
||||
(define_predicate "vfp_compare_operand"
|
||||
(ior (match_operand 0 "s_register_operand")
|
||||
(and (match_code "const_double")
|
||||
(match_test "arm_const_double_rtx (op)"))))
|
||||
|
||||
(define_predicate "arm_float_compare_operand"
|
||||
(if_then_else (match_test "TARGET_VFP")
|
||||
(match_operand 0 "vfp_compare_operand")
|
||||
(match_operand 0 "arm_float_rhs_operand")))
|
||||
|
||||
;; True for valid index operands.
|
||||
(define_predicate "index_operand"
|
||||
(ior (match_operand 0 "s_register_operand")
|
||||
(and (match_operand 0 "immediate_operand")
|
||||
(match_test "(GET_CODE (op) != CONST_INT
|
||||
|| (INTVAL (op) < 4096 && INTVAL (op) > -4096))"))))
|
||||
|
||||
;; True for operators that can be combined with a shift in ARM state.
|
||||
(define_special_predicate "shiftable_operator"
|
||||
(and (match_code "plus,minus,ior,xor,and")
|
||||
(match_test "mode == GET_MODE (op)")))
|
||||
|
||||
;; True for logical binary opertors.
|
||||
(define_special_predicate "logical_binary_operator"
|
||||
(and (match_code "ior,xor,and")
|
||||
(match_test "mode == GET_MODE (op)")))
|
||||
|
||||
;; True for shift operators.
|
||||
(define_special_predicate "shift_operator"
|
||||
(and (ior (ior (and (match_code "mult")
|
||||
(match_test "power_of_two_operand (XEXP (op, 1), mode)"))
|
||||
(and (match_code "rotate")
|
||||
(match_test "GET_CODE (XEXP (op, 1)) == CONST_INT
|
||||
&& ((unsigned HOST_WIDE_INT) INTVAL (XEXP (op, 1))) < 32")))
|
||||
(match_code "ashift,ashiftrt,lshiftrt,rotatert"))
|
||||
(match_test "mode == GET_MODE (op)")))
|
||||
|
||||
;; True for EQ & NE
|
||||
(define_special_predicate "equality_operator"
|
||||
(match_code "eq,ne"))
|
||||
|
||||
;; True for comparisons other than LTGT or UNEQ.
|
||||
(define_special_predicate "arm_comparison_operator"
|
||||
(match_code "eq,ne,le,lt,ge,gt,geu,gtu,leu,ltu,unordered,ordered,unlt,unle,unge,ungt"))
|
||||
|
||||
(define_special_predicate "minmax_operator"
|
||||
(and (match_code "smin,smax,umin,umax")
|
||||
(match_test "mode == GET_MODE (op)")))
|
||||
|
||||
(define_special_predicate "cc_register"
|
||||
(and (match_code "reg")
|
||||
(and (match_test "REGNO (op) == CC_REGNUM")
|
||||
(ior (match_test "mode == GET_MODE (op)")
|
||||
(match_test "mode == VOIDmode && GET_MODE_CLASS (GET_MODE (op)) == MODE_CC")))))
|
||||
|
||||
(define_special_predicate "dominant_cc_register"
|
||||
(match_code "reg")
|
||||
{
|
||||
if (mode == VOIDmode)
|
||||
{
|
||||
mode = GET_MODE (op);
|
||||
|
||||
if (GET_MODE_CLASS (mode) != MODE_CC)
|
||||
return false;
|
||||
}
|
||||
|
||||
return (cc_register (op, mode)
|
||||
&& (mode == CC_DNEmode
|
||||
|| mode == CC_DEQmode
|
||||
|| mode == CC_DLEmode
|
||||
|| mode == CC_DLTmode
|
||||
|| mode == CC_DGEmode
|
||||
|| mode == CC_DGTmode
|
||||
|| mode == CC_DLEUmode
|
||||
|| mode == CC_DLTUmode
|
||||
|| mode == CC_DGEUmode
|
||||
|| mode == CC_DGTUmode));
|
||||
})
|
||||
|
||||
(define_special_predicate "arm_extendqisi_mem_op"
|
||||
(and (match_operand 0 "memory_operand")
|
||||
(match_test "arm_legitimate_address_p (mode, XEXP (op, 0), SIGN_EXTEND,
|
||||
0)")))
|
||||
|
||||
(define_predicate "power_of_two_operand"
|
||||
(match_code "const_int")
|
||||
{
|
||||
HOST_WIDE_INT value = INTVAL (op);
|
||||
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
})
|
||||
|
||||
(define_predicate "nonimmediate_di_operand"
|
||||
(match_code "reg,subreg,mem")
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return true;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return GET_CODE (op) == MEM && memory_address_p (DImode, XEXP (op, 0));
|
||||
})
|
||||
|
||||
(define_predicate "di_operand"
|
||||
(ior (match_code "const_int,const_double")
|
||||
(and (match_code "reg,subreg,mem")
|
||||
(match_operand 0 "nonimmediate_di_operand"))))
|
||||
|
||||
(define_predicate "nonimmediate_soft_df_operand"
|
||||
(match_code "reg,subreg,mem")
|
||||
{
|
||||
if (s_register_operand (op, mode))
|
||||
return true;
|
||||
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return GET_CODE (op) == MEM && memory_address_p (DFmode, XEXP (op, 0));
|
||||
})
|
||||
|
||||
(define_predicate "soft_df_operand"
|
||||
(ior (match_code "const_double")
|
||||
(and (match_code "reg,subreg,mem")
|
||||
(match_operand 0 "nonimmediate_soft_df_operand"))))
|
||||
|
||||
(define_predicate "const_shift_operand"
|
||||
(and (match_code "const_int")
|
||||
(ior (match_operand 0 "power_of_two_operand")
|
||||
(match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) < 32"))))
|
||||
|
||||
|
||||
(define_special_predicate "load_multiple_operation"
|
||||
(match_code "parallel")
|
||||
{
|
||||
HOST_WIDE_INT count = XVECLEN (op, 0);
|
||||
int dest_regno;
|
||||
rtx src_addr;
|
||||
HOST_WIDE_INT i = 1, base = 0;
|
||||
rtx elt;
|
||||
|
||||
if (count <= 1
|
||||
|| GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
return false;
|
||||
|
||||
/* Check to see if this might be a write-back. */
|
||||
if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
|
||||
{
|
||||
i++;
|
||||
base = 1;
|
||||
|
||||
/* Now check it more carefully. */
|
||||
if (GET_CODE (SET_DEST (elt)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Perform a quick check so we don't blow up below. */
|
||||
if (count <= i
|
||||
|| GET_CODE (XVECEXP (op, 0, i - 1)) != SET
|
||||
|| GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
|
||||
|| GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
|
||||
return false;
|
||||
|
||||
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
|
||||
src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
|
||||
|
||||
for (; i < count; i++)
|
||||
{
|
||||
elt = XVECEXP (op, 0, i);
|
||||
|
||||
if (GET_CODE (elt) != SET
|
||||
|| GET_CODE (SET_DEST (elt)) != REG
|
||||
|| GET_MODE (SET_DEST (elt)) != SImode
|
||||
|| REGNO (SET_DEST (elt)) != (unsigned int)(dest_regno + i - base)
|
||||
|| GET_CODE (SET_SRC (elt)) != MEM
|
||||
|| GET_MODE (SET_SRC (elt)) != SImode
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
|
||||
|| !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|
||||
|| GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
(define_special_predicate "store_multiple_operation"
|
||||
(match_code "parallel")
|
||||
{
|
||||
HOST_WIDE_INT count = XVECLEN (op, 0);
|
||||
int src_regno;
|
||||
rtx dest_addr;
|
||||
HOST_WIDE_INT i = 1, base = 0;
|
||||
rtx elt;
|
||||
|
||||
if (count <= 1
|
||||
|| GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
return false;
|
||||
|
||||
/* Check to see if this might be a write-back. */
|
||||
if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
|
||||
{
|
||||
i++;
|
||||
base = 1;
|
||||
|
||||
/* Now check it more carefully. */
|
||||
if (GET_CODE (SET_DEST (elt)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
|
||||
|| GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Perform a quick check so we don't blow up below. */
|
||||
if (count <= i
|
||||
|| GET_CODE (XVECEXP (op, 0, i - 1)) != SET
|
||||
|| GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
|
||||
|| GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
|
||||
return false;
|
||||
|
||||
src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
|
||||
dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
|
||||
|
||||
for (; i < count; i++)
|
||||
{
|
||||
elt = XVECEXP (op, 0, i);
|
||||
|
||||
if (GET_CODE (elt) != SET
|
||||
|| GET_CODE (SET_SRC (elt)) != REG
|
||||
|| GET_MODE (SET_SRC (elt)) != SImode
|
||||
|| REGNO (SET_SRC (elt)) != (unsigned int)(src_regno + i - base)
|
||||
|| GET_CODE (SET_DEST (elt)) != MEM
|
||||
|| GET_MODE (SET_DEST (elt)) != SImode
|
||||
|| GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
|
||||
|| !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
|
||||
|| GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|
||||
|| INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
(define_special_predicate "multi_register_push"
|
||||
(match_code "parallel")
|
||||
{
|
||||
if ((GET_CODE (XVECEXP (op, 0, 0)) != SET)
|
||||
|| (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
|
||||
|| (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
})
|
||||
|
||||
;;-------------------------------------------------------------------------
|
||||
;;
|
||||
;; Thumb predicates
|
||||
;;
|
||||
|
||||
(define_predicate "thumb_cmp_operand"
|
||||
(ior (and (match_code "reg,subreg")
|
||||
(match_operand 0 "s_register_operand"))
|
||||
(and (match_code "const_int")
|
||||
(match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) < 256"))))
|
||||
|
||||
(define_predicate "thumb_cmpneg_operand"
|
||||
(and (match_code "const_int")
|
||||
(match_test "INTVAL (op) < 0 && INTVAL (op) > -256")))
|
||||
|
||||
;; Return TRUE if a result can be stored in OP without clobbering the
|
||||
;; condition code register. Prior to reload we only accept a
|
||||
;; register. After reload we have to be able to handle memory as
|
||||
;; well, since a pseudo may not get a hard reg and reload cannot
|
||||
;; handle output-reloads on jump insns.
|
||||
|
||||
;; We could possibly handle mem before reload as well, but that might
|
||||
;; complicate things with the need to handle increment
|
||||
;; side-effects.
|
||||
(define_predicate "thumb_cbrch_target_operand"
|
||||
(and (match_code "reg,subreg,mem")
|
||||
(ior (match_operand 0 "s_register_operand")
|
||||
(and (match_test "reload_in_progress || reload_completed")
|
||||
(match_operand 0 "memory_operand")))))
|
||||
|
||||
;;-------------------------------------------------------------------------
|
||||
;;
|
||||
;; MAVERICK predicates
|
||||
;;
|
||||
|
||||
(define_predicate "cirrus_register_operand"
|
||||
(match_code "reg,subreg")
|
||||
{
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
|
||||
|| REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
|
||||
})
|
||||
|
||||
(define_predicate "cirrus_fp_register"
|
||||
(match_code "reg,subreg")
|
||||
{
|
||||
if (GET_CODE (op) == SUBREG)
|
||||
op = SUBREG_REG (op);
|
||||
|
||||
return (GET_CODE (op) == REG
|
||||
&& (REGNO (op) >= FIRST_PSEUDO_REGISTER
|
||||
|| REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
|
||||
})
|
||||
|
||||
(define_predicate "cirrus_shift_const"
|
||||
(and (match_code "const_int")
|
||||
(match_test "((unsigned HOST_WIDE_INT) INTVAL (op)) < 64")))
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Rules common to all arm targets
|
||||
|
||||
MD_INCLUDES= $(srcdir)/config/arm/arm-tune.md \
|
||||
$(srcdir)/config/arm/predicates.md \
|
||||
$(srcdir)/config/arm/arm-generic.md \
|
||||
$(srcdir)/config/arm/arm1026ejs.md \
|
||||
$(srcdir)/config/arm/arm1136jfs.md \
|
||||
@ -10,7 +11,7 @@ MD_INCLUDES= $(srcdir)/config/arm/arm-tune.md \
|
||||
$(srcdir)/config/arm/iwmmxt.md \
|
||||
$(srcdir)/config/arm/vfp.md
|
||||
|
||||
s-config s-conditions s-flags s-codes s-constants s-emit s-recog \
|
||||
s-config s-conditions s-flags s-codes s-constants s-emit s-recog s-preds \
|
||||
s-opinit s-extract s-peep s-attr s-attrtab s-output: $(MD_INCLUDES)
|
||||
|
||||
$(srcdir)/config/arm/arm-tune.md: $(srcdir)/config/arm/gentune.sh \
|
||||
|
Loading…
Reference in New Issue
Block a user