diff options
author | uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-04-04 16:25:05 +0000 |
---|---|---|
committer | uweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-04-04 16:25:05 +0000 |
commit | 8cc5de337939c46dd2a1f98ad62daac8fd4d1899 (patch) | |
tree | c567b05d0418a1b19ea35e3f8c7e67c652e4e2ae /gcc/config/s390 | |
parent | 34882fefeb29d8356b0bb17802e26e097ed65688 (diff) | |
download | gcc-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.md | 386 | ||||
-rw-r--r-- | gcc/config/s390/s390-protos.h | 14 | ||||
-rw-r--r-- | gcc/config/s390/s390.c | 468 | ||||
-rw-r--r-- | gcc/config/s390/s390.h | 28 | ||||
-rw-r--r-- | gcc/config/s390/s390.md | 3 |
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. ;; |