;; Constraint definitions for LoongArch.
;; Copyright (C) 2021-2023 Free Software Foundation, Inc.
;; Contributed by Loongson Ltd.
;;
;; 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/>.

;; Register constraints

;; "a" <-----unused
;; "b" "A constant call not local address."
;; "c" "A constant call local address."
;; "d" <-----unused
;; "e" JIRL_REGS
;; "f" FP_REGS
;; "g" <-----unused
;; "h" <-----unused
;; "i" "Matches a general integer constant." (Global non-architectural)
;; "j" SIBCALL_REGS
;; "k" "A memory operand whose address is formed by a base register and
;;      (optionally scaled) index register."
;; "l" "A signed 16-bit constant."
;; "m" "A memory operand whose address is formed by a base register and offset
;;      that is suitable for use in instructions with the same addressing mode
;;      as @code{st.w} and @code{ld.w}."
;; "n" "Matches a non-symbolic integer constant." (Global non-architectural)
;; "o" "Matches an offsettable memory reference." (Global non-architectural)
;; "p" "Matches a general address." (Global non-architectural)
;; "q" CSR_REGS
;; "r" GENERAL_REGS (Global non-architectural)
;; "s" "Matches a symbolic integer constant." (Global non-architectural)
;; "t" <-----unused
;; "u" "A signed 52bit constant and low 32-bit is zero (for logic instructions)"
;; "v" "A signed 64-bit constant and low 44-bit is zero (for logic instructions)."
;; "w" "Matches any valid memory."
;; "x" <-----unused
;; "y" <-----unused
;; "z" FCC_REGS
;; "A" <-----unused
;; "B" <-----unused
;; "C" <-----unused
;; "D" <-----unused
;; "E" "Matches a floating-point constant." (Global non-architectural)
;; "F" "Matches a floating-point constant." (Global non-architectural)
;; "G" "Floating-point zero."
;; "H" <-----unused
;; "I" "A signed 12-bit constant (for arithmetic instructions)."
;; "J" "Integer zero."
;; "K" "An unsigned 12-bit constant (for logic instructions)."
;; "L" <-----unused
;; "M" <-----unused
;; "N" <-----unused
;; "O" <-----unused
;; "P" <-----unused
;; "Q" <-----unused
;; "R" <-----unused
;; "S" <-----unused
;; "T" <-----unused
;; "U" <-----unused
;; "V" "Matches a non-offsettable memory reference." (Global non-architectural)
;; "W" <-----unused
;; "X" "Matches anything." (Global non-architectural)
;; "Y" -
;;    "Yd"
;;       "A constant @code{move_operand} that can be safely loaded using
;;	  @code{la}."
;;    "Yx"
;; "Z" -
;;    "ZC"
;;      "A memory operand whose address is formed by a base register and offset
;;       that is suitable for use in instructions with the same addressing mode
;;       as @code{ll.w} and @code{sc.w}."
;;    "ZB"
;;      "An address that is held in a general-purpose register.
;;      The offset is zero"
;;    "ZD"
;;	"An address operand whose address is formed by a base register
;;	 and offset that is suitable for use in instructions with the same
;;	 addressing mode as @code{preld}."
;; "<" "Matches a pre-dec or post-dec operand." (Global non-architectural)
;; ">" "Matches a pre-inc or post-inc operand." (Global non-architectural)

(define_constraint "b"
  "@internal
   A constant call no local address."
  (match_operand 0 "is_const_call_no_local_symbol"))

(define_constraint "c"
  "@internal
   A constant call local address."
  (match_operand 0 "is_const_call_local_symbol"))

(define_register_constraint "e" "JIRL_REGS"
  "@internal")

(define_register_constraint "f" "TARGET_HARD_FLOAT ? FP_REGS : NO_REGS"
  "A floating-point register (if available).")

(define_register_constraint "j" "SIBCALL_REGS"
  "@internal")

(define_memory_constraint "k"
  "A memory operand whose address is formed by a base register and (optionally scaled)
   index register."
  (and (match_code "mem")
       (match_test "loongarch_base_index_address_p (XEXP (op, 0), mode)")))

(define_constraint "l"
"A signed 16-bit constant."
(and (match_code "const_int")
     (match_test "IMM16_OPERAND (ival)")))

(define_memory_constraint "m"
  "A memory operand whose address is formed by a base register and offset
   that is suitable for use in instructions with the same addressing mode
   as @code{st.w} and @code{ld.w}."
  (and (match_code "mem")
       (match_test "loongarch_12bit_offset_address_p (XEXP (op, 0), mode)")))

(define_register_constraint "q" "CSR_REGS"
  "A general-purpose register except for $r0 and $r1 for lcsr.")

(define_constraint "u"
  "A signed 52bit constant and low 32-bit is zero (for logic instructions)."
  (and (match_code "const_int")
       (match_test "LU32I_OPERAND (ival)")))

(define_constraint "v"
  "A signed 64-bit constant and low 44-bit is zero (for logic instructions)."
  (and (match_code "const_int")
       (match_test "LU52I_OPERAND (ival)")))

(define_register_constraint "z" "FCC_REGS"
  "A floating-point condition code register.")

;; Floating-point constraints

(define_constraint "G"
  "Floating-point zero."
  (and (match_code "const_double")
       (match_test "op == CONST0_RTX (mode)")))

;; Integer constraints

(define_constraint "I"
  "A signed 12-bit constant (for arithmetic instructions)."
  (and (match_code "const_int")
       (match_test "IMM12_OPERAND (ival)")))

(define_constraint "J"
  "Integer zero."
  (and (match_code "const_int")
       (match_test "ival == 0")))

(define_constraint "K"
  "An unsigned 12-bit constant (for logic instructions)."
  (and (match_code "const_int")
       (match_test "IMM12_OPERAND_UNSIGNED (ival)")))

(define_constraint "Yd"
  "@internal
   A constant @code{move_operand} that can be safely loaded using
   @code{la}."
  (and (match_operand 0 "move_operand")
       (match_test "CONSTANT_P (op)")))

(define_constraint "Yx"
   "@internal"
   (match_operand 0 "low_bitmask_operand"))

(define_memory_constraint "ZC"
  "A memory operand whose address is formed by a base register and offset
   that is suitable for use in instructions with the same addressing mode
   as @code{ll.w} and @code{sc.w}."
  (and (match_code "mem")
       (match_test "loongarch_14bit_shifted_offset_address_p (XEXP (op, 0), mode)")))

(define_memory_constraint "ZB"
  "@internal
  An address that is held in a general-purpose register.
  The offset is zero"
  (and (match_code "mem")
       (match_test "REG_P (XEXP (op, 0))")))

(define_address_constraint "ZD"
  "An address operand whose address is formed by a base register
   and offset that is suitable for use in instructions with the same
   addressing mode as @code{preld}."
   (match_test "loongarch_12bit_offset_address_p (op, mode)"))

(define_constraint "ZE"
  "A symbolic suitable as stack canary in the normal/medium code model."
  (match_operand 0 "ssp_normal_operand"))

(define_constraint "ZF"
  "A symbolic suitable as stack canary, but in the extreme code model."
  (and (match_operand 0 "ssp_operand")
       (not (match_operand 0 "ssp_normal_operand"))))
