h8300-protos.h: Remove prototypes for general_operand_src...

* config/h8300/h8300-protos.h: Remove prototypes for
	general_operand_src, general_operand_dst, single_one_operand,
	single_zero_operand, call_insn_operand,
	two_insn_adds_subs_operand, small_call_insn_operand,
	jump_address_operand, bit_operand, bit_memory_operand,
	stack_pointer_operand, const_int_gt_2_operand,
	const_int_ge_8_operand, const_int_qi_operand,
	const_int_hi_operand, incdec_operand, bit_operator,
	nshift_operator, eqne_operator, gtle_operator,
	gtuleu_operator, iorxor_operator.
	Add prototypes for h8sx_shift_type h8sx_classify_shift and
	h8300_ldm_stm_parallel.
	* config/h8300/h8300.c (h8sx_shift_type,): Move to
	h8300-protos.h.
	(SYMBOL_FLAG_FUNCVEC_FUNCTION, SYMBOL_FLAG_EIGHTBIT_DATA,
	SYMBOL_FLAG_TINY_DATA): Move to h8300.h.
	(h8300_ldm_stm_parallel): Make it extern.
	(h8300_ldm_parallel, h8300_stm_parallel,
	h8300_return_parallel, general_operand_src,
	general_operand_dst, h8300_dst_operand, h8300_src_operand,
	nibble_operand, reg_or_nibble_operand, single_one_operand,
	single_zero_operand, call_insn_operand,
	two_insn_adds_subs_operand, small_call_insn_operand,
	jump_address_operand, bit_operand, bit_memory_operand,
	stack_pointer_operand, const_int_gt_2_operand,
	const_int_ge_8_operand, const_int_qi_operand,
	const_int_hi_operand, incdec_operand, eqne_operator,
	gtle_operator, gtuleu_operator, iorxor_operator, bit_operator,
	h8sx_binary_memory_operator, h8sx_unary_memory_operator,
	h8sx_unary_shift_operator, h8sx_binary_shift_operator,
	nshift_operator): Move to predicates.md.
	* config/h8300/h8300.h (PREDICATE_CODES): Remove.
	* config/h8300/h8300.md: Include predicates.md.
	* config/h8300/predicates.md: New.

From-SVN: r96631
This commit is contained in:
Kazu Hirata 2005-03-17 21:01:34 +00:00 committed by Kazu Hirata
parent ffd1953e43
commit 981c7dcef8
6 changed files with 549 additions and 551 deletions

View File

@ -1,3 +1,40 @@
2005-03-17 Kazu Hirata <kazu@cs.umass.edu>
* config/h8300/h8300-protos.h: Remove prototypes for
general_operand_src, general_operand_dst, single_one_operand,
single_zero_operand, call_insn_operand,
two_insn_adds_subs_operand, small_call_insn_operand,
jump_address_operand, bit_operand, bit_memory_operand,
stack_pointer_operand, const_int_gt_2_operand,
const_int_ge_8_operand, const_int_qi_operand,
const_int_hi_operand, incdec_operand, bit_operator,
nshift_operator, eqne_operator, gtle_operator,
gtuleu_operator, iorxor_operator.
Add prototypes for h8sx_shift_type h8sx_classify_shift and
h8300_ldm_stm_parallel.
* config/h8300/h8300.c (h8sx_shift_type,): Move to
h8300-protos.h.
(SYMBOL_FLAG_FUNCVEC_FUNCTION, SYMBOL_FLAG_EIGHTBIT_DATA,
SYMBOL_FLAG_TINY_DATA): Move to h8300.h.
(h8300_ldm_stm_parallel): Make it extern.
(h8300_ldm_parallel, h8300_stm_parallel,
h8300_return_parallel, general_operand_src,
general_operand_dst, h8300_dst_operand, h8300_src_operand,
nibble_operand, reg_or_nibble_operand, single_one_operand,
single_zero_operand, call_insn_operand,
two_insn_adds_subs_operand, small_call_insn_operand,
jump_address_operand, bit_operand, bit_memory_operand,
stack_pointer_operand, const_int_gt_2_operand,
const_int_ge_8_operand, const_int_qi_operand,
const_int_hi_operand, incdec_operand, eqne_operator,
gtle_operator, gtuleu_operator, iorxor_operator, bit_operator,
h8sx_binary_memory_operator, h8sx_unary_memory_operator,
h8sx_unary_shift_operator, h8sx_binary_shift_operator,
nshift_operator): Move to predicates.md.
* config/h8300/h8300.h (PREDICATE_CODES): Remove.
* config/h8300/h8300.md: Include predicates.md.
* config/h8300/predicates.md: New.
2005-03-17 Richard Henderson <rth@redhat.com>
* config.gcc (ia64*-*-hpux*): Add extra_options.

View File

@ -53,29 +53,6 @@ extern int fix_bit_operand (rtx *, enum rtx_code);
extern int h8300_adjust_insn_length (rtx, int);
extern void split_adds_subs (enum machine_mode, rtx[]);
extern int general_operand_src (rtx, enum machine_mode);
extern int general_operand_dst (rtx, enum machine_mode);
extern int single_one_operand (rtx, enum machine_mode);
extern int single_zero_operand (rtx, enum machine_mode);
extern int call_insn_operand (rtx, enum machine_mode);
extern int two_insn_adds_subs_operand (rtx, enum machine_mode);
extern int small_call_insn_operand (rtx, enum machine_mode);
extern int jump_address_operand (rtx, enum machine_mode);
extern int bit_operand (rtx, enum machine_mode);
extern int bit_memory_operand (rtx, enum machine_mode);
extern int stack_pointer_operand (rtx, enum machine_mode);
extern int const_int_gt_2_operand (rtx, enum machine_mode);
extern int const_int_ge_8_operand (rtx, enum machine_mode);
extern int const_int_qi_operand (rtx, enum machine_mode);
extern int const_int_hi_operand (rtx, enum machine_mode);
extern int incdec_operand (rtx, enum machine_mode);
extern int bit_operator (rtx, enum machine_mode);
extern int nshift_operator (rtx, enum machine_mode);
extern int eqne_operator (rtx, enum machine_mode);
extern int gtle_operator (rtx, enum machine_mode);
extern int gtuleu_operator (rtx, enum machine_mode);
extern int iorxor_operator (rtx, enum machine_mode);
extern int h8300_eightbit_constant_address_p (rtx);
extern int h8300_tiny_constant_address_p (rtx);
extern int byte_accesses_mergeable_p (rtx, rtx);
@ -87,6 +64,28 @@ extern int h8300_legitimate_address_p (enum machine_mode, rtx, int);
/* Used in builtins.c */
extern rtx h8300_return_addr_rtx (int, rtx);
/* Classifies an h8sx shift operation.
H8SX_SHIFT_NONE
The shift cannot be done in a single instruction.
H8SX_SHIFT_UNARY
The shift is effectively a unary operation. The instruction will
allow any sort of destination operand and have a format similar
to neg and not. This is true of certain power-of-2 shifts.
H8SX_SHIFT_BINARY
The shift is a binary operation. The destination must be a
register and the source can be a register or a constant. */
enum h8sx_shift_type {
H8SX_SHIFT_NONE,
H8SX_SHIFT_UNARY,
H8SX_SHIFT_BINARY
};
extern enum h8sx_shift_type h8sx_classify_shift (enum machine_mode, enum rtx_code, rtx);
extern int h8300_ldm_stm_parallel (rtvec, int, int);
#endif /* RTX_CODE */
#ifdef TREE_CODE

View File

@ -72,26 +72,6 @@ enum h8300_operand_class
NUM_H8OPS
};
/* Classifies an h8sx shift operation.
H8SX_SHIFT_NONE
The shift cannot be done in a single instruction.
H8SX_SHIFT_UNARY
The shift is effectively a unary operation. The instruction will
allow any sort of destination operand and have a format similar
to neg and not. This is true of certain power-of-2 shifts.
H8SX_SHIFT_BINARY
The shift is a binary operation. The destination must be a
register and the source can be a register or a constant. */
enum h8sx_shift_type
{
H8SX_SHIFT_NONE,
H8SX_SHIFT_UNARY,
H8SX_SHIFT_BINARY
};
/* For a general two-operand instruction, element [X][Y] gives
the length of the opcode fields when the first operand has class
(X + 1) and the second has class Y. */
@ -121,7 +101,6 @@ static int h8300_shift_costs (rtx);
static void h8300_push_pop (int, int, int, int);
static int h8300_stack_offset_p (rtx, int);
static int h8300_ldm_stm_regno (rtx, int, int, int);
static int h8300_ldm_stm_parallel (rtvec, int, int);
static void h8300_reorg (void);
static unsigned int h8300_constant_length (rtx);
static unsigned int h8300_displacement_length (rtx, int);
@ -133,7 +112,6 @@ static unsigned int h8300_bitfield_length (rtx, rtx);
static unsigned int h8300_binary_length (rtx, const h8300_length_table *);
static bool h8300_short_move_mem_p (rtx, enum rtx_code);
static unsigned int h8300_move_length (rtx *, const h8300_length_table *);
enum h8sx_shift_type h8sx_classify_shift (enum machine_mode, enum rtx_code, rtx);
/* CPU_TYPE, says what cpu we're compiling for. */
int cpu_type;
@ -163,11 +141,6 @@ const char *h8_push_op, *h8_pop_op, *h8_mov_op;
/* Value of MOVE_RATIO. */
int h8300_move_ratio;
/* Machine-specific symbol_ref flags. */
#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
#define SYMBOL_FLAG_EIGHTBIT_DATA (SYMBOL_FLAG_MACH_DEP << 1)
#define SYMBOL_FLAG_TINY_DATA (SYMBOL_FLAG_MACH_DEP << 2)
/* See below where shifts are handled for explanation of this enum. */
@ -761,7 +734,7 @@ h8300_ldm_stm_regno (rtx x, int load_p, int index, int nregs)
/* Return true if the elements of VEC starting at FIRST describe an
ldm or stm instruction (LOAD_P says which). */
static int
int
h8300_ldm_stm_parallel (rtvec vec, int load_p, int first)
{
rtx last;
@ -805,31 +778,6 @@ h8300_ldm_stm_parallel (rtvec vec, int load_p, int first)
&& h8300_stack_offset_p (SET_SRC (last), adjust));
}
/* Return true if X is an ldm.l pattern. X is known to be parallel. */
int
h8300_ldm_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return h8300_ldm_stm_parallel (XVEC (x, 0), 1, 0);
}
/* Likewise stm.l. */
int
h8300_stm_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return h8300_ldm_stm_parallel (XVEC (x, 0), 0, 0);
}
/* Likewise rts/l and rte/l. Note that the .md pattern will check
for the return so there's no need to do that here. */
int
h8300_return_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return h8300_ldm_stm_parallel (XVEC (x, 0), 1, 1);
}
/* This is what the stack looks like after the prolog of
a function with a frame has been set up:
@ -1020,169 +968,6 @@ h8300_file_end (void)
fputs ("\t.end\n", asm_out_file);
}
/* Return true if OP is a valid source operand for an integer move
instruction. */
int
general_operand_src (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) == mode
&& GET_CODE (op) == MEM
&& GET_CODE (XEXP (op, 0)) == POST_INC)
return 1;
return general_operand (op, mode);
}
/* Return true if OP is a valid destination operand for an integer move
instruction. */
int
general_operand_dst (rtx op, enum machine_mode mode)
{
if (GET_MODE (op) == mode
&& GET_CODE (op) == MEM
&& GET_CODE (XEXP (op, 0)) == PRE_DEC)
return 1;
return general_operand (op, mode);
}
/* Return true if OP is a suitable first operand for a general arithmetic
insn such as "add". */
int
h8300_dst_operand (rtx op, enum machine_mode mode)
{
if (TARGET_H8300SX)
return nonimmediate_operand (op, mode);
return register_operand (op, mode);
}
/* Likewise the second operand. */
int
h8300_src_operand (rtx op, enum machine_mode mode)
{
if (TARGET_H8300SX)
return general_operand (op, mode);
return nonmemory_operand (op, mode);
}
/* Check that an operand is either a register or an unsigned 4-bit
constant. */
int
nibble_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && TARGET_H8300SX
&& INTVAL (op) >= 0 && INTVAL (op) <= 15);
}
/* Check that an operand is either a register or an unsigned 4-bit
constant. */
int
reg_or_nibble_operand (rtx op, enum machine_mode mode)
{
return (nibble_operand (op, mode) || register_operand (op, mode));
}
/* Return true if OP is a constant that contains only one 1 in its
binary representation. */
int
single_one_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (operand) == CONST_INT)
{
/* We really need to do this masking because 0x80 in QImode is
represented as -128 for example. */
if (exact_log2 (INTVAL (operand) & GET_MODE_MASK (mode)) >= 0)
return 1;
}
return 0;
}
/* Return true if OP is a constant that contains only one 0 in its
binary representation. */
int
single_zero_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (operand) == CONST_INT)
{
/* We really need to do this masking because 0x80 in QImode is
represented as -128 for example. */
if (exact_log2 (~INTVAL (operand) & GET_MODE_MASK (mode)) >= 0)
return 1;
}
return 0;
}
/* Return true if OP is a valid call operand. */
int
call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
if (register_operand (inside, Pmode))
return 1;
if (CONSTANT_ADDRESS_P (inside))
return 1;
}
return 0;
}
/* Return 1 if an addition/subtraction of a constant integer can be
transformed into two consecutive adds/subs that are faster than the
straightforward way. Otherwise, return 0. */
int
two_insn_adds_subs_operand (rtx op, enum machine_mode mode)
{
if (TARGET_H8300SX)
return 0;
if (GET_CODE (op) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (op);
/* Force VALUE to be positive so that we do not have to consider
the negative case. */
if (value < 0)
value = -value;
if (TARGET_H8300H || TARGET_H8300S)
{
/* A constant addition/subtraction takes 2 states in QImode,
4 states in HImode, and 6 states in SImode. Thus, the
only case we can win is when SImode is used, in which
case, two adds/subs are used, taking 4 states. */
if (mode == SImode
&& (value == 2 + 1
|| value == 4 + 1
|| value == 4 + 2
|| value == 4 + 4))
return 1;
}
else
{
/* We do not profit directly by splitting addition or
subtraction of 3 and 4. However, since these are
implemented as a sequence of adds or subs, they do not
clobber (cc0) unlike a sequence of add.b and add.x. */
if (mode == HImode
&& (value == 2 + 1
|| value == 2 + 2))
return 1;
}
}
return 0;
}
/* Split an add of a small constant into two adds/subs insns.
If USE_INCDEC_P is nonzero, we generate the last insn using inc/dec
@ -1231,85 +1016,6 @@ split_adds_subs (enum machine_mode mode, rtx *operands)
return;
}
/* Return true if OP is a valid call operand, and OP represents
an operand for a small call (4 bytes instead of 6 bytes). */
int
small_call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
/* Register indirect is a small call. */
if (register_operand (inside, Pmode))
return 1;
/* A call through the function vector is a small call too. */
if (GET_CODE (inside) == SYMBOL_REF
&& (SYMBOL_REF_FLAGS (inside) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
return 1;
}
/* Otherwise it's a large call. */
return 0;
}
/* Return true if OP is a valid jump operand. */
int
jump_address_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == REG)
return mode == Pmode;
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
if (register_operand (inside, Pmode))
return 1;
if (CONSTANT_ADDRESS_P (inside))
return 1;
}
return 0;
}
/* Recognize valid operands for bit-field instructions. */
int
bit_operand (rtx op, enum machine_mode mode)
{
/* We can accept any nonimmediate operand, except that MEM operands must
be limited to those that use addresses valid for the 'U' constraint. */
if (!nonimmediate_operand (op, mode))
return 0;
/* H8SX accepts pretty much anything here. */
if (TARGET_H8300SX)
return 1;
/* Accept any mem during RTL generation. Otherwise, the code that does
insv and extzv will think that we cannot handle memory. However,
to avoid reload problems, we only accept 'U' MEM operands after RTL
generation. This means that any named pattern which uses this predicate
must force its operands to match 'U' before emitting RTL. */
if (GET_CODE (op) == REG)
return 1;
if (GET_CODE (op) == SUBREG)
return 1;
return (GET_CODE (op) == MEM
&& OK_FOR_U (op));
}
/* Return nonzero if OP is a MEM suitable for bit manipulation insns. */
int
bit_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == MEM
&& OK_FOR_U (op));
}
/* Handle machine specific pragmas for compatibility with existing
compilers for the H8/300.
@ -2258,114 +1964,6 @@ notice_update_cc (rtx body, rtx insn)
break;
}
}
/* Return nonzero if X is a stack pointer. */
int
stack_pointer_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return x == stack_pointer_rtx;
}
/* Return nonzero if X is a constant whose absolute value is greater
than 2. */
int
const_int_gt_2_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (x) == CONST_INT
&& abs (INTVAL (x)) > 2);
}
/* Return nonzero if X is a constant whose absolute value is no
smaller than 8. */
int
const_int_ge_8_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (x) == CONST_INT
&& abs (INTVAL (x)) >= 8);
}
/* Return nonzero if X is a constant expressible in QImode. */
int
const_int_qi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (x) == CONST_INT
&& (INTVAL (x) & 0xff) == INTVAL (x));
}
/* Return nonzero if X is a constant expressible in HImode. */
int
const_int_hi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (x) == CONST_INT
&& (INTVAL (x) & 0xffff) == INTVAL (x));
}
/* Return nonzero if X is a constant suitable for inc/dec. */
int
incdec_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (x) == CONST_INT
&& (CONST_OK_FOR_M (INTVAL (x))
|| CONST_OK_FOR_O (INTVAL (x))));
}
/* Return nonzero if X is either EQ or NE. */
int
eqne_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (x);
return (code == EQ || code == NE);
}
/* Return nonzero if X is either GT or LE. */
int
gtle_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (x);
return (code == GT || code == LE);
}
/* Return nonzero if X is either GTU or LEU. */
int
gtuleu_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (x);
return (code == GTU || code == LEU);
}
/* Return nonzero if X is either IOR or XOR. */
int
iorxor_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (x);
return (code == IOR || code == XOR);
}
/* Recognize valid operators for bit instructions. */
int
bit_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code = GET_CODE (x);
return (code == XOR
|| code == AND
|| code == IOR);
}
/* Given that X occurs in an address of the form (plus X constant),
return the part of X that is expected to be a register. There are
@ -2896,58 +2494,6 @@ h8300_operands_match_p (rtx *operands)
return false;
}
/* Return true if OP is a binary operator in which it would be safe to
replace register operands with memory operands. */
int
h8sx_binary_memory_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (!TARGET_H8300SX)
return false;
if (GET_MODE (op) != QImode
&& GET_MODE (op) != HImode
&& GET_MODE (op) != SImode)
return false;
switch (GET_CODE (op))
{
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
return true;
default:
return h8sx_unary_shift_operator (op, mode);
}
}
/* Like h8sx_binary_memory_operator, but applies to unary operators. */
int
h8sx_unary_memory_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (!TARGET_H8300SX)
return false;
if (GET_MODE (op) != QImode
&& GET_MODE (op) != HImode
&& GET_MODE (op) != SImode)
return false;
switch (GET_CODE (op))
{
case NEG:
case NOT:
return true;
default:
return false;
}
}
/* Try using movmd to move LENGTH bytes from memory region SRC to memory
region DEST. The two regions do not overlap and have the common
@ -4049,26 +3595,6 @@ h8sx_classify_shift (enum machine_mode mode, enum rtx_code code, rtx op)
}
}
/* Return true if X is a shift operation of type H8SX_SHIFT_UNARY. */
int
h8sx_unary_shift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (BINARY_P (x) && NON_COMMUTATIVE_P (x)
&& (h8sx_classify_shift (GET_MODE (x), GET_CODE (x), XEXP (x, 1))
== H8SX_SHIFT_UNARY));
}
/* Likewise H8SX_SHIFT_BINARY. */
int
h8sx_binary_shift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (BINARY_P (x) && NON_COMMUTATIVE_P (x)
&& (h8sx_classify_shift (GET_MODE (x), GET_CODE (x), XEXP (x, 1))
== H8SX_SHIFT_BINARY));
}
/* Return the asm template for a single h8sx shift instruction.
OPERANDS[0] and OPERANDS[1] are the destination, OPERANDS[2]
is the source and OPERANDS[3] is the shift. SUFFIX is the
@ -4115,20 +3641,6 @@ output_h8sx_shift (rtx *operands, int suffix, int optype)
sprintf (buffer, "%s.%c\t%%X2,%%%c0", stem, suffix, optype);
return buffer;
}
int
nshift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (x))
{
case ASHIFTRT:
case LSHIFTRT:
case ASHIFT:
return 1;
default:
return 0;
}
}
/* Emit code to do shifts. */

View File

@ -1200,44 +1200,9 @@ extern int h8300_move_ratio;
#undef MOVE_RATIO
#define MOVE_RATIO h8300_move_ratio
/* Define the codes that are matched by predicates in h8300.c. */
#define PREDICATE_CODES \
{"general_operand_src", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
LABEL_REF, SUBREG, REG, MEM}}, \
{"general_operand_dst", {SUBREG, REG, MEM}}, \
{"h8300_src_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
LABEL_REF, SUBREG, REG, MEM}}, \
{"h8300_dst_operand", {SUBREG, REG, MEM}}, \
{"nibble_operand", {CONST_INT}}, \
{"reg_or_nibble_operand", {CONST_INT, SUBREG, REG}}, \
{"h8sx_unary_shift_operator", {ASHIFTRT, LSHIFTRT, ASHIFT, ROTATE}}, \
{"h8sx_binary_shift_operator", {ASHIFTRT, LSHIFTRT, ASHIFT}}, \
{"h8sx_binary_memory_operator", {PLUS, MINUS, AND, IOR, XOR, ASHIFT, \
ASHIFTRT, LSHIFTRT, ROTATE}}, \
{"h8sx_unary_memory_operator", {NEG, NOT}}, \
{"h8300_ldm_parallel", {PARALLEL}}, \
{"h8300_stm_parallel", {PARALLEL}}, \
{"h8300_return_parallel", {PARALLEL}}, \
{"single_one_operand", {CONST_INT}}, \
{"single_zero_operand", {CONST_INT}}, \
{"call_insn_operand", {MEM}}, \
{"small_call_insn_operand", {MEM}}, \
{"jump_address_operand", {REG, MEM}}, \
{"two_insn_adds_subs_operand", {CONST_INT}}, \
{"bit_operand", {REG, SUBREG, MEM}}, \
{"bit_memory_operand", {MEM}}, \
{"stack_pointer_operand", {REG}}, \
{"const_int_gt_2_operand", {CONST_INT}}, \
{"const_int_ge_8_operand", {CONST_INT}}, \
{"const_int_qi_operand", {CONST_INT}}, \
{"const_int_hi_operand", {CONST_INT}}, \
{"incdec_operand", {CONST_INT}}, \
{"bit_operator", {XOR, AND, IOR}}, \
{"nshift_operator", {ASHIFTRT, LSHIFTRT, ASHIFT}}, \
{"eqne_operator", {EQ, NE}}, \
{"gtle_operator", {GT, LE, GTU, LEU}}, \
{"gtuleu_operator", {GTU, LEU}}, \
{"iorxor_operator", {IOR, XOR}},
/* Machine-specific symbol_ref flags. */
#define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0)
#define SYMBOL_FLAG_EIGHTBIT_DATA (SYMBOL_FLAG_MACH_DEP << 1)
#define SYMBOL_FLAG_TINY_DATA (SYMBOL_FLAG_MACH_DEP << 2)
#endif /* ! GCC_H8300_H */

View File

@ -175,6 +175,8 @@
(ne (symbol_ref "TARGET_H8300H") (const_int 0)) (const_int 10)
(ne (symbol_ref "TARGET_H8300S") (const_int 0)) (const_int 10)]
(const_int 14)))])
(include "predicates.md")
;; ----------------------------------------------------------------------
;; MOVE INSTRUCTIONS

View File

@ -0,0 +1,483 @@
;; Predicate definitions for Renesas H8/300.
;; 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 OP is a valid source operand for an integer move
;; instruction.
(define_predicate "general_operand_src"
(match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,mem")
{
if (GET_MODE (op) == mode
&& GET_CODE (op) == MEM
&& GET_CODE (XEXP (op, 0)) == POST_INC)
return 1;
return general_operand (op, mode);
})
;; Return true if OP is a valid destination operand for an integer
;; move instruction.
(define_predicate "general_operand_dst"
(match_code "subreg,reg,mem")
{
if (GET_MODE (op) == mode
&& GET_CODE (op) == MEM
&& GET_CODE (XEXP (op, 0)) == PRE_DEC)
return 1;
return general_operand (op, mode);
})
;; Likewise the second operand.
(define_predicate "h8300_src_operand"
(match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,mem")
{
if (TARGET_H8300SX)
return general_operand (op, mode);
return nonmemory_operand (op, mode);
})
;; Return true if OP is a suitable first operand for a general
;; arithmetic insn such as "add".
(define_predicate "h8300_dst_operand"
(match_code "subreg,reg,mem")
{
if (TARGET_H8300SX)
return nonimmediate_operand (op, mode);
return register_operand (op, mode);
})
;; Check that an operand is either a register or an unsigned 4-bit
;; constant.
(define_predicate "nibble_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT && TARGET_H8300SX
&& INTVAL (op) >= 0 && INTVAL (op) <= 15);
})
;; Check that an operand is either a register or an unsigned 4-bit
;; constant.
(define_predicate "reg_or_nibble_operand"
(match_code "const_int,subreg,reg")
{
return (nibble_operand (op, mode) || register_operand (op, mode));
})
;; Return true if X is a shift operation of type H8SX_SHIFT_UNARY.
(define_predicate "h8sx_unary_shift_operator"
(match_code "ashiftrt,lshiftrt,ashift,rotate")
{
return (BINARY_P (op) && NON_COMMUTATIVE_P (op)
&& (h8sx_classify_shift (GET_MODE (op), GET_CODE (op), XEXP (op, 1))
== H8SX_SHIFT_UNARY));
})
;; Likewise H8SX_SHIFT_BINARY.
(define_predicate "h8sx_binary_shift_operator"
(match_code "ashiftrt,lshiftrt,ashift")
{
return (BINARY_P (op) && NON_COMMUTATIVE_P (op)
&& (h8sx_classify_shift (GET_MODE (op), GET_CODE (op), XEXP (op, 1))
== H8SX_SHIFT_BINARY));
})
;; Return true if OP is a binary operator in which it would be safe to
;; replace register operands with memory operands.
(define_predicate "h8sx_binary_memory_operator"
(match_code "plus,minus,and,ior,xor,ashift,ashiftrt,lshiftrt,rotate")
{
if (!TARGET_H8300SX)
return false;
if (GET_MODE (op) != QImode
&& GET_MODE (op) != HImode
&& GET_MODE (op) != SImode)
return false;
switch (GET_CODE (op))
{
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
return true;
default:
return h8sx_unary_shift_operator (op, mode);
}
})
;; Like h8sx_binary_memory_operator, but applies to unary operators.
(define_predicate "h8sx_unary_memory_operator"
(match_code "neg,not")
{
if (!TARGET_H8300SX)
return false;
if (GET_MODE (op) != QImode
&& GET_MODE (op) != HImode
&& GET_MODE (op) != SImode)
return false;
switch (GET_CODE (op))
{
case NEG:
case NOT:
return true;
default:
return false;
}
})
;; Return true if X is an ldm.l pattern. X is known to be parallel.
(define_predicate "h8300_ldm_parallel"
(match_code "parallel")
{
return h8300_ldm_stm_parallel (XVEC (op, 0), 1, 0);
})
;; Likewise stm.l.
(define_predicate "h8300_stm_parallel"
(match_code "parallel")
{
return h8300_ldm_stm_parallel (XVEC (op, 0), 0, 0);
})
;; Likewise rts/l and rte/l. Note that the .md pattern will check for
;; the return so there's no need to do that here.
(define_predicate "h8300_return_parallel"
(match_code "parallel")
{
return h8300_ldm_stm_parallel (XVEC (op, 0), 1, 1);
})
;; Return true if OP is a constant that contains only one 1 in its
;; binary representation.
(define_predicate "single_one_operand"
(match_code "const_int")
{
if (GET_CODE (op) == CONST_INT)
{
/* We really need to do this masking because 0x80 in QImode is
represented as -128 for example. */
if (exact_log2 (INTVAL (op) & GET_MODE_MASK (mode)) >= 0)
return 1;
}
return 0;
})
;; Return true if OP is a constant that contains only one 0 in its
;; binary representation.
(define_predicate "single_zero_operand"
(match_code "const_int")
{
if (GET_CODE (op) == CONST_INT)
{
/* We really need to do this masking because 0x80 in QImode is
represented as -128 for example. */
if (exact_log2 (~INTVAL (op) & GET_MODE_MASK (mode)) >= 0)
return 1;
}
return 0;
})
;; Return true if OP is a valid call operand.
(define_predicate "call_insn_operand"
(match_code "mem")
{
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
if (register_operand (inside, Pmode))
return 1;
if (CONSTANT_ADDRESS_P (inside))
return 1;
}
return 0;
})
;; Return true if OP is a valid call operand, and OP represents an
;; operand for a small call (4 bytes instead of 6 bytes).
(define_predicate "small_call_insn_operand"
(match_code "mem")
{
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
/* Register indirect is a small call. */
if (register_operand (inside, Pmode))
return 1;
/* A call through the function vector is a small call too. */
if (GET_CODE (inside) == SYMBOL_REF
&& (SYMBOL_REF_FLAGS (inside) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
return 1;
}
/* Otherwise it's a large call. */
return 0;
})
;; Return true if OP is a valid jump operand.
(define_predicate "jump_address_operand"
(match_code "reg,mem")
{
if (GET_CODE (op) == REG)
return mode == Pmode;
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
if (register_operand (inside, Pmode))
return 1;
if (CONSTANT_ADDRESS_P (inside))
return 1;
}
return 0;
})
;; Return 1 if an addition/subtraction of a constant integer can be
;; transformed into two consecutive adds/subs that are faster than the
;; straightforward way. Otherwise, return 0.
(define_predicate "two_insn_adds_subs_operand"
(match_code "const_int")
{
if (TARGET_H8300SX)
return 0;
if (GET_CODE (op) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (op);
/* Force VALUE to be positive so that we do not have to consider
the negative case. */
if (value < 0)
value = -value;
if (TARGET_H8300H || TARGET_H8300S)
{
/* A constant addition/subtraction takes 2 states in QImode,
4 states in HImode, and 6 states in SImode. Thus, the
only case we can win is when SImode is used, in which
case, two adds/subs are used, taking 4 states. */
if (mode == SImode
&& (value == 2 + 1
|| value == 4 + 1
|| value == 4 + 2
|| value == 4 + 4))
return 1;
}
else
{
/* We do not profit directly by splitting addition or
subtraction of 3 and 4. However, since these are
implemented as a sequence of adds or subs, they do not
clobber (cc0) unlike a sequence of add.b and add.x. */
if (mode == HImode
&& (value == 2 + 1
|| value == 2 + 2))
return 1;
}
}
return 0;
})
;; Recognize valid operands for bit-field instructions.
(define_predicate "bit_operand"
(match_code "reg,subreg,mem")
{
/* We can accept any nonimmediate operand, except that MEM operands must
be limited to those that use addresses valid for the 'U' constraint. */
if (!nonimmediate_operand (op, mode))
return 0;
/* H8SX accepts pretty much anything here. */
if (TARGET_H8300SX)
return 1;
/* Accept any mem during RTL generation. Otherwise, the code that does
insv and extzv will think that we cannot handle memory. However,
to avoid reload problems, we only accept 'U' MEM operands after RTL
generation. This means that any named pattern which uses this predicate
must force its operands to match 'U' before emitting RTL. */
if (GET_CODE (op) == REG)
return 1;
if (GET_CODE (op) == SUBREG)
return 1;
return (GET_CODE (op) == MEM
&& OK_FOR_U (op));
})
;; Return nonzero if OP is a MEM suitable for bit manipulation insns.
(define_predicate "bit_memory_operand"
(match_code "mem")
{
return (GET_CODE (op) == MEM
&& OK_FOR_U (op));
})
;; Return nonzero if X is a stack pointer.
(define_predicate "stack_pointer_operand"
(match_code "reg")
{
return op == stack_pointer_rtx;
})
;; Return nonzero if X is a constant whose absolute value is greater
;; than 2.
(define_predicate "const_int_gt_2_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& abs (INTVAL (op)) > 2);
})
;; Return nonzero if X is a constant whose absolute value is no
;; smaller than 8.
(define_predicate "const_int_ge_8_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& abs (INTVAL (op)) >= 8);
})
;; Return nonzero if X is a constant expressible in QImode.
(define_predicate "const_int_qi_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) & 0xff) == INTVAL (op));
})
;; Return nonzero if X is a constant expressible in HImode.
(define_predicate "const_int_hi_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) & 0xffff) == INTVAL (op));
})
;; Return nonzero if X is a constant suitable for inc/dec.
(define_predicate "incdec_operand"
(match_code "const_int")
{
return (GET_CODE (op) == CONST_INT
&& (CONST_OK_FOR_M (INTVAL (op))
|| CONST_OK_FOR_O (INTVAL (op))));
})
;; Recognize valid operators for bit instructions.
(define_predicate "bit_operator"
(match_code "xor,and,ior")
{
enum rtx_code code = GET_CODE (op);
return (code == XOR
|| code == AND
|| code == IOR);
})
;; Return nonzero if OP is a shift operator.
(define_predicate "nshift_operator"
(match_code "ashiftrt,lshiftrt,ashift")
{
switch (GET_CODE (op))
{
case ASHIFTRT:
case LSHIFTRT:
case ASHIFT:
return 1;
default:
return 0;
}
})
;; Return nonzero if X is either EQ or NE.
(define_predicate "eqne_operator"
(match_code "eq,ne")
{
enum rtx_code code = GET_CODE (op);
return (code == EQ || code == NE);
})
;; Return nonzero if X is either GT or LE.
(define_predicate "gtle_operator"
(match_code "gt,le,gtu,leu")
{
enum rtx_code code = GET_CODE (op);
return (code == GT || code == LE);
})
;; Return nonzero if X is either GTU or LEU.
(define_predicate "gtuleu_operator"
(match_code "gtu,leu")
{
enum rtx_code code = GET_CODE (op);
return (code == GTU || code == LEU);
})
;; Return nonzero if X is either IOR or XOR.
(define_predicate "iorxor_operator"
(match_code "ior,xor")
{
enum rtx_code code = GET_CODE (op);
return (code == IOR || code == XOR);
})