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