| ;; Predicate definitions for Synopsys DesignWare ARC. |
| ;; Copyright (C) 2007-2026 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/>. |
| |
| (define_predicate "dest_reg_operand" |
| (match_code "reg,subreg") |
| { |
| return register_operand (op, mode); |
| }) |
| |
| ;; Returns 1 if OP is a symbol reference. |
| (define_predicate "symbolic_operand" |
| (match_code "symbol_ref, label_ref, const") |
| ) |
| |
| ;; Acceptable arguments to the call insn. |
| (define_predicate "call_address_operand" |
| (ior (match_code "const_int, reg") |
| (match_operand 0 "symbolic_operand") |
| (match_test "CONSTANT_P (op) |
| && arc_legitimate_constant_p (VOIDmode, op)")) |
| ) |
| |
| (define_predicate "call_operand" |
| (and (match_code "mem") |
| (match_test "call_address_operand (XEXP (op, 0), mode)")) |
| ) |
| |
| ;; Return true if OP is a unsigned 6-bit immediate (u6) value. |
| (define_predicate "u6_immediate_operand" |
| (and (match_code "const_int") |
| (match_test "UNSIGNED_INT6 (INTVAL (op))")) |
| ) |
| |
| ;; Return true if OP is a short immediate (shimm) value. |
| (define_predicate "short_immediate_operand" |
| (and (match_code "const_int") |
| (match_test "SMALL_INT (INTVAL (op))")) |
| ) |
| |
| (define_predicate "p2_immediate_operand" |
| (and (match_code "const_int") |
| (match_test "((INTVAL (op) - 1) & INTVAL (op)) == 0") |
| (match_test "INTVAL (op)")) |
| ) |
| |
| ;; Return true if OP will require a long immediate (limm) value. |
| ;; This is currently only used when calculating length attributes. |
| (define_predicate "long_immediate_operand" |
| (match_code "symbol_ref, label_ref, const, const_double, const_int") |
| { |
| switch (GET_CODE (op)) |
| { |
| case SYMBOL_REF : |
| case LABEL_REF : |
| case CONST : |
| return 1; |
| case CONST_INT : |
| return !SIGNED_INT12 (INTVAL (op)); |
| case CONST_DOUBLE : |
| /* These can happen because large unsigned 32 bit constants are |
| represented this way (the multiplication patterns can cause these |
| to be generated). They also occur for SFmode values. */ |
| return 1; |
| default: |
| break; |
| } |
| return 0; |
| } |
| ) |
| |
| ;; Return true if OP is a MEM that when used as a load or store address will |
| ;; require an 8 byte insn. |
| ;; Load and store instructions don't allow the same possibilities but they're |
| ;; similar enough that this one function will do. |
| ;; This is currently only used when calculating length attributes. */ |
| (define_predicate "long_immediate_loadstore_operand" |
| (match_code "mem") |
| { |
| int size = GET_MODE_SIZE (GET_MODE (op)); |
| |
| op = XEXP (op, 0); |
| if (TARGET_NPS_CMEM && cmem_address (op, SImode)) |
| return 0; |
| switch (GET_CODE (op)) |
| { |
| case SYMBOL_REF : |
| case LABEL_REF : |
| case CONST : |
| return 1; |
| case CONST_INT : |
| /* This must be handled as "st c,[limm]". Ditto for load. |
| Technically, the assembler could translate some possibilities to |
| "st c,[limm/2 + limm/2]" if limm/2 will fit in a shimm, but we don't |
| assume that it does. */ |
| return 1; |
| case CONST_DOUBLE : |
| /* These can happen because large unsigned 32 bit constants are |
| represented this way (the multiplication patterns can cause these |
| to be generated). They also occur for SFmode values. */ |
| return 1; |
| case REG : |
| return 0; |
| case PLUS : |
| { |
| rtx x = XEXP (op, 1); |
| |
| if ((GET_CODE (XEXP (op, 0)) == MULT) |
| && REG_P (XEXP (XEXP (op, 0), 0)) |
| && CONSTANT_P (x)) |
| return 1; |
| |
| if (GET_CODE (x) == CONST) |
| { |
| x = XEXP (x, 0); |
| if (GET_CODE (x) == PLUS) |
| x = XEXP (x, 0); |
| } |
| if (CONST_INT_P (x)) |
| return (!SMALL_INT (INTVAL (x)) |
| && (size <= 1 || size > 4 |
| || (INTVAL (x) & (size - 1)) != 0 |
| || !SMALL_INT (INTVAL (x) / size))); |
| else if (GET_CODE (x) == SYMBOL_REF) |
| return TARGET_NO_SDATA_SET || !SYMBOL_REF_SMALL_P (x); |
| return 0; |
| } |
| default: |
| break; |
| } |
| return 0; |
| } |
| ) |
| |
| ;; Return true if OP is any of R0-R3,R12-R15 for ARCompact 16-bit |
| ;; instructions |
| (define_predicate "compact_register_operand" |
| (match_code "reg, subreg") |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| return (GET_CODE (op) == REG) |
| && (REGNO (op) >= FIRST_PSEUDO_REGISTER |
| || COMPACT_GP_REG_P (REGNO (op))) ; |
| } |
| ) |
| |
| (define_predicate "compact_hreg_operand" |
| (match_code "reg, subreg") |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| return (GET_CODE (op) == REG) |
| && (REGNO (op) >= FIRST_PSEUDO_REGISTER |
| || (TARGET_V2 && REGNO (op) <= 31 && REGNO (op) != 30) |
| || !TARGET_V2); |
| } |
| ) |
| |
| ;; Return true if OP is an acceptable memory operand for ARCompact |
| ;; 16-bit store instructions |
| (define_predicate "compact_store_memory_operand" |
| (match_code "mem") |
| { |
| rtx addr, plus0, plus1; |
| int size, off; |
| |
| if (mode == VOIDmode) |
| mode = GET_MODE (op); |
| |
| /* .di instructions have no 16-bit form. */ |
| if (MEM_VOLATILE_P (op) && !TARGET_VOLATILE_CACHE_SET) |
| return 0; |
| |
| /* likewise for uncached types. */ |
| if (arc_is_uncached_mem_p (op)) |
| return 0; |
| |
| size = GET_MODE_SIZE (mode); |
| |
| /* dword operations really put out 2 instructions, so eliminate them. */ |
| if (size > UNITS_PER_WORD) |
| return 0; |
| |
| /* Decode the address now. */ |
| addr = XEXP (op, 0); |
| switch (GET_CODE (addr)) |
| { |
| case REG: |
| return (REGNO (addr) >= FIRST_PSEUDO_REGISTER |
| || COMPACT_GP_REG_P (REGNO (addr)) |
| || (SP_REG_P (REGNO (addr)) && (size != 2))); |
| /* stw_s does not support SP as a parameter. */ |
| case PLUS: |
| plus0 = XEXP (addr, 0); |
| plus1 = XEXP (addr, 1); |
| |
| if ((GET_CODE (plus0) == REG) |
| && ((REGNO (plus0) >= FIRST_PSEUDO_REGISTER) |
| || COMPACT_GP_REG_P (REGNO (plus0))) |
| && (GET_CODE (plus1) == CONST_INT)) |
| { |
| off = INTVAL (plus1); |
| |
| /* Negative offset is not supported in 16-bit load/store insns. */ |
| if (off < 0) |
| return 0; |
| |
| switch (size) |
| { |
| case 1: |
| return (off < 32); |
| case 2: |
| return ((off < 64) && (off % 2 == 0)); |
| case 4: |
| return ((off < 128) && (off % 4 == 0)); |
| } |
| } |
| |
| if ((GET_CODE (plus0) == REG) |
| && ((REGNO (plus0) >= FIRST_PSEUDO_REGISTER) |
| || SP_REG_P (REGNO (plus0))) |
| && (GET_CODE (plus1) == CONST_INT)) |
| { |
| off = INTVAL (plus1); |
| |
| return ((size != 2) && (off >= 0 && off < 128) && (off % 4 == 0)); |
| } |
| default: |
| break; |
| } |
| return 0; |
| } |
| ) |
| |
| ;; Return true if OP is an acceptable argument for a single word |
| ;; move source. |
| (define_predicate "move_src_operand" |
| (match_code "symbol_ref, label_ref, const, const_int, const_double, reg, subreg, mem") |
| { |
| switch (GET_CODE (op)) |
| { |
| case SYMBOL_REF : |
| if (SYMBOL_REF_TLS_MODEL (op)) |
| return 0; |
| return 1; |
| case LABEL_REF : |
| return 1; |
| case CONST : |
| return arc_legitimate_constant_p (mode, op); |
| case CONST_INT : |
| return (LARGE_INT (INTVAL (op))); |
| case CONST_DOUBLE : |
| /* We can handle DImode integer constants in SImode if the value |
| (signed or unsigned) will fit in 32 bits. This is needed because |
| large unsigned 32 bit constants are represented as CONST_DOUBLEs. */ |
| if (mode == SImode) |
| return arc_double_limm_p (op); |
| /* We can handle 32 bit floating point constants. */ |
| if (mode == SFmode) |
| return GET_MODE (op) == SFmode; |
| return 0; |
| case REG : |
| if (REGNO (op) == LP_COUNT) |
| return 1; |
| return register_operand (op, mode); |
| case SUBREG : |
| /* (subreg (mem ...) ...) can occur here if the inner part was once a |
| pseudo-reg and is now a stack slot. */ |
| if (GET_CODE (SUBREG_REG (op)) == MEM) |
| return address_operand (XEXP (SUBREG_REG (op), 0), mode); |
| else |
| return register_operand (op, mode); |
| case MEM : |
| return address_operand (XEXP (op, 0), mode); |
| default : |
| return 0; |
| } |
| } |
| ) |
| |
| ;; Return true if OP is an acceptable argument for a double word |
| ;; move source. |
| (define_predicate "move_double_src_operand" |
| (match_code "reg, subreg, mem, const_int, const_double") |
| { |
| switch (GET_CODE (op)) |
| { |
| case REG : |
| return register_operand (op, mode); |
| case SUBREG : |
| /* (subreg (mem ...) ...) can occur here if the inner part was once a |
| pseudo-reg and is now a stack slot. */ |
| if (GET_CODE (SUBREG_REG (op)) == MEM) |
| return address_operand (XEXP (SUBREG_REG (op), 0), mode); |
| else |
| return register_operand (op, mode); |
| case MEM : |
| return address_operand (XEXP (op, 0), mode); |
| case CONST_INT : |
| case CONST_DOUBLE : |
| return 1; |
| default : |
| return 0; |
| } |
| } |
| ) |
| |
| ;; Return true if OP is an acceptable argument for a move destination. |
| (define_predicate "move_dest_operand" |
| (match_code "reg, subreg, mem") |
| { |
| switch (GET_CODE (op)) |
| { |
| case REG : |
| /* Program Counter register cannot be the target of a move. It is |
| a readonly register. */ |
| if (REGNO (op) == PCL_REG) |
| return 0; |
| else if (TARGET_MULMAC_32BY16_SET |
| && (REGNO (op) == MUL32x16_REG || REGNO (op) == R57_REG)) |
| return 0; |
| else if (TARGET_MUL64_SET |
| && (REGNO (op) == R57_REG || REGNO (op) == MUL64_OUT_REG |
| || REGNO (op) == R59_REG)) |
| return 0; |
| else if (REGNO (op) == LP_COUNT) |
| return 1; |
| else |
| return dest_reg_operand (op, mode); |
| case SUBREG : |
| /* (subreg (mem ...) ...) can occur here if the inner part was once a |
| pseudo-reg and is now a stack slot. */ |
| if (GET_CODE (SUBREG_REG (op)) == MEM) |
| return address_operand (XEXP (SUBREG_REG (op), 0), mode); |
| else |
| return dest_reg_operand (op, mode); |
| case MEM : |
| { |
| rtx addr = XEXP (op, 0); |
| |
| if (GET_CODE (addr) == PLUS |
| && (GET_CODE (XEXP (addr, 0)) == MULT |
| || (!CONST_INT_P (XEXP (addr, 1)) |
| && (TARGET_NO_SDATA_SET |
| || GET_CODE (XEXP (addr, 1)) != SYMBOL_REF |
| || !SYMBOL_REF_SMALL_P (XEXP (addr, 1)))))) |
| return 0; |
| if ((GET_CODE (addr) == PRE_MODIFY || GET_CODE (addr) == POST_MODIFY) |
| && (GET_CODE (XEXP (addr, 1)) != PLUS |
| || !CONST_INT_P (XEXP (XEXP (addr, 1), 1)))) |
| return 0; |
| /* CONST_INT / CONST_DOUBLE is fine, but the PIC CONST ([..] UNSPEC)) |
| constructs are effectively indexed. */ |
| if (flag_pic) |
| { |
| rtx ad0 = addr; |
| while (GET_CODE (ad0) == PLUS) |
| ad0 = XEXP (ad0, 0); |
| if (GET_CODE (ad0) == CONST || GET_CODE (ad0) == UNSPEC) |
| return 0; |
| } |
| return address_operand (addr, mode); |
| } |
| default : |
| return 0; |
| } |
| |
| } |
| ) |
| |
| ;; Return true if OP is a non-volatile non-immediate operand. |
| ;; Volatile memory refs require a special "cache-bypass" instruction |
| ;; and only the standard movXX patterns are set up to handle them. |
| (define_predicate "nonvol_nonimm_operand" |
| (and (match_code "subreg, reg, mem") |
| (match_test "(GET_CODE (op) != MEM || !MEM_VOLATILE_P (op)) && nonimmediate_operand (op, mode)") |
| (match_test "!arc_is_uncached_mem_p (op)")) |
| ) |
| |
| ;; Return 1 if OP is a comparison operator valid for the mode of CC. |
| ;; This allows the use of MATCH_OPERATOR to recognize all the branch insns. |
| |
| (define_predicate "proper_comparison_operator" |
| (match_code "eq, ne, le, lt, ge, gt, leu, ltu, geu, gtu, unordered, ordered, uneq, unge, ungt, unle, unlt, ltgt") |
| { |
| enum rtx_code code = GET_CODE (op); |
| |
| if (!COMPARISON_P (op)) |
| return 0; |
| |
| /* After generic flag-setting insns, we can use eq / ne / pl / mi / pnz . |
| There are some creative uses for hi / ls after shifts, but these are |
| hard to understand for the compiler and could be at best the target of |
| a peephole. */ |
| switch (GET_MODE (XEXP (op, 0))) |
| { |
| case E_CC_ZNmode: |
| return (code == EQ || code == NE || code == GE || code == LT |
| || code == GT); |
| case E_CC_Zmode: |
| return code == EQ || code == NE; |
| case E_CC_Cmode: |
| return code == LTU || code == GEU; |
| case E_CC_Vmode: |
| return code == EQ || code == NE; |
| case E_CC_FP_GTmode: |
| return code == GT || code == UNLE; |
| case E_CC_FP_GEmode: |
| return code == GE || code == UNLT; |
| case E_CC_FP_ORDmode: |
| return code == ORDERED || code == UNORDERED; |
| case E_CC_FP_UNEQmode: |
| return code == UNEQ || code == LTGT; |
| case E_CC_FPXmode: |
| return (code == EQ || code == NE || code == UNEQ || code == LTGT |
| || code == ORDERED || code == UNORDERED); |
| |
| case E_CC_FPUmode: |
| case E_CC_FPUEmode: |
| return 1; |
| case E_CC_FPU_UNEQmode: |
| return 1; |
| |
| case E_CCmode: |
| case E_SImode: /* Used for BRcc. */ |
| return 1; |
| /* From combiner. */ |
| case E_QImode: case E_HImode: case E_DImode: case E_SFmode: case E_DFmode: |
| return 0; |
| case E_VOIDmode: |
| return 0; |
| default: |
| gcc_unreachable (); |
| } |
| }) |
| |
| (define_predicate "equality_comparison_operator" |
| (match_code "eq, ne") |
| { |
| machine_mode opmode = GET_MODE (XEXP (op, 0)); |
| return opmode != CC_Vmode; |
| } |
| ) |
| |
| (define_predicate "ge_lt_comparison_operator" |
| (match_code "ge, lt")) |
| |
| (define_predicate "brcc_nolimm_operator" |
| (ior (match_test "REG_P (XEXP (op, 1))") |
| (and (match_code "eq, ne, lt, ge, ltu, geu") |
| (match_test "CONST_INT_P (XEXP (op, 1))") |
| (match_test "u6_immediate_operand (XEXP (op, 1), SImode)")) |
| (and (match_code "le, gt, leu, gtu") |
| (match_test "CONST_INT_P (XEXP (op, 1))") |
| (match_test "UNSIGNED_INT6 (INTVAL (XEXP (op, 1)) + 1)")))) |
| |
| ;; Return TRUE if this is the condition code register, if we aren't given |
| ;; a mode, accept any CCmode register |
| (define_special_predicate "cc_register" |
| (match_code "reg") |
| { |
| if (mode == VOIDmode) |
| { |
| mode = GET_MODE (op); |
| if (GET_MODE_CLASS (mode) != MODE_CC) |
| return FALSE; |
| } |
| |
| if (mode == GET_MODE (op) && GET_CODE (op) == REG && REGNO (op) == CC_REG) |
| return TRUE; |
| |
| return FALSE; |
| }) |
| |
| ;; Return TRUE if this is the condition code register; if we aren't given |
| ;; a mode, accept any CCmode register. If we are given a mode, accept |
| ;; modes that set a subset of flags. |
| (define_special_predicate "cc_set_register" |
| (match_code "reg") |
| { |
| machine_mode rmode = GET_MODE (op); |
| |
| if (mode == VOIDmode) |
| { |
| mode = rmode; |
| if (GET_MODE_CLASS (mode) != MODE_CC) |
| return FALSE; |
| } |
| |
| if (REGNO (op) != CC_REG) |
| return FALSE; |
| if (mode == rmode |
| || (mode == CC_ZNmode && rmode == CC_Zmode) |
| || (mode == CCmode && rmode == CC_Zmode) |
| || (mode == CCmode && rmode == CC_ZNmode) |
| || (mode == CCmode && rmode == CC_Cmode)) |
| return TRUE; |
| |
| return FALSE; |
| }) |
| |
| ; Accept CC_REG in modes which provide the flags needed for MODE. */ |
| (define_special_predicate "cc_use_register" |
| (match_code "reg") |
| { |
| if (REGNO (op) != CC_REG) |
| return 0; |
| if (GET_MODE (op) == mode) |
| return 1; |
| switch (mode) |
| { |
| case E_CC_Zmode: |
| if (GET_MODE (op) == CC_ZNmode) |
| return 1; |
| /* Fall through. */ |
| case E_CC_ZNmode: case E_CC_Cmode: |
| return GET_MODE (op) == CCmode; |
| default: |
| gcc_unreachable (); |
| } |
| }) |
| |
| (define_special_predicate "zn_compare_operator" |
| (match_code "compare") |
| { |
| return GET_MODE (op) == CC_ZNmode || GET_MODE (op) == CC_Zmode; |
| }) |
| |
| ;; Return true if OP is a shift operator. |
| (define_predicate "shift_operator" |
| (match_code "ashiftrt, lshiftrt, ashift") |
| ) |
| |
| (define_predicate "mult_operator" |
| (and (match_code "mult") (match_test "TARGET_MPY")) |
| ) |
| |
| (define_predicate "commutative_operator" |
| (ior (match_code "plus,ior,xor,and") |
| (match_operand 0 "mult_operator") |
| (and (match_code "ss_plus") |
| (match_test "TARGET_ARC700 || TARGET_EA_SET"))) |
| ) |
| |
| (define_predicate "commutative_operator_sans_mult" |
| (ior (match_code "plus,ior,xor,and") |
| (and (match_code "ss_plus") |
| (match_test "TARGET_ARC700 || TARGET_EA_SET"))) |
| ) |
| |
| (define_predicate "noncommutative_operator" |
| (ior (and (match_code "ashift,ashiftrt,lshiftrt,rotatert") |
| (match_test "TARGET_BARREL_SHIFTER")) |
| (match_code "minus") |
| (and (match_code "ss_minus") |
| (match_test "TARGET_ARC700 || TARGET_EA_SET"))) |
| ) |
| |
| (define_predicate "unary_operator" |
| (ior (match_code "abs,neg,not,sign_extend,zero_extend") |
| (and (ior (match_code "ss_neg") |
| (and (match_code "ss_truncate") |
| (match_test "GET_MODE (XEXP (op, 0)) == HImode"))) |
| (match_test "TARGET_ARC700 || TARGET_EA_SET"))) |
| ) |
| |
| (define_predicate "_1_2_3_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL (op) == 1 || INTVAL (op) == 2 || INTVAL (op) == 3")) |
| ) |
| |
| (define_predicate "_2_4_8_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL (op) == 2 || INTVAL (op) == 4 || INTVAL (op) == 8")) |
| ) |
| |
| (define_predicate "arc_double_register_operand" |
| (match_code "reg") |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| return (GET_CODE (op) == REG |
| && (REGNO (op) >= FIRST_PSEUDO_REGISTER |
| || REGNO_REG_CLASS (REGNO (op)) == DOUBLE_REGS)); |
| }) |
| |
| (define_predicate "shouldbe_register_operand" |
| (match_code "reg,subreg,mem") |
| { |
| return ((reload_in_progress || reload_completed) |
| ? general_operand : register_operand) (op, mode); |
| }) |
| |
| (define_predicate "vector_register_operand" |
| (match_code "reg") |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| return (GET_CODE (op) == REG |
| && (REGNO (op) >= FIRST_PSEUDO_REGISTER |
| || REGNO_REG_CLASS (REGNO (op)) == SIMD_VR_REGS)); |
| }) |
| |
| (define_predicate "vector_register_or_memory_operand" |
| ( ior (match_code "reg") |
| (match_code "mem")) |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| if ((GET_CODE (op) == MEM) |
| && (mode == V8HImode) |
| && GET_CODE (XEXP (op,0)) == REG) |
| return 1; |
| |
| return (GET_CODE (op) == REG |
| && (REGNO (op) >= FIRST_PSEUDO_REGISTER |
| || REGNO_REG_CLASS (REGNO (op)) == SIMD_VR_REGS)); |
| }) |
| |
| (define_predicate "arc_dpfp_operator" |
| (match_code "plus, mult,minus") |
| ) |
| |
| (define_predicate "arc_simd_dma_register_operand" |
| (match_code "reg") |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| return (GET_CODE (op) == REG |
| && (REGNO (op) >= FIRST_PSEUDO_REGISTER |
| || REGNO_REG_CLASS (REGNO (op)) == SIMD_DMA_CONFIG_REGS)); |
| }) |
| |
| (define_predicate "acc1_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 56 : 57)"))) |
| |
| (define_predicate "acc2_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 57 : 56)"))) |
| |
| (define_predicate "mlo_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) == R58_REG"))) |
| |
| (define_predicate "mhi_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) == R59_REG"))) |
| |
| (define_predicate "accl_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) == (TARGET_BIG_ENDIAN ? 59 : 58)") |
| (match_test "TARGET_V2"))) |
| |
| ; Unfortunately, we cannot allow a const_int_operand before reload, because |
| ; reload needs a non-void mode to guide it how to reload the inside of a |
| ; {sign_}extend. |
| (define_predicate "extend_operand" |
| (ior (match_operand 0 "register_operand") |
| (and (match_operand 0 "immediate_operand") |
| (ior (not (match_operand 0 "const_int_operand")) |
| (match_test "reload_in_progress || reload_completed"))))) |
| |
| (define_predicate "millicode_store_operation" |
| (match_code "parallel") |
| { |
| return arc_check_millicode (op, 0, 0); |
| }) |
| |
| (define_predicate "millicode_load_operation" |
| (match_code "parallel") |
| { |
| return arc_check_millicode (op, 2, 2); |
| }) |
| |
| (define_predicate "millicode_load_clob_operation" |
| (match_code "parallel") |
| { |
| return arc_check_millicode (op, 0, 1); |
| }) |
| |
| (define_special_predicate "immediate_usidi_operand" |
| (if_then_else |
| (match_code "const_int") |
| (match_test "INTVAL (op) >= 0") |
| (and (match_test "const_double_operand (op, mode)") |
| (match_test "CONST_DOUBLE_HIGH (op) == 0")))) |
| |
| (define_predicate "short_const_int_operand" |
| (and (match_operand 0 "const_int_operand") |
| (match_test "satisfies_constraint_C16 (op)"))) |
| |
| (define_predicate "mem_noofs_operand" |
| (and (match_code "mem") |
| (match_code "reg" "0"))) |
| |
| (define_predicate "any_mem_operand" |
| (match_code "mem")) |
| |
| ; Special predicate to match even-odd double register pair |
| (define_predicate "even_register_operand" |
| (match_code "reg") |
| { |
| if ((GET_MODE (op) != mode) && (mode != VOIDmode)) |
| return 0; |
| |
| return (REG_P (op) && ((REGNO (op) >= FIRST_PSEUDO_REGISTER) |
| || ((REGNO (op) & 1) == 0))); |
| }) |
| |
| (define_predicate "double_register_operand" |
| (ior (match_test "even_register_operand (op, mode)") |
| (match_test "arc_double_register_operand (op, mode)"))) |
| |
| (define_predicate "cmem_address_0" |
| (and (match_code "symbol_ref") |
| (match_test "SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_CMEM"))) |
| |
| (define_predicate "cmem_address_1" |
| (and (match_code "plus") |
| (match_test "cmem_address_0 (XEXP (op, 0), SImode)"))) |
| |
| (define_predicate "cmem_address_2" |
| (and (match_code "const") |
| (match_test "cmem_address_1 (XEXP (op, 0), SImode)"))) |
| |
| (define_predicate "cmem_address" |
| (ior (match_operand:SI 0 "cmem_address_0") |
| (match_operand:SI 0 "cmem_address_1") |
| (match_operand:SI 0 "cmem_address_2"))) |
| |
| (define_predicate "short_unsigned_const_operand" |
| (and (match_code "const_int") |
| (match_test "satisfies_constraint_J16 (op)"))) |
| |
| (define_predicate "arc_short_operand" |
| (ior (match_test "register_operand (op, mode)") |
| (match_test "short_unsigned_const_operand (op, mode)"))) |
| |
| (define_special_predicate "push_multi_operand" |
| (match_code "parallel") |
| { |
| return arc_check_multi (op, true); |
| }) |
| |
| (define_special_predicate "pop_multi_operand" |
| (match_code "parallel") |
| { |
| return arc_check_multi (op, false); |
| }) |
| |
| (define_predicate "arc_nonmemory_operand" |
| (ior (match_test "register_operand (op, mode)") |
| (and (match_code "const_int, symbol_ref") |
| (match_test "!optimize_size")))) |