diff options
author | David Edelsohn <edelsohn@gnu.org> | 2005-02-28 19:07:36 +0000 |
---|---|---|
committer | David Edelsohn <dje@gcc.gnu.org> | 2005-02-28 14:07:36 -0500 |
commit | 48d723357cd70e728528986d1ed82d7fd0eaa424 (patch) | |
tree | 1f8539c6d34bd651421b24d77dda48652523f485 /gcc | |
parent | 2203a881041c8ecd559282229f6bc8cd019c4697 (diff) | |
download | gcc-48d723357cd70e728528986d1ed82d7fd0eaa424.zip gcc-48d723357cd70e728528986d1ed82d7fd0eaa424.tar.gz gcc-48d723357cd70e728528986d1ed82d7fd0eaa424.tar.bz2 |
rs6000.c (EASY_VECTOR_15): Remove.
* config/rs6000/rs6000.c (EASY_VECTOR_15): Remove.
(EASY_VECTOR_15_ADD_SELF): Remove.
(num_insns_constant_wide): Not static.
(validate_condition_mode): Not static.
(toc_relative_expr_p): Not static.
(legitimate_indirect_address_p): Not static.
(macho_lo_sum_memory_operand): Not static.
(invalid_e500_subreg): Not static.
(easy_vector_same): Not static.
(easy_vector_splat_const): Not static.
(RS6000_SYMBOL_REF_TLS_P): Remove.
(any_operand): Delete.
(any_parallel_operand): Delete.
(count_register_operand): Delete.
(altivec_register_operand): Delete.
(xer_operand): Delete.
(s8bit_cint_operand): Delete.
(short_cint_operand): Delete.
(u_short_cint_operand): Delete.
(non_short_cint_operand): Delete.
(exact_log2_cint_operand): Delete.
(gpc_reg_operand): Delete.
(cc_reg_operand): Delete.
(cc_reg_not_cr0_operand): Delete.
(reg_or_short_operand): Delete.
(reg_or_neg_short_operand): Delete.
(reg_or_aligned_short_operand): Delete.
(reg_or_u_short_operand): Delete.
(reg_or_cint_operand): Delete.
(reg_or_arith_cint_operand): Delete.
(reg_or_add_cint64_operand): Delete.
(reg_or_sub_cint64_operand): Delete.
(reg_or_logical_cint_operand): Delete.
(got_operand): Delete.
(got_no_const_operand): Delete.
(easy_fp_constant): Delete.
(easy_vector_constant): Delete.
(easy_vector_constant_add_self): Delete.
(zero_constant): Delete.
(zero_fp_constant): Delete.
(volatile_mem_operand): Delete.
(offsettable_mem_operand): Delete.
(mem_or_easy_const_operand): Delete.
(add_operand): Delete.
(non_add_cint_operand): Delete.
(logical_operand): Delete.
(non_logical_cint_operand): Delete.
(mask_operand): Delete.
(mask_operand_wrap): Delete.
(mask64_operand): Delete.
(mask64_2_operand): Delete.
(and64_operand): Delete.
(and64_2_operand): Delete.
(and_operand): Delete.
(reg_or_mem_operand): Delete.
(lwa_operand): Delete.
(symbol_ref_operand): Delete.
(call_operand): Delete.
(current_file_function_operand): Delete.
(input_operand): Delete.
(rs6000_nonimmediate_operand): Delete.
(rs6000_tls_symbol_ref): Delete.
(save_world_operation): Delete.
(restore_world_operation): Delete.
(load_multiple_operation): Delete.
(store_multiple_operation): Delete.
(vrsave_operation): Delete.
(mfcr_operation): Delete.
(mtcrf_operation): Delete.
(lmw_operation): Delete.
(stmw_operation): Delete.
(branch_comparison_operator): Delete.
(branch_positive_comparison_operator): Delete.
(scc_comparison_operator): Delete.
(trap_comparison_operator): Delete.
(boolean_operator): Delete.
(boolean_or_operator): Delete.
(min_max_operator): Delete.
* config/rs6000/rs6000.h (RS6000_SYMBOL_REF_TLS_P): Move to here.
(EASY_VECTOR_15): Moved to here.
(EASY_VECTOR_15_ADD_SELF): Move to here.
(PREDICATE_CODES): Delete.
* config/rs6000/rs6000-protos.h: Delete predicate functions.
Declare functions no longer static.
* config/rs6000/predicates.md: New.
* config/rs6000/rs6000.md: Include predicates.md
From-SVN: r95692
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 89 | ||||
-rw-r--r-- | gcc/config/rs6000/predicates.md | 1206 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 80 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 1488 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 88 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 3 |
6 files changed, 1328 insertions, 1626 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3df5494..283128a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,92 @@ +2005-02-28 David Edelsohn <edelsohn@gnu.org> + + * config/rs6000/rs6000.c (EASY_VECTOR_15): Remove. + (EASY_VECTOR_15_ADD_SELF): Remove. + (num_insns_constant_wide): Not static. + (validate_condition_mode): Not static. + (toc_relative_expr_p): Not static. + (legitimate_indirect_address_p): Not static. + (macho_lo_sum_memory_operand): Not static. + (invalid_e500_subreg): Not static. + (easy_vector_same): Not static. + (easy_vector_splat_const): Not static. + (RS6000_SYMBOL_REF_TLS_P): Remove. + (any_operand): Delete. + (any_parallel_operand): Delete. + (count_register_operand): Delete. + (altivec_register_operand): Delete. + (xer_operand): Delete. + (s8bit_cint_operand): Delete. + (short_cint_operand): Delete. + (u_short_cint_operand): Delete. + (non_short_cint_operand): Delete. + (exact_log2_cint_operand): Delete. + (gpc_reg_operand): Delete. + (cc_reg_operand): Delete. + (cc_reg_not_cr0_operand): Delete. + (reg_or_short_operand): Delete. + (reg_or_neg_short_operand): Delete. + (reg_or_aligned_short_operand): Delete. + (reg_or_u_short_operand): Delete. + (reg_or_cint_operand): Delete. + (reg_or_arith_cint_operand): Delete. + (reg_or_add_cint64_operand): Delete. + (reg_or_sub_cint64_operand): Delete. + (reg_or_logical_cint_operand): Delete. + (got_operand): Delete. + (got_no_const_operand): Delete. + (easy_fp_constant): Delete. + (easy_vector_constant): Delete. + (easy_vector_constant_add_self): Delete. + (zero_constant): Delete. + (zero_fp_constant): Delete. + (volatile_mem_operand): Delete. + (offsettable_mem_operand): Delete. + (mem_or_easy_const_operand): Delete. + (add_operand): Delete. + (non_add_cint_operand): Delete. + (logical_operand): Delete. + (non_logical_cint_operand): Delete. + (mask_operand): Delete. + (mask_operand_wrap): Delete. + (mask64_operand): Delete. + (mask64_2_operand): Delete. + (and64_operand): Delete. + (and64_2_operand): Delete. + (and_operand): Delete. + (reg_or_mem_operand): Delete. + (lwa_operand): Delete. + (symbol_ref_operand): Delete. + (call_operand): Delete. + (current_file_function_operand): Delete. + (input_operand): Delete. + (rs6000_nonimmediate_operand): Delete. + (rs6000_tls_symbol_ref): Delete. + (save_world_operation): Delete. + (restore_world_operation): Delete. + (load_multiple_operation): Delete. + (store_multiple_operation): Delete. + (vrsave_operation): Delete. + (mfcr_operation): Delete. + (mtcrf_operation): Delete. + (lmw_operation): Delete. + (stmw_operation): Delete. + (branch_comparison_operator): Delete. + (branch_positive_comparison_operator): Delete. + (scc_comparison_operator): Delete. + (trap_comparison_operator): Delete. + (boolean_operator): Delete. + (boolean_or_operator): Delete. + (min_max_operator): Delete. + * config/rs6000/rs6000.h (RS6000_SYMBOL_REF_TLS_P): Move to here. + (EASY_VECTOR_15): Moved to here. + (EASY_VECTOR_15_ADD_SELF): Move to here. + (PREDICATE_CODES): Delete. + * config/rs6000/rs6000-protos.h: Delete predicate functions. + Declare functions no longer static. + * config/rs6000/predicates.md: New. + * config/rs6000/rs6000.md: Include predicates.md + 2005-02-28 Kazu Hirata <kazu@cs.umass.edu> * calls.c (emit_call_1): Don't use REG_ALWAYS_RETURN. diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md new file mode 100644 index 0000000..10e12af --- /dev/null +++ b/gcc/config/rs6000/predicates.md @@ -0,0 +1,1206 @@ +;; Predicate definitions for POWER and PowerPC. +;; Copyright (C) 2005 Free Software Foundation, Inc. +;; +;; This file is part of GCC. +;; +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; GCC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; Return 1 for anything except PARALLEL. +(define_predicate "any_operand" + (match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,mem")) + +;; Return 1 for any PARALLEL. +(define_predicate "any_parallel_operand" + (match_code "parallel")) + +;; Return 1 if op is COUNT register. +(define_predicate "count_register_operand" + (and (match_code "reg") + (match_test "REGNO (op) == COUNT_REGISTER_REGNUM + || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + +;; Return 1 if op is an Altivec register. +(define_predicate "altivec_register_operand" + (and (match_code "reg") + (match_test "ALTIVEC_REGNO_P (REGNO (op)) + || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + +;; Return 1 if op is XER register. +(define_predicate "xer_operand" + (and (match_code "reg") + (match_test "XER_REGNO_P (REGNO (op))"))) + +;; Return 1 if op is a signed 8-bit constant integer. +;; Integer multiplcation complete more quickly +(define_predicate "s8bit_cint_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) >= -128 && INTVAL (op) <= 127"))) + +;; Return 1 if op is a constant integer that can fit in a D field. +(define_predicate "short_cint_operand" + (and (match_code "const_int") + (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')"))) + +;; Return 1 if op is a constant integer that can fit in an unsigned D field. +(define_predicate "u_short_cint_operand" + (and (match_code "const_int") + (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')"))) + +;; Return 1 if op is a constant integer that cannot fit in a signed D field. +(define_predicate "non_short_cint_operand" + (and (match_code "const_int") + (match_test "(unsigned HOST_WIDE_INT) + (INTVAL (op) + 0x8000) >= 0x10000"))) + +;; Return 1 if op is a positive constant integer that is an exact power of 2. +(define_predicate "exact_log2_cint_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) > 0 && exact_log2 (INTVAL (op)) >= 0"))) + +;; Return 1 if op is a register that is not special. +(define_predicate "gpc_reg_operand" + (and (match_code "reg,subreg") + (and (match_operand 0 "register_operand") + (match_test "GET_CODE (op) != REG + || (REGNO (op) >= ARG_POINTER_REGNUM + && !XER_REGNO_P (REGNO (op))) + || REGNO (op) < MQ_REGNO")))) + +;; Return 1 if op is a register that is a condition register field. +(define_predicate "cc_reg_operand" + (and (match_code "reg,subreg") + (and (match_operand 0 "register_operand") + (match_test "GET_CODE (op) != REG + || REGNO (op) > LAST_VIRTUAL_REGISTER + || CR_REGNO_P (REGNO (op))")))) + +;; Return 1 if op is a register that is a condition register field not cr0. +(define_predicate "cc_reg_not_cr0_operand" + (and (match_code "reg,subreg") + (and (match_operand 0 "register_operand") + (match_test "GET_CODE (op) != REG + || REGNO (op) > LAST_VIRTUAL_REGISTER + || CR_REGNO_NOT_CR0_P (REGNO (op))")))) + +;; Return 1 if op is a constant integer valid for D field +;; or non-special register register. +(define_predicate "reg_or_short_operand" + (if_then_else (match_code "const_int") + (match_operand 0 "short_cint_operand") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is a constant integer valid whose negation is valid for +;; D field or non-special register register. +;; Do not allow a constant zero because all patterns that call this +;; predicate use "addic r1,r2,-const" to set carry when r2 is greater than +;; or equal to const, which does not work for zero. +(define_predicate "reg_or_neg_short_operand" + (if_then_else (match_code "const_int") + (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'P') + && INTVAL (op) != 0") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is a constant integer valid for DS field +;; or non-special register. +(define_predicate "reg_or_aligned_short_operand" + (if_then_else (match_code "const_int") + (and (match_operand 0 "short_cint_operand") + (match_test "!(INTVAL (op) & 3)")) + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is a constant integer whose high-order 16 bits are zero +;; or non-special register. +(define_predicate "reg_or_u_short_operand" + (if_then_else (match_code "const_int") + (match_operand 0 "u_short_cint_operand") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is any constant integer +;; or non-special register. +(define_predicate "reg_or_cint_operand" + (ior (match_code "const_int") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is a 32-bit signed constant integer valid for arithmetic +;; or non-special register. +(define_predicate "reg_or_arith_cint_operand" + (if_then_else (match_code "const_int") + (match_test "HOST_BITS_PER_WIDE_INT == 32 + || ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80000000) + < (unsigned HOST_WIDE_INT) 0x100000000ll)") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is a 32-bit signed constant integer valid for 64-bit addition +;; or non-special register. +(define_predicate "reg_or_add_cint64_operand" + (if_then_else (match_code "const_int") + (match_test "(HOST_BITS_PER_WIDE_INT == 32 && INTVAL (op) < 0x7fff8000) + || ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80000000) + < (unsigned HOST_WIDE_INT) 0x100000000ll)") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is a 32-bit constant integer valid for 64-bit subtraction +;; or non-special register. +(define_predicate "reg_or_sub_cint64_operand" + (if_then_else (match_code "const_int") + (match_test "(HOST_BITS_PER_WIDE_INT == 32 && INTVAL (op) < 0x7fff8000) + || ((unsigned HOST_WIDE_INT) ((- INTVAL (op)) + 0x80000000) + < (unsigned HOST_WIDE_INT) 0x100000000ll)") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if op is any 32-bit unsigned constant integer +;; or non-special register. +(define_predicate "reg_or_logical_cint_operand" + (if_then_else (match_code "const_int") + (match_test "(GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT + && INTVAL (op) >= 0) + || ((INTVAL (op) & GET_MODE_MASK (mode) + & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 0)") + (if_then_else (match_code "const_double") + (match_test "GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT + && mode == DImode + && CONST_DOUBLE_HIGH (op) == 0") + (match_operand 0 "gpc_reg_operand")))) + +;; Return 1 if operand is a CONST_DOUBLE that can be set in a register +;; with no more than one instruction per word. +(define_predicate "easy_fp_constant" + (match_code "const_double") +{ + if (GET_MODE (op) != mode + || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode)) + return 0; + + /* Consider all constants with -msoft-float to be easy. */ + if ((TARGET_SOFT_FLOAT || TARGET_E500_SINGLE) + && mode != DImode) + return 1; + + /* If we are using V.4 style PIC, consider all constants to be hard. */ + if (flag_pic && DEFAULT_ABI == ABI_V4) + return 0; + +#ifdef TARGET_RELOCATABLE + /* Similarly if we are using -mrelocatable, consider all constants + to be hard. */ + if (TARGET_RELOCATABLE) + return 0; +#endif + + if (mode == TFmode) + { + long k[4]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); + + return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1 + && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1 + && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1 + && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1); + } + + else if (mode == DFmode) + { + long k[2]; + REAL_VALUE_TYPE rv; + + if (TARGET_E500_DOUBLE) + return 0; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_DOUBLE (rv, k); + + return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1 + && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1); + } + + else if (mode == SFmode) + { + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + return num_insns_constant_wide (l) == 1; + } + + else if (mode == DImode) + return ((TARGET_POWERPC64 + && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0) + || (num_insns_constant (op, DImode) <= 2)); + + else if (mode == SImode) + return 1; + else + abort (); +}) + +;; Return 1 if the operand is a CONST_VECTOR and can be loaded into a +;; vector register without using memory. +(define_predicate "easy_vector_constant" + (match_code "const_vector") +{ + int cst, cst2; + + if (!TARGET_ALTIVEC && !TARGET_SPE) + return 0; + + if (zero_constant (op, mode) + && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode)) + || (TARGET_SPE && SPE_VECTOR_MODE (mode)))) + return 1; + + if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT) + return 0; + + if (TARGET_SPE && mode == V1DImode) + return 0; + + cst = INTVAL (CONST_VECTOR_ELT (op, 0)); + cst2 = INTVAL (CONST_VECTOR_ELT (op, 1)); + + /* Limit SPE vectors to 15 bits signed. These we can generate with: + li r0, CONSTANT1 + evmergelo r0, r0, r0 + li r0, CONSTANT2 + + I don't know how efficient it would be to allow bigger constants, + considering we'll have an extra 'ori' for every 'li'. I doubt 5 + instructions is better than a 64-bit memory load, but I don't + have the e500 timing specs. */ + if (TARGET_SPE && mode == V2SImode + && cst >= -0x7fff && cst <= 0x7fff + && cst2 >= -0x7fff && cst2 <= 0x7fff) + return 1; + + if (TARGET_ALTIVEC + && easy_vector_same (op, mode)) + { + cst = easy_vector_splat_const (cst, mode); + if (EASY_VECTOR_15_ADD_SELF (cst) + || EASY_VECTOR_15 (cst)) + return 1; + } + return 0; +}) + +;; Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF. +(define_predicate "easy_vector_constant_add_self" + (and (match_code "const_vector") + (and (match_test "TARGET_ALTIVEC") + (and (match_test "easy_vector_same (op, mode)") + (match_test "EASY_VECTOR_15_ADD_SELF + (easy_vector_splat_const + (INTVAL (CONST_VECTOR_ELT (op, 0)), + mode))"))))) + +;; Return 1 if operand is constant zero (scalars and vectors). +(define_predicate "zero_constant" + (and (match_code "const_int,const_double,const_vector") + (match_test "op == CONST0_RTX (mode)"))) + +;; Return 1 if operand is 0.0. +;; or non-special register register field no cr0 +(define_predicate "zero_fp_constant" + (and (match_code "const_double") + (match_test "GET_MODE_CLASS (mode) == MODE_FLOAT + && op == CONST0_RTX (mode)"))) + +;; Return 1 if the operand is in volatile memory. Note that during the +;; RTL generation phase, memory_operand does not return TRUE for volatile +;; memory references. So this function allows us to recognize volatile +;; references where its safe. +(define_predicate "volatile_mem_operand" + (and (and (match_code "mem") + (match_test "MEM_VOLATILE_P (op)")) + (if_then_else (match_test "reload_completed") + (match_operand 0 "memory_operand") + (if_then_else (match_test "reload_in_progress") + (match_test "strict_memory_address_p (mode, XEXP (op, 0))") + (match_test "memory_address_p (mode, XEXP (op, 0))"))))) + +;; Return 1 if the operand is an offsettable memory operand. +(define_predicate "offsettable_mem_operand" + (and (match_code "mem") + (match_test "offsettable_address_p (reload_completed + || reload_in_progress, + mode, XEXP (op, 0))"))) + +;; Return 1 if the operand is either an easy FP constant or memory. +(define_predicate "mem_or_easy_const_operand" + (if_then_else (match_code "const_double") + (match_operand 0 "easy_fp_constant") + (match_operand 0 "memory_operand"))) + +;; Return 1 if the operand is either a non-special register or can be used +;; as the operand of a `mode' add insn. +(define_predicate "add_operand" + (if_then_else (match_code "const_int") + (match_test "CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') + || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')") + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if OP is a constant but not a valid add_operand. +(define_predicate "non_add_cint_operand" + (and (match_code "const_int") + (match_test "!CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') + && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')"))) + +;; Return 1 if the operand is a non-special register or a constant that +;; can be used as the operand of an OR or XOR. +(define_predicate "logical_operand" + (match_code "reg,subreg,const_int,const_double") +{ + HOST_WIDE_INT opl, oph; + + if (gpc_reg_operand (op, mode)) + return 1; + + if (GET_CODE (op) == CONST_INT) + { + opl = INTVAL (op) & GET_MODE_MASK (mode); + + if (HOST_BITS_PER_WIDE_INT <= 32 + && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0) + return 0; + } + else if (GET_CODE (op) == CONST_DOUBLE) + { + if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + abort (); + + opl = CONST_DOUBLE_LOW (op); + oph = CONST_DOUBLE_HIGH (op); + if (oph != 0) + return 0; + } + else + return 0; + + return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0 + || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0); +}) + +;; Return 1 if op is a constant that is not a logical operand, but could +;; be split into one. +(define_predicate "non_logical_cint_operand" + (and (match_code "const_int,const_double") + (and (not (match_operand 0 "logical_operand")) + (match_operand 0 "reg_or_logical_cint_operand")))) + +;; Return 1 if op is a constant that can be encoded in a 32-bit mask (no +;; more than two 1->0 or 0->1 transitions). Reject all ones and all +;; zeros, since these should have been optimized away and confuse the +;; making of MB and ME. +(define_predicate "mask_operand" + (match_code "const_int") +{ + HOST_WIDE_INT c, lsb; + + c = INTVAL (op); + + /* Fail in 64-bit mode if the mask wraps around because the upper + 32-bits of the mask will all be 1s, contrary to GCC's internal view. */ + if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001) + return 0; + + /* We don't change the number of transitions by inverting, + so make sure we start with the LS bit zero. */ + if (c & 1) + c = ~c; + + /* Reject all zeros or all ones. */ + if (c == 0) + return 0; + + /* Find the first transition. */ + lsb = c & -c; + + /* Invert to look for a second transition. */ + c = ~c; + + /* Erase first transition. */ + c &= -lsb; + + /* Find the second transition (if any). */ + lsb = c & -c; + + /* Match if all the bits above are 1's (or c is zero). */ + return c == -lsb; +}) + +;; Return 1 for the PowerPC64 rlwinm corner case. +(define_predicate "mask_operand_wrap" + (match_code "const_int") +{ + HOST_WIDE_INT c, lsb; + + c = INTVAL (op); + + if ((c & 0x80000001) != 0x80000001) + return 0; + + c = ~c; + if (c == 0) + return 0; + + lsb = c & -c; + c = ~c; + c &= -lsb; + lsb = c & -c; + return c == -lsb; +}) + +;; Return 1 if the operand is a constant that is a PowerPC64 mask (no more +;; than one 1->0 or 0->1 transitions). Reject all zeros, since zero +;; should have been optimized away and confuses the making of MB and ME. +(define_predicate "mask64_operand" + (match_code "const_int") +{ + HOST_WIDE_INT c, lsb; + + c = INTVAL (op); + + /* Reject all zeros. */ + if (c == 0) + return 0; + + /* We don't change the number of transitions by inverting, + so make sure we start with the LS bit zero. */ + if (c & 1) + c = ~c; + + /* Find the transition, and check that all bits above are 1's. */ + lsb = c & -c; + + /* Match if all the bits above are 1's (or c is zero). */ + return c == -lsb; +}) + +;; Like mask64_operand, but allow up to three transitions. This +;; predicate is used by insn patterns that generate two rldicl or +;; rldicr machine insns. +(define_predicate "mask64_2_operand" + (match_code "const_int") +{ + return mask64_1or2_operand (op, mode, false); +}) + +;; Return 1 if the operand is either a non-special register or a constant +;; that can be used as the operand of a PowerPC64 logical AND insn. +(define_predicate "and64_operand" + (if_then_else (match_code "const_int") + (match_operand 0 "mask64_operand") + (if_then_else (match_test "fixed_regs[CR0_REGNO]") + (match_operand 0 "gpc_reg_operand") + (match_operand 0 "logical_operand")))) + +;; Like and64_operand, but also match constants that can be implemented +;; with two rldicl or rldicr insns. +(define_predicate "and64_2_operand" + (if_then_else (match_code "const_int") + (match_test "mask64_1or2_operand (op, mode, true)") + (if_then_else (match_test "fixed_regs[CR0_REGNO]") + (match_operand 0 "gpc_reg_operand") + (match_operand 0 "logical_operand")))) + +;; Return 1 if the operand is either a non-special register or a +;; constant that can be used as the operand of a logical AND. +(define_predicate "and_operand" + (if_then_else (match_code "const_int") + (match_operand 0 "mask_operand") + (if_then_else (match_test "fixed_regs[CR0_REGNO]") + (match_operand 0 "gpc_reg_operand") + (match_operand 0 "logical_operand")))) + +;; Return 1 if the operand is a general non-special register or memory operand. +(define_predicate "reg_or_mem_operand" + (if_then_else (match_code "mem") + (ior (match_operand 0 "memory_operand") + (ior (match_test "macho_lo_sum_memory_operand (op, mode)") + (match_operand 0 "volatile_mem_operand"))) + (match_operand 0 "gpc_reg_operand"))) + +;; Return 1 if the operand is a general register or memory operand without +;; pre_inc or pre_dec, which produces invalid form of PowerPC lwa +;; instruction. +(define_predicate "lwa_operand" + (match_code "reg,subreg,mem") +{ + rtx inner = op; + + if (reload_completed && GET_CODE (inner) == SUBREG) + inner = SUBREG_REG (inner); + + return gpc_reg_operand (inner, mode) + || (memory_operand (inner, mode) + && GET_CODE (XEXP (inner, 0)) != PRE_INC + && GET_CODE (XEXP (inner, 0)) != PRE_DEC + && (GET_CODE (XEXP (inner, 0)) != PLUS + || GET_CODE (XEXP (XEXP (inner, 0), 1)) != CONST_INT + || INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0)); +}) + +;; Return 1 if the operand, used inside a MEM, is a SYMBOL_REF. +(define_predicate "symbol_ref_operand" + (and (match_code "symbol_ref") + (match_test "(mode == VOIDmode || GET_MODE (op) == mode) + && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))"))) + +;; Return 1 if op is an operand that can be loaded via the GOT. +;; or non-special register register field no cr0 +(define_predicate "got_operand" + (match_code "symbol_ref,const,label_ref")) + +;; Return 1 if op is a simple reference that can be loaded via the GOT, +;; exclusing labels involving addition. +(define_predicate "got_no_const_operand" + (match_code "symbol_ref,label_ref")) + +;; Return 1 if op is a SYMBOL_REF for a TLS symbol. +(define_predicate "rs6000_tls_symbol_ref" + (and (match_code "symbol_ref") + (match_test "RS6000_SYMBOL_REF_TLS_P (op)"))) + +;; Return 1 if the operand, used inside a MEM, is a valid first argument +;; to CALL. This is a SYMBOL_REF, a pseudo-register, LR or CTR. +(define_predicate "call_operand" + (if_then_else (match_code "reg") + (match_test "REGNO (op) == LINK_REGISTER_REGNUM + || REGNO (op) == COUNT_REGISTER_REGNUM + || REGNO (op) >= FIRST_PSEUDO_REGISTER") + (match_code "symbol_ref"))) + +;; Return 1 if the operand is a SYMBOL_REF for a function known to be in +;; this file. +(define_predicate "current_file_function_operand" + (and (match_code "symbol_ref") + (match_test "(DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op)) + && (SYMBOL_REF_LOCAL_P (op) + || (op == XEXP (DECL_RTL (current_function_decl), + 0)))"))) + +;; Return 1 if this operand is a valid input for a move insn. +(define_predicate "input_operand" + (match_code "label_ref,symbol_ref,const,high,reg,subreg,mem, + const_double,const_vector,const_int,plus") +{ + /* Memory is always valid. */ + if (memory_operand (op, mode)) + return 1; + + /* For floating-point, easy constants are valid. */ + if (GET_MODE_CLASS (mode) == MODE_FLOAT + && CONSTANT_P (op) + && easy_fp_constant (op, mode)) + return 1; + + /* Allow any integer constant. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && (GET_CODE (op) == CONST_INT + || GET_CODE (op) == CONST_DOUBLE)) + return 1; + + /* Allow easy vector constants. */ + if (GET_CODE (op) == CONST_VECTOR + && easy_vector_constant (op, mode)) + return 1; + + /* For floating-point or multi-word mode, the only remaining valid type + is a register. */ + if (GET_MODE_CLASS (mode) == MODE_FLOAT + || GET_MODE_SIZE (mode) > UNITS_PER_WORD) + return register_operand (op, mode); + + /* The only cases left are integral modes one word or smaller (we + do not get called for MODE_CC values). These can be in any + register. */ + if (register_operand (op, mode)) + return 1; + + /* A SYMBOL_REF referring to the TOC is valid. */ + if (legitimate_constant_pool_address_p (op)) + return 1; + + /* A constant pool expression (relative to the TOC) is valid */ + if (toc_relative_expr_p (op)) + return 1; + + /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region + to be valid. */ + if (DEFAULT_ABI == ABI_V4 + && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST) + && small_data_operand (op, Pmode)) + return 1; + + return 0; +}) + +;; Return true if OP is an invalid SUBREG operation on the e500. +(define_predicate "rs6000_nonimmediate_operand" + (match_code "reg,subreg,mem") +{ + if (TARGET_E500_DOUBLE + && GET_CODE (op) == SUBREG + && invalid_e500_subreg (op, mode)) + return 0; + + return nonimmediate_operand (op, mode); +}) + +;; Return true if operand is boolean operator. +(define_predicate "boolean_operator" + (match_code "and,ior,xor")) + +;; Return true if operand is OR-form of boolean operator. +(define_predicate "boolean_or_operator" + (match_code "ior,xor")) + +;; Return true if operand is MIN or MAX operator. +(define_predicate "min_max_operator" + (match_code "smin,smax,umin,umax")) + +;; Return 1 if OP is a comparison operation that is valid for a branch +;; instruction. We only check the opcode against the mode of the CC value. +(define_predicate "branch_comparison_operator" + (match_code "eq,ne,le,lt,ge,gt,leu,ltu,geu,gtu,unordered,ordered,unge,unle") +{ + enum rtx_code code = GET_CODE (op); + enum machine_mode cc_mode; + + if (!COMPARISON_P (op)) + return 0; + + cc_mode = GET_MODE (XEXP (op, 0)); + if (GET_MODE_CLASS (cc_mode) != MODE_CC) + return 0; + + validate_condition_mode (code, cc_mode); + + return 1; +}) + +;; Return 1 if OP is a comparison operation that is valid for an SCC insn -- +;; it must be a positive comparison. +(define_predicate "scc_comparison_operator" + (and (match_code "eq,lt,gt,ltu,gtu,unordered") + (match_operand 0 "branch_comparison_operator"))) + +;; Return 1 if OP is a comparison operation that is valid for a branch +;; insn, which is true if the corresponding bit in the CC register is set. +(define_predicate "branch_positive_comparison_operator" + (and (match_code "eq,lt,gt,ltu,gtu,unordered") + (match_operand 0 "branch_comparison_operator"))) + +;; Return 1 is OP is a comparison operation that is valid for a trap insn. +(define_predicate "trap_comparison_operator" + (and (match_code "eq,ne,le,lt,ge,gt,leu,ltu,geu,gtu") + (match_test "(mode == VOIDmode || mode == GET_MODE (op)) + && COMPARISON_P (op)"))) + +;; Return 1 if OP is a load multiple operation, known to be a PARALLEL. +(define_predicate "load_multiple_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx src_addr; + int i; + + /* 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); + + 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)) != SImode + || REGNO (SET_DEST (elt)) != dest_regno + i + || GET_CODE (SET_SRC (elt)) != MEM + || GET_MODE (SET_SRC (elt)) != SImode + || 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)) != i * 4) + return 0; + } + + return 1; +}) + +;; Return 1 if OP is a store multiple operation, known to be a PARALLEL. +;; The second vector element is a CLOBBER. +(define_predicate "store_multiple_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0) - 1; + unsigned int src_regno; + rtx dest_addr; + int i; + + /* 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); + + for (i = 1; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i + 1); + + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != src_regno + i + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode + || 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)) != i * 4) + return 0; + } + + return 1; +}) + +;; Return 1 if OP is valid for a save_world call in prologue, known to be +;; a PARLLEL. +(define_predicate "save_world_operation" + (match_code "parallel") +{ + int index; + int i; + rtx elt; + int count = XVECLEN (op, 0); + + if (count != 55) + return 0; + + index = 0; + if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != USE) + return 0; + + for (i=1; i <= 18; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || ! memory_operand (SET_DEST (elt), DFmode) + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != DFmode) + return 0; + } + + for (i=1; i <= 12; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != V4SImode) + return 0; + } + + for (i=1; i <= 19; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || ! memory_operand (SET_DEST (elt), Pmode) + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != Pmode) + return 0; + } + + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || ! memory_operand (SET_DEST (elt), Pmode) + || GET_CODE (SET_SRC (elt)) != REG + || REGNO (SET_SRC (elt)) != CR2_REGNO + || GET_MODE (SET_SRC (elt)) != Pmode) + return 0; + + if (GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER) + return 0; + return 1; +}) + +;; Return 1 if OP is valid for a restore_world call in epilogue, known to be +;; a PARLLEL. +(define_predicate "restore_world_operation" + (match_code "parallel") +{ + int index; + int i; + rtx elt; + int count = XVECLEN (op, 0); + + if (count != 59) + return 0; + + index = 0; + if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN + || GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER) + return 0; + + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || ! memory_operand (SET_SRC (elt), Pmode) + || GET_CODE (SET_DEST (elt)) != REG + || REGNO (SET_DEST (elt)) != CR2_REGNO + || GET_MODE (SET_DEST (elt)) != Pmode) + return 0; + + for (i=1; i <= 19; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || ! memory_operand (SET_SRC (elt), Pmode) + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != Pmode) + return 0; + } + + for (i=1; i <= 12; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != V4SImode) + return 0; + } + + for (i=1; i <= 18; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || ! memory_operand (SET_SRC (elt), DFmode) + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != DFmode) + return 0; + } + + if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != USE) + return 0; + return 1; +}) + +;; Return 1 if OP is valid for a vrsave call, known to be a PARALLEL. +(define_predicate "vrsave_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno, src_regno; + int i; + + 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))) != UNSPEC_VOLATILE) + return 0; + + dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0))); + src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); + + if (dest_regno != VRSAVE_REGNO + && src_regno != VRSAVE_REGNO) + return 0; + + for (i = 1; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i); + + if (GET_CODE (elt) != CLOBBER + && GET_CODE (elt) != SET) + return 0; + } + + return 1; +}) + +;; Return 1 if OP is valid for mfcr insn, known to be a PARALLEL. +(define_predicate "mfcr_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count < 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET + || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC + || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2) + return 0; + + for (i = 0; i < count; i++) + { + rtx exp = XVECEXP (op, 0, i); + rtx unspec; + int maskval; + rtx src_reg; + + src_reg = XVECEXP (SET_SRC (exp), 0, 0); + + if (GET_CODE (src_reg) != REG + || GET_MODE (src_reg) != CCmode + || ! CR_REGNO_P (REGNO (src_reg))) + return 0; + + if (GET_CODE (exp) != SET + || GET_CODE (SET_DEST (exp)) != REG + || GET_MODE (SET_DEST (exp)) != SImode + || ! INT_REGNO_P (REGNO (SET_DEST (exp)))) + return 0; + unspec = SET_SRC (exp); + maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg)); + + if (GET_CODE (unspec) != UNSPEC + || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR + || XVECLEN (unspec, 0) != 2 + || XVECEXP (unspec, 0, 0) != src_reg + || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT + || INTVAL (XVECEXP (unspec, 0, 1)) != maskval) + return 0; + } + return 1; +}) + +;; Return 1 if OP is valid for mtcrf insn, known to be a PARALLEL. +(define_predicate "mtcrf_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + int i; + rtx src_reg; + + /* Perform a quick check so we don't blow up below. */ + if (count < 1 + || GET_CODE (XVECEXP (op, 0, 0)) != SET + || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC + || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2) + return 0; + src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0); + + if (GET_CODE (src_reg) != REG + || GET_MODE (src_reg) != SImode + || ! INT_REGNO_P (REGNO (src_reg))) + return 0; + + for (i = 0; i < count; i++) + { + rtx exp = XVECEXP (op, 0, i); + rtx unspec; + int maskval; + + if (GET_CODE (exp) != SET + || GET_CODE (SET_DEST (exp)) != REG + || GET_MODE (SET_DEST (exp)) != CCmode + || ! CR_REGNO_P (REGNO (SET_DEST (exp)))) + return 0; + unspec = SET_SRC (exp); + maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp))); + + if (GET_CODE (unspec) != UNSPEC + || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR + || XVECLEN (unspec, 0) != 2 + || XVECEXP (unspec, 0, 0) != src_reg + || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT + || INTVAL (XVECEXP (unspec, 0, 1)) != maskval) + return 0; + } + return 1; +}) + +;; Return 1 if OP is valid for lmw insn, known to be a PARALLEL. +(define_predicate "lmw_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx src_addr; + unsigned int base_regno; + HOST_WIDE_INT offset; + int i; + + /* 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); + + if (dest_regno > 31 + || count != 32 - (int) dest_regno) + return 0; + + if (legitimate_indirect_address_p (src_addr, 0)) + { + offset = 0; + base_regno = REGNO (src_addr); + if (base_regno == 0) + return 0; + } + else if (rs6000_legitimate_offset_address_p (SImode, src_addr, 0)) + { + offset = INTVAL (XEXP (src_addr, 1)); + base_regno = REGNO (XEXP (src_addr, 0)); + } + else + return 0; + + for (i = 0; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i); + rtx newaddr; + rtx addr_reg; + HOST_WIDE_INT newoffset; + + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != SImode + || REGNO (SET_DEST (elt)) != dest_regno + i + || GET_CODE (SET_SRC (elt)) != MEM + || GET_MODE (SET_SRC (elt)) != SImode) + return 0; + newaddr = XEXP (SET_SRC (elt), 0); + if (legitimate_indirect_address_p (newaddr, 0)) + { + newoffset = 0; + addr_reg = newaddr; + } + else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0)) + { + addr_reg = XEXP (newaddr, 0); + newoffset = INTVAL (XEXP (newaddr, 1)); + } + else + return 0; + if (REGNO (addr_reg) != base_regno + || newoffset != offset + 4 * i) + return 0; + } + + return 1; +}) + +;; Return 1 if OP is valid for stmw insn, known to be a PARALLEL. +(define_predicate "stmw_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int src_regno; + rtx dest_addr; + unsigned int base_regno; + HOST_WIDE_INT offset; + int i; + + /* 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); + + if (src_regno > 31 + || count != 32 - (int) src_regno) + return 0; + + if (legitimate_indirect_address_p (dest_addr, 0)) + { + offset = 0; + base_regno = REGNO (dest_addr); + if (base_regno == 0) + return 0; + } + else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, 0)) + { + offset = INTVAL (XEXP (dest_addr, 1)); + base_regno = REGNO (XEXP (dest_addr, 0)); + } + else + return 0; + + for (i = 0; i < count; i++) + { + rtx elt = XVECEXP (op, 0, i); + rtx newaddr; + rtx addr_reg; + HOST_WIDE_INT newoffset; + + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != SImode + || REGNO (SET_SRC (elt)) != src_regno + i + || GET_CODE (SET_DEST (elt)) != MEM + || GET_MODE (SET_DEST (elt)) != SImode) + return 0; + newaddr = XEXP (SET_DEST (elt), 0); + if (legitimate_indirect_address_p (newaddr, 0)) + { + newoffset = 0; + addr_reg = newaddr; + } + else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0)) + { + addr_reg = XEXP (newaddr, 0); + newoffset = INTVAL (XEXP (newaddr, 1)); + } + else + return 0; + if (REGNO (addr_reg) != base_regno + || newoffset != offset + 4 * i) + return 0; + } + + return 1; +}) diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 4a4fcde..efaca41 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -32,74 +32,29 @@ extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, int, int, int); extern void rs6000_va_start (tree, rtx); #endif /* TREE_CODE */ +extern int easy_vector_same (rtx, enum machine_mode); +extern int easy_vector_splat_const (int, enum machine_mode); +extern int mask64_1or2_operand (rtx, enum machine_mode, bool); +extern bool macho_lo_sum_memory_operand (rtx, enum machine_mode); +extern int num_insns_constant (rtx, enum machine_mode); +extern int num_insns_constant_wide (HOST_WIDE_INT); +extern int small_data_operand (rtx, enum machine_mode); +extern bool toc_relative_expr_p (rtx); +extern bool invalid_e500_subreg (rtx, enum machine_mode); +extern void validate_condition_mode (enum rtx_code, enum machine_mode); +extern bool legitimate_constant_pool_address_p (rtx); +extern bool legitimate_indirect_address_p (rtx, int); +extern bool rs6000_legitimate_offset_address_p (enum machine_mode, rtx, int); + extern struct rtx_def *rs6000_got_register (rtx); extern struct rtx_def *find_addr_reg (rtx); -extern int any_operand (rtx, enum machine_mode); -extern int short_cint_operand (rtx, enum machine_mode); -extern int u_short_cint_operand (rtx, enum machine_mode); -extern int non_short_cint_operand (rtx, enum machine_mode); -extern int exact_log2_cint_operand (rtx, enum machine_mode); -extern int gpc_reg_operand (rtx, enum machine_mode); -extern int cc_reg_operand (rtx, enum machine_mode); -extern int cc_reg_not_cr0_operand (rtx, enum machine_mode); -extern int reg_or_short_operand (rtx, enum machine_mode); -extern int reg_or_neg_short_operand (rtx, enum machine_mode); -extern int reg_or_aligned_short_operand (rtx, enum machine_mode); -extern int reg_or_u_short_operand (rtx, enum machine_mode); -extern int reg_or_cint_operand (rtx, enum machine_mode); -extern int reg_or_arith_cint_operand (rtx, enum machine_mode); -extern int reg_or_add_cint64_operand (rtx, enum machine_mode); -extern int reg_or_sub_cint64_operand (rtx, enum machine_mode); -extern int reg_or_logical_cint_operand (rtx, enum machine_mode); -extern int got_operand (rtx, enum machine_mode); extern int word_offset_memref_operand (rtx, enum machine_mode); -extern int got_no_const_operand (rtx, enum machine_mode); -extern int num_insns_constant (rtx, enum machine_mode); -extern int easy_fp_constant (rtx, enum machine_mode); -extern int easy_vector_constant (rtx, enum machine_mode); extern rtx gen_easy_vector_constant_add_self (rtx); extern const char *output_vec_const_move (rtx *); -extern int zero_fp_constant (rtx, enum machine_mode); -extern int zero_constant (rtx, enum machine_mode); -extern int volatile_mem_operand (rtx, enum machine_mode); -extern int offsettable_mem_operand (rtx, enum machine_mode); -extern int mem_or_easy_const_operand (rtx, enum machine_mode); -extern int add_operand (rtx, enum machine_mode); -extern int non_add_cint_operand (rtx, enum machine_mode); -extern int non_logical_cint_operand (rtx, enum machine_mode); -extern int logical_operand (rtx, enum machine_mode); -extern int mask_operand (rtx, enum machine_mode); -extern int mask_operand_wrap (rtx, enum machine_mode); -extern int mask64_operand (rtx, enum machine_mode); -extern int mask64_2_operand (rtx, enum machine_mode); extern void build_mask64_2_operands (rtx, rtx *); -extern int and64_operand (rtx, enum machine_mode); -extern int and64_2_operand (rtx, enum machine_mode); -extern int and_operand (rtx, enum machine_mode); -extern int count_register_operand (rtx, enum machine_mode); -extern int xer_operand (rtx, enum machine_mode); -extern int reg_or_mem_operand (rtx, enum machine_mode); -extern int lwa_operand (rtx, enum machine_mode); -extern int call_operand (rtx, enum machine_mode); -extern int current_file_function_operand (rtx, enum machine_mode); -extern int input_operand (rtx, enum machine_mode); -extern int small_data_operand (rtx, enum machine_mode); -extern int s8bit_cint_operand (rtx, enum machine_mode); -extern bool legitimate_constant_pool_address_p (rtx); extern int expand_block_clear (rtx[]); extern int expand_block_move (rtx[]); -extern int load_multiple_operation (rtx, enum machine_mode); -extern int save_world_operation (rtx, enum machine_mode); -extern int restore_world_operation (rtx, enum machine_mode); extern const char * rs6000_output_load_multiple (rtx[]); -extern int store_multiple_operation (rtx, enum machine_mode); -extern int branch_comparison_operator (rtx, enum machine_mode); -extern int branch_positive_comparison_operator (rtx, enum machine_mode); -extern int scc_comparison_operator (rtx, enum machine_mode); -extern int trap_comparison_operator (rtx, enum machine_mode); -extern int boolean_operator (rtx, enum machine_mode); -extern int boolean_or_operator (rtx, enum machine_mode); -extern int min_max_operator (rtx, enum machine_mode); extern int includes_lshift_p (rtx, rtx); extern int includes_rshift_p (rtx, rtx); extern int includes_rldic_lshift_p (rtx, rtx); @@ -130,10 +85,6 @@ extern void output_toc (FILE *, rtx, int, enum machine_mode); extern void rs6000_initialize_trampoline (rtx, rtx, rtx); extern struct rtx_def *rs6000_longcall_ref (rtx); extern void rs6000_fatal_bad_address (rtx); -extern int stmw_operation (rtx, enum machine_mode); -extern int mfcr_operation (rtx, enum machine_mode); -extern int mtcrf_operation (rtx, enum machine_mode); -extern int lmw_operation (rtx, enum machine_mode); extern struct rtx_def *create_TOC_reference (rtx); extern void rs6000_split_multireg_move (rtx, rtx); extern void rs6000_emit_move (rtx, rtx, enum machine_mode); @@ -145,7 +96,6 @@ extern bool rs6000_mode_dependent_address (rtx); extern rtx rs6000_return_addr (int, rtx); extern void rs6000_output_symbol_ref (FILE*, rtx); extern HOST_WIDE_INT rs6000_initial_elimination_offset (int, int); -extern bool rs6000_legitimate_offset_address_p (enum machine_mode, rtx, int); extern rtx rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, @@ -197,12 +147,10 @@ extern unsigned int rs6000_dbx_register_number (unsigned int); extern void rs6000_emit_epilogue (int); extern void rs6000_emit_eh_reg_restore (rtx, rtx); extern const char * output_isel (rtx *); -extern int vrsave_operation (rtx, enum machine_mode); extern int rs6000_register_move_cost (enum machine_mode, enum reg_class, enum reg_class); extern int rs6000_memory_move_cost (enum machine_mode, enum reg_class, int); extern bool rs6000_tls_referenced_p (rtx); -extern int rs6000_tls_symbol_ref (rtx, enum machine_mode); extern void rs6000_output_dwarf_dtprel (FILE*, int, rtx); extern int rs6000_hard_regno_nregs (int, enum machine_mode); extern void rs6000_conditional_register_usage (void); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index e07ac50..f0b7c18 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -64,9 +64,6 @@ #define TARGET_NO_PROTOTYPE 0 #endif -#define EASY_VECTOR_15(n) ((n) >= -16 && (n) <= 15) -#define EASY_VECTOR_15_ADD_SELF(n) ((n) >= 0x10 && (n) <= 0x1e && !((n) & 1)) - #define min(A,B) ((A) < (B) ? (A) : (B)) #define max(A,B) ((A) > (B) ? (A) : (B)) @@ -603,8 +600,6 @@ struct processor_costs power4_cost = { static bool rs6000_function_ok_for_sibcall (tree, tree); -static int num_insns_constant_wide (HOST_WIDE_INT); -static void validate_condition_mode (enum rtx_code, enum machine_mode); static rtx rs6000_generate_compare (enum rtx_code); static void rs6000_maybe_dead (rtx); static void rs6000_emit_stack_tie (void); @@ -620,11 +615,8 @@ static unsigned toc_hash_function (const void *); static int toc_hash_eq (const void *, const void *); static int constant_pool_expr_1 (rtx, int *, int *); static bool constant_pool_expr_p (rtx); -static bool toc_relative_expr_p (rtx); static bool legitimate_small_data_p (enum machine_mode, rtx); static bool legitimate_indexed_address_p (rtx, int); -static bool legitimate_indirect_address_p (rtx, int); -static bool macho_lo_sum_memory_operand (rtx x, enum machine_mode mode); static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int); static struct machine_function * rs6000_init_machine_status (void); static bool rs6000_assemble_integer (rtx, unsigned int, int); @@ -710,7 +702,6 @@ static rtx spe_expand_builtin (tree, rtx, bool *); static rtx spe_expand_stv_builtin (enum insn_code, tree); static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx); static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx); -static bool invalid_e500_subreg (rtx, enum machine_mode); static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx); static rs6000_stack_t *rs6000_stack_info (void); static void debug_stack_info (rs6000_stack_t *); @@ -735,8 +726,6 @@ static void compute_save_world_info(rs6000_stack_t *info_ptr); static void is_altivec_return_reg (rtx, void *); static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int); int easy_vector_constant (rtx, enum machine_mode); -static int easy_vector_same (rtx, enum machine_mode); -static int easy_vector_splat_const (int, enum machine_mode); static bool is_ev64_opaque_type (tree); static rtx rs6000_dwarf_register_span (rtx); static rtx rs6000_legitimize_tls_address (rtx, enum tls_model); @@ -853,10 +842,6 @@ static const char alt_reg_names[][8] = /* The VRSAVE bitmask puts bit %v0 as the most significant bit. */ #define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO)) - -/* Return 1 for a symbol ref for a thread-local storage symbol. */ -#define RS6000_SYMBOL_REF_TLS_P(RTX) \ - (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0) /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE @@ -1810,312 +1795,10 @@ direct_return (void) return 0; } -/* Returns 1 always. */ - -int -any_operand (rtx op ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return 1; -} - -/* Returns 1 always. */ - -int -any_parallel_operand (rtx op ATTRIBUTE_UNUSED, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return 1; -} - -/* Returns 1 if op is the count register. */ - -int -count_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) != REG) - return 0; - - if (REGNO (op) == COUNT_REGISTER_REGNUM) - return 1; - - if (REGNO (op) > FIRST_PSEUDO_REGISTER) - return 1; - - return 0; -} - -/* Returns 1 if op is an altivec register. */ - -int -altivec_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (register_operand (op, mode) - && (GET_CODE (op) != REG - || REGNO (op) > FIRST_PSEUDO_REGISTER - || ALTIVEC_REGNO_P (REGNO (op)))); -} - -int -xer_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) != REG) - return 0; - - if (XER_REGNO_P (REGNO (op))) - return 1; - - return 0; -} - -/* Return 1 if OP is a signed 8-bit constant. Int multiplication - by such constants completes more quickly. */ - -int -s8bit_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && (INTVAL (op) >= -128 && INTVAL (op) <= 127)); -} - -/* Return 1 if OP is a constant that can fit in a D field. */ - -int -short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')); -} - -/* Similar for an unsigned D field. */ - -int -u_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && CONST_OK_FOR_LETTER_P (INTVAL (op) & GET_MODE_MASK (mode), 'K')); -} - -/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field. */ - -int -non_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000); -} - -/* Returns 1 if OP is a CONST_INT that is a positive value - and an exact power of 2. */ - -int -exact_log2_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && INTVAL (op) > 0 - && exact_log2 (INTVAL (op)) >= 0); -} - -/* Returns 1 if OP is a register that is not special (i.e., not MQ, - ctr, or lr). */ - -int -gpc_reg_operand (rtx op, enum machine_mode mode) -{ - return (register_operand (op, mode) - && (GET_CODE (op) != REG - || (REGNO (op) >= ARG_POINTER_REGNUM - && !XER_REGNO_P (REGNO (op))) - || REGNO (op) < MQ_REGNO)); -} - -/* Returns 1 if OP is either a pseudo-register or a register denoting a - CR field. */ - -int -cc_reg_operand (rtx op, enum machine_mode mode) -{ - return (register_operand (op, mode) - && (GET_CODE (op) != REG - || REGNO (op) >= FIRST_PSEUDO_REGISTER - || CR_REGNO_P (REGNO (op)))); -} - -/* Returns 1 if OP is either a pseudo-register or a register denoting a - CR field that isn't CR0. */ - -int -cc_reg_not_cr0_operand (rtx op, enum machine_mode mode) -{ - return (register_operand (op, mode) - && (GET_CODE (op) != REG - || REGNO (op) >= FIRST_PSEUDO_REGISTER - || CR_REGNO_NOT_CR0_P (REGNO (op)))); -} - -/* Returns 1 if OP is either a constant integer valid for a D-field or - a non-special register. If a register, it must be in the proper - mode unless MODE is VOIDmode. */ - -int -reg_or_short_operand (rtx op, enum machine_mode mode) -{ - return short_cint_operand (op, mode) || gpc_reg_operand (op, mode); -} - -/* Similar, except check if the negation of the constant would be - valid for a D-field. Don't allow a constant zero, since all the - patterns that call this predicate use "addic r1,r2,-constant" on - a constant value to set a carry when r2 is greater or equal to - "constant". That doesn't work for zero. */ - -int -reg_or_neg_short_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) == CONST_INT) - return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P') && INTVAL (op) != 0; - - return gpc_reg_operand (op, mode); -} - -/* Returns 1 if OP is either a constant integer valid for a DS-field or - a non-special register. If a register, it must be in the proper - mode unless MODE is VOIDmode. */ - -int -reg_or_aligned_short_operand (rtx op, enum machine_mode mode) -{ - if (gpc_reg_operand (op, mode)) - return 1; - else if (short_cint_operand (op, mode) && !(INTVAL (op) & 3)) - return 1; - - return 0; -} - - -/* Return 1 if the operand is either a register or an integer whose - high-order 16 bits are zero. */ - -int -reg_or_u_short_operand (rtx op, enum machine_mode mode) -{ - return u_short_cint_operand (op, mode) || gpc_reg_operand (op, mode); -} - -/* Return 1 is the operand is either a non-special register or ANY - constant integer. */ - -int -reg_or_cint_operand (rtx op, enum machine_mode mode) -{ - return (GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode)); -} - -/* Return 1 is the operand is either a non-special register or ANY - 32-bit signed constant integer. */ - -int -reg_or_arith_cint_operand (rtx op, enum machine_mode mode) -{ - return (gpc_reg_operand (op, mode) - || (GET_CODE (op) == CONST_INT -#if HOST_BITS_PER_WIDE_INT != 32 - && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80000000) - < (unsigned HOST_WIDE_INT) 0x100000000ll) -#endif - )); -} - -/* Return 1 is the operand is either a non-special register or a 32-bit - signed constant integer valid for 64-bit addition. */ - -int -reg_or_add_cint64_operand (rtx op, enum machine_mode mode) -{ - return (gpc_reg_operand (op, mode) - || (GET_CODE (op) == CONST_INT -#if HOST_BITS_PER_WIDE_INT == 32 - && INTVAL (op) < 0x7fff8000 -#else - && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000) - < 0x100000000ll) -#endif - )); -} - -/* Return 1 is the operand is either a non-special register or a 32-bit - signed constant integer valid for 64-bit subtraction. */ - -int -reg_or_sub_cint64_operand (rtx op, enum machine_mode mode) -{ - return (gpc_reg_operand (op, mode) - || (GET_CODE (op) == CONST_INT -#if HOST_BITS_PER_WIDE_INT == 32 - && (- INTVAL (op)) < 0x7fff8000 -#else - && ((unsigned HOST_WIDE_INT) ((- INTVAL (op)) + 0x80008000) - < 0x100000000ll) -#endif - )); -} - -/* Return 1 is the operand is either a non-special register or ANY - 32-bit unsigned constant integer. */ - -int -reg_or_logical_cint_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) == CONST_INT) - { - if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT) - { - if (GET_MODE_BITSIZE (mode) <= 32) - abort (); - - if (INTVAL (op) < 0) - return 0; - } - - return ((INTVAL (op) & GET_MODE_MASK (mode) - & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 0); - } - else if (GET_CODE (op) == CONST_DOUBLE) - { - if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT - || mode != DImode) - abort (); - - return CONST_DOUBLE_HIGH (op) == 0; - } - else - return gpc_reg_operand (op, mode); -} - -/* Return 1 if the operand is an operand that can be loaded via the GOT. */ - -int -got_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == SYMBOL_REF - || GET_CODE (op) == CONST - || GET_CODE (op) == LABEL_REF); -} - -/* Return 1 if the operand is a simple references that can be loaded via - the GOT (labels involving addition aren't allowed). */ - -int -got_no_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF); -} - /* Return the number of instructions it takes to form a constant in an integer register. */ -static int +int num_insns_constant_wide (HOST_WIDE_INT value) { /* signed constant loadable with {cal|addi} */ @@ -2222,88 +1905,9 @@ num_insns_constant (rtx op, enum machine_mode mode) abort (); } -/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a - register with one instruction per word. We only do this if we can - safely read CONST_DOUBLE_{LOW,HIGH}. */ - -int -easy_fp_constant (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) != CONST_DOUBLE - || GET_MODE (op) != mode - || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode)) - return 0; - - /* Consider all constants with -msoft-float to be easy. */ - if ((TARGET_SOFT_FLOAT || TARGET_E500_SINGLE) - && mode != DImode) - return 1; - - /* If we are using V.4 style PIC, consider all constants to be hard. */ - if (flag_pic && DEFAULT_ABI == ABI_V4) - return 0; - -#ifdef TARGET_RELOCATABLE - /* Similarly if we are using -mrelocatable, consider all constants - to be hard. */ - if (TARGET_RELOCATABLE) - return 0; -#endif - - if (mode == TFmode) - { - long k[4]; - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); - - return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1); - } - - else if (mode == DFmode) - { - long k[2]; - REAL_VALUE_TYPE rv; - - if (TARGET_E500_DOUBLE) - return 0; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_DOUBLE (rv, k); - - return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1); - } - - else if (mode == SFmode) - { - long l; - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_SINGLE (rv, l); - - return num_insns_constant_wide (l) == 1; - } - - else if (mode == DImode) - return ((TARGET_POWERPC64 - && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0) - || (num_insns_constant (op, DImode) <= 2)); - - else if (mode == SImode) - return 1; - else - abort (); -} - /* Returns the constant for the splat instruction, if exists. */ -static int +int easy_vector_splat_const (int cst, enum machine_mode mode) { switch (mode) @@ -2336,10 +1940,9 @@ easy_vector_splat_const (int cst, enum machine_mode mode) return 0; } - /* Return nonzero if all elements of a vector have the same value. */ -static int +int easy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) { int units, i, cst; @@ -2355,75 +1958,6 @@ easy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) return 0; } -/* Return 1 if the operand is a CONST_INT and can be put into a - register without using memory. */ - -int -easy_vector_constant (rtx op, enum machine_mode mode) -{ - int cst, cst2; - - if (GET_CODE (op) != CONST_VECTOR - || (!TARGET_ALTIVEC - && !TARGET_SPE)) - return 0; - - if (zero_constant (op, mode) - && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode)) - || (TARGET_SPE && SPE_VECTOR_MODE (mode)))) - return 1; - - if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT) - return 0; - - if (TARGET_SPE && mode == V1DImode) - return 0; - - cst = INTVAL (CONST_VECTOR_ELT (op, 0)); - cst2 = INTVAL (CONST_VECTOR_ELT (op, 1)); - - /* Limit SPE vectors to 15 bits signed. These we can generate with: - li r0, CONSTANT1 - evmergelo r0, r0, r0 - li r0, CONSTANT2 - - I don't know how efficient it would be to allow bigger constants, - considering we'll have an extra 'ori' for every 'li'. I doubt 5 - instructions is better than a 64-bit memory load, but I don't - have the e500 timing specs. */ - if (TARGET_SPE && mode == V2SImode - && cst >= -0x7fff && cst <= 0x7fff - && cst2 >= -0x7fff && cst2 <= 0x7fff) - return 1; - - if (TARGET_ALTIVEC - && easy_vector_same (op, mode)) - { - cst = easy_vector_splat_const (cst, mode); - if (EASY_VECTOR_15_ADD_SELF (cst) - || EASY_VECTOR_15 (cst)) - return 1; - } - return 0; -} - -/* Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF. */ - -int -easy_vector_constant_add_self (rtx op, enum machine_mode mode) -{ - int cst; - if (TARGET_ALTIVEC - && GET_CODE (op) == CONST_VECTOR - && easy_vector_same (op, mode)) - { - cst = easy_vector_splat_const (INTVAL (CONST_VECTOR_ELT (op, 0)), mode); - if (EASY_VECTOR_15_ADD_SELF (cst)) - return 1; - } - return 0; -} - /* Generate easy_vector_constant out of a easy_vector_constant_add_self. */ rtx @@ -2520,241 +2054,7 @@ output_vec_const_move (rtx *operands) abort (); } -/* Return 1 if the operand is the constant 0. This works for scalars - as well as vectors. */ -int -zero_constant (rtx op, enum machine_mode mode) -{ - return op == CONST0_RTX (mode); -} - -/* Return 1 if the operand is 0.0. */ -int -zero_fp_constant (rtx op, enum machine_mode mode) -{ - return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode); -} - -/* Return 1 if the operand is in volatile memory. Note that during - the RTL generation phase, memory_operand does not return TRUE for - volatile memory references. So this function allows us to - recognize volatile references where its safe. */ - -int -volatile_mem_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) != MEM) - return 0; - - if (!MEM_VOLATILE_P (op)) - return 0; - - if (mode != GET_MODE (op)) - return 0; - - if (reload_completed) - return memory_operand (op, mode); - - if (reload_in_progress) - return strict_memory_address_p (mode, XEXP (op, 0)); - - return memory_address_p (mode, XEXP (op, 0)); -} - -/* Return 1 if the operand is an offsettable memory operand. */ - -int -offsettable_mem_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == MEM) - && offsettable_address_p (reload_completed || reload_in_progress, - mode, XEXP (op, 0))); -} - -/* Return 1 if the operand is either an easy FP constant (see above) or - memory. */ - -int -mem_or_easy_const_operand (rtx op, enum machine_mode mode) -{ - return memory_operand (op, mode) || easy_fp_constant (op, mode); -} - -/* Return 1 if the operand is either a non-special register or an item - that can be used as the operand of a `mode' add insn. */ - -int -add_operand (rtx op, enum machine_mode mode) -{ - if (GET_CODE (op) == CONST_INT) - return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') - || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')); - - return gpc_reg_operand (op, mode); -} - -/* Return 1 if OP is a constant but not a valid add_operand. */ - -int -non_add_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == CONST_INT - && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'I') - && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')); -} - -/* Return 1 if the operand is a non-special register or a constant that - can be used as the operand of an OR or XOR insn on the RS/6000. */ - -int -logical_operand (rtx op, enum machine_mode mode) -{ - HOST_WIDE_INT opl, oph; - - if (gpc_reg_operand (op, mode)) - return 1; - - if (GET_CODE (op) == CONST_INT) - { - opl = INTVAL (op) & GET_MODE_MASK (mode); - -#if HOST_BITS_PER_WIDE_INT <= 32 - if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0) - return 0; -#endif - } - else if (GET_CODE (op) == CONST_DOUBLE) - { - if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) - abort (); - - opl = CONST_DOUBLE_LOW (op); - oph = CONST_DOUBLE_HIGH (op); - if (oph != 0) - return 0; - } - else - return 0; - - return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0 - || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0); -} - -/* Return 1 if C is a constant that is not a logical operand (as - above), but could be split into one. */ - -int -non_logical_cint_operand (rtx op, enum machine_mode mode) -{ - return ((GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE) - && ! logical_operand (op, mode) - && reg_or_logical_cint_operand (op, mode)); -} - -/* Return 1 if C is a constant that can be encoded in a 32-bit mask on the - RS/6000. It is if there are no more than two 1->0 or 0->1 transitions. - Reject all ones and all zeros, since these should have been optimized - away and confuse the making of MB and ME. */ - -int -mask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - HOST_WIDE_INT c, lsb; - - if (GET_CODE (op) != CONST_INT) - return 0; - - c = INTVAL (op); - - /* Fail in 64-bit mode if the mask wraps around because the upper - 32-bits of the mask will all be 1s, contrary to GCC's internal view. */ - if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001) - return 0; - - /* We don't change the number of transitions by inverting, - so make sure we start with the LS bit zero. */ - if (c & 1) - c = ~c; - - /* Reject all zeros or all ones. */ - if (c == 0) - return 0; - - /* Find the first transition. */ - lsb = c & -c; - - /* Invert to look for a second transition. */ - c = ~c; - - /* Erase first transition. */ - c &= -lsb; - - /* Find the second transition (if any). */ - lsb = c & -c; - - /* Match if all the bits above are 1's (or c is zero). */ - return c == -lsb; -} - -/* Return 1 for the PowerPC64 rlwinm corner case. */ - int -mask_operand_wrap (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - HOST_WIDE_INT c, lsb; - - if (GET_CODE (op) != CONST_INT) - return 0; - - c = INTVAL (op); - - if ((c & 0x80000001) != 0x80000001) - return 0; - - c = ~c; - if (c == 0) - return 0; - - lsb = c & -c; - c = ~c; - c &= -lsb; - lsb = c & -c; - return c == -lsb; -} - -/* Return 1 if the operand is a constant that is a PowerPC64 mask. - It is if there are no more than one 1->0 or 0->1 transitions. - Reject all zeros, since zero should have been optimized away and - confuses the making of MB and ME. */ - -int -mask64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - if (GET_CODE (op) == CONST_INT) - { - HOST_WIDE_INT c, lsb; - - c = INTVAL (op); - - /* Reject all zeros. */ - if (c == 0) - return 0; - - /* We don't change the number of transitions by inverting, - so make sure we start with the LS bit zero. */ - if (c & 1) - c = ~c; - - /* Find the transition, and check that all bits above are 1's. */ - lsb = c & -c; - - /* Match if all the bits above are 1's (or c is zero). */ - return c == -lsb; - } - return 0; -} - -static int mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED, bool allow_one) { @@ -2809,14 +2109,6 @@ mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED, return 0; } -/* Like mask64_operand, but allow up to three transitions. This - predicate is used by insn patterns that generate two rldicl or - rldicr machine insns. */ -int mask64_2_operand (rtx op, enum machine_mode mode) -{ - return mask64_1or2_operand (op, mode, false); -} - /* Generates shifts and masks for a pair of rldicl or rldicr insns to implement ANDing by the mask IN. */ void @@ -2887,174 +2179,9 @@ build_mask64_2_operands (rtx in, rtx *out) #endif } -/* Return 1 if the operand is either a non-special register or a constant - that can be used as the operand of a PowerPC64 logical AND insn. */ - -int -and64_operand (rtx op, enum machine_mode mode) -{ - if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */ - return (gpc_reg_operand (op, mode) || mask64_operand (op, mode)); - - return (logical_operand (op, mode) || mask64_operand (op, mode)); -} - -/* Like the above, but also match constants that can be implemented - with two rldicl or rldicr insns. */ - -int -and64_2_operand (rtx op, enum machine_mode mode) -{ - if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */ - return gpc_reg_operand (op, mode) || mask64_1or2_operand (op, mode, true); - - return logical_operand (op, mode) || mask64_1or2_operand (op, mode, true); -} - -/* Return 1 if the operand is either a non-special register or a - constant that can be used as the operand of an RS/6000 logical AND insn. */ - -int -and_operand (rtx op, enum machine_mode mode) -{ - if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */ - return (gpc_reg_operand (op, mode) || mask_operand (op, mode)); - - return (logical_operand (op, mode) || mask_operand (op, mode)); -} - -/* Return 1 if the operand is a general register or memory operand. */ - -int -reg_or_mem_operand (rtx op, enum machine_mode mode) -{ - return (gpc_reg_operand (op, mode) - || memory_operand (op, mode) - || macho_lo_sum_memory_operand (op, mode) - || volatile_mem_operand (op, mode)); -} - -/* Return 1 if the operand is a general register or memory operand without - pre_inc or pre_dec which produces invalid form of PowerPC lwa - instruction. */ - -int -lwa_operand (rtx op, enum machine_mode mode) -{ - rtx inner = op; - - if (reload_completed && GET_CODE (inner) == SUBREG) - inner = SUBREG_REG (inner); - - return gpc_reg_operand (inner, mode) - || (memory_operand (inner, mode) - && GET_CODE (XEXP (inner, 0)) != PRE_INC - && GET_CODE (XEXP (inner, 0)) != PRE_DEC - && (GET_CODE (XEXP (inner, 0)) != PLUS - || GET_CODE (XEXP (XEXP (inner, 0), 1)) != CONST_INT - || INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0)); -} - -/* Return 1 if the operand, used inside a MEM, is a SYMBOL_REF. */ - -int -symbol_ref_operand (rtx op, enum machine_mode mode) -{ - if (mode != VOIDmode && GET_MODE (op) != mode) - return 0; - - return (GET_CODE (op) == SYMBOL_REF - && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))); -} - -/* Return 1 if the operand, used inside a MEM, is a valid first argument - to CALL. This is a SYMBOL_REF, a pseudo-register, LR or CTR. */ - -int -call_operand (rtx op, enum machine_mode mode) -{ - if (mode != VOIDmode && GET_MODE (op) != mode) - return 0; - - return (GET_CODE (op) == SYMBOL_REF - || (GET_CODE (op) == REG - && (REGNO (op) == LINK_REGISTER_REGNUM - || REGNO (op) == COUNT_REGISTER_REGNUM - || REGNO (op) >= FIRST_PSEUDO_REGISTER))); -} - -/* Return 1 if the operand is a SYMBOL_REF for a function known to be in - this file. */ - -int -current_file_function_operand (rtx op, - enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return (GET_CODE (op) == SYMBOL_REF - && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op)) - && (SYMBOL_REF_LOCAL_P (op) - || (DECL_RTL_SET_P (current_function_decl) - && op == XEXP (DECL_RTL (current_function_decl), 0)))); -} - -/* Return 1 if this operand is a valid input for a move insn. */ - -int -input_operand (rtx op, enum machine_mode mode) -{ - /* Memory is always valid. */ - if (memory_operand (op, mode)) - return 1; - - /* For floating-point, easy constants are valid. */ - if (GET_MODE_CLASS (mode) == MODE_FLOAT - && CONSTANT_P (op) - && easy_fp_constant (op, mode)) - return 1; - - /* Allow any integer constant. */ - if (GET_MODE_CLASS (mode) == MODE_INT - && (GET_CODE (op) == CONST_INT - || GET_CODE (op) == CONST_DOUBLE)) - return 1; - - /* Allow easy vector constants. */ - if (GET_CODE (op) == CONST_VECTOR - && easy_vector_constant (op, mode)) - return 1; - - /* For floating-point or multi-word mode, the only remaining valid type - is a register. */ - if (GET_MODE_CLASS (mode) == MODE_FLOAT - || GET_MODE_SIZE (mode) > UNITS_PER_WORD) - return register_operand (op, mode); - - /* The only cases left are integral modes one word or smaller (we - do not get called for MODE_CC values). These can be in any - register. */ - if (register_operand (op, mode)) - return 1; - - /* A SYMBOL_REF referring to the TOC is valid. */ - if (legitimate_constant_pool_address_p (op)) - return 1; - - /* A constant pool expression (relative to the TOC) is valid */ - if (toc_relative_expr_p (op)) - return 1; - - /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region - to be valid. */ - if (DEFAULT_ABI == ABI_V4 - && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST) - && small_data_operand (op, Pmode)) - return 1; - - return 0; -} - /* Return TRUE if OP is an invalid SUBREG operation on the e500. */ -static bool + +bool invalid_e500_subreg (rtx op, enum machine_mode mode) { /* Reject (subreg:SI (reg:DF)). */ @@ -3074,19 +2201,6 @@ invalid_e500_subreg (rtx op, enum machine_mode mode) return false; } -/* Just like nonimmediate_operand, but return 0 for invalid SUBREG's - on the e500. */ -int -rs6000_nonimmediate_operand (rtx op, enum machine_mode mode) -{ - if (TARGET_E500_DOUBLE - && GET_CODE (op) == SUBREG - && invalid_e500_subreg (op, mode)) - return 0; - - return nonimmediate_operand (op, mode); -} - /* Darwin, AIX increases natural record alignment to doubleword if the first field is an FP double while the FP fields remain word aligned. */ @@ -3228,7 +2342,7 @@ constant_pool_expr_p (rtx op) return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym; } -static bool +bool toc_relative_expr_p (rtx op) { int have_sym = 0; @@ -3351,13 +2465,13 @@ legitimate_indexed_address_p (rtx x, int strict) && INT_REG_OK_FOR_INDEX_P (op0, strict))); } -static inline bool +inline bool legitimate_indirect_address_p (rtx x, int strict) { return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict); } -static bool +bool macho_lo_sum_memory_operand (rtx x, enum machine_mode mode) { if (!TARGET_MACHO || !flag_pic @@ -3783,15 +2897,6 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model) return dest; } -/* Return 1 if X is a SYMBOL_REF for a TLS symbol. This is used in - instruction definitions. */ - -int -rs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - return RS6000_SYMBOL_REF_TLS_P (x); -} - /* Return 1 if X contains a thread-local symbol. */ bool @@ -9193,225 +8298,6 @@ expand_block_move (rtx operands[]) } -/* Return 1 if OP is suitable for a save_world call in prologue. It is - known to be a PARALLEL. */ -int -save_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int index; - int i; - rtx elt; - int count = XVECLEN (op, 0); - - if (count != 55) - return 0; - - index = 0; - if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER - || GET_CODE (XVECEXP (op, 0, index++)) != USE) - return 0; - - for (i=1; i <= 18; i++) - { - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != MEM - || ! memory_operand (SET_DEST (elt), DFmode) - || GET_CODE (SET_SRC (elt)) != REG - || GET_MODE (SET_SRC (elt)) != DFmode) - return 0; - } - - for (i=1; i <= 12; i++) - { - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != MEM - || GET_CODE (SET_SRC (elt)) != REG - || GET_MODE (SET_SRC (elt)) != V4SImode) - return 0; - } - - for (i=1; i <= 19; i++) - { - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != MEM - || ! memory_operand (SET_DEST (elt), Pmode) - || GET_CODE (SET_SRC (elt)) != REG - || GET_MODE (SET_SRC (elt)) != Pmode) - return 0; - } - - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != MEM - || ! memory_operand (SET_DEST (elt), Pmode) - || GET_CODE (SET_SRC (elt)) != REG - || REGNO (SET_SRC (elt)) != CR2_REGNO - || GET_MODE (SET_SRC (elt)) != Pmode) - return 0; - - if (GET_CODE (XVECEXP (op, 0, index++)) != USE - || GET_CODE (XVECEXP (op, 0, index++)) != USE - || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER) - return 0; - return 1; -} - -/* Return 1 if OP is suitable for a save_world call in prologue. It is - known to be a PARALLEL. */ -int -restore_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int index; - int i; - rtx elt; - int count = XVECLEN (op, 0); - - if (count != 59) - return 0; - - index = 0; - if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN - || GET_CODE (XVECEXP (op, 0, index++)) != USE - || GET_CODE (XVECEXP (op, 0, index++)) != USE - || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER) - return 0; - - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != MEM - || ! memory_operand (SET_SRC (elt), Pmode) - || GET_CODE (SET_DEST (elt)) != REG - || REGNO (SET_DEST (elt)) != CR2_REGNO - || GET_MODE (SET_DEST (elt)) != Pmode) - return 0; - - for (i=1; i <= 19; i++) - { - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != MEM - || ! memory_operand (SET_SRC (elt), Pmode) - || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != Pmode) - return 0; - } - - for (i=1; i <= 12; i++) - { - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != MEM - || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != V4SImode) - return 0; - } - - for (i=1; i <= 18; i++) - { - elt = XVECEXP (op, 0, index++); - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != MEM - || ! memory_operand (SET_SRC (elt), DFmode) - || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != DFmode) - return 0; - } - - if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER - || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER - || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER - || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER - || GET_CODE (XVECEXP (op, 0, index++)) != USE) - return 0; - return 1; -} - - -/* Return 1 if OP is a load multiple operation. It is known to be a - PARALLEL and the first section will be tested. */ - -int -load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0); - unsigned int dest_regno; - rtx src_addr; - int i; - - /* 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); - - 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)) != SImode - || REGNO (SET_DEST (elt)) != dest_regno + i - || GET_CODE (SET_SRC (elt)) != MEM - || GET_MODE (SET_SRC (elt)) != SImode - || 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)) != i * 4) - return 0; - } - - return 1; -} - -/* Similar, but tests for store multiple. Here, the second vector element - is a CLOBBER. It will be tested later. */ - -int -store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0) - 1; - unsigned int src_regno; - rtx dest_addr; - int i; - - /* 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); - - for (i = 1; i < count; i++) - { - rtx elt = XVECEXP (op, 0, i + 1); - - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != REG - || GET_MODE (SET_SRC (elt)) != SImode - || REGNO (SET_SRC (elt)) != src_regno + i - || GET_CODE (SET_DEST (elt)) != MEM - || GET_MODE (SET_DEST (elt)) != SImode - || 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)) != i * 4) - return 0; - } - - return 1; -} - /* Return a string to perform a load_multiple operation. operands[0] is the vector. operands[1] is the source address. @@ -9469,292 +8355,12 @@ rs6000_output_load_multiple (rtx operands[3]) return "{lsi|lswi} %2,%1,%N0"; } -/* Return 1 for a parallel vrsave operation. */ - -int -vrsave_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0); - unsigned int dest_regno, src_regno; - int i; - - 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))) != UNSPEC_VOLATILE) - return 0; - - dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0))); - src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); - - if (dest_regno != VRSAVE_REGNO - && src_regno != VRSAVE_REGNO) - return 0; - - for (i = 1; i < count; i++) - { - rtx elt = XVECEXP (op, 0, i); - - if (GET_CODE (elt) != CLOBBER - && GET_CODE (elt) != SET) - return 0; - } - - return 1; -} - -/* Return 1 for an PARALLEL suitable for mfcr. */ - -int -mfcr_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0); - int i; - - /* Perform a quick check so we don't blow up below. */ - if (count < 1 - || GET_CODE (XVECEXP (op, 0, 0)) != SET - || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC - || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2) - return 0; - - for (i = 0; i < count; i++) - { - rtx exp = XVECEXP (op, 0, i); - rtx unspec; - int maskval; - rtx src_reg; - - src_reg = XVECEXP (SET_SRC (exp), 0, 0); - - if (GET_CODE (src_reg) != REG - || GET_MODE (src_reg) != CCmode - || ! CR_REGNO_P (REGNO (src_reg))) - return 0; - - if (GET_CODE (exp) != SET - || GET_CODE (SET_DEST (exp)) != REG - || GET_MODE (SET_DEST (exp)) != SImode - || ! INT_REGNO_P (REGNO (SET_DEST (exp)))) - return 0; - unspec = SET_SRC (exp); - maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg)); - - if (GET_CODE (unspec) != UNSPEC - || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR - || XVECLEN (unspec, 0) != 2 - || XVECEXP (unspec, 0, 0) != src_reg - || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT - || INTVAL (XVECEXP (unspec, 0, 1)) != maskval) - return 0; - } - return 1; -} - -/* Return 1 for an PARALLEL suitable for mtcrf. */ - -int -mtcrf_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0); - int i; - rtx src_reg; - - /* Perform a quick check so we don't blow up below. */ - if (count < 1 - || GET_CODE (XVECEXP (op, 0, 0)) != SET - || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC - || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2) - return 0; - src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0); - - if (GET_CODE (src_reg) != REG - || GET_MODE (src_reg) != SImode - || ! INT_REGNO_P (REGNO (src_reg))) - return 0; - - for (i = 0; i < count; i++) - { - rtx exp = XVECEXP (op, 0, i); - rtx unspec; - int maskval; - - if (GET_CODE (exp) != SET - || GET_CODE (SET_DEST (exp)) != REG - || GET_MODE (SET_DEST (exp)) != CCmode - || ! CR_REGNO_P (REGNO (SET_DEST (exp)))) - return 0; - unspec = SET_SRC (exp); - maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp))); - - if (GET_CODE (unspec) != UNSPEC - || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR - || XVECLEN (unspec, 0) != 2 - || XVECEXP (unspec, 0, 0) != src_reg - || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT - || INTVAL (XVECEXP (unspec, 0, 1)) != maskval) - return 0; - } - return 1; -} - -/* Return 1 for an PARALLEL suitable for lmw. */ - -int -lmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0); - unsigned int dest_regno; - rtx src_addr; - unsigned int base_regno; - HOST_WIDE_INT offset; - int i; - - /* 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); - - if (dest_regno > 31 - || count != 32 - (int) dest_regno) - return 0; - - if (legitimate_indirect_address_p (src_addr, 0)) - { - offset = 0; - base_regno = REGNO (src_addr); - if (base_regno == 0) - return 0; - } - else if (rs6000_legitimate_offset_address_p (SImode, src_addr, 0)) - { - offset = INTVAL (XEXP (src_addr, 1)); - base_regno = REGNO (XEXP (src_addr, 0)); - } - else - return 0; - - for (i = 0; i < count; i++) - { - rtx elt = XVECEXP (op, 0, i); - rtx newaddr; - rtx addr_reg; - HOST_WIDE_INT newoffset; - - if (GET_CODE (elt) != SET - || GET_CODE (SET_DEST (elt)) != REG - || GET_MODE (SET_DEST (elt)) != SImode - || REGNO (SET_DEST (elt)) != dest_regno + i - || GET_CODE (SET_SRC (elt)) != MEM - || GET_MODE (SET_SRC (elt)) != SImode) - return 0; - newaddr = XEXP (SET_SRC (elt), 0); - if (legitimate_indirect_address_p (newaddr, 0)) - { - newoffset = 0; - addr_reg = newaddr; - } - else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0)) - { - addr_reg = XEXP (newaddr, 0); - newoffset = INTVAL (XEXP (newaddr, 1)); - } - else - return 0; - if (REGNO (addr_reg) != base_regno - || newoffset != offset + 4 * i) - return 0; - } - - return 1; -} - -/* Return 1 for an PARALLEL suitable for stmw. */ - -int -stmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - int count = XVECLEN (op, 0); - unsigned int src_regno; - rtx dest_addr; - unsigned int base_regno; - HOST_WIDE_INT offset; - int i; - - /* 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); - - if (src_regno > 31 - || count != 32 - (int) src_regno) - return 0; - - if (legitimate_indirect_address_p (dest_addr, 0)) - { - offset = 0; - base_regno = REGNO (dest_addr); - if (base_regno == 0) - return 0; - } - else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, 0)) - { - offset = INTVAL (XEXP (dest_addr, 1)); - base_regno = REGNO (XEXP (dest_addr, 0)); - } - else - return 0; - - for (i = 0; i < count; i++) - { - rtx elt = XVECEXP (op, 0, i); - rtx newaddr; - rtx addr_reg; - HOST_WIDE_INT newoffset; - - if (GET_CODE (elt) != SET - || GET_CODE (SET_SRC (elt)) != REG - || GET_MODE (SET_SRC (elt)) != SImode - || REGNO (SET_SRC (elt)) != src_regno + i - || GET_CODE (SET_DEST (elt)) != MEM - || GET_MODE (SET_DEST (elt)) != SImode) - return 0; - newaddr = XEXP (SET_DEST (elt), 0); - if (legitimate_indirect_address_p (newaddr, 0)) - { - newoffset = 0; - addr_reg = newaddr; - } - else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0)) - { - addr_reg = XEXP (newaddr, 0); - newoffset = INTVAL (XEXP (newaddr, 1)); - } - else - return 0; - if (REGNO (addr_reg) != base_regno - || newoffset != offset + 4 * i) - return 0; - } - - return 1; -} /* A validation routine: say whether CODE, a condition code, and MODE match. The other alternatives either don't make sense or should never be generated. */ -static void +void validate_condition_mode (enum rtx_code code, enum machine_mode mode) { if ((GET_RTX_CLASS (code) != RTX_COMPARE @@ -9793,82 +8399,6 @@ validate_condition_mode (enum rtx_code code, enum machine_mode mode) abort (); } -/* Return 1 if OP is a comparison operation that is valid for a branch insn. - We only check the opcode against the mode of the CC value here. */ - -int -branch_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - enum rtx_code code = GET_CODE (op); - enum machine_mode cc_mode; - - if (!COMPARISON_P (op)) - return 0; - - cc_mode = GET_MODE (XEXP (op, 0)); - if (GET_MODE_CLASS (cc_mode) != MODE_CC) - return 0; - - validate_condition_mode (code, cc_mode); - - return 1; -} - -/* Return 1 if OP is a comparison operation that is valid for a branch - insn and which is true if the corresponding bit in the CC register - is set. */ - -int -branch_positive_comparison_operator (rtx op, enum machine_mode mode) -{ - enum rtx_code code; - - if (! branch_comparison_operator (op, mode)) - return 0; - - code = GET_CODE (op); - return (code == EQ || code == LT || code == GT - || code == LTU || code == GTU - || code == UNORDERED); -} - -/* Return 1 if OP is a comparison operation that is valid for an scc - insn: it must be a positive comparison. */ - -int -scc_comparison_operator (rtx op, enum machine_mode mode) -{ - return branch_positive_comparison_operator (op, mode); -} - -int -trap_comparison_operator (rtx op, enum machine_mode mode) -{ - if (mode != VOIDmode && mode != GET_MODE (op)) - return 0; - return COMPARISON_P (op); -} - -int -boolean_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - enum rtx_code code = GET_CODE (op); - return (code == AND || code == IOR || code == XOR); -} - -int -boolean_or_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - enum rtx_code code = GET_CODE (op); - return (code == IOR || code == XOR); -} - -int -min_max_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) -{ - enum rtx_code code = GET_CODE (op); - return (code == SMIN || code == SMAX || code == UMIN || code == UMAX); -} /* Return 1 if ANDOP is a mask that has no bits on that are not in the mask required to convert the result of a rotate insn into a shift diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 1a2d12d..9b8f1fd 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -251,6 +251,10 @@ extern int target_flags; #define HAVE_AS_TLS 0 #endif +/* Return 1 for a symbol ref for a thread-local storage symbol. */ +#define RS6000_SYMBOL_REF_TLS_P(RTX) \ + (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0) + #ifdef IN_LIBGCC2 /* For libgcc2 we make sure this is a compile time constant */ #if defined (__64BIT__) || defined (__powerpc64__) @@ -1931,6 +1935,9 @@ typedef struct rs6000_args || easy_vector_constant (X, GET_MODE (X))) \ && !rs6000_tls_referenced_p (X)) +#define EASY_VECTOR_15(n) ((n) >= -16 && (n) <= 15) +#define EASY_VECTOR_15_ADD_SELF(n) ((n) >= 0x10 && (n) <= 0x1e && !((n) & 1)) + /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. We have two alternate definitions for each of them. @@ -2538,87 +2545,6 @@ extern char rs6000_reg_names[][8]; /* register names (0 vs. %r0). */ #define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR) -/* Define the codes that are matched by predicates in rs6000.c. */ - -#define PREDICATE_CODES \ - {"any_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ - LABEL_REF, SUBREG, REG, MEM}}, \ - {"any_parallel_operand", {PARALLEL}}, \ - {"zero_constant", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \ - LABEL_REF, SUBREG, REG, MEM}}, \ - {"short_cint_operand", {CONST_INT}}, \ - {"u_short_cint_operand", {CONST_INT}}, \ - {"non_short_cint_operand", {CONST_INT}}, \ - {"exact_log2_cint_operand", {CONST_INT}}, \ - {"gpc_reg_operand", {SUBREG, REG}}, \ - {"cc_reg_operand", {SUBREG, REG}}, \ - {"cc_reg_not_cr0_operand", {SUBREG, REG}}, \ - {"reg_or_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_neg_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_aligned_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_u_short_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_arith_cint_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_add_cint64_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_sub_cint64_operand", {SUBREG, REG, CONST_INT}}, \ - {"reg_or_logical_cint_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ - {"got_operand", {SYMBOL_REF, CONST, LABEL_REF}}, \ - {"got_no_const_operand", {SYMBOL_REF, LABEL_REF}}, \ - {"easy_fp_constant", {CONST_DOUBLE}}, \ - {"easy_vector_constant", {CONST_VECTOR}}, \ - {"easy_vector_constant_add_self", {CONST_VECTOR}}, \ - {"zero_fp_constant", {CONST_DOUBLE}}, \ - {"reg_or_mem_operand", {SUBREG, MEM, REG}}, \ - {"lwa_operand", {SUBREG, MEM, REG}}, \ - {"volatile_mem_operand", {MEM}}, \ - {"offsettable_mem_operand", {MEM}}, \ - {"mem_or_easy_const_operand", {SUBREG, MEM, CONST_DOUBLE}}, \ - {"add_operand", {SUBREG, REG, CONST_INT}}, \ - {"non_add_cint_operand", {CONST_INT}}, \ - {"and_operand", {SUBREG, REG, CONST_INT}}, \ - {"and64_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ - {"and64_2_operand", {SUBREG, REG, CONST_INT}}, \ - {"logical_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \ - {"non_logical_cint_operand", {CONST_INT, CONST_DOUBLE}}, \ - {"mask_operand", {CONST_INT}}, \ - {"mask_operand_wrap", {CONST_INT}}, \ - {"mask64_operand", {CONST_INT}}, \ - {"mask64_2_operand", {CONST_INT}}, \ - {"count_register_operand", {REG}}, \ - {"xer_operand", {REG}}, \ - {"symbol_ref_operand", {SYMBOL_REF}}, \ - {"rs6000_tls_symbol_ref", {SYMBOL_REF}}, \ - {"call_operand", {SYMBOL_REF, REG}}, \ - {"current_file_function_operand", {SYMBOL_REF}}, \ - {"input_operand", {SUBREG, MEM, REG, CONST_INT, \ - CONST_DOUBLE, SYMBOL_REF}}, \ - {"rs6000_nonimmediate_operand", {SUBREG, MEM, REG}}, \ - {"load_multiple_operation", {PARALLEL}}, \ - {"store_multiple_operation", {PARALLEL}}, \ - {"lmw_operation", {PARALLEL}}, \ - {"stmw_operation", {PARALLEL}}, \ - {"vrsave_operation", {PARALLEL}}, \ - {"save_world_operation", {PARALLEL}}, \ - {"restore_world_operation", {PARALLEL}}, \ - {"mfcr_operation", {PARALLEL}}, \ - {"mtcrf_operation", {PARALLEL}}, \ - {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \ - GT, LEU, LTU, GEU, GTU, \ - UNORDERED, ORDERED, \ - UNGE, UNLE }}, \ - {"branch_positive_comparison_operator", {EQ, LT, GT, LTU, GTU, \ - UNORDERED }}, \ - {"scc_comparison_operator", {EQ, NE, LE, LT, GE, \ - GT, LEU, LTU, GEU, GTU, \ - UNORDERED, ORDERED, \ - UNGE, UNLE }}, \ - {"trap_comparison_operator", {EQ, NE, LE, LT, GE, \ - GT, LEU, LTU, GEU, GTU}}, \ - {"boolean_operator", {AND, IOR, XOR}}, \ - {"boolean_or_operator", {IOR, XOR}}, \ - {"altivec_register_operand", {REG}}, \ - {"min_max_operator", {SMIN, SMAX, UMIN, UMAX}}, - /* uncomment for disabling the corresponding default options */ /* #define MACHINE_no_sched_interblock */ /* #define MACHINE_no_sched_speculative */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index bf2bf4c..5f297cc 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -101,6 +101,9 @@ (include "8540.md") (include "power4.md") (include "power5.md") + +(include "predicates.md") + (include "darwin.md") |