+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.
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);
/* 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
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. */
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);
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;
/* 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)
\f
/* See below where shifts are handled for explanation of this enum. */
/* 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;
&& 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:
fputs ("\t.end\n", asm_out_file);
}
\f
-/* 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
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.
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);
-}
\f
/* 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
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;
- }
-}
\f
/* 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
}
}
-/* 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
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. */
#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 */
(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")
\f
;; ----------------------------------------------------------------------
;; MOVE INSTRUCTIONS
--- /dev/null
+;; 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);
+})