;; Predicate definitions for Frv. ;; Copyright (C) 2005-2021 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 true if operand is a GPR register.

(define_predicate “integer_register_operand” (match_code “reg,subreg”) { if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

return GPR_AP_OR_PSEUDO_P (REGNO (op)); })

;; Return 1 is OP is a memory operand, or will be turned into one by ;; reload.

(define_predicate “frv_load_operand” (match_code “reg,subreg,mem”) { if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (reload_in_progress) { rtx tmp = op; if (GET_CODE (tmp) == SUBREG) tmp = SUBREG_REG (tmp); if (GET_CODE (tmp) == REG && REGNO (tmp) >= FIRST_PSEUDO_REGISTER) op = reg_equiv_memory_loc (REGNO (tmp)); }

return op && memory_operand (op, mode); })

;; Return true if operand is a GPR register. Do not allow SUBREG's ;; here, in order to prevent a combine bug.

(define_predicate “gpr_no_subreg_operand” (match_code “reg”) { if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

return GPR_OR_PSEUDO_P (REGNO (op)); })

;; Return 1 if operand is a GPR register or a FPR register.

(define_predicate “gpr_or_fpr_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER) return TRUE;

return FALSE; })

;; Return 1 if operand is a GPR register or 12-bit signed immediate.

(define_predicate “gpr_or_int12_operand” (match_code “reg,subreg,const_int,const”) { if (GET_CODE (op) == CONST_INT) return IN_RANGE (INTVAL (op), -2048, 2047);

if (got12_operand (op, mode)) return true;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

return GPR_OR_PSEUDO_P (REGNO (op)); })

;; Return 1 if operand is a GPR register, or a FPR register, or a 12 ;; bit signed immediate.

(define_predicate “gpr_fpr_or_int12_operand” (match_code “reg,subreg,const_int”) { int regno;

if (GET_CODE (op) == CONST_INT) return IN_RANGE (INTVAL (op), -2048, 2047);

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (GPR_P (regno) || FPR_P (regno) || regno >= FIRST_PSEUDO_REGISTER) return TRUE;

return FALSE; })

;; Return 1 if operand is a register or 10-bit signed immediate.

(define_predicate “gpr_or_int10_operand” (match_code “reg,subreg,const_int”) { if (GET_CODE (op) == CONST_INT) return IN_RANGE (INTVAL (op), -512, 511);

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

return GPR_OR_PSEUDO_P (REGNO (op)); })

;; Return 1 if operand is a register or an integer immediate.

(define_predicate “gpr_or_int_operand” (match_code “reg,subreg,const_int”) { if (GET_CODE (op) == CONST_INT) return TRUE;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

return GPR_OR_PSEUDO_P (REGNO (op)); })

;; Return true if operand is something that can be an input for a move ;; operation.

(define_predicate “move_source_operand” (match_code “reg,subreg,const_int,mem,const_double,const,symbol_ref,label_ref”) { rtx subreg; enum rtx_code code;

switch (GET_CODE (op)) { default: break;

case CONST_INT:
case CONST_DOUBLE:
  return immediate_operand (op, mode);

case SUBREG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  subreg = SUBREG_REG (op);
  code = GET_CODE (subreg);
  if (code == MEM)
return frv_legitimate_address_p_1 (mode, XEXP (subreg, 0),
				   reload_completed, FALSE, FALSE);

  return (code == REG);

case REG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  return TRUE;

case MEM:
  return frv_legitimate_memory_operand (op, mode, FALSE);
}

return FALSE; })

;; Return true if operand is something that can be an output for a ;; move operation.

(define_predicate “move_destination_operand” (match_code “reg,subreg,mem”) { rtx subreg; enum rtx_code code;

switch (GET_CODE (op)) { default: break;

case SUBREG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  subreg = SUBREG_REG (op);
  code = GET_CODE (subreg);
  if (code == MEM)
return frv_legitimate_address_p_1 (mode, XEXP (subreg, 0),
				   reload_completed, FALSE, FALSE);

  return (code == REG);

case REG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  return TRUE;

case MEM:
  return frv_legitimate_memory_operand (op, mode, FALSE);
}

return FALSE; })

;; Return true if we the operand is a valid destination for a movcc_fp ;; instruction. This means rejecting fcc_operands, since we need ;; scratch registers to write to them.

(define_predicate “movcc_fp_destination_operand” (match_code “reg,subreg,mem”) { if (fcc_operand (op, mode)) return FALSE;

return move_destination_operand (op, mode); })

;; Return true if operand is something that can be an input for a ;; conditional move operation.

(define_predicate “condexec_source_operand” (match_code “reg,subreg,const_int,mem,const_double”) { rtx subreg; enum rtx_code code;

switch (GET_CODE (op)) { default: break;

case CONST_INT:
case CONST_DOUBLE:
  return ZERO_P (op);

case SUBREG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  subreg = SUBREG_REG (op);
  code = GET_CODE (subreg);
  if (code == MEM)
return frv_legitimate_address_p_1 (mode, XEXP (subreg, 0),
				   reload_completed, TRUE, FALSE);

  return (code == REG);

case REG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  return TRUE;

case MEM:
  return frv_legitimate_memory_operand (op, mode, TRUE);
}

return FALSE; })

;; Return true if operand is something that can be an output for a ;; conditional move operation.

(define_predicate “condexec_dest_operand” (match_code “reg,subreg,mem”) { rtx subreg; enum rtx_code code;

switch (GET_CODE (op)) { default: break;

case SUBREG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  subreg = SUBREG_REG (op);
  code = GET_CODE (subreg);
  if (code == MEM)
return frv_legitimate_address_p_1 (mode, XEXP (subreg, 0),
				   reload_completed, TRUE, FALSE);

  return (code == REG);

case REG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
    return FALSE;

  return TRUE;

case MEM:
  return frv_legitimate_memory_operand (op, mode, TRUE);
}

return FALSE; })

;; Return true if operand is a register of any flavor or a 0 of the ;; appropriate type.

(define_predicate “reg_or_0_operand” (match_code “reg,subreg,const_int,const_double”) { switch (GET_CODE (op)) { default: break;

case REG:
case SUBREG:
  if (GET_MODE (op) != mode && mode != VOIDmode)
return FALSE;

  return register_operand (op, mode);

case CONST_INT:
case CONST_DOUBLE:
  return ZERO_P (op);
}

return FALSE; })

;; Return true if operand is the link register.

(define_predicate “lr_operand” (match_code “reg”) { if (GET_CODE (op) != REG) return FALSE;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (REGNO (op) != LR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER) return FALSE;

return TRUE; })

;; Return true if operand is a gpr register or a valid memory operand.

(define_predicate “gpr_or_memory_operand” (match_code “reg,subreg,mem”) { return (integer_register_operand (op, mode) || frv_legitimate_memory_operand (op, mode, FALSE)); })

;; Return true if operand is a gpr register, a valid memory operand, ;; or a memory operand that can be made valid using an additional gpr ;; register.

(define_predicate “gpr_or_memory_operand_with_scratch” (match_code “reg,subreg,mem”) { rtx addr;

if (gpr_or_memory_operand (op, mode)) return TRUE;

if (GET_CODE (op) != MEM) return FALSE;

if (GET_MODE (op) != mode) return FALSE;

addr = XEXP (op, 0);

if (GET_CODE (addr) != PLUS) return FALSE;

if (!integer_register_operand (XEXP (addr, 0), Pmode)) return FALSE;

if (GET_CODE (XEXP (addr, 1)) != CONST_INT) return FALSE;

return TRUE; })

;; Return true if operand is a fpr register or a valid memory ;; operation.

(define_predicate “fpr_or_memory_operand” (match_code “reg,subreg,mem”) { return (fpr_operand (op, mode) || frv_legitimate_memory_operand (op, mode, FALSE)); })

;; Return 1 if operand is a 12-bit signed immediate.

(define_predicate “int12_operand” (match_code “const_int”) { if (GET_CODE (op) != CONST_INT) return FALSE;

return IN_RANGE (INTVAL (op), -2048, 2047); })

;; Return 1 if operand is an integer constant that takes 2 ;; instructions to load up and can be split into sethi/setlo ;; instructions..

(define_predicate “int_2word_operand” (match_code “const_int,const_double,symbol_ref,label_ref,const”) { HOST_WIDE_INT value; long l;

switch (GET_CODE (op)) { default: break;

case LABEL_REF:
  if (TARGET_FDPIC)
return FALSE;
  
  return (flag_pic == 0);

case CONST:
  if (flag_pic || TARGET_FDPIC)
return FALSE;

  op = XEXP (op, 0);
  if (GET_CODE (op) == PLUS && GET_CODE (XEXP (op, 1)) == CONST_INT)
op = XEXP (op, 0);
  return GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF;

case SYMBOL_REF:
  if (TARGET_FDPIC)
return FALSE;
  
  /* small data references are already 1 word */
  return (flag_pic == 0) && (! SYMBOL_REF_SMALL_P (op));

case CONST_INT:
  return ! IN_RANGE (INTVAL (op), -32768, 32767);

case CONST_DOUBLE:
  if (GET_MODE (op) == SFmode)
{
  REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (op), l);
  value = l;
  return ! IN_RANGE (value, -32768, 32767);
}
  else if (GET_MODE (op) == VOIDmode)
{
  value = CONST_DOUBLE_LOW (op);
  return ! IN_RANGE (value, -32768, 32767);
}
  break;
}

return FALSE; })

;; Return true if operand is the uClinux PIC register.

(define_predicate “fdpic_operand” (match_code “reg”) { if (!TARGET_FDPIC) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (REGNO (op) != FDPIC_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER) return FALSE;

return TRUE; })

;; TODO: Add a comment here.

(define_predicate “fdpic_fptr_operand” (match_code “reg”) { if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE; if (GET_CODE (op) != REG) return FALSE; if (REGNO (op) != FDPIC_FPTR_REGNO && REGNO (op) < FIRST_PSEUDO_REGISTER) return FALSE; return TRUE; })

;; An address operand that may use a pair of registers, an addressing ;; mode that we reject in general.

(define_predicate “ldd_address_operand” (match_code “reg,subreg,plus”) { if (GET_MODE (op) != mode && GET_MODE (op) != VOIDmode) return FALSE;

return frv_legitimate_address_p_1 (DImode, op, reload_completed, FALSE, TRUE); })

;; TODO: Add a comment here.

(define_predicate “got12_operand” (match_code “const”) { struct frv_unspec unspec;

if (frv_const_unspec_p (op, &unspec)) switch (unspec.reloc) { case R_FRV_GOT12: case R_FRV_GOTOFF12: case R_FRV_FUNCDESC_GOT12: case R_FRV_FUNCDESC_GOTOFF12: case R_FRV_GPREL12: case R_FRV_TLSMOFF12: return true; } return false; })

;; Return true if OP is a valid const-unspec expression.

(define_predicate “const_unspec_operand” (match_code “const”) { struct frv_unspec unspec;

return frv_const_unspec_p (op, &unspec); })

;; Return true if operand is an icc register.

(define_predicate “icc_operand” (match_code “reg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); return ICC_OR_PSEUDO_P (regno); })

;; Return true if operand is an fcc register.

(define_predicate “fcc_operand” (match_code “reg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); return FCC_OR_PSEUDO_P (regno); })

;; Return true if operand is either an fcc or icc register.

(define_predicate “cc_operand” (match_code “reg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (CC_OR_PSEUDO_P (regno)) return TRUE;

return FALSE; })

;; Return true if operand is an integer CCR register.

(define_predicate “icr_operand” (match_code “reg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); return ICR_OR_PSEUDO_P (regno); })

;; Return true if operand is an fcc register.

(define_predicate “fcr_operand” (match_code “reg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); return FCR_OR_PSEUDO_P (regno); })

;; Return true if operand is either an fcc or icc register.

(define_predicate “cr_operand” (match_code “reg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (CR_OR_PSEUDO_P (regno)) return TRUE;

return FALSE; })

;; Return true if operand is a FPR register.

(define_predicate “fpr_operand” (match_code “reg,subreg”) { if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

return FPR_OR_PSEUDO_P (REGNO (op)); })

;; Return true if operand is an even GPR or FPR register.

(define_predicate “even_reg_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (regno >= FIRST_PSEUDO_REGISTER) return TRUE;

if (GPR_P (regno)) return (((regno - GPR_FIRST) & 1) == 0);

if (FPR_P (regno)) return (((regno - FPR_FIRST) & 1) == 0);

return FALSE; })

;; Return true if operand is an odd GPR register.

(define_predicate “odd_reg_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); /* Assume that reload will give us an even register. */ if (regno >= FIRST_PSEUDO_REGISTER) return FALSE;

if (GPR_P (regno)) return (((regno - GPR_FIRST) & 1) != 0);

if (FPR_P (regno)) return (((regno - FPR_FIRST) & 1) != 0);

return FALSE; })

;; Return true if operand is an even GPR register.

(define_predicate “even_gpr_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (regno >= FIRST_PSEUDO_REGISTER) return TRUE;

if (! GPR_P (regno)) return FALSE;

return (((regno - GPR_FIRST) & 1) == 0); })

;; Return true if operand is an odd GPR register.

(define_predicate “odd_gpr_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); /* Assume that reload will give us an even register. */ if (regno >= FIRST_PSEUDO_REGISTER) return FALSE;

if (! GPR_P (regno)) return FALSE;

return (((regno - GPR_FIRST) & 1) != 0); })

;; Return true if operand is a quad aligned FPR register.

(define_predicate “quad_fpr_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (regno >= FIRST_PSEUDO_REGISTER) return TRUE;

if (! FPR_P (regno)) return FALSE;

return (((regno - FPR_FIRST) & 3) == 0); })

;; Return true if operand is an even FPR register.

(define_predicate “even_fpr_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); if (regno >= FIRST_PSEUDO_REGISTER) return TRUE;

if (! FPR_P (regno)) return FALSE;

return (((regno - FPR_FIRST) & 1) == 0); })

;; Return true if operand is an odd FPR register.

(define_predicate “odd_fpr_operand” (match_code “reg,subreg”) { int regno;

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

regno = REGNO (op); /* Assume that reload will give us an even register. */ if (regno >= FIRST_PSEUDO_REGISTER) return FALSE;

if (! FPR_P (regno)) return FALSE;

return (((regno - FPR_FIRST) & 1) != 0); })

;; Return true if operand is a 2 word memory address that can be ;; loaded in one instruction to load or store. We assume the stack ;; and frame pointers are suitably aligned, and variables in the small ;; data area. FIXME -- at some we should recognize other globals and ;; statics. We can't assume that any old pointer is aligned, given ;; that arguments could be passed on an odd word on the stack and the ;; address taken and passed through to another function.

(define_predicate “dbl_memory_one_insn_operand” (match_code “mem”) { rtx addr; rtx addr_reg;

if (! TARGET_DWORD) return FALSE;

if (GET_CODE (op) != MEM) return FALSE;

if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD) return FALSE;

addr = XEXP (op, 0); if (GET_CODE (addr) == REG) addr_reg = addr;

else if (GET_CODE (addr) == PLUS) { rtx addr0 = XEXP (addr, 0); rtx addr1 = XEXP (addr, 1);

  if (GET_CODE (addr0) != REG)
return FALSE;

  if (got12_operand (addr1, VOIDmode))
return TRUE;

  if (GET_CODE (addr1) != CONST_INT)
return FALSE;

  if ((INTVAL (addr1) & 7) != 0)
return FALSE;

  addr_reg = addr0;
}

else return FALSE;

if (addr_reg == frame_pointer_rtx || addr_reg == stack_pointer_rtx) return TRUE;

return FALSE; })

;; Return true if operand is a 2 word memory address that needs to use ;; two instructions to load or store.

(define_predicate “dbl_memory_two_insn_operand” (match_code “mem”) { if (GET_CODE (op) != MEM) return FALSE;

if (mode != VOIDmode && GET_MODE_SIZE (mode) != 2*UNITS_PER_WORD) return FALSE;

if (! TARGET_DWORD) return TRUE;

return ! dbl_memory_one_insn_operand (op, mode); })

;; Return true if operand is a memory reference suitable for a call.

(define_predicate “call_operand” (match_code “reg,subreg,const_int,const,symbol_ref”) { if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT) return FALSE;

if (GET_CODE (op) == SYMBOL_REF) return !TARGET_LONG_CALLS || SYMBOL_REF_LOCAL_P (op);

/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should never occur anyway), but prevents reload from not handling the case properly of a call through a pointer on a function that calls vfork/setjmp, etc. due to the need to flush all of the registers to stack. */ return gpr_or_int12_operand (op, mode); })

;; Return true if operand is a memory reference suitable for a ;; sibcall.

(define_predicate “sibcall_operand” (match_code “reg,subreg,const_int,const”) { if (GET_MODE (op) != mode && mode != VOIDmode && GET_CODE (op) != CONST_INT) return FALSE;

/* Note this doesn't allow reg+reg or reg+imm12 addressing (which should never occur anyway), but prevents reload from not handling the case properly of a call through a pointer on a function that calls vfork/setjmp, etc. due to the need to flush all of the registers to stack. */ return gpr_or_int12_operand (op, mode); })

;; Return 1 if operand is an integer constant with the bottom 16 bits ;; clear.

(define_predicate “upper_int16_operand” (match_code “const_int”) { if (GET_CODE (op) != CONST_INT) return FALSE;

return ((INTVAL (op) & 0xffff) == 0); })

;; Return 1 if operand is a 16-bit unsigned immediate.

(define_predicate “uint16_operand” (match_code “const_int”) { if (GET_CODE (op) != CONST_INT) return FALSE;

return IN_RANGE (INTVAL (op), 0, 0xffff); })

;; Returns 1 if OP is either a SYMBOL_REF or a constant.

(define_predicate “symbolic_operand” (match_code “symbol_ref,const,const_int”) { enum rtx_code c = GET_CODE (op);

if (c == CONST) { /* Allow (const:SI (plus:SI (symbol_ref) (const_int))). */ return GET_MODE (op) == SImode && GET_CODE (XEXP (op, 0)) == PLUS && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT; }

return c == SYMBOL_REF || c == CONST_INT; })

;; Return true if operator is a kind of relational operator.

(define_predicate “relational_operator” (match_code “eq,ne,le,lt,ge,gt,leu,ltu,geu,gtu”) { return (integer_relational_operator (op, mode) || float_relational_operator (op, mode)); })

;; Return true if OP is a relational operator suitable for CCmode, ;; CC_UNSmode or CC_NZmode.

(define_predicate “integer_relational_operator” (match_code “eq,ne,le,lt,ge,gt,leu,ltu,geu,gtu”) { if (mode != VOIDmode && mode != GET_MODE (op)) return FALSE;

/* The allowable relations depend on the mode of the ICC register. */ switch (GET_CODE (op)) { default: return FALSE;

case EQ:
case NE:
case LT:
case GE:
  return (GET_MODE (XEXP (op, 0)) == CC_NZmode
      || GET_MODE (XEXP (op, 0)) == CCmode);

case LE:
case GT:
  return GET_MODE (XEXP (op, 0)) == CCmode;

case GTU:
case GEU:
case LTU:
case LEU:
  return (GET_MODE (XEXP (op, 0)) == CC_NZmode
      || GET_MODE (XEXP (op, 0)) == CC_UNSmode);
}

})

;; Return true if operator is a floating point relational operator.

(define_predicate “float_relational_operator” (match_code “eq,ne,le,lt,ge,gt”) { if (mode != VOIDmode && mode != GET_MODE (op)) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case EQ: case NE:
case LE: case LT:
case GE: case GT:

#if 0 case UEQ: case UNE: case ULE: case ULT: case UGE: case UGT: case ORDERED: case UNORDERED: #endif return GET_MODE (XEXP (op, 0)) == CC_FPmode; } })

;; Return true if operator is EQ/NE of a conditional execution ;; register.

(define_predicate “ccr_eqne_operator” (match_code “eq,ne”) { machine_mode op_mode = GET_MODE (op); rtx op0; rtx op1; int regno;

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case EQ:
case NE:
  break;
}

op1 = XEXP (op, 1); if (op1 != const0_rtx) return FALSE;

op0 = XEXP (op, 0); if (GET_CODE (op0) != REG) return FALSE;

regno = REGNO (op0); if (op_mode == CC_CCRmode && CR_OR_PSEUDO_P (regno)) return TRUE;

return FALSE; })

;; Return true if operator is a minimum or maximum operator (both ;; signed and unsigned).

(define_predicate “minmax_operator” (match_code “smin,smax,umin,umax”) { if (mode != VOIDmode && mode != GET_MODE (op)) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case SMIN:
case SMAX:
case UMIN:
case UMAX:
  break;
}

return TRUE; })

;; Return true if operator is an integer binary operator that can ;; executed conditionally and takes 1 cycle.

(define_predicate “condexec_si_binary_operator” (match_code “plus,minus,and,ior,xor,ashift,ashiftrt,lshiftrt”) { machine_mode op_mode = GET_MODE (op);

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
  return TRUE;
}

})

;; Return true if operator is an integer binary operator that can be ;; executed conditionally by a media instruction.

(define_predicate “condexec_si_media_operator” (match_code “and,ior,xor”) { machine_mode op_mode = GET_MODE (op);

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case AND:
case IOR:
case XOR:
  return TRUE;
}

})

;; Return true if operator is an integer division operator that can ;; executed conditionally.

(define_predicate “condexec_si_divide_operator” (match_code “div,udiv”) { machine_mode op_mode = GET_MODE (op);

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case DIV:
case UDIV:
  return TRUE;
}

})

;; Return true if operator is an integer unary operator that can ;; executed conditionally.

(define_predicate “condexec_si_unary_operator” (match_code “not,neg”) { machine_mode op_mode = GET_MODE (op);

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case NEG:
case NOT:
  return TRUE;
}

})

;; Return true if operator is an addition or subtraction ;; expression. Such expressions can be evaluated conditionally by ;; floating-point instructions.

(define_predicate “condexec_sf_add_operator” (match_code “plus,minus”) { machine_mode op_mode = GET_MODE (op);

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case PLUS:
case MINUS:
  return TRUE;
}

})

;; Return true if operator is a conversion-type expression that can be ;; evaluated conditionally by floating-point instructions.

(define_predicate “condexec_sf_conv_operator” (match_code “abs,neg”) { machine_mode op_mode = GET_MODE (op);

if (mode != VOIDmode && op_mode != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case NEG:
case ABS:
  return TRUE;
}

})

;; Return true if OP is an integer binary operator that can be ;; combined with a (set ... (compare:CC_NZ ...)) pattern.

(define_predicate “intop_compare_operator” (match_code “plus,minus,and,ior,xor,ashift,ashiftrt,lshiftrt”) { if (mode != VOIDmode && GET_MODE (op) != mode) return FALSE;

switch (GET_CODE (op)) { default: return FALSE;

case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case ASHIFTRT:
case LSHIFTRT:
  return GET_MODE (op) == SImode;
}

})

;; Return 1 if operand is a register or 6-bit signed immediate.

(define_predicate “fpr_or_int6_operand” (match_code “reg,subreg,const_int”) { if (GET_CODE (op) == CONST_INT) return IN_RANGE (INTVAL (op), -32, 31);

if (GET_MODE (op) != mode && mode != VOIDmode) return FALSE;

if (GET_CODE (op) == SUBREG) { if (GET_CODE (SUBREG_REG (op)) != REG) return register_operand (op, mode);

  op = SUBREG_REG (op);
}

if (GET_CODE (op) != REG) return FALSE;

return FPR_OR_PSEUDO_P (REGNO (op)); })

;; Return 1 if operand is a 6-bit signed immediate.

(define_predicate “int6_operand” (match_code “const_int”) { if (GET_CODE (op) != CONST_INT) return FALSE;

return IN_RANGE (INTVAL (op), -32, 31); })

;; Return 1 if operand is a 5-bit signed immediate.

(define_predicate “int5_operand” (match_code “const_int”) { return GET_CODE (op) == CONST_INT && IN_RANGE (INTVAL (op), -16, 15); })

;; Return 1 if operand is a 5-bit unsigned immediate.

(define_predicate “uint5_operand” (match_code “const_int”) { return GET_CODE (op) == CONST_INT && IN_RANGE (INTVAL (op), 0, 31); })

;; Return 1 if operand is a 4-bit unsigned immediate.

(define_predicate “uint4_operand” (match_code “const_int”) { return GET_CODE (op) == CONST_INT && IN_RANGE (INTVAL (op), 0, 15); })

;; Return 1 if operand is a 1-bit unsigned immediate (0 or 1).

(define_predicate “uint1_operand” (match_code “const_int”) { return GET_CODE (op) == CONST_INT && IN_RANGE (INTVAL (op), 0, 1); })

;; Return 1 if operand is a valid ACC register number.

(define_predicate “acc_operand” (match_code “reg,subreg”) { return ((mode == VOIDmode || mode == GET_MODE (op)) && REG_P (op) && ACC_P (REGNO (op)) && ((REGNO (op) - ACC_FIRST) & ~ACC_MASK) == 0); })

;; Return 1 if operand is a valid even ACC register number.

(define_predicate “even_acc_operand” (match_code “reg,subreg”) { return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 1) == 0; })

;; Return 1 if operand is zero or four.

(define_predicate “quad_acc_operand” (match_code “reg,subreg”) { return acc_operand (op, mode) && ((REGNO (op) - ACC_FIRST) & 3) == 0; })

;; Return 1 if operand is a valid ACCG register number.

(define_predicate “accg_operand” (match_code “reg,subreg”) { return ((mode == VOIDmode || mode == GET_MODE (op)) && REG_P (op) && ACCG_P (REGNO (op)) && ((REGNO (op) - ACCG_FIRST) & ~ACC_MASK) == 0); })