predicates.md: New file.

* config/cris/predicates.md: New file.
	* config/cris/cris-protos.h (cris_store_multiple_op_p)
	(cris_movem_load_rest_p): Declare.
	* config/cris/cris.c (cris_store_multiple_op): Return bool, not int.
	(cris_movem_load_rest_p): Ditto.  Globalize.
	(cris_bdap_operand, cris_bdap_biap_operand,
	cris_orthogonal_operator, cris_commutative_orth_op,
	cris_operand_extend_operator,
	cris_additive_operand_extend_operator, cris_extend_operator,
	cris_plus_or_bound_operator, cris_mem_op,
	cris_general_operand_or_symbol,
	cris_general_operand_or_gotless_symbol,
	cris_general_operand_or_plt_symbol, cris_mem_call_operand,
	cris_load_multiple_op): Remove predicate functions.
	(cris_symbol, cris_gotless_symbol) <case UNSPEC>: Return 0, don't
	abort, for UNSPECs other than CRIS_UNSPEC_PLT.
	* config/cris/cris.h (PREDICATE_CODES): Don't define.
	* config/cris/cris.md: Include predicates.md.
	("call", "call_value"): Generate CONSTs of Pmode, not VOIDmode.

From-SVN: r98471
This commit is contained in:
Hans-Peter Nilsson 2005-04-20 22:31:30 +00:00 committed by Hans-Peter Nilsson
parent c3e5898be3
commit 68a813322b
6 changed files with 221 additions and 339 deletions

View File

@ -1,3 +1,25 @@
2005-04-21 Hans-Peter Nilsson <hp@axis.com>
* config/cris/predicates.md: New file.
* config/cris/cris-protos.h (cris_store_multiple_op_p)
(cris_movem_load_rest_p): Declare.
* config/cris/cris.c (cris_store_multiple_op): Return bool, not int.
(cris_movem_load_rest_p): Ditto. Globalize.
(cris_bdap_operand, cris_bdap_biap_operand,
cris_orthogonal_operator, cris_commutative_orth_op,
cris_operand_extend_operator,
cris_additive_operand_extend_operator, cris_extend_operator,
cris_plus_or_bound_operator, cris_mem_op,
cris_general_operand_or_symbol,
cris_general_operand_or_gotless_symbol,
cris_general_operand_or_plt_symbol, cris_mem_call_operand,
cris_load_multiple_op): Remove predicate functions.
(cris_symbol, cris_gotless_symbol) <case UNSPEC>: Return 0, don't
abort, for UNSPECs other than CRIS_UNSPEC_PLT.
* config/cris/cris.h (PREDICATE_CODES): Don't define.
* config/cris/cris.md: Include predicates.md.
("call", "call_value"): Generate CONSTs of Pmode, not VOIDmode.
2005-04-20 Ian Lance Taylor <ian@airs.com> 2005-04-20 Ian Lance Taylor <ian@airs.com>
* c-common.def: Remove STMT_EXPR (moved to cp/cp-tree.def). * c-common.def: Remove STMT_EXPR (moved to cp/cp-tree.def).

View File

@ -41,6 +41,8 @@ extern int cris_legitimate_pic_operand (rtx);
extern int cris_gotless_symbol (rtx); extern int cris_gotless_symbol (rtx);
extern int cris_got_symbol (rtx); extern int cris_got_symbol (rtx);
extern int cris_symbol (rtx); extern int cris_symbol (rtx);
extern bool cris_store_multiple_op_p (rtx);
extern bool cris_movem_load_rest_p (rtx, int);
extern void cris_asm_output_symbol_ref (FILE *, rtx); extern void cris_asm_output_symbol_ref (FILE *, rtx);
extern bool cris_output_addr_const_extra (FILE *, rtx); extern bool cris_output_addr_const_extra (FILE *, rtx);
extern int cris_cfun_uses_pic_table (void); extern int cris_cfun_uses_pic_table (void);

View File

@ -120,8 +120,6 @@ static void cris_operand_lossage (const char *, rtx);
static int cris_reg_saved_in_regsave_area (unsigned int, bool); static int cris_reg_saved_in_regsave_area (unsigned int, bool);
static int cris_movem_load_rest_p (rtx, int);
static void cris_asm_output_mi_thunk static void cris_asm_output_mi_thunk
(FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
@ -205,280 +203,9 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
struct gcc_target targetm = TARGET_INITIALIZER; struct gcc_target targetm = TARGET_INITIALIZER;
/* Predicate functions. */
/* This checks a part of an address, the one that is not a plain register
for an addressing mode using BDAP.
Allowed operands is either:
a) a register
b) a CONST operand (but not a symbol when generating PIC)
c) a [r] or [r+] in SImode, or sign-extend from HI or QI. */
int
cris_bdap_operand (rtx op, enum machine_mode mode)
{
register enum rtx_code code = GET_CODE (op);
if (mode != SImode && (mode != VOIDmode || GET_MODE (op) != VOIDmode))
return 0;
/* Just return whether this is a simple register or constant. */
if (register_operand (op, mode)
|| (CONSTANT_P (op) && !(flag_pic && cris_symbol (op))))
return 1;
/* Is it a [r] or possibly a [r+]? */
if (code == MEM)
{
rtx tem = XEXP (op, 0);
if (mode == SImode
&& (register_operand (tem, SImode)
|| (GET_CODE (tem) == POST_INC
&& register_operand (XEXP (tem, 0), SImode))))
return 1;
else
return 0;
}
/* Perhaps a sign-extended mem: [r].(b|w) or [r+].(b|w)? */
if (code == SIGN_EXTEND)
{
rtx tem = XEXP (op, 0);
if (GET_CODE (tem) != MEM)
return 0;
tem = XEXP (tem, 0);
if (mode == SImode
&& (register_operand (tem, SImode)
|| (GET_CODE (tem) == POST_INC
&& register_operand (XEXP (tem, 0), SImode))))
return 1;
else
return 0;
}
return 0;
}
/* This is similar to cris_bdap_operand:
It checks a part of an address, the one that is not a plain register
for an addressing mode using BDAP *or* BIAP.
Allowed operands is either:
a) a register
b) a CONST operand (but not a symbol when generating PIC)
c) a mult of (1, 2 or 4) and a register
d) a [r] or [r+] in SImode, or sign-extend from HI or QI. */
int
cris_bdap_biap_operand (rtx op, enum machine_mode mode)
{
register enum rtx_code code = GET_CODE (op);
rtx reg;
rtx val;
/* Check for bdap operand. */
if (cris_bdap_operand (op, mode))
return 1;
if (mode != SImode && (mode != VOIDmode || GET_MODE (op) != VOIDmode))
return 0;
/* Check that we're looking at a BIAP operand. */
if (code != MULT)
return 0;
/* Canonicalize register and multiplicand. */
if (GET_CODE (XEXP (op, 0)) == CONST_INT)
{
val = XEXP (op, 0);
reg = XEXP (op, 1);
}
else
{
val = XEXP (op, 1);
reg = XEXP (op, 0);
}
/* Check that the operands are correct after canonicalization. */
if (! register_operand (reg, SImode) || GET_CODE (val) != CONST_INT)
return 0;
/* Check that the multiplicand has a valid value. */
if ((code == MULT
&& (INTVAL (val) == 1 || INTVAL (val) == 2 || INTVAL (val) == 4)))
return 1;
return 0;
}
/* Check if MODE is same as mode for X, and X is PLUS, MINUS, IOR or
AND or UMIN. */
int
cris_orthogonal_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
if (mode == VOIDmode)
mode = GET_MODE (x);
return (GET_MODE (x) == mode
&& (code == PLUS || code == MINUS
|| code == IOR || code == AND || code == UMIN));
}
/* Check if MODE is same as mode for X, and X is PLUS, IOR or AND or
UMIN. */
int
cris_commutative_orth_op (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
if (mode == VOIDmode)
mode = GET_MODE (x);
return (GET_MODE (x) == mode &&
(code == PLUS
|| code == IOR || code == AND || code == UMIN));
}
/* Check if MODE is same as mode for X, and X is PLUS or MINUS or UMIN.
By the name, you might think we should include MULT. We don't because
it doesn't accept the same addressing modes as the others (ony
registers) and there's also the problem of handling TARGET_MUL_BUG. */
int
cris_operand_extend_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
if (mode == VOIDmode)
mode = GET_MODE (x);
return (GET_MODE (x) == mode
&& (code == PLUS || code == MINUS || code == UMIN));
}
/* Check if MODE is same as mode for X, and X is PLUS or MINUS. */
int
cris_additive_operand_extend_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
if (mode == VOIDmode)
mode = GET_MODE (x);
return (GET_MODE (x) == mode
&& (code == PLUS || code == MINUS));
}
/* Check to see if MODE is same as mode for X, and X is SIGN_EXTEND or
ZERO_EXTEND. */
int
cris_extend_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
if (mode == VOIDmode)
mode = GET_MODE (x);
return
(GET_MODE (x) == mode && (code == SIGN_EXTEND || code == ZERO_EXTEND));
}
/* Check to see if MODE is same as mode for X, and X is PLUS or BOUND. */
int
cris_plus_or_bound_operator (rtx x, enum machine_mode mode)
{
enum rtx_code code = GET_CODE (x);
if (mode == VOIDmode)
mode = GET_MODE (x);
return
(GET_MODE (x) == mode && (code == UMIN || code == PLUS));
}
/* Used as an operator to get a handle on a already-known-valid MEM rtx:es
(no need to validate the address), where some address expression parts
have their own match_operand. */
int
cris_mem_op (rtx x, enum machine_mode mode)
{
if (mode == VOIDmode)
mode = GET_MODE (x);
return GET_MODE (x) == mode && GET_CODE (x) == MEM;
}
/* Since with -fPIC, not all symbols are valid PIC symbols or indeed
general_operands, we have to have a predicate that matches it for the
"movsi" expander. */
int
cris_general_operand_or_symbol (rtx op, enum machine_mode mode)
{
return general_operand (op, mode)
|| (CONSTANT_P (op) && cris_symbol (op));
}
/* Since a PIC symbol without a GOT entry is not a general_operand, we
have to have a predicate that matches it. We use this in the expanded
"movsi" anonymous pattern. */
int
cris_general_operand_or_gotless_symbol (rtx op, enum machine_mode mode)
{
return general_operand (op, mode)
|| (GET_CODE (op) == UNSPEC && XINT (op, 1) == CRIS_UNSPEC_GOT)
|| (CONSTANT_P (op) && cris_gotless_symbol (op));
}
/* Since a PLT symbol is not a general_operand, we have to have a
predicate that matches it when we need it. We use this in the expanded
"call" and "call_value" anonymous patterns. */
int
cris_general_operand_or_plt_symbol (rtx op, enum machine_mode mode)
{
return general_operand (op, mode)
|| (GET_CODE (op) == CONST
&& GET_CODE (XEXP (op, 0)) == UNSPEC
&& !TARGET_AVOID_GOTPLT);
}
/* This matches a (MEM (general_operand)) or
(MEM (cris_general_operand_or_symbol)). The second one isn't a valid
memory_operand, so we need this predicate to recognize call
destinations before we change them to a PLT operand (by wrapping in
UNSPEC CRIS_UNSPEC_PLT). */
int
cris_mem_call_operand (rtx op, enum machine_mode mode)
{
rtx xmem;
if (GET_CODE (op) != MEM)
return 0;
if (memory_operand (op, mode))
return 1;
xmem = XEXP (op, 0);
return cris_general_operand_or_symbol (xmem, GET_MODE (op));
}
/* Helper for cris_load_multiple_op and cris_ret_movem_op. */ /* Helper for cris_load_multiple_op and cris_ret_movem_op. */
static int bool
cris_movem_load_rest_p (rtx op, int offs) cris_movem_load_rest_p (rtx op, int offs)
{ {
unsigned int reg_count = XVECLEN (op, 0) - offs; unsigned int reg_count = XVECLEN (op, 0) - offs;
@ -495,7 +222,7 @@ cris_movem_load_rest_p (rtx op, int offs)
|| GET_CODE (XVECEXP (op, 0, offs)) != SET || GET_CODE (XVECEXP (op, 0, offs)) != SET
|| GET_CODE (SET_DEST (XVECEXP (op, 0, offs))) != REG || GET_CODE (SET_DEST (XVECEXP (op, 0, offs))) != REG
|| GET_CODE (SET_SRC (XVECEXP (op, 0, offs))) != MEM) || GET_CODE (SET_SRC (XVECEXP (op, 0, offs))) != MEM)
return 0; return false;
/* Check a possible post-inc indicator. */ /* Check a possible post-inc indicator. */
if (GET_CODE (SET_SRC (XVECEXP (op, 0, offs + 1))) == PLUS) if (GET_CODE (SET_SRC (XVECEXP (op, 0, offs + 1))) == PLUS)
@ -511,7 +238,7 @@ cris_movem_load_rest_p (rtx op, int offs)
|| REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, offs + 1))) || REGNO (reg) != REGNO (SET_DEST (XVECEXP (op, 0, offs + 1)))
|| GET_CODE (inc) != CONST_INT || GET_CODE (inc) != CONST_INT
|| INTVAL (inc) != (HOST_WIDE_INT) reg_count * 4) || INTVAL (inc) != (HOST_WIDE_INT) reg_count * 4)
return 0; return false;
i = offs + 2; i = offs + 2;
} }
else else
@ -531,7 +258,7 @@ cris_movem_load_rest_p (rtx op, int offs)
|| GET_CODE (SET_SRC (elt)) != MEM || GET_CODE (SET_SRC (elt)) != MEM
|| GET_MODE (SET_SRC (elt)) != SImode || GET_MODE (SET_SRC (elt)) != SImode
|| !memory_address_p (SImode, src_addr)) || !memory_address_p (SImode, src_addr))
return 0; return false;
for (setno = 1; i < XVECLEN (op, 0); setno++, i++) for (setno = 1; i < XVECLEN (op, 0); setno++, i++)
{ {
@ -548,24 +275,17 @@ cris_movem_load_rest_p (rtx op, int offs)
|| ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr) || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
|| GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
|| INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != setno * 4) || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != setno * 4)
return 0; return false;
} }
return 1; return true;
} }
/* Predicate for the parallel contents in a movem from-memory. */ /* Worker function for predicate for the parallel contents in a movem
to-memory. */
int bool
cris_load_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) cris_store_multiple_op_p (rtx op)
{
return cris_movem_load_rest_p (op, 0);
}
/* Predicate for the parallel contents in a movem to-memory. */
int
cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{ {
int reg_count = XVECLEN (op, 0); int reg_count = XVECLEN (op, 0);
rtx dest; rtx dest;
@ -581,18 +301,18 @@ cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
/* Perform a quick check so we don't blow up below. FIXME: Adjust for /* Perform a quick check so we don't blow up below. FIXME: Adjust for
other than (MEM reg) and (MEM (PLUS reg const)). */ other than (MEM reg) and (MEM (PLUS reg const)). */
if (reg_count <= 1) if (reg_count <= 1)
return 0; return false;
elt = XVECEXP (op, 0, 0); elt = XVECEXP (op, 0, 0);
if (GET_CODE (elt) != SET) if (GET_CODE (elt) != SET)
return 0; return false;
dest = SET_DEST (elt); dest = SET_DEST (elt);
if (GET_CODE (SET_SRC (elt)) != REG if (GET_CODE (SET_SRC (elt)) != REG
|| GET_CODE (dest) != MEM) || GET_CODE (dest) != MEM)
return 0; return false;
dest_addr = XEXP (dest, 0); dest_addr = XEXP (dest, 0);
@ -620,7 +340,7 @@ cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
&& REGNO (XEXP (dest_addr, 0)) == REGNO (reg) && REGNO (XEXP (dest_addr, 0)) == REGNO (reg)
&& GET_CODE (XEXP (dest_addr, 1)) == CONST_INT && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT
&& INTVAL (XEXP (dest_addr, 1)) == INTVAL (inc)))) && INTVAL (XEXP (dest_addr, 1)) == INTVAL (inc))))
return 0; return false;
i = 2; i = 2;
} }
@ -637,7 +357,7 @@ cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|| REGNO (SET_SRC (elt)) != (unsigned int) regno || REGNO (SET_SRC (elt)) != (unsigned int) regno
|| GET_CODE (SET_DEST (elt)) != MEM || GET_CODE (SET_DEST (elt)) != MEM
|| GET_MODE (SET_DEST (elt)) != SImode) || GET_MODE (SET_DEST (elt)) != SImode)
return 0; return false;
if (REG_P (dest_addr)) if (REG_P (dest_addr))
{ {
@ -652,7 +372,7 @@ cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
offset = INTVAL (XEXP (dest_addr, 1)); offset = INTVAL (XEXP (dest_addr, 1));
} }
else else
return 0; return false;
for (setno = 1; i < XVECLEN (op, 0); setno++, i++) for (setno = 1; i < XVECLEN (op, 0); setno++, i++)
{ {
@ -669,10 +389,10 @@ cris_store_multiple_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|| ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_base) || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_base)
|| GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
|| INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != setno * 4 + offset) || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != setno * 4 + offset)
return 0; return false;
} }
return 1; return true;
} }
/* The CONDITIONAL_REGISTER_USAGE worker. */ /* The CONDITIONAL_REGISTER_USAGE worker. */
@ -2176,7 +1896,7 @@ cris_symbol (rtx x)
return 1; return 1;
case UNSPEC: case UNSPEC:
if (XINT (x, 1) == CRIS_UNSPEC_GOT) if (XINT (x, 1) == CRIS_UNSPEC_GOT || XINT (x, 1) != CRIS_UNSPEC_PLT)
return 0; return 0;
/* A PLT reference. */ /* A PLT reference. */
ASSERT_PLT_UNSPEC (x); ASSERT_PLT_UNSPEC (x);
@ -2218,6 +1938,8 @@ cris_gotless_symbol (rtx x)
case UNSPEC: case UNSPEC:
if (XINT (x, 1) == CRIS_UNSPEC_GOT) if (XINT (x, 1) == CRIS_UNSPEC_GOT)
return 1; return 1;
if (XINT (x, 1) != CRIS_UNSPEC_PLT)
return 0;
ASSERT_PLT_UNSPEC (x); ASSERT_PLT_UNSPEC (x);
return 1; return 1;

View File

@ -1616,44 +1616,6 @@ struct cum_args {int regs;};
/* Node: Misc */ /* Node: Misc */
/* FIXME: Check this one more time. */
#define PREDICATE_CODES \
{"cris_orthogonal_operator", \
{PLUS, MINUS, IOR, AND, UMIN}}, \
{"cris_commutative_orth_op", \
{PLUS, IOR, AND, UMIN}}, \
{"cris_operand_extend_operator", \
{PLUS, MINUS, UMIN}}, \
{"cris_additive_operand_extend_operator", \
{PLUS, MINUS}}, \
{"cris_extend_operator", \
{ZERO_EXTEND, SIGN_EXTEND}}, \
{"cris_plus_or_bound_operator", \
{PLUS, UMIN}}, \
{"cris_mem_op", \
{MEM}}, \
{"cris_load_multiple_op", \
{PARALLEL}}, \
{"cris_store_multiple_op", \
{PARALLEL}}, \
{"cris_bdap_operand", \
{SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT, \
CONST_DOUBLE, CONST, SIGN_EXTEND}}, \
{"cris_bdap_biap_operand", \
{SUBREG, REG, LABEL_REF, SYMBOL_REF, MEM, CONST_INT, \
CONST_DOUBLE, CONST, SIGN_EXTEND, MULT}}, \
{"cris_general_operand_or_gotless_symbol", \
{CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
LABEL_REF, SUBREG, REG, MEM, UNSPEC}}, \
{"cris_general_operand_or_symbol", \
{CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
LABEL_REF, SUBREG, REG, MEM}}, \
{"cris_general_operand_or_plt_symbol", \
{CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
LABEL_REF, SUBREG, REG, MEM}}, \
{"cris_mem_call_operand", \
{MEM}},
/* A combination of the bound (umin) insn together with a /* A combination of the bound (umin) insn together with a
sign-extended add via the table to PC seems optimal. sign-extended add via the table to PC seems optimal.
If the table overflows, the assembler will take care of it. If the table overflows, the assembler will take care of it.

View File

@ -141,6 +141,10 @@
(define_delay (eq_attr "slottable" "has_slot") (define_delay (eq_attr "slottable" "has_slot")
[(eq_attr "slottable" "yes") (nil) (nil)]) [(eq_attr "slottable" "yes") (nil) (nil)])
;; Operand and operator predicates.
(include "predicates.md")
;; Test insns. ;; Test insns.
;; DImode ;; DImode
@ -3944,7 +3948,7 @@
for the symbol cause bad recombinatorial effects? */ for the symbol cause bad recombinatorial effects? */
op0 = force_reg (Pmode, op0 = force_reg (Pmode,
gen_rtx_CONST gen_rtx_CONST
(VOIDmode, (Pmode,
gen_rtx_UNSPEC (VOIDmode, gen_rtx_UNSPEC (VOIDmode,
gen_rtvec (1, op0), gen_rtvec (1, op0),
CRIS_UNSPEC_PLT))); CRIS_UNSPEC_PLT)));
@ -4009,7 +4013,7 @@
for the symbol cause bad recombinatorial effects? */ for the symbol cause bad recombinatorial effects? */
op1 = force_reg (Pmode, op1 = force_reg (Pmode,
gen_rtx_CONST gen_rtx_CONST
(VOIDmode, (Pmode,
gen_rtx_UNSPEC (VOIDmode, gen_rtx_UNSPEC (VOIDmode,
gen_rtvec (1, op1), gen_rtvec (1, op1),
CRIS_UNSPEC_PLT))); CRIS_UNSPEC_PLT)));

View File

@ -0,0 +1,170 @@
;; Operand and operator predicates for the GCC CRIS port.
;; 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.
;; Operator predicates.
(define_predicate "cris_orthogonal_operator"
(match_code "plus, minus, ior, and, umin"))
(define_predicate "cris_commutative_orth_op"
(match_code "plus, ior, and, umin"))
;; By the name, you might think we should include MULT. We don't because
;; it doesn't accept the same addressing modes as the others (only
;; registers) and there's also the problem of handling TARGET_MUL_BUG.
(define_predicate "cris_operand_extend_operator"
(match_code "plus, minus, umin"))
(define_predicate "cris_additive_operand_extend_operator"
(match_code "plus, minus"))
(define_predicate "cris_extend_operator"
(match_code "zero_extend, sign_extend"))
(define_predicate "cris_plus_or_bound_operator"
(match_code "plus, umin"))
;; Used as an operator to get a handle on a already-known-valid MEM rtx:es
;; (no need to validate the address), where some address expression parts
;; have their own match_operand.
(define_predicate "cris_mem_op"
(match_code "mem"))
(define_predicate "cris_load_multiple_op"
(and (match_code "parallel")
(match_test "cris_movem_load_rest_p (op, 0)")))
(define_predicate "cris_store_multiple_op"
(and (match_code "parallel")
(match_test "cris_store_multiple_op_p (op)")))
;; Operand helper predicates.
(define_predicate "cris_bdap_const_operand"
(and (match_code "label_ref, symbol_ref, const_int, const_double, const")
(not (and (match_test "flag_pic")
(match_test "cris_symbol (op)")))))
(define_predicate "cris_simple_address_operand"
(ior (match_operand:SI 0 "register_operand")
(and (match_code "post_inc")
(match_test "register_operand (XEXP (op, 0), Pmode)"))))
(define_predicate "cris_simple_operand"
(ior (match_operand 0 "register_operand")
(and (match_code "mem")
(match_test "cris_simple_address_operand (XEXP (op, 0),
Pmode)"))))
;; The caller needs to use :SI.
(define_predicate "cris_bdap_sign_extend_operand"
(and (match_code "sign_extend")
(and (match_test "MEM_P (XEXP (op, 0))")
(match_test "cris_simple_address_operand (XEXP (XEXP (op, 0), 0),
Pmode)"))))
;; FIXME: Should not have to test for 1.
(define_predicate "cris_scale_int_operand"
(and (match_code "const_int")
(ior (ior (match_test "op == GEN_INT (4)")
(match_test "op == const2_rtx"))
(match_test "op == const1_rtx"))))
;; FIXME: Should be able to assume (reg int).
(define_predicate "cris_biap_mult_operand"
(and (match_code "mult")
(ior (and (match_test "register_operand (XEXP (op, 0), Pmode)")
(match_test "cris_scale_int_operand (XEXP (op, 1), Pmode)"))
(and (match_test "cris_scale_int_operand (XEXP (op, 0), Pmode)")
(match_test "register_operand (XEXP (op, 1), Pmode)")))))
;; Operand predicates.
;; This checks a part of an address, the one that is not a plain register
;; for an addressing mode using BDAP.
;; Allowed operands are either:
;; a) a register
;; b) a CONST operand (but not a symbol when generating PIC)
;; c) a [r] or [r+] in SImode, or sign-extend from HI or QI.
(define_predicate "cris_bdap_operand"
(ior (match_operand 0 "cris_bdap_const_operand")
(ior (match_operand:SI 0 "cris_simple_operand")
(match_operand:SI 0 "cris_bdap_sign_extend_operand"))))
;; This is similar to cris_bdap_operand:
;; It checks a part of an address, the one that is not a plain register
;; for an addressing mode using BDAP or BIAP.
;; Allowed operands are either:
;; a) a register
;; b) a CONST operand (but not a symbol when generating PIC)
;; c) a mult of (1, 2 or 4) and a register
;; d) a [r] or [r+] in SImode, or sign-extend from HI or QI. */
(define_predicate "cris_bdap_biap_operand"
(ior (match_operand 0 "cris_bdap_operand")
(match_operand 0 "cris_biap_mult_operand")))
;; Since a PIC symbol without a GOT entry is not a general_operand, we
;; have to have a predicate that matches it. We use this in the expanded
;; "movsi" anonymous pattern.
;; FIXME: Can s/special_// when PR 20413 is fixed.
(define_special_predicate "cris_general_operand_or_gotless_symbol"
(ior (match_operand 0 "general_operand")
(and (match_code "const, symbol_ref, label_ref, unspec")
(match_test "cris_gotless_symbol (op)"))))
;; Since with -fPIC, not all symbols are valid PIC symbols or indeed
;; general_operands, we have to have a predicate that matches it for the
;; "movsi" expander.
;; FIXME: Can s/special_// when PR 20413 is fixed.
(define_special_predicate "cris_general_operand_or_symbol"
(ior (match_operand 0 "general_operand")
(and (match_code "const, symbol_ref, label_ref")
(match_test "cris_symbol (op)"))))
;; Since a PLT symbol is not a general_operand, we have to have a
;; predicate that matches it when we need it. We use this in the expanded
;; "call" and "call_value" anonymous patterns.
(define_predicate "cris_general_operand_or_plt_symbol"
(ior (match_operand 0 "general_operand")
(and (match_code "const")
(and (match_test "GET_CODE (XEXP (op, 0)) == UNSPEC")
(not (match_test "TARGET_AVOID_GOTPLT"))))))
;; This matches a (MEM (general_operand)) or
;; (MEM (cris_general_operand_or_symbol)). The second one isn't a valid
;; memory_operand, so we need this predicate to recognize call
;; destinations before we change them to a PLT operand (by wrapping in
;; UNSPEC CRIS_UNSPEC_PLT).
(define_predicate "cris_mem_call_operand"
(and (match_code "mem")
(ior (match_operand 0 "memory_operand")
(match_test "cris_general_operand_or_symbol (XEXP (op, 0),
Pmode)"))))