997 lines
28 KiB
Markdown
997 lines
28 KiB
Markdown
|
;; Machine description of the Lattice Mico32 architecture for GNU C compiler.
|
||
|
;; Contributed by Jon Beniston <jon@beniston.com>
|
||
|
|
||
|
;; Copyright (C) 2009 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 (SImode, operands[0], gen_rtx_HIGH (SImode, operands[1])));
|
||
|
emit_insn (gen_rtx_SET (SImode, 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 "movmemsi"
|
||
|
[(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")
|
||
|
(match_operand:SI 1 "movsi_rhs_operand" "m,r,r,J,K,L,U,S,Y"))]
|
||
|
"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)"
|
||
|
[(set_attr "type" "load,arith,store,store,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_insn "return"
|
||
|
[(return)]
|
||
|
"lm32_can_use_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]);
|
||
|
rtx one = GEN_INT (1);
|
||
|
|
||
|
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")]
|
||
|
)
|