;; Machine description for Moxie ;; Copyright (C) 2009-2021 Free Software Foundation, Inc. ;; Contributed by Anthony Green green@moxielogic.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/.

;; ------------------------------------------------------------------------- ;; Moxie specific constraints, predicates and attributes ;; -------------------------------------------------------------------------

(include “constraints.md”) (include “predicates.md”)

; Most instructions are two bytes long. (define_attr “length” "" (const_int 2))

;; ------------------------------------------------------------------------- ;; nop instruction ;; -------------------------------------------------------------------------

(define_insn “nop” [(const_int 0)] "" “nop”)

;; ------------------------------------------------------------------------- ;; Arithmetic instructions ;; -------------------------------------------------------------------------

(define_insn “addsi3” [(set (match_operand:SI 0 “register_operand” “=r,r,r”) (plus:SI (match_operand:SI 1 “register_operand” “0,0,0”) (match_operand:SI 2 “moxie_add_operand” “I,N,r”)))] "" “@ inc\t%0, %2 dec\t%0, -%2 add\t%0, %2”)

(define_insn “subsi3” [(set (match_operand:SI 0 “register_operand” “=r,r”) (minus:SI (match_operand:SI 1 “register_operand” “0,0”) (match_operand:SI 2 “moxie_sub_operand” “I,r”)))] "" “@ dec\t%0, %2 sub\t%0, %2”)

(define_insn “mulsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (mult:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" “mul\t%0, %2”)

(define_code_iterator EXTEND [sign_extend zero_extend]) (define_code_attr mul [(sign_extend “mul”) (zero_extend “umul”)])

(define_insn “si3_highpart” [(set (match_operand:SI 0 “register_operand” “=r”) (truncate:SI (lshiftrt:DI (mult:DI (EXTEND:DI (match_operand:SI 1 “register_operand” “0”)) (EXTEND:DI (match_operand:SI 2 “register_operand” “r”))) (const_int 32))))] “TARGET_HAS_MULX” “.x\t%0, %2”)

(define_expand “sidi3” [(set (match_operand:DI 0 “register_operand” "") (mult:DI (EXTEND:DI (match_operand:SI 1 “register_operand” “0”)) (EXTEND:DI (match_operand:SI 2 “register_operand” “r”))))] “TARGET_HAS_MULX” { rtx hi = gen_reg_rtx (SImode); rtx lo = gen_reg_rtx (SImode);

emit_insn (gen_si3_highpart (hi, operands[1], operands[2])); emit_insn (gen_mulsi3 (lo, operands[1], operands[2])); emit_move_insn (gen_lowpart (SImode, operands[0]), lo); emit_move_insn (gen_highpart (SImode, operands[0]), hi); DONE; })

(define_insn “divsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (div:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" “div\t%0, %2”)

(define_insn “udivsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (udiv:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" “udiv\t%0, %2”)

(define_insn “modsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (mod:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" “mod\t%0, %2”)

(define_insn “umodsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (umod:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" “umod\t%0, %2”)

;; ------------------------------------------------------------------------- ;; Unary arithmetic instructions ;; -------------------------------------------------------------------------

(define_insn “negsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (neg:SI (match_operand:SI 1 “register_operand” “r”)))] "" “neg\t%0, %1”)

(define_insn “one_cmplsi2” [(set (match_operand:SI 0 “register_operand” “=r”) (not:SI (match_operand:SI 1 “register_operand” “r”)))] "" “not\t%0, %1”)

;; ------------------------------------------------------------------------- ;; Logical operators ;; -------------------------------------------------------------------------

(define_insn “andsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (and:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" { return “and\t%0, %2”; })

(define_insn “xorsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (xor:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" { return “xor\t%0, %2”; })

(define_insn “iorsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (ior:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" { return “or\t%0, %2”; })

;; ------------------------------------------------------------------------- ;; Shifters ;; -------------------------------------------------------------------------

(define_insn “ashlsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (ashift:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" { return “ashl\t%0, %2”; })

(define_insn “ashrsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (ashiftrt:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" { return “ashr\t%0, %2”; })

(define_insn “lshrsi3” [(set (match_operand:SI 0 “register_operand” “=r”) (lshiftrt:SI (match_operand:SI 1 “register_operand” “0”) (match_operand:SI 2 “register_operand” “r”)))] "" { return “lshr\t%0, %2”; })

;; ------------------------------------------------------------------------- ;; Move instructions ;; -------------------------------------------------------------------------

;; SImode

;; Push a register onto the stack (define_insn “movsi_push” [(set (mem:SI (pre_dec:SI (reg:SI 1))) (match_operand:SI 0 “register_operand” “r”))] "" “push\t$sp, %0”)

;; Pop a register from the stack (define_insn “movsi_pop” [(set (match_operand:SI 1 “register_operand” “=r”) (mem:SI (post_inc:SI (match_operand:SI 0 “register_operand” “r”))))] "" “pop\t%0, %1”)

(define_expand “movsi” [(set (match_operand:SI 0 “general_operand” "") (match_operand:SI 1 “general_operand” "“))] "" " { /* If this is a store, force the value into a register. */ if (! (reload_in_progress || reload_completed)) { if (MEM_P (operands[0])) { operands[1] = force_reg (SImode, operands[1]); if (MEM_P (XEXP (operands[0], 0))) operands[0] = gen_rtx_MEM (SImode, force_reg (SImode, XEXP (operands[0], 0))); } else if (MEM_P (operands[1]) && MEM_P (XEXP (operands[1], 0))) operands[1] = gen_rtx_MEM (SImode, force_reg (SImode, XEXP (operands[1], 0))); } }”)

(define_insn “*movsi” [(set (match_operand:SI 0 “nonimmediate_operand” “=r,r,r,W,A,r,r,B,r”) (match_operand:SI 1 “moxie_general_movsrc_operand” “O,r,i,r,r,W,A,r,B”))] “register_operand (operands[0], SImode) || register_operand (operands[1], SImode)” “@ xor\t%0, %0 mov\t%0, %1 ldi.l\t%0, %1 st.l\t%0, %1 sta.l\t%0, %1 ld.l\t%0, %1 lda.l\t%0, %1 sto.l\t%0, %1 ldo.l\t%0, %1” [(set_attr “length” “2,2,6,2,6,2,6,4,4”)])

(define_insn “zero_extendqisi2” [(set (match_operand:SI 0 “register_operand” “=r,r,r,r”) (zero_extend:SI (match_operand:QI 1 “nonimmediate_operand” “r,W,A,B”)))] "" “@ zex.b\t%0, %1 ld.b\t%0, %1 lda.b\t%0, %1 ldo.b\t%0, %1” [(set_attr “length” “2,2,6,4”)])

(define_insn “zero_extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r,r,r,r”) (zero_extend:SI (match_operand:HI 1 “nonimmediate_operand” “r,W,A,B”)))] "" “@ zex.s\t%0, %1 ld.s\t%0, %1 lda.s\t%0, %1 ldo.s\t%0, %1” [(set_attr “length” “2,2,6,4”)])

(define_insn “extendqisi2” [(set (match_operand:SI 0 “register_operand” “=r”) (sign_extend:SI (match_operand:QI 1 “nonimmediate_operand” “r”)))] "" “@ sex.b\t%0, %1” [(set_attr “length” “2”)])

(define_insn “extendhisi2” [(set (match_operand:SI 0 “register_operand” “=r”) (sign_extend:SI (match_operand:HI 1 “nonimmediate_operand” “r”)))] "" “@ sex.s\t%0, %1” [(set_attr “length” “2”)])

(define_expand “movqi” [(set (match_operand:QI 0 “general_operand” "") (match_operand:QI 1 “general_operand” "“))] "" " { /* If this is a store, force the value into a register. */ if (MEM_P (operands[0])) operands[1] = force_reg (QImode, operands[1]); }”)

(define_insn “*movqi” [(set (match_operand:QI 0 “nonimmediate_operand” “=r,r,r,W,A,r,r,B,r”) (match_operand:QI 1 “moxie_general_movsrc_operand” “O,r,i,r,r,W,A,r,B”))] “register_operand (operands[0], QImode) || register_operand (operands[1], QImode)” “@ xor\t%0, %0 mov\t%0, %1 ldi.b\t%0, %1 st.b\t%0, %1 sta.b\t%0, %1 ld.b\t%0, %1 lda.b\t%0, %1 sto.b\t%0, %1 ldo.b\t%0, %1” [(set_attr “length” “2,2,6,2,6,2,6,4,4”)])

(define_expand “movhi” [(set (match_operand:HI 0 “general_operand” "") (match_operand:HI 1 “general_operand” "“))] "" " { /* If this is a store, force the value into a register. */ if (MEM_P (operands[0])) operands[1] = force_reg (HImode, operands[1]); }”)

(define_insn “*movhi” [(set (match_operand:HI 0 “nonimmediate_operand” “=r,r,r,W,A,r,r,B,r”) (match_operand:HI 1 “moxie_general_movsrc_operand” “O,r,i,r,r,W,A,r,B”))] “(register_operand (operands[0], HImode) || register_operand (operands[1], HImode))” “@ xor\t%0, %0 mov\t%0, %1 ldi.s\t%0, %1 st.s\t%0, %1 sta.s\t%0, %1 ld.s\t%0, %1 lda.s\t%0, %1 sto.s\t%0, %1 ldo.s\t%0, %1” [(set_attr “length” “2,2,6,2,6,2,6,4,4”)])

;; ------------------------------------------------------------------------- ;; Compare instructions ;; -------------------------------------------------------------------------

(define_constants [(CC_REG 19)])

(define_expand “cbranchsi4” [(set (reg:CC CC_REG) (compare:CC (match_operand:SI 1 “general_operand” "") (match_operand:SI 2 “general_operand” ""))) (set (pc) (if_then_else (match_operator 0 “comparison_operator” [(reg:CC CC_REG) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "" " /* Force the compare operands into registers. */ if (GET_CODE (operands[1]) != REG) operands[1] = force_reg (SImode, operands[1]); if (GET_CODE (operands[2]) != REG) operands[2] = force_reg (SImode, operands[2]); ")

(define_insn “*cmpsi” [(set (reg:CC CC_REG) (compare (match_operand:SI 0 “register_operand” “r”) (match_operand:SI 1 “register_operand” “r”)))] "" “cmp\t%0, %1”)

;; ------------------------------------------------------------------------- ;; Branch instructions ;; -------------------------------------------------------------------------

(define_code_iterator cond [ne eq lt ltu gt gtu ge le geu leu]) (define_code_attr CC [(ne “ne”) (eq “eq”) (lt “lt”) (ltu “ltu”) (gt “gt”) (gtu “gtu”) (ge “ge”) (le “le”) (geu “geu”) (leu “leu”) ]) (define_code_attr rCC [(ne “eq”) (eq “ne”) (lt “ge”) (ltu “geu”) (gt “le”) (gtu “leu”) (ge “lt”) (le “gt”) (geu “ltu”) (leu “gtu”) ])

(define_insn “*bcond:code” [(set (pc) (if_then_else (cond (reg:CC CC_REG) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" { if (get_attr_length (insn) == 2) return “b\t%l0”; else return “b\t.+6\n\tjmpa %l0”; } [(set (attr “length”) (if_then_else (lt (abs (minus (pc) (match_dup 0))) (const_int 1022)) (const_int 2) (const_int 8)))])

;; ------------------------------------------------------------------------- ;; Call and Jump instructions ;; -------------------------------------------------------------------------

(define_expand “call” [(call (match_operand:QI 0 “memory_operand” "") (match_operand 1 “general_operand” ""))] "" { gcc_assert (MEM_P (operands[0])); })

(define_insn “*call” [(call (mem:QI (match_operand:SI 0 “nonmemory_operand” “i,r”)) (match_operand 1 "" ""))] "" “@ jsra\t%0 jsr\t%0” [(set_attr “length” “6,2”)])

(define_expand “call_value” [(set (match_operand 0 "" "") (call (match_operand:QI 1 “memory_operand” "") (match_operand 2 "" "")))] "" { gcc_assert (MEM_P (operands[1])); })

(define_insn “*call_value” [(set (match_operand 0 “register_operand” “=r”) (call (mem:QI (match_operand:SI 1 “immediate_operand” “i”)) (match_operand 2 "" "")))] "" “jsra\t%1” [(set_attr “length” “6”)])

(define_insn “*call_value_indirect” [(set (match_operand 0 “register_operand” “=r”) (call (mem:QI (match_operand:SI 1 “register_operand” “r”)) (match_operand 2 "" "")))] "" “jsr\t%1”)

(define_insn “indirect_jump” [(set (pc) (match_operand:SI 0 “nonimmediate_operand” “r”))] "" “jmp\t%0”)

(define_insn “jump” [(set (pc) (label_ref (match_operand 0 "" "")))] "" “jmpa\t%l0” [(set_attr “length” “6”)])

;; ------------------------------------------------------------------------- ;; Prologue & Epilogue ;; -------------------------------------------------------------------------

(define_expand “prologue” [(clobber (const_int 0))] "" " { moxie_expand_prologue (); DONE; } ")

(define_expand “epilogue” [(return)] "" " { moxie_expand_epilogue (); DONE; } ")

(define_insn “returner” [(return)] “reload_completed” “ret”)