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:
parent
b9850b3d44
commit
0e5d569cd5
@ -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
|
||||
|
456
gcc/config/sparc/predicates.md
Normal file
456
gcc/config/sparc/predicates.md
Normal 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"))
|
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user