518 lines
14 KiB
Markdown
518 lines
14 KiB
Markdown
|
;; 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 "<mul>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"
|
||
|
"<mul>.x\\t%0, %2")
|
||
|
|
||
|
(define_expand "<mul>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_<mul>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 "*b<cond: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<CC>\\t%l0";
|
||
|
else
|
||
|
return "b<rCC>\\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")
|