pa-protos.h: Add prototypes for magic_milli and shadd_constant_p.

* config/pa/pa-protos.h: Add prototypes for magic_milli and
	shadd_constant_p.
	* config/pa/pa.c (reg_or_0_operand, call_operand_address,
	symbolic_operand, symbolic_memory_operand,
	reg_or_0_or_nonsymb_mem_operand, reg_before_reload_operand,
	indexed_memory_operand, move_dest_operand, move_src_operand,
	prefetch_cc_operand, prefetch_nocc_operand,
	reg_or_cint_move_operand, pic_label_operand, fp_reg_operand,
	arith_operand, arith11_operand, pre_cint_operand,
	post_cint_operan, arith_double_operand, ireg_or_int5_operand,
	ireg_operand, int5_operand, uint5_operand, int11_operand,
	uint32_operand, arith5_operand, and_operand, ior_operand,
	lhs_lshift_operand, lhs_lshift_cint_operand, arith32_operand,
	pc_or_label_operand, div_operand, plus_xor_ior_operator,
	shadd_operand, movb_comparison_operator,
	cmpib_comparison_operator): Move to predicates.md.
	(magic_milli, shadd_constant_p): Make it extern.
	* config/pa/pa.h (PREDICATE_CODES): Remove.
	* config/pa/pa.md: Include predicates.md.
	* config/pa/predicates.md: New.

From-SVN: r96692
This commit is contained in:
Kazu Hirata 2005-03-18 18:10:48 +00:00 committed by Kazu Hirata
parent 22a14e0dcc
commit c9a8819075
6 changed files with 578 additions and 532 deletions

View File

@ -1,4 +1,4 @@
2005-03-18 2005-03-18 Kazu Hirata <kazu@cs.umass.edu>
2005-03-18 Kazu Hirata <kazu@cs.umass.edu>
* config/m32r/m32r-protos.h: Remove the prototypes for
call_address_operand, symbolic_operand, seth_add3_operand,
@ -26,6 +26,27 @@
* config/m32r/m32r.md: Include predicates.md.
* config/m32r/predicates.md: New.
* config/pa/pa-protos.h: Add prototypes for magic_milli and
shadd_constant_p.
* config/pa/pa.c (reg_or_0_operand, call_operand_address,
symbolic_operand, symbolic_memory_operand,
reg_or_0_or_nonsymb_mem_operand, reg_before_reload_operand,
indexed_memory_operand, move_dest_operand, move_src_operand,
prefetch_cc_operand, prefetch_nocc_operand,
reg_or_cint_move_operand, pic_label_operand, fp_reg_operand,
arith_operand, arith11_operand, pre_cint_operand,
post_cint_operan, arith_double_operand, ireg_or_int5_operand,
ireg_operand, int5_operand, uint5_operand, int11_operand,
uint32_operand, arith5_operand, and_operand, ior_operand,
lhs_lshift_operand, lhs_lshift_cint_operand, arith32_operand,
pc_or_label_operand, div_operand, plus_xor_ior_operator,
shadd_operand, movb_comparison_operator,
cmpib_comparison_operator): Move to predicates.md.
(magic_milli, shadd_constant_p): Make it extern.
* config/pa/pa.h (PREDICATE_CODES): Remove.
* config/pa/pa.md: Include predicates.md.
* config/pa/predicates.md: New.
2005-03-18 Kazu Hirata <kazu@cs.umass.edu>
* hooks.c, hooks.h, intl.c, opts.h, prefix.c, tree-gimple.c,

View File

@ -176,6 +176,9 @@ extern void pa_asm_output_aligned_local (FILE *, const char *,
unsigned int);
extern void pa_hpux_asm_output_external (FILE *, tree, const char *);
extern const int magic_milli[];
extern int shadd_constant_p (int);
/* Functions in varasm.c used by pa.c. */
extern void som_readonly_data_section (void);
extern void som_one_only_readonly_data_section (void);

View File

@ -91,7 +91,6 @@ static void pa_reorg (void);
static void pa_combine_instructions (void);
static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx);
static int forward_branch_p (rtx);
static int shadd_constant_p (int);
static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *);
static int compute_movmem_length (rtx);
static int compute_clrmem_length (rtx);
@ -550,26 +549,6 @@ copy_reg_pointer (rtx to, rtx from)
mark_reg_pointer (to, REGNO_POINTER_ALIGN (REGNO (from)));
}
/* Return nonzero only if OP is a register of mode MODE,
or CONST0_RTX. */
int
reg_or_0_operand (rtx op, enum machine_mode mode)
{
return (op == CONST0_RTX (mode) || register_operand (op, mode));
}
/* Return nonzero if OP is suitable for use in a call to a named
function.
For 2.5 try to eliminate either call_operand_address or
function_label_operand, they perform very similar functions. */
int
call_operand_address (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_MODE (op) == word_mode
&& CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);
}
/* Return 1 if X contains a symbolic expression. We know these
expressions will have one of a few well defined forms, so
we need only check those forms. */
@ -584,95 +563,6 @@ symbolic_expression_p (rtx x)
return (symbolic_operand (x, VOIDmode));
}
int
symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
/* Return truth value of statement that OP is a symbolic memory
operand of mode MODE. */
int
symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
|| GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
}
/* Return 1 if the operand is either a register, zero, or a memory operand
that is not symbolic. */
int
reg_or_0_or_nonsymb_mem_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (op == CONST0_RTX (mode))
return 1;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating move insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (XEXP (op, 0)) == PLUS
&& REG_P (XEXP (XEXP (op, 0), 0))
&& REG_P (XEXP (XEXP (op, 0), 1)))
return 0;
return (!symbolic_memory_operand (op, mode)
&& memory_address_p (mode, XEXP (op, 0)));
}
/* Return 1 if the operand is a register operand or a non-symbolic memory
operand after reload. This predicate is used for branch patterns that
internally handle register reloading. We need to accept non-symbolic
memory operands after reload to ensure that the pattern is still valid
if reload didn't find a hard register for the operand. */
int
reg_before_reload_operand (rtx op, enum machine_mode mode)
{
/* Don't accept a SUBREG since it will need a reload. */
if (GET_CODE (op) == SUBREG)
return 0;
if (register_operand (op, mode))
return 1;
if (reload_completed
&& memory_operand (op, mode)
&& !symbolic_memory_operand (op, mode))
return 1;
return 0;
}
/* Accept any constant that can be moved in one instruction into a
general register. */
int
@ -683,198 +573,7 @@ cint_ok_for_move (HOST_WIDE_INT intval)
|| CONST_OK_FOR_LETTER_P (intval, 'N')
|| CONST_OK_FOR_LETTER_P (intval, 'K'));
}
/* Return 1 iff OP is an indexed memory operand. */
int
indexed_memory_operand (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) != mode)
return 0;
/* Before reload, a (SUBREG (MEM...)) forces reloading into a register. */
if (reload_completed && GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
return 0;
op = XEXP (op, 0);
return (memory_address_p (mode, op) && IS_INDEX_ADDR_P (op));
}
/* Accept anything that can be used as a destination operand for a
move instruction. We don't accept indexed memory operands since
they are supported only for floating point stores. */
int
move_dest_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (GET_MODE (op) != mode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
return 0;
op = XEXP (op, 0);
return (memory_address_p (mode, op)
&& !IS_INDEX_ADDR_P (op)
&& !IS_LO_SUM_DLT_ADDR_P (op));
}
/* Accept anything that can be used as a source operand for a move
instruction. */
int
move_src_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (GET_CODE (op) == CONST_INT)
return cint_ok_for_move (INTVAL (op));
if (GET_MODE (op) != mode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating move insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (XEXP (op, 0)) == PLUS
&& REG_P (XEXP (XEXP (op, 0), 0))
&& REG_P (XEXP (XEXP (op, 0), 1)))
return 0;
return memory_address_p (mode, XEXP (op, 0));
}
/* Accept anything that can be used as the source operand for a prefetch
instruction with a cache-control completer. */
int
prefetch_cc_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
/* We must reject virtual registers as we don't allow REG+D. */
if (op == virtual_incoming_args_rtx
|| op == virtual_stack_vars_rtx
|| op == virtual_stack_dynamic_rtx
|| op == virtual_outgoing_args_rtx
|| op == virtual_cfa_rtx)
return 0;
if (!REG_P (op) && !IS_INDEX_ADDR_P (op))
return 0;
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating prefetch insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (op) == PLUS
&& REG_P (XEXP (op, 0)))
return 0;
return memory_address_p (mode, op);
}
/* Accept anything that can be used as the source operand for a prefetch
instruction with no cache-control completer. */
int
prefetch_nocc_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating prefetch insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (op) == PLUS
&& REG_P (XEXP (op, 0))
&& REG_P (XEXP (op, 1)))
return 0;
return memory_address_p (mode, op);
}
/* Accept REG and any CONST_INT that can be moved in one instruction into a
general register. */
int
reg_or_cint_move_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
return (GET_CODE (op) == CONST_INT && cint_ok_for_move (INTVAL (op)));
}
int
pic_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (!flag_pic)
return 0;
switch (GET_CODE (op))
{
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return (GET_CODE (XEXP (op, 0)) == LABEL_REF
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
int
fp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return reg_renumber && FP_REG_P (op);
}
/* Return truth value of whether OP can be used as an operand in a
three operand arithmetic insn that accepts registers of mode MODE
or 14-bit signed integers. */
int
arith_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
}
/* Return truth value of whether OP can be used as an operand in a
three operand arithmetic insn that accepts registers of mode MODE
or 11-bit signed integers. */
int
arith11_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
}
/* Return truth value of whether OP can be used as an operand in a
adddi3 insn. */
int
@ -885,94 +584,6 @@ adddi3_operand (rtx op, enum machine_mode mode)
&& (TARGET_64BIT ? INT_14_BITS (op) : INT_11_BITS (op))));
}
/* A constant integer suitable for use in a PRE_MODIFY memory
reference. */
int
pre_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10);
}
/* A constant integer suitable for use in a POST_MODIFY memory
reference. */
int
post_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10);
}
int
arith_double_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == mode
&& VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
&& ((CONST_DOUBLE_HIGH (op) >= 0)
== ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
}
/* Return truth value of whether OP is an integer which fits the
range constraining immediate operands in three-address insns, or
is an integer register. */
int
ireg_or_int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return ((GET_CODE (op) == CONST_INT && INT_5_BITS (op))
|| (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
}
/* Return nonzero if OP is an integer register, else return zero. */
int
ireg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32);
}
/* Return truth value of whether OP is an integer which fits the
range constraining immediate operands in three-address insns. */
int
int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
}
int
uint5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
}
int
int11_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
}
int
uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
#if HOST_BITS_PER_WIDE_INT > 32
/* All allowed constants will fit a CONST_INT. */
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= 0 && INTVAL (op) < (HOST_WIDE_INT) 1 << 32));
#else
return (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0));
#endif
}
int
arith5_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || int5_operand (op, mode);
}
/* True iff zdepi can be used to generate this CONST_INT.
zdepi first sign extends a 5 bit signed number to a given field
length, then places this field anywhere in a zero. */
@ -1002,14 +613,6 @@ and_mask_p (unsigned HOST_WIDE_INT mask)
return (mask & (mask - 1)) == 0;
}
/* True iff depi or extru can be used to compute (reg & OP). */
int
and_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && and_mask_p (INTVAL (op))));
}
/* True iff depi can be used to compute (reg | MASK). */
int
ior_mask_p (unsigned HOST_WIDE_INT mask)
@ -1017,44 +620,6 @@ ior_mask_p (unsigned HOST_WIDE_INT mask)
mask += mask & -mask;
return (mask & (mask - 1)) == 0;
}
/* True iff depi can be used to compute (reg | OP). */
int
ior_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op)));
}
int
lhs_lshift_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || lhs_lshift_cint_operand (op, mode);
}
/* True iff OP is a CONST_INT of the forms 0...0xxxx or 0...01...1xxxx.
Such values can be the left hand side x in (x << r), using the zvdepi
instruction. */
int
lhs_lshift_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
unsigned HOST_WIDE_INT x;
if (GET_CODE (op) != CONST_INT)
return 0;
x = INTVAL (op) >> 4;
return (x & (x + 1)) == 0;
}
int
arith32_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || GET_CODE (op) == CONST_INT;
}
int
pc_or_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
}
/* Legitimize PIC addresses. If the address is already
position-independent, we return ORIG. Newly generated
@ -5741,8 +5306,7 @@ output_mul_insn (int unsignedp ATTRIBUTE_UNUSED, rtx insn)
/* Emit the rtl for doing a division by a constant. */
/* Do magic division millicodes exist for this value? */
static const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
1, 1};
const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1};
/* We'll use an array to keep track of the magic millicodes and
whether or not we've used them already. [n][0] is signed, [n][1] is
@ -5750,15 +5314,6 @@ static const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
static int div_milli[16][2];
int
div_operand (rtx op, enum machine_mode mode)
{
return (mode == SImode
&& ((GET_CODE (op) == REG && REGNO (op) == 25)
|| (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
&& INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
}
int
emit_hpdiv_const (rtx *operands, int unsignedp)
{
@ -8440,16 +7995,9 @@ fmpysuboperands (rtx *operands)
return 1;
}
int
plus_xor_ior_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == PLUS || GET_CODE (op) == XOR
|| GET_CODE (op) == IOR);
}
/* Return 1 if the given constant is 2, 4, or 8. These are the valid
constants for shadd instructions. */
static int
int
shadd_constant_p (int val)
{
if (val == 2 || val == 4 || val == 8)
@ -8458,14 +8006,6 @@ shadd_constant_p (int val)
return 0;
}
/* Return 1 if OP is a CONST_INT with the value 2, 4, or 8. These are
the valid constant for shadd instructions. */
int
shadd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op)));
}
/* Return 1 if OP is valid as a base or index register in a
REG+REG address. */
@ -8528,14 +8068,6 @@ eq_neq_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
}
/* Return 1 if OP is an operator suitable for use in a movb instruction. */
int
movb_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE
|| GET_CODE (op) == LT || GET_CODE (op) == GE);
}
/* Return 1 if INSN is in the delay slot of a call instruction. */
int
jump_in_call_delay (rtx insn)
@ -9367,23 +8899,6 @@ pa_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
/* Return 1 if this is a comparison operator. This allows the use of
MATCH_OPERATOR to recognize all the branch insns. */
int
cmpib_comparison_operator (rtx op, enum machine_mode mode)
{
return ((mode == VOIDmode || GET_MODE (op) == mode)
&& (GET_CODE (op) == EQ
|| GET_CODE (op) == NE
|| GET_CODE (op) == GT
|| GET_CODE (op) == GTU
|| GET_CODE (op) == GE
|| GET_CODE (op) == LT
|| GET_CODE (op) == LE
|| GET_CODE (op) == LEU));
}
/* Return a string to output before text in the current function.
This function is only used with SOM. Because we don't support

View File

@ -2128,49 +2128,6 @@ forget_section (void) \
/* The number of Pmode words for the setjmp buffer. */
#define JMP_BUF_SIZE 50
#define PREDICATE_CODES \
{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"call_operand_address", {LABEL_REF, SYMBOL_REF, CONST_INT, \
CONST_DOUBLE, CONST, HIGH}}, \
{"indexed_memory_operand", {SUBREG, MEM}}, \
{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
{"symbolic_memory_operand", {SUBREG, MEM}}, \
{"reg_before_reload_operand", {REG, MEM}}, \
{"reg_or_0_or_nonsymb_mem_operand", {SUBREG, REG, MEM, CONST_INT, \
CONST_DOUBLE}}, \
{"move_dest_operand", {SUBREG, REG, MEM}}, \
{"move_src_operand", {SUBREG, REG, CONST_INT, MEM}}, \
{"prefetch_cc_operand", {MEM}}, \
{"prefetch_nocc_operand", {MEM}}, \
{"reg_or_cint_move_operand", {SUBREG, REG, CONST_INT}}, \
{"pic_label_operand", {LABEL_REF, CONST}}, \
{"fp_reg_operand", {REG}}, \
{"arith_operand", {SUBREG, REG, CONST_INT}}, \
{"arith11_operand", {SUBREG, REG, CONST_INT}}, \
{"pre_cint_operand", {CONST_INT}}, \
{"post_cint_operand", {CONST_INT}}, \
{"arith_double_operand", {SUBREG, REG, CONST_DOUBLE}}, \
{"ireg_or_int5_operand", {CONST_INT, REG}}, \
{"int5_operand", {CONST_INT}}, \
{"uint5_operand", {CONST_INT}}, \
{"int11_operand", {CONST_INT}}, \
{"uint32_operand", {CONST_INT, \
HOST_BITS_PER_WIDE_INT > 32 ? 0 : CONST_DOUBLE}}, \
{"arith5_operand", {SUBREG, REG, CONST_INT}}, \
{"and_operand", {SUBREG, REG, CONST_INT}}, \
{"ior_operand", {CONST_INT}}, \
{"lhs_lshift_cint_operand", {CONST_INT}}, \
{"lhs_lshift_operand", {SUBREG, REG, CONST_INT}}, \
{"arith32_operand", {SUBREG, REG, CONST_INT}}, \
{"pc_or_label_operand", {PC, LABEL_REF}}, \
{"plus_xor_ior_operator", {PLUS, XOR, IOR}}, \
{"shadd_operand", {CONST_INT}}, \
{"div_operand", {REG, CONST_INT}}, \
{"ireg_operand", {REG}}, \
{"cmpib_comparison_operator", {EQ, NE, LT, LE, LEU, \
GT, GTU, GE}}, \
{"movb_comparison_operator", {EQ, NE, LT, GE}},
/* We need a libcall to canonicalize function pointers on TARGET_ELF32. */
#define CANONICALIZE_FUNCPTR_FOR_COMPARE_LIBCALL \
"__canonicalize_funcptr_for_compare"

View File

@ -561,7 +561,7 @@
(eq_attr "cpu" "8000"))
"inm_8000,fdivsqrt_8000*6,rnm_8000")
(include "predicates.md")
;; Compare instructions.
;; This controls RTL generation and register allocation.

550
gcc/config/pa/predicates.md Normal file
View File

@ -0,0 +1,550 @@
;; Predicate definitions for HP PA-RISC.
;; 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 nonzero only if OP is a register of mode MODE, or
;; CONST0_RTX.
(define_predicate "reg_or_0_operand"
(match_code "subreg,reg,const_int,const_double")
{
return (op == CONST0_RTX (mode) || register_operand (op, mode));
})
;; Return nonzero if OP is suitable for use in a call to a named
;; function.
;;
;; For 2.5 try to eliminate either call_operand_address or
;; function_label_operand, they perform very similar functions.
(define_predicate "call_operand_address"
(match_code "label_ref,symbol_ref,const_int,const_double,const,high")
{
return (GET_MODE (op) == word_mode
&& CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);
})
;; Return 1 iff OP is an indexed memory operand.
(define_predicate "indexed_memory_operand"
(match_code "subreg,mem")
{
if (GET_MODE (op) != mode)
return 0;
/* Before reload, a (SUBREG (MEM...)) forces reloading into a register. */
if (reload_completed && GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
return 0;
op = XEXP (op, 0);
return (memory_address_p (mode, op) && IS_INDEX_ADDR_P (op));
})
;; TODO: Add a comment.
(define_predicate "symbolic_operand"
(match_code "symbol_ref,label_ref,const")
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
})
;; Return truth value of statement that OP is a symbolic memory
;; operand of mode MODE.
(define_predicate "symbolic_memory_operand"
(match_code "subreg,mem")
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
|| GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
})
;; Return 1 if the operand is a register operand or a non-symbolic
;; memory operand after reload. This predicate is used for branch
;; patterns that internally handle register reloading. We need to
;; accept non-symbolic memory operands after reload to ensure that the
;; pattern is still valid if reload didn't find a hard register for
;; the operand.
(define_predicate "reg_before_reload_operand"
(match_code "reg,mem")
{
/* Don't accept a SUBREG since it will need a reload. */
if (GET_CODE (op) == SUBREG)
return 0;
if (register_operand (op, mode))
return 1;
if (reload_completed
&& memory_operand (op, mode)
&& !symbolic_memory_operand (op, mode))
return 1;
return 0;
})
;; Return 1 if the operand is either a register, zero, or a memory
;; operand that is not symbolic.
(define_predicate "reg_or_0_or_nonsymb_mem_operand"
(match_code "subreg,reg,mem,const_int,const_double")
{
if (register_operand (op, mode))
return 1;
if (op == CONST0_RTX (mode))
return 1;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating move insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (XEXP (op, 0)) == PLUS
&& REG_P (XEXP (XEXP (op, 0), 0))
&& REG_P (XEXP (XEXP (op, 0), 1)))
return 0;
return (!symbolic_memory_operand (op, mode)
&& memory_address_p (mode, XEXP (op, 0)));
})
;; Accept anything that can be used as a destination operand for a
;; move instruction. We don't accept indexed memory operands since
;; they are supported only for floating point stores.
(define_predicate "move_dest_operand"
(match_code "subreg,reg,mem")
{
if (register_operand (op, mode))
return 1;
if (GET_MODE (op) != mode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
return 0;
op = XEXP (op, 0);
return (memory_address_p (mode, op)
&& !IS_INDEX_ADDR_P (op)
&& !IS_LO_SUM_DLT_ADDR_P (op));
})
;; Accept anything that can be used as a source operand for a move
;; instruction.
(define_predicate "move_src_operand"
(match_code "subreg,reg,const_int,mem")
{
if (register_operand (op, mode))
return 1;
if (GET_CODE (op) == CONST_INT)
return cint_ok_for_move (INTVAL (op));
if (GET_MODE (op) != mode)
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating move insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (XEXP (op, 0)) == PLUS
&& REG_P (XEXP (XEXP (op, 0), 0))
&& REG_P (XEXP (XEXP (op, 0), 1)))
return 0;
return memory_address_p (mode, XEXP (op, 0));
})
;; Accept anything that can be used as the source operand for a
;; prefetch instruction with a cache-control completer.
(define_predicate "prefetch_cc_operand"
(match_code "mem")
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
/* We must reject virtual registers as we don't allow REG+D. */
if (op == virtual_incoming_args_rtx
|| op == virtual_stack_vars_rtx
|| op == virtual_stack_dynamic_rtx
|| op == virtual_outgoing_args_rtx
|| op == virtual_cfa_rtx)
return 0;
if (!REG_P (op) && !IS_INDEX_ADDR_P (op))
return 0;
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating prefetch insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (op) == PLUS
&& REG_P (XEXP (op, 0)))
return 0;
return memory_address_p (mode, op);
})
;; Accept anything that can be used as the source operand for a
;; prefetch instruction with no cache-control completer.
(define_predicate "prefetch_nocc_operand"
(match_code "mem")
{
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating prefetch insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
&& GET_CODE (op) == PLUS
&& REG_P (XEXP (op, 0))
&& REG_P (XEXP (op, 1)))
return 0;
return memory_address_p (mode, op);
})
;; Accept REG and any CONST_INT that can be moved in one instruction
;; into a general register.
(define_predicate "reg_or_cint_move_operand"
(match_code "subreg,reg,const_int")
{
if (register_operand (op, mode))
return 1;
return (GET_CODE (op) == CONST_INT && cint_ok_for_move (INTVAL (op)));
})
;; TODO: Add a comment here.
(define_predicate "pic_label_operand"
(match_code "label_ref,const")
{
if (!flag_pic)
return 0;
switch (GET_CODE (op))
{
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return (GET_CODE (XEXP (op, 0)) == LABEL_REF
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
})
;; TODO: Add a comment here.
(define_predicate "fp_reg_operand"
(match_code "reg")
{
return reg_renumber && FP_REG_P (op);
})
;; Return truth value of whether OP can be used as an operand in a
;; three operand arithmetic insn that accepts registers of mode MODE
;; or 14-bit signed integers.
(define_predicate "arith_operand"
(match_code "subreg,reg,const_int")
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
})
;; Return truth value of whether OP can be used as an operand in a
;; three operand arithmetic insn that accepts registers of mode MODE
;; or 11-bit signed integers.
(define_predicate "arith11_operand"
(match_code "subreg,reg,const_int")
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
})
;; A constant integer suitable for use in a PRE_MODIFY memory
;; reference.
(define_predicate "pre_cint_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10);
})
;; A constant integer suitable for use in a POST_MODIFY memory
;; reference.
(define_predicate "post_cint_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10);
})
;; TODO: Add a comment here.
(define_predicate "arith_double_operand"
(match_code "subreg,reg,const_double")
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == mode
&& VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
&& ((CONST_DOUBLE_HIGH (op) >= 0)
== ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
})
;; Return truth value of whether OP is an integer which fits the range
;; constraining immediate operands in three-address insns, or is an
;; integer register.
(define_predicate "ireg_or_int5_operand"
(match_code "const_int,reg")
{
return ((GET_CODE (op) == CONST_INT && INT_5_BITS (op))
|| (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
})
;; Return truth value of whether OP is an integer which fits the range
;; constraining immediate operands in three-address insns.
(define_predicate "int5_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
})
;; Return truth value of whether OP is an integer which fits the range
;; constraining immediate operands in three-address insns.
(define_predicate "uint5_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
})
;; Return truth value of whether OP is an integer which fits the range
;; constraining immediate operands in three-address insns.
(define_predicate "int11_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
})
;; Return truth value of whether OP is an integer which fits the range
;; constraining immediate operands in three-address insns.
(define_predicate "uint32_operand"
(match_code "const_int,const_double")
{
#if HOST_BITS_PER_WIDE_INT > 32
/* All allowed constants will fit a CONST_INT. */
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) >= 0 && INTVAL (op) < (HOST_WIDE_INT) 1 << 32));
#else
return (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0));
#endif
})
;; Return truth value of whether OP is an integer which fits the range
;; constraining immediate operands in three-address insns.
(define_predicate "arith5_operand"
(match_code "subreg,reg,const_int")
{
return register_operand (op, mode) || int5_operand (op, mode);
})
;; True iff depi or extru can be used to compute (reg & OP).
(define_predicate "and_operand"
(match_code "subreg,reg,const_int")
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && and_mask_p (INTVAL (op))));
})
;; True iff depi can be used to compute (reg | OP).
(define_predicate "ior_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op)));
})
;; True iff OP is a CONST_INT of the forms 0...0xxxx or
;; 0...01...1xxxx. Such values can be the left hand side x in (x <<
;; r), using the zvdepi instruction.
(define_predicate "lhs_lshift_cint_operand"
(match_code "const_int")
{
unsigned HOST_WIDE_INT x;
if (GET_CODE (op) != CONST_INT)
return 0;
x = INTVAL (op) >> 4;
return (x & (x + 1)) == 0;
})
;; TODO: Add a comment here.
(define_predicate "lhs_lshift_operand"
(match_code "subreg,reg,const_int")
{
return register_operand (op, mode) || lhs_lshift_cint_operand (op, mode);
})
;; TODO: Add a comment here.
(define_predicate "arith32_operand"
(match_code "subreg,reg,const_int")
{
return register_operand (op, mode) || GET_CODE (op) == CONST_INT;
})
;; TODO: Add a comment here.
(define_predicate "pc_or_label_operand"
(match_code "pc,label_ref")
{
return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
})
;; TODO: Add a comment here.
(define_predicate "plus_xor_ior_operator"
(match_code "plus,xor,ior")
{
return (GET_CODE (op) == PLUS || GET_CODE (op) == XOR
|| GET_CODE (op) == IOR);
})
;; Return 1 if OP is a CONST_INT with the value 2, 4, or 8. These are
;; the valid constant for shadd instructions.
(define_predicate "shadd_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op)));
})
;; TODO: Add a comment here.
(define_predicate "div_operand"
(match_code "reg,const_int")
{
return (mode == SImode
&& ((GET_CODE (op) == REG && REGNO (op) == 25)
|| (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
&& INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
})
;; Return nonzero if OP is an integer register, else return zero.
(define_predicate "ireg_operand"
(match_code "reg")
{
return (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32);
})
;; Return 1 if this is a comparison operator. This allows the use of
;; MATCH_OPERATOR to recognize all the branch insns.
(define_predicate "cmpib_comparison_operator"
(match_code "eq,ne,lt,le,leu,gt,gtu,ge")
{
return ((mode == VOIDmode || GET_MODE (op) == mode)
&& (GET_CODE (op) == EQ
|| GET_CODE (op) == NE
|| GET_CODE (op) == GT
|| GET_CODE (op) == GTU
|| GET_CODE (op) == GE
|| GET_CODE (op) == LT
|| GET_CODE (op) == LE
|| GET_CODE (op) == LEU));
})
;; Return 1 if OP is an operator suitable for use in a movb
;; instruction.
(define_predicate "movb_comparison_operator"
(match_code "eq,ne,lt,ge")
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE
|| GET_CODE (op) == LT || GET_CODE (op) == GE);
})