28 KiB
;; Machine description of the Lattice Mico32 architecture for GNU C compiler. ;; Contributed by Jon Beniston jon@beniston.com
;; Copyright (C) 2009-2021 Free Software Foundation, Inc.
;; 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/.
;; Include predicate and constraint definitions (include "predicates.md") (include "constraints.md")
;; Register numbers (define_constants [(RA_REGNUM 29) ; return address register. ] )
;; LM32 specific volatile operations (define_constants [(UNSPECV_BLOCKAGE 1)] ; prevent scheduling across pro/epilog boundaries )
;; LM32 specific operations
(define_constants
[(UNSPEC_GOT 2)
(UNSPEC_GOTOFF_HI16 3)
(UNSPEC_GOTOFF_LO16 4)]
)
;; --------------------------------- ;; instruction types ;; ---------------------------------
(define_attr "type" "unknown,load,store,arith,compare,shift,multiply,divide,call,icall,ubranch,uibranch,cbranch" (const_string "unknown"))
;; --------------------------------- ;; instruction lengths ;; ---------------------------------
; All instructions are 4 bytes
; Except for branches that are out of range, and have to be implemented
; as two instructions
(define_attr "length" ""
(cond [
(eq_attr "type" "cbranch")
(if_then_else
(lt (abs (minus (match_dup 2) (pc)))
(const_int 32768)
)
(const_int 4)
(const_int 8)
)
]
(const_int 4))
)
;; --------------------------------- ;; scheduling ;; ---------------------------------
(define_automaton "lm32")
(define_cpu_unit "x" "lm32") (define_cpu_unit "m" "lm32") (define_cpu_unit "w" "lm32")
(define_insn_reservation "singlecycle" 1 (eq_attr "type" "store,arith,call,icall,ubranch,uibranch,cbranch") "x")
(define_insn_reservation "twocycle" 2 (eq_attr "type" "compare,shift,divide") "x,m")
(define_insn_reservation "threecycle" 3 (eq_attr "type" "load,multiply") "x,m,w")
;; --------------------------------- ;; mov ;; ---------------------------------
(define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") (match_operand:QI 1 "general_operand" ""))] "" " { if (can_create_pseudo_p ()) { if (GET_CODE (operand0) == MEM) { /* Source operand for store must be in a register. */ operands[1] = force_reg (QImode, operands[1]); } } }")
(define_expand "movhi" [(set (match_operand:HI 0 "general_operand" "") (match_operand:HI 1 "general_operand" ""))] "" " { if (can_create_pseudo_p ()) { if (GET_CODE (operands[0]) == MEM) { /* Source operand for store must be in a register. */ operands[1] = force_reg (HImode, operands[1]); } } }")
(define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] "" " { if (can_create_pseudo_p ()) { if (GET_CODE (operands[0]) == MEM || (GET_CODE (operands[0]) == SUBREG && GET_CODE (SUBREG_REG (operands[0])) == MEM)) { /* Source operand for store must be in a register. */ operands[1] = force_reg (SImode, operands[1]); } }
if (flag_pic && symbolic_operand (operands[1], SImode))
{
if (GET_CODE (operands[1]) == LABEL_REF
|| (GET_CODE (operands[1]) == SYMBOL_REF
&& SYMBOL_REF_LOCAL_P (operands[1])
&& !SYMBOL_REF_WEAK (operands[1])))
{
emit_insn (gen_movsi_gotoff_hi16 (operands[0], operands[1]));
emit_insn (gen_addsi3 (operands[0],
operands[0],
pic_offset_table_rtx));
emit_insn (gen_movsi_gotoff_lo16 (operands[0],
operands[0],
operands[1]));
}
else
emit_insn (gen_movsi_got (operands[0], operands[1]));
crtl->uses_pic_offset_table = 1;
DONE;
}
else if (flag_pic && GET_CODE (operands[1]) == CONST)
{
rtx op = XEXP (operands[1], 0);
if (GET_CODE (op) == PLUS)
{
rtx arg0 = XEXP (op, 0);
rtx arg1 = XEXP (op, 1);
if (GET_CODE (arg0) == LABEL_REF
|| (GET_CODE (arg0) == SYMBOL_REF
&& SYMBOL_REF_LOCAL_P (arg0)
&& !SYMBOL_REF_WEAK (arg0)))
{
emit_insn (gen_movsi_gotoff_hi16 (operands[0], arg0));
emit_insn (gen_addsi3 (operands[0],
operands[0],
pic_offset_table_rtx));
emit_insn (gen_movsi_gotoff_lo16 (operands[0],
operands[0],
arg0));
}
else
emit_insn (gen_movsi_got (operands[0], arg0));
emit_insn (gen_addsi3 (operands[0], operands[0], arg1));
crtl->uses_pic_offset_table = 1;
DONE;
}
}
else if (!flag_pic && reloc_operand (operands[1], GET_MODE (operands[1])))
{
emit_insn (gen_rtx_SET (operands[0], gen_rtx_HIGH (SImode, operands[1])));
emit_insn (gen_rtx_SET (operands[0], gen_rtx_LO_SUM (SImode, operands[0],
operands[1])));
DONE;
}
else if (GET_CODE (operands[1]) == CONST_INT)
{
if (!(satisfies_constraint_K (operands[1])
|| satisfies_constraint_L (operands[1])
|| satisfies_constraint_U (operands[1])))
{
emit_insn (gen_movsi_insn (operands[0],
GEN_INT (INTVAL (operands[1]) & ~0xffff)));
emit_insn (gen_iorsi3 (operands[0],
operands[0],
GEN_INT (INTVAL (operands[1]) & 0xffff)));
DONE;
}
}
}")
(define_expand "cpymemsi" [(parallel [(set (match_operand:BLK 0 "general_operand" "") (match_operand:BLK 1 "general_operand" "")) (use (match_operand:SI 2 "" "")) (use (match_operand:SI 3 "const_int_operand" ""))])] "" { if (!lm32_expand_block_move (operands)) FAIL; DONE; })
;; --------------------------------- ;; load/stores/moves ;; ---------------------------------
(define_insn "movsi_got" [(set (match_operand:SI 0 "register_operand" "=r") (unspec:SI [(match_operand 1 "" "")] UNSPEC_GOT))] "flag_pic" "lw %0, (gp+got(%1))" [(set_attr "type" "load")] )
(define_insn "movsi_gotoff_hi16" [(set (match_operand:SI 0 "register_operand" "=r") (unspec:SI [(match_operand 1 "" "")] UNSPEC_GOTOFF_HI16))] "flag_pic" "orhi %0, r0, gotoffhi16(%1)" [(set_attr "type" "load")] )
(define_insn "movsi_gotoff_lo16"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(plus:SI (match_operand:SI 1 "register_operand" "0")
(match_operand 2 "" ""))] UNSPEC_GOTOFF_LO16))]
"flag_pic"
"addi %0, %1, gotofflo16(%2)"
[(set_attr "type" "arith")]
)
(define_insn "*movsi_lo_sum" [(set (match_operand:SI 0 "register_operand" "=r") (lo_sum:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "reloc_operand" "i")))] "!flag_pic" "ori %0, %0, lo(%2)" [(set_attr "type" "arith")] )
(define_insn "*movqi_insn"
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m,m,r")
(match_operand:QI 1 "general_operand" "m,r,r,J,n"))]
"lm32_move_ok (QImode, operands)"
"@
lbu %0, %1
or %0, %1, r0
sb %0, %1
sb %0, r0
addi %0, r0, %1"
[(set_attr "type" "load,arith,store,store,arith")]
)
(define_insn "*movhi_insn"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,m,r,r")
(match_operand:HI 1 "general_operand" "m,r,r,J,K,L"))]
"lm32_move_ok (HImode, operands)"
"@
lhu %0, %1
or %0, %1, r0
sh %0, %1
sh %0, r0
addi %0, r0, %1
ori %0, r0, %1"
[(set_attr "type" "load,arith,store,store,arith,arith")]
)
(define_insn "movsi_insn"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m,m,r,r,r,r,r,r")
(match_operand:SI 1 "general_operand" "m,r,r,J,K,L,U,S,Y,n"))]
"lm32_move_ok (SImode, operands)"
"@
lw %0, %1
or %0, %1, r0
sw %0, %1
sw %0, r0
addi %0, r0, %1
ori %0, r0, %1
orhi %0, r0, hi(%1)
mva %0, gp(%1)
orhi %0, r0, hi(%1)
ori %0, r0, lo(%1); orhi %0, %0, hi(%1)"
[(set_attr "type" "load,arith,store,store,arith,arith,arith,arith,arith,arith")]
)
;; --------------------------------- ;; sign and zero extension ;; ---------------------------------
(define_insn "*extendqihi2" [(set (match_operand:HI 0 "register_operand" "=r,r") (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))] "TARGET_SIGN_EXTEND_ENABLED || (GET_CODE (operands[1]) != REG)" "@ lb %0, %1 sextb %0, %1" [(set_attr "type" "load,arith")] )
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=r,r")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
""
"@
lbu %0, %1
andi %0, %1, 0xff"
[(set_attr "type" "load,arith")]
)
(define_insn "*extendqisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))] "TARGET_SIGN_EXTEND_ENABLED || (GET_CODE (operands[1]) != REG)" "@ lb %0, %1 sextb %0, %1" [(set_attr "type" "load,arith")] )
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "m,r")))]
""
"@
lbu %0, %1
andi %0, %1, 0xff"
[(set_attr "type" "load,arith")]
)
(define_insn "*extendhisi2" [(set (match_operand:SI 0 "register_operand" "=r,r") (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))] "TARGET_SIGN_EXTEND_ENABLED || (GET_CODE (operands[1]) != REG)" "@ lh %0, %1 sexth %0, %1" [(set_attr "type" "load,arith")] )
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
""
"@
lhu %0, %1
andi %0, %1, 0xffff"
[(set_attr "type" "load,arith")]
)
;; --------------------------------- ;; compare ;; ---------------------------------
(define_expand "cstoresi4" [(set (match_operand:SI 0 "register_operand") (match_operator:SI 1 "ordered_comparison_operator" [(match_operand:SI 2 "register_operand") (match_operand:SI 3 "register_or_int_operand")]))] "" { lm32_expand_scc (operands); DONE; })
(define_insn "*seq" [(set (match_operand:SI 0 "register_operand" "=r,r") (eq:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_K_operand" "r,K")))] "" "@ cmpe %0, %z1, %2 cmpei %0, %z1, %2" [(set_attr "type" "compare")] )
(define_insn "*sne" [(set (match_operand:SI 0 "register_operand" "=r,r") (ne:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_K_operand" "r,K")))] "" "@ cmpne %0, %z1, %2 cmpnei %0, %z1, %2" [(set_attr "type" "compare")] )
(define_insn "*sgt" [(set (match_operand:SI 0 "register_operand" "=r,r") (gt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") (match_operand:SI 2 "register_or_K_operand" "r,K")))] "" "@ cmpg %0, %z1, %2 cmpgi %0, %z1, %2" [(set_attr "type" "compare")] )
(define_insn "*sge" [(set (match_operand:SI 0 "register_operand" "=r,r") (ge:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") (match_operand:SI 2 "register_or_K_operand" "r,K")))] "" "@ cmpge %0, %z1, %2 cmpgei %0, %z1, %2" [(set_attr "type" "compare")] )
(define_insn "*sgtu" [(set (match_operand:SI 0 "register_operand" "=r,r") (gtu:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "" "@ cmpgu %0, %z1, %2 cmpgui %0, %z1, %2" [(set_attr "type" "compare")] )
(define_insn "*sgeu" [(set (match_operand:SI 0 "register_operand" "=r,r") (geu:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "" "@ cmpgeu %0, %z1, %2 cmpgeui %0, %z1, %2" [(set_attr "type" "compare")] )
;; --------------------------------- ;; unconditional branch ;; ---------------------------------
(define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "bi %0" [(set_attr "type" "ubranch")] )
(define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "register_operand" "r"))] "" "b %0" [(set_attr "type" "uibranch")] )
;; --------------------------------- ;; conditional branch ;; ---------------------------------
(define_expand "cbranchsi4"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(match_operand:SI 1 "register_operand")
(match_operand:SI 2 "nonmemory_operand")])
(label_ref (match_operand 3 "" ""))
(pc)))]
""
"
{
lm32_expand_conditional_branch (operands);
DONE;
}")
(define_insn "*beq"
[(set (pc)
(if_then_else (eq:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "register_or_zero_operand" "rJ"))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
{
return get_attr_length (insn) == 4
? "be %z0,%z1,%2"
: "bne %z0,%z1,8\n\tbi %2";
}
[(set_attr "type" "cbranch")])
(define_insn "*bne"
[(set (pc)
(if_then_else (ne:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "register_or_zero_operand" "rJ"))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
{
return get_attr_length (insn) == 4
? "bne %z0,%z1,%2"
: "be %z0,%z1,8\n\tbi %2";
}
[(set_attr "type" "cbranch")])
(define_insn "*bgt"
[(set (pc)
(if_then_else (gt:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "register_or_zero_operand" "rJ"))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
{
return get_attr_length (insn) == 4
? "bg %z0,%z1,%2"
: "bge %z1,%z0,8\n\tbi %2";
}
[(set_attr "type" "cbranch")])
(define_insn "*bge"
[(set (pc)
(if_then_else (ge:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "register_or_zero_operand" "rJ"))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
{
return get_attr_length (insn) == 4
? "bge %z0,%z1,%2"
: "bg %z1,%z0,8\n\tbi %2";
}
[(set_attr "type" "cbranch")])
(define_insn "*bgtu"
[(set (pc)
(if_then_else (gtu:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "register_or_zero_operand" "rJ"))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
{
return get_attr_length (insn) == 4
? "bgu %z0,%z1,%2"
: "bgeu %z1,%z0,8\n\tbi %2";
}
[(set_attr "type" "cbranch")])
(define_insn "*bgeu"
[(set (pc)
(if_then_else (geu:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "register_or_zero_operand" "rJ"))
(label_ref (match_operand 2 "" ""))
(pc)))]
""
{
return get_attr_length (insn) == 4
? "bgeu %z0,%z1,%2"
: "bgu %z1,%z0,8\n\tbi %2";
}
[(set_attr "type" "cbranch")])
;; --------------------------------- ;; call ;; ---------------------------------
(define_expand "call" [(parallel [(call (match_operand 0 "" "") (match_operand 1 "" "")) (clobber (reg:SI RA_REGNUM)) ])] "" " { rtx addr = XEXP (operands[0], 0); if (!CONSTANT_ADDRESS_P (addr)) XEXP (operands[0], 0) = force_reg (Pmode, addr); }")
(define_insn "*call"
[(call (mem:SI (match_operand:SI 0 "call_operand" "r,s"))
(match_operand 1 "" ""))
(clobber (reg:SI RA_REGNUM))]
""
"@
call %0
calli %0"
[(set_attr "type" "call,icall")]
)
(define_expand "call_value" [(parallel [(set (match_operand 0 "" "") (call (match_operand 1 "" "") (match_operand 2 "" ""))) (clobber (reg:SI RA_REGNUM)) ])] "" " { rtx addr = XEXP (operands[1], 0); if (!CONSTANT_ADDRESS_P (addr)) XEXP (operands[1], 0) = force_reg (Pmode, addr); }")
(define_insn "*call_value"
[(set (match_operand 0 "register_operand" "=r,r")
(call (mem:SI (match_operand:SI 1 "call_operand" "r,s"))
(match_operand 2 "" "")))
(clobber (reg:SI RA_REGNUM))]
""
"@
call %1
calli %1"
[(set_attr "type" "call,icall")]
)
(define_insn "return_internal"
[(use (match_operand:SI 0 "register_operand" "r"))
(return)]
""
"b %0"
[(set_attr "type" "uibranch")]
)
(define_expand "return" [(return)] "lm32_can_use_return ()" "" )
(define_expand "simple_return" [(simple_return)] "" "" )
(define_insn "*return"
[(return)]
"reload_completed"
"ret"
[(set_attr "type" "uibranch")]
)
(define_insn "*simple_return"
[(simple_return)]
""
"ret"
[(set_attr "type" "uibranch")]
)
;; --------------------------------- ;; switch/case statements ;; ---------------------------------
(define_expand "tablejump" [(set (pc) (match_operand 0 "register_operand" "")) (use (label_ref (match_operand 1 "" "")))] "" " { rtx target = operands[0]; if (flag_pic) { /* For PIC, the table entry is relative to the start of the table. */ rtx label = gen_reg_rtx (SImode); target = gen_reg_rtx (SImode); emit_move_insn (label, gen_rtx_LABEL_REF (SImode, operands[1])); emit_insn (gen_addsi3 (target, operands[0], label)); } emit_jump_insn (gen_tablejumpsi (target, operands[1])); DONE; }")
(define_insn "tablejumpsi"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
""
"b %0"
[(set_attr "type" "ubranch")]
)
;; --------------------------------- ;; arithmetic ;; ---------------------------------
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(plus:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ")
(match_operand:SI 2 "register_or_K_operand" "r,K")))]
""
"@
add %0, %z1, %2
addi %0, %z1, %2"
[(set_attr "type" "arith")]
)
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
(match_operand:SI 2 "register_or_zero_operand" "rJ")))]
""
"sub %0, %z1, %z2"
[(set_attr "type" "arith")]
)
(define_insn "mulsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (mult:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_K_operand" "r,K")))] "TARGET_MULTIPLY_ENABLED" "@ mul %0, %z1, %2 muli %0, %z1, %2" [(set_attr "type" "multiply")] )
(define_insn "udivsi3" [(set (match_operand:SI 0 "register_operand" "=r") (udiv:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") (match_operand:SI 2 "register_operand" "r")))] "TARGET_DIVIDE_ENABLED" "divu %0, %z1, %2" [(set_attr "type" "divide")] )
(define_insn "umodsi3" [(set (match_operand:SI 0 "register_operand" "=r") (umod:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") (match_operand:SI 2 "register_operand" "r")))] "TARGET_DIVIDE_ENABLED" "modu %0, %z1, %2" [(set_attr "type" "divide")] )
;; --------------------------------- ;; negation and inversion ;; ---------------------------------
(define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")))] "" "sub %0, r0, %z1" [(set_attr "type" "arith")] )
(define_insn "one_cmplsi2" [(set (match_operand:SI 0 "register_operand" "=r") (not:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")))] "" "not %0, %z1" [(set_attr "type" "arith")] )
;; --------------------------------- ;; logical ;; ---------------------------------
(define_insn "andsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (and:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "" "@ and %0, %z1, %2 andi %0, %z1, %2" [(set_attr "type" "arith")] )
(define_insn "iorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (ior:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "" "@ or %0, %z1, %2 ori %0, %z1, %2" [(set_attr "type" "arith")] )
(define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (xor:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "" "@ xor %0, %z1, %2 xori %0, %z1, %2" [(set_attr "type" "arith")] )
(define_insn "*norsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (not:SI (ior:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L"))))] "" "@ nor %0, %z1, %2 nori %0, %z1, %2" [(set_attr "type" "arith")] )
(define_insn "*xnorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (not:SI (xor:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L"))))] "" "@ xnor %0, %z1, %2 xnori %0, %z1, %2" [(set_attr "type" "arith")] )
;; --------------------------------- ;; shifts ;; ---------------------------------
(define_expand "ashlsi3" [(set (match_operand:SI 0 "register_operand" "") (ashift:SI (match_operand:SI 1 "register_or_zero_operand" "") (match_operand:SI 2 "register_or_L_operand" "")))] "" { if (!TARGET_BARREL_SHIFT_ENABLED) { if (!optimize_size && satisfies_constraint_L (operands[2]) && INTVAL (operands[2]) <= 8) { int i; int shifts = INTVAL (operands[2]);
if (shifts == 0)
emit_move_insn (operands[0], operands[1]);
else
emit_insn (gen_addsi3 (operands[0], operands[1], operands[1]));
for (i = 1; i < shifts; i++)
emit_insn (gen_addsi3 (operands[0], operands[0], operands[0]));
DONE;
}
else
FAIL;
}
})
(define_insn "*ashlsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (ashift:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "TARGET_BARREL_SHIFT_ENABLED" "@ sl %0, %z1, %2 sli %0, %z1, %2" [(set_attr "type" "shift")] )
(define_expand "ashrsi3" [(set (match_operand:SI 0 "register_operand" "") (ashiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "") (match_operand:SI 2 "register_or_L_operand" "")))] "" { if (!TARGET_BARREL_SHIFT_ENABLED) { if (!optimize_size && satisfies_constraint_L (operands[2]) && INTVAL (operands[2]) <= 8) { int i; int shifts = INTVAL (operands[2]); rtx one = GEN_INT (1);
if (shifts == 0)
emit_move_insn (operands[0], operands[1]);
else
emit_insn (gen_ashrsi3_1bit (operands[0], operands[1], one));
for (i = 1; i < shifts; i++)
emit_insn (gen_ashrsi3_1bit (operands[0], operands[0], one));
DONE;
}
else
FAIL;
}
})
(define_insn "*ashrsi3" [(set (match_operand:SI 0 "register_operand" "=r,r") (ashiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") (match_operand:SI 2 "register_or_L_operand" "r,L")))] "TARGET_BARREL_SHIFT_ENABLED" "@ sr %0, %z1, %2 sri %0, %z1, %2" [(set_attr "type" "shift")] )
(define_insn "ashrsi3_1bit" [(set (match_operand:SI 0 "register_operand" "=r") (ashiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") (match_operand:SI 2 "constant_M_operand" "M")))] "!TARGET_BARREL_SHIFT_ENABLED" "sri %0, %z1, %2" [(set_attr "type" "shift")] )
(define_expand "lshrsi3" [(set (match_operand:SI 0 "register_operand" "") (lshiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "") (match_operand:SI 2 "register_or_L_operand" "")))] "" { if (!TARGET_BARREL_SHIFT_ENABLED) { if (!optimize_size && satisfies_constraint_L (operands[2]) && INTVAL (operands[2]) <= 8) { int i; int shifts = INTVAL (operands[2]); rtx one = GEN_INT (1);
if (shifts == 0)
emit_move_insn (operands[0], operands[1]);
else
emit_insn (gen_lshrsi3_1bit (operands[0], operands[1], one));
for (i = 1; i < shifts; i++)
emit_insn (gen_lshrsi3_1bit (operands[0], operands[0], one));
DONE;
}
else
FAIL;
}
})
(define_insn "*lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(lshiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ")
(match_operand:SI 2 "register_or_L_operand" "r,L")))]
"TARGET_BARREL_SHIFT_ENABLED"
"@
sru %0, %z1, %2
srui %0, %z1, %2"
[(set_attr "type" "shift")]
)
(define_insn "lshrsi3_1bit"
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
(match_operand:SI 2 "constant_M_operand" "M")))]
"!TARGET_BARREL_SHIFT_ENABLED"
"srui %0, %z1, %2"
[(set_attr "type" "shift")]
)
;; --------------------------------- ;; function entry / exit ;; ---------------------------------
(define_expand "prologue" [(const_int 1)] "" " { lm32_expand_prologue (); DONE; }")
(define_expand "epilogue" [(return)] "" " { lm32_expand_epilogue (); DONE; }")
;; --------------------------------- ;; nop ;; ---------------------------------
(define_insn "nop"
[(const_int 0)]
""
"nop"
[(set_attr "type" "arith")]
)
;; --------------------------------- ;; blockage ;; ---------------------------------
;; used to stop the scheduler from ;; scheduling code across certain boundaries
(define_insn "blockage" [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)] "" "" [(set_attr "length" "0")] )