;; Machine description for FT32
;; Copyright (C) 2015-2020 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")))]
"!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 "*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"))
]
""
{
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")