sparc.c (reg_or_0_operand, [...]): Delete.

* config/sparc/sparc.c (reg_or_0_operand, const1_operand,
	fp_zero_operand, fp_register_operand, intreg_operand,
	fcc_reg_operand, fcc0_reg_operand, icc_or_fcc_reg_operand,
	call_operand, call_operand_address, tgd_symbolic_operand,
	tld_symbolic_operand, tie_symbolic_operand, tle_symbolic_operand,
	symbolic_operand, symbolic_memory_operand, label_ref_operand,
	sp64_medium_pic_operand, data_segment_operand,
	text_segment_operand, splittable_symbolic_memory_operand,
	reg_or_nonsymb_mem_operand, splittable_immediate_memory_operand,
	eq_or_neq, normal_comp_operator, noov_compare_op,
	noov_compare64_op, v9_regcmp_op, extend_op, cc_arithop,
	cc_arithopn, arith_operand, arith_4096_operand, arith_add_operand,
	const64_operand, const64_high_operand, arith11_operand,
	arith10_operand, arith_double_operand, arith_double_4096_operand,
	arith_double_add_operand, arith11_double_operand,
	arith10_double_operand, small_int, small_int_or_double,
	uns_small_int, uns_arith_operand, clobbered_register,
	input_operand, compare_operand): Delete.
	(sparc_emit_set_const32): Use predicates in assertion.  Remove special
	code for TARGET_ARCH64 && HOST_BITS_PER_WIDE_INT != 64.
	(sparc_emit_set_const64): Call gcc_unreachable if H_B_P_W_I == 32.
	(GEN_HIGHINT64, GEN_INT64): Delete.
	(sparc_emit_set_safe_HIGH64, gen_safe_SET64, gen_safe_OR64,
	gen_safe_XOR64): Adjust for above deletion.
	(sparc_emit_set_const64): Support only H_B_P_W_I == 64 and CONST_INTs.
	Use 'unsigned HOST_WIDE_INT' instead of 'long' for bitmask.
	(legitimate_constant_p): Use const_zero_operand instead.
	(sparc_extra_constraint_check): Likewise.
	* config/sparc/sparc.h (CONST_DOUBLE_OK_FOR_LETTER_P): Remove 'O'.
	(PREFERRED_RELOAD_CLASS): Use const_zero_operand.
	(PREDICATE_CODES): Delete.
	* config/sparc/sparc.md: Include predicates.md.
	(All patterns): Adjust for new predicate names.
	(cmpdi, cmpdi_sp64): Use arith_operand predicate.
	(movhi_const64_special, movsi_const64_special): Add 'K' constraint.
	(movdi): Use general_operand predicate.
	(movdi_sp64_dbl): Delete.
	(movdi_const64_special): Add 'N' constraint.
	(movdicc): Use arith10_operand predicate.
	(movdi_cc_sp64, movdi_cc_sp64_trunc): Use arith11_operand predicate.
	(movdi_cc_reg_sp64): Use arith10_operand predicate.
	(movdi_cc_reg_sp64_trunc): Delete.
	(cmp_zero_extract, cmp_zero_extract_sp64): Use small_int_operand.
	(adddi3_insn_sp32, addx, cmp_cc_plus, cmp_ccx_plus, cmp_cc_plus_set,
	cmp_ccx_plus_set): Use register_operand predicate.
	(adddi3_sp64, cmp_ccx_plus_set): Use arith_operand predicate.
	(subdi3_sp32): Delete.
	(subdi3_insn_sp32): Change to define_insn_and_split.
	(subdi3_sp64, cmp_minus_ccx, cmp_minus_ccx_set): Use arith_operand.
	(muldi3, muldi3_sp64, muldi3_v8plus): Likewise.
	(smulsi3_highpart_v8plus, const_smulsi3_highpart_v8plus,
	umulsi3_highpart_v8plus, const_umulsi3_highpart_v8plus): Use
	small_int_operand predicate.
	(divdi3, udivdi3): Use arith_operand predicate.
	(udivsi3, udivsi3_sp32, udivsi3_sp64): Use nonimmediate_operand.
	(and<V64I>3_sp64, ior<V64I>3_sp64, xor<V64I:mode>3_sp64,
	xor_not_<V64I:mode>_sp64) : Use arith_operand predicate.
	(xordi3_sp64_dbl): Delete.
	(cmp_ccx_arith_op, cmp_ccx_arith_op_set, cmp_ccx_xor_not,
	cmp_ccx_xor_not_set, cmp_ccx_arith_op_not, cmp_ccx_arith_op_not_set,
	cmp_ccx_neg, cmp_ccx_set_neg, one_cmpl<V64I>2_sp64, cmp_ccx_not,
	cmp_ccx_set_not): Use arith_operand predicate.
	(ashrsi3_extend2, lshrsi3_extend2 et al.): Use small_int_operand.
	* config/sparc/predicates.md: New file.

From-SVN: r98494
This commit is contained in:
Eric Botcazou 2005-04-21 08:37:52 +02:00 committed by Eric Botcazou
parent b9850b3d44
commit 0e5d569cd5
5 changed files with 941 additions and 1390 deletions

View File

@ -1,3 +1,70 @@
2005-04-21 Eric Botcazou <ebotcazou@libertysurf.fr>
* config/sparc/sparc.c (reg_or_0_operand, const1_operand,
fp_zero_operand, fp_register_operand, intreg_operand,
fcc_reg_operand, fcc0_reg_operand, icc_or_fcc_reg_operand,
call_operand, call_operand_address, tgd_symbolic_operand,
tld_symbolic_operand, tie_symbolic_operand, tle_symbolic_operand,
symbolic_operand, symbolic_memory_operand, label_ref_operand,
sp64_medium_pic_operand, data_segment_operand,
text_segment_operand, splittable_symbolic_memory_operand,
reg_or_nonsymb_mem_operand, splittable_immediate_memory_operand,
eq_or_neq, normal_comp_operator, noov_compare_op,
noov_compare64_op, v9_regcmp_op, extend_op, cc_arithop,
cc_arithopn, arith_operand, arith_4096_operand, arith_add_operand,
const64_operand, const64_high_operand, arith11_operand,
arith10_operand, arith_double_operand, arith_double_4096_operand,
arith_double_add_operand, arith11_double_operand,
arith10_double_operand, small_int, small_int_or_double,
uns_small_int, uns_arith_operand, clobbered_register,
input_operand, compare_operand): Delete.
(sparc_emit_set_const32): Use predicates in assertion. Remove special
code for TARGET_ARCH64 && HOST_BITS_PER_WIDE_INT != 64.
(sparc_emit_set_const64): Call gcc_unreachable if H_B_P_W_I == 32.
(GEN_HIGHINT64, GEN_INT64): Delete.
(sparc_emit_set_safe_HIGH64, gen_safe_SET64, gen_safe_OR64,
gen_safe_XOR64): Adjust for above deletion.
(sparc_emit_set_const64): Support only H_B_P_W_I == 64 and CONST_INTs.
Use 'unsigned HOST_WIDE_INT' instead of 'long' for bitmask.
(legitimate_constant_p): Use const_zero_operand instead.
(sparc_extra_constraint_check): Likewise.
* config/sparc/sparc.h (CONST_DOUBLE_OK_FOR_LETTER_P): Remove 'O'.
(PREFERRED_RELOAD_CLASS): Use const_zero_operand.
(PREDICATE_CODES): Delete.
* config/sparc/sparc.md: Include predicates.md.
(All patterns): Adjust for new predicate names.
(cmpdi, cmpdi_sp64): Use arith_operand predicate.
(movhi_const64_special, movsi_const64_special): Add 'K' constraint.
(movdi): Use general_operand predicate.
(movdi_sp64_dbl): Delete.
(movdi_const64_special): Add 'N' constraint.
(movdicc): Use arith10_operand predicate.
(movdi_cc_sp64, movdi_cc_sp64_trunc): Use arith11_operand predicate.
(movdi_cc_reg_sp64): Use arith10_operand predicate.
(movdi_cc_reg_sp64_trunc): Delete.
(cmp_zero_extract, cmp_zero_extract_sp64): Use small_int_operand.
(adddi3_insn_sp32, addx, cmp_cc_plus, cmp_ccx_plus, cmp_cc_plus_set,
cmp_ccx_plus_set): Use register_operand predicate.
(adddi3_sp64, cmp_ccx_plus_set): Use arith_operand predicate.
(subdi3_sp32): Delete.
(subdi3_insn_sp32): Change to define_insn_and_split.
(subdi3_sp64, cmp_minus_ccx, cmp_minus_ccx_set): Use arith_operand.
(muldi3, muldi3_sp64, muldi3_v8plus): Likewise.
(smulsi3_highpart_v8plus, const_smulsi3_highpart_v8plus,
umulsi3_highpart_v8plus, const_umulsi3_highpart_v8plus): Use
small_int_operand predicate.
(divdi3, udivdi3): Use arith_operand predicate.
(udivsi3, udivsi3_sp32, udivsi3_sp64): Use nonimmediate_operand.
(and<V64I>3_sp64, ior<V64I>3_sp64, xor<V64I:mode>3_sp64,
xor_not_<V64I:mode>_sp64) : Use arith_operand predicate.
(xordi3_sp64_dbl): Delete.
(cmp_ccx_arith_op, cmp_ccx_arith_op_set, cmp_ccx_xor_not,
cmp_ccx_xor_not_set, cmp_ccx_arith_op_not, cmp_ccx_arith_op_not_set,
cmp_ccx_neg, cmp_ccx_set_neg, one_cmpl<V64I>2_sp64, cmp_ccx_not,
cmp_ccx_set_not): Use arith_operand predicate.
(ashrsi3_extend2, lshrsi3_extend2 et al.): Use small_int_operand.
* config/sparc/predicates.md: New file.
2005-04-21 Kazu Hirata <kazu@cs.umass.edu>
PR tree-optimization/14846

View File

@ -0,0 +1,456 @@
;; Predicate definitions for SPARC.
;; 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.
;; Predicates for numerical constants.
;; Return true if OP is the zero constant for MODE.
(define_predicate "const_zero_operand"
(and (match_code "const_int,const_double,const_vector")
(match_test "op == CONST0_RTX (mode)")))
;; Return true if OP is the one constant for MODE.
(define_predicate "const_one_operand"
(and (match_code "const_int,const_double,const_vector")
(match_test "op == CONST1_RTX (mode)")))
;; Return true if OP is the integer constant 4096.
(define_predicate "const_4096_operand"
(and (match_code "const_int")
(match_test "INTVAL (op) == 4096")))
;; Return true if OP is a constant that is representable by a 13-bit
;; signed field. This is an acceptable immediate operand for most
;; 3-address instructions.
(define_predicate "small_int_operand"
(and (match_code "const_int")
(match_test "SPARC_SIMM13_P (INTVAL (op))")))
;; Return true if OP is a constant operand for the umul instruction. That
;; instruction sign-extends immediate values just like all other SPARC
;; instructions, but interprets the extended result as an unsigned number.
(define_predicate "uns_small_int_operand"
(match_code "const_int,const_double")
{
#if HOST_BITS_PER_WIDE_INT == 32
return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
#else
return (GET_CODE (op) == CONST_INT
&& ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
|| (INTVAL (op) >= 0xFFFFF000
&& INTVAL (op) <= 0xFFFFFFFF)));
#endif
})
;; Return true if OP is a constant that can be loaded by the sethi instruction.
;; The first test avoids emitting sethi to load zero for example.
(define_predicate "const_high_operand"
(and (match_code "const_int")
(and (match_test "INTVAL (op) & ~(HOST_WIDE_INT)0x3ff")
(match_test "SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))"))))
;; Predicates for symbolic constants.
;; Return true if OP is either a symbol reference or a sum of a symbol
;; reference and a constant.
(define_predicate "symbolic_operand"
(match_code "symbol_ref,label_ref,const")
{
enum machine_mode omode = GET_MODE (op);
if (omode != mode && omode != VOIDmode && mode != VOIDmode)
return false;
switch (GET_CODE (op))
{
case SYMBOL_REF:
return !SYMBOL_REF_TLS_MODEL (op);
case LABEL_REF:
return true;
case CONST:
op = XEXP (op, 0);
return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
gcc_unreachable ();
}
})
;; Return true if OP is a symbolic operand for the TLS Global Dynamic model.
(define_predicate "tgd_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "tls_symbolic_operand (op) == TLS_MODEL_GLOBAL_DYNAMIC")))
;; Return true if OP is a symbolic operand for the TLS Local Dynamic model.
(define_predicate "tld_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "tls_symbolic_operand (op) == TLS_MODEL_LOCAL_DYNAMIC")))
;; Return true if OP is a symbolic operand for the TLS Initial Exec model.
(define_predicate "tie_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "tls_symbolic_operand (op) == TLS_MODEL_INITIAL_EXEC")))
;; Return true if OP is a symbolic operand for the TLS Local Exec model.
(define_predicate "tle_symbolic_operand"
(and (match_code "symbol_ref")
(match_test "tls_symbolic_operand (op) == TLS_MODEL_LOCAL_EXEC")))
;; Return true if the operand is an argument used in generating PIC references
;; in either the medium/low or embedded medium/anywhere code models on V9.
;; Check for (const (minus (symbol_ref:GOT)
;; (const (minus (label) (pc)))))
(define_predicate "medium_pic_operand"
(match_code "const")
{
/* Check for (const (minus (symbol_ref:GOT)
(const (minus (label) (pc))))). */
op = XEXP (op, 0);
return GET_CODE (op) == MINUS
&& GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& GET_CODE (XEXP (op, 1)) == CONST
&& GET_CODE (XEXP (XEXP (op, 1), 0)) == MINUS;
})
;; Return true if OP is a LABEL_REF of mode MODE.
(define_predicate "label_ref_operand"
(and (match_code "label_ref")
(match_test "GET_MODE (op) == mode")))
;; Return true if OP is a data segment reference. This includes the readonly
;; data segment or, in other words, anything but the text segment.
;; This is needed in the embedded medium/anywhere code model on V9. These
;; values are accessed with EMBMEDANY_BASE_REG. */
(define_predicate "data_segment_operand"
(match_code "symbol_ref,plus,const")
{
switch (GET_CODE (op))
{
case SYMBOL_REF :
return ! SYMBOL_REF_FUNCTION_P (op);
case PLUS :
/* Assume canonical format of symbol + constant.
Fall through. */
case CONST :
return data_segment_operand (XEXP (op, 0), VOIDmode);
default :
gcc_unreachable ();
}
})
;; Return true if OP is a text segment reference.
;; This is needed in the embedded medium/anywhere code model on V9.
(define_predicate "text_segment_operand"
(match_code "label_ref,symbol_ref,plus,const")
{
switch (GET_CODE (op))
{
case LABEL_REF :
return true;
case SYMBOL_REF :
return SYMBOL_REF_FUNCTION_P (op);
case PLUS :
/* Assume canonical format of symbol + constant.
Fall through. */
case CONST :
return text_segment_operand (XEXP (op, 0), VOIDmode);
default :
gcc_unreachable ();
}
})
;; Predicates for registers.
;; Return true if OP is either the zero constant or a register.
(define_predicate "register_or_zero_operand"
(ior (match_operand 0 "register_operand")
(match_operand 0 "const_zero_operand")))
;; Return true if OP is a register operand in a floating point register.
(define_predicate "fp_register_operand"
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op); /* Possibly a MEM */
return REG_P (op) && SPARC_FP_REG_P (REGNO (op));
})
;; Return true if OP is an integer register.
(define_special_predicate "int_register_operand"
(ior (match_test "register_operand (op, SImode)")
(match_test "TARGET_ARCH64 && register_operand (op, DImode)")))
;; Return true if OP is a floating point condition code register.
(define_predicate "fcc_register_operand"
(match_code "reg")
{
if (mode != VOIDmode && mode != GET_MODE (op))
return false;
if (mode == VOIDmode
&& (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
return false;
#if 0 /* ??? 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */
if (reg_renumber == 0)
return REGNO (op) >= FIRST_PSEUDO_REGISTER;
return REGNO_OK_FOR_CCFP_P (REGNO (op));
#else
return ((unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG) < 4;
#endif
})
;; Return true if OP is the floating point condition code register fcc0.
(define_predicate "fcc0_register_operand"
(match_code "reg")
{
if (mode != VOIDmode && mode != GET_MODE (op))
return false;
if (mode == VOIDmode
&& (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
return false;
return REGNO (op) == SPARC_FCC_REG;
})
;; Return true if OP is an integer or floating point condition code register.
(define_predicate "icc_or_fcc_register_operand"
(match_code "reg")
{
if (REGNO (op) == SPARC_ICC_REG)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return false;
if (mode == VOIDmode
&& GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
return false;
return true;
}
return fcc_register_operand (op, mode);
})
;; Predicates for arithmetic instructions.
;; Return true if OP is a register, or is a constant that is representable
;; by a 13-bit signed field. This is an acceptable operand for most
;; 3-address instructions.
(define_predicate "arith_operand"
(ior (match_operand 0 "register_operand")
(match_operand 0 "small_int_operand")))
;; 64-bit: Same as above.
;; 32-bit: Return true if OP is a register, or is a constant that is
;; representable by a couple of 13-bit signed fields. This is an
;; acceptable operand for most 3-address splitters.
(define_predicate "arith_double_operand"
(match_code "const_int,const_double,reg,subreg")
{
bool arith_simple_operand = arith_operand (op, mode);
HOST_WIDE_INT m1, m2;
if (TARGET_ARCH64 || arith_simple_operand)
return arith_simple_operand;
#if HOST_BITS_PER_WIDE_INT == 32
if (GET_CODE (op) != CONST_DOUBLE)
return false;
m1 = CONST_DOUBLE_LOW (op);
m2 = CONST_DOUBLE_HIGH (op);
#else
if (GET_CODE (op) != CONST_INT)
return false;
m1 = INTVAL (op) & 0xffffffff;
m2 = INTVAL (op) >> 32;
#endif
return SPARC_SIMM13_P (m1) && SPARC_SIMM13_P (m2);
})
;; Return true if OP is suitable as second operand for add/sub.
(define_predicate "arith_add_operand"
(ior (match_operand 0 "arith_operand")
(match_operand 0 "const_4096_operand")))
;; Return true if OP is suitable as second double operand for add/sub.
(define_predicate "arith_double_add_operand"
(match_code "const_int,const_double,reg,subreg")
{
bool _arith_double_operand = arith_double_operand (op, mode);
if (_arith_double_operand)
return true;
return TARGET_ARCH64 && const_4096_operand (op, mode);
})
;; Return true if OP is a register, or is a CONST_INT that can fit in a
;; signed 10-bit immediate field. This is an acceptable SImode operand for
;; the movrcc instructions.
(define_predicate "arith10_operand"
(ior (match_operand 0 "register_operand")
(and (match_code "const_int")
(match_test "SPARC_SIMM10_P (INTVAL (op))"))))
;; Return true if OP is a register, or is a CONST_INT that can fit in a
;; signed 11-bit immediate field. This is an acceptable SImode operand for
;; the movcc instructions.
(define_predicate "arith11_operand"
(ior (match_operand 0 "register_operand")
(and (match_code "const_int")
(match_test "SPARC_SIMM11_P (INTVAL (op))"))))
;; Return true if OP is a register or a constant for the umul instruction.
(define_predicate "uns_arith_operand"
(ior (match_operand 0 "register_operand")
(match_operand 0 "uns_small_int_operand")))
;; Predicates for miscellanous instructions.
;; Return true if OP is valid for the lhs of a comparison insn.
(define_predicate "compare_operand"
(match_code "reg, subreg, zero_extract")
{
if (GET_CODE (op) == ZERO_EXTRACT)
return (register_operand (XEXP (op, 0), mode)
&& small_int_operand (XEXP (op, 1), mode)
&& small_int_operand (XEXP (op, 2), mode)
/* This matches cmp_zero_extract. */
&& ((mode == SImode
&& INTVAL (XEXP (op, 2)) > 19)
/* This matches cmp_zero_extract_sp64. */
|| (TARGET_ARCH64
&& mode == DImode
&& INTVAL (XEXP (op, 2)) > 51)));
else
return register_operand (op, mode);
})
;; Return true if OP is a valid operand for the source of a move insn.
(define_predicate "input_operand"
(match_code "const_int,const_double,const_vector,reg,subreg,mem")
{
enum mode_class mclass;
/* If both modes are non-void they must be the same. */
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return false;
/* Allow any 1-instruction integer constant. */
if (GET_MODE_CLASS (mode) == MODE_INT
&& (small_int_operand (op, mode) || const_high_operand (op, mode)))
return true;
/* If 32-bit mode and this is a DImode constant, allow it
so that the splits can be generated. */
if (TARGET_ARCH32
&& mode == DImode
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
return true;
if (register_operand (op, mode))
return true;
mclass = GET_MODE_CLASS (mode);
if ((mclass == MODE_FLOAT && GET_CODE (op) == CONST_DOUBLE)
|| (mclass == MODE_VECTOR_INT && GET_CODE (op) == CONST_VECTOR))
return true;
/* If this is a SUBREG, look inside so that we handle
paradoxical ones. */
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
/* Check for valid MEM forms. */
if (GET_CODE (op) == MEM)
return memory_address_p (mode, XEXP (op, 0));
return false;
})
;; Return true if OP is an address suitable for a call insn.
;; Call insn on SPARC can take a PC-relative constant address
;; or any regular memory address.
(define_predicate "call_address_operand"
(ior (match_operand 0 "symbolic_operand")
(match_test "memory_address_p (Pmode, op)")))
;; Return true if OP is an operand suitable for a call insn.
(define_predicate "call_operand"
(and (match_code "mem")
(match_test "call_address_operand (XEXP (op, 0), mode)")))
;; Predicates for operators.
;; Return true if OP is a comparison operator. This allows the use of
;; MATCH_OPERATOR to recognize all the branch insns.
(define_predicate "noov_compare_operator"
(match_code "ne,eq,ge,gt,le,lt,geu,gtu,leu,ltu")
{
enum rtx_code code = GET_CODE (op);
if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
|| GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
/* These are the only branches which work with CC_NOOVmode. */
return (code == EQ || code == NE || code == GE || code == LT);
return true;
})
;; Return true if OP is a 64-bit comparison operator. This allows the use of
;; MATCH_OPERATOR to recognize all the branch insns.
(define_predicate "noov_compare64_operator"
(and (match_code "ne,eq,ge,gt,le,lt,geu,gtu,leu,ltu")
(match_test "TARGET_V9"))
{
enum rtx_code code = GET_CODE (op);
if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
/* These are the only branches which work with CCX_NOOVmode. */
return (code == EQ || code == NE || code == GE || code == LT);
return (GET_MODE (XEXP (op, 0)) == CCXmode);
})
;; Return true if OP is a comparison operator suitable for use in V9
;; conditional move or branch on register contents instructions.
(define_predicate "v9_register_compare_operator"
(match_code "eq,ne,ge,lt,le,gt"))
;; Return true if OP is an operator which can set the condition codes
;; explicitly. We do not include PLUS and MINUS because these
;; require CC_NOOVmode, which we handle explicitly.
(define_predicate "cc_arith_operator"
(match_code "and,ior,xor"))
;; Return true if OP is an operator which can bitwise complement its
;; second operand and set the condition codes explicitly.
;; XOR is not here because combine canonicalizes (xor (not ...) ...)
;; and (xor ... (not ...)) to (not (xor ...)). */
(define_predicate "cc_arith_not_operator"
(match_code "and,ior"))

View File

@ -805,56 +805,6 @@ v9_regcmp_p (enum rtx_code code)
/* Operand constraints. */
/* Return nonzero only if OP is a register of mode MODE,
or const0_rtx. */
int
reg_or_0_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (op == const0_rtx)
return 1;
if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& CONST_DOUBLE_LOW (op) == 0)
return 1;
if (fp_zero_operand (op, mode))
return 1;
return 0;
}
/* Return nonzero only if OP is const1_rtx. */
int
const1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return op == const1_rtx;
}
/* Nonzero if OP is a floating point value with value 0.0. */
int
fp_zero_operand (rtx op, enum machine_mode mode)
{
enum mode_class mclass = GET_MODE_CLASS (GET_MODE (op));
if (mclass != MODE_FLOAT && mclass != MODE_VECTOR_INT)
return 0;
return op == CONST0_RTX (mode);
}
/* Nonzero if OP is a register operand in floating point register. */
int
fp_register_operand (rtx op, enum machine_mode mode)
{
if (! register_operand (op, mode))
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op));
}
/* Nonzero if OP is a floating point constant which can
be loaded into an integer register using a single
sethi instruction. */
@ -931,94 +881,6 @@ fp_high_losum_p (rtx op)
return 0;
}
/* Nonzero if OP is an integer register. */
int
intreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (register_operand (op, SImode)
|| (TARGET_ARCH64 && register_operand (op, DImode)));
}
/* Nonzero if OP is a floating point condition code register. */
int
fcc_reg_operand (rtx op, enum machine_mode mode)
{
/* This can happen when recog is called from combine. Op may be a MEM.
Fail instead of calling abort in this case. */
if (GET_CODE (op) != REG)
return 0;
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (mode == VOIDmode
&& (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
return 0;
#if 0 /* ??? ==> 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */
if (reg_renumber == 0)
return REGNO (op) >= FIRST_PSEUDO_REGISTER;
return REGNO_OK_FOR_CCFP_P (REGNO (op));
#else
return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
#endif
}
/* Nonzero if OP is a floating point condition code fcc0 register. */
int
fcc0_reg_operand (rtx op, enum machine_mode mode)
{
/* This can happen when recog is called from combine. Op may be a MEM.
Fail instead of calling abort in this case. */
if (GET_CODE (op) != REG)
return 0;
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (mode == VOIDmode
&& (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
return 0;
return REGNO (op) == SPARC_FCC_REG;
}
/* Nonzero if OP is an integer or floating point condition code register. */
int
icc_or_fcc_reg_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (mode == VOIDmode
&& GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
return 0;
return 1;
}
return fcc_reg_operand (op, mode);
}
/* Call insn on SPARC can take a PC-relative constant address, or any regular
memory address. */
int
call_operand (rtx op, enum machine_mode mode)
{
gcc_assert (GET_CODE (op) == MEM);
op = XEXP (op, 0);
return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
}
int
call_operand_address (rtx op, enum machine_mode mode)
{
return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
}
/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
otherwise return 0. */
@ -1029,628 +891,6 @@ tls_symbolic_operand (rtx op)
return 0;
return SYMBOL_REF_TLS_MODEL (op);
}
int
tgd_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return tls_symbolic_operand (op) == TLS_MODEL_GLOBAL_DYNAMIC;
}
int
tld_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_DYNAMIC;
}
int
tie_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return tls_symbolic_operand (op) == TLS_MODEL_INITIAL_EXEC;
}
int
tle_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_EXEC;
}
/* Returns 1 if OP is either a symbol reference or a sum of a symbol
reference and a constant. */
int
symbolic_operand (register rtx op, enum machine_mode mode)
{
enum machine_mode omode = GET_MODE (op);
if (omode != mode && omode != VOIDmode && mode != VOIDmode)
return 0;
switch (GET_CODE (op))
{
case SYMBOL_REF:
return !SYMBOL_REF_TLS_MODEL (op);
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
&& !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
/* Return truth value of statement that OP is a symbolic memory
operand of mode MODE. */
int
symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return ((GET_CODE (op) == SYMBOL_REF && !SYMBOL_REF_TLS_MODEL (op))
|| GET_CODE (op) == CONST || GET_CODE (op) == HIGH
|| GET_CODE (op) == LABEL_REF);
}
/* Return truth value of statement that OP is a LABEL_REF of mode MODE. */
int
label_ref_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != LABEL_REF)
return 0;
if (GET_MODE (op) != mode)
return 0;
return 1;
}
/* Return 1 if the operand is an argument used in generating pic references
in either the medium/low or medium/anywhere code models of sparc64. */
int
sp64_medium_pic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
/* Check for (const (minus (symbol_ref:GOT)
(const (minus (label) (pc))))). */
if (GET_CODE (op) != CONST)
return 0;
op = XEXP (op, 0);
if (GET_CODE (op) != MINUS)
return 0;
if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
return 0;
/* ??? Ensure symbol is GOT. */
if (GET_CODE (XEXP (op, 1)) != CONST)
return 0;
if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
return 0;
return 1;
}
/* Return 1 if the operand is a data segment reference. This includes
the readonly data segment, or in other words anything but the text segment.
This is needed in the medium/anywhere code model on v9. These values
are accessed with EMBMEDANY_BASE_REG. */
int
data_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case SYMBOL_REF :
return ! SYMBOL_REF_FUNCTION_P (op);
case PLUS :
/* Assume canonical format of symbol + constant.
Fall through. */
case CONST :
return data_segment_operand (XEXP (op, 0), VOIDmode);
default :
return 0;
}
}
/* Return 1 if the operand is a text segment reference.
This is needed in the medium/anywhere code model on v9. */
int
text_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
switch (GET_CODE (op))
{
case LABEL_REF :
return 1;
case SYMBOL_REF :
return SYMBOL_REF_FUNCTION_P (op);
case PLUS :
/* Assume canonical format of symbol + constant.
Fall through. */
case CONST :
return text_segment_operand (XEXP (op, 0), VOIDmode);
default :
return 0;
}
}
/* Return 1 if the operand is either a register or a memory operand that is
not symbolic. */
int
reg_or_nonsymb_mem_operand (register rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
return 1;
return 0;
}
int
splittable_symbolic_memory_operand (rtx op,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != MEM)
return 0;
if (! symbolic_operand (XEXP (op, 0), Pmode))
return 0;
return 1;
}
int
splittable_immediate_memory_operand (rtx op,
enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != MEM)
return 0;
if (! immediate_operand (XEXP (op, 0), Pmode))
return 0;
return 1;
}
/* Return truth value of whether OP is EQ or NE. */
int
eq_or_neq (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
}
/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
or LTU for non-floating-point. We handle those specially. */
int
normal_comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code;
if (!COMPARISON_P (op))
return 0;
if (GET_MODE (XEXP (op, 0)) == CCFPmode
|| GET_MODE (XEXP (op, 0)) == CCFPEmode)
return 1;
code = GET_CODE (op);
return (code != NE && code != EQ && code != GEU && code != LTU);
}
/* Return 1 if this is a comparison operator. This allows the use of
MATCH_OPERATOR to recognize all the branch insns. */
int
noov_compare_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code;
if (!COMPARISON_P (op))
return 0;
code = GET_CODE (op);
if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
|| GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
/* These are the only branches which work with CC_NOOVmode. */
return (code == EQ || code == NE || code == GE || code == LT);
return 1;
}
/* Return 1 if this is a 64-bit comparison operator. This allows the use of
MATCH_OPERATOR to recognize all the branch insns. */
int
noov_compare64_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code;
if (! TARGET_V9)
return 0;
if (!COMPARISON_P (op))
return 0;
code = GET_CODE (op);
if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
/* These are the only branches which work with CCX_NOOVmode. */
return (code == EQ || code == NE || code == GE || code == LT);
return (GET_MODE (XEXP (op, 0)) == CCXmode);
}
/* Nonzero if OP is a comparison operator suitable for use in v9
conditional move or branch on register contents instructions. */
int
v9_regcmp_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
enum rtx_code code;
if (!COMPARISON_P (op))
return 0;
code = GET_CODE (op);
return v9_regcmp_p (code);
}
/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */
int
extend_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
}
/* Return nonzero if OP is an operator of mode MODE which can set
the condition codes explicitly. We do not include PLUS and MINUS
because these require CC_NOOVmode, which we handle explicitly. */
int
cc_arithop (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) == AND
|| GET_CODE (op) == IOR
|| GET_CODE (op) == XOR)
return 1;
return 0;
}
/* Return nonzero if OP is an operator of mode MODE which can bitwise
complement its second operand and set the condition codes explicitly. */
int
cc_arithopn (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
/* XOR is not here because combine canonicalizes (xor (not ...) ...)
and (xor ... (not ...)) to (not (xor ...)). */
return (GET_CODE (op) == AND
|| GET_CODE (op) == IOR);
}
/* Return true if OP is a register, or is a CONST_INT that can fit in a
signed 13 bit immediate field. This is an acceptable SImode operand for
most 3 address instructions. */
int
arith_operand (rtx op, enum machine_mode mode)
{
if (register_operand (op, mode))
return 1;
if (GET_CODE (op) != CONST_INT)
return 0;
return SMALL_INT32 (op);
}
/* Return true if OP is a constant 4096 */
int
arith_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
if (GET_CODE (op) != CONST_INT)
return 0;
else
return INTVAL (op) == 4096;
}
/* Return true if OP is suitable as second operand for add/sub */
int
arith_add_operand (rtx op, enum machine_mode mode)
{
return arith_operand (op, mode) || arith_4096_operand (op, mode);
}
/* Return true if OP is a CONST_INT or a CONST_DOUBLE which can fit in the
immediate field of OR and XOR instructions. Used for 64-bit
constant formation patterns. */
int
const64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return ((GET_CODE (op) == CONST_INT
&& SPARC_SIMM13_P (INTVAL (op)))
#if HOST_BITS_PER_WIDE_INT != 64
|| (GET_CODE (op) == CONST_DOUBLE
&& SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
&& (CONST_DOUBLE_HIGH (op) ==
((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ?
(HOST_WIDE_INT)-1 : 0)))
#endif
);
}
/* The same, but only for sethi instructions. */
int
const64_high_operand (rtx op, enum machine_mode mode)
{
return ((GET_CODE (op) == CONST_INT
&& (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0
&& SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
)
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0
&& SPARC_SETHI_P (CONST_DOUBLE_LOW (op))));
}
/* Return true if OP is a register, or is a CONST_INT that can fit in a
signed 11 bit immediate field. This is an acceptable SImode operand for
the movcc instructions. */
int
arith11_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
}
/* Return true if OP is a register, or is a CONST_INT that can fit in a
signed 10 bit immediate field. This is an acceptable SImode operand for
the movrcc instructions. */
int
arith10_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
}
/* Return true if OP is a register, is a CONST_INT that fits in a 13 bit
immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit
immediate field.
ARCH64: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
can fit in a 13 bit immediate field. This is an acceptable DImode operand
for most 3 address instructions. */
int
arith_double_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && SMALL_INT (op))
|| (! TARGET_ARCH64
&& GET_CODE (op) == CONST_DOUBLE
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000)
|| (TARGET_ARCH64
&& GET_CODE (op) == CONST_DOUBLE
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
&& ((CONST_DOUBLE_HIGH (op) == -1
&& (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
|| (CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
}
/* Return true if OP is a constant 4096 for DImode on ARCH64 */
int
arith_double_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (TARGET_ARCH64 &&
((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) ||
(GET_CODE (op) == CONST_DOUBLE &&
CONST_DOUBLE_LOW (op) == 4096 &&
CONST_DOUBLE_HIGH (op) == 0)));
}
/* Return true if OP is suitable as second operand for add/sub in DImode */
int
arith_double_add_operand (rtx op, enum machine_mode mode)
{
return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);
}
/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
can fit in an 11 bit immediate field. This is an acceptable DImode
operand for the movcc instructions. */
/* ??? Replace with arith11_operand? */
int
arith11_double_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800
&& ((CONST_DOUBLE_HIGH (op) == -1
&& (CONST_DOUBLE_LOW (op) & 0x400) == 0x400)
|| (CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & 0x400) == 0)))
|| (GET_CODE (op) == CONST_INT
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));
}
/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
can fit in an 10 bit immediate field. This is an acceptable DImode
operand for the movrcc instructions. */
/* ??? Replace with arith10_operand? */
int
arith10_double_operand (rtx op, enum machine_mode mode)
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400
&& ((CONST_DOUBLE_HIGH (op) == -1
&& (CONST_DOUBLE_LOW (op) & 0x200) == 0x200)
|| (CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & 0x200) == 0)))
|| (GET_CODE (op) == CONST_INT
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));
}
/* Return truth value of whether OP is an integer which fits the
range constraining immediate operands in most three-address insns,
which have a 13 bit immediate field. */
int
small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
}
int
small_int_or_double (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))));
}
/* Recognize operand values for the umul instruction. That instruction sign
extends immediate values just like all other sparc instructions, but
interprets the extended result as an unsigned number. */
int
uns_small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
#if HOST_BITS_PER_WIDE_INT > 32
/* All allowed constants will fit a CONST_INT. */
return (GET_CODE (op) == CONST_INT
&& ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
|| (INTVAL (op) >= 0xFFFFF000
&& INTVAL (op) <= 0xFFFFFFFF)));
#else
return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
#endif
}
int
uns_arith_operand (rtx op, enum machine_mode mode)
{
return register_operand (op, mode) || uns_small_int (op, mode);
}
/* Return truth value of statement that OP is a call-clobbered register. */
int
clobbered_register (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
{
return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
}
/* Return 1 if OP is a valid operand for the source of a move insn. */
int
input_operand (rtx op, enum machine_mode mode)
{
enum mode_class mclass;
/* If both modes are non-void they must be the same. */
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
/* Allow any one instruction integer constant, and all CONST_INT
variants when we are working in DImode and !arch64. */
if (GET_MODE_CLASS (mode) == MODE_INT
&& ((GET_CODE (op) == CONST_INT
&& (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
|| SPARC_SIMM13_P (INTVAL (op))
|| (mode == DImode
&& ! TARGET_ARCH64)))
|| (TARGET_ARCH64
&& GET_CODE (op) == CONST_DOUBLE
&& ((CONST_DOUBLE_HIGH (op) == 0
&& SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))
||
#if HOST_BITS_PER_WIDE_INT == 64
(CONST_DOUBLE_HIGH (op) == 0
&& SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))
#else
(SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
&& (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
&& CONST_DOUBLE_HIGH (op) == 0)
|| (CONST_DOUBLE_HIGH (op) == -1
&& CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
#endif
))))
return 1;
/* If !arch64 and this is a DImode const, allow it so that
the splits can be generated. */
if (! TARGET_ARCH64
&& mode == DImode
&& GET_CODE (op) == CONST_DOUBLE)
return 1;
if (register_operand (op, mode))
return 1;
mclass = GET_MODE_CLASS (mode);
if ((mclass == MODE_FLOAT && GET_CODE (op) == CONST_DOUBLE)
|| (mclass == MODE_VECTOR_INT && GET_CODE (op) == CONST_VECTOR))
return 1;
/* If this is a SUBREG, look inside so that we handle
paradoxical ones. */
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
/* Check for valid MEM forms. */
if (GET_CODE (op) == MEM)
return memory_address_p (mode, XEXP (op, 0));
return 0;
}
/* Return 1 if OP is valid for the lhs of a compare insn. */
int
compare_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) == ZERO_EXTRACT)
return (register_operand (XEXP (op, 0), mode)
&& small_int_or_double (XEXP (op, 1), mode)
&& small_int_or_double (XEXP (op, 2), mode)
/* This matches cmp_zero_extract. */
&& ((mode == SImode
&& ((GET_CODE (XEXP (op, 2)) == CONST_INT
&& INTVAL (XEXP (op, 2)) > 19)
|| (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
&& CONST_DOUBLE_LOW (XEXP (op, 2)) > 19)))
/* This matches cmp_zero_extract_sp64. */
|| (mode == DImode
&& TARGET_ARCH64
&& ((GET_CODE (XEXP (op, 2)) == CONST_INT
&& INTVAL (XEXP (op, 2)) > 51)
|| (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
&& CONST_DOUBLE_LOW (XEXP (op, 2)) > 51)))));
else
return register_operand (op, mode);
}
/* We know it can't be done in one insn when we get here,
the movsi expander guarantees this. */
@ -1660,15 +900,6 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
enum machine_mode mode = GET_MODE (op0);
rtx temp;
if (GET_CODE (op1) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (op1);
gcc_assert (! SPARC_SETHI_P (value & GET_MODE_MASK (mode))
&& ! SPARC_SIMM13_P (value));
}
/* Full 2-insn decomposition is needed. */
if (reload_in_progress || reload_completed)
temp = op0;
else
@ -1676,20 +907,15 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
if (GET_CODE (op1) == CONST_INT)
{
gcc_assert (!small_int_operand (op1, mode)
&& !const_high_operand (op1, mode));
/* Emit them as real moves instead of a HIGH/LO_SUM,
this way CSE can see everything and reuse intermediate
values if it wants. */
if (TARGET_ARCH64
&& HOST_BITS_PER_WIDE_INT != 64
&& (INTVAL (op1) & 0x80000000) != 0)
emit_insn (gen_rtx_SET
(VOIDmode, temp,
immed_double_const (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff,
0, DImode)));
else
emit_insn (gen_rtx_SET (VOIDmode, temp,
GEN_INT (INTVAL (op1)
& ~(HOST_WIDE_INT)0x3ff)));
emit_insn (gen_rtx_SET (VOIDmode, temp,
GEN_INT (INTVAL (op1)
& ~(HOST_WIDE_INT)0x3ff)));
emit_insn (gen_rtx_SET (VOIDmode,
op0,
@ -1703,7 +929,6 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
gen_rtx_HIGH (mode, op1)));
emit_insn (gen_rtx_SET (VOIDmode,
op0, gen_rtx_LO_SUM (mode, temp, op1)));
}
}
@ -1910,6 +1135,13 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
}
}
#if HOST_BITS_PER_WIDE_INT == 32
void
sparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
{
gcc_unreachable ();
}
#else
/* These avoid problems when cross compiling. If we do not
go through all this hair then the optimizer will see
invalid REG_EQUAL notes or in some cases none at all. */
@ -1918,17 +1150,6 @@ static rtx gen_safe_SET64 (rtx, HOST_WIDE_INT);
static rtx gen_safe_OR64 (rtx, HOST_WIDE_INT);
static rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT);
#if HOST_BITS_PER_WIDE_INT == 64
#define GEN_HIGHINT64(__x) GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff)
#define GEN_INT64(__x) GEN_INT (__x)
#else
#define GEN_HIGHINT64(__x) \
immed_double_const ((__x) & ~(HOST_WIDE_INT)0x3ff, 0, DImode)
#define GEN_INT64(__x) \
immed_double_const ((__x) & 0xffffffff, \
((__x) & 0x80000000 ? -1 : 0), DImode)
#endif
/* The optimizer is not to assume anything about exactly
which bits are set for a HIGH, they are unspecified.
Unfortunately this leads to many missed optimizations
@ -1937,25 +1158,25 @@ static rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT);
static void
sparc_emit_set_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
{
emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_HIGHINT64 (val)));
emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_INT (val & ~(HOST_WIDE_INT)0x3ff)));
}
static rtx
gen_safe_SET64 (rtx dest, HOST_WIDE_INT val)
{
return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val));
return gen_rtx_SET (VOIDmode, dest, GEN_INT (val));
}
static rtx
gen_safe_OR64 (rtx src, HOST_WIDE_INT val)
{
return gen_rtx_IOR (DImode, src, GEN_INT64 (val));
return gen_rtx_IOR (DImode, src, GEN_INT (val));
}
static rtx
gen_safe_XOR64 (rtx src, HOST_WIDE_INT val)
{
return gen_rtx_XOR (DImode, src, GEN_INT64 (val));
return gen_rtx_XOR (DImode, src, GEN_INT (val));
}
/* Worker routines for 64-bit constant formation on arch64.
@ -2293,8 +1514,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
if (reload_in_progress || reload_completed)
temp = op0;
if (GET_CODE (op1) != CONST_DOUBLE
&& GET_CODE (op1) != CONST_INT)
if (GET_CODE (op1) != CONST_INT)
{
sparc_emit_set_symbolic_const64 (op0, op1, temp);
return;
@ -2303,28 +1523,8 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
if (! temp)
temp = gen_reg_rtx (DImode);
if (GET_CODE (op1) == CONST_DOUBLE)
{
#if HOST_BITS_PER_WIDE_INT == 64
high_bits = (CONST_DOUBLE_LOW (op1) >> 32) & 0xffffffff;
low_bits = CONST_DOUBLE_LOW (op1) & 0xffffffff;
#else
high_bits = CONST_DOUBLE_HIGH (op1);
low_bits = CONST_DOUBLE_LOW (op1);
#endif
}
else
{
#if HOST_BITS_PER_WIDE_INT == 64
high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
low_bits = (INTVAL (op1) & 0xffffffff);
#else
high_bits = ((INTVAL (op1) < 0) ?
0xffffffff :
0x00000000);
low_bits = INTVAL (op1);
#endif
}
high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
low_bits = (INTVAL (op1) & 0xffffffff);
/* low_bits bits 0 --> 31
high_bits bits 32 --> 63 */
@ -2452,26 +1652,20 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
|| (((~high_bits) & 0xffffffff) == 0xffffffff
&& ((~low_bits) & 0x80000000) != 0))
{
int fast_int = (~low_bits & 0xffffffff);
unsigned HOST_WIDE_INT fast_int = (~low_bits & 0xffffffff);
if ((SPARC_SETHI_P (fast_int)
&& (~high_bits & 0xffffffff) == 0)
|| SPARC_SIMM13_P (fast_int))
emit_insn (gen_safe_SET64 (temp, fast_int));
else
sparc_emit_set_const64 (temp, GEN_INT64 (fast_int));
sparc_emit_set_const64 (temp, GEN_INT (fast_int));
}
else
{
rtx negated_const;
#if HOST_BITS_PER_WIDE_INT == 64
negated_const = GEN_INT (((~low_bits) & 0xfffffc00) |
(((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));
#else
negated_const = immed_double_const ((~low_bits) & 0xfffffc00,
(~high_bits) & 0xffffffff,
DImode);
#endif
sparc_emit_set_const64 (temp, negated_const);
}
@ -2536,6 +1730,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
#endif
sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
}
#endif /* HOST_BITS_PER_WIDE_INT == 32 */
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. For floating-point,
@ -3448,7 +2643,7 @@ legitimate_constant_p (rtx x)
&& (GET_MODE (x) == SFmode
|| GET_MODE (x) == DFmode
|| GET_MODE (x) == TFmode)
&& fp_zero_operand (x, GET_MODE (x)))
&& const_zero_operand (x, GET_MODE (x)))
return true;
return false;
@ -8643,7 +7838,7 @@ sparc_extra_constraint_check (rtx op, int c, int strict)
break;
case 'Y':
return fp_zero_operand (op, GET_MODE (op));
return const_zero_operand (op, GET_MODE (op));
default:
return 0;

View File

@ -1189,8 +1189,8 @@ extern char leaf_reg_remap[];
: (C) == 'c' ? FPCC_REGS \
: NO_REGS))
/* The letters I, J, K, L and M in a register constraint string
can be used to stand for particular ranges of immediate operands.
/* The letters I, J, K, L, M, N, O, P in a register constraint string
can be used to stand for particular ranges of CONST_INTs.
This macro defines what the ranges are.
C is the letter, and VALUE is a constant value.
Return 1 if VALUE is in the range specified by C.
@ -1201,20 +1201,32 @@ extern char leaf_reg_remap[];
`L' is used for the range of constants supported by the movcc insns.
`M' is used for the range of constants supported by the movrcc insns.
`N' is like K, but for constants wider than 32 bits.
`O' is used for the range which is just 4096. */
`O' is used for the range which is just 4096.
`P' is free. */
/* Predicates for 10-bit, 11-bit and 13-bit signed constants. */
#define SPARC_SIMM10_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x200 < 0x400)
#define SPARC_SIMM11_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x400 < 0x800)
#define SPARC_SIMM13_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x1000 < 0x2000)
/* 10 and 11 bit immediates are only used for a few specific insns.
/* 10- and 11-bit immediates are only used for a few specific insns.
SMALL_INT is used throughout the port so we continue to use it. */
#define SMALL_INT(X) (SPARC_SIMM13_P (INTVAL (X)))
/* 13 bit immediate, considering only the low 32 bits */
#define SMALL_INT32(X) (SPARC_SIMM13_P (trunc_int_for_mode \
(INTVAL (X), SImode)))
/* Predicate for constants that can be loaded with a sethi instruction.
This is the general, 64-bit aware, bitwise version that ensures that
only constants whose representation fits in the mask
0x00000000fffffc00
are accepted. It will reject, for example, negative SImode constants
on 64-bit hosts, so correct handling is to mask the value beforehand
according to the mode of the instruction. */
#define SPARC_SETHI_P(X) \
(((unsigned HOST_WIDE_INT) (X) \
& ((unsigned HOST_WIDE_INT) 0x3ff - GET_MODE_MASK (SImode) - 1)) == 0)
/* Version of the above predicate for SImode constants and below. */
#define SPARC_SETHI32_P(X) \
(SPARC_SETHI_P ((unsigned HOST_WIDE_INT) (X) & GET_MODE_MASK (SImode)))
@ -1228,13 +1240,12 @@ extern char leaf_reg_remap[];
: (C) == 'O' ? (VALUE) == 4096 \
: 0)
/* Similar, but for floating constants, and defining letters G and H.
/* Similar, but for CONST_DOUBLEs, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
((C) == 'G' ? fp_zero_operand (VALUE, GET_MODE (VALUE)) \
((C) == 'G' ? const_zero_operand (VALUE, GET_MODE (VALUE)) \
: (C) == 'H' ? arith_double_operand (VALUE, DImode) \
: (C) == 'O' ? arith_double_4096_operand (VALUE, DImode) \
: 0)
/* Given an rtx X being reloaded into a reg required to be
@ -1257,7 +1268,7 @@ extern char leaf_reg_remap[];
|| (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
&& ! TARGET_FPU) \
|| (GET_MODE (X) == TFmode \
&& ! fp_zero_operand (X, TFmode))) \
&& ! const_zero_operand (X, TFmode))) \
? NO_REGS \
: (!FP_REG_CLASS_P (CLASS) \
&& GET_MODE_CLASS (GET_MODE (X)) == MODE_INT) \
@ -2449,58 +2460,5 @@ extern int sparc_indent_opcode;
#define TARGET_SUN_TLS TARGET_TLS
#define TARGET_GNU_TLS 0
/* Define the codes that are matched by predicates in sparc.c. */
#define PREDICATE_CODES \
{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"const1_operand", {CONST_INT}}, \
{"fp_zero_operand", {CONST_DOUBLE}}, \
{"fp_register_operand", {SUBREG, REG}}, \
{"intreg_operand", {SUBREG, REG}}, \
{"fcc_reg_operand", {REG}}, \
{"fcc0_reg_operand", {REG}}, \
{"icc_or_fcc_reg_operand", {REG}}, \
{"call_operand", {MEM}}, \
{"call_operand_address", {SYMBOL_REF, LABEL_REF, CONST, CONST_DOUBLE, \
SUBREG, REG, PLUS, LO_SUM, CONST_INT}}, \
{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
{"symbolic_memory_operand", {SUBREG, MEM}}, \
{"label_ref_operand", {LABEL_REF}}, \
{"sp64_medium_pic_operand", {CONST}}, \
{"data_segment_operand", {SYMBOL_REF, PLUS, CONST}}, \
{"text_segment_operand", {LABEL_REF, SYMBOL_REF, PLUS, CONST}}, \
{"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
{"splittable_symbolic_memory_operand", {MEM}}, \
{"splittable_immediate_memory_operand", {MEM}}, \
{"eq_or_neq", {EQ, NE}}, \
{"normal_comp_operator", {GE, GT, LE, LT, GTU, LEU}}, \
{"noov_compare_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \
{"noov_compare64_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \
{"v9_regcmp_op", {EQ, NE, GE, LT, LE, GT}}, \
{"extend_op", {SIGN_EXTEND, ZERO_EXTEND}}, \
{"cc_arithop", {AND, IOR, XOR}}, \
{"cc_arithopn", {AND, IOR}}, \
{"arith_operand", {SUBREG, REG, CONST_INT}}, \
{"arith_add_operand", {SUBREG, REG, CONST_INT}}, \
{"arith11_operand", {SUBREG, REG, CONST_INT}}, \
{"arith10_operand", {SUBREG, REG, CONST_INT}}, \
{"arith_double_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"arith_double_add_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"arith11_double_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"arith10_double_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
{"small_int", {CONST_INT}}, \
{"small_int_or_double", {CONST_INT, CONST_DOUBLE}}, \
{"uns_small_int", {CONST_INT}}, \
{"uns_arith_operand", {SUBREG, REG, CONST_INT}}, \
{"clobbered_register", {REG}}, \
{"input_operand", {SUBREG, REG, CONST_INT, MEM, CONST}}, \
{"compare_operand", {SUBREG, REG, ZERO_EXTRACT}}, \
{"const64_operand", {CONST_INT, CONST_DOUBLE}}, \
{"const64_high_operand", {CONST_INT, CONST_DOUBLE}}, \
{"tgd_symbolic_operand", {SYMBOL_REF}}, \
{"tld_symbolic_operand", {SYMBOL_REF}}, \
{"tie_symbolic_operand", {SYMBOL_REF}}, \
{"tle_symbolic_operand", {SYMBOL_REF}},
/* The number of Pmode words for the setjmp buffer. */
#define JMP_BUF_SIZE 12

File diff suppressed because it is too large Load Diff