;; Predicate definitions for POWER and PowerPC.
-;; Copyright (C) 2005-2016 Free Software Foundation, Inc.
+;; Copyright (C) 2005-2019 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
(match_test "REGNO (op) == CTR_REGNO
|| REGNO (op) > LAST_VIRTUAL_REGISTER")))
+;; Return 1 if op is a SUBREG that is used to look at a SFmode value as
+;; and integer or vice versa.
+;;
+;; In the normal case where SFmode is in a floating point/vector register, it
+;; is stored as a DFmode and has a different format. If we don't transform the
+;; value, things that use logical operations on the values will get the wrong
+;; value.
+;;
+;; If we don't have 64-bit and direct move, this conversion will be done by
+;; store and load, instead of by fiddling with the bits within the register.
+(define_predicate "sf_subreg_operand"
+ (match_code "subreg")
+{
+ rtx inner_reg = SUBREG_REG (op);
+ machine_mode inner_mode = GET_MODE (inner_reg);
+
+ if (TARGET_ALLOW_SF_SUBREG || !REG_P (inner_reg))
+ return 0;
+
+ if ((mode == SFmode && GET_MODE_CLASS (inner_mode) == MODE_INT)
+ || (GET_MODE_CLASS (mode) == MODE_INT && inner_mode == SFmode))
+ {
+ if (INT_REGNO_P (REGNO (inner_reg)))
+ return 0;
+
+ return 1;
+ }
+ return 0;
+})
+
;; Return 1 if op is an Altivec register.
(define_predicate "altivec_register_operand"
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
if (!REG_P (op))
return 0;
;; Return 1 if op is a VSX register.
(define_predicate "vsx_register_operand"
(match_operand 0 "register_operand")
+{
+ if (GET_CODE (op) == SUBREG)
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
+
+ if (!REG_P (op))
+ return 0;
+
+ if (REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ return 1;
+
+ return VSX_REGNO_P (REGNO (op));
+})
+
+;; Like vsx_register_operand, but allow SF SUBREGS
+(define_predicate "vsx_reg_sfsubreg_ok"
+ (match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
if (!REG_P (op))
return 0;
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
if (!REG_P (op))
return 0;
(match_operand 0 "register_operand")
{
if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
+
if (!REG_P (op))
return 0;
return CA_REGNO_P (REGNO (op));
})
+;; Return 1 if operand is constant zero (scalars and vectors).
+(define_predicate "zero_constant"
+ (and (match_code "const_int,const_double,const_wide_int,const_vector")
+ (match_test "op == CONST0_RTX (mode)")))
+
+;; Return 1 if operand is constant -1 (scalars and vectors).
+(define_predicate "all_ones_constant"
+ (and (match_code "const_int,const_double,const_wide_int,const_vector")
+ (match_test "op == CONSTM1_RTX (mode) && !FLOAT_MODE_P (mode)")))
+
;; Return 1 if op is a signed 5-bit constant integer.
(define_predicate "s5bit_cint_operand"
(and (match_code "const_int")
(and (match_code "const_int")
(match_test "INTVAL (op) >= 0 && INTVAL (op) <= 63")))
+;; Return 1 if op is an unsigned 7-bit constant integer.
+(define_predicate "u7bit_cint_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 127)")))
+
;; Return 1 if op is a signed 8-bit constant integer.
;; Integer multiplication complete more quickly
(define_predicate "s8bit_cint_operand"
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), 2, 3)")))
+;; Match op = 0..7.
+(define_predicate "const_0_to_7_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 7)")))
+
+;; Match op = 0..11
+(define_predicate "const_0_to_12_operand"
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (INTVAL (op), 0, 12)")))
+
;; Match op = 0..15
(define_predicate "const_0_to_15_operand"
(and (match_code "const_int")
(match_test "IN_RANGE (INTVAL (op), 0, 15)")))
;; Return 1 if op is a register that is not special.
+;; Disallow (SUBREG:SF (REG:SI)) and (SUBREG:SI (REG:SF)) on VSX systems where
+;; you need to be careful in moving a SFmode to SImode and vice versa due to
+;; the fact that SFmode is represented as DFmode in the VSX registers.
(define_predicate "gpc_reg_operand"
(match_operand 0 "register_operand")
{
- if ((TARGET_E500_DOUBLE || TARGET_SPE) && invalid_e500_subreg (op, mode))
- return 0;
-
if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
if (!REG_P (op))
return 0;
})
;; Return 1 if op is a general purpose register. Unlike gpc_reg_operand, don't
-;; allow floating point or vector registers.
+;; allow floating point or vector registers. Since vector registers are not
+;; allowed, we don't have to reject SFmode/SImode subregs.
(define_predicate "int_reg_operand"
(match_operand 0 "register_operand")
{
- if ((TARGET_E500_DOUBLE || TARGET_SPE) && invalid_e500_subreg (op, mode))
- return 0;
-
if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ {
+ if (TARGET_NO_SF_SUBREG && sf_subreg_operand (op, mode))
+ return 0;
+
+ op = SUBREG_REG (op);
+ }
if (!REG_P (op))
return 0;
})
;; Like int_reg_operand, but don't return true for pseudo registers
+;; We don't have to check for SF SUBREGS because pseudo registers
+;; are not allowed, and SF SUBREGs are ok within GPR registers.
(define_predicate "int_reg_operand_not_pseudo"
(match_operand 0 "register_operand")
{
- if ((TARGET_E500_DOUBLE || TARGET_SPE) && invalid_e500_subreg (op, mode))
- return 0;
-
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return FP_REGNO_P (r);
})
-;; Return true if this is a register that can has D-form addressing (GPR and
-;; traditional FPR registers for scalars). ISA 3.0 (power9) adds D-form
-;; addressing for scalars in Altivec registers.
-;;
-;; If this is a pseudo only allow for GPR fusion in power8. If we have the
-;; power9 fusion allow the floating point types.
-(define_predicate "toc_fusion_or_p9_reg_operand"
- (match_code "reg,subreg")
-{
- HOST_WIDE_INT r;
- bool gpr_p = (mode == QImode || mode == HImode || mode == SImode
- || mode == SFmode
- || (TARGET_POWERPC64 && (mode == DImode || mode == DFmode)));
- bool fpr_p = (TARGET_P9_FUSION
- && (mode == DFmode || mode == SFmode
- || (TARGET_POWERPC64 && mode == DImode)));
- bool vmx_p = (TARGET_P9_FUSION && TARGET_P9_VECTOR
- && (mode == DFmode || mode == SFmode));
-
- if (!TARGET_P8_FUSION)
- return 0;
-
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- if (!REG_P (op))
- return 0;
-
- r = REGNO (op);
- if (r >= FIRST_PSEUDO_REGISTER)
- return (gpr_p || fpr_p || vmx_p);
-
- if (INT_REGNO_P (r))
- return gpr_p;
-
- if (FP_REGNO_P (r))
- return fpr_p;
-
- if (ALTIVEC_REGNO_P (r))
- return vmx_p;
-
- return 0;
-})
-
;; Return 1 if op is a HTM specific SPR register.
(define_predicate "htm_spr_reg_operand"
(match_operand 0 "register_operand")
return CR_REGNO_NOT_CR0_P (REGNO (op));
})
-;; Return 1 if op is a register that is a condition register field and if generating microcode, not cr0.
-(define_predicate "cc_reg_not_micro_cr0_operand"
- (match_operand 0 "register_operand")
-{
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
-
- if (!REG_P (op))
- return 0;
-
- if (REGNO (op) > LAST_VIRTUAL_REGISTER)
- return 1;
-
- if (rs6000_gen_cell_microcode)
- return CR_REGNO_NOT_CR0_P (REGNO (op));
- else
- return CR_REGNO_P (REGNO (op));
-})
-
;; Return 1 if op is a constant integer valid for D field
;; or non-special register register.
(define_predicate "reg_or_short_operand"
(match_operand 0 "u_short_cint_operand")
(match_operand 0 "gpc_reg_operand")))
-;; Return 1 if op is any constant integer
-;; or non-special register.
+;; Return 1 if op is any constant integer or a non-special register.
(define_predicate "reg_or_cint_operand"
(ior (match_code "const_int")
(match_operand 0 "gpc_reg_operand")))
+;; Return 1 if op is constant zero or a non-special register.
+(define_predicate "reg_or_zero_operand"
+ (ior (match_operand 0 "zero_constant")
+ (match_operand 0 "gpc_reg_operand")))
+
;; Return 1 if op is a constant integer valid for addition with addis, addi.
(define_predicate "add_cint_operand"
(and (match_code "const_int")
(define_predicate "easy_fp_constant"
(match_code "const_double")
{
- if (GET_MODE (op) != mode
- || (!SCALAR_FLOAT_MODE_P (mode) && mode != DImode))
- return 0;
+ gcc_assert (GET_MODE (op) == mode && SCALAR_FLOAT_MODE_P (mode));
- /* Consider all constants with -msoft-float to be easy. */
- if ((TARGET_SOFT_FLOAT || TARGET_E500_SINGLE
- || (TARGET_HARD_FLOAT && (TARGET_SINGLE_FLOAT && ! TARGET_DOUBLE_FLOAT)))
- && mode != DImode)
- return 1;
+ /* Consider all constants with -msoft-float to be easy when regs are
+ 32-bit and thus can be loaded with a maximum of 2 insns. For
+ 64-bit avoid long dependent insn sequences. */
+ if (TARGET_SOFT_FLOAT)
+ {
+ if (!TARGET_POWERPC64)
+ return 1;
+
+ int size = GET_MODE_SIZE (mode);
+ if (size < 8)
+ return 1;
+
+ int load_from_mem_insns = 2;
+ if (size > 8)
+ load_from_mem_insns++;
+ if (TARGET_CMODEL != CMODEL_SMALL)
+ load_from_mem_insns++;
+ if (num_insns_constant (op, mode) <= load_from_mem_insns)
+ return 1;
+ }
/* 0.0D is not all zero bits. */
if (DECIMAL_FLOAT_MODE_P (mode))
return 0;
/* The constant 0.0 is easy under VSX. */
- if (TARGET_VSX && SCALAR_FLOAT_MODE_P (mode) && op == CONST0_RTX (mode))
+ if (TARGET_VSX && op == CONST0_RTX (mode))
return 1;
- /* If we are using V.4 style PIC, consider all constants to be hard. */
- if (flag_pic && DEFAULT_ABI == ABI_V4)
- return 0;
-
- /* If we have real FPRs, consider floating point constants hard (other than
- 0.0 under VSX), so that the constant gets pushed to memory during the
- early RTL phases. This has the advantage that double precision constants
- that can be represented in single precision without a loss of precision
- will use single precision loads. */
-
- switch (mode)
- {
- case KFmode:
- case IFmode:
- case TFmode:
- case DFmode:
- case SFmode:
- return 0;
-
- case DImode:
- return (num_insns_constant (op, DImode) <= 2);
-
- case SImode:
- return 1;
-
- default:
- gcc_unreachable ();
- }
+ /* Otherwise consider floating point constants hard, so that the
+ constant gets pushed to memory during the early RTL phases. This
+ has the advantage that double precision constants that can be
+ represented in single precision without a loss of precision will
+ use single precision loads. */
+ return 0;
})
-;; Return 1 if the operand is a CONST_VECTOR or VEC_DUPLICATE of a constant
-;; that can loaded with a XXSPLTIB instruction and then a VUPKHSB, VECSB2W or
-;; VECSB2D instruction.
+;; Return 1 if the operand is a constant that can loaded with a XXSPLTIB
+;; instruction and then a VUPKHSB, VECSB2W or VECSB2D instruction.
(define_predicate "xxspltib_constant_split"
(match_code "const_vector,vec_duplicate,const_int")
})
-;; Return 1 if the operand is a CONST_VECTOR that can loaded directly with a
-;; XXSPLTIB instruction.
+;; Return 1 if the operand is constant that can loaded directly with a XXSPLTIB
+;; instruction.
(define_predicate "xxspltib_constant_nosplit"
(match_code "const_vector,vec_duplicate,const_int")
(define_predicate "easy_vector_constant"
(match_code "const_vector")
{
- /* As the paired vectors are actually FPRs it seems that there is
- no easy way to load a CONST_VECTOR without using memory. */
- if (TARGET_PAIRED_FLOAT)
- return false;
-
- /* Because IEEE 128-bit floating point is considered a vector type
- in order to pass it in VSX registers, it might use this function
- instead of easy_fp_constant. */
- if (FLOAT128_VECTOR_P (mode))
- return easy_fp_constant (op, mode);
-
if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode))
{
int value = 256;
return easy_altivec_constant (op, mode);
}
- if (SPE_VECTOR_MODE (mode))
- {
- int cst, cst2;
- if (zero_constant (op, mode))
- return true;
- if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
- return false;
-
- /* Limit SPE vectors to 15 bits signed. These we can generate with:
- li r0, CONSTANT1
- evmergelo r0, r0, r0
- li r0, CONSTANT2
-
- I don't know how efficient it would be to allow bigger constants,
- considering we'll have an extra 'ori' for every 'li'. I doubt 5
- instructions is better than a 64-bit memory load, but I don't
- have the e500 timing specs. */
- if (mode == V2SImode)
- {
- cst = INTVAL (CONST_VECTOR_ELT (op, 0));
- cst2 = INTVAL (CONST_VECTOR_ELT (op, 1));
- return cst >= -0x7fff && cst <= 0x7fff
- && cst2 >= -0x7fff && cst2 <= 0x7fff;
- }
- }
-
return false;
})
(and (match_test "easy_altivec_constant (op, mode)")
(match_test "vspltis_shifted (op) != 0")))))
-;; Return 1 if operand is constant zero (scalars and vectors).
-(define_predicate "zero_constant"
- (and (match_code "const_int,const_double,const_wide_int,const_vector")
- (match_test "op == CONST0_RTX (mode)")))
+;; Return 1 if operand is a vector int register or is either a vector constant
+;; of all 0 bits of a vector constant of all 1 bits.
+(define_predicate "vector_int_reg_or_same_bit"
+ (match_code "reg,subreg,const_vector")
+{
+ if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
+ return 0;
-;; Return 1 if operand is constant -1 (scalars and vectors).
-(define_predicate "all_ones_constant"
- (and (match_code "const_int,const_double,const_wide_int,const_vector")
- (match_test "op == CONSTM1_RTX (mode) && !FLOAT_MODE_P (mode)")))
+ else if (REG_P (op) || SUBREG_P (op))
+ return vint_operand (op, mode);
+
+ else
+ return op == CONST0_RTX (mode) || op == CONSTM1_RTX (mode);
+})
;; Return 1 if operand is 0.0.
(define_predicate "zero_fp_constant"
(and (and (match_code "mem")
(match_test "MEM_VOLATILE_P (op)"))
(if_then_else (match_test "reload_completed")
- (match_operand 0 "memory_operand")
- (if_then_else (match_test "reload_in_progress")
- (match_test "strict_memory_address_p (mode, XEXP (op, 0))")
- (match_test "memory_address_p (mode, XEXP (op, 0))")))))
+ (match_operand 0 "memory_operand")
+ (match_test "memory_address_p (mode, XEXP (op, 0))"))))
;; Return 1 if the operand is an offsettable memory operand.
(define_predicate "offsettable_mem_operand"
(and (match_operand 0 "memory_operand")
(match_test "offsettable_nonstrict_memref_p (op)")))
+;; Return 1 if the operand is a simple offsettable memory operand
+;; that does not include pre-increment, post-increment, etc.
+(define_predicate "simple_offsettable_mem_operand"
+ (match_operand 0 "offsettable_mem_operand")
+{
+ rtx addr = XEXP (op, 0);
+
+ if (GET_CODE (addr) != PLUS && GET_CODE (addr) != LO_SUM)
+ return 0;
+
+ if (!CONSTANT_P (XEXP (addr, 1)))
+ return 0;
+
+ return base_reg_operand (XEXP (addr, 0), Pmode);
+})
+
;; Return 1 if the operand is suitable for load/store quad memory.
;; This predicate only checks for non-atomic loads/stores (not lqarx/stqcx).
(define_predicate "quad_memory_operand"
if (GET_MODE_SIZE (mode) != 16 || !MEM_P (op) || MEM_ALIGN (op) < 128)
return false;
- return quad_address_p (XEXP (op, 0), mode, true);
+ return quad_address_p (XEXP (op, 0), mode, false);
})
;; Return 1 if the operand is suitable for load/store to vector registers with
(define_predicate "vsx_quad_dform_memory_operand"
(match_code "mem")
{
- if (!TARGET_P9_DFORM_VECTOR || !MEM_P (op) || GET_MODE_SIZE (mode) != 16)
+ if (!TARGET_P9_VECTOR || !MEM_P (op) || GET_MODE_SIZE (mode) != 16)
return false;
return quad_address_p (XEXP (op, 0), mode, false);
&& !satisfies_constraint_L (op)")))
;; Return 1 if the operand is a constant that can be used as the operand
-;; of an OR or XOR.
+;; of an AND, OR or XOR.
(define_predicate "logical_const_operand"
(match_code "const_int")
{
})
;; Return 1 if the operand is a non-special register or a constant that
-;; can be used as the operand of an OR or XOR.
+;; can be used as the operand of an AND, OR or XOR.
(define_predicate "logical_operand"
(ior (match_operand 0 "gpc_reg_operand")
(match_operand 0 "logical_const_operand")))
;; Return 1 if the operand is a general non-special register or memory operand.
(define_predicate "reg_or_mem_operand"
- (ior (match_operand 0 "memory_operand")
- (ior (and (match_code "mem")
- (match_test "macho_lo_sum_memory_operand (op, mode)"))
- (ior (match_operand 0 "volatile_mem_operand")
- (match_operand 0 "gpc_reg_operand")))))
-
-;; Return 1 if the operand is either an easy FP constant or memory or reg.
-(define_predicate "reg_or_none500mem_operand"
- (if_then_else (match_code "mem")
- (and (match_test "!TARGET_E500_DOUBLE")
- (ior (match_operand 0 "memory_operand")
- (ior (match_test "macho_lo_sum_memory_operand (op, mode)")
- (match_operand 0 "volatile_mem_operand"))))
- (match_operand 0 "gpc_reg_operand")))
+ (ior (match_operand 0 "memory_operand")
+ (and (match_code "mem")
+ (match_test "macho_lo_sum_memory_operand (op, mode)"))
+ (match_operand 0 "volatile_mem_operand")
+ (match_operand 0 "gpc_reg_operand")))
;; Return 1 if the operand is CONST_DOUBLE 0, register or memory operand.
(define_predicate "zero_reg_mem_operand"
return true;
if (!memory_operand (inner, mode))
return false;
- if (!rs6000_gen_cell_microcode)
- return false;
addr = XEXP (inner, 0);
if (GET_CODE (addr) == PRE_INC
(and (match_code "symbol_ref")
(match_test "RS6000_SYMBOL_REF_TLS_P (op)")))
+;; Return 1 for the UNSPEC used in TLS call operands
+(define_predicate "unspec_tls"
+ (match_code "unspec")
+{
+ return XINT (op, 1) == UNSPEC_TLSGD || XINT (op, 1) == UNSPEC_TLSLD;
+})
+
;; Return 1 if the operand, used inside a MEM, is a valid first argument
;; to CALL. This is a SYMBOL_REF, a pseudo-register, LR or CTR.
(define_predicate "call_operand"
|| REGNO (op) >= FIRST_PSEUDO_REGISTER")
(match_code "symbol_ref")))
+;; Return 1 if the operand, used inside a MEM, is a valid first argument
+;; to an indirect CALL. This is LR, CTR, or a PLTSEQ unspec using CTR.
+(define_predicate "indirect_call_operand"
+ (match_code "reg,unspec")
+{
+ if (REG_P (op))
+ return (REGNO (op) == LR_REGNO
+ || REGNO (op) == CTR_REGNO);
+ if (GET_CODE (op) == UNSPEC)
+ {
+ if (XINT (op, 1) != UNSPEC_PLTSEQ)
+ return false;
+ op = XVECEXP (op, 0, 0);
+ return REG_P (op) && REGNO (op) == CTR_REGNO;
+ }
+ return false;
+})
+
;; Return 1 if the operand is a SYMBOL_REF for a function known to be in
;; this file.
(define_predicate "current_file_function_operand"
(and (match_code "symbol_ref")
(match_test "(DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))
&& (SYMBOL_REF_LOCAL_P (op)
- || op == XEXP (DECL_RTL (current_function_decl), 0))
+ || (op == XEXP (DECL_RTL (current_function_decl), 0)
+ && !decl_replaceable_p (current_function_decl)))
&& !((DEFAULT_ABI == ABI_AIX
|| DEFAULT_ABI == ABI_ELFv2)
&& (SYMBOL_REF_EXTERNAL_P (op)
&& easy_vector_constant (op, mode))
return 1;
- /* Do not allow invalid E500 subregs. */
- if ((TARGET_E500_DOUBLE || TARGET_SPE)
- && GET_CODE (op) == SUBREG
- && invalid_e500_subreg (op, mode))
- return 0;
-
/* For floating-point or multi-word mode, the only remaining valid type
is a register. */
if (SCALAR_FLOAT_MODE_P (mode)
;; Return 1 if this operand is a valid input for a vsx_splat insn.
(define_predicate "splat_input_operand"
- (match_code "symbol_ref,const,reg,subreg,mem,
- const_double,const_wide_int,const_vector,const_int")
+ (match_code "reg,subreg,mem")
{
+ machine_mode vmode;
+
+ if (mode == DFmode)
+ vmode = V2DFmode;
+ else if (mode == DImode)
+ vmode = V2DImode;
+ else if (mode == SImode && TARGET_P9_VECTOR)
+ vmode = V4SImode;
+ else if (mode == SFmode && TARGET_P9_VECTOR)
+ vmode = V4SFmode;
+ else
+ return false;
+
if (MEM_P (op))
{
+ rtx addr = XEXP (op, 0);
+
if (! volatile_ok && MEM_VOLATILE_P (op))
return 0;
- if (mode == DFmode)
- mode = V2DFmode;
- else if (mode == DImode)
- mode = V2DImode;
- else if (mode == SImode && TARGET_P9_VECTOR)
- mode = V4SImode;
- else if (mode == SFmode && TARGET_P9_VECTOR)
- mode = V4SFmode;
+
+ if (lra_in_progress || reload_completed)
+ return indexed_or_indirect_address (addr, vmode);
else
- gcc_unreachable ();
- return memory_address_addr_space_p (mode, XEXP (op, 0),
- MEM_ADDR_SPACE (op));
+ return memory_address_addr_space_p (vmode, addr, MEM_ADDR_SPACE (op));
}
- return input_operand (op, mode);
-})
-
-;; Return true if OP is a non-immediate operand and not an invalid
-;; SUBREG operation on the e500.
-(define_predicate "rs6000_nonimmediate_operand"
- (match_code "reg,subreg,mem")
-{
- if ((TARGET_E500_DOUBLE || TARGET_SPE)
- && GET_CODE (op) == SUBREG
- && invalid_e500_subreg (op, mode))
- return 0;
-
- return nonimmediate_operand (op, mode);
+ return gpc_reg_operand (op, mode);
})
;; Return true if operand is an operator used in rotate-and-mask instructions.
GET_MODE (XEXP (op, 0))),
1"))))
-;; Return 1 if OP is a valid comparison operator for "cbranch" instructions.
-;; If we're assuming that FP operations cannot generate user-visible traps,
-;; then on e500 we can use the ordered-signaling instructions to implement
-;; the unordered-quiet FP comparison predicates modulo a reversal.
-(define_predicate "rs6000_cbranch_operator"
- (if_then_else (match_test "TARGET_HARD_FLOAT && !TARGET_FPRS")
- (if_then_else (match_test "flag_trapping_math")
- (match_operand 0 "ordered_comparison_operator")
- (ior (match_operand 0 "ordered_comparison_operator")
- (match_code ("unlt,unle,ungt,unge"))))
- (match_operand 0 "comparison_operator")))
-
;; Return 1 if OP is an unsigned comparison operator.
(define_predicate "unsigned_comparison_operator"
(match_code "ltu,gtu,leu,geu"))
(and (match_operand 0 "branch_comparison_operator")
(match_code "ne,le,ge,leu,geu,ordered")))
-;; Return 1 if OP is a comparison operator suitable for vector/scalar
-;; comparisons that generate a -1/0 mask.
+;; Return 1 if OP is a comparison operator suitable for floating point
+;; vector/scalar comparisons that generate a -1/0 mask.
(define_predicate "fpmask_comparison_operator"
(match_code "eq,gt,ge"))
+;; Return 1 if OP is a comparison operator suitable for vector/scalar
+;; comparisons that generate a 0/-1 mask (i.e. the inverse of
+;; fpmask_comparison_operator).
+(define_predicate "invert_fpmask_comparison_operator"
+ (match_code "ne,unlt,unle"))
+
+;; Return 1 if OP is a comparison operation suitable for integer vector/scalar
+;; comparisons that generate a -1/0 mask.
+(define_predicate "vecint_comparison_operator"
+ (match_code "eq,gt,gtu"))
+
;; Return 1 if OP is a comparison operation that is valid for a branch
;; insn, which is true if the corresponding bit in the CC register is set.
(define_predicate "branch_positive_comparison_operator"
(and (match_operand 0 "branch_comparison_operator")
(match_code "eq,lt,gt,ltu,gtu,unordered")))
-;; Return 1 if OP is a load multiple operation, known to be a PARALLEL.
-(define_predicate "load_multiple_operation"
- (match_code "parallel")
-{
- int count = XVECLEN (op, 0);
- unsigned int dest_regno;
- rtx src_addr;
- int i;
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
- return 0;
-
- dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
- src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
-
- for (i = 1; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_DEST (elt)) != REG
- || GET_MODE (SET_DEST (elt)) != SImode
- || REGNO (SET_DEST (elt)) != dest_regno + i
- || GET_CODE (SET_SRC (elt)) != MEM
- || GET_MODE (SET_SRC (elt)) != SImode
- || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
- || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
- return 0;
- }
-
- return 1;
-})
-
-;; Return 1 if OP is a store multiple operation, known to be a PARALLEL.
-;; The second vector element is a CLOBBER.
-(define_predicate "store_multiple_operation"
- (match_code "parallel")
-{
- int count = XVECLEN (op, 0) - 1;
- unsigned int src_regno;
- rtx dest_addr;
- int i;
-
- /* Perform a quick check so we don't blow up below. */
- if (count <= 1
- || GET_CODE (XVECEXP (op, 0, 0)) != SET
- || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
- || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
- return 0;
-
- src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
- dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
-
- for (i = 1; i < count; i++)
- {
- rtx elt = XVECEXP (op, 0, i + 1);
-
- if (GET_CODE (elt) != SET
- || GET_CODE (SET_SRC (elt)) != REG
- || GET_MODE (SET_SRC (elt)) != SImode
- || REGNO (SET_SRC (elt)) != src_regno + i
- || GET_CODE (SET_DEST (elt)) != MEM
- || GET_MODE (SET_DEST (elt)) != SImode
- || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
- || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
- || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
- || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
- return 0;
- }
-
- return 1;
-})
-
;; Return 1 if OP is valid for a save_world call in prologue, known to be
;; a PARLLEL.
(define_predicate "save_world_operation"
rtx elt;
int count = XVECLEN (op, 0);
- if (count != 59)
+ if (count != 58)
return 0;
index = 0;
if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN
- || GET_CODE (XVECEXP (op, 0, index++)) != USE
|| GET_CODE (XVECEXP (op, 0, index++)) != USE
|| GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
return 0;
return GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_TOCREL;
})
-;; Match the TOC memory operand that can be fused with an addis instruction.
-;; This is used in matching a potential fused address before register
-;; allocation.
-(define_predicate "toc_fusion_mem_raw"
- (match_code "mem")
-{
- if (!TARGET_TOC_FUSION_INT || !can_create_pseudo_p ())
- return false;
-
- return small_toc_ref (XEXP (op, 0), Pmode);
-})
-
-;; Match the memory operand that has been fused with an addis instruction and
-;; wrapped inside of an (unspec [...] UNSPEC_FUSION_ADDIS) wrapper.
-(define_predicate "toc_fusion_mem_wrapped"
- (match_code "mem")
-{
- rtx addr;
-
- if (!TARGET_TOC_FUSION_INT)
- return false;
-
- if (!MEM_P (op))
- return false;
-
- addr = XEXP (op, 0);
- return (GET_CODE (addr) == UNSPEC && XINT (addr, 1) == UNSPEC_FUSION_ADDIS);
-})
-
;; Match the first insn (addis) in fusing the combination of addis and loads to
;; GPR registers on power8.
(define_predicate "fusion_gpr_addis"
if ((value & (HOST_WIDE_INT)0xffff0000) == 0)
return 0;
- /* Power8 currently will only do the fusion if the top 11 bits of the addis
- value are all 1's or 0's. Ignore this restriction if we are testing
- advanced fusion. */
- if (TARGET_P9_FUSION)
- return 1;
-
- return (IN_RANGE (value >> 16, -32, 31));
+ /* Power8 only does the fusion if the top 12 bits of the addis value are all
+ 1's or 0's. */
+ return (IN_RANGE (value >> 16, -16, 15));
})
;; Match the second insn (lbz, lhz, lwz, ld) in fusing the combination of addis
switch (mode)
{
- case QImode:
- case HImode:
- case SImode:
+ case E_QImode:
+ case E_HImode:
+ case E_SImode:
break;
- case DImode:
+ case E_DImode:
if (!TARGET_POWERPC64)
return 0;
break;
+ /* Do not allow SF/DFmode in GPR fusion. While the loads do occur, they
+ are not common. */
default:
return 0;
}
;; Match a GPR load (lbz, lhz, lwz, ld) that uses a combined address in the
;; memory field with both the addis and the memory offset. Sign extension
;; is not handled here, since lha and lwa are not fused.
-;; With extended fusion, also match a FPR load (lfd, lfs) and float_extend
(define_predicate "fusion_addis_mem_combo_load"
- (match_code "mem,zero_extend,float_extend")
+ (match_code "mem,zero_extend")
{
rtx addr, base, offset;
- /* Handle zero/float extend. */
- if (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == FLOAT_EXTEND)
+ /* Handle zero extend. */
+ if (GET_CODE (op) == ZERO_EXTEND)
{
op = XEXP (op, 0);
mode = GET_MODE (op);
switch (mode)
{
- case QImode:
- case HImode:
- case SImode:
+ case E_QImode:
+ case E_HImode:
+ case E_SImode:
break;
- case DImode:
+ /* Do not fuse 64-bit DImode in 32-bit since it splits into two
+ separate instructions. */
+ case E_DImode:
if (!TARGET_POWERPC64)
return 0;
break;
- case SFmode:
- case DFmode:
- if (!TARGET_P9_FUSION)
- return 0;
- break;
-
+ /* Do not allow SF/DFmode in GPR fusion. While the loads do occur, they
+ are not common. */
default:
return 0;
}
return 0;
})
-
-;; Like fusion_addis_mem_combo_load, but for stores
-(define_predicate "fusion_addis_mem_combo_store"
- (match_code "mem")
-{
- rtx addr, base, offset;
-
- if (!MEM_P (op) || !TARGET_P9_FUSION)
- return 0;
-
- switch (mode)
- {
- case QImode:
- case HImode:
- case SImode:
- break;
-
- case DImode:
- if (!TARGET_POWERPC64)
- return 0;
- break;
-
- case SFmode:
- if (!TARGET_SF_FPR)
- return 0;
- break;
-
- case DFmode:
- if (!TARGET_DF_FPR)
- return 0;
- break;
-
- default:
- return 0;
- }
-
- addr = XEXP (op, 0);
- if (GET_CODE (addr) != PLUS && GET_CODE (addr) != LO_SUM)
- return 0;
-
- base = XEXP (addr, 0);
- if (!fusion_gpr_addis (base, GET_MODE (base)))
- return 0;
-
- offset = XEXP (addr, 1);
- if (GET_CODE (addr) == PLUS)
- return satisfies_constraint_I (offset);
-
- else if (GET_CODE (addr) == LO_SUM)
- {
- if (TARGET_XCOFF || (TARGET_ELF && TARGET_POWERPC64))
- return small_toc_ref (offset, GET_MODE (offset));
-
- else if (TARGET_ELF && !TARGET_POWERPC64)
- return CONSTANT_P (offset);
- }
-
- return 0;
-})
-
-;; Return true if the operand is a float_extend or zero extend of an
-;; offsettable memory operand suitable for use in fusion
-(define_predicate "fusion_offsettable_mem_operand"
- (match_code "mem,zero_extend,float_extend")
-{
- if (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == FLOAT_EXTEND)
- {
- op = XEXP (op, 0);
- mode = GET_MODE (op);
- }
-
- if (!memory_operand (op, mode))
- return 0;
-
- return offsettable_nonstrict_memref_p (op);
-})