summaryrefslogtreecommitdiff
path: root/gcc/config/s390
diff options
context:
space:
mode:
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2005-04-04 16:25:05 +0000
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2005-04-04 16:25:05 +0000
commit8cc5de337939c46dd2a1f98ad62daac8fd4d1899 (patch)
treec567b05d0418a1b19ea35e3f8c7e67c652e4e2ae /gcc/config/s390
parent34882fefeb29d8356b0bb17802e26e097ed65688 (diff)
downloadgcc-8cc5de337939c46dd2a1f98ad62daac8fd4d1899.tar.gz
2005-04-04 Adrian Strae�tling <straetling@de.ibm.com>
* config/s390/s390-protos.h: (s390_comparison, s390_alc_comparison, s390_slb_comparison, const0_operand, consttable_operand, larl_operand, s_operand, shift_count_operand, bras_sym_operand, load_multiple_operation, store_multiple_operation, s390_plus_operand): Remove prototypes. (s390_legitimate_address_without_index_p): New prototype. * config/s390/s390.c: (SYMBOL_FLAG_ALIGN1, DISP_IN_RANGE): Move to s390.h. (s390_comparison, s390_alc_comparison, s390_slb_comparison, const0_operand, consttable_operand, larl_operand, s_operand, shift_count_operand, bras_sym_operand, load_multiple_operation, store_multiple_operation, s390_plus_operand): Move to predicates.md. (check_mode): Remove. (s390_branch_condition_mask): Remove 'static'. Move prototype to s390-protos.h. (s390_legitimate_address_without_index_p): New. * config/s390/s390.h (PREDICATE_CODES): Remove. * config/s390/s390.md: Include predicates.md. * config/s390/predicates.md: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@97554 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/s390')
-rw-r--r--gcc/config/s390/predicates.md386
-rw-r--r--gcc/config/s390/s390-protos.h14
-rw-r--r--gcc/config/s390/s390.c468
-rw-r--r--gcc/config/s390/s390.h28
-rw-r--r--gcc/config/s390/s390.md3
5 files changed, 414 insertions, 485 deletions
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
new file mode 100644
index 00000000000..9af62a886b9
--- /dev/null
+++ b/gcc/config/s390/predicates.md
@@ -0,0 +1,386 @@
+;; Predicate definitions for S/390 and zSeries.
+;; Copyright (C) 2005 Free Software Foundation, Inc.
+;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and
+;; Ulrich Weigand (uweigand@de.ibm.com).
+;;
+;; 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.
+
+;; OP is the current operation.
+;; MODE is the current operation mode.
+
+;; operands --------------------------------------------------------------
+
+;; Return true if OP a (const_int 0) operand.
+
+(define_predicate "const0_operand"
+ (and (match_code "const_int, const_double")
+ (match_test "op == CONST0_RTX (mode)")))
+
+;; Return true if OP is constant.
+
+(define_special_predicate "consttable_operand"
+ (and (match_code "symbol_ref, label_ref, const, const_int, const_double")
+ (match_test "CONSTANT_P (op)")))
+
+;; Return true if OP is a valid S-type operand.
+
+(define_predicate "s_operand"
+ (and (match_code "subreg, mem")
+ (match_operand 0 "general_operand"))
+{
+ /* Just like memory_operand, allow (subreg (mem ...))
+ after reload. */
+ if (reload_completed
+ && GET_CODE (op) == SUBREG
+ && GET_CODE (SUBREG_REG (op)) == MEM)
+ op = SUBREG_REG (op);
+
+ if (GET_CODE (op) != MEM)
+ return false;
+ if (!s390_legitimate_address_without_index_p (op))
+ return false;
+
+ return true;
+})
+
+;; Return true if OP is a valid operand for the BRAS instruction.
+;; Allow SYMBOL_REFs and @PLT stubs.
+
+(define_special_predicate "bras_sym_operand"
+ (ior (match_code "symbol_ref")
+ (and (match_code "const")
+ (and (match_test "GET_CODE (XEXP (op, 0)) == UNSPEC")
+ (match_test "XINT (XEXP (op, 0), 1) == UNSPEC_PLT")))))
+
+;; Return true if OP is a PLUS that is not a legitimate
+;; operand for the LA instruction.
+
+(define_predicate "s390_plus_operand"
+ (and (match_code "plus")
+ (and (match_test "mode == Pmode")
+ (match_test "!legitimate_la_operand_p (op)"))))
+
+;; Return true if OP is a valid shift count operand.
+
+(define_predicate "shift_count_operand"
+ (match_code "reg, subreg, plus, const_int")
+{
+ HOST_WIDE_INT offset = 0;
+
+ /* We can have an integer constant, an address register,
+ or a sum of the two. Note that reload already checks
+ that any register present is an address register, so
+ we just check for any register here. */
+ if (GET_CODE (op) == CONST_INT)
+ {
+ offset = INTVAL (op);
+ op = NULL_RTX;
+ }
+ if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
+ {
+ offset = INTVAL (XEXP (op, 1));
+ op = XEXP (op, 0);
+ }
+ while (op && GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ if (op && GET_CODE (op) != REG)
+ return false;
+
+ /* Unfortunately we have to reject constants that are invalid
+ for an address, or else reload will get confused. */
+ if (!DISP_IN_RANGE (offset))
+ return false;
+
+ return true;
+})
+
+;; Return true if OP a valid operand for the LARL instruction.
+
+(define_predicate "larl_operand"
+ (match_code "label_ref, symbol_ref, const, const_int, const_double")
+{
+ /* Allow labels and local symbols. */
+ if (GET_CODE (op) == LABEL_REF)
+ return true;
+ if (GET_CODE (op) == SYMBOL_REF)
+ return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
+ && SYMBOL_REF_TLS_MODEL (op) == 0
+ && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
+
+ /* Everything else must have a CONST, so strip it. */
+ if (GET_CODE (op) != CONST)
+ return false;
+ op = XEXP (op, 0);
+
+ /* Allow adding *even* in-range constants. */
+ if (GET_CODE (op) == PLUS)
+ {
+ if (GET_CODE (XEXP (op, 1)) != CONST_INT
+ || (INTVAL (XEXP (op, 1)) & 1) != 0)
+ return false;
+ if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 32
+ || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 32))
+ return false;
+ op = XEXP (op, 0);
+ }
+
+ /* Labels and local symbols allowed here as well. */
+ if (GET_CODE (op) == LABEL_REF)
+ return true;
+ if (GET_CODE (op) == SYMBOL_REF)
+ return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
+ && SYMBOL_REF_TLS_MODEL (op) == 0
+ && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
+
+ /* Now we must have a @GOTENT offset or @PLT stub
+ or an @INDNTPOFF TLS offset. */
+ if (GET_CODE (op) == UNSPEC
+ && XINT (op, 1) == UNSPEC_GOTENT)
+ return true;
+ if (GET_CODE (op) == UNSPEC
+ && XINT (op, 1) == UNSPEC_PLT)
+ return true;
+ if (GET_CODE (op) == UNSPEC
+ && XINT (op, 1) == UNSPEC_INDNTPOFF)
+ return true;
+
+ return false;
+})
+
+;; operators --------------------------------------------------------------
+
+;; Return nonzero if OP is a valid comparison operator
+;; for a branch condition.
+
+(define_predicate "s390_comparison"
+ (match_code "eq, ne, lt, gt, le, ge, ltu, gtu, leu, geu,
+ uneq, unlt, ungt, unle, unge, ltgt,
+ unordered, ordered")
+{
+ if (GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM
+ || XEXP (op, 1) != const0_rtx)
+ return false;
+
+ return (s390_branch_condition_mask (op) >= 0);
+})
+
+;; Return nonzero if OP is a valid comparison operator
+;; for an ALC condition.
+
+(define_predicate "s390_alc_comparison"
+ (match_code "zero_extend, sign_extend, ltu, gtu, leu, geu")
+{
+ while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
+ op = XEXP (op, 0);
+
+ if (!COMPARISON_P (op))
+ return false;
+
+ if (GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM
+ || XEXP (op, 1) != const0_rtx)
+ return false;
+
+ switch (GET_MODE (XEXP (op, 0)))
+ {
+ case CCL1mode:
+ return GET_CODE (op) == LTU;
+
+ case CCL2mode:
+ return GET_CODE (op) == LEU;
+
+ case CCL3mode:
+ return GET_CODE (op) == GEU;
+
+ case CCUmode:
+ return GET_CODE (op) == GTU;
+
+ case CCURmode:
+ return GET_CODE (op) == LTU;
+
+ case CCSmode:
+ return GET_CODE (op) == UNGT;
+
+ case CCSRmode:
+ return GET_CODE (op) == UNLT;
+
+ default:
+ return false;
+ }
+})
+
+;; Return nonzero if OP is a valid comparison operator
+;; for an SLB condition.
+
+(define_predicate "s390_slb_comparison"
+ (match_code "zero_extend, sign_extend, ltu, gtu, leu, geu")
+{
+ while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
+ op = XEXP (op, 0);
+
+ if (!COMPARISON_P (op))
+ return false;
+
+ if (GET_CODE (XEXP (op, 0)) != REG
+ || REGNO (XEXP (op, 0)) != CC_REGNUM
+ || XEXP (op, 1) != const0_rtx)
+ return false;
+
+ switch (GET_MODE (XEXP (op, 0)))
+ {
+ case CCL1mode:
+ return GET_CODE (op) == GEU;
+
+ case CCL2mode:
+ return GET_CODE (op) == GTU;
+
+ case CCL3mode:
+ return GET_CODE (op) == LTU;
+
+ case CCUmode:
+ return GET_CODE (op) == LEU;
+
+ case CCURmode:
+ return GET_CODE (op) == GEU;
+
+ case CCSmode:
+ return GET_CODE (op) == LE;
+
+ case CCSRmode:
+ return GET_CODE (op) == GE;
+
+ default:
+ return false;
+ }
+})
+
+;; Return true if OP is a load multiple operation. It is known to be a
+;; PARALLEL and the first section will be tested.
+
+(define_special_predicate "load_multiple_operation"
+ (match_code "parallel")
+{
+ enum machine_mode elt_mode;
+ int count = XVECLEN (op, 0);
+ unsigned int dest_regno;
+ rtx src_addr;
+ int i, off;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+ return false;
+
+ dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+ src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+ elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
+
+ /* Check, is base, or base + displacement. */
+
+ if (GET_CODE (src_addr) == REG)
+ off = 0;
+ else if (GET_CODE (src_addr) == PLUS
+ && GET_CODE (XEXP (src_addr, 0)) == REG
+ && GET_CODE (XEXP (src_addr, 1)) == CONST_INT)
+ {
+ off = INTVAL (XEXP (src_addr, 1));
+ src_addr = XEXP (src_addr, 0);
+ }
+ else
+ return false;
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_DEST (elt)) != REG
+ || GET_MODE (SET_DEST (elt)) != elt_mode
+ || REGNO (SET_DEST (elt)) != dest_regno + i
+ || GET_CODE (SET_SRC (elt)) != MEM
+ || GET_MODE (SET_SRC (elt)) != elt_mode
+ || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+ || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
+ != off + i * GET_MODE_SIZE (elt_mode))
+ return false;
+ }
+
+ return true;
+})
+
+;; Return true if OP is a store multiple operation. It is known to be a
+;; PARALLEL and the first section will be tested.
+
+(define_special_predicate "store_multiple_operation"
+ (match_code "parallel")
+{
+ enum machine_mode elt_mode;
+ int count = XVECLEN (op, 0);
+ unsigned int src_regno;
+ rtx dest_addr;
+ int i, off;
+
+ /* Perform a quick check so we don't blow up below. */
+ if (count <= 1
+ || GET_CODE (XVECEXP (op, 0, 0)) != SET
+ || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
+ || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
+ return false;
+
+ src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
+ dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
+ elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
+
+ /* Check, is base, or base + displacement. */
+
+ if (GET_CODE (dest_addr) == REG)
+ off = 0;
+ else if (GET_CODE (dest_addr) == PLUS
+ && GET_CODE (XEXP (dest_addr, 0)) == REG
+ && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
+ {
+ off = INTVAL (XEXP (dest_addr, 1));
+ dest_addr = XEXP (dest_addr, 0);
+ }
+ else
+ return false;
+
+ for (i = 1; i < count; i++)
+ {
+ rtx elt = XVECEXP (op, 0, i);
+
+ if (GET_CODE (elt) != SET
+ || GET_CODE (SET_SRC (elt)) != REG
+ || GET_MODE (SET_SRC (elt)) != elt_mode
+ || REGNO (SET_SRC (elt)) != src_regno + i
+ || GET_CODE (SET_DEST (elt)) != MEM
+ || GET_MODE (SET_DEST (elt)) != elt_mode
+ || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
+ || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
+ || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
+ || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
+ != off + i * GET_MODE_SIZE (elt_mode))
+ return false;
+ }
+ return true;
+})
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index 25aeef86991..e8f94efe3e3 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -33,14 +33,6 @@ extern void s390_conditional_register_usage (void);
#ifdef RTX_CODE
extern int s390_extra_constraint_str (rtx, int, const char *);
extern int s390_const_ok_for_constraint_p (HOST_WIDE_INT, int, const char *);
-extern int const0_operand (rtx, enum machine_mode);
-extern int consttable_operand (rtx, enum machine_mode);
-extern int larl_operand (rtx, enum machine_mode);
-extern int s_operand (rtx, enum machine_mode);
-extern int shift_count_operand (rtx, enum machine_mode);
-extern int bras_sym_operand (rtx, enum machine_mode);
-extern int load_multiple_operation (rtx, enum machine_mode);
-extern int store_multiple_operation (rtx, enum machine_mode);
extern int s390_single_part (rtx, enum machine_mode, enum machine_mode, int);
extern unsigned HOST_WIDE_INT s390_extract_part (rtx, enum machine_mode, int);
extern bool s390_split_ok_p (rtx, rtx, enum machine_mode, int);
@@ -51,9 +43,6 @@ extern int s390_match_ccmode (rtx, enum machine_mode);
extern enum machine_mode s390_tm_ccmode (rtx, rtx, int);
extern enum machine_mode s390_select_ccmode (enum rtx_code, rtx, rtx);
extern void s390_canonicalize_comparison (enum rtx_code *, rtx *, rtx *);
-extern int s390_comparison (rtx op, enum machine_mode mode);
-extern int s390_alc_comparison (rtx op, enum machine_mode mode);
-extern int s390_slb_comparison (rtx op, enum machine_mode mode);
extern rtx s390_emit_compare (enum rtx_code, rtx, rtx);
extern void s390_emit_jump (rtx, rtx);
extern int symbolic_reference_mentioned_p (rtx);
@@ -74,7 +63,6 @@ extern enum reg_class s390_secondary_input_reload_class (enum reg_class,
extern enum reg_class s390_secondary_output_reload_class (enum reg_class,
enum machine_mode,
rtx);
-extern int s390_plus_operand (rtx, enum machine_mode);
extern void s390_expand_plus_operand (rtx, rtx, rtx);
extern void emit_symbolic_move (rtx *);
extern void s390_load_address (rtx, rtx);
@@ -103,6 +91,8 @@ extern void s390_output_dwarf_dtprel (FILE*, int, rtx);
extern int s390_agen_dep_p (rtx, rtx);
extern rtx s390_load_got (void);
extern void s390_emit_tpf_eh_return (rtx);
+extern bool s390_legitimate_address_without_index_p (rtx);
+extern int s390_branch_condition_mask (rtx);
#endif /* RTX_CODE */
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 90919e36d53..8bbe3f59ebc 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -52,9 +52,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "optabs.h"
#include "tree-gimple.h"
-/* Machine-specific symbol_ref flags. */
-#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0)
-
static bool s390_assemble_integer (rtx, unsigned int, int);
static void s390_encode_section_info (tree, rtx, int);
@@ -380,9 +377,7 @@ struct machine_function GTY(())
(1 << (BITNUM))))
static int s390_match_ccmode_set (rtx, enum machine_mode);
-static int s390_branch_condition_mask (rtx);
static const char *s390_branch_condition_mnemonic (rtx, int);
-static int check_mode (rtx, enum machine_mode *);
static int s390_short_displacement (rtx);
static int s390_decompose_address (rtx, struct s390_address *);
static rtx get_thread_pointer (void);
@@ -413,10 +408,20 @@ static int s390_function_arg_size (enum machine_mode, tree);
static bool s390_function_arg_float (enum machine_mode, tree);
static struct machine_function * s390_init_machine_status (void);
-/* Check whether integer displacement is in range. */
-#define DISP_IN_RANGE(d) \
- (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \
- : ((d) >= 0 && (d) <= 4095))
+/* Return true if CODE is a valid address without index. */
+
+bool
+s390_legitimate_address_without_index_p (rtx op)
+{
+ struct s390_address addr;
+
+ if (!s390_decompose_address (XEXP (op, 0), &addr))
+ return false;
+ if (addr.indx)
+ return false;
+
+ return true;
+}
/* Return true if SET either doesn't set the CC register, or else
the source and destination have matching CC modes and that
@@ -791,126 +796,10 @@ s390_emit_jump (rtx target, rtx cond)
emit_jump_insn (insn);
}
-/* Return nonzero if OP is a valid comparison operator
- for a branch condition in mode MODE. */
-
-int
-s390_comparison (rtx op, enum machine_mode mode)
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- if (!COMPARISON_P (op))
- return 0;
-
- if (GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM
- || XEXP (op, 1) != const0_rtx)
- return 0;
-
- return s390_branch_condition_mask (op) >= 0;
-}
-
-/* Return nonzero if OP is a valid comparison operator
- for an ALC condition in mode MODE. */
-
-int
-s390_alc_comparison (rtx op, enum machine_mode mode)
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
- op = XEXP (op, 0);
-
- if (!COMPARISON_P (op))
- return 0;
-
- if (GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM
- || XEXP (op, 1) != const0_rtx)
- return 0;
-
- switch (GET_MODE (XEXP (op, 0)))
- {
- case CCL1mode:
- return GET_CODE (op) == LTU;
-
- case CCL2mode:
- return GET_CODE (op) == LEU;
-
- case CCL3mode:
- return GET_CODE (op) == GEU;
-
- case CCUmode:
- return GET_CODE (op) == GTU;
-
- case CCURmode:
- return GET_CODE (op) == LTU;
-
- case CCSmode:
- return GET_CODE (op) == UNGT;
-
- case CCSRmode:
- return GET_CODE (op) == UNLT;
-
- default:
- return 0;
- }
-}
-
-/* Return nonzero if OP is a valid comparison operator
- for an SLB condition in mode MODE. */
-
-int
-s390_slb_comparison (rtx op, enum machine_mode mode)
-{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- while (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == SIGN_EXTEND)
- op = XEXP (op, 0);
-
- if (!COMPARISON_P (op))
- return 0;
-
- if (GET_CODE (XEXP (op, 0)) != REG
- || REGNO (XEXP (op, 0)) != CC_REGNUM
- || XEXP (op, 1) != const0_rtx)
- return 0;
-
- switch (GET_MODE (XEXP (op, 0)))
- {
- case CCL1mode:
- return GET_CODE (op) == GEU;
-
- case CCL2mode:
- return GET_CODE (op) == GTU;
-
- case CCL3mode:
- return GET_CODE (op) == LTU;
-
- case CCUmode:
- return GET_CODE (op) == LEU;
-
- case CCURmode:
- return GET_CODE (op) == GEU;
-
- case CCSmode:
- return GET_CODE (op) == LE;
-
- case CCSRmode:
- return GET_CODE (op) == GE;
-
- default:
- return 0;
- }
-}
-
/* Return branch condition mask to implement a branch
specified by CODE. Return -1 for invalid comparisons. */
-static int
+int
s390_branch_condition_mask (rtx code)
{
const int CC0 = 1 << 3;
@@ -1508,172 +1397,6 @@ s390_safe_attr_type (rtx insn)
return TYPE_NONE;
}
-/* Return true if OP a (const_int 0) operand.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-const0_operand (register rtx op, enum machine_mode mode)
-{
- return op == CONST0_RTX (mode);
-}
-
-/* Return true if OP is constant.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-consttable_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return CONSTANT_P (op);
-}
-
-/* Return true if the mode of operand OP matches MODE.
- If MODE is set to VOIDmode, set it to the mode of OP. */
-
-static int
-check_mode (register rtx op, enum machine_mode *mode)
-{
- if (*mode == VOIDmode)
- *mode = GET_MODE (op);
- else
- {
- if (GET_MODE (op) != VOIDmode && GET_MODE (op) != *mode)
- return 0;
- }
- return 1;
-}
-
-/* Return true if OP a valid operand for the LARL instruction.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-larl_operand (register rtx op, enum machine_mode mode)
-{
- if (! check_mode (op, &mode))
- return 0;
-
- /* Allow labels and local symbols. */
- if (GET_CODE (op) == LABEL_REF)
- return 1;
- if (GET_CODE (op) == SYMBOL_REF)
- return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
- && SYMBOL_REF_TLS_MODEL (op) == 0
- && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
-
- /* Everything else must have a CONST, so strip it. */
- if (GET_CODE (op) != CONST)
- return 0;
- op = XEXP (op, 0);
-
- /* Allow adding *even* in-range constants. */
- if (GET_CODE (op) == PLUS)
- {
- if (GET_CODE (XEXP (op, 1)) != CONST_INT
- || (INTVAL (XEXP (op, 1)) & 1) != 0)
- return 0;
-#if HOST_BITS_PER_WIDE_INT > 32
- if (INTVAL (XEXP (op, 1)) >= (HOST_WIDE_INT)1 << 32
- || INTVAL (XEXP (op, 1)) < -((HOST_WIDE_INT)1 << 32))
- return 0;
-#endif
- op = XEXP (op, 0);
- }
-
- /* Labels and local symbols allowed here as well. */
- if (GET_CODE (op) == LABEL_REF)
- return 1;
- if (GET_CODE (op) == SYMBOL_REF)
- return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0
- && SYMBOL_REF_TLS_MODEL (op) == 0
- && (!flag_pic || SYMBOL_REF_LOCAL_P (op)));
-
- /* Now we must have a @GOTENT offset or @PLT stub
- or an @INDNTPOFF TLS offset. */
- if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_GOTENT)
- return 1;
- if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_PLT)
- return 1;
- if (GET_CODE (op) == UNSPEC
- && XINT (op, 1) == UNSPEC_INDNTPOFF)
- return 1;
-
- return 0;
-}
-
-/* Return true if OP is a valid S-type operand.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-s_operand (rtx op, enum machine_mode mode)
-{
- struct s390_address addr;
-
- /* Call general_operand first, so that we don't have to
- check for many special cases. */
- if (!general_operand (op, mode))
- return 0;
-
- /* Just like memory_operand, allow (subreg (mem ...))
- after reload. */
- if (reload_completed
- && GET_CODE (op) == SUBREG
- && GET_CODE (SUBREG_REG (op)) == MEM)
- op = SUBREG_REG (op);
-
- if (GET_CODE (op) != MEM)
- return 0;
- if (!s390_decompose_address (XEXP (op, 0), &addr))
- return 0;
- if (addr.indx)
- return 0;
-
- return 1;
-}
-
-/* Return true if OP a valid shift count operand.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-shift_count_operand (rtx op, enum machine_mode mode)
-{
- HOST_WIDE_INT offset = 0;
-
- if (! check_mode (op, &mode))
- return 0;
-
- /* We can have an integer constant, an address register,
- or a sum of the two. Note that reload already checks
- that any register present is an address register, so
- we just check for any register here. */
- if (GET_CODE (op) == CONST_INT)
- {
- offset = INTVAL (op);
- op = NULL_RTX;
- }
- if (op && GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
- {
- offset = INTVAL (XEXP (op, 1));
- op = XEXP (op, 0);
- }
- while (op && GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- if (op && GET_CODE (op) != REG)
- return 0;
-
- /* Unfortunately we have to reject constants that are invalid
- for an address, or else reload will get confused. */
- if (!DISP_IN_RANGE (offset))
- return 0;
-
- return 1;
-}
-
/* Return true if DISP is a valid short displacement. */
static int
@@ -2112,27 +1835,6 @@ s390_address_cost (rtx addr)
return ad.indx? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (1);
}
-/* Return true if OP is a valid operand for the BRAS instruction.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-bras_sym_operand (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- register enum rtx_code code = GET_CODE (op);
-
- /* Allow SYMBOL_REFs. */
- if (code == SYMBOL_REF)
- return 1;
-
- /* Allow @PLT stubs. */
- if (code == CONST
- && GET_CODE (XEXP (op, 0)) == UNSPEC
- && XINT (XEXP (op, 0), 1) == UNSPEC_PLT)
- return 1;
- return 0;
-}
-
/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
otherwise return 0. */
@@ -2144,126 +1846,6 @@ tls_symbolic_operand (register rtx op)
return SYMBOL_REF_TLS_MODEL (op);
}
-/* Return true if OP is a load multiple operation. It is known to be a
- PARALLEL and the first section will be tested.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum machine_mode elt_mode;
- int count = XVECLEN (op, 0);
- unsigned int dest_regno;
- rtx src_addr;
- int i, off;
-
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
- return 0;
-
- dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
- src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
- elt_mode = GET_MODE (SET_DEST (XVECEXP (op, 0, 0)));
-
- /* Check, is base, or base + displacement. */
-
- if (GET_CODE (src_addr) == REG)
- off = 0;
- else if (GET_CODE (src_addr) == PLUS
- && GET_CODE (XEXP (src_addr, 0)) == REG
- && GET_CODE (XEXP (src_addr, 1)) == CONST_INT)
- {
- off = INTVAL (XEXP (src_addr, 1));
- src_addr = XEXP (src_addr, 0);
- }
- else
- return 0;
-
- for (i = 1; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_DEST (elt)) != REG
- || GET_MODE (SET_DEST (elt)) != elt_mode
- || REGNO (SET_DEST (elt)) != dest_regno + i
- || GET_CODE (SET_SRC (elt)) != MEM
- || GET_MODE (SET_SRC (elt)) != elt_mode
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
- || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1))
- != off + i * GET_MODE_SIZE (elt_mode))
- return 0;
- }
-
- return 1;
-}
-
-/* Return true if OP is a store multiple operation. It is known to be a
- PARALLEL and the first section will be tested.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum machine_mode elt_mode;
- int count = XVECLEN (op, 0);
- unsigned int src_regno;
- rtx dest_addr;
- int i, off;
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
- return 0;
-
- src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
- dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
- elt_mode = GET_MODE (SET_SRC (XVECEXP (op, 0, 0)));
-
- /* Check, is base, or base + displacement. */
-
- if (GET_CODE (dest_addr) == REG)
- off = 0;
- else if (GET_CODE (dest_addr) == PLUS
- && GET_CODE (XEXP (dest_addr, 0)) == REG
- && GET_CODE (XEXP (dest_addr, 1)) == CONST_INT)
- {
- off = INTVAL (XEXP (dest_addr, 1));
- dest_addr = XEXP (dest_addr, 0);
- }
- else
- return 0;
-
- for (i = 1; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_SRC (elt)) != REG
- || GET_MODE (SET_SRC (elt)) != elt_mode
- || REGNO (SET_SRC (elt)) != src_regno + i
- || GET_CODE (SET_DEST (elt)) != MEM
- || GET_MODE (SET_DEST (elt)) != elt_mode
- || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
- || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1))
- != off + i * GET_MODE_SIZE (elt_mode))
- return 0;
- }
- return 1;
-}
-
/* Split DImode access register reference REG (on 64-bit) into its constituent
low and high parts, and store them into LO and HI. Note that gen_lowpart/
gen_highpart cannot be used as they assume all registers are word-sized,
@@ -2570,26 +2152,6 @@ s390_secondary_output_reload_class (enum reg_class class,
return NO_REGS;
}
-/* Return true if OP is a PLUS that is not a legitimate
- operand for the LA instruction.
- OP is the current operation.
- MODE is the current operation mode. */
-
-int
-s390_plus_operand (register rtx op, enum machine_mode mode)
-{
- if (!check_mode (op, &mode) || mode != Pmode)
- return FALSE;
-
- if (GET_CODE (op) != PLUS)
- return FALSE;
-
- if (legitimate_la_operand_p (op))
- return FALSE;
-
- return TRUE;
-}
-
/* Generate code to load SRC, which is PLUS that is not a
legitimate operand for the LA instruction, into TARGET.
SCRATCH may be used as scratch register. */
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index a6b7a3afd51..af09184ce63 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -1043,26 +1043,6 @@ do { \
/* Miscellaneous parameters. */
-/* Define the codes that are matched by predicates in aux-output.c. */
-#define PREDICATE_CODES \
- {"s_operand", { SUBREG, MEM }}, \
- {"shift_count_operand", { REG, SUBREG, PLUS, CONST_INT }}, \
- {"bras_sym_operand",{ SYMBOL_REF, CONST }}, \
- {"larl_operand", { SYMBOL_REF, CONST, CONST_INT, CONST_DOUBLE }}, \
- {"load_multiple_operation", {PARALLEL}}, \
- {"store_multiple_operation", {PARALLEL}}, \
- {"const0_operand", { CONST_INT, CONST_DOUBLE }}, \
- {"consttable_operand", { SYMBOL_REF, LABEL_REF, CONST, \
- CONST_INT, CONST_DOUBLE }}, \
- {"s390_plus_operand", { PLUS }}, \
- {"s390_comparison", { EQ, NE, LT, GT, LE, GE, LTU, GTU, LEU, GEU, \
- UNEQ, UNLT, UNGT, UNLE, UNGE, LTGT, \
- UNORDERED, ORDERED }}, \
- {"s390_alc_comparison", { ZERO_EXTEND, SIGN_EXTEND, \
- LTU, GTU, LEU, GEU }}, \
- {"s390_slb_comparison", { ZERO_EXTEND, SIGN_EXTEND, \
- LTU, GTU, LEU, GEU }},
-
/* Specify the machine mode that this machine uses for the index in the
tablejump instruction. */
#define CASE_VECTOR_MODE (TARGET_64BIT ? DImode : SImode)
@@ -1083,4 +1063,12 @@ do { \
indexing purposes) so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
+/* Machine-specific symbol_ref flags. */
+#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0)
+
+/* Check whether integer displacement is in range. */
+#define DISP_IN_RANGE(d) \
+ (TARGET_LONG_DISPLACEMENT? ((d) >= -524288 && (d) <= 524287) \
+ : ((d) >= 0 && (d) <= 4095))
+
#endif
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 4c779c34180..022d7791bba 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -229,6 +229,9 @@
;; Pipeline description for z990.
(include "2084.md")
+;; Predicates
+(include "predicates.md")
+
;;
;;- Compare instructions.
;;