| ;; Insn predicate definitions for AVR 8-bit microcontrollers. |
| ;; Copyright (C) 2006-2025 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/>. |
| |
| ;; Registers from r0 to r15. |
| (define_predicate "l_register_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) <= 15"))) |
| |
| ;; Registers from r16 to r31. |
| (define_predicate "d_register_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) >= 16 && REGNO (op) <= 31"))) |
| |
| (define_predicate "scratch_or_dreg_operand" |
| (ior (match_operand 0 "d_register_operand") |
| (and (match_code ("scratch")) |
| (match_operand 0 "scratch_operand")))) |
| |
| (define_predicate "even_register_operand" |
| (and (match_code "reg") |
| (and (match_test "REGNO (op) <= 31") |
| (match_test "(REGNO (op) & 1) == 0")))) |
| |
| (define_predicate "odd_register_operand" |
| (and (match_code "reg") |
| (and (match_test "REGNO (op) <= 31") |
| (match_test "(REGNO (op) & 1) != 0")))) |
| |
| ;; SP register. |
| (define_predicate "stack_register_operand" |
| (and (match_code "reg") |
| (match_test "REGNO (op) == REG_SP"))) |
| |
| ;; Return true if OP is a valid address for lower half of I/O space. |
| (define_special_predicate "low_io_address_operand" |
| (ior (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op) - avr_arch->sfr_offset, |
| 0, 0x1F)")) |
| (and (match_code "symbol_ref") |
| (match_test "SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_IO_LOW")))) |
| |
| ;; Return true if OP is a register_operand or low_io_operand. |
| (define_predicate "reg_or_low_io_operand" |
| (ior (match_operand 0 "register_operand") |
| (and (match_code "mem") |
| ; Deliberately only allow QImode no matter what the mode of |
| ; the operand is. This effectively disallows and I/O that |
| ; is not QImode for that operand. |
| (match_test "GET_MODE (op) == QImode") |
| (match_test "low_io_address_operand (XEXP (op, 0), Pmode)")))) |
| |
| ;; Return true if OP is a valid address for high half of I/O space. |
| (define_predicate "high_io_address_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op) - avr_arch->sfr_offset, |
| 0x20, 0x3F)"))) |
| |
| ;; Return true if OP is a valid address of I/O space. |
| (define_special_predicate "io_address_operand" |
| (ior (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op) - avr_arch->sfr_offset, |
| 0, 0x3F)")) |
| (and (match_code "symbol_ref") |
| (match_test "SYMBOL_REF_FLAGS (op) & SYMBOL_FLAG_IO")))) |
| |
| ;; Return 1 if OP is a general operand not in flash memory |
| (define_predicate "nop_general_operand" |
| (and (match_operand 0 "general_operand") |
| (match_test "!avr_mem_flash_p (op)"))) |
| |
| ;; Return 1 if OP is an "ordinary" general operand, i.e. a general |
| ;; operand whose load is not handled by a libgcc call or ELPM. |
| (define_predicate "nox_general_operand" |
| (and (match_operand 0 "general_operand") |
| (not (match_test "avr_load_libgcc_p (op)")) |
| (not (match_test "avr_mem_flashx_p (op)")) |
| (not (match_test "avr_mem_memx_p (op)")))) |
| |
| ;; Return 1 if OP is the zero constant for MODE. |
| (define_predicate "const0_operand" |
| (and (match_code "const_int,const_fixed,const_double") |
| (match_test "op == CONST0_RTX (mode)"))) |
| |
| ;; Return 1 if OP is the one constant integer for MODE. |
| (define_predicate "const1_operand" |
| (and (match_code "const_int") |
| (match_test "op == CONST1_RTX (mode)"))) |
| |
| ;; Return 1 if OP is the constant integer 7 for MODE. |
| (define_predicate "const7_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL(op) == 7"))) |
| |
| ;; Return 1 if OP is the constant integer 15 for MODE. |
| (define_predicate "const15_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL(op) == 15"))) |
| |
| ;; Return 1 if OP is the constant integer 23 for MODE. |
| (define_predicate "const23_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL(op) == 23"))) |
| |
| ;; Return 1 if OP is the constant integer 31 for MODE. |
| (define_predicate "const31_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL(op) == 31"))) |
| |
| |
| ;; Return 1 if OP is constant integer 0..7 for MODE. |
| (define_predicate "const_0_to_7_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 0, 7)"))) |
| |
| ;; Return 1 if OP is constant integer 0..15 for MODE. |
| (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 constant integer 0..23 for MODE. |
| (define_predicate "const_0_to_23_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 0, 23)"))) |
| |
| ;; Return 1 if OP is constant integer 0..31 for MODE. |
| (define_predicate "const_0_to_31_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 0, 31)"))) |
| |
| ;; Return 1 if OP is constant integer 2..7 for MODE. |
| (define_predicate "const_2_to_7_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 2, 7)"))) |
| |
| ;; Return true if OP is constant integer 1..3 for MODE. |
| (define_predicate "const_1_to_3_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 1, 3)"))) |
| |
| ;; Return 1 if OP is constant integer 1..6 for MODE. |
| (define_predicate "const_1_to_6_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 1, 6)"))) |
| |
| ;; Return 1 if OP is constant integer 2..6 for MODE. |
| (define_predicate "const_2_to_6_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 2, 6)"))) |
| |
| ;; Return 1 if OP is constant integer -255..-1. |
| (define_predicate "const_m255_to_m1_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), -255, -1)"))) |
| |
| ;; Return true if OP is a CONST_INT in { -2, -1, 1, 2 }. |
| (define_predicate "abs1_abs2_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL (op) != 0") |
| (match_test "IN_RANGE (INTVAL (op), -2, 2)"))) |
| |
| ;; Returns true if OP is either the constant zero or a register. |
| (define_predicate "reg_or_0_operand" |
| (ior (match_operand 0 "register_operand") |
| (match_operand 0 "const0_operand"))) |
| |
| ;; Returns true if OP is either the constant zero or an upper register. |
| (define_predicate "dreg_or_0_operand" |
| (ior (match_operand 0 "d_register_operand") |
| (match_operand 0 "const0_operand"))) |
| |
| ;; Returns 1 if OP is a SYMBOL_REF. |
| (define_predicate "symbol_ref_operand" |
| (match_code "symbol_ref")) |
| |
| ;; Returns true when OP is a SYMBOL_REF, CONST or CONST_INT that is |
| ;; a multiple of 256, i.e. lo8(OP) = 0. |
| (define_predicate "const_0mod256_operand" |
| (ior (and (match_code "symbol_ref") |
| (match_test "SYMBOL_REF_DECL (op) |
| && DECL_P (SYMBOL_REF_DECL (op)) |
| && DECL_ALIGN (SYMBOL_REF_DECL (op)) >= 8 * 256")) |
| (and (match_code "const") |
| (match_test "GET_CODE (XEXP (op, 0)) == PLUS") |
| (match_test "const_0mod256_operand (XEXP (XEXP (op, 0), 0), HImode)") |
| (match_test "const_0mod256_operand (XEXP (XEXP (op, 0), 1), HImode)")) |
| (and (match_code "const_int") |
| (match_test "INTVAL (op) % 256 == 0")))) |
| |
| ;; Return true if OP is a text segment reference. |
| ;; This is needed for program memory address expressions. |
| (define_predicate "text_segment_operand" |
| (match_code "code_label,label_ref,symbol_ref,plus,const") |
| { |
| switch (GET_CODE (op)) |
| { |
| case CODE_LABEL: |
| return true; |
| case LABEL_REF : |
| return true; |
| case SYMBOL_REF : |
| return SYMBOL_REF_FUNCTION_P (op); |
| case PLUS : |
| // Assume canonical format of symbol + constant. |
| // Fall through. |
| case CONST : |
| return text_segment_operand (XEXP (op, 0), VOIDmode); |
| default : |
| return false; |
| } |
| }) |
| |
| ;; Return true if OP is a constant that contains only one 1 in its |
| ;; binary representation. |
| (define_predicate "single_one_operand" |
| (and (match_code "const_int") |
| (match_test "exact_log2(INTVAL (op) & GET_MODE_MASK (mode)) >= 0"))) |
| |
| ;; Return true if OP is a constant that contains only one 0 in its |
| ;; binary representation. |
| (define_predicate "single_zero_operand" |
| (and (match_code "const_int") |
| (match_test "exact_log2(~INTVAL (op) & GET_MODE_MASK (mode)) >= 0"))) |
| |
| ;; |
| (define_predicate "avr_sp_immediate_operand" |
| (and (match_code "const_int") |
| (match_test "satisfies_constraint_Csp (op)"))) |
| |
| ;; True for EQ & NE |
| (define_predicate "eqne_operator" |
| (match_code "eq,ne")) |
| |
| ;; True for GE & LT |
| (define_predicate "gelt_operator" |
| (match_code "ge,lt")) |
| |
| ;; True for GT, GTU, LE & LEU |
| (define_predicate "difficult_comparison_operator" |
| (match_code "gt,gtu,le,leu")) |
| |
| ;; False for GT, GTU, LE & LEU |
| (define_predicate "simple_comparison_operator" |
| (and (match_operand 0 "comparison_operator") |
| (not (match_code "gt,gtu,le,leu")))) |
| |
| ;; True for EQ, NE, GE, LT, GT, LE |
| (define_predicate "signed_comparison_operator" |
| (match_code "eq,ne,ge,lt,gt,le")) |
| |
| ;; True for SIGN_EXTEND, ZERO_EXTEND. |
| (define_predicate "extend_operator" |
| (match_code "sign_extend,zero_extend")) |
| |
| ;; True for 8-bit operations that set SREG.N and SREG.Z in a |
| ;; usable way: |
| ;; * OP0 is a QImode register, and |
| ;; * OP1 is a QImode register or CONST_INT, and |
| ;; |
| ;; the allowed operations is one of: |
| ;; |
| ;; * SHIFTs with a const_int offset in { 1, 2, 3 }. |
| ;; * MINUS and XOR with a register operand |
| ;; * IOR and AND with a register operand, or d-reg + const_int |
| ;; * PLUS with a register operand, or d-reg + const_int, |
| ;; or a const_int in { -2, -1, 1, 2 }. */ |
| (define_predicate "op8_ZN_operator" |
| (and (match_code "plus,minus,ashift,ashiftrt,lshiftrt,and,ior,xor") |
| (match_test "avr_op8_ZN_operator (op)"))) |
| |
| ;; Return true if OP is a valid call operand. |
| (define_predicate "call_insn_operand" |
| (and (match_code "mem") |
| (ior (match_test "register_operand (XEXP (op, 0), mode)") |
| (match_test "CONSTANT_ADDRESS_P (XEXP (op, 0))")))) |
| |
| ;; For some insns we must ensure that no hard register is inserted |
| ;; into their operands because the insns are split and the split |
| ;; involves hard registers. An example are divmod insn that are |
| ;; split to insns that represent implicit library calls. |
| |
| ;; True for register that is pseudo register. |
| (define_predicate "pseudo_register_operand" |
| (and (match_operand 0 "register_operand") |
| (not (and (match_code "reg") |
| (match_test "HARD_REGISTER_P (op)"))))) |
| |
| ;; True for operand that is pseudo register or CONST_INT. |
| (define_predicate "pseudo_register_or_const_int_operand" |
| (ior (match_operand 0 "const_int_operand") |
| (match_operand 0 "pseudo_register_operand"))) |
| |
| ;; We keep combiner from inserting hard registers into the input of sign- and |
| ;; zero-extends. A hard register in the input operand is not wanted because |
| ;; 32-bit multiply patterns clobber some hard registers and extends with a |
| ;; hard register that overlaps these clobbers won't combine to a widening |
| ;; multiplication. There is no need for combine to propagate or insert |
| ;; hard registers, register allocation can do it just as well. |
| |
| ;; True for operand that is pseudo register at combine time. |
| (define_predicate "combine_pseudo_register_operand" |
| (ior (match_operand 0 "pseudo_register_operand") |
| (and (match_operand 0 "register_operand") |
| (match_test "reload_completed || reload_in_progress")))) |
| |
| ;; Return true if OP is a constant integer that is either |
| ;; 8 or 16 or 24. |
| (define_predicate "const_8_16_24_operand" |
| (and (match_code "const_int") |
| (match_test "INTVAL(op) == 8 || INTVAL(op) == 16 || INTVAL(op) == 24"))) |
| |
| ;; Unsigned CONST_INT that fits in 8 bits, i.e. 0..255. |
| (define_predicate "u8_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 0, 255)"))) |
| |
| ;; Signed CONST_INT that fits in 8 bits, i.e. -128..127. |
| (define_predicate "s8_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), -128, 127)"))) |
| |
| ;; One-extended CONST_INT that fits in 8 bits, i.e. -256..-1. |
| (define_predicate "o8_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), -256, -1)"))) |
| |
| ;; Signed CONST_INT that fits in 9 bits, i.e. -256..255. |
| (define_predicate "s9_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), -256, 255)"))) |
| |
| (define_predicate "register_or_s9_operand" |
| (ior (match_operand 0 "register_operand") |
| (match_operand 0 "s9_operand"))) |
| |
| ;; Unsigned CONST_INT that fits in 16 bits, i.e. 0..65536. |
| (define_predicate "u16_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), 0, (1<<16)-1)"))) |
| |
| ;; Signed CONST_INT that fits in 16 bits, i.e. -32768..32767. |
| (define_predicate "s16_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), -(1<<15), (1<<15)-1)"))) |
| |
| ;; One-extended CONST_INT that fits in 16 bits, i.e. -65536..-1. |
| (define_predicate "o16_operand" |
| (and (match_code "const_int") |
| (match_test "IN_RANGE (INTVAL (op), -(1<<16), -1)"))) |
| |
| ;; Const int, fixed, or double operand |
| (define_predicate "const_operand" |
| (ior (match_code "const_fixed") |
| (match_code "const_double") |
| (match_operand 0 "const_int_operand"))) |
| |
| ;; Const int, const fixed, or const double operand |
| (define_predicate "nonmemory_or_const_operand" |
| (ior (match_code "const_fixed") |
| (match_code "const_double") |
| (match_operand 0 "nonmemory_operand"))) |
| |
| ;; Immediate, const fixed, or const double operand |
| (define_predicate "const_or_immediate_operand" |
| (ior (match_code "const_fixed") |
| (match_code "const_double") |
| (match_operand 0 "immediate_operand"))) |
| |
| (define_predicate "set_some_operation" |
| (and (match_code "parallel") |
| (match_test "avr_set_some_operation (op)"))) |