diff options
Diffstat (limited to 'gcc/config/rs6000/predicates.md')
-rw-r--r-- | gcc/config/rs6000/predicates.md | 203 |
1 files changed, 197 insertions, 6 deletions
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 1c99f7712f5..3b1a4561fba 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -142,6 +142,11 @@ (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 a signed 8-bit constant integer. ;; Integer multiplication complete more quickly (define_predicate "s8bit_cint_operand" @@ -163,6 +168,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") @@ -271,6 +282,70 @@ 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") @@ -1598,6 +1673,35 @@ 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" @@ -1620,8 +1724,6 @@ else 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. */ value = INTVAL (int_const); if ((value & (HOST_WIDE_INT)0xffff) != 0) return 0; @@ -1629,6 +1731,12 @@ 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)); }) @@ -1694,13 +1802,14 @@ ;; 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. -(define_predicate "fusion_gpr_mem_combo" - (match_code "mem,zero_extend") +;; 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") { rtx addr, base, offset; - /* Handle zero extend. */ - if (GET_CODE (op) == ZERO_EXTEND) + /* Handle zero/float extend. */ + if (GET_CODE (op) == ZERO_EXTEND || GET_CODE (op) == FLOAT_EXTEND) { op = XEXP (op, 0); mode = GET_MODE (op); @@ -1721,6 +1830,71 @@ return 0; break; + case SFmode: + case DFmode: + if (!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 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; } @@ -1748,3 +1922,20 @@ 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); +}) |