aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8/gcc/config/rs6000/predicates.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8/gcc/config/rs6000/predicates.md')
-rw-r--r--gcc-4.8/gcc/config/rs6000/predicates.md319
1 files changed, 318 insertions, 1 deletions
diff --git a/gcc-4.8/gcc/config/rs6000/predicates.md b/gcc-4.8/gcc/config/rs6000/predicates.md
index 07944db10..0659e066e 100644
--- a/gcc-4.8/gcc/config/rs6000/predicates.md
+++ b/gcc-4.8/gcc/config/rs6000/predicates.md
@@ -124,6 +124,11 @@
(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")
@@ -135,6 +140,11 @@
(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")
@@ -161,11 +171,21 @@
(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..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.
(define_predicate "gpc_reg_operand"
(match_operand 0 "register_operand")
@@ -182,9 +202,95 @@
if (REGNO (op) >= ARG_POINTER_REGNUM && !CA_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.
+(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 (!REG_P (op))
+ return 0;
+
+ if (REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ return 1;
+
+ 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 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
+(define_predicate "quad_int_reg_operand"
+ (match_operand 0 "register_operand")
+{
+ HOST_WIDE_INT r;
+
+ if (!TARGET_QUAD_MEMORY && !TARGET_QUAD_MEMORY_ATOMIC)
+ 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 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"
(match_operand 0 "register_operand")
@@ -315,6 +421,11 @@
&& CONST_DOUBLE_HIGH (op) == 0")
(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"
@@ -333,6 +444,11 @@
&& mode != DImode)
return 1;
+ /* The constant 0.0 is easy under VSX. */
+ if ((mode == SFmode || mode == DFmode || mode == SDmode || mode == DDmode)
+ && VECTOR_UNIT_VSX_P (DFmode) && op == CONST0_RTX (mode))
+ return 1;
+
if (DECIMAL_FLOAT_MODE_P (mode))
return 0;
@@ -521,6 +637,55 @@
(and (match_operand 0 "memory_operand")
(match_test "offsettable_nonstrict_memref_p (op)")))
+;; 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")
+{
+ rtx addr, op0, op1;
+ int ret;
+
+ if (!TARGET_QUAD_MEMORY && !TARGET_SYNC_TI)
+ ret = 0;
+
+ else if (!memory_operand (op, mode))
+ ret = 0;
+
+ else if (GET_MODE_SIZE (GET_MODE (op)) != 16)
+ ret = 0;
+
+ else if (MEM_ALIGN (op) < 128)
+ ret = 0;
+
+ else
+ {
+ addr = XEXP (op, 0);
+ if (int_reg_operand (addr, Pmode))
+ ret = 1;
+
+ else if (GET_CODE (addr) != PLUS)
+ ret = 0;
+
+ else
+ {
+ op0 = XEXP (addr, 0);
+ op1 = XEXP (addr, 1);
+ ret = (int_reg_operand (op0, Pmode)
+ && GET_CODE (op1) == CONST_INT
+ && IN_RANGE (INTVAL (op1), -32768, 32767)
+ && (INTVAL (op1) & 15) == 0);
+ }
+ }
+
+ if (TARGET_DEBUG_ADDR)
+ {
+ fprintf (stderr, "\nquad_memory_operand, ret = %s\n", ret ? "true" : "false");
+ debug_rtx (op);
+ }
+
+ return ret;
+})
+
;; Return 1 if the operand is an indexed or indirect memory operand.
(define_predicate "indexed_or_indirect_operand"
(match_code "mem")
@@ -535,6 +700,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")
+{
+ 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,
@@ -560,6 +738,28 @@
&& REG_P (XEXP (op, 1)))")
(match_operand 0 "address_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 update-indexed-form address. Note
+;; that PRE_INC/PRE_DEC will always be non-indexed (i.e. non X-form) since the
+;; increment is based on the mode size and will therefor always be a const.
+(define_special_predicate "update_indexed_address_mem"
+ (match_test "(MEM_P (op)
+ && GET_CODE (XEXP (op, 0)) == PRE_MODIFY
+ && indexed_address (XEXP (XEXP (op, 0), 1), mode))"))
+
;; 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
@@ -883,7 +1083,8 @@
(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
+ && ((DEFAULT_ABI != ABI_AIX
+ && DEFAULT_ABI != ABI_ELFv2)
|| !SYMBOL_REF_EXTERNAL_P (op)))
|| (op == XEXP (DECL_RTL (current_function_decl),
0)))")))
@@ -1364,6 +1565,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")
@@ -1534,3 +1755,99 @@
return GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_TOCREL;
})
+
+;; 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;
+
+ /* 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;
+
+ if ((value & (HOST_WIDE_INT)0xffff0000) == 0)
+ return 0;
+
+ 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;
+
+ /* 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 QImode:
+ case HImode:
+ case SImode:
+ break;
+
+ case DImode:
+ if (!TARGET_POWERPC64)
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ addr = XEXP (op, 0);
+ if (GET_CODE (addr) == PLUS)
+ {
+ rtx base = XEXP (addr, 0);
+ rtx offset = XEXP (addr, 1);
+
+ return (base_reg_operand (base, GET_MODE (base))
+ && satisfies_constraint_I (offset));
+ }
+
+ else if (GET_CODE (addr) == LO_SUM)
+ {
+ rtx base = XEXP (addr, 0);
+ rtx offset = XEXP (addr, 1);
+
+ if (!base_reg_operand (base, GET_MODE (base)))
+ return 0;
+
+ else 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;
+})