summaryrefslogtreecommitdiff
path: root/gcc/config/rx/predicates.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rx/predicates.md')
-rw-r--r--gcc/config/rx/predicates.md288
1 files changed, 288 insertions, 0 deletions
diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md
new file mode 100644
index 00000000000..d7a363ebb88
--- /dev/null
+++ b/gcc/config/rx/predicates.md
@@ -0,0 +1,288 @@
+;; Predicate definitions for Renesas RX.
+;; Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+;; Contributed by Red Hat.
+;;
+;; 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 3, 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 COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+
+;; Check that the operand is suitable for a call insn.
+;; Only registers and symbol refs are allowed.
+
+(define_predicate "rx_call_operand"
+ (match_code "symbol_ref,reg")
+)
+
+;; For sibcall operations we can only use a symbolic address.
+
+(define_predicate "rx_symbolic_call_operand"
+ (match_code "symbol_ref")
+)
+
+;; Check that the operand is suitable for a shift insn
+;; Only small integers or a value in a register are permitted.
+
+(define_predicate "rx_shift_operand"
+ (match_code "const_int,reg")
+ {
+ if (CONST_INT_P (op))
+ return IN_RANGE (INTVAL (op), 0, 31);
+ return true;
+ }
+)
+
+;; Check that the operand is suitable as the source operand
+;; for a logic or arithmeitc instruction. Registers, integers
+;; and a restricted subset of memory addresses are allowed.
+
+(define_predicate "rx_source_operand"
+ (match_code "const_int,reg,mem")
+ {
+ if (CONST_INT_P (op))
+ return rx_is_legitimate_constant (op);
+
+ if (! MEM_P (op))
+ return true;
+
+ /* Do not allow size conversions whilst accessing memory. */
+ if (GET_MODE (op) != mode)
+ return false;
+
+ return rx_is_restricted_memory_address (XEXP (op, 0), mode);
+ }
+)
+
+;; Check that the operand is suitable as the source operand
+;; for a comparison instruction. This is the same as
+;; rx_source_operand except that SUBREGs are allowed but
+;; CONST_INTs are not.
+
+(define_predicate "rx_compare_operand"
+ (match_code "subreg,reg,mem")
+ {
+ if (GET_CODE (op) == SUBREG)
+ return REG_P (XEXP (op, 0));
+
+ if (! MEM_P (op))
+ return true;
+
+ return rx_is_restricted_memory_address (XEXP (op, 0), mode);
+ }
+)
+
+;; Return true if OP is a store multiple operation. This looks like:
+;;
+;; [(set (SP) (MINUS (SP) (INT)))
+;; (set (MEM (SP)) (REG))
+;; (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated}
+;; ]
+
+(define_special_predicate "rx_store_multiple_vector"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ unsigned int src_regno;
+ rtx element;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 2)
+ return false;
+
+ /* Check that the first element of the vector is the stack adjust. */
+ element = XVECEXP (op, 0, 0);
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || REGNO (SET_DEST (element)) != SP_REG
+ || GET_CODE (SET_SRC (element)) != MINUS
+ || ! REG_P (XEXP (SET_SRC (element), 0))
+ || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
+ return false;
+
+ /* Check that the next element is the first push. */
+ element = XVECEXP (op, 0, 1);
+ if ( ! SET_P (element)
+ || ! REG_P (SET_SRC (element))
+ || GET_MODE (SET_SRC (element)) != SImode
+ || ! MEM_P (SET_DEST (element))
+ || GET_MODE (SET_DEST (element)) != SImode
+ || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
+ || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
+ || REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
+ || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
+ != GET_MODE_SIZE (SImode))
+ return false;
+
+ src_regno = REGNO (SET_SRC (element));
+
+ /* Check that the remaining elements use SP-<disp>
+ addressing and decreasing register numbers. */
+ for (i = 2; i < count; i++)
+ {
+ element = XVECEXP (op, 0, i);
+
+ if ( ! SET_P (element)
+ || ! REG_P (SET_SRC (element))
+ || GET_MODE (SET_SRC (element)) != SImode
+ || REGNO (SET_SRC (element)) != src_regno - (i - 1)
+ || ! MEM_P (SET_DEST (element))
+ || GET_MODE (SET_DEST (element)) != SImode
+ || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS
+ || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0))
+ || REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1))
+ || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1))
+ != i * GET_MODE_SIZE (SImode))
+ return false;
+ }
+ return true;
+})
+
+;; Return true if OP is a load multiple operation.
+;; This looks like:
+;; [(set (SP) (PLUS (SP) (INT)))
+;; (set (REG) (MEM (SP)))
+;; (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated}
+;; ]
+
+(define_special_predicate "rx_load_multiple_vector"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ unsigned int dest_regno;
+ rtx element;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 2)
+ return false;
+
+ /* Check that the first element of the vector is the stack adjust. */
+ element = XVECEXP (op, 0, 0);
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || REGNO (SET_DEST (element)) != SP_REG
+ || GET_CODE (SET_SRC (element)) != PLUS
+ || ! REG_P (XEXP (SET_SRC (element), 0))
+ || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
+ return false;
+
+ /* Check that the next element is the first push. */
+ element = XVECEXP (op, 0, 1);
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || ! MEM_P (SET_SRC (element))
+ || ! REG_P (XEXP (SET_SRC (element), 0))
+ || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
+ return false;
+
+ dest_regno = REGNO (SET_DEST (element));
+
+ /* Check that the remaining elements use SP+<disp>
+ addressing and incremental register numbers. */
+ for (i = 2; i < count; i++)
+ {
+ element = XVECEXP (op, 0, i);
+
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || GET_MODE (SET_DEST (element)) != SImode
+ || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
+ || ! MEM_P (SET_SRC (element))
+ || GET_MODE (SET_SRC (element)) != SImode
+ || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
+ || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
+ || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
+ || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
+ != (i - 1) * GET_MODE_SIZE (SImode))
+ return false;
+ }
+ return true;
+})
+
+;; Return true if OP is a pop-and-return load multiple operation.
+;; This looks like:
+;; [(set (SP) (PLUS (SP) (INT)))
+;; (set (REG) (MEM (SP)))
+;; (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated}
+;; (return)
+;; ]
+
+(define_special_predicate "rx_rtsd_vector"
+ (match_code "parallel")
+{
+ int count = XVECLEN (op, 0);
+ unsigned int dest_regno;
+ rtx element;
+ int i;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 2)
+ return false;
+
+ /* Check that the first element of the vector is the stack adjust. */
+ element = XVECEXP (op, 0, 0);
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || REGNO (SET_DEST (element)) != SP_REG
+ || GET_CODE (SET_SRC (element)) != PLUS
+ || ! REG_P (XEXP (SET_SRC (element), 0))
+ || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (SET_SRC (element), 1)))
+ return false;
+
+ /* Check that the next element is the first push. */
+ element = XVECEXP (op, 0, 1);
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || ! MEM_P (SET_SRC (element))
+ || ! REG_P (XEXP (SET_SRC (element), 0))
+ || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG)
+ return false;
+
+ dest_regno = REGNO (SET_DEST (element));
+
+ /* Check that the remaining elements, if any, and except
+ for the last one, use SP+<disp> addressing and incremental
+ register numbers. */
+ for (i = 2; i < count - 1; i++)
+ {
+ element = XVECEXP (op, 0, i);
+
+ if ( ! SET_P (element)
+ || ! REG_P (SET_DEST (element))
+ || GET_MODE (SET_DEST (element)) != SImode
+ || REGNO (SET_DEST (element)) != dest_regno + (i - 1)
+ || ! MEM_P (SET_SRC (element))
+ || GET_MODE (SET_SRC (element)) != SImode
+ || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS
+ || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0))
+ || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG
+ || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1))
+ || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1))
+ != (i - 1) * GET_MODE_SIZE (SImode))
+ return false;
+ }
+
+ /* The last element must be a RETURN. */
+ element = XVECEXP (op, 0, count - 1);
+ return GET_CODE (element) == RETURN;
+})