home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
gcc-2.7.2.1-base.tgz
/
gcc-2.7.2.1-base.tar
/
fsf
/
gcc
/
config
/
sh
/
sh.md
< prev
next >
Wrap
Text File
|
1995-11-05
|
59KB
|
1,944 lines
;;- Machine description for the Hitachi SH.
;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
;; Contributed by Steve Chamberlain (sac@cygnus.com).
;; Improved by Jim Wilson (wilson@cygnus.com).
;; This file is part of GNU CC.
;; GNU CC 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 2, or (at your option)
;; any later version.
;; GNU CC 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 GNU CC; see the file COPYING. If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;; ??? Should prepend a * to all pattern names which are not used.
;; This will make the compiler smaller, and rebuilds after changes faster.
;; ??? Should be enhanced to include support for many more GNU superoptimizer
;; sequences. Especially the sequences for arithmetic right shifts.
;; ??? Should check all DImode patterns for consistency and usefulness.
;; ??? Should add support for using BSR for short function calls.
;; ??? The MAC.W and MAC.L instructions are not supported. There is no
;; way to generate them.
;; ??? The BSR instruction is not supported. It might be possible to
;; generate it by keeping track of function sizes (and hence relative
;; addresses), and then using it only if the target is earlier in the same
;; file, and is within range. Better would be assembler/linker relaxing,
;; but that is much harder.
;; ??? The cmp/str instruction is not supported. Perhaps it can be used
;; for a str* inline function.
;; Special constraints for SH machine description:
;;
;; t -- T
;; x -- mac
;; l -- pr
;; z -- r0
;;
;; Special formats used for outputting SH instructions:
;;
;; %. -- print a .s if insn needs delay slot
;; %@ -- print rte/rts if is/isn't an interrupt function
;; %# -- output a nop if there is nothing to put in the delay slot
;; %O -- print a constant without the #
;; %R -- print the lsw reg of a double
;; %S -- print the msw reg of a double
;; %T -- print next word of a double REG or MEM
;;
;; Special predicates:
;;
;; arith_operand -- operand is valid source for arithmetic op
;; arith_reg_operand -- operand is valid register for arithmetic op
;; general_movdst_operand -- operand is valid move destination
;; general_movsrc_operand -- operand is valid move source
;; logical_operand -- operand is valid source for logical op
;; -------------------------------------------------------------------------
;; Attributes
;; -------------------------------------------------------------------------
; Target CPU.
(define_attr "cpu" "sh0,sh1,sh2,sh3"
(const (symbol_ref "sh_cpu_attr")))
;;
;; cbranch conditional branch instructions
;; jump unconditional jumps
;; arith ordinary arithmetic
;; load from memory
;; store to memory
;; move register to register
;; smpy word precision integer multiply
;; dmpy longword or doublelongword precision integer multiply
;; return rts
;; pload load of pr reg, which can't be put into delay slot of rts
;; pstore store of pr reg, which can't be put into delay slot of jsr
;; pcload pc relative load of constant value
;; rte return from exception
;; sfunc special function call with known used registers
;; call function call
(define_attr "type"
"cbranch,jump,arith,other,load,store,move,smpy,dmpy,return,pload,pstore,pcload,rte,sfunc,call"
(const_string "other"))
; If a conditional branch destination is within -252..258 bytes away
; from the instruction it can be 2 bytes long. Something in the
; range -4090..4100 bytes can be 6 bytes long. All other conditional
; branches are 16 bytes long.
; An unconditional jump in the range -4092..4098 can be 2 bytes long.
; Otherwise, it must be 14 bytes long.
; All other instructions are two bytes long by default.
; All positive offsets have an adjustment added, which is the number of bytes
; difference between this instruction length and the next larger instruction
; length. This is because shorten_branches starts with the largest
; instruction size and then tries to reduce them.
(define_attr "length" ""
(cond [(eq_attr "type" "cbranch")
(if_then_else (and (ge (minus (match_dup 0) (pc))
(const_int -252))
(le (minus (match_dup 0) (pc))
(const_int 262)))
(const_int 2)
(if_then_else (and (ge (minus (match_dup 0) (pc))
(const_int -4090))
(le (minus (match_dup 0) (pc))
(const_int 4110)))
(const_int 6)
(const_int 16)))
(eq_attr "type" "jump")
(if_then_else (and (ge (minus (match_dup 0) (pc))
(const_int -4092))
(le (minus (match_dup 0) (pc))
(const_int 4110)))
(const_int 2)
(const_int 14))
] (const_int 2)))
;; (define_function_unit {name} {num-units} {n-users} {test}
;; {ready-delay} {issue-delay} [{conflict-list}])
;; ??? These are probably not correct.
(define_function_unit "memory" 1 0 (eq_attr "type" "load,pcload,pload") 2 2)
(define_function_unit "mpy" 1 0 (eq_attr "type" "smpy") 2 2)
(define_function_unit "mpy" 1 0 (eq_attr "type" "dmpy") 3 3)
; Definitions for filling branch delay slots.
(define_attr "needs_delay_slot" "yes,no" (const_string "no"))
(define_attr "hit_stack" "yes,no" (const_string "no"))
(define_attr "interrupt_function" "no,yes"
(const (symbol_ref "pragma_interrupt")))
(define_attr "in_delay_slot" "yes,no"
(cond [(eq_attr "type" "cbranch") (const_string "no")
(eq_attr "type" "pcload") (const_string "no")
(eq_attr "needs_delay_slot" "yes") (const_string "no")
(eq_attr "length" "2") (const_string "yes")
] (const_string "no")))
(define_delay
(eq_attr "needs_delay_slot" "yes")
[(eq_attr "in_delay_slot" "yes") (nil) (nil)])
;; On the SH and SH2, the rte instruction reads the return pc from the stack,
;; and thus we can't put a pop instruction in its delay slot.
;; ??? On the SH3, the rte instruction does not use the stack, so a pop
;; instruction can go in the delay slot.
;; Since a normal return (rts) implicitly uses the PR register,
;; we can't allow PR register loads in an rts delay slot.
(define_delay
(eq_attr "type" "return")
[(and (eq_attr "in_delay_slot" "yes")
(ior (and (eq_attr "interrupt_function" "no")
(eq_attr "type" "!pload"))
(and (eq_attr "interrupt_function" "yes")
(eq_attr "hit_stack" "no")))) (nil) (nil)])
;; Since a call implicitly uses the PR register, we can't allow
;; a PR register store in a jsr delay slot.
(define_delay
(ior (eq_attr "type" "call") (eq_attr "type" "sfunc"))
[(and (eq_attr "in_delay_slot" "yes")
(eq_attr "type" "!pstore")) (nil) (nil)])
;; Say that we have annulled true branches, since this gives smaller and
;; faster code when branches are predicted as not taken.
;; ??? Branches which are out-of-range actually have two delay slots,
;; the first is either always executed or else annulled false, and the
;; second is always annulled false. Handling these differently from
;; in range branches would give better code.
(define_delay
(and (eq_attr "type" "cbranch")
(eq_attr "cpu" "sh2,sh3"))
[(eq_attr "in_delay_slot" "yes") (eq_attr "in_delay_slot" "yes") (nil)])
;; -------------------------------------------------------------------------
;; SImode signed integer comparisons
;; -------------------------------------------------------------------------
(define_insn ""
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(eq:SI (reg:SI 18)
(const_int 1)))]
""
"movt %0")
;; ??? This combiner pattern does not work, because combine does not combine
;; instructions that set a hard register when SMALL_REGISTER_CLASSES is
;; defined. Perhaps use a pseudo-reg for the T bit?
(define_insn ""
[(set (reg:SI 18)
(eq:SI (and:SI (match_operand:SI 0 "arith_reg_operand" "z,r")
(match_operand:SI 1 "arith_operand" "L,r"))
(const_int 0)))]
""
"tst %1,%0")
;; ??? Perhaps should only accept reg/constant if the register is reg 0.
;; That would still allow reload to create cmpi instructions, but would
;; perhaps allow forcing the constant into a register when that is better.
;; Probably should use r0 for mem/imm compares, but force constant into a
;; register for pseudo/imm compares.
(define_insn "cmpeqsi_t"
[(set (reg:SI 18) (eq:SI (match_operand:SI 0 "arith_reg_operand" "r,z,r")
(match_operand:SI 1 "arith_operand" "N,rI,r")))]
""
"@
tst %0,%0
cmp/eq %1,%0
cmp/eq %1,%0")
(define_insn "cmpgtsi_t"
[(set (reg:SI 18) (gt:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
(match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
""
"@
cmp/gt %1,%0
cmp/pl %0")
(define_insn "cmpgesi_t"
[(set (reg:SI 18) (ge:SI (match_operand:SI 0 "arith_reg_operand" "r,r")
(match_operand:SI 1 "arith_reg_or_0_operand" "r,N")))]
""
"@
cmp/ge %1,%0
cmp/pz %0")
;; -------------------------------------------------------------------------
;; SImode unsigned integer comparisons
;; -------------------------------------------------------------------------
(define_insn "cmpgeusi_t"
[(set (reg:SI 18) (geu:SI (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
""
"cmp/hs %1,%0")
(define_insn "cmpgtusi_t"
[(set (reg:SI 18) (gtu:SI (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
""
"cmp/hi %1,%0")
;; We save the compare operands in the cmpxx patterns and use them when
;; we generate the branch.
(define_expand "cmpsi"
[(set (reg:SI 18) (compare (match_operand:SI 0 "arith_operand" "")
(match_operand:SI 1 "arith_operand" "")))]
""
"
{
sh_compare_op0 = operands[0];
sh_compare_op1 = operands[1];
DONE;
}")
;; -------------------------------------------------------------------------
;; Addition instructions
;; -------------------------------------------------------------------------
;; ??? This should be a define expand.
(define_insn "adddi3"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
(plus:DI (match_operand:DI 1 "arith_reg_operand" "%0")
(match_operand:DI 2 "arith_reg_operand" "r")))
(clobber (reg:SI 18))]
""
"clrt\;addc %R2,%R0\;addc %S2,%S0"
[(set_attr "length" "6")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(plus:SI (match_operand:SI 1 "arith_operand" "%0")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"add %2,%0"
[(set_attr "type" "arith")])
;; -------------------------------------------------------------------------
;; Subtraction instructions
;; -------------------------------------------------------------------------
;; ??? This should be a define expand.
(define_insn "subdi3"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
(minus:DI (match_operand:DI 1 "arith_reg_operand" "0")
(match_operand:DI 2 "arith_reg_operand" "r")))
(clobber (reg:SI 18))]
""
"clrt\;subc %R2,%R0\;subc %S2,%S0"
[(set_attr "length" "6")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(minus:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "arith_reg_operand" "r")))]
""
"sub %2,%0"
[(set_attr "type" "arith")])
;; -------------------------------------------------------------------------
;; Division instructions
;; -------------------------------------------------------------------------
;; We take advantage of the library routines which don't clobber as many
;; registers as a normal function call would.
;; We must use a pseudo-reg forced to reg 0 in the SET_DEST rather than
;; hard register 0. If we used hard register 0, then the next instruction
;; would be a move from hard register 0 to a pseudo-reg. If the pseudo-reg
;; gets allocated to a stack slot that needs its address reloaded, then
;; there is nothing to prevent reload from using r0 to reload the address.
;; This reload would clobber the value in r0 we are trying to store.
;; If we let reload allocate r0, then this problem can never happen.
(define_insn ""
[(set (match_operand:SI 1 "register_operand" "=z")
(udiv:SI (reg:SI 4) (reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(use (match_operand:SI 0 "arith_reg_operand" "r"))]
""
"jsr @%0%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
(define_expand "udivsi3"
[(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
(set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
(set (match_dup 3) (symbol_ref:SI "__udivsi3"))
(parallel [(set (match_operand:SI 0 "register_operand" "")
(udiv:SI (reg:SI 4)
(reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(use (match_dup 3))])]
""
"operands[3] = gen_reg_rtx(SImode);")
(define_insn ""
[(set (match_operand:SI 1 "register_operand" "=z")
(div:SI (reg:SI 4) (reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 1))
(clobber (reg:SI 2))
(clobber (reg:SI 3))
(use (match_operand:SI 0 "arith_reg_operand" "r"))]
""
"jsr @%0%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
(define_expand "divsi3"
[(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
(set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
(set (match_dup 3) (symbol_ref:SI "__sdivsi3"))
(parallel [(set (match_operand:SI 0 "register_operand" "")
(div:SI (reg:SI 4)
(reg:SI 5)))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 1))
(clobber (reg:SI 2))
(clobber (reg:SI 3))
(use (match_dup 3))])]
""
"operands[3] = gen_reg_rtx(SImode);")
;; -------------------------------------------------------------------------
;; Multiplication instructions
;; -------------------------------------------------------------------------
(define_insn ""
[(set (reg:SI 21)
(mult:SI (zero_extend:SI (match_operand:HI 1 "arith_reg_operand" "r"))
(zero_extend:SI (match_operand:HI 2 "arith_reg_operand" "r"))))]
""
"mulu %2,%1"
[(set_attr "type" "smpy")])
(define_insn ""
[(set (reg:SI 21)
(mult:SI (sign_extend:SI
(match_operand:HI 1 "arith_reg_operand" "r"))
(sign_extend:SI
(match_operand:HI 2 "arith_reg_operand" "r"))))]
""
"muls %2,%1"
[(set_attr "type" "smpy")])
(define_expand "mulhisi3"
[(set (reg:SI 21)
(mult:SI (sign_extend:SI
(match_operand:HI 1 "arith_reg_operand" ""))
(sign_extend:SI
(match_operand:HI 2 "arith_reg_operand" ""))))
(set (match_operand:SI 0 "arith_reg_operand" "")
(reg:SI 21))]
""
"")
(define_expand "umulhisi3"
[(set (reg:SI 21)
(mult:SI (zero_extend:SI
(match_operand:HI 1 "arith_reg_operand" ""))
(zero_extend:SI
(match_operand:HI 2 "arith_reg_operand" ""))))
(set (match_operand:SI 0 "arith_reg_operand" "")
(reg:SI 21))]
""
"")
;; mulsi3 on the SH2 can be done in one instruction, on the SH1 we generate
;; a call to a routine which clobbers known registers.
(define_insn ""
[(set (match_operand:SI 1 "register_operand" "=z")
(mult:SI (reg:SI 4) (reg:SI 5)))
(clobber (reg:SI 21))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 3))
(clobber (reg:SI 2))
(clobber (reg:SI 1))
(use (match_operand:SI 0 "arith_reg_operand" "r"))]
""
"jsr @%0%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
(define_expand "mulsi3_call"
[(set (reg:SI 4) (match_operand:SI 1 "general_operand" ""))
(set (reg:SI 5) (match_operand:SI 2 "general_operand" ""))
(set (match_dup 3) (symbol_ref:SI "__mulsi3"))
(parallel[(set (match_operand:SI 0 "register_operand" "")
(mult:SI (reg:SI 4)
(reg:SI 5)))
(clobber (reg:SI 21))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(clobber (reg:SI 3))
(clobber (reg:SI 2))
(clobber (reg:SI 1))
(use (match_dup 3))])]
""
"operands[3] = gen_reg_rtx(SImode);")
(define_insn "mul_l"
[(set (reg:SI 21)
(mult:SI (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH2"
"mul.l %1,%0"
[(set_attr "type" "dmpy")])
(define_expand "mulsi3"
[(set (reg:SI 21)
(mult:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "arith_reg_operand" "")))
(set (match_operand:SI 0 "arith_reg_operand" "")
(reg:SI 21))]
""
"
{
if (!TARGET_SH2)
{
FAIL;
/* ??? Does this give worse or better code? */
emit_insn (gen_mulsi3_call (operands[0], operands[1], operands[2]));
DONE;
}
}")
(define_insn ""
[(set (reg:DI 20)
(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH2"
"dmuls.l %2,%1"
[(set_attr "type" "dmpy")])
(define_expand "mulsidi3"
[(set (reg:DI 20)
(mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" ""))))
(set (match_operand:DI 0 "arith_reg_operand" "")
(reg:DI 20))]
"TARGET_SH2"
"")
(define_insn ""
[(set (reg:DI 20)
(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH2"
"dmulu.l %2,%1"
[(set_attr "type" "dmpy")])
(define_expand "umulsidi3"
[(set (reg:DI 20)
(mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" ""))))
(set (match_operand:DI 0 "arith_reg_operand" "")
(reg:DI 20))]
"TARGET_SH2"
"")
(define_insn ""
[(set (reg:SI 20)
(truncate:SI
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "r")))
(const_int 32))))
(clobber (reg:SI 21))]
"TARGET_SH2"
"dmuls.l %2,%1"
[(set_attr "type" "dmpy")])
(define_expand "smulsi3_highpart"
[(parallel [(set (reg:SI 20)
(truncate:SI
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
(sign_extend:DI (match_operand:SI 2 "arith_reg_operand" "")))
(const_int 32))))
(clobber (reg:SI 21))])
(set (match_operand:SI 0 "arith_reg_operand" "")
(reg:SI 20))]
"TARGET_SH2"
"")
(define_insn ""
[(set (reg:SI 20)
(truncate:SI
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" "r"))
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "r")))
(const_int 32))))
(clobber (reg:SI 21))]
"TARGET_SH2"
"dmulu.l %2,%1"
[(set_attr "type" "dmpy")])
(define_expand "umulsi3_highpart"
[(parallel [(set (reg:SI 20)
(truncate:SI
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "arith_reg_operand" ""))
(zero_extend:DI (match_operand:SI 2 "arith_reg_operand" "")))
(const_int 32))))
(clobber (reg:SI 21))])
(set (match_operand:SI 0 "arith_reg_operand" "")
(reg:SI 20))]
"TARGET_SH2"
"")
;; -------------------------------------------------------------------------
;; Logical operations
;; -------------------------------------------------------------------------
(define_insn ""
[(set (match_operand:SI 0 "arith_reg_operand" "=r,z")
(and:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(match_operand:SI 2 "logical_operand" "r,L")))]
""
"and %2,%0"
[(set_attr "type" "arith")])
;; If the constant is 255, then emit a extu.b instruction instead of an
;; and, since that will give better code.
(define_expand "andsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(and:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "logical_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 255)
{
emit_insn (gen_zero_extendqisi2 (operands[0],
gen_lowpart (QImode, operands[1])));
DONE;
}
}")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "=r,z")
(ior:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(match_operand:SI 2 "logical_operand" "r,L")))]
""
"or %2,%0")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "=z,r")
(xor:SI (match_operand:SI 1 "arith_reg_operand" "%0,0")
(match_operand:SI 2 "logical_operand" "L,r")))]
""
"xor %2,%0"
[(set_attr "type" "arith")])
;; -------------------------------------------------------------------------
;; Shifts and rotates
;; -------------------------------------------------------------------------
(define_insn "rotlsi3_1"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(rotate:SI (match_operand:SI 1 "arith_reg_operand" "0")
(const_int 1)))
(set (reg:SI 18)
(lshiftrt:SI (match_dup 1) (const_int 31)))]
""
"rotl %0")
(define_insn "rotlsi3_31"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(rotate:SI (match_operand:SI 1 "arith_reg_operand" "0")
(const_int 31)))
(clobber (reg:SI 18))]
""
"rotr %0")
(define_insn ""
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(rotate:SI (match_operand:SI 1 "arith_reg_operand" "r")
(const_int 16)))]
""
"swap.w %1,%0")
(define_expand "rotlsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(rotate:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "immediate_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT)
FAIL;
if (INTVAL (operands[2]) == 1)
{
emit_insn (gen_rotlsi3_1 (operands[0], operands[1]));
DONE;
}
else if (INTVAL (operands[2]) == 31)
{
emit_insn (gen_rotlsi3_31 (operands[0], operands[1]));
DONE;
}
else if (INTVAL (operands[2]) != 16)
FAIL;
}")
(define_insn ""
[(set (match_operand:HI 0 "arith_reg_operand" "=r")
(rotate:HI (match_operand:HI 1 "arith_reg_operand" "r")
(const_int 8)))]
""
"swap.b %1,%0")
(define_expand "rotlhi3"
[(set (match_operand:HI 0 "arith_reg_operand" "")
(rotate:HI (match_operand:HI 1 "arith_reg_operand" "")
(match_operand:HI 2 "immediate_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 8)
FAIL;
}")
;;
;; shift left
(define_insn "ashlsi3_d"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "arith_reg_operand" "r")))]
"TARGET_SH3"
"shld %2,%0")
(define_insn "ashlsi3_k"
[(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0,0")
(match_operand:SI 2 "const_int_operand" "M,K")))]
"CONST_OK_FOR_K (INTVAL (operands[2]))"
"@
add %0,%0
shll%O2 %0")
(define_insn "ashlsi3_n"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "const_int_operand" "n")))
(clobber (reg:SI 18))]
""
"#"
[(set (attr "length")
(cond [(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 1))
(const_string "2")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 2))
(const_string "4")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 3))
(const_string "6")]
(const_string "8")))
(set_attr "type" "arith")])
(define_split
[(set (match_operand:SI 0 "arith_reg_operand" "")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "const_int_operand" "n")))
(clobber (reg:SI 18))]
""
[(use (reg:SI 0))]
"
{
gen_shifty_op (ASHIFT, operands);
DONE;
}")
(define_expand "ashlsi3"
[(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
(ashift:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))
(clobber (reg:SI 18))])]
""
"
{
if (TARGET_SH3 && arith_reg_operand (operands[2], GET_MODE (operands[2])))
{
emit_insn (gen_ashlsi3_d (operands[0], operands[1], operands[2]));
DONE;
}
if (! immediate_operand (operands[2], GET_MODE (operands[2])))
FAIL;
}")
;
; arithmetic shift right
;
(define_insn "ashrsi3_k"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "const_int_operand" "M")))
(clobber (reg:SI 18))]
"INTVAL (operands[2]) == 1"
"shar %0"
[(set_attr "type" "arith")])
;; ??? This should be a define expand.
(define_insn "ashrsi2_16"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "r")
(const_int 16)))]
""
"swap.w %1,%0\;exts.w %0,%0"
[(set_attr "length" "4")])
;; ??? This should be a define expand.
(define_insn "ashrsi2_31"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(const_int 31)))
(clobber (reg:SI 18))]
""
"@
shll %0\;subc %0,%0"
[(set_attr "length" "4")])
(define_insn "ashrsi3_d"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH3"
"shad %2,%1")
(define_insn "ashrsi3_n"
[(set (reg:SI 4)
(ashiftrt:SI (reg:SI 4)
(match_operand:SI 0 "const_int_operand" "i")))
(clobber (reg:SI 18))
(clobber (reg:SI 17))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
""
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
(define_expand "ashrsi3"
[(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
(ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))
(clobber (reg:SI 18))])]
""
"if (expand_ashiftrt (operands)) DONE; else FAIL;")
;; logical shift right
(define_insn "lshrsi3_d"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH3"
"shld %2,%0")
;; Only the single bit shift clobbers the T bit.
(define_insn "lshrsi3_m"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "const_int_operand" "M")))
(clobber (reg:SI 18))]
"CONST_OK_FOR_M (INTVAL (operands[2]))"
"shlr %0")
(define_insn "lshrsi3_k"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "const_int_operand" "K")))]
"CONST_OK_FOR_K (INTVAL (operands[2]))
&& ! CONST_OK_FOR_M (INTVAL (operands[2]))"
"shlr%O2 %0")
(define_insn "lshrsi3_n"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0")
(match_operand:SI 2 "const_int_operand" "n")))
(clobber (reg:SI 18))]
""
"#"
[(set (attr "length")
(cond [(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 1))
(const_string "2")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 2))
(const_string "4")
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 3))
(const_string "6")]
(const_string "8")))
(set_attr "type" "arith")])
(define_split
[(set (match_operand:SI 0 "arith_reg_operand" "")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "const_int_operand" "n")))
(clobber (reg:SI 18))]
""
[(use (reg:SI 0))]
"
{
gen_shifty_op (LSHIFTRT, operands);
DONE;
}")
(define_expand "lshrsi3"
[(parallel [(set (match_operand:SI 0 "arith_reg_operand" "")
(lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "")
(match_operand:SI 2 "nonmemory_operand" "")))
(clobber (reg:SI 18))])]
""
"
{
if (TARGET_SH3 && arith_reg_operand (operands[2], GET_MODE (operands[2])))
{
rtx count = copy_to_mode_reg (SImode, operands[2]);
emit_insn (gen_negsi2 (count, count));
emit_insn (gen_ashlsi3_d (operands[0], operands[1], count));
DONE;
}
if (! immediate_operand (operands[2], GET_MODE (operands[2])))
FAIL;
}")
;; ??? This should be a define expand.
(define_insn "ashldi3_k"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
(ashift:DI (match_operand:DI 1 "arith_reg_operand" "0")
(const_int 1)))
(clobber (reg:SI 18))]
""
"shll %R0\;rotcl %S0"
[(set_attr "length" "4")])
(define_expand "ashldi3"
[(parallel [(set (match_operand:DI 0 "arith_reg_operand" "")
(ashift:DI (match_operand:DI 1 "arith_reg_operand" "")
(match_operand:DI 2 "immediate_operand" "")))
(clobber (reg:SI 18))])]
""
"{ if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) != 1) FAIL;} ")
;; ??? This should be a define expand.
(define_insn "lshrdi3_k"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
(lshiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0")
(const_int 1)))
(clobber (reg:SI 18))]
""
"shlr %S0\;rotcr %R0"
[(set_attr "length" "4")])
(define_expand "lshrdi3"
[(parallel [(set (match_operand:DI 0 "arith_reg_operand" "")
(lshiftrt:DI (match_operand:DI 1 "arith_reg_operand" "")
(match_operand:DI 2 "immediate_operand" "")))
(clobber (reg:SI 18))])]
""
"{ if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) != 1) FAIL;} ")
;; ??? This should be a define expand.
(define_insn "ashrdi3_k"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
(ashiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0")
(const_int 1)))
(clobber (reg:SI 18))]
""
"shar %S0\;rotcr %R0"
[(set_attr "length" "4")])
(define_expand "ashrdi3"
[(parallel [(set (match_operand:DI 0 "arith_reg_operand" "")
(ashiftrt:DI (match_operand:DI 1 "arith_reg_operand" "")
(match_operand:DI 2 "immediate_operand" "")))
(clobber (reg:SI 18))])]
""
"{ if (GET_CODE (operands[2]) != CONST_INT
|| INTVAL (operands[2]) != 1) FAIL; } ")
;; -------------------------------------------------------------------------
;; Unary arithmetic
;; -------------------------------------------------------------------------
(define_insn "negc"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(neg:SI (plus:SI (reg:SI 18)
(match_operand:SI 1 "arith_reg_operand" "r"))))
(set (reg:SI 18)
(ne:SI (ior:SI (reg:SI 18) (match_dup 1))
(const_int 0)))]
""
"negc %1,%0"
[(set_attr "type" "arith")])
(define_expand "negdi2"
[(set (match_operand:DI 0 "arith_reg_operand" "")
(neg:DI (match_operand:DI 1 "arith_reg_operand" "")))
(clobber (reg:SI 18))]
""
"
{
int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1);
int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
rtx low_src = operand_subword (operands[1], low_word, 0, DImode);
rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
rtx low_dst = operand_subword (operands[0], low_word, 1, DImode);
rtx high_dst = operand_subword (operands[0], high_word, 1, DImode);
emit_insn (gen_clrt ());
emit_insn (gen_negc (low_dst, low_src));
emit_insn (gen_negc (high_dst, high_src));
DONE;
}")
(define_insn "negsi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(neg:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
""
"neg %1,%0"
[(set_attr "type" "arith")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(not:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
""
"not %1,%0"
[(set_attr "type" "arith")])
;; -------------------------------------------------------------------------
;; Zero extension instructions
;; -------------------------------------------------------------------------
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "arith_reg_operand" "r")))]
""
"extu.w %1,%0"
[(set_attr "type" "arith")])
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "arith_reg_operand" "r")))]
""
"extu.b %1,%0"
[(set_attr "type" "arith")])
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "arith_reg_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "arith_reg_operand" "r")))]
""
"extu.b %1,%0"
[(set_attr "type" "arith")])
;; -------------------------------------------------------------------------
;; Sign extension instructions
;; -------------------------------------------------------------------------
;; ??? This should be a define expand.
;; ??? Or perhaps it should be dropped?
(define_insn "extendsidi2"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
(sign_extend:DI (match_operand:SI 1 "arith_reg_operand" "r")))
(clobber (reg:SI 18))]
""
"mov %1,%S0\;mov %1,%R0\;shll %S0\;subc %S0,%S0"
[(set_attr "length" "8")])
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
(sign_extend:SI (match_operand:HI 1 "general_movsrc_operand" "r,m")))]
""
"@
exts.w %1,%0
mov.w %1,%0"
[(set_attr "type" "arith,load")])
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
(sign_extend:SI (match_operand:QI 1 "general_movsrc_operand" "r,m")))]
""
"@
exts.b %1,%0
mov.b %1,%0"
[(set_attr "type" "arith,load")])
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "arith_reg_operand" "=r,r")
(sign_extend:HI (match_operand:QI 1 "general_movsrc_operand" "r,m")))]
""
"@
exts.b %1,%0
mov.b %1,%0"
[(set_attr "type" "arith,load")])
;; -------------------------------------------------------------------------
;; Move instructions
;; -------------------------------------------------------------------------
;; define push and pop so it is easy for sh.c
(define_insn "push"
[(set (mem:SI (pre_dec:SI (reg:SI 15)))
(match_operand:SI 0 "register_operand" "r,l,x"))]
""
"@
mov.l %0,@-r15
sts.l %0,@-r15
sts.l %0,@-r15"
[(set_attr "type" "store,pstore,store")
(set_attr "hit_stack" "yes")])
(define_insn "pop"
[(set (match_operand:SI 0 "register_operand" "=r,l,x")
(mem:SI (post_inc:SI (reg:SI 15))))]
""
"@
mov.l @r15+,%0
lds.l @r15+,%0
lds.l @r15+,%0"
[(set_attr "type" "load,pload,load")
(set_attr "hit_stack" "yes")])
;; These two patterns can happen as the result of optimization, when
;; comparisons get simplified to a move of zero or 1 into the T reg.
;; They don't disappear completely, because the T reg is a fixed hard reg.
(define_insn "clrt"
[(set (reg:SI 18) (const_int 0))]
""
"clrt")
(define_insn "sett"
[(set (reg:SI 18) (const_int 1))]
""
"sett")
;; t/z is first, so that it will be preferred over r/r when reloading a move
;; of a pseudo-reg into the T reg
(define_insn "movsi_i"
[(set (match_operand:SI 0 "general_movdst_operand" "=t,r,r,r,r,r,m,<,xl,xl,r")
(match_operand:SI 1 "general_movsrc_operand" "z,Q,rI,m,xl,t,r,xl,r,>,i"))]
"register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)"
"@
tst %1,%1\;rotcl %1\;xor #1,%1\;rotcr %1
mov.l %1,%0
mov %1,%0
mov.l %1,%0
sts %1,%0
movt %0
mov.l %1,%0
sts.l %1,%0
lds %1,%0
lds.l %1,%0
fake %1,%0"
[(set_attr "type" "move,pcload,move,load,move,store,store,move,load,move,move")
(set_attr "length" "8,*,*,*,*,*,*,*,*,*,*")])
(define_expand "movsi"
[(set (match_operand:SI 0 "general_movdst_operand" "")
(match_operand:SI 1 "general_movsrc_operand" ""))]
""
"{ if (prepare_move_operands (operands, SImode)) DONE; }")
(define_insn "movqi_i"
[(set (match_operand:QI 0 "general_movdst_operand" "=r,r,m,r,r,l")
(match_operand:QI 1 "general_movsrc_operand" "ri,m,r,t,l,r"))]
"arith_reg_operand (operands[0], QImode)
|| arith_reg_operand (operands[1], QImode)"
"@
mov %1,%0
mov.b %1,%0
mov.b %1,%0
movt %0
sts %1,%0
lds %1,%0"
[(set_attr "type" "move,load,store,move,move,move")])
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
"{ if (prepare_move_operands (operands, QImode)) DONE; }")
(define_insn "movhi_i"
[(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m,r,l,r")
(match_operand:HI 1 "general_movsrc_operand" "Q,rI,m,t,r,l,r,i"))]
"arith_reg_operand (operands[0], HImode)
|| arith_reg_operand (operands[1], HImode)"
"@
mov.w %1,%0
mov %1,%0
mov.w %1,%0
movt %0
mov.w %1,%0
sts %1,%0
lds %1,%0
fake %1,%0"
[(set_attr "type" "pcload,move,load,move,store,move,move,move")])
(define_expand "movhi"
[(set (match_operand:HI 0 "general_movdst_operand" "")
(match_operand:HI 1 "general_movsrc_operand" ""))]
""
"{ if (prepare_move_operands (operands, HImode)) DONE; }")
;; ??? This should be a define expand.
(define_insn ""
[(set (match_operand:DI 0 "general_movdst_operand" "=r,r,r,m,r,r")
(match_operand:DI 1 "general_movsrc_operand" "Q,r,m,r,i,x"))]
"arith_reg_operand (operands[0], DImode)
|| arith_reg_operand (operands[1], DImode)"
"* return output_movedouble (insn, operands, DImode);"
[(set_attr "length" "4")
(set_attr "type" "pcload,move,load,store,move,move")])
;; If the output is a register and the input is memory or a register, we have
;; to be careful and see which word needs to be loaded first.
(define_split
[(set (match_operand:DI 0 "general_movdst_operand" "")
(match_operand:DI 1 "general_movsrc_operand" ""))]
"reload_completed"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
"
{
int regno;
if ((GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
|| (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) == POST_INC))
FAIL;
if (GET_CODE (operands[0]) == REG)
regno = REGNO (operands[0]);
else if (GET_CODE (operands[0]) == SUBREG)
regno = REGNO (SUBREG_REG (operands[0])) + SUBREG_WORD (operands[0]);
else if (GET_CODE (operands[0]) == MEM)
regno = -1;
if (regno == -1
|| ! refers_to_regno_p (regno, regno + 1, operands[1], 0))
{
operands[2] = operand_subword (operands[0], 0, 0, DImode);
operands[3] = operand_subword (operands[1], 0, 0, DImode);
operands[4] = operand_subword (operands[0], 1, 0, DImode);
operands[5] = operand_subword (operands[1], 1, 0, DImode);
}
else
{
operands[2] = operand_subword (operands[0], 1, 0, DImode);
operands[3] = operand_subword (operands[1], 1, 0, DImode);
operands[4] = operand_subword (operands[0], 0, 0, DImode);
operands[5] = operand_subword (operands[1], 0, 0, DImode);
}
if (operands[2] == 0 || operands[3] == 0
|| operands[4] == 0 || operands[5] == 0)
FAIL;
}")
(define_expand "movdi"
[(set (match_operand:DI 0 "general_movdst_operand" "")
(match_operand:DI 1 "general_movsrc_operand" ""))]
""
"{ if ( prepare_move_operands (operands, DImode)) DONE; }")
;; ??? This should be a define expand.
(define_insn "movdf_k"
[(set (match_operand:DF 0 "general_movdst_operand" "=r,r,m")
(match_operand:DF 1 "general_movsrc_operand" "r,m,r"))]
"arith_reg_operand (operands[0], DFmode)
|| arith_reg_operand (operands[1], DFmode)"
"* return output_movedouble (insn, operands, DFmode);"
[(set_attr "length" "4")
(set_attr "type" "move,load,store")])
;; If the output is a register and the input is memory or a register, we have
;; to be careful and see which word needs to be loaded first.
(define_split
[(set (match_operand:DF 0 "general_movdst_operand" "")
(match_operand:DF 1 "general_movsrc_operand" ""))]
"reload_completed"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
"
{
int regno;
if ((GET_CODE (operands[0]) == MEM
&& GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
|| (GET_CODE (operands[1]) == MEM
&& GET_CODE (XEXP (operands[1], 0)) == POST_INC))
FAIL;
if (GET_CODE (operands[0]) == REG)
regno = REGNO (operands[0]);
else if (GET_CODE (operands[0]) == SUBREG)
regno = REGNO (SUBREG_REG (operands[0])) + SUBREG_WORD (operands[0]);
else if (GET_CODE (operands[0]) == MEM)
regno = -1;
if (regno == -1
|| ! refers_to_regno_p (regno, regno + 1, operands[1], 0))
{
operands[2] = operand_subword (operands[0], 0, 0, DFmode);
operands[3] = operand_subword (operands[1], 0, 0, DFmode);
operands[4] = operand_subword (operands[0], 1, 0, DFmode);
operands[5] = operand_subword (operands[1], 1, 0, DFmode);
}
else
{
operands[2] = operand_subword (operands[0], 1, 0, DFmode);
operands[3] = operand_subword (operands[1], 1, 0, DFmode);
operands[4] = operand_subword (operands[0], 0, 0, DFmode);
operands[5] = operand_subword (operands[1], 0, 0, DFmode);
}
if (operands[2] == 0 || operands[3] == 0
|| operands[4] == 0 || operands[5] == 0)
FAIL;
}")
(define_expand "movdf"
[(set (match_operand:DF 0 "general_movdst_operand" "")
(match_operand:DF 1 "general_movsrc_operand" ""))]
""
"{ if (prepare_move_operands (operands, DFmode)) DONE; }")
(define_insn "movsf_i"
[(set (match_operand:SF 0 "general_movdst_operand" "=r,r,r,m,l,r")
(match_operand:SF 1 "general_movsrc_operand" "r,I,m,r,r,l"))]
"arith_reg_operand (operands[0], SFmode)
|| arith_reg_operand (operands[1], SFmode)"
"@
mov %1,%0
mov %1,%0
mov.l %1,%0
mov.l %1,%0
lds %1,%0
sts %1,%0"
[(set_attr "type" "move,move,load,store,move,move")])
(define_expand "movsf"
[(set (match_operand:SF 0 "general_movdst_operand" "")
(match_operand:SF 1 "general_movsrc_operand" ""))]
""
"{ if (prepare_move_operands (operands, SFmode)) DONE; }")
;; ------------------------------------------------------------------------
;; Define the real conditional branch instructions.
;; ------------------------------------------------------------------------
(define_insn "branch_true"
[(set (pc) (if_then_else (eq (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_branch (1, insn, operands);"
[(set_attr "type" "cbranch")])
(define_insn "branch_false"
[(set (pc) (if_then_else (ne (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"* return output_branch (0, insn, operands);"
[(set_attr "type" "cbranch")])
(define_insn "inverse_branch_true"
[(set (pc) (if_then_else (eq (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_branch (0, insn, operands);"
[(set_attr "type" "cbranch")])
(define_insn "inverse_branch_false"
[(set (pc) (if_then_else (ne (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"* return output_branch (1, insn, operands);"
[(set_attr "type" "cbranch")])
;; Conditional branch insns
(define_expand "beq"
[(set (reg:SI 18) (eq:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"from_compare (operands, EQ);")
; There is no bne compare, so we reverse the branch arms.
(define_expand "bne"
[(set (reg:SI 18) (eq:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"from_compare (operands, NE);")
(define_expand "bgt"
[(set (reg:SI 18) (gt:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"from_compare (operands, GT);")
(define_expand "blt"
[(set (reg:SI 18) (ge:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"from_compare (operands, LT);")
(define_expand "ble"
[(set (reg:SI 18) (gt:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"from_compare (operands, LE);")
(define_expand "bge"
[(set (reg:SI 18) (ge:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"from_compare (operands, GE);")
(define_expand "bgtu"
[(set (reg:SI 18) (gtu:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"from_compare (operands, GTU); ")
(define_expand "bltu"
[(set (reg:SI 18) (geu:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"from_compare (operands, LTU);")
(define_expand "bgeu"
[(set (reg:SI 18) (geu:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"from_compare (operands, GEU);")
(define_expand "bleu"
[(set (reg:SI 18) (gtu:SI (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (eq (reg:SI 18) (const_int 1))
(pc)
(label_ref (match_operand 0 "" ""))))]
""
"from_compare (operands, LEU);")
;; ------------------------------------------------------------------------
;; Jump and linkage insns
;; ------------------------------------------------------------------------
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"*
{
/* The length is 16 if the delay slot is unfilled. */
if (get_attr_length(insn) >= 14)
return output_far_jump(insn, operands[0]);
else
return \"bra %l0%#\";
}"
[(set_attr "type" "jump")
(set_attr "needs_delay_slot" "yes")])
(define_insn "calli"
[(call (mem:SI (match_operand:SI 0 "arith_reg_operand" "r"))
(match_operand 1 "" ""))
(clobber (reg:SI 17))]
""
"jsr @%0%#"
[(set_attr "type" "call")
(set_attr "needs_delay_slot" "yes")])
(define_insn "call_valuei"
[(set (match_operand 0 "" "=rf")
(call (mem:SI (match_operand:SI 1 "arith_reg_operand" "r"))
(match_operand 2 "" "")))
(clobber (reg:SI 17))]
""
"jsr @%1%#"
[(set_attr "type" "call")
(set_attr "needs_delay_slot" "yes")])
(define_expand "call"
[(parallel [(call (mem:SI (match_operand 0 "arith_reg_operand" ""))
(match_operand 1 "" ""))
(clobber (reg:SI 17))])]
""
"operands[0] = force_reg (SImode, XEXP (operands[0], 0));")
(define_expand "call_value"
[(parallel [(set (match_operand 0 "arith_reg_operand" "")
(call (mem:SI (match_operand 1 "arith_reg_operand" ""))
(match_operand 2 "" "")))
(clobber (reg:SI 17))])]
""
"operands[1] = force_reg (SImode, XEXP (operands[1], 0));")
(define_insn "indirect_jump"
[(set (pc)
(match_operand:SI 0 "arith_reg_operand" "r"))]
""
"jmp @%0%#"
[(set_attr "needs_delay_slot" "yes")])
;; ------------------------------------------------------------------------
;; Misc insns
;; ------------------------------------------------------------------------
;; ??? This combiner pattern does not work, because combine does not combine
;; instructions that set a hard register when SMALL_REGISTER_CLASSES is
;; defined. Perhaps use a pseudo-reg for the T bit?
(define_insn "dect"
[(parallel [(set (match_operand:SI 0 "arith_reg_operand" "=r")
(plus:SI (match_dup 0)
(const_int -1)))
(set (reg:SI 18)
(eq:SI (plus:SI (match_dup 0) (const_int -1))
(const_int 0)))])]
"TARGET_SH2"
"dt %0")
(define_insn "nop"
[(const_int 0)]
""
"nop")
;; Load address of a label. This is only generated by the casesi expand.
;; This must use unspec, because this only works immediately before a casesi.
(define_insn "mova"
[(set (reg:SI 0)
(unspec [(label_ref (match_operand 0 "" ""))] 1))]
""
"mova %O0,r0"
[(set_attr "in_delay_slot" "no")])
;; case instruction for switch statements.
;; 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.
;; ??? There should be a barrier after the jump at the end.
(define_expand "casesi"
[(set (match_dup 5) (match_operand:SI 0 "arith_reg_operand" ""))
(set (match_dup 5) (minus:SI (match_dup 5)
(match_operand:SI 1 "arith_operand" "")))
(set (reg:SI 18)
(gtu:SI (match_dup 5)
(match_operand:SI 2 "arith_reg_operand" "")))
(set (pc)
(if_then_else (eq (reg:SI 18)
(const_int 1))
(label_ref (match_operand 4 "" ""))
(pc)))
(set (match_dup 6) (match_dup 5))
(set (match_dup 6) (ashift:SI (match_dup 6) (match_dup 7)))
(set (reg:SI 0) (unspec [(label_ref (match_operand 3 "" ""))] 1))
(parallel [(set (reg:SI 0) (plus:SI (reg:SI 0)
(mem:HI (plus:SI (reg:SI 0)
(match_dup 6)))))
(set (match_dup 6) (mem:HI (plus:SI (reg:SI 0) (match_dup 6))))])
(set (pc) (reg:SI 0))]
""
"
{
operands[1] = copy_to_mode_reg (SImode, operands[1]);
operands[2] = copy_to_mode_reg (SImode, operands[2]);
operands[5] = gen_reg_rtx (SImode);
operands[6] = gen_reg_rtx (SImode);
operands[7] = GEN_INT (TARGET_BIGTABLE ? 2 : 1);
}")
(define_insn "casesi_worker"
[(set (reg:SI 0)
(plus:SI (reg:SI 0)
(mem:HI (plus:SI (reg:SI 0)
(match_operand:SI 0 "arith_reg_operand" "+r")))))
(set (match_dup 0) (mem:HI (plus:SI (reg:SI 0)
(match_dup 0))))]
""
"*
{
if (TARGET_BIGTABLE)
return \"mov.l @(r0,%0),%0\;add %0,r0\";
else
return \"mov.w @(r0,%0),%0\;add %0,r0\";
}"
[(set_attr "length" "4")])
(define_insn "return"
[(return)]
"reload_completed"
"%@ %#"
[(set_attr "type" "return")
(set_attr "needs_delay_slot" "yes")])
(define_expand "prologue"
[(const_int 0)]
""
"sh_expand_prologue (); DONE;")
(define_expand "epilogue"
[(return)]
""
"sh_expand_epilogue ();")
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 0)]
""
""
[(set_attr "length" "0")])
;; ------------------------------------------------------------------------
;; Scc instructions
;; ------------------------------------------------------------------------
(define_insn "movt"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(eq:SI (reg:SI 18) (const_int 1)))]
""
"movt %0")
(define_expand "seq"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (EQ);")
(define_expand "slt"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (LT);")
(define_expand "sle"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (LE);")
(define_expand "sgt"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (GT);")
(define_expand "sge"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (GE);")
(define_expand "sgtu"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (GTU);")
(define_expand "sltu"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (LTU);")
(define_expand "sleu"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (LEU);")
(define_expand "sgeu"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))]
""
"operands[1] = prepare_scc_operands (GEU);")
(define_expand "sne"
[(set (match_operand:SI 0 "arith_reg_operand" "")
(match_dup 1))
(set (match_dup 0) (xor:SI (match_dup 0) (const_int 1)))]
""
"operands[1] = prepare_scc_operands (EQ);")
;; -------------------------------------------------------------------------
;; Instructions to cope with inline literal tables
;; -------------------------------------------------------------------------
; 2 byte integer in line
(define_insn "consttable_2"
[(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")] 2)]
""
"*
{
assemble_integer (operands[0], 2, 1);
return \"\";
}"
[(set_attr "length" "2")
(set_attr "in_delay_slot" "no")])
; 4 byte integer in line
(define_insn "consttable_4"
[(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")] 4)]
""
"*
{
assemble_integer (operands[0], 4, 1);
return \"\";
}"
[(set_attr "length" "4")
(set_attr "in_delay_slot" "no")])
; 8 byte integer in line
(define_insn "consttable_8"
[(unspec_volatile [(match_operand:SI 0 "general_operand" "=g")] 6)]
""
"*
{
assemble_integer (operands[0], 8, 1);
return \"\";
}"
[(set_attr "length" "8")
(set_attr "in_delay_slot" "no")])
; align to a two byte boundary
(define_insn "align_2"
[(unspec_volatile [(const_int 0)] 10)]
""
".align 1"
[(set_attr "length" "0")
(set_attr "in_delay_slot" "no")])
; align to a four byte boundary
(define_insn "align_4"
[(unspec_volatile [(const_int 0)] 5)]
""
".align 2"
[(set_attr "in_delay_slot" "no")])
; emitted at the end of the literal table, used to emit the
; 32bit branch labels if needed.
(define_insn "consttable_end"
[(unspec_volatile [(const_int 0)] 11)]
""
"* return output_jump_label_table ();"
[(set_attr "in_delay_slot" "no")])
;; -------------------------------------------------------------------------
;; Misc
;; -------------------------------------------------------------------------
;; String/block move insn.
(define_expand "movstrsi"
[(parallel [(set (mem:BLK (match_operand:BLK 0 "" ""))
(mem:BLK (match_operand:BLK 1 "" "")))
(use (match_operand:SI 2 "nonmemory_operand" ""))
(use (match_operand:SI 3 "immediate_operand" ""))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 5))
(clobber (reg:SI 0))])]
""
"
{
if(expand_block_move (operands))
DONE;
else FAIL;
}")
(define_insn "block_move_real"
[(parallel [(set (mem:BLK (reg:SI 4))
(mem:BLK (reg:SI 5)))
(use (match_operand:SI 0 "arith_reg_operand" "r"))
(clobber (reg:SI 17))
(clobber (reg:SI 0))])]
""
"jsr @%0%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
(define_insn "block_lump_real"
[(parallel [(set (mem:BLK (reg:SI 4))
(mem:BLK (reg:SI 5)))
(use (match_operand:SI 0 "arith_reg_operand" "r"))
(use (reg:SI 6))
(clobber (reg:SI 17))
(clobber (reg:SI 4))
(clobber (reg:SI 5))
(clobber (reg:SI 6))
(clobber (reg:SI 0))])]
""
"jsr @%0%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
;; -------------------------------------------------------------------------
;; Peepholes
;; -------------------------------------------------------------------------
;; This matches cases where a stack pointer increment at the start of the
;; epilogue combines with a stack slot read loading the return value.
(define_peephole
[(set (match_operand:SI 0 "arith_reg_operand" "")
(mem:SI (match_operand:SI 1 "arith_reg_operand" "")))
(set (match_dup 1) (plus:SI (match_dup 1) (const_int 4)))]
"REGNO (operands[1]) != REGNO (operands[0])"
"mov.l @%1+,%0")
;; See the comment on the dt combiner pattern above.
(define_peephole
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(plus:SI (match_dup 0)
(const_int -1)))
(set (reg:SI 18)
(eq:SI (match_dup 0)
(const_int 0)))]
"TARGET_SH2"
"dt %0")
;; These convert sequences such as `mov #k,r0; add r15,r0; mov.l @r0,rn'
;; to `mov #k,r0; mov.l @(r0,r15),rn'. These sequences are generated by
;; reload when the constant is too large for a reg+offset address.
;; ??? We would get much better code if this was done in reload. This would
;; require modifying find_reloads_address to recognize that if the constant
;; is out-of-range for an immediate add, then we get better code by reloading
;; the constant into a register than by reloading the sum into a register,
;; since the former is one instruction shorter if the address does not need
;; to be offsettable. Unfortunately this does not work, because there is
;; only one register, r0, that can be used as an index register. This register
;; is also the function return value register. So, if we try to force reload
;; to use double-reg addresses, then we end up with some instructions that
;; need to use r0 twice. The only way to fix this is to change the calling
;; convention so that r0 is not used to return values.
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (mem:SI (match_dup 0))
(match_operand:SI 2 "general_movsrc_operand" ""))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.l %2,@(%0,%1)")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (match_operand:SI 2 "general_movdst_operand" "")
(mem:SI (match_dup 0)))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.l @(%0,%1),%2")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (mem:HI (match_dup 0))
(match_operand:HI 2 "general_movsrc_operand" ""))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.w %2,@(%0,%1)")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (match_operand:HI 2 "general_movdst_operand" "")
(mem:HI (match_dup 0)))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.w @(%0,%1),%2")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (mem:QI (match_dup 0))
(match_operand:QI 2 "general_movsrc_operand" ""))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.b %2,@(%0,%1)")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (match_operand:QI 2 "general_movdst_operand" "")
(mem:QI (match_dup 0)))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.b @(%0,%1),%2")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (mem:SF (match_dup 0))
(match_operand:SF 2 "general_movsrc_operand" ""))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.l %2,@(%0,%1)")
(define_peephole
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (match_dup 0) (match_operand:SI 1 "register_operand" "r")))
(set (match_operand:SF 2 "general_movdst_operand" "")
(mem:SF (match_dup 0)))]
"REGNO (operands[0]) == 0 && reg_unused_after (operands[0], insn)"
"mov.l @(%0,%1),%2")