Commit 48d72335 by David Edelsohn Committed by David Edelsohn

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
parent 2203a881
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.
......
;; 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;
})
......@@ -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);
......
......@@ -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);
......@@ -854,10 +843,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
#define TARGET_ATTRIBUTE_TABLE rs6000_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,104 +1958,35 @@ 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. */
/* Generate easy_vector_constant out of a easy_vector_constant_add_self. */
int
easy_vector_constant (rtx op, enum machine_mode mode)
rtx
gen_easy_vector_constant_add_self (rtx op)
{
int cst, cst2;
int i, units;
rtvec v;
units = GET_MODE_NUNITS (GET_MODE (op));
v = rtvec_alloc (units);
if (GET_CODE (op) != CONST_VECTOR
|| (!TARGET_ALTIVEC
&& !TARGET_SPE))
return 0;
for (i = 0; i < units; i++)
RTVEC_ELT (v, i) =
GEN_INT (INTVAL (CONST_VECTOR_ELT (op, i)) >> 1);
return gen_rtx_raw_CONST_VECTOR (GET_MODE (op), v);
}
if (zero_constant (op, mode)
&& ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
|| (TARGET_SPE && SPE_VECTOR_MODE (mode))))
return 1;
const char *
output_vec_const_move (rtx *operands)
{
int cst, cst2;
enum machine_mode mode;
rtx dest, vec;
if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
return 0;
dest = operands[0];
vec = operands[1];
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
gen_easy_vector_constant_add_self (rtx op)
{
int i, units;
rtvec v;
units = GET_MODE_NUNITS (GET_MODE (op));
v = rtvec_alloc (units);
for (i = 0; i < units; i++)
RTVEC_ELT (v, i) =
GEN_INT (INTVAL (CONST_VECTOR_ELT (op, i)) >> 1);
return gen_rtx_raw_CONST_VECTOR (GET_MODE (op), v);
}
const char *
output_vec_const_move (rtx *operands)
{
int cst, cst2;
enum machine_mode mode;
rtx dest, vec;
dest = operands[0];
vec = operands[1];
cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
mode = GET_MODE (dest);
cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
mode = GET_MODE (dest);
if (TARGET_ALTIVEC)
{
......@@ -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,241 +2179,63 @@ 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. */
/* Return TRUE if OP is an invalid SUBREG operation on the e500. */
int
and64_operand (rtx op, enum machine_mode mode)
bool
invalid_e500_subreg (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. */
/* Reject (subreg:SI (reg:DF)). */
if (GET_CODE (op) == SUBREG
&& mode == SImode
&& REG_P (SUBREG_REG (op))
&& GET_MODE (SUBREG_REG (op)) == DFmode)
return true;
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);
/* Reject (subreg:DF (reg:DI)). */
if (GET_CODE (op) == SUBREG
&& mode == DFmode
&& REG_P (SUBREG_REG (op))
&& GET_MODE (SUBREG_REG (op)) == DImode)
return true;
return logical_operand (op, mode) || mask64_1or2_operand (op, mode, true);
return false;
}
/* 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. */
/* Darwin, AIX increases natural record alignment to doubleword if the first
field is an FP double while the FP fields remain word aligned. */
int
and_operand (rtx op, enum machine_mode mode)
unsigned int
rs6000_special_round_type_align (tree type, int computed, int specified)
{
if (fixed_regs[CR0_REGNO]) /* CR0 not available, don't do andi./andis. */
return (gpc_reg_operand (op, mode) || mask_operand (op, mode));
tree field = TYPE_FIELDS (type);
return (logical_operand (op, mode) || mask_operand (op, mode));
}
/* Skip all non field decls */
while (field != NULL && TREE_CODE (field) != FIELD_DECL)
field = TREE_CHAIN (field);
/* Return 1 if the operand is a general register or memory operand. */
if (field == NULL || field == type || DECL_MODE (field) != DFmode)
return MAX (computed, specified);
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 MAX (MAX (computed, specified), 64);
}
/* 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. */
/* Return 1 for an operand in small memory on V.4/eabi. */
int
lwa_operand (rtx op, enum machine_mode mode)
small_data_operand (rtx op ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
rtx inner = op;
#if TARGET_ELF
rtx sym_ref;
if (reload_completed && GET_CODE (inner) == SUBREG)
inner = SUBREG_REG (inner);
if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
return 0;
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));
}
if (DEFAULT_ABI != ABI_V4)
return 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
invalid_e500_subreg (rtx op, enum machine_mode mode)
{
/* Reject (subreg:SI (reg:DF)). */
if (GET_CODE (op) == SUBREG
&& mode == SImode
&& REG_P (SUBREG_REG (op))
&& GET_MODE (SUBREG_REG (op)) == DFmode)
return true;
/* Reject (subreg:DF (reg:DI)). */
if (GET_CODE (op) == SUBREG
&& mode == DFmode
&& REG_P (SUBREG_REG (op))
&& GET_MODE (SUBREG_REG (op)) == DImode)
return true;
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. */
unsigned int
rs6000_special_round_type_align (tree type, int computed, int specified)
{
tree field = TYPE_FIELDS (type);
/* Skip all non field decls */
while (field != NULL && TREE_CODE (field) != FIELD_DECL)
field = TREE_CHAIN (field);
if (field == NULL || field == type || DECL_MODE (field) != DFmode)
return MAX (computed, specified);
return MAX (MAX (computed, specified), 64);
}
/* Return 1 for an operand in small memory on V.4/eabi. */
int
small_data_operand (rtx op ATTRIBUTE_UNUSED,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
#if TARGET_ELF
rtx sym_ref;
if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
return 0;
if (DEFAULT_ABI != ABI_V4)
return 0;
if (GET_CODE (op) == SYMBOL_REF)
sym_ref = op;
if (GET_CODE (op) == SYMBOL_REF)
sym_ref = op;
else if (GET_CODE (op) != CONST
|| GET_CODE (XEXP (op, 0)) != PLUS
......@@ -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
......
......@@ -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 */
......
......@@ -101,6 +101,9 @@
(include "8540.md")
(include "power4.md")
(include "power5.md")
(include "predicates.md")
(include "darwin.md")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment