;; Predicate definitions for POWER and PowerPC. ;; Copyright (C) 2005-2015 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; ;; GCC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; ;; GCC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; http://www.gnu.org/licenses/.
;; Return 1 for anything except PARALLEL. (define_predicate “any_operand” (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” (match_code “parallel”))
;; Return 1 if op is COUNT register. (define_predicate “count_register_operand” (and (match_code “reg”) (match_test “REGNO (op) == CTR_REGNO || REGNO (op) > LAST_VIRTUAL_REGISTER”)))
;; 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 (!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” (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” (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 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” (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 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” (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 VLOGICAL_REGNO_P (REGNO (op)); })
;; Return 1 if op is the carry register. (define_predicate “ca_operand” (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 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 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”) (match_test “satisfies_constraint_I (op)”)))
;; Return 1 if op is a constant integer that can fit in an unsigned D field. (define_predicate “u_short_cint_operand” (and (match_code “const_int”) (match_test “satisfies_constraint_K (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”) (match_test “(unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000”)))
;; Return 1 if op is a positive constant integer that is an exact power of 2. (define_predicate “exact_log2_cint_operand” (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..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”) { 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) >= 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 ;; 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” (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” (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_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” (if_then_else (match_code “const_int”) (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” (if_then_else (match_code “const_int”) (and (match_operand 0 “short_cint_operand”) (match_test “!(INTVAL (op) & 3)”)) (match_operand 0 “gpc_reg_operand”)))
;; Return 1 if op is a constant integer whose high-order 16 bits are zero ;; or non-special register. (define_predicate “reg_or_u_short_operand” (if_then_else (match_code “const_int”) (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. (define_predicate “reg_or_cint_operand” (ior (match_code “const_int”) (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_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 “(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 ;; or non-special register. (define_predicate “reg_or_logical_cint_operand” (if_then_else (match_code “const_int”) (match_test “(GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && INTVAL (op) >= 0) || ((INTVAL (op) & GET_MODE_MASK (mode) & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 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” (match_code “const_double”) { 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 || (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: case DFmode: case SFmode: return 0;
case DImode: return (num_insns_constant (op, DImode) <= 2); case SImode: return 1; default: gcc_unreachable (); }
})
;; Return 1 if the operand is a CONST_VECTOR and can be loaded into a ;; vector register without using memory. (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;
if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode)) { if (zero_constant (op, mode)) 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; })
;; Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF. (define_predicate “easy_vector_constant_add_self” (and (match_code “const_vector”) (and (match_test “TARGET_ALTIVEC”) (match_test “easy_altivec_constant (op, mode)”))) { HOST_WIDE_INT val; int elt; if (mode == V2DImode || mode == V2DFmode) return 0; 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); })
;; Same as easy_vector_constant but only for EASY_VECTOR_MSB. (define_predicate “easy_vector_constant_msb” (and (match_code “const_vector”) (and (match_test “TARGET_ALTIVEC”) (match_test “easy_altivec_constant (op, mode)”))) { HOST_WIDE_INT val; int elt; if (mode == V2DImode || mode == V2DFmode) return 0; 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_wide_int,const_vector”) (match_test “op == CONST0_RTX (mode)”)))
;; Return 1 if operand is 0.0. (define_predicate “zero_fp_constant” (and (match_code “const_double”) (match_test “SCALAR_FLOAT_MODE_P (mode) && op == CONST0_RTX (mode)”)))
;; Return 1 if the operand is in volatile memory. Note that during the ;; RTL generation phase, memory_operand does not return TRUE for volatile ;; memory references. So this function allows us to recognize volatile ;; references where it's safe. (define_predicate “volatile_mem_operand” (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))”)))))
;; 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 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”) { op = XEXP (op, 0); if (VECTOR_MEM_ALTIVEC_P (mode) && GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT && INTVAL (XEXP (op, 1)) == -16) op = XEXP (op, 0);
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, ;; while VSX uses the full address and traps) (define_predicate “altivec_indexed_or_indirect_operand” (match_code “mem”) { op = XEXP (op, 0); if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode) && GET_CODE (op) == AND && GET_CODE (XEXP (op, 1)) == CONST_INT && INTVAL (XEXP (op, 1)) == -16) return indexed_or_indirect_address (XEXP (op, 0), mode);
return 0; })
;; Return 1 if the operand is an indexed or indirect address. (define_special_predicate “indexed_or_indirect_address” (and (match_test “REG_P (op) || (GET_CODE (op) == PLUS /* Omit testing REG_P (XEXP (op, 0)). */ && 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 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))))”))
;; 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 either a non-special register or can be used ;; as the operand of a `mode' add insn. (define_predicate “add_operand” (if_then_else (match_code “const_int”) (match_test “satisfies_constraint_I (op) || 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”) (match_test “!satisfies_constraint_I (op) && !satisfies_constraint_L (op)”)))
;; 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”) { HOST_WIDE_INT opl;
opl = INTVAL (op) & GET_MODE_MASK (mode);
return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0 || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0); })
;; 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. (define_predicate “logical_operand” (ior (match_operand 0 “gpc_reg_operand”) (match_operand 0 “logical_const_operand”)))
;; 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_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”) { unsigned 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”) { unsigned 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”) { unsigned 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”) { unsigned 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; })
;; Match a mask_operand or a mask64_operand. (define_predicate “any_mask_operand” (ior (match_operand 0 “mask_operand”) (and (match_test “TARGET_POWERPC64 && mode == DImode”) (match_operand 0 “mask64_operand”))))
;; 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”) (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”))))
;; Return 1 if the operand is a constant that can be used as the operand ;; of a logical AND, implemented with two rld* insns, and it cannot be done ;; using just one insn. (define_predicate “and_2rld_operand” (and (match_operand 0 “and64_2_operand”) (not (match_operand 0 “and_operand”))))
;; Return 1 if the operand is either a logical operand or a short cint operand. (define_predicate “scc_eq_operand” (ior (match_operand 0 “logical_operand”) (match_operand 0 “short_cint_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”)))
;; Return 1 if the operand is CONST_DOUBLE 0, register or memory operand. (define_predicate “zero_reg_mem_operand” (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. (define_predicate “lwa_operand” (match_code “reg,subreg,mem”) { rtx inner, addr, offset;
inner = op; if (reload_completed && GET_CODE (inner) == SUBREG) inner = SUBREG_REG (inner);
if (gpc_reg_operand (inner, mode)) 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 || GET_CODE (addr) == PRE_DEC || (GET_CODE (addr) == PRE_MODIFY && !legitimate_indexed_address_p (XEXP (addr, 1), 0))) return false; if (GET_CODE (addr) == LO_SUM && GET_CODE (XEXP (addr, 0)) == REG && GET_CODE (XEXP (addr, 1)) == CONST) addr = XEXP (XEXP (addr, 1), 0); if (GET_CODE (addr) != PLUS) return true; offset = XEXP (addr, 1); if (GET_CODE (offset) != CONST_INT) return true; return INTVAL (offset) % 4 == 0; })
;; Return 1 if the operand, used inside a MEM, is a SYMBOL_REF. (define_predicate “symbol_ref_operand” (and (match_code “symbol_ref”) (match_test “(mode == VOIDmode || GET_MODE (op) == mode) && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))”)))
;; Return 1 if op is an operand that can be loaded via the GOT. ;; or non-special register register field no cr0 (define_predicate “got_operand” (match_code “symbol_ref,const,label_ref”))
;; Return 1 if op is a simple reference that can be loaded via the GOT, ;; excluding labels involving addition. (define_predicate “got_no_const_operand” (match_code “symbol_ref,label_ref”))
;; Return 1 if op is a SYMBOL_REF for a TLS symbol. (define_predicate “rs6000_tls_symbol_ref” (and (match_code “symbol_ref”) (match_test “RS6000_SYMBOL_REF_TLS_P (op)”)))
;; 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” (if_then_else (match_code “reg”) (match_test “REGNO (op) == LR_REGNO || REGNO (op) == CTR_REGNO || REGNO (op) >= FIRST_PSEUDO_REGISTER”) (match_code “symbol_ref”)))
;; 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) && !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 “symbol_ref,const,reg,subreg,mem, const_double,const_wide_int,const_vector,const_int”) { /* Memory is always valid. */ if (memory_operand (op, mode)) return 1;
/* For floating-point, easy constants are valid. */ if (SCALAR_FLOAT_MODE_P (mode) && easy_fp_constant (op, mode)) return 1;
/* Allow any integer constant. */ if (GET_MODE_CLASS (mode) == MODE_INT && CONST_SCALAR_INT_P (op)) return 1;
/* Allow easy vector constants. */ if (GET_CODE (op) == CONST_VECTOR && 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;
/* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region to be valid. */ if (DEFAULT_ABI == ABI_V4 && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST) && small_data_operand (op, Pmode)) return 1;
return 0; })
;; 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”) { if (MEM_P (op)) { if (! volatile_ok && MEM_VOLATILE_P (op)) return 0; if (mode == DFmode) mode = V2DFmode; else if (mode == DImode) mode = V2DImode; else gcc_unreachable (); return memory_address_addr_space_p (mode, XEXP (op, 0), 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 true if operand is boolean operator. (define_predicate “boolean_operator” (match_code “and,ior,xor”))
;; Return true if operand is OR-form of boolean operator. (define_predicate “boolean_or_operator” (match_code “ior,xor”))
;; Return true if operand is an equality operator. (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. (define_predicate “branch_comparison_operator” (and (match_operand 0 “comparison_operator”) (and (match_test “GET_MODE_CLASS (GET_MODE (XEXP (op, 0))) == MODE_CC”) (match_test “validate_condition_mode (GET_CODE (op), 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”))
;; 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. (define_predicate “scc_comparison_operator” (and (match_operand 0 “branch_comparison_operator”) (match_code “eq,lt,gt,ltu,gtu,unordered”)))
;; Return 1 if OP is a comparison operation whose inverse would be valid for ;; an SCC insn. (define_predicate “scc_rev_comparison_operator” (and (match_operand 0 “branch_comparison_operator”) (match_code “ne,le,ge,leu,geu,ordered”)))
;; 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” (match_code “parallel”) { int index; int i; rtx elt; int count = XVECLEN (op, 0);
if (count != 54) return 0;
index = 0; if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER || GET_CODE (XVECEXP (op, 0, index++)) != USE) return 0;
for (i=1; i <= 18; i++) { elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != MEM || ! memory_operand (SET_DEST (elt), DFmode) || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != DFmode) return 0; }
for (i=1; i <= 12; i++) { elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != MEM || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != V4SImode) return 0; }
for (i=1; i <= 19; i++) { elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != MEM || ! memory_operand (SET_DEST (elt), Pmode) || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != Pmode) return 0; }
elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_DEST (elt)) != MEM || ! memory_operand (SET_DEST (elt), Pmode) || GET_CODE (SET_SRC (elt)) != REG || REGNO (SET_SRC (elt)) != CR2_REGNO || GET_MODE (SET_SRC (elt)) != Pmode) return 0;
if (GET_CODE (XVECEXP (op, 0, index++)) != SET || GET_CODE (XVECEXP (op, 0, index++)) != SET) return 0; return 1; })
;; Return 1 if OP is valid for a restore_world call in epilogue, known to be ;; a PARLLEL. (define_predicate “restore_world_operation” (match_code “parallel”) { int index; int i; rtx elt; int count = XVECLEN (op, 0);
if (count != 59) 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;
elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != MEM || ! memory_operand (SET_SRC (elt), Pmode) || GET_CODE (SET_DEST (elt)) != REG || REGNO (SET_DEST (elt)) != CR2_REGNO || GET_MODE (SET_DEST (elt)) != Pmode) return 0;
for (i=1; i <= 19; i++) { elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != MEM || ! memory_operand (SET_SRC (elt), Pmode) || GET_CODE (SET_DEST (elt)) != REG || GET_MODE (SET_DEST (elt)) != Pmode) return 0; }
for (i=1; i <= 12; i++) { elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != MEM || GET_CODE (SET_DEST (elt)) != REG || GET_MODE (SET_DEST (elt)) != V4SImode) return 0; }
for (i=1; i <= 18; i++) { elt = XVECEXP (op, 0, index++); if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != MEM || ! memory_operand (SET_SRC (elt), DFmode) || GET_CODE (SET_DEST (elt)) != REG || GET_MODE (SET_DEST (elt)) != DFmode) return 0; }
if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER || GET_CODE (XVECEXP (op, 0, index++)) != USE) return 0; return 1; })
;; Return 1 if OP is valid for a vrsave call, known to be a PARALLEL. (define_predicate “vrsave_operation” (match_code “parallel”) { int count = XVECLEN (op, 0); unsigned int dest_regno, src_regno; int i;
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))) != UNSPEC_VOLATILE || XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPECV_SET_VRSAVE) return 0;
dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0))); src_regno = REGNO (XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 1));
if (dest_regno != VRSAVE_REGNO || src_regno != VRSAVE_REGNO) return 0;
for (i = 1; i < count; i++) { rtx elt = XVECEXP (op, 0, i);
if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != SET) return 0; }
return 1; })
;; Return 1 if OP is valid for mfcr insn, known to be a PARALLEL. (define_predicate “mfcr_operation” (match_code “parallel”) { int count = XVECLEN (op, 0); 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_SRC (XVECEXP (op, 0, 0))) != UNSPEC || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2) return 0;
for (i = 0; i < count; i++) { rtx exp = XVECEXP (op, 0, i); rtx unspec; int maskval; rtx src_reg;
src_reg = XVECEXP (SET_SRC (exp), 0, 0); if (GET_CODE (src_reg) != REG || GET_MODE (src_reg) != CCmode || ! CR_REGNO_P (REGNO (src_reg))) return 0; if (GET_CODE (exp) != SET || GET_CODE (SET_DEST (exp)) != REG || GET_MODE (SET_DEST (exp)) != SImode || ! INT_REGNO_P (REGNO (SET_DEST (exp)))) return 0; unspec = SET_SRC (exp); maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg)); if (GET_CODE (unspec) != UNSPEC || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR || XVECLEN (unspec, 0) != 2 || XVECEXP (unspec, 0, 0) != src_reg || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT || INTVAL (XVECEXP (unspec, 0, 1)) != maskval) return 0; }
return 1; })
;; Return 1 if OP is valid for mtcrf insn, known to be a PARALLEL. (define_predicate “mtcrf_operation” (match_code “parallel”) { int count = XVECLEN (op, 0); int i; rtx src_reg;
/* Perform a quick check so we don't blow up below. */ if (count < 1 || GET_CODE (XVECEXP (op, 0, 0)) != SET || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2) return 0; src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0);
if (GET_CODE (src_reg) != REG || GET_MODE (src_reg) != SImode || ! INT_REGNO_P (REGNO (src_reg))) return 0;
for (i = 0; i < count; i++) { rtx exp = XVECEXP (op, 0, i); rtx unspec; int maskval;
if (GET_CODE (exp) != SET || GET_CODE (SET_DEST (exp)) != REG || GET_MODE (SET_DEST (exp)) != CCmode || ! CR_REGNO_P (REGNO (SET_DEST (exp)))) return 0; unspec = SET_SRC (exp); maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp))); if (GET_CODE (unspec) != UNSPEC || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR || XVECLEN (unspec, 0) != 2 || XVECEXP (unspec, 0, 0) != src_reg || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT || INTVAL (XVECEXP (unspec, 0, 1)) != maskval) return 0; }
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”) { int count = XVECLEN (op, 0); unsigned int dest_regno; rtx src_addr; unsigned int base_regno; HOST_WIDE_INT offset; 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);
if (dest_regno > 31 || count != 32 - (int) dest_regno) return 0;
if (legitimate_indirect_address_p (src_addr, 0)) { offset = 0; base_regno = REGNO (src_addr); if (base_regno == 0) return 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)); } else return 0;
for (i = 0; i < count; i++) { rtx elt = XVECEXP (op, 0, i); rtx newaddr; rtx addr_reg; HOST_WIDE_INT newoffset;
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) return 0; newaddr = XEXP (SET_SRC (elt), 0); if (legitimate_indirect_address_p (newaddr, 0)) { newoffset = 0; addr_reg = newaddr; } else if (rs6000_legitimate_offset_address_p (SImode, newaddr, false, false)) { addr_reg = XEXP (newaddr, 0); newoffset = INTVAL (XEXP (newaddr, 1)); } else return 0; if (REGNO (addr_reg) != base_regno || newoffset != offset + 4 * i) return 0; }
return 1; })
;; Return 1 if OP is valid for stmw insn, known to be a PARALLEL. (define_predicate “stmw_operation” (match_code “parallel”) { int count = XVECLEN (op, 0); unsigned int src_regno; rtx dest_addr; unsigned int base_regno; HOST_WIDE_INT offset; 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);
if (src_regno > 31 || count != 32 - (int) src_regno) return 0;
if (legitimate_indirect_address_p (dest_addr, 0)) { offset = 0; base_regno = REGNO (dest_addr); if (base_regno == 0) return 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)); } else return 0;
for (i = 0; i < count; i++) { rtx elt = XVECEXP (op, 0, i); rtx newaddr; rtx addr_reg; HOST_WIDE_INT newoffset;
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) return 0; newaddr = XEXP (SET_DEST (elt), 0); if (legitimate_indirect_address_p (newaddr, 0)) { newoffset = 0; addr_reg = newaddr; } else if (rs6000_legitimate_offset_address_p (SImode, newaddr, false, false)) { addr_reg = XEXP (newaddr, 0); newoffset = INTVAL (XEXP (newaddr, 1)); } else return 0; if (REGNO (addr_reg) != base_regno || newoffset != offset + 4 * i) return 0; }
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 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, 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 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 && 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. (define_predicate “fusion_gpr_mem_combo” (match_code “mem,zero_extend”) { rtx addr, base, offset;
/* Handle zero extend. */ if (GET_CODE (op) == ZERO_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 && 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; })