;; Machine description for FT32 ;; Copyright (C) 2015-2021 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”) (mult:DI (zero_extend:DI (match_operand:SI 1 “register_operand” “r”)) (zero_extend:DI (match_operand:SI 2 “register_operand” “r”)))) (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”)))] “!TARGET_NODIV” “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”)))] “!TARGET_NODIV” “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”)))] “!TARGET_NODIV” “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”)))] “!TARGET_NODIV” “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

(define_insn “*sne” [(set (match_operand:SI 0 “register_operand” “=r”) (reg:SI CC_REG))] "" “bextu.l %0,$cc,32|0;xor.l %0,%0,-1” )

;; 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 “*bcond:code” [(set (pc) (if_then_else (cond (reg:CC CC_REG) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" { return “jmpc ,%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”)) ] "" { if (TARGET_NOPM) return "ldk.l\t$cc,%l1;ashl.l\t%2,%0,2;add.l\t%2,%2,$cc;ldi.l\t%2,%2,0;jmpi\t%2"; else return "ldk.l\t$cc,%l1;ashl.l\t%2,%0,2;add.l\t%2,%2,$cc;lpmi.l\t%2,%2,0;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 “cpymemsi” [(set (match_operand:BLK 0 “memory_operand” “=W,BW”) (match_operand:BLK 1 “memory_operand” “W,BW”)) (use (match_operand:SI 2 “ft32_imm_operand” “KA,KA”)) (use (match_operand:SI 3)) ] "" "memcpy.%d3 %b0,%b1,%2 " )

(define_insn “setmemsi” [(set (match_operand:BLK 0 “memory_operand” “=BW”) (unspec:BLK [ (use (match_operand:QI 2 “register_operand” “r”)) (use (match_operand:SI 1 “ft32_imm_operand” “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 “pretend_returner” [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand:SI 0))) (return)] “reload_completed” “pop.l $cc;add.l $sp,$sp,%0;jmpi $cc”)

(define_insn “returner24” [ (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int 24))) (return)] "" “jmp __epilog24”)