;; GCC machine description for Renesas H8/300
;; Copyright (C) 1992-2024 Free Software Foundation, Inc.

;;   Contributed by Steve Chamberlain (sac@cygnus.com),
;;   Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).

;; 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/>.

;; We compute exact length on each instruction for most of the time.
;; In some case, most notably bit operations that may involve memory
;; operands, the lengths in this file are "worst case".

;; On the H8/300H and H8S, adds/subs operate on the 32bit "er"
;; registers.  Right now GCC doesn't expose the "e" half to the
;; compiler, so using add/subs for addhi and subhi is safe.  Long
;; term, we want to expose the "e" half to the compiler (gives us 8
;; more 16bit registers).  At that point addhi and subhi can't use
;; adds/subs.

;; There's currently no way to have an insv/extzv expander for the H8/300H
;; because word_mode is different for the H8/300 and H8/300H.

;; Shifts/rotates by small constants should be handled by special
;; patterns so we get the length and cc status correct.

;; Bitfield operations no longer accept memory operands.  We need
;; to add variants which operate on memory back to the MD.

;; ??? Implement remaining bit ops available on the h8300

;; ----------------------------------------------------------------------
;; CONSTANTS
;; ----------------------------------------------------------------------

(define_constants
  [(UNSPEC_INCDEC	0)
   (UNSPEC_MONITOR	1)])

(define_constants
  [(UNSPEC_MOVMD	100)
   (UNSPEC_STPCPY	101)])

(define_constants
  [(R0_REG	 0)
   (SC_REG	 3)
   (COUNTER_REG  4)
   (SOURCE_REG   5)
   (DESTINATION_REG 6)
   (HFP_REG	 6)
   (SP_REG	 7)
   (MAC_REG	 8)
   (AP_REG	 9)
   (RAP_REG	10)
   (FP_REG	11)
   (CC_REG	12)])

;; ----------------------------------------------------------------------
;; ATTRIBUTES
;; ----------------------------------------------------------------------

(define_attr "cpu" "h8300,h8300h"
  (const (symbol_ref "cpu_type")))

(define_attr "type" "branch,arith,bitbranch,call"
  (const_string "arith"))

(define_attr "length_table" "none,add,logicb,movb,movw,movl,mova_zero,mova,unary,mov_imm4,short_immediate,bitfield,bitbranch"
  (const_string "none"))

;; The size of instructions in bytes.

(define_attr "length" ""
  (cond [(eq_attr "type" "branch")
	 ;; In a forward delayed branch, (pc) represents the end of the
	 ;; delay sequence, not the end of the branch itself.
	 (if_then_else (and (ge (minus (match_dup 0) (pc))
				(const_int -126))
			    (le (plus (minus (match_dup 0) (pc))
				      (symbol_ref "DELAY_SLOT_LENGTH (insn)"))
				(const_int 125)))
		       (const_int 2)
		       (if_then_else (and (eq_attr "cpu" "h8300h")
					  (and (ge (minus (pc) (match_dup 0))
						   (const_int -32000))
					       (le (minus (pc) (match_dup 0))
						   (const_int 32000))))
				     (const_int 4)
				     (const_int 6)))
	 (eq_attr "type" "bitbranch")
	 (if_then_else (and (ge (minus (match_dup 0) (pc))
				(const_int -126))
			    (le (minus (match_dup 0) (pc))
				(const_int 126)))
		       (plus (symbol_ref "h8300_insn_length_from_table (insn, operands)")
			     (const_int 2))
		       (if_then_else (and (eq_attr "cpu" "h8300h")
					  (and (ge (minus (pc) (match_dup 0))
						   (const_int -32000))
					       (le (minus (pc) (match_dup 0))
						   (const_int 32000))))
				     (plus (symbol_ref "h8300_insn_length_from_table (insn, operands)")
					   (const_int 4))
				     (plus (symbol_ref "h8300_insn_length_from_table (insn, operands)")
					   (const_int 6))))
	 (eq_attr "length_table" "!none")
	 (symbol_ref "h8300_insn_length_from_table (insn, operands)")]
	(const_int 200)))

;; Condition code settings.
;;
;; none - insn does not affect cc
;; none_0hit - insn does not affect cc but it does modify operand 0
;;	This attribute is used to keep track of when operand 0 changes.
;;	See the description of NOTICE_UPDATE_CC for more info.
;; set_znv - insn sets z,n,v to usable values (like a tst insn); c is unknown.
;; set_zn  - insn sets z,n to usable values; v,c are unknown.
;; compare - compare instruction
;; clobber - value of cc is unknown

(define_attr "old_cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
  (const_string "clobber"))

;; So the idea here is to define iterators and substitutions so that we
;; can easily modify the patterns with CC clobbers into a pattern
;; which sets appropriate condition codes

;; The modes we're supporting.  This is used when we want to generate
;; multiple patterns where only the mode differs from a single template
(define_mode_iterator H8cc [CC CCZN CCZ])

;; This is used to generate multiple define_substs from a single
;; template for the different variants we might have.
(define_mode_attr cc [(CC "cc") (CCZN "cczn") (CCZ "ccz")])

;; The primary substitution pattern.  <cc> is used to create multiple
;; substitutions based on the CC bits that are set.
;;
;; The mode iterator sets the actual mode on the condition code
;; REG expression.
(define_subst "subst_<cc>"
  [(set (match_operand 0 "")
	(match_operand 1 ""))
   (clobber (reg:CC CC_REG))]
  ""
  [(set (reg:H8cc CC_REG)
	(compare:H8cc (match_dup 1) (const_int 0)))
   (set (match_dup 0) (match_dup 1))])


;; So when we see <cc> or <cczn> in a define_insn pattern, we'll
;; apply the subst_cczn or subset_cc define_subst to generate a
;; new pattern that compare-elim can use
(define_subst_attr "cczn" "subst_cczn" "" "_cczn")
(define_subst_attr "ccz" "subst_ccz" "" "_ccz")
(define_subst_attr "cc" "subst_cc" "" "_cc")

;; Type of delay slot.  NONE means the instruction has no delay slot.
;; JUMP means it is an unconditional jump that (if short enough)
;; could be implemented using bra/s.

(define_attr "delay_slot" "none,jump"
  (const_string "none"))

;; "yes" if the instruction can be put into a delay slot.  It's not
;; entirely clear that jsr is not valid in delay slots, but it
;; definitely doesn't have the effect of causing the called function
;; to return to the target of the delayed branch.

(define_attr "can_delay" "no,yes"
  (cond [(eq_attr "type" "branch,bitbranch,call")
	   (const_string "no")
	 (geu (symbol_ref "get_attr_length (insn)") (const_int 2))
	   (const_string "no")]
	(const_string "yes")))

;; Only allow jumps to have a delay slot if we think they might
;; be short enough.  This is just an optimization: we don't know
;; for certain whether they will be or not.

(define_delay (and (eq_attr "delay_slot" "jump")
		   (eq (symbol_ref "get_attr_length (insn)") (const_int 2)))
  [(eq_attr "can_delay" "yes")
   (nil)
   (nil)])

;; Provide the maximum length of an assembly instruction in an asm
;; statement.  The maximum length of 14 bytes is achieved on H8SX.

(define_asm_attributes
  [(set (attr "length")
	(cond [(match_test "TARGET_H8300H") (const_int 10)
	       (match_test "TARGET_H8300S") (const_int 10)]
	      (const_int 14)))])

(include "predicates.md")
(include "constraints.md")

;; ----------------------------------------------------------------------
;; MACRO DEFINITIONS
;; ----------------------------------------------------------------------

;; This mode iterator allows :P to be used for patterns that operate on
;; pointer-sized quantities.  Exactly one of the two alternatives will match.

(define_mode_iterator P [(HI "Pmode == HImode") (SI "Pmode == SImode")])

(define_mode_iterator QHI [QI HI])

(define_mode_iterator HSI [HI SI])
(define_mode_iterator HSI2 [HI SI])

(define_mode_iterator QHSI [QI HI SI])
(define_mode_iterator QHSI2 [QI HI SI])

(define_mode_iterator QHSIF [QI HI SI SF])

(define_mode_iterator SFI [SF SI])

(define_code_iterator shifts [ashift ashiftrt lshiftrt])

(define_code_iterator logicals [ior xor and])

(define_code_iterator ors [ior xor])

(define_code_iterator eqne [eq ne])
(define_code_attr eqne_invert [(eq "ne") (ne "eq")])

;; For storing the C flag, map from the unsigned comparison to the right
;; code for testing the C bit.
(define_code_iterator geultu [geu ltu])
(define_code_attr geultu_to_c [(geu "eq") (ltu "ne")])


(include "movepush.md")
(include "mova.md")
(include "testcompare.md")
(include "addsub.md")
(include "multiply.md")
(include "divmod.md")
(include "logical.md")
(include "other.md")
(include "jumpcall.md")
(include "proepi.md")
(include "extensions.md")
(include "shiftrotate.md")
(include "bitfield.md")
(include "combiner.md")
;;(include "peepholes.md")
