diff options
Diffstat (limited to 'gcc/config/ft32/ft32.md')
-rw-r--r-- | gcc/config/ft32/ft32.md | 932 |
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") |