From 963fc8d00baeca7920bc49e5defc53e290495d85 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Wed, 28 May 2008 14:11:19 +0000 Subject: [PATCH] constraints.md ('b', [...]): New constraint letters defined. 2008-05-28 Andreas Krebbel * config/s390/constraints.md ('b', 'C', 'D', 'e'): New constraint letters defined. * config/s390/s390.c (s390_compare_and_branch_condition_mask, s390_contiguous_bitmask_p, s390_symref_operand_p, s390_check_symref_alignment, s390_reload_larl_operand, s390_reload_symref_address): New functions. (s390_branch_condition_mnemonic): Support compare and branch instructions. (s390_mem_constraint): Avoid symrefs to accepted by the 'T' and 'W' constraints. (s390_secondary_reload): Add secondary reloads for unaligned symbol refs or symbol refs to floating point or QI/TI mode integer values. (legitimate_address_p): Accept symbol references as addresses. (s390_expand_insv): Use rotate and insert selected bits instruction for insv when building for z10. (print_operand_address): Handle symbol ref addresses. (print_operand): Output modifier 'c' added for signed byte values. (s390_encode_section_info): Mark symbol refs with SYMBOL_FLAG_NOT_NATURALLY_ALIGNED if appropriate. * config/s390/s390.md (SIL,RRS,RIS): New instruction formats added. (length attribute): RRF, RRR have 4 byte length. (FPALL, INTALL): New mode iterators added. (*tstdi_sign, *cmpdi_ccs_sign, *cmpsi_ccs_sign, *cmp_ccs, *cmpdi_ccu_zero, *cmpdi_ccu, *cmpsi_ccu, *cmphi_ccu, *movdi_64, *movsi_zarch, *movhi, movmem, *movmem_short, *extendsidi2, *extendhidi2_extimm, *extendhisi2_extimm, *zero_extendsidi2, adddi3, *adddi3_31z, *adddi3_31, addsi3, *add3, *add3_carry1_cc, *add3_carry2_cc, *add3_cc, *add3_imm_cc, *muldi3_sign, muldi3, *mulsi3_sign, mulsi3, mulsidi3): Patterns enhanced with z10 instructions. (*cmphi_ccs_z10, *cmpdi_ccs_signhi_rl, *cmpsi_ccu_zerohi_rlsi, *cmp_ccu_zerohi_rldi, *cmp_and_br_signed_, *cmp_and_br_unsigned_, reload_tomem_z10, reload_toreg_z10, reload_tomem_z10, reload_toreg_z10, reload_larl_odd_addend_z10, *execute_rl, *insv_z10, *insv_z10_noshift, *insv_or_z10_noshift, *zero_extendhi2_z10, *cmp_and_trap_signed_int, *cmp_and_trap_unsigned_int, prefetch): New pattern or expander definition. (movmem, clrmem, cmpmem): New splitters added. * config/s390/predicates.md (larl_operand): Use SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1 replaced with SYMBOL_REF_ALIGN1_P. (s390_signed_integer_comparison, s390_unsigned_integer_comparison): New predicates. * config/s390/s390-protos.h (s390_check_symref_alignment, s390_contiguous_bitmask_p, s390_reload_larl_operand, s390_reload_symref_address, s390_compare_and_branch_condition_mask): Prototypes added. * config/s390/s390.h (TARGET_MEM_CONSTRAINT, SYMBOL_REF_ALIGN1_P, SYMBOL_FLAG_NOT_NATURALLY_ALIGNED, SYMBOL_REF_NOT_NATURALLY_ALIGNED_P): Macro definition added. From-SVN: r136098 --- gcc/ChangeLog | 65 +++ gcc/config/s390/constraints.md | 43 +- gcc/config/s390/predicates.md | 16 +- gcc/config/s390/s390-protos.h | 10 +- gcc/config/s390/s390.c | 375 +++++++++++++++- gcc/config/s390/s390.h | 32 +- gcc/config/s390/s390.md | 769 ++++++++++++++++++++++++++------- 7 files changed, 1119 insertions(+), 191 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a538ccde668..a64b0b01185 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,68 @@ +2008-05-28 Andreas Krebbel + + * config/s390/constraints.md ('b', 'C', 'D', 'e'): New constraint + letters defined. + + * config/s390/s390.c (s390_compare_and_branch_condition_mask, + s390_contiguous_bitmask_p, s390_symref_operand_p, + s390_check_symref_alignment, s390_reload_larl_operand, + s390_reload_symref_address): New functions. + (s390_branch_condition_mnemonic): Support compare and branch + instructions. + (s390_mem_constraint): Avoid symrefs to accepted by the 'T' + and 'W' constraints. + (s390_secondary_reload): Add secondary reloads for unaligned + symbol refs or symbol refs to floating point or QI/TI mode + integer values. + (legitimate_address_p): Accept symbol references as addresses. + (s390_expand_insv): Use rotate and insert selected bits + instruction for insv when building for z10. + (print_operand_address): Handle symbol ref addresses. + (print_operand): Output modifier 'c' added for signed byte + values. + (s390_encode_section_info): Mark symbol refs with + SYMBOL_FLAG_NOT_NATURALLY_ALIGNED if appropriate. + + * config/s390/s390.md (SIL,RRS,RIS): New instruction formats added. + (length attribute): RRF, RRR have 4 byte length. + (FPALL, INTALL): New mode iterators added. + (*tstdi_sign, *cmpdi_ccs_sign, *cmpsi_ccs_sign, + *cmp_ccs, *cmpdi_ccu_zero, *cmpdi_ccu, *cmpsi_ccu, *cmphi_ccu, + *movdi_64, *movsi_zarch, *movhi, movmem, *movmem_short, + *extendsidi2, *extendhidi2_extimm, *extendhisi2_extimm, + *zero_extendsidi2, adddi3, *adddi3_31z, *adddi3_31, addsi3, + *add3, *add3_carry1_cc, *add3_carry2_cc, + *add3_cc, *add3_imm_cc, *muldi3_sign, muldi3, + *mulsi3_sign, mulsi3, mulsidi3): Patterns enhanced with z10 + instructions. + (*cmphi_ccs_z10, *cmpdi_ccs_signhi_rl, *cmpsi_ccu_zerohi_rlsi, + *cmp_ccu_zerohi_rldi, *cmp_and_br_signed_, + *cmp_and_br_unsigned_, reload_tomem_z10, + reload_toreg_z10, + reload_tomem_z10, + reload_toreg_z10, + reload_larl_odd_addend_z10, *execute_rl, *insv_z10, + *insv_z10_noshift, *insv_or_z10_noshift, + *zero_extendhi2_z10, *cmp_and_trap_signed_int, + *cmp_and_trap_unsigned_int, prefetch): New pattern or expander + definition. + (movmem, clrmem, cmpmem): New splitters added. + + * config/s390/predicates.md (larl_operand): Use + SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1 replaced with + SYMBOL_REF_ALIGN1_P. + (s390_signed_integer_comparison, + s390_unsigned_integer_comparison): New predicates. + + * config/s390/s390-protos.h (s390_check_symref_alignment, + s390_contiguous_bitmask_p, s390_reload_larl_operand, + s390_reload_symref_address, + s390_compare_and_branch_condition_mask): Prototypes added. + + * config/s390/s390.h (TARGET_MEM_CONSTRAINT, + SYMBOL_REF_ALIGN1_P, SYMBOL_FLAG_NOT_NATURALLY_ALIGNED, + SYMBOL_REF_NOT_NATURALLY_ALIGNED_P): Macro definition added. + 2008-05-28 Andreas Krebbel * config/s390/s390.c (z10_cost): New cost function for z10. diff --git a/gcc/config/s390/constraints.md b/gcc/config/s390/constraints.md index 92fd3254ca5..ad953080ff1 100644 --- a/gcc/config/s390/constraints.md +++ b/gcc/config/s390/constraints.md @@ -1,5 +1,5 @@ ;; Constraints definitions belonging to the gcc backend for IBM S/390. -;; Copyright (C) 2006, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc. ;; Written by Wolfgang Gellerich, using code and information found in ;; files s390.md, s390.h, and s390.c. ;; @@ -24,10 +24,14 @@ ;; Special constraints for s/390 machine description: ;; ;; a -- Any address register from 1 to 15. +;; b -- Memory operand whose address is a symbol reference or a symbol +;; reference + constant which can be proven to be naturally aligned. ;; c -- Condition code register 33. ;; d -- Any register from 0 to 15. ;; f -- Floating point registers. ;; t -- Access registers 36 and 37. +;; C -- A signed 8-bit constant (-128..127) +;; D -- An unsigned 16-bit constant (0..65535) ;; G -- Const double zero operand ;; I -- An 8-bit constant (0..255). ;; J -- A 12-bit constant (0..4095). @@ -102,6 +106,19 @@ ;; General constraints for constants. ;; +(define_constraint "C" + "@internal + An 8-bit signed immediate constant (-128..127)" + (and (match_code "const_int") + (match_test "ival >= -128 && ival <= 127"))) + + +(define_constraint "D" + "An unsigned 16-bit constant (0..65535)" + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 65535"))) + + (define_constraint "G" "@internal Const double zero operand" @@ -127,7 +144,6 @@ (match_test "ival >= -32768 && ival <= 32767"))) - (define_constraint "L" "Value appropriate as displacement. (0..4095) for short displacement @@ -355,7 +371,6 @@ (match_test "s390_mem_constraint (\"Q\", op)")) - (define_memory_constraint "R" "Memory reference with index register and short displacement" (match_test "s390_mem_constraint (\"R\", op)")) @@ -371,6 +386,27 @@ (match_test "s390_mem_constraint (\"T\", op)")) +(define_memory_constraint "b" + "Memory reference whose address is a naturally aligned symbol reference." + (match_test "MEM_P (op) + && s390_check_symref_alignment (XEXP (op, 0), + GET_MODE_SIZE (GET_MODE (op)))")) + +(define_memory_constraint "e" + "Matches all memory references available on the current architecture +level. This constraint will never be used and using it in an inline +assembly is *always* a bug since there is no instruction accepting all +those addresses. It just serves as a placeholder for a generic memory +constraint." + (match_test "legitimate_address_p (GET_MODE (op), op, 1)")) + +; This defines 'm' as normal memory constraint. This is only possible +; since the standard memory constraint is re-defined in s390.h using +; the TARGET_MEM_CONSTRAINT macro. +(define_memory_constraint "m" + "Matches the most general memory address for pre-z10 machines." + (match_test "s390_mem_constraint (\"R\", op) + || s390_mem_constraint (\"T\", op)")) (define_memory_constraint "AQ" "@internal @@ -425,7 +461,6 @@ (match_test "s390_mem_constraint (\"BT\", op)")) - (define_address_constraint "U" "Pointer with short displacement" (match_test "s390_mem_constraint (\"U\", op)")) diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md index 50bf0c1eda9..ca5d17556a5 100644 --- a/gcc/config/s390/predicates.md +++ b/gcc/config/s390/predicates.md @@ -1,5 +1,5 @@ ;; Predicate definitions for S/390 and zSeries. -;; Copyright (C) 2005, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc. ;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and ;; Ulrich Weigand (uweigand@de.ibm.com). ;; @@ -110,7 +110,7 @@ if (GET_CODE (op) == LABEL_REF) return true; if (GET_CODE (op) == SYMBOL_REF) - return ((SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_ALIGN1) == 0 + return (!SYMBOL_REF_ALIGN1_P (op) && SYMBOL_REF_TLS_MODEL (op) == 0 && (!flag_pic || SYMBOL_REF_LOCAL_P (op))); @@ -172,6 +172,18 @@ return (s390_branch_condition_mask (op) >= 0); }) +(define_predicate "s390_signed_integer_comparison" + (match_code "eq, ne, lt, gt, le, ge") +{ + return (s390_compare_and_branch_condition_mask (op) >= 0); +}) + +(define_predicate "s390_unsigned_integer_comparison" + (match_code "eq, ne, ltu, gtu, leu, geu") +{ + return (s390_compare_and_branch_condition_mask (op) >= 0); +}) + ;; Return nonzero if OP is a valid comparison operator ;; for an ALC condition. diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h index 7e329f2a565..76f73f9dd2c 100644 --- a/gcc/config/s390/s390-protos.h +++ b/gcc/config/s390/s390-protos.h @@ -1,5 +1,7 @@ /* Definitions of target machine for GNU compiler, for IBM S/390. - Copyright (C) 2000, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc. + Copyright (C) 2000, 2002, 2003, 2004, 2005, 2007, 2008 Free + Software Foundation, Inc. + Contributed by Hartmut Penner (hpenner@de.ibm.com) This file is part of GCC. @@ -27,7 +29,7 @@ extern int s390_mem_constraint (const char *str, rtx op); extern int s390_O_constraint_str (const char c, HOST_WIDE_INT value); extern int s390_N_constraint_str (const char *str, HOST_WIDE_INT value); extern int s390_float_const_zero_p (rtx value); - +extern bool s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment); /* Declare functions in s390.c. */ @@ -51,6 +53,7 @@ extern int s390_const_ok_for_constraint_p (HOST_WIDE_INT, int, const char *); extern int s390_const_double_ok_for_constraint_p (rtx, int, const char *); 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_contiguous_bitmask_p (unsigned HOST_WIDE_INT, int, int *, int *); extern bool s390_split_ok_p (rtx, rtx, enum machine_mode, int); extern bool s390_overlap_p (rtx, rtx, HOST_WIDE_INT); extern bool s390_offset_p (rtx, rtx, rtx); @@ -80,6 +83,8 @@ 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 void s390_reload_larl_operand (rtx , rtx , rtx); +extern void s390_reload_symref_address (rtx , rtx , rtx , bool); extern void s390_expand_plus_operand (rtx, rtx, rtx); extern void emit_symbolic_move (rtx *); extern void s390_load_address (rtx, rtx); @@ -113,6 +118,7 @@ extern void s390_emit_tpf_eh_return (rtx); extern bool s390_legitimate_address_without_index_p (rtx); extern bool s390_decompose_shift_count (rtx, rtx *, HOST_WIDE_INT *); extern int s390_branch_condition_mask (rtx); +extern int s390_compare_and_branch_condition_mask (rtx); #endif /* RTX_CODE */ diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 37660a25872..5ffbcaef338 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -1,8 +1,9 @@ /* Subroutines used for code generation on IBM S/390 and zSeries Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007 Free Software Foundation, Inc. + 2007, 2008 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and - Ulrich Weigand (uweigand@de.ibm.com). + Ulrich Weigand (uweigand@de.ibm.com) and + Andreas Krebbel (Andreas.Krebbel@de.ibm.com). This file is part of GCC. @@ -1061,6 +1062,41 @@ s390_branch_condition_mask (rtx code) } } + +/* Return branch condition mask to implement a compare and branch + specified by CODE. Return -1 for invalid comparisons. */ + +int +s390_compare_and_branch_condition_mask (rtx code) +{ + const int CC0 = 1 << 3; + const int CC1 = 1 << 2; + const int CC2 = 1 << 1; + + switch (GET_CODE (code)) + { + case EQ: + return CC0; + case NE: + return CC1 | CC2; + case LT: + case LTU: + return CC1; + case GT: + case GTU: + return CC2; + case LE: + case LEU: + return CC0 | CC1; + case GE: + case GEU: + return CC0 | CC2; + default: + gcc_unreachable (); + } + return -1; +} + /* If INV is false, return assembler mnemonic string to implement a branch specified by CODE. If INV is true, return mnemonic for the corresponding inverted branch. */ @@ -1068,6 +1104,8 @@ s390_branch_condition_mask (rtx code) static const char * s390_branch_condition_mnemonic (rtx code, int inv) { + int mask; + static const char *const mnemonic[16] = { NULL, "o", "h", "nle", @@ -1076,7 +1114,13 @@ s390_branch_condition_mnemonic (rtx code, int inv) "le", "nh", "no", NULL }; - int mask = s390_branch_condition_mask (code); + if (GET_CODE (XEXP (code, 0)) == REG + && REGNO (XEXP (code, 0)) == CC_REGNUM + && XEXP (code, 1) == const0_rtx) + mask = s390_branch_condition_mask (code); + else + mask = s390_compare_and_branch_condition_mask (code); + gcc_assert (mask >= 0); if (inv) @@ -1153,6 +1197,67 @@ s390_single_part (rtx op, return part == -1 ? -1 : n_parts - 1 - part; } +/* Return true if IN contains a contiguous bitfield in the lower SIZE + bits and no other bits are set in IN. POS and LENGTH can be used + to obtain the start position and the length of the bitfield. + + POS gives the position of the first bit of the bitfield counting + from the lowest order bit starting with zero. In order to use this + value for S/390 instructions this has to be converted to "bits big + endian" style. */ + +bool +s390_contiguous_bitmask_p (unsigned HOST_WIDE_INT in, int size, + int *pos, int *length) +{ + int tmp_pos = 0; + int tmp_length = 0; + int i; + unsigned HOST_WIDE_INT mask = 1ULL; + bool contiguous = false; + + for (i = 0; i < size; mask <<= 1, i++) + { + if (contiguous) + { + if (mask & in) + tmp_length++; + else + break; + } + else + { + if (mask & in) + { + contiguous = true; + tmp_length++; + } + else + tmp_pos++; + } + } + + if (!tmp_length) + return false; + + /* Calculate a mask for all bits beyond the contiguous bits. */ + mask = (-1LL & ~(((1ULL << (tmp_length + tmp_pos - 1)) << 1) - 1)); + + if (mask & in) + return false; + + if (tmp_length + tmp_pos - 1 > size) + return false; + + if (length) + *length = tmp_length; + + if (pos) + *pos = tmp_pos; + + return true; +} + /* Check whether we can (and want to) split a double-word move in mode MODE from SRC to DST into two single-word moves, moving the subword FIRST_SUBWORD first. */ @@ -2034,10 +2139,9 @@ s390_mem_constraint (const char *str, rtx op) return 0; if (GET_CODE (op) != MEM) return 0; - /* Any invalid address here will be fixed up by reload, - so accept it for the most generic constraint. */ - if (s390_decompose_address (XEXP (op, 0), &addr) - && s390_short_displacement (addr.disp)) + if (!s390_decompose_address (XEXP (op, 0), &addr)) + return 0; + if (s390_short_displacement (addr.disp)) return 0; break; @@ -2054,10 +2158,9 @@ s390_mem_constraint (const char *str, rtx op) case 'W': if (!TARGET_LONG_DISPLACEMENT) return 0; - /* Any invalid address here will be fixed up by reload, - so accept it for the most generic constraint. */ - if (s390_decompose_address (op, &addr) - && s390_short_displacement (addr.disp)) + if (!s390_decompose_address (op, &addr)) + return 0; + if (s390_short_displacement (addr.disp)) return 0; break; @@ -2693,6 +2796,132 @@ s390_preferred_reload_class (rtx op, enum reg_class class) return class; } +/* Return true if ADDR is of kind symbol_ref or symbol_ref + const_int + and return these parts in SYMREF and ADDEND. You can pass NULL in + SYMREF and/or ADDEND if you are not interested in these values. */ + +static bool +s390_symref_operand_p (rtx addr, rtx *symref, HOST_WIDE_INT *addend) +{ + HOST_WIDE_INT tmpaddend = 0; + + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + if (GET_CODE (addr) == PLUS) + { + if (GET_CODE (XEXP (addr, 0)) == SYMBOL_REF + && CONST_INT_P (XEXP (addr, 1))) + { + tmpaddend = INTVAL (XEXP (addr, 1)); + addr = XEXP (addr, 0); + } + else + return false; + } + else + if (GET_CODE (addr) != SYMBOL_REF) + return false; + + if (symref) + *symref = addr; + if (addend) + *addend = tmpaddend; + + return true; +} + +/* Return true if ADDR is SYMBOL_REF + addend with addend being a + multiple of ALIGNMENT and the SYMBOL_REF being naturally + aligned. */ + +bool +s390_check_symref_alignment (rtx addr, HOST_WIDE_INT alignment) +{ + HOST_WIDE_INT addend; + rtx symref; + + if (!s390_symref_operand_p (addr, &symref, &addend)) + return false; + + return (!SYMBOL_REF_NOT_NATURALLY_ALIGNED_P (symref) + && !(addend & (alignment - 1))); +} + +/* ADDR is moved into REG using larl. If ADDR isn't a valid larl + operand SCRATCH is used to reload the even part of the address and + adding one. */ + +void +s390_reload_larl_operand (rtx reg, rtx addr, rtx scratch) +{ + HOST_WIDE_INT addend; + rtx symref; + + if (!s390_symref_operand_p (addr, &symref, &addend)) + gcc_unreachable (); + + if (!(addend & 1)) + /* Easy case. The addend is even so larl will do fine. */ + emit_move_insn (reg, addr); + else + { + /* We can leave the scratch register untouched if the target + register is a valid base register. */ + if (REGNO (reg) < FIRST_PSEUDO_REGISTER + && REGNO_REG_CLASS (REGNO (reg)) == ADDR_REGS) + scratch = reg; + + gcc_assert (REGNO (scratch) < FIRST_PSEUDO_REGISTER); + gcc_assert (REGNO_REG_CLASS (REGNO (scratch)) == ADDR_REGS); + + if (addend != 1) + emit_move_insn (scratch, + gen_rtx_CONST (Pmode, + gen_rtx_PLUS (Pmode, symref, + GEN_INT (addend - 1)))); + else + emit_move_insn (scratch, symref); + + /* Increment the address using la in order to avoid clobbering cc. */ + emit_move_insn (reg, gen_rtx_PLUS (Pmode, scratch, const1_rtx)); + } +} + +/* Generate what is necessary to move between REG and MEM using + SCRATCH. The direction is given by TOMEM. */ + +void +s390_reload_symref_address (rtx reg, rtx mem, rtx scratch, bool tomem) +{ + /* Reload might have pulled a constant out of the literal pool. + Force it back in. */ + if (CONST_INT_P (mem) || GET_CODE (mem) == CONST_DOUBLE + || GET_CODE (mem) == CONST) + mem = force_const_mem (GET_MODE (reg), mem); + + gcc_assert (MEM_P (mem)); + + /* For a load from memory we can leave the scratch register + untouched if the target register is a valid base register. */ + if (!tomem + && REGNO (reg) < FIRST_PSEUDO_REGISTER + && REGNO_REG_CLASS (REGNO (reg)) == ADDR_REGS + && GET_MODE (reg) == GET_MODE (scratch)) + scratch = reg; + + /* Load address into scratch register. Since we can't have a + secondary reload for a secondary reload we have to cover the case + where larl would need a secondary reload here as well. */ + s390_reload_larl_operand (scratch, XEXP (mem, 0), scratch); + + /* Now we can use a standard load/store to do the move. */ + if (tomem) + emit_move_insn (replace_equiv_address (mem, scratch), reg); + else + emit_move_insn (reg, replace_equiv_address (mem, scratch)); +} + /* Inform reload about cases where moving X with a mode MODE to a register in CLASS requires an extra scratch or immediate register. Return the class needed for the immediate register. */ @@ -2705,6 +2934,60 @@ s390_secondary_reload (bool in_p, rtx x, enum reg_class class, if (reg_classes_intersect_p (CC_REGS, class)) return GENERAL_REGS; + if (TARGET_Z10) + { + /* On z10 several optimizer steps may generate larl operands with + an odd addend. */ + if (in_p + && s390_symref_operand_p (x, NULL, NULL) + && mode == Pmode + && !s390_check_symref_alignment (x, 2)) + sri->icode = ((mode == DImode) ? CODE_FOR_reloaddi_larl_odd_addend_z10 + : CODE_FOR_reloadsi_larl_odd_addend_z10); + + /* On z10 we need a scratch register when moving QI, TI or floating + point mode values from or to a memory location with a SYMBOL_REF + or if the symref addend of a SI or DI move is not aligned to the + width of the access. */ + if (MEM_P (x) + && s390_symref_operand_p (XEXP (x, 0), NULL, NULL) + && (mode == QImode || mode == TImode || FLOAT_MODE_P (mode) + || (!TARGET_64BIT && mode == DImode) + || ((mode == HImode || mode == SImode || mode == DImode) + && (!s390_check_symref_alignment (XEXP (x, 0), + GET_MODE_SIZE (mode)))))) + { +#define __SECONDARY_RELOAD_CASE(M,m) \ + case M##mode: \ + if (TARGET_64BIT) \ + sri->icode = in_p ? CODE_FOR_reload##m##di_toreg_z10 : \ + CODE_FOR_reload##m##di_tomem_z10; \ + else \ + sri->icode = in_p ? CODE_FOR_reload##m##si_toreg_z10 : \ + CODE_FOR_reload##m##si_tomem_z10; \ + break; + + switch (GET_MODE (x)) + { + __SECONDARY_RELOAD_CASE (QI, qi); + __SECONDARY_RELOAD_CASE (HI, hi); + __SECONDARY_RELOAD_CASE (SI, si); + __SECONDARY_RELOAD_CASE (DI, di); + __SECONDARY_RELOAD_CASE (TI, ti); + __SECONDARY_RELOAD_CASE (SF, sf); + __SECONDARY_RELOAD_CASE (DF, df); + __SECONDARY_RELOAD_CASE (TF, tf); + __SECONDARY_RELOAD_CASE (SD, sd); + __SECONDARY_RELOAD_CASE (DD, dd); + __SECONDARY_RELOAD_CASE (TD, td); + + default: + gcc_unreachable (); + } +#undef __SECONDARY_RELOAD_CASE + } + } + /* We need a scratch register when loading a PLUS expression which is not a legitimate operand of the LOAD ADDRESS instruction. */ if (in_p && s390_plus_operand (x, mode)) @@ -2811,10 +3094,16 @@ s390_expand_plus_operand (rtx target, rtx src, STRICT specifies whether strict register checking applies. */ bool -legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, - rtx addr, int strict) +legitimate_address_p (enum machine_mode mode, rtx addr, int strict) { struct s390_address ad; + + if (TARGET_Z10 + && larl_operand (addr, VOIDmode) + && (mode == VOIDmode + || s390_check_symref_alignment (addr, GET_MODE_SIZE (mode)))) + return true; + if (!s390_decompose_address (addr, &ad)) return false; @@ -4052,14 +4341,31 @@ s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1, return false; } -/* Expand code for the insv template. Return true if successful, false else. */ +/* Expand code for the insv template. Return true if successful. */ -bool +bool s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src) { int bitsize = INTVAL (op1); int bitpos = INTVAL (op2); + /* On z10 we can use the risbg instruction to implement insv. */ + if (TARGET_Z10 + && ((GET_MODE (dest) == DImode && GET_MODE (src) == DImode) + || (GET_MODE (dest) == SImode && GET_MODE (src) == SImode))) + { + rtx op; + rtx clobber; + + op = gen_rtx_SET (GET_MODE(src), + gen_rtx_ZERO_EXTRACT (GET_MODE (dest), dest, op1, op2), + src); + clobber = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, CC_REGNUM)); + emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clobber))); + + return true; + } + /* We need byte alignment. */ if (bitsize % BITS_PER_UNIT) return false; @@ -4596,6 +4902,13 @@ print_operand_address (FILE *file, rtx addr) { struct s390_address ad; + if (s390_symref_operand_p (addr, NULL, NULL)) + { + gcc_assert (TARGET_Z10); + output_addr_const (file, addr); + return; + } + if (!s390_decompose_address (addr, &ad) || (ad.base && !REGNO_OK_FOR_BASE_P (REGNO (ad.base))) || (ad.indx && !REGNO_OK_FOR_INDEX_P (REGNO (ad.indx)))) @@ -4629,6 +4942,7 @@ print_operand_address (FILE *file, rtx addr) 'Y': print shift count operand. 'b': print integer X as if it's an unsigned byte. + 'c': print integer X as if it's an signed byte. 'x': print integer X as if it's an unsigned halfword. 'h': print integer X as if it's a signed halfword. 'i': print the first nonzero HImode part of X. @@ -4774,6 +5088,8 @@ print_operand (FILE *file, rtx x, int code) case CONST_INT: if (code == 'b') fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xff); + else if (code == 'c') + fprintf (file, HOST_WIDE_INT_PRINT_DEC, ((INTVAL (x) & 0xff) ^ 0x80) - 0x80); else if (code == 'x') fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0xffff); else if (code == 'h') @@ -8563,11 +8879,30 @@ s390_encode_section_info (tree decl, rtx rtl, int first) { default_encode_section_info (decl, rtl, first); - /* If a variable has a forced alignment to < 2 bytes, mark it with - SYMBOL_FLAG_ALIGN1 to prevent it from being used as LARL operand. */ - if (TREE_CODE (decl) == VAR_DECL - && DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16) - SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1; + if (TREE_CODE (decl) == VAR_DECL) + { + /* If a variable has a forced alignment to < 2 bytes, mark it + with SYMBOL_FLAG_ALIGN1 to prevent it from being used as LARL + operand. */ + if (DECL_USER_ALIGN (decl) && DECL_ALIGN (decl) < 16) + SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_ALIGN1; + if (!DECL_SIZE (decl) + || !DECL_ALIGN (decl) + || !host_integerp (DECL_SIZE (decl), 0) + || (DECL_ALIGN (decl) <= 64 + && DECL_ALIGN (decl) != tree_low_cst (DECL_SIZE (decl), 0))) + SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED; + } + + /* Literal pool references don't have a decl so they are handled + differently here. We rely on the information in the MEM_ALIGN + entry to decide upon natural alignment. */ + if (MEM_P (rtl) + && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF + && TREE_CONSTANT_POOL_ADDRESS_P (XEXP (rtl, 0)) + && (MEM_ALIGN (rtl) == 0 + || MEM_ALIGN (rtl) < GET_MODE_BITSIZE (GET_MODE (rtl)))) + SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED; } /* Output thunk to FILE that implements a C++ virtual function call (with diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 819154feef1..79286d5a9bc 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -1,8 +1,9 @@ /* Definitions of target machine for GNU compiler, for IBM S/390 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007 Free Software Foundation, Inc. + 2007, 2008 Free Software Foundation, Inc. Contributed by Hartmut Penner (hpenner@de.ibm.com) and Ulrich Weigand (uweigand@de.ibm.com). + Andreas Krebbel (Andreas.Krebbel@de.ibm.com) This file is part of GCC. @@ -62,6 +63,10 @@ extern enum processor_flags s390_tune_flags; extern enum processor_type s390_arch; extern enum processor_flags s390_arch_flags; +/* These flags indicate that the generated code should run on a cpu + providing the respective hardware facility regardless of the + current cpu mode (ESA or z/Architecture). */ + #define TARGET_CPU_IEEE_FLOAT \ (s390_arch_flags & PF_IEEE_FLOAT) #define TARGET_CPU_ZARCH \ @@ -75,6 +80,10 @@ extern enum processor_flags s390_arch_flags; #define TARGET_CPU_Z10 \ (s390_arch_flags & PF_Z10) +/* These flags indicate that the generated code should run on a cpu + providing the respective hardware facility when run in + z/Architecture mode. */ + #define TARGET_LONG_DISPLACEMENT \ (TARGET_ZARCH && TARGET_CPU_LONG_DISPLACEMENT) #define TARGET_EXTIMM \ @@ -491,11 +500,14 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER]; #define PREFERRED_RELOAD_CLASS(X, CLASS) \ s390_preferred_reload_class ((X), (CLASS)) -/* We need secondary memory to move data between GPRs and FPRs. */ +/* We need secondary memory to move data between GPRs and FPRs. With + DFP the ldgr lgdr instructions are available. But these + instructions do not handle GPR pairs so it is not possible for 31 + bit. */ #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \ ((CLASS1) != (CLASS2) \ && ((CLASS1) == FP_REGS || (CLASS2) == FP_REGS) \ - && (!TARGET_DFP || GET_MODE_SIZE (MODE) != 8)) + && (!TARGET_DFP || !TARGET_64BIT || GET_MODE_SIZE (MODE) != 8)) /* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on 64bit because the movsi and movsf patterns don't handle r/f moves. */ @@ -693,6 +705,13 @@ CUMULATIVE_ARGS; /* Maximum number of registers that can appear in a valid memory address. */ #define MAX_REGS_PER_ADDRESS 2 +/* This definition replaces the formerly used 'm' constraint with a +different constraint letter in order to avoid changing semantics of +the 'm' constraint when accepting new address formats in +legitimate_address_p. The constraint letter defined here must not be +used in insn definitions or inline assemblies. */ +#define TARGET_MEM_CONSTRAINT 'e' + /* S/390 has no mode dependent addresses. */ #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) @@ -959,7 +978,12 @@ do { \ #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = 64, 1) /* Machine-specific symbol_ref flags. */ -#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0) +#define SYMBOL_FLAG_ALIGN1 (SYMBOL_FLAG_MACH_DEP << 0) +#define SYMBOL_REF_ALIGN1_P(X) \ + ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_ALIGN1)) +#define SYMBOL_FLAG_NOT_NATURALLY_ALIGNED (SYMBOL_FLAG_MACH_DEP << 1) +#define SYMBOL_REF_NOT_NATURALLY_ALIGNED_P(X) \ + ((SYMBOL_REF_FLAGS (X) & SYMBOL_FLAG_NOT_NATURALLY_ALIGNED)) /* Check whether integer displacement is in range. */ #define DISP_IN_RANGE(d) \ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 54f4e0e9a87..f97e756518f 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -1,8 +1,9 @@ ;;- Machine description for GNU compiler -- S/390 / zSeries version. -;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 +;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 ;; Free Software Foundation, Inc. ;; Contributed by Hartmut Penner (hpenner@de.ibm.com) and -;; Ulrich Weigand (uweigand@de.ibm.com). +;; Ulrich Weigand (uweigand@de.ibm.com) and +;; Andreas Krebbel (Andreas.Krebbel@de.ibm.com) ;; This file is part of GCC. @@ -38,6 +39,7 @@ ;; %Y: print shift count operand. ;; ;; %b: print integer X as if it's an unsigned byte. +;; %c: print integer X as if it's an signed byte. ;; %x: print integer X as if it's an unsigned halfword. ;; %h: print integer X as if it's a signed halfword. ;; %i: print the first nonzero HImode part of X. @@ -189,7 +191,7 @@ ;; Used to determine defaults for length and other attribute values. (define_attr "op_type" - "NN,E,RR,RRE,RX,RS,RSI,RI,SI,S,SS,SSE,RXE,RSE,RIL,RIE,RXY,RSY,SIY,RRF,RRR" + "NN,E,RR,RRE,RX,RS,RSI,RI,SI,S,SS,SSE,RXE,RSE,RIL,RIE,RXY,RSY,SIY,RRF,RRR,SIL,RRS,RIS" (const_string "NN")) ;; Instruction type attribute used for scheduling. @@ -218,8 +220,8 @@ ;; Length in bytes. (define_attr "length" "" - (cond [(eq_attr "op_type" "E,RR") (const_int 2) - (eq_attr "op_type" "RX,RI,RRE,RS,RSI,S,SI") (const_int 4)] + (cond [(eq_attr "op_type" "E,RR") (const_int 2) + (eq_attr "op_type" "RX,RI,RRE,RS,RSI,S,SI,RRF,RRR") (const_int 4)] (const_int 6))) @@ -286,6 +288,7 @@ (define_mode_iterator FP_ALL [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP") (SD "TARGET_HARD_DFP")]) (define_mode_iterator FP [TF DF SF (TD "TARGET_HARD_DFP") (DD "TARGET_HARD_DFP")]) +(define_mode_iterator FPALL [TF DF SF TD DD SD]) (define_mode_iterator BFP [TF DF SF]) (define_mode_iterator DFP [TD DD]) (define_mode_iterator DFP_ALL [TD DD SD]) @@ -315,6 +318,7 @@ ;; This mode iterator allows the integer patterns to be defined from the ;; same template. (define_mode_iterator INT [(DI "TARGET_64BIT") SI HI QI]) +(define_mode_iterator INTALL [TI DI SI HI QI]) ;; This iterator allows to unify all 'bCOND' expander patterns. (define_code_iterator COMPARE [eq ne gt gtu lt ltu ge geu le leu unordered @@ -457,7 +461,6 @@ ;; Maximum unsigned integer that fits in MODE. (define_mode_attr max_uint [(HI "65535") (QI "255")]) - ;; ;;- Compare instructions. ;; @@ -543,14 +546,19 @@ (define_insn "*tstdi_sign" [(set (reg CC_REGNUM) - (compare (ashiftrt:DI (ashift:DI (subreg:DI (match_operand:SI 0 "register_operand" "d") 0) - (const_int 32)) (const_int 32)) - (match_operand:DI 1 "const0_operand" ""))) - (set (match_operand:DI 2 "register_operand" "=d") + (compare + (ashiftrt:DI + (ashift:DI + (subreg:DI (match_operand:SI 0 "nonimmediate_operand" "d,RT") 0) + (const_int 32)) (const_int 32)) + (match_operand:DI 1 "const0_operand" ""))) + (set (match_operand:DI 2 "register_operand" "=d,d") (sign_extend:DI (match_dup 0)))] "s390_match_ccmode(insn, CCSmode) && TARGET_64BIT" - "ltgfr\t%2,%0" - [(set_attr "op_type" "RRE")]) + "ltgfr\t%2,%0 + ltgf\t%2,%0" + [(set_attr "op_type" "RRE,RXY") + (set_attr "cpu_facility" "*,z10")]) ; ltr, lt, ltgr, ltg (define_insn "*tst_extimm" @@ -726,90 +734,159 @@ (define_insn "*cmpdi_ccs_sign" [(set (reg CC_REGNUM) - (compare (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT")) - (match_operand:DI 0 "register_operand" "d,d")))] + (compare (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" + "d,RT,b")) + (match_operand:DI 0 "register_operand" "d, d,d")))] "s390_match_ccmode(insn, CCSRmode) && TARGET_64BIT" "@ cgfr\t%0,%1 - cgf\t%0,%1" - [(set_attr "op_type" "RRE,RXY")]) + cgf\t%0,%1 + cgfrl\t%0,%1" + [(set_attr "op_type" "RRE,RXY,RIL") + (set_attr "cpu_facility" "*,*,z10") + (set_attr "type" "*,*,larl")]) (define_insn "*cmpsi_ccs_sign" [(set (reg CC_REGNUM) - (compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T")) - (match_operand:SI 0 "register_operand" "d,d")))] + (compare (sign_extend:SI (match_operand:HI 1 "memory_operand" "R,T,b")) + (match_operand:SI 0 "register_operand" "d,d,d")))] "s390_match_ccmode(insn, CCSRmode)" "@ ch\t%0,%1 - chy\t%0,%1" - [(set_attr "op_type" "RX,RXY")]) + chy\t%0,%1 + chrl\t%0,%1" + [(set_attr "op_type" "RX,RXY,RIL") + (set_attr "cpu_facility" "*,*,z10") + (set_attr "type" "*,*,larl")]) + +(define_insn "*cmphi_ccs_z10" + [(set (reg CC_REGNUM) + (compare (match_operand:HI 0 "s_operand" "Q") + (match_operand:HI 1 "immediate_operand" "K")))] + "s390_match_ccmode(insn, CCSmode) && TARGET_Z10" + "chhsi\t%0,%1" + [(set_attr "op_type" "SIL")]) + +(define_insn "*cmpdi_ccs_signhi_rl" + [(set (reg CC_REGNUM) + (compare (sign_extend:DI (match_operand:HI 1 "memory_operand" "RT,b")) + (match_operand:GPR 0 "register_operand" "d,d")))] + "s390_match_ccmode(insn, CCSRmode) && TARGET_Z10" + "@ + cgh\t%0,%1 + cghrl\t%0,%1" + [(set_attr "op_type" "RXY,RIL") + (set_attr "type" "*,larl")]) -; cr, chi, cfi, c, cy, cgr, cghi, cgfi, cg +; cr, chi, cfi, c, cy, cgr, cghi, cgfi, cg, chsi, cghsi, crl, cgrl (define_insn "*cmp_ccs" [(set (reg CC_REGNUM) - (compare (match_operand:GPR 0 "register_operand" "d,d,d,d,d") - (match_operand:GPR 1 "general_operand" "d,K,Os,R,T")))] + (compare (match_operand:GPR 0 "nonimmediate_operand" + "d,d,Q, d,d,d,d") + (match_operand:GPR 1 "general_operand" + "d,K,K,Os,R,T,b")))] "s390_match_ccmode(insn, CCSmode)" "@ cr\t%0,%1 chi\t%0,%h1 + chsi\t%0,%h1 cfi\t%0,%1 c\t%0,%1 - c\t%0,%1" - [(set_attr "op_type" "RR,RI,RIL,RX,RXY")]) + c\t%0,%1 + crl\t%0,%1" + [(set_attr "op_type" "RR,RI,SIL,RIL,RX,RXY,RIL") + (set_attr "cpu_facility" "*,*,z10,extimm,*,*,z10") + (set_attr "type" "*,*,*,*,*,*,larl")]) ; Compare (unsigned) instructions +(define_insn "*cmpsi_ccu_zerohi_rlsi" + [(set (reg CC_REGNUM) + (compare (zero_extend:SI (mem:HI (match_operand:SI 1 + "larl_operand" "X"))) + (match_operand:SI 0 "register_operand" "d")))] + "s390_match_ccmode(insn, CCURmode) && TARGET_Z10" + "clhrl\t%0,%1" + [(set_attr "op_type" "RIL") + (set_attr "type" "larl")]) + +; clhrl, clghrl +(define_insn "*cmp_ccu_zerohi_rldi" + [(set (reg CC_REGNUM) + (compare (zero_extend:GPR (mem:HI (match_operand:DI 1 + "larl_operand" "X"))) + (match_operand:GPR 0 "register_operand" "d")))] + "s390_match_ccmode(insn, CCURmode) && TARGET_Z10" + "clhrl\t%0,%1" + [(set_attr "op_type" "RIL") + (set_attr "type" "larl")]) + (define_insn "*cmpdi_ccu_zero" [(set (reg CC_REGNUM) - (compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT")) - (match_operand:DI 0 "register_operand" "d,d")))] + (compare (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" + "d,RT,b")) + (match_operand:DI 0 "register_operand" "d, d,d")))] "s390_match_ccmode (insn, CCURmode) && TARGET_64BIT" "@ clgfr\t%0,%1 - clgf\t%0,%1" - [(set_attr "op_type" "RRE,RXY")]) + clgf\t%0,%1 + clgfrl\t%0,%1" + [(set_attr "op_type" "RRE,RXY,RIL") + (set_attr "cpu_facility" "*,*,z10") + (set_attr "type" "*,*,larl")]) (define_insn "*cmpdi_ccu" [(set (reg CC_REGNUM) - (compare (match_operand:DI 0 "nonimmediate_operand" "d,d,d,Q,BQ") - (match_operand:DI 1 "general_operand" "d,Op,RT,BQ,Q")))] + (compare (match_operand:DI 0 "nonimmediate_operand" + "d, d,d,Q, d, Q,BQ") + (match_operand:DI 1 "general_operand" + "d,Op,b,D,RT,BQ,Q")))] "s390_match_ccmode (insn, CCUmode) && TARGET_64BIT" "@ clgr\t%0,%1 clgfi\t%0,%1 + clgrl\t%0,%1 + clghsi\t%0,%x1 clg\t%0,%1 # #" - [(set_attr "op_type" "RRE,RIL,RXY,SS,SS")]) + [(set_attr "op_type" "RRE,RIL,RIL,SIL,RXY,SS,SS") + (set_attr "cpu_facility" "*,extimm,z10,z10,*,*,*") + (set_attr "type" "*,*,larl,*,*,*,*")]) (define_insn "*cmpsi_ccu" [(set (reg CC_REGNUM) - (compare (match_operand:SI 0 "nonimmediate_operand" "d,d,d,d,Q,BQ") - (match_operand:SI 1 "general_operand" "d,Os,R,T,BQ,Q")))] + (compare (match_operand:SI 0 "nonimmediate_operand" "d, d,d,Q,d,d, Q,BQ") + (match_operand:SI 1 "general_operand" "d,Os,b,D,R,T,BQ, Q")))] "s390_match_ccmode (insn, CCUmode)" "@ clr\t%0,%1 clfi\t%0,%o1 + clrl\t%0,%1 + clfhsi\t%0,%x1 cl\t%0,%1 cly\t%0,%1 # #" - [(set_attr "op_type" "RR,RIL,RX,RXY,SS,SS")]) + [(set_attr "op_type" "RR,RIL,RIL,SIL,RX,RXY,SS,SS") + (set_attr "cpu_facility" "*,extimm,z10,z10,*,*,*,*") + (set_attr "type" "*,*,larl,*,*,*,*,*")]) (define_insn "*cmphi_ccu" [(set (reg CC_REGNUM) - (compare (match_operand:HI 0 "nonimmediate_operand" "d,d,Q,BQ") - (match_operand:HI 1 "general_operand" "Q,S,BQ,Q")))] + (compare (match_operand:HI 0 "nonimmediate_operand" "d,d,Q,Q,BQ") + (match_operand:HI 1 "general_operand" "Q,S,D,BQ,Q")))] "s390_match_ccmode (insn, CCUmode) && !register_operand (operands[1], HImode)" "@ clm\t%0,3,%S1 clmy\t%0,3,%S1 + clhhsi\t%0,%1 # #" - [(set_attr "op_type" "RS,RSY,SS,SS")]) + [(set_attr "op_type" "RS,RSY,SIL,SS,SS") + (set_attr "cpu_facility" "*,*,z10,*,*")]) (define_insn "*cmpqi_ccu" [(set (reg CC_REGNUM) @@ -885,6 +962,59 @@ [(set_attr "op_type" "RRE,RXE") (set_attr "type" "fsimp")]) + +; Compare and Branch instructions + +; cij, cgij, crj, cgrj, cfi, cgfi, cr, cgr +(define_insn "*cmp_and_br_signed_" + [(set (pc) + (if_then_else (match_operator 0 "s390_signed_integer_comparison" + [(match_operand:GPR 1 "register_operand" "d,d") + (match_operand:GPR 2 "nonmemory_operand" "d,C")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10" +{ + if (get_attr_length (insn) == 6) + return which_alternative ? + "cij%C0\t%1,%c2,%l3" : "crj%C0\t%1,%2,%l3"; + else + return which_alternative ? + "cfi\t%1,%c2\;jg%C0\t%l3" : "cr\t%1,%2\;jg%C0\t%l3"; +} + [(set_attr "op_type" "RIE") + (set_attr "type" "branch") + (set (attr "length") + (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) + (const_int 6) (const_int 12)))]) ; 8 byte for cr/jg + ; 10 byte for cgr/jg + +; clij, clgij, clrj, clgrj, clfi, clgfi, clr, clgr +(define_insn "*cmp_and_br_unsigned_" + [(set (pc) + (if_then_else (match_operator 0 "s390_unsigned_integer_comparison" + [(match_operand:GPR 1 "register_operand" "d,d") + (match_operand:GPR 2 "nonmemory_operand" "d,I")]) + (label_ref (match_operand 3 "" "")) + (pc))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10" +{ + if (get_attr_length (insn) == 6) + return which_alternative ? + "clij%C0\t%1,%b2,%l3" : "clrj%C0\t%1,%2,%l3"; + else + return which_alternative ? + "clfi\t%1,%b2\;jg%C0\t%l3" : "clr\t%1,%2\;jg%C0\t%l3"; +} + [(set_attr "op_type" "RIE") + (set_attr "type" "branch") + (set (attr "length") + (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) + (const_int 6) (const_int 12)))]) ; 8 byte for clr/jg + ; 10 byte for clgr/jg + ;; ;;- Move instructions. ;; @@ -951,6 +1081,60 @@ ; Patterns used for secondary reloads ; +; z10 provides move instructions accepting larl memory operands. +; Unfortunately there is no such variant for QI, TI and FP mode moves. +; These patterns are also used for unaligned SI and DI accesses. + +(define_expand "reload_tomem_z10" + [(parallel [(match_operand:INTALL 0 "memory_operand" "") + (match_operand:INTALL 1 "register_operand" "=d") + (match_operand:P 2 "register_operand" "=&a")])] + "TARGET_Z10" +{ + s390_reload_symref_address (operands[1], operands[0], operands[2], 1); + DONE; +}) + +(define_expand "reload_toreg_z10" + [(parallel [(match_operand:INTALL 0 "register_operand" "=d") + (match_operand:INTALL 1 "memory_operand" "") + (match_operand:P 2 "register_operand" "=a")])] + "TARGET_Z10" +{ + s390_reload_symref_address (operands[0], operands[1], operands[2], 0); + DONE; +}) + +(define_expand "reload_tomem_z10" + [(parallel [(match_operand:FPALL 0 "memory_operand" "") + (match_operand:FPALL 1 "register_operand" "=d") + (match_operand:P 2 "register_operand" "=&a")])] + "TARGET_Z10" +{ + s390_reload_symref_address (operands[1], operands[0], operands[2], 1); + DONE; +}) + +(define_expand "reload_toreg_z10" + [(parallel [(match_operand:FPALL 0 "register_operand" "=d") + (match_operand:FPALL 1 "memory_operand" "") + (match_operand:P 2 "register_operand" "=a")])] + "TARGET_Z10" +{ + s390_reload_symref_address (operands[0], operands[1], operands[2], 0); + DONE; +}) + +(define_expand "reload_larl_odd_addend_z10" + [(parallel [(match_operand:P 0 "register_operand" "=d") + (match_operand:P 1 "larl_operand" "") + (match_operand:P 2 "register_operand" "=a")])] + "TARGET_Z10" +{ + s390_reload_larl_operand (operands[0], operands[1], operands[2]); + DONE; +}) + ; Handles loading a PLUS (load address) expression (define_expand "reload_plus" @@ -1020,11 +1204,11 @@ (define_insn "*movdi_64" [(set (match_operand:DI 0 "nonimmediate_operand" - "=d,d,d,d,d,d,d,d,f,d,d,d,d, - RT,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q") + "=d,d,d,d,d,d,d,d,f,d,d,d,d,d, + RT,!*f,!*f,!*f,!R,!T,b,Q,d,t,Q,t,?Q") (match_operand:DI 1 "general_operand" - "K,N0HD0,N1HD0,N2HD0,N3HD0,Os,N0SD0,N1SD0,d,f,L,d,RT, - d,*f,R,T,*f,*f,t,d,t,Q,?Q"))] + "K,N0HD0,N1HD0,N2HD0,N3HD0,Os,N0SD0,N1SD0,d,f,L,b,d,RT, + d,*f,R,T,*f,*f,d,K,t,d,t,Q,?Q"))] "TARGET_64BIT" "@ lghi\t%0,%h1 @@ -1038,6 +1222,7 @@ ldgr\t%0,%1 lgdr\t%0,%1 lay\t%0,%a1 + lgrl\t%0,%1 lgr\t%0,%1 lg\t%0,%1 stg\t%1,%0 @@ -1046,17 +1231,21 @@ ldy\t%0,%1 std\t%1,%0 stdy\t%1,%0 + stgrl\t%1,%0 + mvghi\t%0,%1 # # stam\t%1,%N1,%S0 lam\t%0,%N0,%S1 #" - [(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RRE,RRE,RXY,RRE,RXY,RXY, - RR,RX,RXY,RX,RXY,*,*,RS,RS,SS") - (set_attr "type" "*,*,*,*,*,*,*,*,floaddf,floaddf,la,lr,load,store, - floaddf,floaddf,floaddf,fstoredf,fstoredf,*,*,*,*,*") + [(set_attr "op_type" "RI,RI,RI,RI,RI,RIL,RIL,RIL,RRE,RRE,RXY,RIL,RRE,RXY, + RXY,RR,RX,RXY,RX,RXY,RIL,SIL,*,*,RS,RS,SS") + (set_attr "type" "*,*,*,*,*,*,*,*,floaddf,floaddf,la,larl,lr,load,store, + floaddf,floaddf,floaddf,fstoredf,fstoredf,larl,*,*,*, + *,*,*") (set_attr "cpu_facility" "*,*,*,*,*,extimm,extimm,extimm,dfp,dfp,longdisp, - *,*,*,*,*,longdisp,*,longdisp,*,*,*,*,*")]) + z10,*,*,*,*,*,longdisp,*,longdisp, + z10,z10,*,*,*,*,*")]) (define_split [(set (match_operand:DI 0 "register_operand" "") @@ -1092,8 +1281,10 @@ s390_split_access_reg (operands[0], &operands[3], &operands[4]);") (define_insn "*movdi_31" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,Q,S,d,o,!*f,!*f,!*f,!R,!T,Q") - (match_operand:DI 1 "general_operand" "Q,S,d,d,dPRT,d,*f,R,T,*f,*f,Q"))] + [(set (match_operand:DI 0 "nonimmediate_operand" + "=d,d,Q,S,d ,o,!*f,!*f,!*f,!R,!T,Q,d") + (match_operand:DI 1 "general_operand" + " Q,S,d,d,dPRT,d, *f, R, T,*f,*f,Q,b"))] "!TARGET_64BIT" "@ lm\t%0,%N0,%S1 @@ -1107,9 +1298,26 @@ ldy\t%0,%1 std\t%1,%0 stdy\t%1,%0 + # #" - [(set_attr "op_type" "RS,RSY,RS,RSY,*,*,RR,RX,RXY,RX,RXY,SS") - (set_attr "type" "lm,lm,stm,stm,*,*,floaddf,floaddf,floaddf,fstoredf,fstoredf,*")]) + [(set_attr "op_type" "RS,RSY,RS,RSY,*,*,RR,RX,RXY,RX,RXY,SS,*") + (set_attr "type" "lm,lm,stm,stm,*,*,floaddf,floaddf,floaddf,fstoredf,fstoredf,*,*") + (set_attr "cpu_facility" "*,*,*,*,*,*,*,*,*,*,*,*,z10")]) + +; For a load from a symbol ref we can use one of the target registers +; together with larl to load the address. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (match_operand:DI 1 "memory_operand" ""))] + "!TARGET_64BIT && reload_completed && TARGET_Z10 + && larl_operand (XEXP (operands[1], 0), SImode)" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 0) (match_dup 1))] +{ + operands[2] = operand_subword (operands[0], 1, 0, DImode); + operands[3] = XEXP (operands[1], 0); + operands[1] = replace_equiv_address (operands[1], operands[2]); +}) (define_split [(set (match_operand:DI 0 "nonimmediate_operand" "") @@ -1227,9 +1435,9 @@ (define_insn "*movsi_zarch" [(set (match_operand:SI 0 "nonimmediate_operand" - "=d,d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,d,t,Q,t,?Q") + "=d,d,d,d,d,d,d,d,d,R,T,!*f,!*f,!*f,!R,!T,d,t,Q,b,Q,t,?Q") (match_operand:SI 1 "general_operand" - "K,N0HS0,N1HS0,Os,L,d,R,T,d,d,*f,R,T,*f,*f,t,d,t,Q,?Q"))] + "K,N0HS0,N1HS0,Os,L,b,d,R,T,d,d,*f,R,T,*f,*f,t,d,t,d,K,Q,?Q"))] "TARGET_ZARCH" "@ lhi\t%0,%h1 @@ -1237,6 +1445,7 @@ llill\t%0,%i1 iilf\t%0,%o1 lay\t%0,%a1 + lrl\t%0,%1 lr\t%0,%1 l\t%0,%1 ly\t%0,%1 @@ -1250,12 +1459,16 @@ ear\t%0,%1 sar\t%0,%1 stam\t%1,%1,%S0 + strl\t%1,%0 + mvhi\t%0,%1 lam\t%0,%0,%S1 #" - [(set_attr "op_type" "RI,RI,RI,RIL,RXY,RR,RX,RXY,RX,RXY, - RR,RX,RXY,RX,RXY,RRE,RRE,RS,RS,SS") - (set_attr "type" "*,*,*,*,la,lr,load,load,store,store, - floadsf,floadsf,floadsf,fstoresf,fstoresf,*,*,*,*,*")]) + [(set_attr "op_type" "RI,RI,RI,RIL,RXY,RIL,RR,RX,RXY,RX,RXY, + RR,RX,RXY,RX,RXY,RRE,RRE,RS,RIL,SIL,RS,SS") + (set_attr "type" "*,*,*,*,la,larl,lr,load,load,store,store, + floadsf,floadsf,floadsf,fstoresf,fstoresf,*,*,*,larl,*,*,*") + (set_attr "cpu_facility" "*,*,*,extimm,longdisp,z10,*,*,longdisp,*,longdisp, + *,*,longdisp,*,longdisp,*,*,*,z10,z10,*,*")]) (define_insn "*movsi_esa" [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,R,!*f,!*f,!R,d,t,Q,t,?Q") @@ -1381,19 +1594,23 @@ }) (define_insn "*movhi" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,T,?Q") - (match_operand:HI 1 "general_operand" "d,n,R,T,d,d,?Q"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,d,R,T,b,Q,?Q") + (match_operand:HI 1 "general_operand" " d,n,R,T,b,d,d,d,K,?Q"))] "" "@ lr\t%0,%1 lhi\t%0,%h1 lh\t%0,%1 lhy\t%0,%1 + lhrl\t%0,%1 sth\t%1,%0 sthy\t%1,%0 + sthrl\t%1,%0 + mvhhi\t%0,%1 #" - [(set_attr "op_type" "RR,RI,RX,RXY,RX,RXY,SS") - (set_attr "type" "lr,*,*,*,store,store,*")]) + [(set_attr "op_type" "RR,RI,RX,RXY,RIL,RX,RXY,RIL,SIL,SS") + (set_attr "type" "lr,*,*,*,larl,store,store,store,*,*") + (set_attr "cpu_facility" "*,*,*,*,z10,*,*,z10,z10,*")]) (define_peephole2 [(set (match_operand:HI 0 "register_operand" "") @@ -2014,6 +2231,17 @@ ;; String instructions. ;; +(define_insn "*execute_rl" + [(match_parallel 0 "" + [(unspec [(match_operand 1 "register_operand" "a") + (match_operand 2 "" "") + (match_operand:SI 3 "larl_operand" "X")] UNSPEC_EXECUTE)])] + "TARGET_Z10 && GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT + && GET_MODE_SIZE (GET_MODE (operands[1])) <= UNITS_PER_WORD" + "exrl\t%1,%3" + [(set_attr "op_type" "RIL") + (set_attr "type" "cs")]) + (define_insn "*execute" [(match_parallel 0 "" [(unspec [(match_operand 1 "register_operand" "a") @@ -2158,9 +2386,9 @@ ; (define_expand "movmem" - [(set (match_operand:BLK 0 "memory_operand" "") - (match_operand:BLK 1 "memory_operand" "")) - (use (match_operand:GPR 2 "general_operand" "")) + [(set (match_operand:BLK 0 "memory_operand" "") ; destination + (match_operand:BLK 1 "memory_operand" "")) ; source + (use (match_operand:GPR 2 "general_operand" "")) ; count (match_operand 3 "" "")] "" "s390_expand_movmem (operands[0], operands[1], operands[2]); DONE;") @@ -2179,15 +2407,16 @@ "operands[3] = gen_rtx_SCRATCH (Pmode);") (define_insn "*movmem_short" - [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q") - (match_operand:BLK 1 "memory_operand" "Q,Q,Q")) - (use (match_operand 2 "nonmemory_operand" "n,a,a")) - (use (match_operand 3 "immediate_operand" "X,R,X")) - (clobber (match_scratch 4 "=X,X,&a"))] + [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q,Q") + (match_operand:BLK 1 "memory_operand" "Q,Q,Q,Q")) + (use (match_operand 2 "nonmemory_operand" "n,a,a,a")) + (use (match_operand 3 "immediate_operand" "X,R,X,X")) + (clobber (match_scratch 4 "=X,X,X,&a"))] "(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode) && GET_MODE (operands[4]) == Pmode" "#" - [(set_attr "type" "cs")]) + [(set_attr "type" "cs") + (set_attr "cpu_facility" "*,*,z10,*")]) (define_split [(set (match_operand:BLK 0 "memory_operand" "") @@ -2215,6 +2444,20 @@ (use (const_int 1))])] "") +(define_split + [(set (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" "")) + (use (match_operand 2 "register_operand" "")) + (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) + (clobber (scratch))] + "TARGET_Z10 && reload_completed" + [(parallel + [(unspec [(match_dup 2) (const_int 0) + (label_ref (match_dup 3))] UNSPEC_EXECUTE) + (set (match_dup 0) (match_dup 1)) + (use (const_int 1))])] + "operands[3] = gen_label_rtx ();") + (define_split [(set (match_operand:BLK 0 "memory_operand" "") (match_operand:BLK 1 "memory_operand" "")) @@ -2358,16 +2601,17 @@ "operands[2] = gen_rtx_SCRATCH (Pmode);") (define_insn "*clrmem_short" - [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q") + [(set (match_operand:BLK 0 "memory_operand" "=Q,Q,Q,Q") (const_int 0)) - (use (match_operand 1 "nonmemory_operand" "n,a,a")) - (use (match_operand 2 "immediate_operand" "X,R,X")) - (clobber (match_scratch 3 "=X,X,&a")) + (use (match_operand 1 "nonmemory_operand" "n,a,a,a")) + (use (match_operand 2 "immediate_operand" "X,R,X,X")) + (clobber (match_scratch 3 "=X,X,X,&a")) (clobber (reg:CC CC_REGNUM))] "(GET_MODE (operands[1]) == Pmode || GET_MODE (operands[1]) == VOIDmode) && GET_MODE (operands[3]) == Pmode" "#" - [(set_attr "type" "cs")]) + [(set_attr "type" "cs") + (set_attr "cpu_facility" "*,*,z10,*")]) (define_split [(set (match_operand:BLK 0 "memory_operand" "") @@ -2399,6 +2643,22 @@ (clobber (reg:CC CC_REGNUM))])] "") +(define_split + [(set (match_operand:BLK 0 "memory_operand" "") + (const_int 0)) + (use (match_operand 1 "register_operand" "")) + (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) + (clobber (scratch)) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10 && reload_completed" + [(parallel + [(unspec [(match_dup 1) (const_int 0) + (label_ref (match_dup 3))] UNSPEC_EXECUTE) + (set (match_dup 0) (const_int 0)) + (use (const_int 1)) + (clobber (reg:CC CC_REGNUM))])] + "operands[3] = gen_label_rtx ();") + (define_split [(set (match_operand:BLK 0 "memory_operand" "") (const_int 0)) @@ -2499,15 +2759,16 @@ (define_insn "*cmpmem_short" [(set (reg:CCU CC_REGNUM) - (compare:CCU (match_operand:BLK 0 "memory_operand" "Q,Q,Q") - (match_operand:BLK 1 "memory_operand" "Q,Q,Q"))) - (use (match_operand 2 "nonmemory_operand" "n,a,a")) - (use (match_operand 3 "immediate_operand" "X,R,X")) - (clobber (match_scratch 4 "=X,X,&a"))] + (compare:CCU (match_operand:BLK 0 "memory_operand" "Q,Q,Q,Q") + (match_operand:BLK 1 "memory_operand" "Q,Q,Q,Q"))) + (use (match_operand 2 "nonmemory_operand" "n,a,a,a")) + (use (match_operand 3 "immediate_operand" "X,R,X,X")) + (clobber (match_scratch 4 "=X,X,X,&a"))] "(GET_MODE (operands[2]) == Pmode || GET_MODE (operands[2]) == VOIDmode) && GET_MODE (operands[4]) == Pmode" "#" - [(set_attr "type" "cs")]) + [(set_attr "type" "cs") + (set_attr "cpu_facility" "*,*,z10,*")]) (define_split [(set (reg:CCU CC_REGNUM) @@ -2537,6 +2798,21 @@ (use (const_int 1))])] "") +(define_split + [(set (reg:CCU CC_REGNUM) + (compare:CCU (match_operand:BLK 0 "memory_operand" "") + (match_operand:BLK 1 "memory_operand" ""))) + (use (match_operand 2 "register_operand" "")) + (use (const:BLK (unspec:BLK [(const_int 0)] UNSPEC_INSN))) + (clobber (scratch))] + "TARGET_Z10 && reload_completed" + [(parallel + [(unspec [(match_dup 2) (const_int 0) + (label_ref (match_dup 4))] UNSPEC_EXECUTE) + (set (reg:CCU CC_REGNUM) (compare:CCU (match_dup 0) (match_dup 1))) + (use (const_int 1))])] + "operands[4] = gen_label_rtx ();") + (define_split [(set (reg:CCU CC_REGNUM) (compare:CCU (match_operand:BLK 0 "memory_operand" "") @@ -2776,6 +3052,83 @@ FAIL; }) +(define_insn "*insv_z10" + [(set (zero_extract:GPR (match_operand:GPR 0 "nonimmediate_operand" "+d") + (match_operand 1 "const_int_operand" "I") + (match_operand 2 "const_int_operand" "I")) + (match_operand:GPR 3 "nonimmediate_operand" "d")) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10 + && (INTVAL (operands[1]) + INTVAL (operands[2])) <= + GET_MODE_BITSIZE (mode)" +{ + int start = INTVAL (operands[2]); + int size = INTVAL (operands[1]); + int offset = 64 - GET_MODE_BITSIZE (mode); + + operands[2] = GEN_INT (offset + start); /* start bit position */ + operands[1] = GEN_INT (offset + start + size - 1); /* end bit position */ + operands[4] = GEN_INT (GET_MODE_BITSIZE (mode) - + start - size); /* left shift count */ + + return "risbg\t%0,%3,%b2,%b1,%b4"; +} + [(set_attr "op_type" "RIE")]) + +; and op1 with a mask being 1 for the selected bits and 0 for the rest +; and op3=op0 with a mask being 0 for the selected bits and 1 for the rest +(define_insn "*insv_z10_noshift" + [(set (match_operand:GPR 0 "nonimmediate_operand" "=d") + (ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d") + (match_operand 2 "const_int_operand" "n")) + (and:GPR (match_operand:GPR 3 "nonimmediate_operand" "0") + (match_operand 4 "const_int_operand" "n")))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10 + && s390_contiguous_bitmask_p (INTVAL (operands[2]), + GET_MODE_BITSIZE (mode), NULL, NULL) + && INTVAL (operands[2]) == ~(INTVAL (operands[4]))" + +{ + int start; + int size; + + s390_contiguous_bitmask_p (INTVAL (operands[2]), + GET_MODE_BITSIZE (mode), &start, &size); + + operands[5] = GEN_INT (64 - start - size); /* start bit position */ + operands[6] = GEN_INT (64 - 1 - start); /* end bit position */ + operands[7] = const0_rtx; /* left shift count */ + + return "risbg\t%0,%1,%b5,%b6,%b7"; +} + [(set_attr "op_type" "RIE")]) + +; and op1 with a mask being 1 for the selected bits and 0 for the rest +(define_insn "*insv_or_z10_noshift" + [(set (match_operand:GPR 0 "nonimmediate_operand" "=d") + (ior:GPR (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "d") + (match_operand 2 "const_int_operand" "n")) + (match_operand:GPR 3 "nonimmediate_operand" "0"))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_Z10 + && s390_contiguous_bitmask_p (INTVAL (operands[2]), + GET_MODE_BITSIZE (mode), NULL, NULL)" +{ + int start; + int size; + + s390_contiguous_bitmask_p (INTVAL (operands[2]), + GET_MODE_BITSIZE (mode), &start, &size); + + operands[4] = GEN_INT (64 - start - size); /* start bit position */ + operands[5] = GEN_INT (64 - 1 - start); /* end bit position */ + operands[6] = const0_rtx; /* left shift count */ + + return "rosbg\t%0,%1,%b4,%b5,%b6"; +} + [(set_attr "op_type" "RIE")]) + (define_insn "*insv_mem_reg" [(set (zero_extract:P (match_operand:QI 0 "memory_operand" "+Q,S") (match_operand 1 "const_int_operand" "n,n") @@ -2871,13 +3224,16 @@ }) (define_insn "*extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT")))] + [(set (match_operand:DI 0 "register_operand" "=d,d,d") + (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT,b")))] "TARGET_64BIT" "@ lgfr\t%0,%1 - lgf\t%0,%1" - [(set_attr "op_type" "RRE,RXY")]) + lgf\t%0,%1 + lgfrl\t%0,%1" + [(set_attr "op_type" "RRE,RXY,RIL") + (set_attr "type" "*,*,larl") + (set_attr "cpu_facility" "*,*,z10")]) ; ; extend(hi|qi)(si|di)2 instruction pattern(s). @@ -2912,13 +3268,16 @@ ; (define_insn "*extendhidi2_extimm" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,RT")))] + [(set (match_operand:DI 0 "register_operand" "=d,d,d") + (sign_extend:DI (match_operand:HI 1 "general_operand" "d,RT,b")))] "TARGET_64BIT && TARGET_EXTIMM" "@ lghr\t%0,%1 - lgh\t%0,%1" - [(set_attr "op_type" "RRE,RXY")]) + lgh\t%0,%1 + lghrl\t%0,%1" + [(set_attr "op_type" "RRE,RXY,RIL") + (set_attr "type" "*,*,larl") + (set_attr "cpu_facility" "extimm,extimm,z10")]) (define_insn "*extendhidi2" [(set (match_operand:DI 0 "register_operand" "=d") @@ -2932,14 +3291,17 @@ ; (define_insn "*extendhisi2_extimm" - [(set (match_operand:SI 0 "register_operand" "=d,d,d") - (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,T")))] + [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" " d,R,T,b")))] "TARGET_EXTIMM" "@ lhr\t%0,%1 lh\t%0,%1 - lhy\t%0,%1" - [(set_attr "op_type" "RRE,RX,RXY")]) + lhy\t%0,%1 + lhrl\t%0,%1" + [(set_attr "op_type" "RRE,RX,RXY,RIL") + (set_attr "type" "*,*,*,larl") + (set_attr "cpu_facility" "extimm,extimm,extimm,z10")]) (define_insn "*extendhisi2" [(set (match_operand:SI 0 "register_operand" "=d,d") @@ -3011,13 +3373,16 @@ }) (define_insn "*zero_extendsidi2" - [(set (match_operand:DI 0 "register_operand" "=d,d") - (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT")))] + [(set (match_operand:DI 0 "register_operand" "=d,d,d") + (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,RT,b")))] "TARGET_64BIT" "@ llgfr\t%0,%1 - llgf\t%0,%1" - [(set_attr "op_type" "RRE,RXY")]) + llgf\t%0,%1 + llgfrl\t%0,%1" + [(set_attr "op_type" "RRE,RXY,RIL") + (set_attr "type" "*,*,larl") + (set_attr "cpu_facility" "*,*,z10")]) ; ; LLGT-type instructions (zero-extend from 31 bit to 64 bit). @@ -3116,6 +3481,19 @@ } }) +; llhrl, llghrl +(define_insn "*zero_extendhi2_z10" + [(set (match_operand:GPR 0 "register_operand" "=d,d,d") + (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "d,RT,b")))] + "TARGET_Z10" + "@ + llhr\t%0,%1 + llh\t%0,%1 + llhrl\t%0,%1" + [(set_attr "op_type" "RXY,RRE,RIL") + (set_attr "type" "*,*,larl") + (set_attr "cpu_facility" "*,*,z10")]) + ; llhr, llcr, llghr, llgcr, llh, llc, llgh, llgc (define_insn "*zero_extend2_extimm" [(set (match_operand:GPR 0 "register_operand" "=d,d") @@ -3628,7 +4006,7 @@ (define_expand "adddi3" [(parallel - [(set (match_operand:DI 0 "register_operand" "") + [(set (match_operand:DI 0 "nonimmediate_operand" "") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") (match_operand:DI 2 "general_operand" ""))) (clobber (reg:CC CC_REGNUM))])] @@ -3683,7 +4061,7 @@ [(set_attr "op_type" "RRE,RXY")]) (define_insn_and_split "*adddi3_31z" - [(set (match_operand:DI 0 "register_operand" "=&d") + [(set (match_operand:DI 0 "nonimmediate_operand" "=&d") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") (match_operand:DI 2 "general_operand" "do") ) ) (clobber (reg:CC CC_REGNUM))] @@ -3708,7 +4086,7 @@ operands[8] = operand_subword (operands[2], 1, 0, DImode);") (define_insn_and_split "*adddi3_31" - [(set (match_operand:DI 0 "register_operand" "=&d") + [(set (match_operand:DI 0 "nonimmediate_operand" "=&d") (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") (match_operand:DI 2 "general_operand" "do") ) ) (clobber (reg:CC CC_REGNUM))] @@ -3745,7 +4123,7 @@ (define_expand "addsi3" [(parallel - [(set (match_operand:SI 0 "register_operand" "") + [(set (match_operand:SI 0 "nonimmediate_operand" "") (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") (match_operand:SI 2 "general_operand" ""))) (clobber (reg:CC CC_REGNUM))])] @@ -3767,11 +4145,11 @@ ; add(di|si)3 instruction pattern(s). ; -; ar, ahi, alfi, slfi, a, ay, agr, aghi, algfi, slgfi, ag +; ar, ahi, alfi, slfi, a, ay, agr, aghi, algfi, slgfi, ag, asi, agsi (define_insn "*add3" - [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d") - (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0,0") - (match_operand:GPR 2 "general_operand" "d,K,Op,On,R,T") ) ) + [(set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,d,d,d,d,QS") + (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0,0,0") + (match_operand:GPR 2 "general_operand" "d,K,Op,On,R,T,C") ) ) (clobber (reg:CC CC_REGNUM))] "" "@ @@ -3780,16 +4158,18 @@ alfi\t%0,%2 slfi\t%0,%n2 a\t%0,%2 - a\t%0,%2" - [(set_attr "op_type" "RR,RI,RIL,RIL,RX,RXY")]) + a\t%0,%2 + asi\t%0,%c2" + [(set_attr "op_type" "RR,RI,RIL,RIL,RX,RXY,SIY") + (set_attr "cpu_facility" "*,*,extimm,extimm,*,*,z10")]) -; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg +; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg, alsi, algsi (define_insn "*add3_carry1_cc" [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0") - (match_operand:GPR 2 "general_operand" "d,Op,On,R,T")) + (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0,0") + (match_operand:GPR 2 "general_operand" "d,Op,On,R,T,C")) (match_dup 1))) - (set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d") + (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,d,d,d,d") (plus:GPR (match_dup 1) (match_dup 2)))] "s390_match_ccmode (insn, CCL1mode)" "@ @@ -3797,8 +4177,10 @@ alfi\t%0,%2 slfi\t%0,%n2 al\t%0,%2 - al\t%0,%2" - [(set_attr "op_type" "RR,RIL,RIL,RX,RXY")]) + al\t%0,%2 + alsi\t%0,%c2" + [(set_attr "op_type" "RR,RIL,RIL,RX,RXY,SIY") + (set_attr "cpu_facility" "*,extimm,extimm,*,*,z10")]) ; alr, al, aly, algr, alg (define_insn "*add3_carry1_cconly" @@ -3814,13 +4196,13 @@ al\t%0,%2" [(set_attr "op_type" "RR,RX,RXY")]) -; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg +; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg, alsi, algsi (define_insn "*add3_carry2_cc" [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0") - (match_operand:GPR 2 "general_operand" "d,Op,On,R,T")) + (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0,0") + (match_operand:GPR 2 "general_operand" "d,Op,On,R,T,C")) (match_dup 2))) - (set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d") + (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,d,d,d,RS") (plus:GPR (match_dup 1) (match_dup 2)))] "s390_match_ccmode (insn, CCL1mode)" "@ @@ -3828,8 +4210,10 @@ alfi\t%0,%2 slfi\t%0,%n2 al\t%0,%2 - al\t%0,%2" - [(set_attr "op_type" "RR,RIL,RIL,RX,RXY")]) + al\t%0,%2 + alsi\t%0,%c2" + [(set_attr "op_type" "RR,RIL,RIL,RX,RXY,SIY") + (set_attr "cpu_facility" "*,extimm,extimm,*,*,z10")]) ; alr, al, aly, algr, alg (define_insn "*add3_carry2_cconly" @@ -3845,13 +4229,13 @@ al\t%0,%2" [(set_attr "op_type" "RR,RX,RXY")]) -; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg +; alr, alfi, slfi, al, aly, algr, algfi, slgfi, alg, alsi, algsi (define_insn "*add3_cc" [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0") - (match_operand:GPR 2 "general_operand" "d,Op,On,R,T")) + (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "%0,0,0,0,0,0") + (match_operand:GPR 2 "general_operand" "d,Op,On,R,T,C")) (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d") + (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,d,d,d,RS") (plus:GPR (match_dup 1) (match_dup 2)))] "s390_match_ccmode (insn, CCLmode)" "@ @@ -3859,8 +4243,10 @@ alfi\t%0,%2 slfi\t%0,%n2 al\t%0,%2 - al\t%0,%2" - [(set_attr "op_type" "RR,RIL,RIL,RX,RXY")]) + al\t%0,%2 + alsi\t%0,%c2" + [(set_attr "op_type" "RR,RIL,RIL,RX,RXY,SIY") + (set_attr "cpu_facility" "*,extimm,extimm,*,*,z10")]) ; alr, al, aly, algr, alg (define_insn "*add3_cconly" @@ -3889,22 +4275,25 @@ al\t%0,%2" [(set_attr "op_type" "RR,RX,RXY")]) -; ahi, afi, aghi, agfi +; ahi, afi, aghi, agfi, asi, agsi (define_insn "*add3_imm_cc" [(set (reg CC_REGNUM) - (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "0,0") - (match_operand:GPR 2 "const_int_operand" "K,Os")) + (compare (plus:GPR (match_operand:GPR 1 "nonimmediate_operand" "0,0,0") + (match_operand:GPR 2 "const_int_operand" "K,Os,C")) (const_int 0))) - (set (match_operand:GPR 0 "register_operand" "=d,d") + (set (match_operand:GPR 0 "nonimmediate_operand" "=d,d,QS") (plus:GPR (match_dup 1) (match_dup 2)))] "s390_match_ccmode (insn, CCAmode) && (CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'K', \"K\") - || CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'O', \"Os\")) + || CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'O', \"Os\") + || CONST_OK_FOR_CONSTRAINT_P (INTVAL (operands[2]), 'C', \"C\")) && INTVAL (operands[2]) != -((HOST_WIDE_INT)1 << (GET_MODE_BITSIZE(mode) - 1))" "@ ahi\t%0,%h2 - afi\t%0,%2" - [(set_attr "op_type" "RI,RIL")]) + afi\t%0,%2 + asi\t%0,%c2" + [(set_attr "op_type" "RI,RIL,SIY") + (set_attr "cpu_facility" "*,extimm,z10")]) ; ; add(tf|df|sf|td|dd)3 instruction pattern(s). @@ -4503,69 +4892,78 @@ (define_insn "*muldi3_sign" [(set (match_operand:DI 0 "register_operand" "=d,d") - (mult:DI (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "d,RT")) + (mult:DI (sign_extend:DI (match_operand:SI 2 "general_operand" "d,RT")) (match_operand:DI 1 "register_operand" "0,0")))] "TARGET_64BIT" "@ msgfr\t%0,%2 msgf\t%0,%2" - [(set_attr "op_type" "RRE,RXY") - (set_attr "type" "imuldi")]) + [(set_attr "op_type" "RRE,RXY") + (set_attr "type" "imuldi")]) (define_insn "muldi3" - [(set (match_operand:DI 0 "register_operand" "=d,d,d") - (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:DI 2 "general_operand" "d,K,RT")))] + [(set (match_operand:DI 0 "register_operand" "=d,d,d,d") + (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,0,0") + (match_operand:DI 2 "general_operand" "d,K,RT,Os")))] "TARGET_64BIT" "@ msgr\t%0,%2 mghi\t%0,%h2 - msg\t%0,%2" - [(set_attr "op_type" "RRE,RI,RXY") - (set_attr "type" "imuldi")]) + msg\t%0,%2 + msgfi\t%0,%2" + [(set_attr "op_type" "RRE,RI,RXY,RIL") + (set_attr "type" "imuldi") + (set_attr "cpu_facility" "*,*,*,z10")]) ; ; mulsi3 instruction pattern(s). ; (define_insn "*mulsi3_sign" - [(set (match_operand:SI 0 "register_operand" "=d") - (mult:SI (sign_extend:SI (match_operand:HI 2 "memory_operand" "R")) - (match_operand:SI 1 "register_operand" "0")))] + [(set (match_operand:SI 0 "register_operand" "=d,d") + (mult:SI (sign_extend:SI (match_operand:HI 2 "memory_operand" "R,T")) + (match_operand:SI 1 "register_operand" "0,0")))] "" - "mh\t%0,%2" - [(set_attr "op_type" "RX") - (set_attr "type" "imulhi")]) + "@ + mh\t%0,%2 + mhy\t%0,%2" + [(set_attr "op_type" "RX,RXY") + (set_attr "type" "imulhi") + (set_attr "cpu_facility" "*,z10")]) (define_insn "mulsi3" - [(set (match_operand:SI 0 "register_operand" "=d,d,d,d") - (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0") - (match_operand:SI 2 "general_operand" "d,K,R,T")))] + [(set (match_operand:SI 0 "register_operand" "=d,d,d,d,d") + (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,0,0,0") + (match_operand:SI 2 "general_operand" "d,K,R,T,Os")))] "" "@ msr\t%0,%2 mhi\t%0,%h2 ms\t%0,%2 - msy\t%0,%2" - [(set_attr "op_type" "RRE,RI,RX,RXY") - (set_attr "type" "imulsi,imulhi,imulsi,imulsi")]) + msy\t%0,%2 + msfi\t%0,%2" + [(set_attr "op_type" "RRE,RI,RX,RXY,RIL") + (set_attr "type" "imulsi,imulhi,imulsi,imulsi,imulsi") + (set_attr "cpu_facility" "*,*,*,*,z10")]) ; ; mulsidi3 instruction pattern(s). ; (define_insn "mulsidi3" - [(set (match_operand:DI 0 "register_operand" "=d,d") + [(set (match_operand:DI 0 "register_operand" "=d,d,d") (mult:DI (sign_extend:DI - (match_operand:SI 1 "register_operand" "%0,0")) + (match_operand:SI 1 "register_operand" "%0,0,0")) (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "d,R"))))] + (match_operand:SI 2 "nonimmediate_operand" "d,R,T"))))] "!TARGET_64BIT" "@ mr\t%0,%2 - m\t%0,%2" - [(set_attr "op_type" "RR,RX") - (set_attr "type" "imulsi")]) + m\t%0,%2 + mfy\t%0,%2" + [(set_attr "op_type" "RR,RX,RXY") + (set_attr "type" "imulsi") + (set_attr "cpu_facility" "*,*,z10")]) ; ; umulsidi3 instruction pattern(s). @@ -6762,6 +7160,32 @@ [(set_attr "op_type" "RI") (set_attr "type" "branch")]) +; crt, cgrt, cit, cgit +(define_insn "*cmp_and_trap_signed_int" + [(trap_if (match_operator 0 "s390_signed_integer_comparison" + [(match_operand:GPR 1 "register_operand" "d,d") + (match_operand:GPR 2 "nonmemory_operand" "d,K")]) + (const_int 0))] + "TARGET_Z10" + "@ + crt%C0\t%1,%2 + cit%C0\t%1,%h2" + [(set_attr "op_type" "RRF,RIE") + (set_attr "type" "branch")]) + +; clrt, clgrt, clfit, clgit +(define_insn "*cmp_and_trap_unsigned_int" + [(trap_if (match_operator 0 "s390_unsigned_integer_comparison" + [(match_operand:GPR 1 "register_operand" "d,d") + (match_operand:GPR 2 "nonmemory_operand" "d,D")]) + (const_int 0))] + "TARGET_Z10" + "@ + clrt%C0\t%1,%2 + clit%C0\t%1,%x2" + [(set_attr "op_type" "RRF,RIE") + (set_attr "type" "branch")]) + ;; ;;- Loop instructions. ;; @@ -7908,3 +8332,30 @@ "" "" [(set_attr "length" "0")]) + + +; +; Data prefetch patterns +; + +(define_insn "prefetch" + [(prefetch (match_operand 0 "address_operand" "UW,X") + (match_operand:SI 1 "const_int_operand" "n,n") + (match_operand:SI 2 "const_int_operand" "n,n"))] + "TARGET_Z10" +{ + if (larl_operand (operands[0], Pmode)) + return INTVAL (operands[1]) == 1 ? "pfdrl\t2,%a0" : "pfdrl\t1,%a0"; + + if (s390_mem_constraint ("W", operands[0]) + || s390_mem_constraint ("U", operands[0])) + return INTVAL (operands[1]) == 1 ? "pfd\t2,%a0" : "pfd\t1,%a0"; + + /* This point might be reached if op0 is a larl operand with an + uneven addend. In this case we simply omit issuing a prefetch + instruction. */ + + return ""; + +} [(set_attr "type" "load,larl") + (set_attr "op_type" "RXY,RIL")]) -- 2.30.2