aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/ft32/ft32.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/ft32/ft32.md')
-rw-r--r--gcc/config/ft32/ft32.md932
1 files changed, 932 insertions, 0 deletions
diff --git a/gcc/config/ft32/ft32.md b/gcc/config/ft32/ft32.md
new file mode 100644
index 0000000..68dc683
--- /dev/null
+++ b/gcc/config/ft32/ft32.md
@@ -0,0 +1,932 @@
+;; Machine description for FT32
+;; Copyright (C) 2015 Free Software Foundation, Inc.
+;; Contributed by FTDI <support@ftdi.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/>.
+
+;; -------------------------------------------------------------------------
+;; FT32 specific constraints, predicates and attributes
+;; -------------------------------------------------------------------------
+
+(include "constraints.md")
+(include "predicates.md")
+
+(define_constants [
+ (FP_REG 0)
+ (SP_REG 1)
+ (CC_REG 35)
+])
+
+(define_c_enum "unspec"
+ [UNSPEC_STRLEN
+ UNSPEC_MOVMEM
+ UNSPEC_SETMEM
+ UNSPEC_STPCPY
+ UNSPEC_INDEX_JMP
+ UNSPEC_LPM
+ UNSPEC_FMUL
+ UNSPEC_FMULS
+ UNSPEC_FMULSU
+ UNSPEC_COPYSIGN
+ UNSPEC_IDENTITY
+ UNSPEC_INSERT_BITS
+ UNSPEC_JMP_EPILOG
+ UNSPEC_JMP_EPILOG24
+ UNSPEC_JMP_PROLOG
+ UNSPEC_XCHG
+ ])
+
+;; -------------------------------------------------------------------------
+;; nop instruction
+;; -------------------------------------------------------------------------
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop")
+
+;; -------------------------------------------------------------------------
+;; Arithmetic instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "KA,r")))
+ ]
+ ""
+ "add.l %0,%1,%2")
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "KA,r")))]
+ ""
+ "sub.l %0,%1,%2")
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (mult:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "KA,r")))]
+ ""
+ "mul.l %0,%1,%2")
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (zero_extend:DI (match_operand:SI 2 "ft32_rimm_operand" "r,KA"))))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "mul.l $cc,%1,%2\;muluh.l %h0,%1,%2\;move.l %0,$cc")
+
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (div:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+ "div.l %0,%1,%2")
+
+(define_insn "modsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (mod:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+ "mod.l %0,%1,%2")
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (udiv:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+ "udiv.l %0,%1,%2")
+
+(define_insn "umodsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (umod:SI
+ (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "register_operand" "r,KA")))]
+ ""
+ "umod.l %0,%1,%2")
+
+(define_insn "extvsi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "ft32_bwidth_operand" "b")
+ (match_operand:SI 3 "const_int_operand" "i")))]
+ ""
+ "bexts.l %0,%1,((15 & %2) << 5) | (%3)")
+
+(define_insn "extzvsi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "ft32_bwidth_operand" "b")
+ (match_operand:SI 3 "const_int_operand" "i")))]
+ ""
+ "bextu.l %0,%1,((15 & %2) << 5) | (%3)")
+
+(define_insn "insvsi"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r,r")
+ (match_operand:SI 1 "ft32_bwidth_operand" "b,b")
+ (match_operand:SI 2 "const_int_operand" "i,i"))
+ (match_operand:SI 3 "general_operand" "r,O"))
+ (clobber (match_scratch:SI 4 "=&r,r"))]
+ ""
+ {
+ if (which_alternative == 0)
+ {
+ return \"ldl.l %4,%3,((%1&15)<<5)|(%2)\;bins.l %0,%0,%4\";
+ }
+ else
+ {
+ if ((INTVAL(operands[3]) == 0) || (INTVAL(operands[1]) == 1))
+ return \"bins.l %0,%0,(%3<<9)|((%1&15)<<5)|(%2)\";
+ else
+ return \"ldk.l %4,(%3<<10)|((%1&15)<<5)|(%2)\;bins.l %0,%0,%4\";
+ }
+ })
+
+;; -------------------------------------------------------------------------
+;; Unary arithmetic instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "xor.l %0,%1,-1")
+
+;; -------------------------------------------------------------------------
+;; Logical operators
+;; -------------------------------------------------------------------------
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "r,r,r")
+ (match_operand:SI 2 "general_operand" "r,x,KA")))]
+ ""
+ "@
+ and.l %0,%1,%2
+ bins.l %0,%1,%g2
+ and.l %0,%1,%2")
+
+(define_insn "andqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r,r,r")
+ (and:QI (match_operand:QI 1 "register_operand" "r,r,r")
+ (match_operand:QI 2 "general_operand" "r,x,KA")))]
+ ""
+ "@
+ and.b %0,%1,%2
+ bins.b %0,%1,%g2
+ and.b %0,%1,%2")
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+{
+ return "xor.l %0,%1,%2";
+})
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "r,r,r")
+ (match_operand:SI 2 "general_operand" "r,w,KA")))]
+ ""
+ "@
+ or.l %0,%1,%2
+ bins.l %0,%1,%f2
+ or.l %0,%1,%2")
+
+;; -------------------------------------------------------------------------
+;; Shifters
+;; -------------------------------------------------------------------------
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+{
+ return "ashl.l %0,%1,%2";
+})
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+{
+ return "ashr.l %0,%1,%2";
+})
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "ft32_rimm_operand" "r,KA")))]
+ ""
+{
+ return "lshr.l %0,%1,%2";
+})
+
+;; -------------------------------------------------------------------------
+;; Move instructions
+;; -------------------------------------------------------------------------
+
+;; SImode
+
+;; Push a register onto the stack
+(define_insn "movsi_push"
+ [(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
+ (match_operand:SI 0 "register_operand" "r"))]
+ ""
+ "push.l %0")
+
+;; Pop a register from the stack
+(define_insn "movsi_pop"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mem:SI (post_inc:SI (reg:SI SP_REG))))]
+ ""
+ "pop.l %0")
+
+(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)));
+ }
+ /*
+ if (MEM_P (operands[0])) {
+ rtx o = XEXP (operands[0], 0);
+ if (!REG_P(o) &&
+ !CONST_INT_P(o) &&
+ GET_CODE(o) != SYMBOL_REF &&
+ GET_CODE(o) != LABEL_REF) {
+ operands[0] = gen_rtx_MEM (SImode, force_reg (SImode, XEXP (operands[0], 0)));
+ }
+ }
+ */
+ }
+})
+
+(define_insn "*rtestsi"
+ [(set (reg:SI CC_REG)
+ (match_operand:SI 0 "register_operand" "r"))]
+ ""
+ "cmp.l %0,0"
+)
+
+(define_insn "*rtestqi"
+ [(set (reg:QI CC_REG)
+ (match_operand:QI 0 "register_operand" "r"))]
+ ""
+ "cmp.b %0,0"
+)
+
+(define_insn "*movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,BW,r,r,r,r,A,r,r")
+ (match_operand:SI 1 "ft32_general_movsrc_operand" "r,r,BW,A,S,i,r,e,f"))]
+ "register_operand (operands[0], SImode) || register_operand (operands[1], SImode)"
+ "@
+ move.l %0,%1
+ sti.l %0,%1
+ ldi.l %0,%1
+ lda.l %0,%1
+ ldk.l %0,%1
+ *return ft32_load_immediate(operands[0], INTVAL(operands[1]));
+ sta.l %0,%1
+ lpm.l %0,%1
+ lpmi.l %0,%1"
+)
+
+(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 (!(reload_in_progress || reload_completed))
+ {
+ if (MEM_P (operands[0]))
+ {
+ operands[1] = force_reg (QImode, operands[1]);
+ if (MEM_P (XEXP (operands[0], 0)))
+ operands[0] = gen_rtx_MEM (QImode, force_reg (SImode, XEXP (operands[0], 0)));
+ }
+ else
+ {
+ if (MEM_P (operands[1]) && MEM_P (XEXP (operands[1], 0)))
+ operands[1] = gen_rtx_MEM (QImode, force_reg (SImode, XEXP (operands[1], 0)));
+ }
+ if (MEM_P (operands[0]) && !REG_P(XEXP (operands[0], 0)))
+ {
+ operands[0] = gen_rtx_MEM (QImode, force_reg (SImode, XEXP (operands[0], 0)));
+ }
+ }
+})
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "BW,r,f")))]
+ ""
+ "@
+ ldi.b %0,%1
+ and.l %0,%1,255
+ lpmi.b %0,%1"
+)
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r")))]
+ ""
+ "bexts.l %0,%1,(8<<5)|0"
+)
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "BW,r,f")))]
+ ""
+ "@
+ ldi.s %0,%1
+ bextu.l %0,%1,(0<<5)|0
+ lpmi.s %0,%1"
+)
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r")))]
+ ""
+ "bexts.l %0,%1,(0<<5)|0"
+)
+
+(define_insn "*movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,BW,r,r,A,r,r,r")
+ (match_operand:QI 1 "ft32_general_movsrc_operand" "r,r,BW,A,r,I,e,f"))]
+ "register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode)"
+ "@
+ move.b %0,%1
+ sti.b %0,%1
+ ldi.b %0,%1
+ lda.b %0,%1
+ sta.b %0,%1
+ ldk.b %0,%1
+ lpm.b %0,%1
+ lpmi.b %0,%1"
+)
+
+(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 (!(reload_in_progress || reload_completed))
+ {
+ if (MEM_P (operands[0]))
+ {
+ operands[1] = force_reg (HImode, operands[1]);
+ if (MEM_P (XEXP (operands[0], 0)))
+ operands[0] = gen_rtx_MEM (HImode, force_reg (SImode, XEXP (operands[0], 0)));
+ }
+ else
+ {
+ if (MEM_P (operands[1]) && MEM_P (XEXP (operands[1], 0)))
+ operands[1] = gen_rtx_MEM (HImode, force_reg (SImode, XEXP (operands[1], 0)));
+ }
+ if (MEM_P (operands[0]))
+ {
+ rtx o = XEXP (operands[0], 0);
+ if (!REG_P(o) &&
+ !CONST_INT_P(o) &&
+ GET_CODE(o) != SYMBOL_REF &&
+ GET_CODE(o) != LABEL_REF) {
+ operands[0] = gen_rtx_MEM (HImode, force_reg (SImode, XEXP (operands[0], 0)));
+ }
+ }
+ }
+})
+
+(define_insn "*movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,BW,r,r,A,r,r,r")
+ (match_operand:HI 1 "ft32_general_movsrc_operand" "r,r,BW,A,r,I,e,f"))]
+ "(register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode))"
+ "@
+ move.s %0,%1
+ sti.s %0,%1
+ ldi.s %0,%1
+ lda.s %0,%1
+ sta.s %0,%1
+ ldk.s %0,%1
+ lpm.s %0,%1
+ lpmi.s %0,%1"
+)
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+{
+ /* If this is a store, force the value into a register. */
+ if (MEM_P (operands[0]))
+ operands[1] = force_reg (SFmode, operands[1]);
+ if (CONST_DOUBLE_P(operands[1]))
+ operands[1] = force_const_mem(SFmode, operands[1]);
+})
+
+(define_insn "*movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,BW,r,r,A,r,r")
+ (match_operand:SF 1 "ft32_general_movsrc_operand" "r,r,BW,A,r,I,f"))]
+ "(register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode))"
+ "@
+ move.l %0,%1
+ sti.l %0,%1
+ ldi.l %0,%1
+ lda.l %0,%1
+ sta.l %0,%1
+ ldk.l %0,%1
+ lpmi.l %0,%1"
+)
+
+;; -------------------------------------------------------------------------
+;; Compare instructions
+;; -------------------------------------------------------------------------
+
+(define_expand "cbranchsi4"
+ [(set (reg:CC CC_REG)
+ (compare:CC
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "ft32_rimm_operand" "")))
+ (set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(reg:CC CC_REG) (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_insn "cmpsi"
+ [(set (reg:CC CC_REG)
+ (compare:CC
+ (match_operand:SI 0 "register_operand" "r,r")
+ (match_operand:SI 1 "ft32_rimm_operand" "r,KA")))]
+ ""
+ "cmp.l %0,%1")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "const_int_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "btst.l %0,(1<<5)|%1\;jmpc nz,%l2")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
+ (eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1)
+ (match_operand:SI 1 "const_int_operand" "i"))
+ (const_int 0))
+ (label_ref (match_operand 2 "" ""))
+ (pc)))
+ (clobber (reg:CC CC_REG))]
+ ""
+ "btst.l %0,(1<<5)|%1\;jmpc z,%l2")
+
+(define_expand "cbranchqi4"
+ [(set (reg:CC CC_REG)
+ (compare:CC
+ (match_operand:QI 1 "register_operand" "")
+ (match_operand:QI 2 "ft32_rimm_operand" "")))
+ (set (pc)
+ (if_then_else (match_operator 0 "comparison_operator"
+ [(reg:CC CC_REG) (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+ "")
+
+(define_insn "*cmpqi"
+ [(set (reg:CC CC_REG)
+ (compare:CC
+ (match_operand:QI 0 "register_operand" "r,r")
+ (match_operand:QI 1 "ft32_rimm_operand" "r,KA")))]
+ ""
+ "cmp.b %0,%1")
+
+;; -------------------------------------------------------------------------
+;; Branch instructions
+;; -------------------------------------------------------------------------
+
+(define_code_iterator cond [ne eq lt ltu gt gtu ge le geu leu])
+(define_code_attr CC [(ne "nz") (eq "z") (lt "lt") (ltu "b")
+ (gt "gt") (gtu "a") (ge "gte") (le "lte")
+ (geu "ae") (leu "be") ])
+(define_code_attr rCC [(ne "z") (eq "nz") (lt "gte") (ltu "ae")
+ (gt "lte") (gtu "be") (ge "lt") (le "gt")
+ (geu "b") (leu "a") ])
+
+(define_insn "*b<cond:code>"
+ [(set (pc)
+ (if_then_else (cond (reg:CC CC_REG)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ return "jmpc <CC>,%l0";
+}
+)
+
+(define_expand "cstoresi4"
+ [(set (reg:CC CC_REG)
+ (compare:CC (match_operand:SI 2 "register_operand" "r,r")
+ (match_operand:SI 3 "ft32_rimm_operand" "r,KA")))
+ (set (match_operand:SI 0 "register_operand")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(reg:CC CC_REG) (const_int 0)]))]
+ ""
+{
+ rtx test;
+
+ switch (GET_CODE (operands[1])) {
+ case NE:
+ case GEU:
+ case LT:
+ case LE:
+ case LEU:
+ test = gen_rtx_fmt_ee (reverse_condition (GET_CODE (operands[1])),
+ SImode, operands[2], operands[3]);
+ emit_insn(gen_cstoresi4(operands[0], test, operands[2], operands[3]));
+ emit_insn(gen_xorsi3(operands[0], operands[0], gen_int_mode(1, SImode)));
+ DONE;
+ default:
+ ;
+ }
+})
+
+(define_insn "*seq"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (reg CC_REG) (const_int 0)))]
+ ""
+ "bextu.l %0,$cc,32|0"
+)
+
+(define_insn "*sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (reg CC_REG) (const_int 0)))]
+ ""
+ "bextu.l %0,$cc,32|1"
+)
+
+(define_insn "*sge"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (reg CC_REG) (const_int 0)))]
+ ""
+ "bextu.l %0,$cc,32|4"
+)
+
+(define_insn "*sgt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (reg CC_REG) (const_int 0)))]
+ ""
+ "bextu.l %0,$cc,32|5"
+)
+
+(define_insn "*sgtu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gtu:SI (reg CC_REG) (const_int 0)))]
+ ""
+ "bextu.l %0,$cc,32|6"
+)
+
+;; -------------------------------------------------------------------------
+;; 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 "" ""))]
+ ""
+ "@
+ call %0
+ calli %0"
+)
+
+(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 "" "")))]
+ ""
+ "call %1"
+)
+
+(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 "" "")))]
+ ""
+ "calli %1"
+)
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "r"))]
+ ""
+ "jmpi %0")
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "jmp %l0"
+)
+
+(define_insn "call_prolog"
+ [(unspec:SI [(match_operand 0 "" "")]
+ UNSPEC_JMP_PROLOG)]
+ ""
+ "call __prolog_%0"
+)
+
+(define_insn "jump_epilog"
+ [(unspec:SI [(match_operand 0 "" "")]
+ UNSPEC_JMP_EPILOG)]
+ ""
+ "jmp __epilog_%0"
+)
+
+(define_insn "jump_epilog24"
+ [(unspec:SI [(match_operand 0 "" "")]
+ UNSPEC_JMP_EPILOG24)]
+ ""
+ "jmp __epilog24_%0"
+)
+
+
+;; Subroutines of "casesi".
+;; operand 0 is index
+;; operand 1 is the minimum bound
+;; operand 2 is the maximum bound - minimum bound + 1
+;; operand 3 is CODE_LABEL for the table;
+;; operand 4 is the CODE_LABEL to go to if index out of range.
+
+(define_expand "casesi"
+ [(match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "const_int_operand" "")
+ (match_operand:SI 2 "const_int_operand" "")
+ (match_operand 3 "" "")
+ (match_operand 4 "" "")]
+ ""
+ "
+{
+ if (GET_CODE (operands[0]) != REG)
+ operands[0] = force_reg (SImode, operands[0]);
+
+ if (operands[1] != const0_rtx)
+ {
+ rtx index = gen_reg_rtx (SImode);
+ rtx offset = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (offset, operands[1]));
+ emit_insn (gen_subsi3 (index, operands[0], offset));
+ operands[0] = index;
+ }
+
+ {
+ rtx test = gen_rtx_GTU (VOIDmode, operands[0], operands[2]);
+ emit_jump_insn (gen_cbranchsi4 (test, operands[0], operands[2], operands[4]));
+ }
+
+ emit_jump_insn (gen_casesi0 (operands[0], operands[3]));
+ DONE;
+}")
+
+(define_insn "casesi0"
+ [(set (pc) (mem:SI (plus:SI
+ (mult:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 4))
+ (label_ref (match_operand 1 "" "")))))
+ (clobber (match_scratch:SI 2 "=&r"))
+ ]
+ ""
+ "ldk.l\t$cc,%l1\;ashl.l\t%2,%0,2\;add.l\t%2,%2,$cc\;jmpi\t%2"
+ )
+
+;; -------------------------------------------------------------------------
+;; Atomic exchange instruction
+;; -------------------------------------------------------------------------
+
+(define_insn "atomic_exchangesi"
+ [(set (match_operand:SI 0 "register_operand" "=&r,r") ;; output
+ (match_operand:SI 1 "memory_operand" "+BW,A")) ;; memory
+ (set (match_dup 1)
+ (unspec:SI
+ [(match_operand:SI 2 "register_operand" "0,0") ;; input
+ (match_operand:SI 3 "const_int_operand")] ;; model
+ UNSPEC_XCHG))]
+ ""
+ "@
+ exi.l %0,%1
+ exa.l %0,%1")
+
+(define_insn "atomic_exchangehi"
+ [(set (match_operand:HI 0 "register_operand" "=&r,r") ;; output
+ (match_operand:HI 1 "memory_operand" "+BW,A")) ;; memory
+ (set (match_dup 1)
+ (unspec:HI
+ [(match_operand:HI 2 "register_operand" "0,0") ;; input
+ (match_operand:HI 3 "const_int_operand")] ;; model
+ UNSPEC_XCHG))]
+ ""
+ "@
+ exi.s %0,%1
+ exa.s %0,%1")
+
+(define_insn "atomic_exchangeqi"
+ [(set (match_operand:QI 0 "register_operand" "=&r,r") ;; output
+ (match_operand:QI 1 "memory_operand" "+BW,A")) ;; memory
+ (set (match_dup 1)
+ (unspec:QI
+ [(match_operand:QI 2 "register_operand" "0,0") ;; input
+ (match_operand:QI 3 "const_int_operand")] ;; model
+ UNSPEC_XCHG))]
+ ""
+ "@
+ exi.b %0,%1
+ exa.b %0,%1")
+
+;; -------------------------------------------------------------------------
+;; String instructions
+;; -------------------------------------------------------------------------
+
+(define_insn "cmpstrsi"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (compare:SI (match_operand:BLK 1 "memory_operand" "W,BW")
+ (match_operand:BLK 2 "memory_operand" "W,BW")))
+ (clobber (match_operand:SI 3))
+ ]
+ ""
+ "strcmp.%d3 %0,%b1,%b2"
+)
+
+(define_insn "movstr"
+[(set (match_operand:BLK 1 "memory_operand" "=W")
+ (match_operand:BLK 2 "memory_operand" "W"))
+ (use (match_operand:SI 0))
+ (clobber (match_dup 0))
+ ]
+"0"
+"stpcpy %b1,%b2 # %0 %b1 %b2"
+)
+
+(define_insn "movmemsi"
+ [(set (match_operand:BLK 0 "memory_operand" "=W,W,BW")
+ (match_operand:BLK 1 "memory_operand" "W,W,BW"))
+ (use (match_operand:SI 2 "ft32_rimm_operand" "r,KA,rKA"))
+ (use (match_operand:SI 3))
+ ]
+ ""
+ "memcpy.%d3 %b0,%b1,%2 # %3!"
+)
+
+(define_insn "setmemsi"
+ [(set (match_operand:BLK 0 "memory_operand" "=BW,BW") (unspec:BLK [
+ (use (match_operand:QI 2 "register_operand" "r,r"))
+ (use (match_operand:SI 1 "ft32_rimm_operand" "r,KA"))
+ ] UNSPEC_SETMEM))
+ (use (match_operand:SI 3))
+ ]
+ ""
+ "memset.%d3 %b0,%2,%1"
+)
+
+(define_insn "strlensi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:BLK 1 "memory_operand" "W")
+ (match_operand:QI 2 "const_int_operand" "")
+ (match_operand:SI 3 "ft32_rimm_operand" "")]
+ UNSPEC_STRLEN))]
+ ""
+ "strlen.%d3 %0,%b1 # %2 %3"
+)
+
+;; -------------------------------------------------------------------------
+;; Prologue & Epilogue
+;; -------------------------------------------------------------------------
+
+(define_expand "prologue"
+ [(clobber (const_int 0))]
+ ""
+{
+ extern void ft32_expand_prologue();
+ ft32_expand_prologue ();
+ DONE;
+})
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+{
+ extern void ft32_expand_epilogue();
+ ft32_expand_epilogue ();
+ DONE;
+})
+
+(define_insn "link"
+ [
+;; (set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
+;; (reg:SI FP_REG))
+ (set (match_operand:SI 0)
+ (reg:SI SP_REG))
+ (set (reg:SI SP_REG)
+ (plus:SI (reg:SI SP_REG)
+ (match_operand:SI 1 "general_operand" "L")))]
+ ""
+ "link %0,%m1"
+)
+
+(define_insn "unlink"
+ [(set (reg:SI FP_REG)
+ (mem:SI (reg:SI FP_REG)))
+ (set (reg:SI SP_REG)
+ (plus:SI (reg:SI FP_REG)
+ (const_int 4)))]
+ ""
+ "unlink $r29"
+)
+
+(define_insn "returner"
+ [(return)]
+ "reload_completed"
+ "return")
+
+(define_insn "returner24"
+ [
+ (set (reg:SI SP_REG)
+ (plus:SI
+ (reg:SI SP_REG)
+ (const_int 24)))
+ (return)]
+ ""
+ "jmp __epilog24")