summaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/predicates.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/predicates.md')
-rw-r--r--gcc/config/rs6000/predicates.md203
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);
+})