Mercurial > hg > CbC > CbC_gcc
diff gcc/config/rs6000/predicates.md @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/config/rs6000/predicates.md Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/config/rs6000/predicates.md Fri Oct 27 22:46:09 2017 +0900 @@ -1,6 +1,5 @@ ;; Predicate definitions for POWER and PowerPC. -;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 -;; Free Software Foundation, Inc. +;; Copyright (C) 2005-2017 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -20,7 +19,7 @@ ;; Return 1 for anything except PARALLEL. (define_predicate "any_operand" - (match_code "const_int,const_double,const,symbol_ref,label_ref,subreg,reg,mem")) + (match_code "const_int,const_double,const_wide_int,const,symbol_ref,label_ref,subreg,reg,mem")) ;; Return 1 for any PARALLEL. (define_predicate "any_parallel_operand" @@ -31,66 +30,221 @@ (and (match_code "reg") (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" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || ALTIVEC_REGNO_P (REGNO (op)) - || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + (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 ALTIVEC_REGNO_P (REGNO (op)); +}) ;; Return 1 if op is a VSX register. (define_predicate "vsx_register_operand" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || VSX_REGNO_P (REGNO (op)) - || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + (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); + + if (!REG_P (op)) + return 0; + + if (REGNO (op) >= FIRST_PSEUDO_REGISTER) + return 1; + + return VSX_REGNO_P (REGNO (op)); +}) ;; Return 1 if op is a vector register that operates on floating point vectors ;; (either altivec or VSX). (define_predicate "vfloat_operand" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || VFLOAT_REGNO_P (REGNO (op)) - || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + (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 VFLOAT_REGNO_P (REGNO (op)); +}) ;; Return 1 if op is a vector register that operates on integer vectors ;; (only altivec, VSX doesn't support integer vectors) (define_predicate "vint_operand" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || VINT_REGNO_P (REGNO (op)) - || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + (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 VINT_REGNO_P (REGNO (op)); +}) ;; Return 1 if op is a vector register to do logical operations on (and, or, ;; xor, etc.) (define_predicate "vlogical_operand" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || VLOGICAL_REGNO_P (REGNO (op)) - || REGNO (op) > LAST_VIRTUAL_REGISTER"))) + (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 VLOGICAL_REGNO_P (REGNO (op)); +}) ;; Return 1 if op is the carry register. (define_predicate "ca_operand" - (and (match_code "reg") - (match_test "CA_REGNO_P (REGNO (op))"))) + (match_operand 0 "register_operand") +{ + if (GET_CODE (op) == SUBREG) + 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") (match_test "INTVAL (op) >= -16 && INTVAL (op) <= 15"))) +;; Return 1 if op is a unsigned 3-bit constant integer. +(define_predicate "u3bit_cint_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 7"))) + ;; Return 1 if op is a unsigned 5-bit constant integer. (define_predicate "u5bit_cint_operand" (and (match_code "const_int") (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 31"))) +;; Return 1 if op is a unsigned 6-bit constant integer. +(define_predicate "u6bit_cint_operand" + (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 "INTVAL (op) >= -128 && INTVAL (op) <= 127"))) +;; Return 1 if op is a unsigned 10-bit constant integer. +(define_predicate "u10bit_cint_operand" + (and (match_code "const_int") + (match_test "INTVAL (op) >= 0 && INTVAL (op) <= 1023"))) + ;; Return 1 if op is a constant integer that can fit in a D field. (define_predicate "short_cint_operand" (and (match_code "const_int") @@ -101,6 +255,12 @@ (and (match_code "const_int") (match_test "satisfies_constraint_K (op)"))) +;; Return 1 if op is a constant integer that is a signed 16-bit constant +;; shifted left 16 bits +(define_predicate "upper16_cint_operand" + (and (match_code "const_int") + (match_test "satisfies_constraint_L (op)"))) + ;; Return 1 if op is a constant integer that cannot fit in a signed D field. (define_predicate "non_short_cint_operand" (and (match_code "const_int") @@ -112,37 +272,264 @@ (and (match_code "const_int") (match_test "INTVAL (op) > 0 && exact_log2 (INTVAL (op)) >= 0"))) +;; Match op = 0 or op = 1. +(define_predicate "const_0_to_1_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 1)"))) + +;; Match op = 0..3. +(define_predicate "const_0_to_3_operand" + (and (match_code "const_int") + (match_test "IN_RANGE (INTVAL (op), 0, 3)"))) + +;; Match op = 2 or op = 3. +(define_predicate "const_2_to_3_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" - (and (match_operand 0 "register_operand") - (match_test "(GET_CODE (op) != REG - || (REGNO (op) >= ARG_POINTER_REGNUM - && !CA_REGNO_P (REGNO (op))) - || REGNO (op) < MQ_REGNO) - && !((TARGET_E500_DOUBLE || TARGET_SPE) - && invalid_e500_subreg (op, mode))"))) + (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; + + if (TARGET_ALTIVEC && ALTIVEC_REGNO_P (REGNO (op))) + return 1; + + if (TARGET_VSX && VSX_REGNO_P (REGNO (op))) + return 1; + + return INT_REGNO_P (REGNO (op)) || FP_REGNO_P (REGNO (op)); +}) + +;; Return 1 if op is a general purpose register. Unlike gpc_reg_operand, don't +;; 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 (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 INT_REGNO_P (REGNO (op)); +}) + +;; 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 (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (!REG_P (op)) + return 0; + + if (REGNO (op) >= FIRST_PSEUDO_REGISTER) + return 0; + + return INT_REGNO_P (REGNO (op)); +}) + +;; Like int_reg_operand, but only return true for base registers +(define_predicate "base_reg_operand" + (match_operand 0 "int_reg_operand") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (!REG_P (op)) + return 0; + + return (REGNO (op) != FIRST_GPR_REGNO); +}) + + +;; Return true if this is a traditional floating point register +(define_predicate "fpr_reg_operand" + (match_code "reg,subreg") +{ + HOST_WIDE_INT r; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (!REG_P (op)) + return 0; + + r = REGNO (op); + if (r >= FIRST_PSEUDO_REGISTER) + return 1; + + 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") +{ + if (!TARGET_HTM) + return 0; + + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (op); + + if (!REG_P (op)) + return 0; + + switch (REGNO (op)) + { + case TFHAR_REGNO: + case TFIAR_REGNO: + case TEXASR_REGNO: + return 1; + default: + break; + } + + /* Unknown SPR. */ + return 0; +}) + +;; Return 1 if op is a general purpose register that is an even register +;; which suitable for a load/store quad operation +;; Subregs are not allowed here because when they are combine can +;; create (subreg:PTI (reg:TI pseudo)) which will cause reload to +;; think the innermost reg needs reloading, in TImode instead of +;; PTImode. So reload will choose a reg in TImode which has no +;; requirement that the reg be even. +(define_predicate "quad_int_reg_operand" + (match_code "reg") +{ + HOST_WIDE_INT r; + + if (!TARGET_QUAD_MEMORY && !TARGET_QUAD_MEMORY_ATOMIC) + return 0; + + r = REGNO (op); + if (r >= FIRST_PSEUDO_REGISTER) + return 1; + + return (INT_REGNO_P (r) && ((r & 1) == 0)); +}) ;; Return 1 if op is a register that is a condition register field. (define_predicate "cc_reg_operand" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || REGNO (op) > LAST_VIRTUAL_REGISTER - || CR_REGNO_P (REGNO (op))"))) + (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; + + return CR_REGNO_P (REGNO (op)); +}) ;; Return 1 if op is a register that is a condition register field not cr0. (define_predicate "cc_reg_not_cr0_operand" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || REGNO (op) > LAST_VIRTUAL_REGISTER - || CR_REGNO_NOT_CR0_P (REGNO (op))"))) + (match_operand 0 "register_operand") +{ + if (GET_CODE (op) == SUBREG) + op = SUBREG_REG (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" - (and (match_operand 0 "register_operand") - (match_test "GET_CODE (op) != REG - || REGNO (op) > LAST_VIRTUAL_REGISTER - || (rs6000_gen_cell_microcode && CR_REGNO_NOT_CR0_P (REGNO (op))) - || (!rs6000_gen_cell_microcode && CR_REGNO_P (REGNO (op)))"))) + if (!REG_P (op)) + return 0; + + if (REGNO (op) > LAST_VIRTUAL_REGISTER) + return 1; + + return CR_REGNO_NOT_CR0_P (REGNO (op)); +}) ;; Return 1 if op is a constant integer valid for D field ;; or non-special register register. @@ -151,17 +538,6 @@ (match_operand 0 "short_cint_operand") (match_operand 0 "gpc_reg_operand"))) -;; Return 1 if op is a constant integer valid whose negation is valid for -;; D field or non-special register register. -;; Do not allow a constant zero because all patterns that call this -;; predicate use "addic r1,r2,-const" to set carry when r2 is greater than -;; or equal to const, which does not work for zero. -(define_predicate "reg_or_neg_short_operand" - (if_then_else (match_code "const_int") - (match_test "satisfies_constraint_P (op) - && INTVAL (op) != 0") - (match_operand 0 "gpc_reg_operand"))) - ;; Return 1 if op is a constant integer valid for DS field ;; or non-special register. (define_predicate "reg_or_aligned_short_operand" @@ -177,32 +553,37 @@ (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") + (match_test "((unsigned HOST_WIDE_INT) INTVAL (op) + + (mode == SImode ? 0x80000000 : 0x80008000)) + < (unsigned HOST_WIDE_INT) 0x100000000ll"))) + ;; Return 1 if op is a constant integer valid for addition ;; or non-special register. (define_predicate "reg_or_add_cint_operand" (if_then_else (match_code "const_int") - (match_test "(HOST_BITS_PER_WIDE_INT == 32 - && (mode == SImode || INTVAL (op) < 0x7fff8000)) - || ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000) - < (unsigned HOST_WIDE_INT) 0x100000000ll)") + (match_operand 0 "add_cint_operand") (match_operand 0 "gpc_reg_operand"))) ;; Return 1 if op is a constant integer valid for subtraction ;; or non-special register. (define_predicate "reg_or_sub_cint_operand" (if_then_else (match_code "const_int") - (match_test "(HOST_BITS_PER_WIDE_INT == 32 - && (mode == SImode || - INTVAL (op) < 0x7fff8000)) - || ((unsigned HOST_WIDE_INT) (- INTVAL (op) - + (mode == SImode - ? 0x80000000 : 0x80008000)) - < (unsigned HOST_WIDE_INT) 0x100000000ll)") + (match_test "(unsigned HOST_WIDE_INT) + (- UINTVAL (op) + (mode == SImode ? 0x80000000 : 0x80008000)) + < (unsigned HOST_WIDE_INT) 0x100000000ll") (match_operand 0 "gpc_reg_operand"))) ;; Return 1 if op is any 32-bit unsigned constant integer @@ -213,109 +594,95 @@ && INTVAL (op) >= 0) || ((INTVAL (op) & GET_MODE_MASK (mode) & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 0)") - (if_then_else (match_code "const_double") - (match_test "GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT - && mode == DImode - && CONST_DOUBLE_HIGH (op) == 0") - (match_operand 0 "gpc_reg_operand")))) + (match_operand 0 "gpc_reg_operand"))) + +;; Like reg_or_logical_cint_operand, but allow vsx registers +(define_predicate "vsx_reg_or_cint_operand" + (ior (match_operand 0 "vsx_register_operand") + (match_operand 0 "reg_or_logical_cint_operand"))) ;; Return 1 if operand is a CONST_DOUBLE that can be set in a register ;; with no more than one instruction per word. (define_predicate "easy_fp_constant" (match_code "const_double") { - long k[4]; - REAL_VALUE_TYPE rv; - if (GET_MODE (op) != mode || (!SCALAR_FLOAT_MODE_P (mode) && mode != DImode)) return 0; /* Consider all constants with -msoft-float to be easy. */ - if ((TARGET_SOFT_FLOAT || TARGET_E500_SINGLE + if ((TARGET_SOFT_FLOAT || (TARGET_HARD_FLOAT && (TARGET_SINGLE_FLOAT && ! TARGET_DOUBLE_FLOAT))) && mode != DImode) 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)) + return 1; + /* If we are using V.4 style PIC, consider all constants to be hard. */ if (flag_pic && DEFAULT_ABI == ABI_V4) return 0; -#ifdef TARGET_RELOCATABLE - /* Similarly if we are using -mrelocatable, consider all constants - to be hard. */ - if (TARGET_RELOCATABLE) - return 0; -#endif + /* If 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 TFmode: - if (TARGET_E500_DOUBLE) - return 0; + case E_KFmode: + case E_IFmode: + case E_TFmode: + case E_DFmode: + case E_SFmode: + return 0; - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k); - - return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1); + case E_DImode: + return (num_insns_constant (op, DImode) <= 2); - case DFmode: - /* The constant 0.f is easy under VSX. */ - if (op == CONST0_RTX (DFmode) && VECTOR_UNIT_VSX_P (DFmode)) - return 1; + case E_SImode: + return 1; - /* Force constants to memory before reload to utilize - compress_float_constant. - Avoid this when flag_unsafe_math_optimizations is enabled - because RDIV division to reciprocal optimization is not able - to regenerate the division. */ - if (TARGET_E500_DOUBLE - || (!reload_in_progress && !reload_completed - && !flag_unsafe_math_optimizations)) - return 0; + default: + gcc_unreachable (); + } +}) - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_DOUBLE (rv, k); +;; Return 1 if the operand is a constant that can loaded with a XXSPLTIB +;; instruction and then a VUPKHSB, VECSB2W or VECSB2D instruction. - return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1 - && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1); - - case SFmode: - /* The constant 0.f is easy. */ - if (op == CONST0_RTX (SFmode)) - return 1; +(define_predicate "xxspltib_constant_split" + (match_code "const_vector,vec_duplicate,const_int") +{ + int value = 256; + int num_insns = -1; - /* Force constants to memory before reload to utilize - compress_float_constant. - Avoid this when flag_unsafe_math_optimizations is enabled - because RDIV division to reciprocal optimization is not able - to regenerate the division. */ - if (!reload_in_progress && !reload_completed - && !flag_unsafe_math_optimizations) - return 0; + if (!xxspltib_constant_p (op, mode, &num_insns, &value)) + return false; + + return num_insns > 1; +}) + - REAL_VALUE_FROM_CONST_DOUBLE (rv, op); - REAL_VALUE_TO_TARGET_SINGLE (rv, k[0]); - - return num_insns_constant_wide (k[0]) == 1; +;; Return 1 if the operand is constant that can loaded directly with a XXSPLTIB +;; instruction. - case DImode: - return ((TARGET_POWERPC64 - && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0) - || (num_insns_constant (op, DImode) <= 2)); +(define_predicate "xxspltib_constant_nosplit" + (match_code "const_vector,vec_duplicate,const_int") +{ + int value = 256; + int num_insns = -1; - case SImode: - return 1; + if (!xxspltib_constant_p (op, mode, &num_insns, &value)) + return false; - default: - gcc_unreachable (); - } + return num_insns == 1; }) ;; Return 1 if the operand is a CONST_VECTOR and can be loaded into a @@ -328,40 +695,27 @@ 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)) { - if (zero_constant (op, mode)) + int value = 256; + int num_insns = -1; + + if (zero_constant (op, mode) || all_ones_constant (op, mode)) + return true; + + if (TARGET_P9_VECTOR + && xxspltib_constant_p (op, mode, &num_insns, &value)) return true; 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; }) @@ -372,9 +726,11 @@ (match_test "easy_altivec_constant (op, mode)"))) { HOST_WIDE_INT val; + int elt; if (mode == V2DImode || mode == V2DFmode) return 0; - val = const_vector_elt_as_int (op, GET_MODE_NUNITS (mode) - 1); + elt = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 : 0; + val = const_vector_elt_as_int (op, elt); val = ((val & 0xff) ^ 0x80) - 0x80; return EASY_VECTOR_15_ADD_SELF (val); }) @@ -386,19 +742,38 @@ (match_test "easy_altivec_constant (op, mode)"))) { HOST_WIDE_INT val; + int elt; if (mode == V2DImode || mode == V2DFmode) return 0; - val = const_vector_elt_as_int (op, GET_MODE_NUNITS (mode) - 1); + elt = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 : 0; + val = const_vector_elt_as_int (op, elt); return EASY_VECTOR_MSB (val, GET_MODE_INNER (mode)); }) -;; Return 1 if operand is constant zero (scalars and vectors). -(define_predicate "zero_constant" - (and (match_code "const_int,const_double,const_vector") - (match_test "op == CONST0_RTX (mode)"))) +;; Return true if this is an easy altivec constant that we form +;; by using VSLDOI. +(define_predicate "easy_vector_constant_vsldoi" + (and (match_code "const_vector") + (and (match_test "TARGET_ALTIVEC") + (and (match_test "easy_altivec_constant (op, mode)") + (match_test "vspltis_shifted (op) != 0"))))) + +;; 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; + + 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. -;; or non-special register register field no cr0 (define_predicate "zero_fp_constant" (and (match_code "const_double") (match_test "SCALAR_FLOAT_MODE_P (mode) @@ -412,34 +787,54 @@ (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 memory operand with an address divisible by 4 -(define_predicate "word_offset_memref_operand" - (match_operand 0 "memory_operand") +;; 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") { - /* Address inside MEM. */ - op = XEXP (op, 0); + 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); +}) - /* Extract address from auto-inc/dec. */ - if (GET_CODE (op) == PRE_INC - || GET_CODE (op) == PRE_DEC) - op = XEXP (op, 0); - else if (GET_CODE (op) == PRE_MODIFY) - op = XEXP (op, 1); +;; 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" + (match_code "mem") +{ + if (!TARGET_QUAD_MEMORY && !TARGET_SYNC_TI) + return false; + + if (GET_MODE_SIZE (mode) != 16 || !MEM_P (op) || MEM_ALIGN (op) < 128) + return false; - return (GET_CODE (op) != PLUS - || ! REG_P (XEXP (op, 0)) - || GET_CODE (XEXP (op, 1)) != CONST_INT - || INTVAL (XEXP (op, 1)) % 4 == 0); + return quad_address_p (XEXP (op, 0), mode, false); +}) + +;; Return 1 if the operand is suitable for load/store to vector registers with +;; d-form addressing (register+offset), which was added in ISA 3.0. +;; Unlike quad_memory_operand, we do not have to check for alignment. +(define_predicate "vsx_quad_dform_memory_operand" + (match_code "mem") +{ + if (!TARGET_P9_VECTOR || !MEM_P (op) || GET_MODE_SIZE (mode) != 16) + return false; + + return quad_address_p (XEXP (op, 0), mode, false); }) ;; Return 1 if the operand is an indexed or indirect memory operand. @@ -456,6 +851,19 @@ return indexed_or_indirect_address (op, mode); }) +;; Like indexed_or_indirect_operand, but also allow a GPR register if direct +;; moves are supported. +(define_predicate "reg_or_indexed_operand" + (match_code "mem,reg,subreg") +{ + if (MEM_P (op)) + return indexed_or_indirect_operand (op, mode); + else if (TARGET_DIRECT_MOVE) + return register_operand (op, mode); + return + 0; +}) + ;; Return 1 if the operand is an indexed or indirect memory operand with an ;; AND -16 in it, used to recognize when we need to switch to Altivec loads ;; to realign loops instead of VSX (altivec silently ignores the bottom bits, @@ -481,14 +889,26 @@ && REG_P (XEXP (op, 1)))") (match_operand 0 "address_operand"))) -;; Used for the destination of the fix_truncdfsi2 expander. -;; If stfiwx will be used, the result goes to memory; otherwise, -;; we're going to emit a store and a load of a subreg, so the dest is a -;; register. -(define_predicate "fix_trunc_dest_operand" - (if_then_else (match_test "! TARGET_E500_DOUBLE && TARGET_PPC_GFXOPT") - (match_operand 0 "memory_operand") - (match_operand 0 "gpc_reg_operand"))) +;; Return 1 if the operand is an index-form address. +(define_special_predicate "indexed_address" + (match_test "(GET_CODE (op) == PLUS + && REG_P (XEXP (op, 0)) + && REG_P (XEXP (op, 1)))")) + +;; Return 1 if the operand is a MEM with an update-form address. This may +;; also include update-indexed form. +(define_special_predicate "update_address_mem" + (match_test "(MEM_P (op) + && (GET_CODE (XEXP (op, 0)) == PRE_INC + || GET_CODE (XEXP (op, 0)) == PRE_DEC + || GET_CODE (XEXP (op, 0)) == PRE_MODIFY))")) + +;; Return 1 if the operand is a MEM with an indexed-form address. +(define_special_predicate "indexed_address_mem" + (match_test "(MEM_P (op) + && (indexed_address (XEXP (op, 0), mode) + || (GET_CODE (XEXP (op, 0)) == PRE_MODIFY + && indexed_address (XEXP (XEXP (op, 0), 1), mode))))")) ;; Return 1 if the operand is either a non-special register or can be used ;; as the operand of a `mode' add insn. @@ -498,6 +918,12 @@ || satisfies_constraint_L (op)") (match_operand 0 "gpc_reg_operand"))) +;; Return 1 if the operand is either a non-special register, or 0, or -1. +(define_predicate "adde_operand" + (if_then_else (match_code "const_int") + (match_test "INTVAL (op) == 0 || INTVAL (op) == -1") + (match_operand 0 "gpc_reg_operand"))) + ;; Return 1 if OP is a constant but not a valid add_operand. (define_predicate "non_add_cint_operand" (and (match_code "const_int") @@ -507,29 +933,11 @@ ;; Return 1 if the operand is a constant that can be used as the operand ;; of an OR or XOR. (define_predicate "logical_const_operand" - (match_code "const_int,const_double") + (match_code "const_int") { - HOST_WIDE_INT opl, oph; - - if (GET_CODE (op) == CONST_INT) - { - opl = INTVAL (op) & GET_MODE_MASK (mode); + HOST_WIDE_INT opl; - if (HOST_BITS_PER_WIDE_INT <= 32 - && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0) - return 0; - } - else if (GET_CODE (op) == CONST_DOUBLE) - { - gcc_assert (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT); - - opl = CONST_DOUBLE_LOW (op); - oph = CONST_DOUBLE_HIGH (op); - if (oph != 0) - return 0; - } - else - return 0; + opl = INTVAL (op) & GET_MODE_MASK (mode); return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0 || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0); @@ -544,168 +952,18 @@ ;; Return 1 if op is a constant that is not a logical operand, but could ;; be split into one. (define_predicate "non_logical_cint_operand" - (and (match_code "const_int,const_double") + (and (match_code "const_int,const_wide_int") (and (not (match_operand 0 "logical_operand")) (match_operand 0 "reg_or_logical_cint_operand")))) -;; Return 1 if op is a constant that can be encoded in a 32-bit mask, -;; suitable for use with rlwinm (no more than two 1->0 or 0->1 -;; transitions). Reject all ones and all zeros, since these should have -;; been optimized away and confuse the making of MB and ME. -(define_predicate "mask_operand" - (match_code "const_int") -{ - HOST_WIDE_INT c, lsb; - - c = INTVAL (op); - - if (TARGET_POWERPC64) - { - /* Fail if the mask is not 32-bit. */ - if (mode == DImode && (c & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0) - return 0; - - /* Fail if the mask wraps around because the upper 32-bits of the - mask will all be 1s, contrary to GCC's internal view. */ - if ((c & 0x80000001) == 0x80000001) - return 0; - } - - /* We don't change the number of transitions by inverting, - so make sure we start with the LS bit zero. */ - if (c & 1) - c = ~c; - - /* Reject all zeros or all ones. */ - if (c == 0) - return 0; - - /* Find the first transition. */ - lsb = c & -c; - - /* Invert to look for a second transition. */ - c = ~c; - - /* Erase first transition. */ - c &= -lsb; - - /* Find the second transition (if any). */ - lsb = c & -c; - - /* Match if all the bits above are 1's (or c is zero). */ - return c == -lsb; -}) - -;; Return 1 for the PowerPC64 rlwinm corner case. -(define_predicate "mask_operand_wrap" - (match_code "const_int") -{ - HOST_WIDE_INT c, lsb; - - c = INTVAL (op); - - if ((c & 0x80000001) != 0x80000001) - return 0; - - c = ~c; - if (c == 0) - return 0; - - lsb = c & -c; - c = ~c; - c &= -lsb; - lsb = c & -c; - return c == -lsb; -}) - -;; Return 1 if the operand is a constant that is a PowerPC64 mask -;; suitable for use with rldicl or rldicr (no more than one 1->0 or 0->1 -;; transition). Reject all zeros, since zero should have been -;; optimized away and confuses the making of MB and ME. -(define_predicate "mask64_operand" - (match_code "const_int") -{ - HOST_WIDE_INT c, lsb; - - c = INTVAL (op); - - /* Reject all zeros. */ - if (c == 0) - return 0; - - /* We don't change the number of transitions by inverting, - so make sure we start with the LS bit zero. */ - if (c & 1) - c = ~c; - - /* Find the first transition. */ - lsb = c & -c; - - /* Match if all the bits above are 1's (or c is zero). */ - return c == -lsb; -}) - -;; Like mask64_operand, but allow up to three transitions. This -;; predicate is used by insn patterns that generate two rldicl or -;; rldicr machine insns. -(define_predicate "mask64_2_operand" - (match_code "const_int") -{ - HOST_WIDE_INT c, lsb; - - c = INTVAL (op); - - /* Disallow all zeros. */ - if (c == 0) - return 0; - - /* We don't change the number of transitions by inverting, - so make sure we start with the LS bit zero. */ - if (c & 1) - c = ~c; - - /* Find the first transition. */ - lsb = c & -c; - - /* Invert to look for a second transition. */ - c = ~c; - - /* Erase first transition. */ - c &= -lsb; - - /* Find the second transition. */ - lsb = c & -c; - - /* Invert to look for a third transition. */ - c = ~c; - - /* Erase second transition. */ - c &= -lsb; - - /* Find the third transition (if any). */ - lsb = c & -c; - - /* Match if all the bits above are 1's (or c is zero). */ - return c == -lsb; -}) - -;; Like and_operand, but also match constants that can be implemented -;; with two rldicl or rldicr insns. -(define_predicate "and64_2_operand" - (ior (match_operand 0 "mask64_2_operand") - (if_then_else (match_test "fixed_regs[CR0_REGNO]") - (match_operand 0 "gpc_reg_operand") - (match_operand 0 "logical_operand")))) - ;; Return 1 if the operand is either a non-special register or a ;; constant that can be used as the operand of a logical AND. (define_predicate "and_operand" - (ior (match_operand 0 "mask_operand") - (ior (and (match_test "TARGET_POWERPC64 && mode == DImode") - (match_operand 0 "mask64_operand")) - (if_then_else (match_test "fixed_regs[CR0_REGNO]") - (match_operand 0 "gpc_reg_operand") - (match_operand 0 "logical_operand"))))) + (ior (and (match_code "const_int") + (match_test "rs6000_is_valid_and_mask (op, mode)")) + (if_then_else (match_test "fixed_regs[CR0_REGNO]") + (match_operand 0 "gpc_reg_operand") + (match_operand 0 "logical_operand")))) ;; Return 1 if the operand is either a logical operand or a short cint operand. (define_predicate "scc_eq_operand" @@ -714,26 +972,26 @@ ;; 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" - (ior (match_operand 0 "zero_fp_constant") + (ior (and (match_test "TARGET_VSX") + (match_operand 0 "zero_fp_constant")) (match_operand 0 "reg_or_mem_operand"))) +;; Return 1 if the operand is a CONST_INT and it is the element for 64-bit +;; data types inside of a vector that scalar instructions operate on +(define_predicate "vsx_scalar_64bit" + (match_code "const_int") +{ + return (INTVAL (op) == VECTOR_ELEMENT_SCALAR_64BIT); +}) + ;; Return 1 if the operand is a general register or memory operand without ;; pre_inc or pre_dec or pre_modify, which produces invalid form of PowerPC ;; lwa instruction. @@ -750,6 +1008,7 @@ return true; if (!memory_operand (inner, mode)) return false; + addr = XEXP (inner, 0); if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC @@ -803,16 +1062,18 @@ (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) - && (DEFAULT_ABI != ABI_AIX - || !SYMBOL_REF_EXTERNAL_P (op))) - || (op == XEXP (DECL_RTL (current_function_decl), - 0)))"))) + && (SYMBOL_REF_LOCAL_P (op) + || (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) + || SYMBOL_REF_WEAK (op)))"))) ;; Return 1 if this operand is a valid input for a move insn. (define_predicate "input_operand" - (match_code "label_ref,symbol_ref,const,high,reg,subreg,mem, - const_double,const_vector,const_int,plus") + (match_code "symbol_ref,const,reg,subreg,mem, + const_double,const_wide_int,const_vector,const_int") { /* Memory is always valid. */ if (memory_operand (op, mode)) @@ -820,14 +1081,12 @@ /* For floating-point, easy constants are valid. */ if (SCALAR_FLOAT_MODE_P (mode) - && CONSTANT_P (op) && easy_fp_constant (op, mode)) return 1; /* Allow any integer constant. */ if (GET_MODE_CLASS (mode) == MODE_INT - && (GET_CODE (op) == CONST_INT - || GET_CODE (op) == CONST_DOUBLE)) + && CONST_SCALAR_INT_P (op)) return 1; /* Allow easy vector constants. */ @@ -835,32 +1094,22 @@ && 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) || GET_MODE_SIZE (mode) > UNITS_PER_WORD) return register_operand (op, mode); + /* We don't allow moving the carry bit around. */ + if (ca_operand (op, mode)) + return 0; + /* The only cases left are integral modes one word or smaller (we do not get called for MODE_CC values). These can be in any register. */ if (register_operand (op, mode)) return 1; - /* A SYMBOL_REF referring to the TOC is valid. */ - if (legitimate_constant_pool_address_p (op, mode, false)) - return 1; - - /* A constant pool expression (relative to the TOC) is valid */ - if (toc_relative_expr_p (op)) - return 1; - /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region to be valid. */ if (DEFAULT_ABI == ABI_V4 @@ -871,18 +1120,42 @@ return 0; }) -;; Return true if OP is an invalid SUBREG operation on the e500. -(define_predicate "rs6000_nonimmediate_operand" +;; Return 1 if this operand is a valid input for a vsx_splat insn. +(define_predicate "splat_input_operand" (match_code "reg,subreg,mem") { - if ((TARGET_E500_DOUBLE || TARGET_SPE) - && GET_CODE (op) == SUBREG - && invalid_e500_subreg (op, mode)) - return 0; + 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; - return nonimmediate_operand (op, mode); + if (MEM_P (op)) + { + rtx addr = XEXP (op, 0); + + if (! volatile_ok && MEM_VOLATILE_P (op)) + return 0; + + if (lra_in_progress || reload_completed) + return indexed_or_indirect_address (addr, vmode); + else + return memory_address_addr_space_p (vmode, addr, MEM_ADDR_SPACE (op)); + } + return gpc_reg_operand (op, mode); }) +;; Return true if operand is an operator used in rotate-and-mask instructions. +(define_predicate "rotate_mask_operator" + (match_code "rotate,ashift,lshiftrt")) + ;; Return true if operand is boolean operator. (define_predicate "boolean_operator" (match_code "and,ior,xor")) @@ -895,10 +1168,6 @@ (define_special_predicate "equality_operator" (match_code "eq,ne")) -;; Return true if operand is MIN or MAX operator. -(define_predicate "min_max_operator" - (match_code "smin,smax,umin,umax")) - ;; Return 1 if OP is a comparison operation that is valid for a branch ;; instruction. We check the opcode against the mode of the CC value. ;; validate_condition_mode is an assertion. @@ -909,10 +1178,13 @@ GET_MODE (XEXP (op, 0))), 1")))) -(define_predicate "rs6000_cbranch_operator" - (if_then_else (match_test "TARGET_HARD_FLOAT && !TARGET_FPRS") - (match_operand 0 "ordered_comparison_operator") - (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")) + +;; Return 1 if OP is a signed comparison operator. +(define_predicate "signed_comparison_operator" + (match_code "lt,gt,le,ge")) ;; Return 1 if OP is a comparison operation that is valid for an SCC insn -- ;; it must be a positive comparison. @@ -926,6 +1198,22 @@ (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 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" @@ -1272,6 +1560,26 @@ return 1; }) +;; Return 1 if OP is valid for crsave insn, known to be a PARALLEL. +(define_predicate "crsave_operation" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + int i; + + for (i = 1; i < count; i++) + { + rtx exp = XVECEXP (op, 0, i); + + if (GET_CODE (exp) != USE + || GET_CODE (XEXP (exp, 0)) != REG + || GET_MODE (XEXP (exp, 0)) != CCmode + || ! CR_REGNO_P (REGNO (XEXP (exp, 0)))) + return 0; + } + return 1; +}) + ;; Return 1 if OP is valid for lmw insn, known to be a PARALLEL. (define_predicate "lmw_operation" (match_code "parallel") @@ -1304,7 +1612,7 @@ if (base_regno == 0) return 0; } - else if (rs6000_legitimate_offset_address_p (SImode, src_addr, 0)) + else if (rs6000_legitimate_offset_address_p (SImode, src_addr, false, false)) { offset = INTVAL (XEXP (src_addr, 1)); base_regno = REGNO (XEXP (src_addr, 0)); @@ -1332,7 +1640,7 @@ newoffset = 0; addr_reg = newaddr; } - else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0)) + else if (rs6000_legitimate_offset_address_p (SImode, newaddr, false, false)) { addr_reg = XEXP (newaddr, 0); newoffset = INTVAL (XEXP (newaddr, 1)); @@ -1379,7 +1687,7 @@ if (base_regno == 0) return 0; } - else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, 0)) + else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, false, false)) { offset = INTVAL (XEXP (dest_addr, 1)); base_regno = REGNO (XEXP (dest_addr, 0)); @@ -1407,7 +1715,7 @@ newoffset = 0; addr_reg = newaddr; } - else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0)) + else if (rs6000_legitimate_offset_address_p (SImode, newaddr, false, false)) { addr_reg = XEXP (newaddr, 0); newoffset = INTVAL (XEXP (newaddr, 1)); @@ -1421,3 +1729,302 @@ return 1; }) + +;; Return 1 if OP is a stack tie operand. +(define_predicate "tie_operand" + (match_code "parallel") +{ + return (GET_CODE (XVECEXP (op, 0, 0)) == SET + && GET_CODE (XEXP (XVECEXP (op, 0, 0), 0)) == MEM + && GET_MODE (XEXP (XVECEXP (op, 0, 0), 0)) == BLKmode + && XEXP (XVECEXP (op, 0, 0), 1) == const0_rtx); +}) + +;; Match a small code model toc reference (or medium and large +;; model toc references before reload). +(define_predicate "small_toc_ref" + (match_code "unspec,plus") +{ + if (GET_CODE (op) == PLUS && add_cint_operand (XEXP (op, 1), mode)) + op = XEXP (op, 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" + (match_code "const_int,high,plus") +{ + HOST_WIDE_INT value; + rtx int_const; + + if (GET_CODE (op) == HIGH) + return 1; + + if (CONST_INT_P (op)) + int_const = op; + + else if (GET_CODE (op) == PLUS + && base_reg_operand (XEXP (op, 0), Pmode) + && CONST_INT_P (XEXP (op, 1))) + int_const = XEXP (op, 1); + + else + return 0; + + value = INTVAL (int_const); + if ((value & (HOST_WIDE_INT)0xffff) != 0) + return 0; + + 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)); +}) + +;; Match the second insn (lbz, lhz, lwz, ld) in fusing the combination of addis +;; and loads to GPR registers on power8. +(define_predicate "fusion_gpr_mem_load" + (match_code "mem,sign_extend,zero_extend") +{ + rtx addr, base, offset; + + /* Handle sign/zero extend. */ + if (GET_CODE (op) == ZERO_EXTEND + || (TARGET_P8_FUSION_SIGN && GET_CODE (op) == SIGN_EXTEND)) + { + op = XEXP (op, 0); + mode = GET_MODE (op); + } + + if (!MEM_P (op)) + return 0; + + switch (mode) + { + case E_QImode: + case E_HImode: + case E_SImode: + break; + + case E_DImode: + if (!TARGET_POWERPC64) + 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 (!base_reg_operand (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; +}) + +;; 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 P9 fusion, also match a fpr/vector load and float_extend +(define_predicate "fusion_addis_mem_combo_load" + (match_code "mem,zero_extend,float_extend") +{ + rtx addr, base, offset; + + /* Handle zero/float extend. */ + if (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == FLOAT_EXTEND) + { + op = XEXP (op, 0); + mode = GET_MODE (op); + } + + if (!MEM_P (op)) + return 0; + + switch (mode) + { + case E_QImode: + case E_HImode: + case E_SImode: + break; + + /* 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; + + /* ISA 2.08/power8 only had fusion of GPR loads. */ + case E_SFmode: + if (!TARGET_P9_FUSION) + return 0; + break; + + /* ISA 2.08/power8 only had fusion of GPR loads. Do not allow 64-bit + DFmode in 32-bit if -msoft-float since it splits into two separate + instructions. */ + case E_DFmode: + if ((!TARGET_POWERPC64 && !TARGET_DF_FPR) || !TARGET_P9_FUSION) + 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; +}) + +;; 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 E_QImode: + case E_HImode: + case E_SImode: + case E_SFmode: + break; + + /* 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; + + /* Do not allow 64-bit DFmode in 32-bit if -msoft-float since it splits + into two separate instructions. Do allow fusion if we have hardware + floating point. */ + case E_DFmode: + if (!TARGET_POWERPC64 && !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); +})