8sa1-gcc/gcc/config/m88k/m88k.md
Richard Kenner 996a5f59fb Remove references to LSHIFT and lshlsi3.
From-SVN: r7016
1994-04-10 07:13:16 -04:00

4017 lines
118 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;- Machine description for the Motorola 88000 for GNU C compiler
;; Copyright (C) 1988, 89, 90, 91, 93, 1994 Free Software Foundation, Inc.
;; Contributed by Michael Tiemann (tiemann@mcc.com)
;; Additional changes by Michael Meissner (meissner@osf.org)
;; Version 2 port by Tom Wood (twood@pets.sps.mot.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, 675 Mass Ave, Cambridge, MA 02139, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;; RCS rev field. This is a NOP, just to get the RCS id into the
;; program image.
(define_expand "m88k_rcs_id"
[(match_operand:SI 0 "" "")]
""
"{ static char rcs_id[] = \"$What: <@(#) m88k.md,v 1.5> $\";
FAIL; }")
;; Attribute describing the processor. This attribute must match exactly
;; with the processor_type enumeration in m88k.h.
; Target CPU.
(define_attr "cpu" "m88100,m88110,m88000"
(const (symbol_ref "m88k_cpu")))
; Type of each instruction. Default is arithmetic.
; I'd like to write the list as this, but genattrtab won't accept it.
;
; "branch,jump,call, ; flow-control instructions
; load,store,loadd,loada, ; data unit instructions
; spadd,dpadd,spcmp,dpcmp,spdiv,dpdiv,idiv, ; FPU add instructions
; spmul,dpmul,imul, ; FPU multiply instructions
; arith,bit,mov ; integer unit instructions
; marith,weird" ; multi-word instructions
; Classification of each insn. Some insns of TYPE_BRANCH are multi-word.
(define_attr "type"
"branch,jump,call,load,store,loadd,loada,spadd,dpadd,spcmp,dpcmp,spdiv,dpdiv,idiv,spmul,dpmul,imul,arith,bit,mov,marith,weird"
(const_string "arith"))
(define_attr "fpu" "yes,no"
(if_then_else
(eq_attr "type" "spmul,dpmul,imul,spadd,dpadd,spcmp,dpcmp,spdiv,dpdiv,idiv")
(const_string "yes") (const_string "no")))
; Length in # of instructions of each insn. The values are not exact, but
; are safe.
(define_attr "length" ""
(cond [(eq_attr "type" "marith,weird,branch")
(const_int 2)]
(const_int 1)))
; Describe a user's asm statement.
(define_asm_attributes
[(set_attr "type" "weird")])
; Define the delay slot requirements for branches and calls.
; The m88100 annuls instructions if a conditional branch is taken.
; For insns of TYPE_BRANCH that are multi-word instructions, the
; delay slot applies to the first instruction.
; @@ For the moment, reorg.c requires that the delay slot of a branch not
; be a call or branch.
(define_delay (eq_attr "type" "branch,jump")
[(and
(and
(eq_attr "type" "!branch,jump,call,marith,weird") ; required.
(eq_attr "type" "!load,loadd")) ; issue as-soon-as-possible.
(eq_attr "fpu" "no")) ; issue as-soon-as-possible.
(eq_attr "type" "!call,branch,jump") (nil)]) ; @@ was (const_int 1)
; output_call supports an unconditional branch in the delay slot of
; a call. (@@ Support for this case is expected in reorg.c soon.)
(define_delay (eq_attr "type" "call")
[(eq_attr "type" "!branch,call,marith,weird") ; required.
(nil) (nil)])
; An abstract block diagram of the function units for the m88100.
;
; *
; |
; +---v----+
; | decode |
; +-vv-v-v-+ fpu
; ,----------'| | `----------------------.
; | | | | ,-----.
; load | store | | arith | | |
; | | | +-v-v-+ | dp source
; | | | | fp1 |---'
; store | | | div +-v-v-+
; ,------. | | | ,-----. ,-----------' `-----------.
; | | | | | | | | |
; | +--v---v--+ ,---' | | +-v-v---+ +---v---+
; | | stage 2 | | | `---| add 2 | | mul 2 |
; | +---------+ | +--v--+ +-------+ imul +-------+
; | | stage 1 | | | alu | | add 3 | ,--------| mul 3 |
; | +---------+ | +--v--+ +-------+ | +-------+
; | | stage 0 | | | | add 4 | | | mul 4 |
; | +--v---v--+ | | +---v---+ | +-------+
; | | | | | | | | mul 5 |
; | * | | | | | +---v---+
; | | | | | +----v----+ |
; | load | | | fp add `------>| fp last |<------' fp mul
; | | | | +---v-v--^+
; | | | | | | |
; | | | | | `--' dp dest
; | | +--v-----v--+ |
; | `--->| writeback |<--------------------'
; | +--v-----v--+
; | | |
; `------------------' *
;
; The decode unit need not be specified.
; Consideration of writeback contention is critical to superb scheduling.
;
; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
; Describing the '100 alu is currently not useful.
;(define_function_unit "alu" 1 0 (eq_attr "type"
; "!store,marith,weird") 1 0)
;(define_function_unit "alu" 1 0 (eq_attr "type" "marith,weird") 2 0)
(define_function_unit "alu" 1 0
(and (eq_attr "type" "loada,arith,mov") (eq_attr "cpu" "!m88100")) 2 0)
(define_function_unit "alu" 1 0
(and (eq_attr "type" "marith,weird") (eq_attr "cpu" "!m88100")) 4 0)
(define_function_unit "bit" 1 0
(and (eq_attr "type" "bit") (eq_attr "cpu" "!m88100")) 2 2)
(define_function_unit "mem100" 1 0
(and (eq_attr "type" "store,loada") (eq_attr "cpu" "m88100")) 1 0)
(define_function_unit "mem100" 1 0
(and (eq_attr "type" "load") (eq_attr "cpu" "m88100")) 3 0)
(define_function_unit "mem100" 1 0
(and (eq_attr "type" "loadd") (eq_attr "cpu" "m88100")) 3 2)
(define_function_unit "mem110" 1 0
(and (eq_attr "type" "load,loadd") (eq_attr "cpu" "!m88100")) 3 2)
(define_function_unit "mem110" 1 0
(and (eq_attr "type" "store") (eq_attr "cpu" "!m88100")) 1 2)
; The times are adjusted to include fp1 and fplast, but then are further
; adjusted based on the actual generated code. The notation to the right
; is the total latency. A range denotes a group of instructions and/or
; conditions (the extra clock of fplast time with some sequences).
(define_function_unit "fpmul100" 1 0
(and (eq_attr "type" "spmul") (eq_attr "cpu" "m88100")) 4 0) ; 6-8
(define_function_unit "fpmul100" 1 0
(and (eq_attr "type" "dpmul") (eq_attr "cpu" "m88100")) 7 0) ; 9-10
(define_function_unit "fpmul100" 1 0
(and (eq_attr "type" "imul") (eq_attr "cpu" "m88100")) 3 0) ; 4
(define_function_unit "fpmul110" 1 0
(and (eq_attr "type" "imul,spmul,dpmul")
(eq_attr "cpu" "!m88100")) 5 2) ; 3
(define_function_unit "fpadd100" 1 5
(and (eq_attr "type" "spadd,spcmp") (eq_attr "cpu" "m88100")) 3 0) ; 5-6
(define_function_unit "fpadd100" 1 5
(and (eq_attr "type" "dpadd,dpcmp") (eq_attr "cpu" "m88100")) 4 0) ; 6-7
(define_function_unit "fpadd110" 1 0
(and (eq_attr "type" "spadd,dpadd") (eq_attr "cpu" "!m88100")) 5 2) ; 3
(define_function_unit "fpadd110" 1 0
(and (eq_attr "type" "spcmp,dpcmp") (eq_attr "cpu" "!m88100")) 2 2) ; 1
(define_function_unit "fpadd100" 1 5
(and (eq_attr "type" "spdiv") (eq_attr "cpu" "m88100")) 30 0) ; 30-31
(define_function_unit "fpadd100" 1 5
(and (eq_attr "type" "dpdiv") (eq_attr "cpu" "m88100")) 60 0) ; 60-61
(define_function_unit "fpadd100" 1 5
(and (eq_attr "type" "idiv") (eq_attr "cpu" "m88100")) 38 0) ; 38
(define_function_unit "div" 1 1
(and (eq_attr "type" "spdiv") (eq_attr "cpu" "!m88100")) 25 2) ; 13
(define_function_unit "div" 1 1
(and (eq_attr "type" "dpdiv") (eq_attr "cpu" "!m88100")) 45 2) ; 23
(define_function_unit "div" 1 1
(and (eq_attr "type" "idiv") (eq_attr "cpu" "!m88100")) 35 2) ; 18
;; Superoptimizer sequences
;; geu+: { r = ((unsigned_word) v0 >= (unsigned_word) v1) + v2; }
;; subu.co r5,r2,r3
;; addu.cio r6,r4,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(geu:SI (match_operand:SI 2 "register_operand" "r")
(match_operand:SI 3 "register_operand" "r"))))]
""
[(set (reg:CC 0) (unspec:CC [(match_dup 2) (match_dup 3)] 1))
(set (match_dup 0)
(plus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 0)))]
"")
;; leu+: { r = ((unsigned_word) v0 <= (unsigned_word) v1) + v2; }
;; subu.co r5,r3,r2
;; addu.cio r6,r4,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(leu:SI (match_operand:SI 3 "register_operand" "r")
(match_operand:SI 2 "register_operand" "r"))))]
""
[(set (reg:CC 0) (unspec:CC [(match_dup 2) (match_dup 3)] 1))
(set (match_dup 0)
(plus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 0)))]
"")
;; eq0+: { r = (v0 == 0) + v1; }
;; subu.co r4,r0,r2
;; addu.cio r5,r3,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(eq:SI (match_operand:SI 2 "register_operand" "r")
(const_int 0))))]
""
[(set (reg:CC 0) (unspec:CC [(const_int 0) (match_dup 2)] 1))
(set (match_dup 0)
(plus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 0)))]
"")
;; ltu-: { r = v2 - ((unsigned_word) v0 < (unsigned_word) v1); }
;; subu.co r5,r2,r3
;; subu.cio r6,r4,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (ltu:SI (match_operand:SI 2 "register_operand" "r")
(match_operand:SI 3 "register_operand" "r"))
(match_operand:SI 1 "register_operand" "r")))]
""
[(set (reg:CC 0) (unspec:CC [(match_dup 2) (match_dup 3)] 1))
(set (match_dup 0)
(minus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 1)))]
"")
;; gtu-: { r = v2 - ((unsigned_word) v0 > (unsigned_word) v1); }
;; subu.co r5,r3,r2
;; subu.cio r6,r4,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (gtu:SI (match_operand:SI 3 "register_operand" "r")
(match_operand:SI 2 "register_operand" "r"))
(match_operand:SI 1 "register_operand" "r")))]
""
[(set (reg:CC 0) (unspec:CC [(match_dup 2) (match_dup 3)] 1))
(set (match_dup 0)
(minus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 1)))]
"")
;; ne0-: { r = v1 - (v0 != 0); }
;; subu.co r4,r0,r2
;; subu.cio r5,r3,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(plus:SI (ne:SI (match_operand:SI 2 "register_operand" "r")
(const_int 0))
(match_operand:SI 1 "register_operand" "r")))]
""
[(set (reg:CC 0) (unspec:CC [(const_int 0) (match_dup 2)] 1))
(set (match_dup 0)
(minus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 1)))]
"")
;; ges0-: { r = v1 - ((signed_word) v0 >= 0); }
;; addu.co r4,r2,r2
;; subu.cio r5,r3,r0
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(xor:SI (lshiftrt:SI
(match_operand:SI 2 "register_operand" "r")
(const_int 31))
(const_int 1))))]
""
[(set (reg:CC 0) (unspec:CC [(match_dup 2) (match_dup 2)] 0))
(set (match_dup 0)
(minus:SI (match_dup 1)
(unspec:SI [(const_int 0)
(reg:CC 0)] 1)))]
"")
;; This rich set of complex patterns are mostly due to Torbjorn Granlund
;; (tege@sics.se). They've changed since then, so don't complain to him
;; if they don't work right.
;; Regarding shifts, gen_lshlsi3 generates ASHIFT. The gen functions
;; produce the necessary insns to support TARGET_*_LARGE_SHIFT, so nothing
;; special needs to be done here.
;; Optimize possible cases of the set instruction.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (const_int -1)
(match_operand:SI 1 "register_operand" "r")))]
""
"set %0,%#r0,%1"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (ashift:SI (const_int -1)
(match_operand:SI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "r")))]
""
"set %0,%2,%1"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operand:SI 1 "register_operand" "r")
(ashift:SI (const_int -1)
(match_operand:SI 2 "register_operand" "r"))))]
""
"set %0,%1,%2"
[(set_attr "type" "bit")])
;; Optimize possible cases of the mak instruction.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "int5_operand" ""))
(match_operand:SI 3 "immediate_operand" "n")))]
"mak_mask_p (INTVAL (operands[3]) >> INTVAL (operands[2]))"
"*
{
operands[4] = gen_rtx (CONST_INT, SImode,
exact_log2 (1 + (INTVAL (operands[3])
>> INTVAL(operands[2]))));
return \"mak %0,%1,%4<%2>\";
}"
[(set_attr "type" "bit")])
;; Optimize possible cases of output_and.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashift:SI (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "int5_operand" "")
(match_operand:SI 3 "int5_operand" ""))
(match_operand:SI 4 "int5_operand" "")))]
"INTVAL (operands[2]) + INTVAL (operands[3]) + INTVAL (operands[4]) == 32"
"*
{
operands[2]
= gen_rtx (CONST_INT, SImode,
((1 << INTVAL (operands[2])) - 1) << INTVAL (operands[4]));
return output_and (operands);
}"
[(set_attr "type" "marith")]) ; arith,bit,marith. length is 1 or 2.
;; Improve logical operations on compare words
;;
;; We define all logical operations on CCmode values to preserve the pairwise
;; relationship of the compare bits. This allows a future branch prediction
;; pass the degree of freedom needed to change and/bb0-le into or/bb1-gt.
;; THIS IS CURRENTLY FALSE!
;;
;; Opportunities arise when conditional expressions using && and || are made
;; unconditional. When these are used to branch, the sequence is
;; cmp/cmp/extu/extu/{and,or}/bcnd-{eq0,ne0}. When these are used to create
;; a value, the sequence is cmp/cmp/extu/extu/{and,or} for 1 or 0 or
;; cmp/cmp/ext/ext/{and,or} for -1 or 0.
;;
;; When the extracted conditions are the same, the define_split patterns
;; below change extu/extu/{and,or} into {and,or}/extu. If the reversed
;; conditions match, one compare word can be complimented, resulting in
;; {and.c,or.c}/extu. These changes are done for ext/ext/{and,or} as well.
;; If the conditions don't line up, one can be rotated. To keep the pairwise
;; relationship, it may be necessary to both rotate and compliment. Rotating
;; makes branching cheaper, but doesn't help (or hurt) creating a value, so
;; we don't do this for ext/ext/{and,or}.
;;
;; These changes result in the sequence extu/bcnd-{eq0,ne0} which is combined
;; into an alternate form of bb0 and bb1.
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (neg:SI
(match_operator 1 "even_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)]))
(neg:SI
(match_operator 3 "relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)]))))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
""
[(set (match_dup 5)
(ior:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(neg:SI (match_op_dup 1 [(match_dup 5) (const_int 0)])))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
if (GET_CODE (operands[1]) == GET_CODE (operands[3]))
; /* The conditions match. */
else if (GET_CODE (operands[1])
== reverse_condition (GET_CODE (operands[3])))
/* Reverse the condition by complimenting the compare word. */
operands[4] = gen_rtx (NOT, CCmode, operands[4]);
else
{
/* Make the condition pairs line up by rotating the compare word. */
int cv1 = condition_value (operands[1]);
int cv2 = condition_value (operands[3]);
operands[4] = gen_rtx (ROTATE, CCmode, operands[4],
gen_rtx (CONST_INT, VOIDmode,
((cv2 & ~1) - (cv1 & ~1)) & 0x1f));
/* Reverse the condition if needed. */
if ((cv1 & 1) != (cv2 & 1))
operands[4] = gen_rtx (NOT, CCmode, operands[4]);
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (neg:SI
(match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)]))
(neg:SI
(match_operator 3 "odd_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)]))))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
""
[(set (match_dup 5)
(and:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(neg:SI (match_op_dup 1 [(match_dup 5) (const_int 0)])))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
if (GET_CODE (operands[1]) == GET_CODE (operands[3]))
; /* The conditions match. */
else
{
/* Make the condition pairs line up by rotating the compare word. */
int cv1 = condition_value (operands[1]);
int cv2 = condition_value (operands[3]);
operands[4] = gen_rtx (ROTATE, CCmode, operands[4],
gen_rtx (CONST_INT, VOIDmode,
(cv2 - cv1) & 0x1f));
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (neg:SI
(match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)]))
(neg:SI
(match_operator 3 "even_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)]))))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
""
[(set (match_dup 5)
(ior:CCEVEN (not:CC (match_dup 2))
(match_dup 4)))
(set (match_dup 0)
(neg:SI (match_op_dup 3 [(match_dup 5) (const_int 0)])))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
if (GET_CODE (operands[1])
== reverse_condition (GET_CODE (operands[3])))
;
else
{
/* Make the condition pairs line up by rotating the compare word. */
int cv1 = condition_value (operands[1]);
int cv2 = condition_value (operands[3]);
operands[2] = gen_rtx (ROTATE, CCmode, operands[2],
gen_rtx (CONST_INT, VOIDmode,
((cv1 & ~1) - (cv2 & ~1)) & 0x1f));
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operator 1 "even_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)])
(match_operator 3 "relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
"GET_CODE (operands[1]) == GET_CODE (operands[3])
|| GET_CODE (operands[1]) == reverse_condition (GET_CODE (operands[3]))"
[(set (match_dup 5)
(ior:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(match_op_dup 1 [(match_dup 5) (const_int 0)]))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
/* Reverse the condition by complimenting the compare word. */
if (GET_CODE (operands[1]) != GET_CODE (operands[3]))
operands[4] = gen_rtx (NOT, CCmode, operands[4]);")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)])
(match_operator 3 "odd_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
"GET_CODE (operands[1]) == GET_CODE (operands[3])"
[(set (match_dup 5)
(and:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(match_op_dup 1 [(match_dup 5) (const_int 0)]))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)])
(match_operator 3 "even_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
"GET_CODE (operands[1]) == reverse_condition (GET_CODE (operands[3]))"
[(set (match_dup 5)
(ior:CCEVEN (not:CC (match_dup 4))
(match_dup 2)))
(set (match_dup 0)
(match_op_dup 1 [(match_dup 5) (const_int 0)]))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (neg:SI
(match_operator 1 "even_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)]))
(neg:SI
(match_operator 3 "relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)]))))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
""
[(set (match_dup 5)
(and:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(neg:SI (match_op_dup 1 [(match_dup 5) (const_int 0)])))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
if (GET_CODE (operands[1]) == GET_CODE (operands[3]))
; /* The conditions match. */
else if (GET_CODE (operands[1])
== reverse_condition (GET_CODE (operands[3])))
/* Reverse the condition by complimenting the compare word. */
operands[4] = gen_rtx (NOT, CCmode, operands[4]);
else
{
/* Make the condition pairs line up by rotating the compare word. */
int cv1 = condition_value (operands[1]);
int cv2 = condition_value (operands[3]);
operands[4] = gen_rtx (ROTATE, CCmode, operands[4],
gen_rtx (CONST_INT, VOIDmode,
((cv2 & ~1) - (cv1 & ~1)) & 0x1f));
/* Reverse the condition if needed. */
if ((cv1 & 1) != (cv2 & 1))
operands[4] = gen_rtx (NOT, CCmode, operands[4]);
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (neg:SI
(match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)]))
(neg:SI
(match_operator 3 "odd_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)]))))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
""
[(set (match_dup 5)
(ior:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(neg:SI (match_op_dup 1 [(match_dup 5) (const_int 0)])))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
if (GET_CODE (operands[1]) == GET_CODE (operands[3]))
; /* The conditions match. */
else
{
/* Make the condition pairs line up by rotating the compare word. */
int cv1 = condition_value (operands[1]);
int cv2 = condition_value (operands[3]);
operands[4] = gen_rtx (ROTATE, CCmode, operands[4],
gen_rtx (CONST_INT, VOIDmode,
(cv2 - cv1) & 0x1f));
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (neg:SI
(match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)]))
(neg:SI
(match_operator 3 "even_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)]))))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
""
[(set (match_dup 5)
(and:CCEVEN (not:CC (match_dup 2))
(match_dup 4)))
(set (match_dup 0)
(neg:SI (match_op_dup 3 [(match_dup 5) (const_int 0)])))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
if (GET_CODE (operands[1])
== reverse_condition (GET_CODE (operands[3])))
;
else
{
/* Make the condition pairs line up by rotating the compare word. */
int cv1 = condition_value (operands[1]);
int cv2 = condition_value (operands[3]);
operands[2] = gen_rtx (ROTATE, CCmode, operands[2],
gen_rtx (CONST_INT, VOIDmode,
((cv1 & ~1) - (cv2 & ~1)) & 0x1f));
}")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operator 1 "even_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)])
(match_operator 3 "relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
"GET_CODE (operands[1]) == GET_CODE (operands[3])
|| GET_CODE (operands[1]) == reverse_condition (GET_CODE (operands[3]))"
[(set (match_dup 5)
(and:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(match_op_dup 1 [(match_dup 5) (const_int 0)]))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);
/* Reverse the condition by complimenting the compare word. */
if (GET_CODE (operands[1]) != GET_CODE (operands[3]))
operands[4] = gen_rtx (NOT, CCmode, operands[4]);")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)])
(match_operator 3 "odd_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
"GET_CODE (operands[1]) == GET_CODE (operands[3])"
[(set (match_dup 5)
(ior:CCEVEN (match_dup 4)
(match_dup 2)))
(set (match_dup 0)
(match_op_dup 1 [(match_dup 5) (const_int 0)]))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);")
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (match_operator 1 "odd_relop"
[(match_operand 2 "partial_ccmode_register_operand" "%r")
(const_int 0)])
(match_operator 3 "even_relop"
[(match_operand 4 "partial_ccmode_register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 5 "register_operand" "=r"))]
"GET_CODE (operands[1]) == reverse_condition (GET_CODE (operands[3]))"
[(set (match_dup 5)
(and:CCEVEN (not:CC (match_dup 2))
(match_dup 4)))
(set (match_dup 0)
(match_op_dup 3 [(match_dup 5) (const_int 0)]))]
"operands[5] = gen_rtx(SUBREG, CCEVENmode, operands[5], 0);")
;; Logical operations on compare words.
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(and:CCEVEN (not:CC (match_operand 1 "partial_ccmode_register_operand" "r"))
(match_operand 2 "partial_ccmode_register_operand" "r")))]
""
"and.c %0,%2,%1")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(and:CCEVEN (match_operand 1 "partial_ccmode_register_operand" "%r")
(match_operand 2 "partial_ccmode_register_operand" "r")))]
""
"and %0,%1,%2")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(ior:CCEVEN (not:CC (match_operand 1 "partial_ccmode_register_operand" "r"))
(match_operand 2 "partial_ccmode_register_operand" "r")))]
""
"or.c %0,%2,%1")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(ior:CCEVEN (match_operand 1 "partial_ccmode_register_operand" "%r")
(match_operand 2 "partial_ccmode_register_operand" "r")))]
""
"or %0,%1,%2")
(define_insn ""
[(set (match_operand:CC 0 "register_operand" "=r")
(rotate:CC (match_operand:CC 1 "register_operand" "r")
(match_operand:CC 2 "int5_operand" "")))]
""
"rot %0,%1,%2"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" "")))]
""
"rot %0,%1,%2"
[(set_attr "type" "bit")])
;; rotate/and[.c] and rotate/ior[.c]
(define_split
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(ior:CCEVEN (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" ""))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_operand:CCEVEN 4 "register_operand" "=r"))]
""
[(set (match_dup 4)
(rotate:CC (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(ior:CCEVEN (match_dup 4) (match_dup 3)))]
"")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(ior:CC (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" ""))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_scratch:CCEVEN 4 "=r"))]
""
"#")
(define_split
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(ior:CCEVEN (not:CC (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" "")))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_operand:CCEVEN 4 "register_operand" "=r"))]
""
[(set (match_dup 4)
(rotate:CC (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(ior:CCEVEN (not:CC (match_dup 4)) (match_dup 3)))]
"")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(ior:CCEVEN (not:CC (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" "")))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_scratch:CCEVEN 4 "=r"))]
""
"#")
(define_split
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(and:CCEVEN (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" ""))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_operand:CCEVEN 4 "register_operand" "=r"))]
""
[(set (match_dup 4)
(rotate:CC (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(and:CCEVEN (match_dup 4) (match_dup 3)))]
"")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(and:CCEVEN (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" ""))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_scratch:CCEVEN 4 "=r"))]
""
"#")
(define_split
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(and:CCEVEN (not:CC (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" "")))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_operand:CCEVEN 4 "register_operand" "=r"))]
""
[(set (match_dup 4)
(rotate:CC (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(and:CCEVEN (not:CC (match_dup 4)) (match_dup 3)))]
"")
(define_insn ""
[(set (match_operand:CCEVEN 0 "register_operand" "=r")
(and:CCEVEN (not:CC (rotate:CC (match_operand 1 "partial_ccmode_register_operand" "r")
(match_operand:CC 2 "int5_operand" "")))
(match_operand 3 "partial_ccmode_register_operand" "r")))
(clobber (match_scratch:CCEVEN 4 "=r"))]
""
"#")
;; Recognize bcnd instructions for integer values. This is distinguished
;; from a conditional branch instruction (below) with SImode instead of
;; CCmode.
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "relop_no_unsigned"
[(match_operand:SI 1 "register_operand" "r")
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%B0,%1,%P2%P3"
[(set_attr "type" "branch")])
;; Recognize tests for sign and zero.
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "equality_op"
[(match_operand:SI 1 "register_operand" "r")
(const_int -2147483648)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%E0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "equality_op"
[(zero_extract:SI
(match_operand:SI 1 "register_operand" "r")
(const_int 31)
(const_int 1))
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%D0,%1,%P2%P3"
[(set_attr "type" "branch")])
;; Recognize bcnd instructions for double integer values
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "relop_no_unsigned"
[(sign_extend:DI
(match_operand:SI 1 "register_operand" "r"))
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%B0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "equality_op"
[(zero_extend:DI
(match_operand:SI 1 "register_operand" "r"))
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%B0,%1,%P2%P3"
[(set_attr "type" "branch")])
; @@ I doubt this is interesting until cmpdi is provided. Anyway, it needs
; to be reworked.
;
;(define_insn ""
; [(set (pc)
; (if_then_else
; (match_operator 0 "relop_no_unsigned"
; [(match_operand:DI 1 "register_operand" "r")
; (const_int 0)])
; (match_operand 2 "pc_or_label_ref" "")
; (match_operand 3 "pc_or_label_ref" "")))]
; ""
; "*
;{
; switch (GET_CODE (operands[0]))
; {
; case EQ:
; case NE:
; /* I'm not sure if it's safe to use .n here. */
; return \"or %!,%1,%d1\;bcnd %R3%B0,%!,%P2%P3\";
; case GE:
; case LT:
; return \"bcnd%. %R3%B0,%1,%P2%P3\";
; case GT:
; {
; rtx op2 = operands[2];
; operands[2] = operands[3];
; operands[3] = op2;
; }
; case LE:
; if (GET_CODE (operands[3]) == LABEL_REF)
; {
; int label_num;
; operands[2] = gen_label_rtx ();
; label_num = XINT (operands[2], 3);
; output_asm_insn
; (\"bcnd%. %#lt0,%1,%2\;or %!,%1,%d1\;bcnd %#ne0,%!,%3\", operands);
; output_label (label_num);
; return \"\";
; }
; else
; return \"bcnd%. %#lt0,%1,%2\;or %!,%1,%d1\;bcnd %#eq0,%!,%2\";
; }
;}")
;; Recognize bcnd instructions for single precision float values
;; Exclude relational operations as they must signal NaNs.
;; @@ These bcnd insns for float and double values don't seem to be recognized.
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "equality_op"
[(float_extend:DF
(match_operand:SF 1 "register_operand" "r"))
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%D0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "equality_op"
[(match_operand:SF 1 "register_operand" "r")
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bcnd%. %R3%D0,%1,%P2%P3"
[(set_attr "type" "branch")])
;; Recognize bcnd instructions for double precision float values
;; Exclude relational operations as they must signal NaNs.
(define_insn ""
[(set (pc)
(if_then_else
(match_operator 0 "equality_op"
[(match_operand:DF 1 "register_operand" "r")
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"*
{
int label_num;
if (GET_CODE (operands[0]) == NE)
{
rtx op2 = operands[2];
operands[2] = operands[3];
operands[3] = op2;
}
if (GET_CODE (operands[3]) == LABEL_REF)
return \"bcnd 0x5,%1,%3\;bcnd %#ne0,%d1,%3\";
operands[3] = gen_label_rtx ();
label_num = XINT (operands[3], 3);
output_asm_insn (\"bcnd 0x5,%1,%3\;bcnd %#eq0,%d1,%2\", operands);
output_label (label_num);
return \"\";
}"
[(set_attr "type" "weird")
(set_attr "length" "3")])
;; Recognize bb0 and bb1 instructions. These use two unusual template
;; patterns, %Lx and %Px. %Lx outputs a 1 if operand `x' is a LABEL_REF
;; otherwise it outputs a 0. It then may print ".n" if the delay slot
;; is used. %Px does noting if `x' is PC and outputs the operand if `x'
;; is a LABEL_REF.
(define_insn ""
[(set (pc)
(if_then_else
(ne (sign_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "int5_operand" ""))
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L2 (31-%1),%0,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(eq (sign_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "int5_operand" ""))
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L3 (31-%1),%0,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(ne (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "int5_operand" ""))
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L2 (31-%1),%0,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(eq (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
(const_int 1)
(match_operand:SI 1 "int5_operand" ""))
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L3 (31-%1),%0,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(eq (and:SI (match_operand:SI 0 "reg_or_bbx_mask_operand" "%r")
(match_operand:SI 1 "reg_or_bbx_mask_operand" "n"))
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
"(GET_CODE (operands[0]) == CONST_INT)
!= (GET_CODE (operands[1]) == CONST_INT)"
"bb%L3 %p1,%0,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(ne (and:SI (match_operand:SI 0 "reg_or_bbx_mask_operand" "%r")
(match_operand:SI 1 "reg_or_bbx_mask_operand" "n"))
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
"(GET_CODE (operands[0]) == CONST_INT)
!= (GET_CODE (operands[1]) == CONST_INT)"
"bb%L2 %p1,%0,%P2%P3"
[(set_attr "type" "branch")])
;; The comparison operations store the comparison into a register and
;; record that register. The following Bxx or Sxx insn uses that
;; register as an input. To facilitate use of bcnd instead of cmp/bb1,
;; cmpsi records it's operands and produces no code when any operand
;; is constant. In this case, the Bxx insns use gen_bcnd and the
;; Sxx insns use gen_test to ensure a cmp has been emitted.
;;
;; This could also be done for SFmode and DFmode having only beq and bne
;; use gen_bcnd. The others must signal NaNs. It seems though that zero
;; has already been copied into a register.
;;
;; cmpsi/beq and cmpsi/bne can always be done with bcnd if any operand
;; is a constant. (This idea is due to Torbjorn Granlund.) Others can
;; use bcnd only if an operand is zero.
;;
;; It is necessary to distinguish a register holding condition codes.
;; This is done by context.
(define_expand "test"
[(set (match_dup 2)
(compare:CC (match_operand 0 "" "")
(match_operand 1 "" "")))]
""
"
{
if (m88k_compare_reg)
abort ();
if (GET_CODE (operands[0]) == CONST_INT
&& ! SMALL_INT (operands[0]))
operands[0] = force_reg (SImode, operands[0]);
if (GET_CODE (operands[1]) == CONST_INT
&& ! SMALL_INT (operands[1]))
operands[1] = force_reg (SImode, operands[1]);
operands[2] = m88k_compare_reg = gen_reg_rtx (CCmode);
}")
; @@ The docs say don't do this. It's probably a nop since the insn looks
; identical to cmpsi against zero. Is there an advantage to providing
; this, perhaps with a different form?
;(define_expand "tstsi"
; [(set (match_dup 1)
; (compare:CC (match_operand:SI 0 "register_operand" "")
; (const_int 0)))]
; ""
; "
;{
; m88k_compare_reg = 0;
; m88k_compare_op0 = operands[0];
; m88k_compare_op1 = const0_rtx;
; DONE;
;}")
(define_expand "cmpsi"
[(set (match_dup 2)
(compare:CC (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[0]) == CONST_INT
|| GET_CODE (operands[1]) == CONST_INT)
{
m88k_compare_reg = 0;
m88k_compare_op0 = operands[0];
m88k_compare_op1 = operands[1];
DONE;
}
operands[2] = m88k_compare_reg = gen_reg_rtx (CCmode);
}")
(define_expand "cmpsf"
[(set (match_dup 2)
(compare:CC (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "register_operand" "")))]
""
"operands[2] = m88k_compare_reg = gen_reg_rtx (CCmode);")
(define_expand "cmpdf"
[(set (match_dup 2)
(compare:CC (match_operand:DF 0 "general_operand" "")
(match_operand:DF 1 "general_operand" "")))]
""
"
{
operands[0] = legitimize_operand (operands[0], DFmode);
operands[1] = legitimize_operand (operands[1], DFmode);
operands[2] = m88k_compare_reg = gen_reg_rtx (CCmode);
}")
; @@ Get back to this later on.
;
;(define_insn "cmpdi"
; [(set (cc0)
; (compare:CC (match_operand:DI 0 "register_operand" "r")
; (match_operand:DI 1 "register_operand" "r")))]
; ""
; "*
;{
; if ((cc_status.mdep & MDEP_LS_CHANGE) != 0)
; abort (); /* output_move_double MDEP_LS_CHANGE bits were set. */
;
; cc_status.mdep &= ~ MDEP_LS_MASK;
;
; operands[2] = gen_label_rtx ();
; /* Remember, %! is the condition code register and %@ is the
; literal synthesis register. */
;
; output_asm_insn (\"cmp %!,%0,%1\;bb0 %#eq,%!,%l2\;cmp %!,%d0,%d1\",
; operands);
;
; output_asm_insn (\"extu %@,%!,4<8>\;clr %!,%!,4<4>\", operands);
; output_asm_insn (\"mak %@,%@,4<4>\;or %!,%!,%@\", operands);
; output_label (XINT (operands[2], 3));
; return \"\";
;}"
;; The actual compare instructions.
(define_insn ""
[(set (match_operand:CC 0 "register_operand" "=r")
(compare:CC (match_operand:SI 1 "register_operand" "rO")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"cmp %0,%r1,%2")
(define_insn ""
[(set (match_operand:CC 0 "register_operand" "=r,r,r,r")
(compare:CC (match_operand:SF 1 "register_operand" "r,r,x,x")
(match_operand:SF 2 "real_or_0_operand" "r,G,x,G")))]
""
"@
fcmp.sss %0,%1,%2
fcmp.sss %0,%1,%#r0
fcmp.sss %0,%1,%2
fcmp.sss %0,%1,%#x0"
[(set_attr "type" "spcmp")])
(define_insn ""
[(set (match_operand:CC 0 "register_operand" "=r,r")
(compare:CC (match_operand:DF 1 "register_operand" "r,x")
(float_extend:DF
(match_operand:SF 2 "register_operand" "r,x"))))]
""
"fcmp.sds %0,%1,%2"
[(set_attr "type" "dpcmp")])
(define_insn ""
[(set (match_operand:CC 0 "register_operand" "=r,r")
(compare:CC (float_extend:DF
(match_operand:SF 1 "register_operand" "r,x"))
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fcmp.ssd %0,%1,%2"
[(set_attr "type" "dpcmp")])
(define_insn ""
[(set (match_operand:CC 0 "register_operand" "=r,r,r,r")
(compare:CC (match_operand:DF 1 "register_operand" "r,r,x,x")
(match_operand:DF 2 "real_or_0_operand" "r,G,x,G")))]
""
"@
fcmp.sdd %0,%1,%2
fcmp.sds %0,%1,%#r0
fcmp.sdd %0,%1,%2
fcmp.sds %0,%1,%#x0"
[(set_attr "type" "dpcmp")])
;; Store condition code insns. The compare insns set a register
;; rather than cc0 and record that register for use here. See above
;; for the special treatment of cmpsi with a constant operand.
;; @@ For the m88110, use fcmpu for bxx sxx inequality comparisons.
(define_expand "seq"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (EQ, SImode);")
(define_expand "sne"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (NE, SImode);")
(define_expand "sgt"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (GT, SImode);")
(define_expand "sgtu"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (GTU, SImode);")
(define_expand "slt"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (LT, SImode);")
(define_expand "sltu"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (LTU, SImode);")
(define_expand "sge"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (GE, SImode);")
(define_expand "sgeu"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (GEU, SImode);")
(define_expand "sle"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (LE, SImode);")
(define_expand "sleu"
[(set (match_operand:SI 0 "register_operand" "")
(match_dup 1))]
""
"operands[1] = emit_test (LEU, SImode);")
;; The actual set condition code instruction.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "relop"
[(match_operand:CC 2 "register_operand" "r")
(const_int 0)]))]
""
"ext %0,%2,1<%C1>"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "even_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)]))]
""
"ext %0,%2,1<%C1>"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operator:SI 1 "odd_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)])))]
""
"ext %0,%2,1<%!%C1>"
[(set_attr "type" "bit")])
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "odd_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)]))
(clobber (match_operand:SI 3 "register_operand" "=r"))]
""
[(set (match_dup 3) (not:SI (match_op_dup 1 [(match_dup 2) (const_int 0)])))
(set (match_dup 0) (not:SI (match_dup 3)))]
"")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operator:SI 1 "odd_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)]))
(clobber (match_scratch:SI 3 "=r"))]
""
"#")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI
(match_operator:SI 1 "relop"
[(match_operand:CC 2 "register_operand" "r")
(const_int 0)])))]
""
"extu %0,%2,1<%C1>"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI
(match_operator:SI 1 "even_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)])))]
""
"extu %0,%2,1<%C1>"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI
(not:SI (match_operator:SI 1 "odd_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)]))))]
""
"extu %0,%2,1<%!%C1>"
[(set_attr "type" "bit")])
(define_split
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operator:SI 1 "odd_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)])))
(clobber (match_operand:SI 3 "register_operand" "=r"))]
""
[(set (match_dup 3) (neg:SI (not:SI (match_op_dup 1 [(match_dup 2)
(const_int 0)]))))
(set (match_dup 0) (xor:SI (match_dup 3) (const_int 1)))]
"")
(define_insn
""
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operator:SI 1 "odd_relop"
[(match_operand:CCEVEN 2 "register_operand" "r")
(const_int 0)])))
(clobber (match_scratch:SI 3 "=r"))]
""
"#")
;; Conditional branch insns. The compare insns set a register
;; rather than cc0 and record that register for use here. See above
;; for the special case of cmpsi with a constant operand.
(define_expand "bcnd"
[(set (pc)
(if_then_else (match_operand 0 "" "")
(label_ref (match_operand 1 "" ""))
(pc)))]
""
"if (m88k_compare_reg) abort ();")
(define_expand "bxx"
[(set (pc)
(if_then_else (match_operand 0 "" "")
(label_ref (match_operand 1 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0) abort ();")
(define_expand "beq"
[(set (pc)
(if_then_else (eq (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_bcnd (EQ, operands[0]);
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bne"
[(set (pc)
(if_then_else (ne (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_bcnd (NE, operands[0]);
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bgt"
[(set (pc)
(if_then_else (gt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_bcnd (GT, operands[0]);
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bgtu"
[(set (pc)
(if_then_else (gtu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_jump_insn (gen_bxx (emit_test (GTU, VOIDmode), operands[0]));
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "blt"
[(set (pc)
(if_then_else (lt (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_bcnd (LT, operands[0]);
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bltu"
[(set (pc)
(if_then_else (ltu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_jump_insn (gen_bxx (emit_test (LTU, VOIDmode), operands[0]));
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bge"
[(set (pc)
(if_then_else (ge (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_bcnd (GE, operands[0]);
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bgeu"
[(set (pc)
(if_then_else (geu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_jump_insn (gen_bxx (emit_test (GEU, VOIDmode), operands[0]));
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "ble"
[(set (pc)
(if_then_else (le (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_bcnd (LE, operands[0]);
DONE;
}
operands[1] = m88k_compare_reg;")
(define_expand "bleu"
[(set (pc)
(if_then_else (leu (match_dup 1) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"if (m88k_compare_reg == 0)
{
emit_jump_insn (gen_bxx (emit_test (LEU, VOIDmode), operands[0]));
DONE;
}
operands[1] = m88k_compare_reg;")
;; The actual conditional branch instruction (both directions). This
;; uses two unusual template patterns, %Rx and %Px. %Rx is a prefix code
;; for the immediately following condition and reverses the condition iff
;; operand `x' is a LABEL_REF. %Px does nothing if `x' is PC and outputs
;; the operand if `x' is a LABEL_REF.
(define_insn ""
[(set (pc) (if_then_else
(match_operator 0 "relop"
[(match_operand:CC 1 "register_operand" "r")
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"*
{
if (mostly_false_jump (insn, operands[0]))
return \"bb0%. %R2%C0,%1,%P2%P3\";
else
return \"bb1%. %R3%C0,%1,%P2%P3\";
}"
[(set_attr "type" "branch")])
;;
;; Here branch prediction is sacrificed. To get it back, you need
;; - CCODD (CC mode where the ODD bits are valid)
;; - several define_split that can apply De Morgan's Law.
;; - transformations between CCEVEN and CCODD modes.
;;
(define_insn ""
[(set (pc) (if_then_else
(match_operator 0 "even_relop"
[(match_operand:CCEVEN 1 "register_operand" "r")
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L2%. %C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc) (if_then_else
(match_operator 0 "odd_relop"
[(match_operand:CCEVEN 1 "register_operand" "r")
(const_int 0)])
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L3%. %!%C0,%1,%P2%P3"
[(set_attr "type" "branch")])
;; Branch conditional on scc values. These arise from manipulations on
;; compare words above.
;; Are these really used ?
(define_insn ""
[(set (pc)
(if_then_else
(ne (match_operator 0 "relop"
[(match_operand:CC 1 "register_operand" "r")
(const_int 0)])
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L2 %C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(ne (match_operator 0 "even_relop"
[(match_operand:CCEVEN 1 "register_operand" "r")
(const_int 0)])
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L2 %C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(ne (match_operator 0 "odd_relop"
[(match_operand:CCEVEN 1 "register_operand" "r")
(const_int 0)])
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L3 %!%C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(eq (match_operator 0 "relop"
[(match_operand:CC 1 "register_operand" "r")
(const_int 0)])
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L3 %C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(eq (match_operator 0 "even_relop"
[(match_operand:CCEVEN 1 "register_operand" "r")
(const_int 0)])
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L3 %C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else
(eq (match_operator 0 "odd_relop"
[(match_operand:CCEVEN 1 "register_operand" "r")
(const_int 0)])
(const_int 0))
(match_operand 2 "pc_or_label_ref" "")
(match_operand 3 "pc_or_label_ref" "")))]
""
"bb%L2 %!%C0,%1,%P2%P3"
[(set_attr "type" "branch")])
(define_insn "locate1"
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (unspec:SI [(label_ref (match_operand 1 "" ""))] 0)))]
""
"or.u %0,%#r0,%#hi16(%1#abdiff)")
(define_insn "locate2"
[(parallel [(set (reg:SI 1) (pc))
(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_dup 0)
(unspec:SI
[(label_ref (match_operand 1 "" ""))] 0)))])]
""
"bsr.n %1\;or %0,%0,%#lo16(%1#abdiff)\\n%1:"
[(set_attr "length" "2")])
;; SImode move instructions
(define_expand "movsi"
[(set (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, SImode, 0))
DONE;
}")
(define_expand "reload_insi"
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "general_operand" ""))
(clobber (match_operand:SI 2 "register_operand" "=&r"))]
""
"
{
if (emit_move_sequence (operands, SImode, operands[2]))
DONE;
/* We don't want the clobber emitted, so handle this ourselves. */
emit_insn (gen_rtx (SET, VOIDmode, operands[0], operands[1]));
DONE;
}")
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m,r,r,r,x,x,x,m")
(match_operand:SI 1 "move_operand" "rI,m,rO,J,M,x,r,x,m,x"))]
"(register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
|| operands[1] == const0_rtx)"
"@
or %0,%#r0,%1
%V1ld\\t %0,%1
%v0st\\t %r1,%0
subu %0,%#r0,%n1
set %0,%#r0,%s1
mov.s %0,%1
mov.s %0,%1
mov %0,%1
%V1ld\\t %0,%1
%v0st\\t %1,%0"
[(set_attr "type" "arith,load,store,arith,bit,mov,mov,mov,load,store")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
(match_operand:SI 1 "arith32_operand" "rI,J,L,M,n"))]
""
"@
or %0,%#r0,%1
subu %0,%#r0,%n1
or.u %0,%#r0,%X1
set %0,%#r0,%s1
or.u %0,%#r0,%X1\;or %0,%0,%x1"
[(set_attr "type" "arith,arith,arith,bit,marith")])
;; @@ Why the constraint "in"? Doesn't `i' include `n'?
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")))]
""
"or %0,%1,%#lo16(%g2)")
;; For PIC, symbol_refs are put inside unspec so that the optimizer won't
;; confuse them with real addresses.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(unspec:SI [(match_operand:SI 2 "immediate_operand" "in")] 0)))]
""
"or %0,%1,%#lo16(%g2)"
;; Need to set length for this arith insn because operand2
;; is not an "arith_operand".
[(set_attr "length" "1")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (match_operand 1 "" "")))]
""
"or.u %0,%#r0,%#hi16(%g1)")
;; For PIC, symbol_refs are put inside unspec so that the optimizer won't
;; confuse them with real addresses.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (unspec:SI [(match_operand 1 "" "")] 0)))]
""
"or.u %0,%#r0,%#hi16(%g1)"
;; Need to set length for this arith insn because operand2
;; is not an arith_operand.
[(set_attr "length" "1")])
;; HImode move instructions
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, HImode, 0))
DONE;
}")
(define_insn ""
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r")
(match_operand:HI 1 "move_operand" "rP,m,rO,N"))]
"(register_operand (operands[0], HImode)
|| register_operand (operands[1], HImode)
|| operands[1] == const0_rtx)"
"@
or %0,%#r0,%h1
%V1ld.hu\\t %0,%1
%v0st.h\\t %r1,%0
subu %0,%#r0,%H1"
[(set_attr "type" "arith,load,store,arith")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(subreg:HI (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")) 0))]
"!flag_pic"
"or %0,%1,%#lo16(%2)")
;; QImode move instructions
(define_expand "movqi"
[(set (match_operand:QI 0 "general_operand" "")
(match_operand:QI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, QImode, 0))
DONE;
}")
(define_insn ""
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m,r")
(match_operand:QI 1 "move_operand" "rP,m,rO,N"))]
"(register_operand (operands[0], QImode)
|| register_operand (operands[1], QImode)
|| operands[1] == const0_rtx)"
"@
or %0,%#r0,%q1
%V1ld.bu\\t %0,%1
%v0st.b\\t %r1,%0
subu %r0,%#r0,%Q1"
[(set_attr "type" "arith,load,store,arith")])
(define_insn ""
[(set (match_operand:QI 0 "register_operand" "=r")
(subreg:QI (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")) 0))]
"!flag_pic"
"or %0,%1,%#lo16(%2)")
;; DImode move instructions
(define_expand "movdi"
[(set (match_operand:DI 0 "general_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, DImode, 0))
DONE;
}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r,x")
(const_int 0))]
""
"@
or %0,%#r0,0\;or %d0,%#r0,0
mov %0,%#x0"
[(set_attr "type" "marith,mov")])
(define_insn ""
[(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,x,x,x,m")
(match_operand:DI 1 "nonimmediate_operand" "r,m,r,x,r,x,m,x"))]
""
"@
or %0,%#r0,%1\;or %d0,%#r0,%d1
%V1ld.d\\t %0,%1
%v0st.d\\t %1,%0
mov.d %0,%1
mov.d %0,%1
mov %0,%1
%V1ld.d\\t %0,%1
%v0st.d\\t %1,%0"
[(set_attr "type" "marith,loadd,store,mov,mov,mov,loadd,store")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(subreg:DI (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")) 0))]
"!flag_pic"
"or %0,%1,%#lo16(%2)")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(match_operand:DI 1 "immediate_operand" "n"))]
""
"* return output_load_const_dimode (operands);"
[(set_attr "type" "marith")
(set_attr "length" "4")]) ; length is 2, 3 or 4.
;; DFmode move instructions
(define_expand "movdf"
[(set (match_operand:DF 0 "general_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, DFmode, 0))
DONE;
}")
(define_split
[(set (match_operand:DF 0 "register_operand" "=r")
(match_operand:DF 1 "register_operand" "r"))]
"reload_completed
&& GET_CODE (operands[0]) == REG && !XRF_REGNO_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && !XRF_REGNO_P (REGNO (operands[1]))"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 4) (match_dup 5))]
"
{ 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); }")
;; @@ This pattern is incomplete and doesn't appear necessary.
;;
;; This pattern forces (set (reg:DF ...) (const_double ...))
;; to be reloaded by putting the constant into memory.
;; It must come before the more general movdf pattern.
;(define_insn ""
; [(set (match_operand:DF 0 "general_operand" "=r,o")
; (match_operand:DF 1 "" "G,G"))]
; "GET_CODE (operands[1]) == CONST_DOUBLE"
; "*
;{
; switch (which_alternative)
; {
; case 0:
; return \"or %0,%#r0,0\;or %d0,%#r0,0\";
; case 1:
; operands[1] = adj_offsettable_operand (operands[0], 4);
; return \"%v0st\\t %#r0,%0\;st %#r0,%1\";
; }
;}")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(const_int 0))]
""
"@
or %0,%#r0,0\;or %d0,%#r0,0
mov %0,%#x0"
[(set_attr "type" "marith,mov")])
(define_insn ""
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,x,r,x,x,m")
(match_operand:DF 1 "nonimmediate_operand" "r,m,r,r,x,x,m,x"))]
""
"@
or %0,%#r0,%1\;or %d0,%#r0,%d1
%V1ld.d\\t %0,%1
%v0st.d\\t %1,%0
mov.d %0,%1
mov.d %0,%1
mov %0,%1
%V1ld.d\\t %0,%1
%v0st.d\\t %1,%0"
[(set_attr "type" "marith,loadd,store,mov,mov,mov,loadd,store")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r")
(subreg:DF (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")) 0))]
"!flag_pic"
"or %0,%1,%#lo16(%2)")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r")
(match_operand:DF 1 "immediate_operand" "F"))]
""
"* return output_load_const_double (operands);"
[(set_attr "type" "marith")
(set_attr "length" "4")]) ; length is 2, 3, or 4.
;; SFmode move instructions
(define_expand "movsf"
[(set (match_operand:SF 0 "general_operand" "")
(match_operand:SF 1 "general_operand" ""))]
""
"
{
if (emit_move_sequence (operands, SFmode, 0))
DONE;
}")
;; @@ What happens to fconst0_rtx?
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=r,x")
(const_int 0))]
""
"@
or %0,%#r0,0
mov %0,%#x0"
[(set_attr "type" "arith,mov")])
(define_insn ""
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,x,r,x,x,m")
(match_operand:SF 1 "nonimmediate_operand" "r,m,r,r,x,x,m,x"))]
""
"@
or %0,%#r0,%1
%V1ld\\t %0,%1
%v0st\\t %r1,%0
mov.s %0,%1
mov.s %0,%1
mov %0,%1
%V1ld\\t %0,%1
%v0st\\t %r1,%0"
[(set_attr "type" "arith,load,store,mov,mov,mov,load,store")])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=r")
(subreg:SF (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "immediate_operand" "in")) 0))]
"!flag_pic"
"or %0,%1,%#lo16(%2)")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=r")
(match_operand:SF 1 "immediate_operand" "F"))]
"operands[1] != const0_rtx"
"* return output_load_const_float (operands);"
[(set_attr "type" "marith")]) ; length is 1 or 2.
;; String/block move insn. See m88k.c for details.
(define_expand "movstrsi"
[(parallel [(set (mem:BLK (match_operand:BLK 0 "" ""))
(mem:BLK (match_operand:BLK 1 "" "")))
(use (match_operand:SI 2 "arith32_operand" ""))
(use (match_operand:SI 3 "immediate_operand" ""))])]
""
"
{
rtx dest_mem = operands[0];
rtx src_mem = operands[1];
operands[0] = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
expand_block_move (dest_mem, src_mem, operands);
DONE;
}")
(define_insn ""
[(set (match_operand:QI 0 "register_operand" "=r")
(match_operand:BLK 1 "memory_operand" "m"))]
""
"%V1ld.bu\\t %0,%1"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r")
(match_operand:BLK 1 "memory_operand" "m"))]
""
"%V1ld.hu\\t %0,%1"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:BLK 1 "memory_operand" "m"))]
""
"%V1ld\\t %0,%1"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(match_operand:BLK 1 "memory_operand" "m"))]
""
"%V1ld.d\\t %0,%1"
[(set_attr "type" "loadd")])
(define_insn ""
[(set (match_operand:BLK 0 "memory_operand" "=m")
(match_operand:QI 1 "register_operand" "r"))]
""
"%v0st.b\\t %1,%0"
[(set_attr "type" "store")])
(define_insn ""
[(set (match_operand:BLK 0 "memory_operand" "=m")
(match_operand:HI 1 "register_operand" "r"))]
""
"%v0st.h\\t %1,%0"
[(set_attr "type" "store")])
(define_insn ""
[(set (match_operand:BLK 0 "memory_operand" "=m")
(match_operand:SI 1 "register_operand" "r"))]
""
"%v0st\\t %1,%0"
[(set_attr "type" "store")])
(define_insn ""
[(set (match_operand:BLK 0 "memory_operand" "=m")
(match_operand:DI 1 "register_operand" "r"))]
""
"%v0st.d\\t %1,%0"
[(set_attr "type" "store")])
;; Call a non-looping block move library function (e.g. __movstrSI96x64).
;; operand 0 is the function name
;; operand 1 is the destination pointer
;; operand 2 is the source pointer
;; operand 3 is the offset for the source and destination pointers
;; operand 4 is the first value to be loaded
;; operand 5 is the register to hold the value (r4 or r5)
(define_expand "call_block_move"
[(set (reg:SI 3) (minus:SI (match_operand:SI 2 "register_operand" "")
(match_operand:SI 3 "immediate_operand" "")))
(set (match_operand 5 "register_operand" "")
(match_operand 4 "memory_operand" ""))
(set (reg:SI 2) (minus:SI (match_operand:SI 1 "register_operand" "")
(match_dup 3)))
(use (reg:SI 2))
(use (reg:SI 3))
(use (match_dup 5))
(parallel [(set (reg:DI 2)
(call (mem:SI (match_operand 0 "" ""))
(const_int 0)))
(clobber (reg:SI 1))])]
""
"")
;; Call an SImode looping block move library function (e.g. __movstrSI64n68).
;; operands 0-5 as in the non-looping interface
;; operand 6 is the loop count
(define_expand "call_movstrsi_loop"
[(set (reg:SI 3) (minus:SI (match_operand:SI 2 "register_operand" "")
(match_operand:SI 3 "immediate_operand" "")))
(set (match_operand:SI 5 "register_operand" "")
(match_operand 4 "memory_operand" ""))
(set (reg:SI 2) (minus:SI (match_operand:SI 1 "register_operand" "")
(match_dup 3)))
(set (reg:SI 6) (match_operand:SI 6 "immediate_operand" ""))
(use (reg:SI 2))
(use (reg:SI 3))
(use (match_dup 5))
(use (reg:SI 6))
(parallel [(set (reg:DI 2)
(call (mem:SI (match_operand 0 "" ""))
(const_int 0)))
(clobber (reg:SI 1))])]
""
"")
;;- zero extension instructions
(define_expand "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& symbolic_address_p (XEXP (operands[1], 0)))
operands[1]
= legitimize_address (flag_pic, operands[1], 0, 0);
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(zero_extend:SI (match_operand:HI 1 "move_operand" "!r,n,m")))]
"GET_CODE (operands[1]) != CONST_INT"
"@
mask %0,%1,0xffff
or %0,%#r0,%h1
%V1ld.hu\\t %0,%1"
[(set_attr "type" "arith,arith,load")])
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& symbolic_address_p (XEXP (operands[1], 0)))
operands[1]
= legitimize_address (flag_pic, operands[1], 0, 0);
}")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r,r,r")
(zero_extend:HI (match_operand:QI 1 "move_operand" "r,n,m")))]
"GET_CODE (operands[1]) != CONST_INT"
"@
mask %0,%1,0xff
or %0,%#r0,%q1
%V1ld.bu\\t %0,%1"
[(set_attr "type" "arith,arith,load")])
(define_expand "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& symbolic_address_p (XEXP (operands[1], 0)))
{
operands[1]
= legitimize_address (flag_pic, operands[1], 0, 0);
emit_insn (gen_rtx (SET, VOIDmode, operands[0],
gen_rtx (ZERO_EXTEND, SImode, operands[1])));
DONE;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(zero_extend:SI (match_operand:QI 1 "move_operand" "r,n,m")))]
"GET_CODE (operands[1]) != CONST_INT"
"@
mask %0,%1,0xff
or %0,%#r0,%q1
%V1ld.bu\\t %0,%1"
[(set_attr "type" "arith,arith,load")])
;;- sign extension instructions
(define_expand "extendsidi2"
[(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1)
(match_operand:SI 1 "general_operand" "g"))
(set (subreg:SI (match_dup 0) 0)
(ashiftrt:SI (subreg:SI (match_dup 0) 1)
(const_int 31)))]
""
"")
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& symbolic_address_p (XEXP (operands[1], 0)))
operands[1]
= legitimize_address (flag_pic, operands[1], 0, 0);
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(sign_extend:SI (match_operand:HI 1 "move_operand" "!r,P,N,m")))]
"GET_CODE (operands[1]) != CONST_INT"
"@
ext %0,%1,16<0>
or %0,%#r0,%h1
subu %0,%#r0,%H1
%V1ld.h\\t %0,%1"
[(set_attr "type" "bit,arith,arith,load")])
(define_expand "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& symbolic_address_p (XEXP (operands[1], 0)))
operands[1]
= legitimize_address (flag_pic, operands[1], 0, 0);
}")
(define_insn ""
[(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
(sign_extend:HI (match_operand:QI 1 "move_operand" "!r,P,N,m")))]
"GET_CODE (operands[1]) != CONST_INT"
"@
ext %0,%1,8<0>
or %0,%#r0,%q1
subu %0,%#r0,%Q1
%V1ld.b\\t %0,%1"
[(set_attr "type" "bit,arith,arith,load")])
(define_expand "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& symbolic_address_p (XEXP (operands[1], 0)))
operands[1]
= legitimize_address (flag_pic, operands[1], 0, 0);
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(sign_extend:SI (match_operand:QI 1 "move_operand" "!r,P,N,m")))]
"GET_CODE (operands[1]) != CONST_INT"
"@
ext %0,%1,8<0>
or %0,%#r0,%q1
subu %0,%#r0,%Q1
%V1ld.b\\t %0,%1"
[(set_attr "type" "bit,arith,arith,load")])
;; Conversions between float and double.
;; The fadd instruction does not conform to IEEE 754 when used to
;; convert between float and double. In particular, the sign of -0 is
;; not preserved. Interestingly, fsub does conform.
(define_expand "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=r")
(float_extend:DF (match_operand:SF 1 "register_operand" "r")))]
""
"")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r")
(float_extend:DF (match_operand:SF 1 "register_operand" "r")))]
"! TARGET_88110"
"fsub.dss %0,%1,%#r0"
[(set_attr "type" "spadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(float_extend:DF (match_operand:SF 1 "register_operand" "r,x")))]
"TARGET_88110"
"fcvt.ds %0,%1"
[(set_attr "type" "spadd")])
(define_expand "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(float_truncate:SF (match_operand:DF 1 "register_operand" "r")))]
""
"")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=r")
(float_truncate:SF (match_operand:DF 1 "register_operand" "r")))]
"! TARGET_88110"
"fsub.sds %0,%1,%#r0"
[(set_attr "type" "dpadd")])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=r,x")
(float_truncate:SF (match_operand:DF 1 "register_operand" "r,x")))]
"TARGET_88110"
"fcvt.sd %0,%1"
[(set_attr "type" "dpadd")])
;; Conversions between floating point and integer
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=r,x")
(float:DF (match_operand:SI 1 "register_operand" "r,r")))]
""
"flt.ds %0,%1"
[(set_attr "type" "spadd,dpadd")])
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=r,x")
(float:SF (match_operand:SI 1 "register_operand" "r,r")))]
""
"flt.ss %0,%1"
[(set_attr "type" "spadd,spadd")])
(define_insn "fix_truncdfsi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(fix:SI (match_operand:DF 1 "register_operand" "r,x")))]
""
"trnc.sd %0,%1"
[(set_attr "type" "dpadd,dpadd")])
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(fix:SI (match_operand:SF 1 "register_operand" "r,x")))]
""
"trnc.ss %0,%1"
[(set_attr "type" "spadd,dpadd")])
;;- arithmetic instructions
;;- add instructions
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(plus:SI (match_operand:SI 1 "add_operand" "%r,r")
(match_operand:SI 2 "add_operand" "rI,J")))]
""
"@
addu %0,%1,%2
subu %0,%1,%n2")
;; patterns for mixed mode floating point.
;; Do not define patterns that utilize mixed mode arithmetic that result
;; in narrowing the precision, because it loses accuracy, since the standard
;; requires double rounding, whereas the 88000 instruction only rounds once.
(define_expand "adddf3"
[(set (match_operand:DF 0 "register_operand" "=r,x")
(plus:DF (match_operand:DF 1 "general_operand" "%r,x")
(match_operand:DF 2 "general_operand" "r,x")))]
""
"
{
operands[1] = legitimize_operand (operands[1], DFmode);
operands[2] = legitimize_operand (operands[2], DFmode);
}")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(plus:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fadd.dss %0,%1,%2"
[(set_attr "type" "spadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(plus:DF (match_operand:DF 1 "register_operand" "r,x")
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fadd.dds %0,%1,%2"
[(set_attr "type" "dpadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(plus:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fadd.dsd %0,%1,%2"
[(set_attr "type" "dpadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(plus:DF (match_operand:DF 1 "register_operand" "%r,x")
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fadd.ddd %0,%1,%2"
[(set_attr "type" "dpadd")])
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=r,x")
(plus:SF (match_operand:SF 1 "register_operand" "%r,x")
(match_operand:SF 2 "register_operand" "r,x")))]
""
"fadd.sss %0,%1,%2"
[(set_attr "type" "spadd")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_operand:DI 1 "register_operand" "r")
(zero_extend:DI
(match_operand:SI 2 "register_operand" "r"))))
(clobber (reg:CC 0))]
""
"addu.co %d0,%d1,%2\;addu.ci %0,%1,%#r0"
[(set_attr "type" "marith")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (zero_extend:DI
(match_operand:SI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:CC 0))]
""
"addu.co %d0,%1,%d2\;addu.ci %0,%#r0,%2"
[(set_attr "type" "marith")])
(define_insn "adddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_operand:DI 1 "register_operand" "%r")
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:CC 0))]
""
"addu.co %d0,%d1,%d2\;addu.ci %0,%1,%2"
[(set_attr "type" "marith")])
;; Add with carry insns.
(define_insn ""
[(parallel [(set (match_operand:SI 0 "reg_or_0_operand" "=r")
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "rO")
(match_operand:SI 2 "reg_or_0_operand" "rO")))
(set (reg:CC 0)
(unspec:CC [(match_dup 1) (match_dup 2)] 0))])]
""
"addu.co %r0,%r1,%r2")
(define_insn ""
[(set (reg:CC 0) (unspec:CC [(match_operand:SI 0 "reg_or_0_operand" "rO")
(match_operand:SI 1 "reg_or_0_operand" "rO")]
0))]
""
"addu.co %#r0,%r0,%r1")
(define_insn ""
[(set (match_operand:SI 0 "reg_or_0_operand" "=r")
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "rO")
(unspec:SI [(match_operand:SI 2 "reg_or_0_operand" "rO")
(reg:CC 0)] 0)))]
""
"addu.ci %r0,%r1,%r2")
;;- subtract instructions
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(minus:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith32_operand" "rI")))]
""
"subu %0,%1,%2")
;; patterns for mixed mode floating point
;; Do not define patterns that utilize mixed mode arithmetic that result
;; in narrowing the precision, because it loses accuracy, since the standard
;; requires double rounding, whereas the 88000 instruction only rounds once.
(define_expand "subdf3"
[(set (match_operand:DF 0 "register_operand" "=r,x")
(minus:DF (match_operand:DF 1 "general_operand" "r,x")
(match_operand:DF 2 "general_operand" "r,x")))]
""
"
{
operands[1] = legitimize_operand (operands[1], DFmode);
operands[2] = legitimize_operand (operands[2], DFmode);
}")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(minus:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fsub.dss %0,%1,%2"
[(set_attr "type" "spadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(minus:DF (match_operand:DF 1 "register_operand" "r,x")
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fsub.dds %0,%1,%2"
[(set_attr "type" "dpadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(minus:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fsub.dsd %0,%1,%2"
[(set_attr "type" "dpadd")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(minus:DF (match_operand:DF 1 "register_operand" "r,x")
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fsub.ddd %0,%1,%2"
[(set_attr "type" "dpadd")])
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=r,x")
(minus:SF (match_operand:SF 1 "register_operand" "r,x")
(match_operand:SF 2 "register_operand" "r,x")))]
""
"fsub.sss %0,%1,%2"
[(set_attr "type" "spadd")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "register_operand" "r")
(zero_extend:DI
(match_operand:SI 2 "register_operand" "r"))))
(clobber (reg:CC 0))]
""
"subu.co %d0,%d1,%2\;subu.ci %0,%1,%#r0"
[(set_attr "type" "marith")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (zero_extend:DI
(match_operand:SI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:CC 0))]
""
"subu.co %d0,%1,%d2\;subu.ci %0,%#r0,%2"
[(set_attr "type" "marith")])
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "register_operand" "r")))
(clobber (reg:CC 0))]
""
"subu.co %d0,%d1,%d2\;subu.ci %0,%1,%2"
[(set_attr "type" "marith")])
;; Subtract with carry insns.
(define_insn ""
[(parallel [(set (match_operand:SI 0 "reg_or_0_operand" "=r")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rO")
(match_operand:SI 2 "reg_or_0_operand" "rO")))
(set (reg:CC 0)
(unspec:CC [(match_dup 1) (match_dup 2)] 1))])]
""
"subu.co %r0,%r1,%r2")
(define_insn ""
[(set (reg:CC 0) (unspec:CC [(match_operand:SI 0 "reg_or_0_operand" "rO")
(match_operand:SI 1 "reg_or_0_operand" "rO")]
1))]
""
"subu.co %#r0,%r0,%r1")
(define_insn ""
[(set (match_operand:SI 0 "reg_or_0_operand" "=r")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rO")
(unspec:SI [(match_operand:SI 2 "reg_or_0_operand" "rO")
(reg:CC 0)] 1)))]
""
"subu.ci %r0,%r1,%r2")
;;- multiply instructions
;;
;; There is an unfounded silicon eratta for E.1 requiring that an
;; immediate constant value in div/divu/mul instructions be less than
;; 0x800. This is no longer provided for.
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(mult:SI (match_operand:SI 1 "arith32_operand" "%r")
(match_operand:SI 2 "arith32_operand" "rI")))]
""
"mul %0,%1,%2"
[(set_attr "type" "imul")])
(define_insn "umulsidi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%r"))
(zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
"TARGET_88110"
"mulu.d %0,%1,%2"
[(set_attr "type" "imul")])
;; patterns for mixed mode floating point
;; Do not define patterns that utilize mixed mode arithmetic that result
;; in narrowing the precision, because it loses accuracy, since the standard
;; requires double rounding, whereas the 88000 instruction only rounds once.
(define_expand "muldf3"
[(set (match_operand:DF 0 "register_operand" "=r,x")
(mult:DF (match_operand:DF 1 "general_operand" "%r,x")
(match_operand:DF 2 "general_operand" "r,x")))]
""
"
{
operands[1] = legitimize_operand (operands[1], DFmode);
operands[2] = legitimize_operand (operands[2], DFmode);
}")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fmul.dss %0,%1,%2"
[(set_attr "type" "spmul")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(mult:DF (match_operand:DF 1 "register_operand" "r,x")
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fmul.dds %0,%1,%2"
[(set_attr "type" "spmul")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fmul.dsd %0,%1,%2"
[(set_attr "type" "spmul")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(mult:DF (match_operand:DF 1 "register_operand" "%r,x")
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fmul.ddd %0,%1,%2"
[(set_attr "type" "dpmul")])
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=r,x")
(mult:SF (match_operand:SF 1 "register_operand" "%r,x")
(match_operand:SF 2 "register_operand" "r,x")))]
""
"fmul.sss %0,%1,%2"
[(set_attr "type" "spmul")])
;;- divide instructions
;;
;; The 88k div and divu instructions don't reliably trap on
;; divide-by-zero. A trap to vector 503 asserts divide-by-zero. The
;; general scheme for doing divide is to do a 4-way split based on the
;; sign of the two operand and do the appropriate negates.
;;
;; The conditional trap instruction is not used as this serializes the
;; processor. Instead a conditional branch and an unconditional trap
;; are used, but after the divu. Since the divu takes up to 38 cycles,
;; the conditional branch is essentially free.
;;
;; Two target options control how divide is done. One options selects
;; whether to do the branch and negate scheme instead of using the div
;; instruction; the other option selects whether to explicitly check
;; for divide-by-zero or take your chances. If the div instruction is
;; used, the O/S must complete the operation if the operands are
;; negative. The O/S will signal an overflow condition if the most
;; negative number (-214783648) is divided by negative 1.
;;
;; There is an unfounded silicon eratta for E.1 requiring that an
;; immediate constant value in div/divu/mul instructions be less than
;; 0x800. This is no longer provided for.
;; Division by 0 trap
(define_insn "trap_divide_by_zero"
[(trap_if (const_int 1) 503)]
""
"tb0 0,%#r0,503"
[(set_attr "type" "weird")])
;; Conditional division by 0 trap.
(define_expand "tcnd_divide_by_zero"
[(set (pc)
(if_then_else (eq (match_operand:SI 0 "register_operand" "")
(const_int 0))
(pc)
(match_operand 1 "" "")))
(trap_if (const_int 1) 503)]
""
"
{
emit_insn (gen_cmpsi (operands[0], const0_rtx));
emit_jump_insn (gen_bne (operands[1]));
emit_insn (gen_trap_divide_by_zero ());
DONE;
}")
(define_expand "divsi3"
[(set (match_operand:SI 0 "register_operand" "")
(div:SI (match_operand:SI 1 "arith32_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
rtx op0 = operands[0];
rtx op1 = operands[1];
rtx op2 = operands[2];
rtx join_label;
/* @@ This needs to be reworked. Torbjorn Granlund has suggested making
it a runtime (perhaps quite special). */
if (GET_CODE (op1) == CONST_INT)
op1 = force_reg (SImode, op1);
else if (GET_CODE (op2) == CONST_INT
&& ! SMALL_INT (operands[2]))
op2 = force_reg (SImode, op2);
if (op2 == const0_rtx)
{
emit_insn (gen_trap_divide_by_zero ());
emit_insn (gen_dummy (op0));
DONE;
}
if (TARGET_USE_DIV)
{
emit_move_insn (op0, gen_rtx (DIV, SImode, op1, op2));
if (TARGET_CHECK_ZERO_DIV && GET_CODE (op2) != CONST_INT)
{
rtx label = gen_label_rtx ();
emit_insn (gen_tcnd_divide_by_zero (op2, label));
emit_label (label);
emit_insn (gen_dummy (op0));
}
DONE;
}
join_label = gen_label_rtx ();
if (GET_CODE (op1) == CONST_INT)
{
int neg = FALSE;
rtx neg_op2 = gen_reg_rtx (SImode);
rtx label1 = gen_label_rtx ();
if (INTVAL (op1) < 0)
{
neg = TRUE;
op1 = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op1));
}
op1 = force_reg (SImode, op1);
emit_insn (gen_negsi2 (neg_op2, op2));
emit_insn (gen_cmpsi (op2, const0_rtx));
emit_jump_insn (gen_bgt (label1));
/* constant / 0-or-negative */
emit_move_insn (op0, gen_rtx (UDIV, SImode, op1, neg_op2));
if (!neg)
emit_insn (gen_negsi2 (op0, op0));
if (TARGET_CHECK_ZERO_DIV)
emit_insn (gen_tcnd_divide_by_zero (op2, join_label));
emit_jump_insn (gen_jump (join_label));
emit_barrier ();
emit_label (label1); /* constant / positive */
emit_move_insn (op0, gen_rtx (UDIV, SImode, op1, op2));
if (neg)
emit_insn (gen_negsi2 (op0, op0));
}
else if (GET_CODE (op2) == CONST_INT)
{
int neg = FALSE;
rtx neg_op1 = gen_reg_rtx (SImode);
rtx label1 = gen_label_rtx ();
if (INTVAL (op2) < 0)
{
neg = TRUE;
op2 = gen_rtx (CONST_INT, VOIDmode, -INTVAL (op2));
}
else if (! SMALL_INT (operands[2]))
op2 = force_reg (SImode, op2);
emit_insn (gen_negsi2 (neg_op1, op1));
emit_insn (gen_cmpsi (op1, const0_rtx));
emit_jump_insn (gen_bge (label1));
/* 0-or-negative / constant */
emit_move_insn (op0, gen_rtx (UDIV, SImode, neg_op1, op2));
if (!neg)
emit_insn (gen_negsi2 (op0, op0));
emit_jump_insn (gen_jump (join_label));
emit_barrier ();
emit_label (label1); /* positive / constant */
emit_move_insn (op0, gen_rtx (UDIV, SImode, op1, op2));
if (neg)
emit_insn (gen_negsi2 (op0, op0));
}
else
{
rtx neg_op1 = gen_reg_rtx (SImode);
rtx neg_op2 = gen_reg_rtx (SImode);
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
rtx label3 = gen_label_rtx ();
rtx label4;
emit_insn (gen_negsi2 (neg_op2, op2));
emit_insn (gen_cmpsi (op2, const0_rtx));
emit_jump_insn (gen_bgt (label1));
emit_insn (gen_negsi2 (neg_op1, op1));
emit_insn (gen_cmpsi (op1, const0_rtx));
emit_jump_insn (gen_bge (label2));
/* negative / negative-or-0 */
emit_move_insn (op0, gen_rtx (UDIV, SImode, neg_op1, neg_op2));
if (TARGET_CHECK_ZERO_DIV)
{
label4 = gen_label_rtx ();
emit_insn (gen_cmpsi (op2, const0_rtx));
emit_jump_insn (gen_bne (join_label));
emit_label (label4);
emit_insn (gen_trap_divide_by_zero ());
}
emit_jump_insn (gen_jump (join_label));
emit_barrier ();
emit_label (label2); /* pos.-or-0 / neg.-or-0 */
emit_move_insn (op0, gen_rtx (UDIV, SImode, op1, neg_op2));
if (TARGET_CHECK_ZERO_DIV)
{
emit_insn (gen_cmpsi (op2, const0_rtx));
emit_jump_insn (gen_beq (label4));
}
emit_insn (gen_negsi2 (op0, op0));
emit_jump_insn (gen_jump (join_label));
emit_barrier ();
emit_label (label1);
emit_insn (gen_negsi2 (neg_op1, op1));
emit_insn (gen_cmpsi (op1, const0_rtx));
emit_jump_insn (gen_bge (label3));
/* negative / positive */
emit_move_insn (op0, gen_rtx (UDIV, SImode, neg_op1, op2));
emit_insn (gen_negsi2 (op0, op0));
emit_jump_insn (gen_jump (join_label));
emit_barrier ();
emit_label (label3); /* positive-or-0 / positive */
emit_move_insn (op0, gen_rtx (UDIV, SImode, op1, op2));
}
emit_label (join_label);
emit_insn (gen_dummy (op0));
DONE;
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(div:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"div %0,%1,%2"
[(set_attr "type" "idiv")])
(define_expand "udivsi3"
[(set (match_operand:SI 0 "register_operand" "")
(udiv:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
rtx op2 = operands[2];
if (op2 == const0_rtx)
{
emit_insn (gen_trap_divide_by_zero ());
emit_insn (gen_dummy (operands[0]));
DONE;
}
else if (GET_CODE (op2) != CONST_INT && TARGET_CHECK_ZERO_DIV)
{
rtx label = gen_label_rtx ();
emit_insn (gen_rtx (SET, VOIDmode, operands[0],
gen_rtx (UDIV, SImode, operands[1], op2)));
emit_insn (gen_tcnd_divide_by_zero (op2, label));
emit_label (label);
emit_insn (gen_dummy (operands[0]));
DONE;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(udiv:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith32_operand" "rI")))]
"operands[2] != const0_rtx"
"divu %0,%1,%2"
[(set_attr "type" "idiv")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(udiv:SI (match_operand:SI 1 "register_operand" "r")
(const_int 0)))]
""
"tb0 0,%#r0,503"
[(set_attr "type" "weird")])
;; patterns for mixed mode floating point.
;; Do not define patterns that utilize mixed mode arithmetic that result
;; in narrowing the precision, because it loses accuracy, since the standard
;; requires double rounding, whereas the 88000 instruction only rounds once.
(define_expand "divdf3"
[(set (match_operand:DF 0 "register_operand" "=r,x")
(div:DF (match_operand:DF 1 "general_operand" "r,x")
(match_operand:DF 2 "general_operand" "r,x")))]
""
"
{
operands[1] = legitimize_operand (operands[1], DFmode);
if (real_power_of_2_operand (operands[2]))
{
union real_extract u;
bcopy (&CONST_DOUBLE_LOW (operands[2]), &u, sizeof u);
emit_insn (gen_muldf3 (operands[0], operands[1],
CONST_DOUBLE_FROM_REAL_VALUE (1.0/u.d, DFmode)));
DONE;
}
else if (! register_operand (operands[2], DFmode))
operands[2] = force_reg (DFmode, operands[2]);
}")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(div:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fdiv.dss %0,%1,%2"
[(set_attr "type" "dpdiv")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(div:DF (match_operand:DF 1 "register_operand" "r,x")
(float_extend:DF (match_operand:SF 2 "register_operand" "r,x"))))]
""
"fdiv.dds %0,%1,%2"
[(set_attr "type" "dpdiv")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(div:DF (float_extend:DF (match_operand:SF 1 "register_operand" "r,x"))
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fdiv.dsd %0,%1,%2"
[(set_attr "type" "dpdiv")])
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=r,x")
(div:SF (match_operand:SF 1 "register_operand" "r,x")
(match_operand:SF 2 "register_operand" "r,x")))]
""
"fdiv.sss %0,%1,%2"
[(set_attr "type" "spdiv")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=r,x")
(div:DF (match_operand:DF 1 "register_operand" "r,x")
(match_operand:DF 2 "register_operand" "r,x")))]
""
"fdiv.ddd %0,%1,%2"
[(set_attr "type" "dpdiv")])
;; - remainder instructions, don't define, since the hardware doesn't have any
;; direct support, and GNU can synthesis them out of div/mul just fine.
;;- load effective address, must come after add, so that we favor using
;; addu reg,reg,reg instead of: lda reg,reg,reg (addu doesn't require
;; the data unit), and also future 88k chips might not support unscaled
;; lda instructions.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "address_operand" "p"))]
"m88k_gp_threshold > 0 && symbolic_address_p (operands[1])"
"addu %0,%a1")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:HI 1 "address_operand" "p"))]
""
"lda.h %0,%a1"
[(set_attr "type" "loada")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SI 1 "address_operand" "p"))]
""
"lda %0,%a1"
[(set_attr "type" "loada")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:DI 1 "address_operand" "p"))]
""
"lda.d %0,%a1"
[(set_attr "type" "loada")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:SF 1 "address_operand" "p"))]
""
"lda %0,%a1"
[(set_attr "type" "loada")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(match_operand:DF 1 "address_operand" "p"))]
""
"lda.d %0,%a1"
[(set_attr "type" "loada")])
;;- and instructions (with complement also)
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(and:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "r")))]
""
"and.c %0,%2,%1")
;; If the operation is being performed on a 32-bit constant such that
;; it cannot be done in one insn, do it in two. We may lose a bit on
;; CSE in pathological cases, but it seems better doing it this way.
(define_expand "andsi3"
[(set (match_operand:SI 0 "register_operand" "")
(and:SI (match_operand:SI 1 "arith32_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int value = INTVAL (operands[2]);
if (! (SMALL_INTVAL (value)
|| (value & 0xffff0000) == 0xffff0000
|| (value & 0xffff) == 0xffff
|| (value & 0xffff) == 0
|| integer_ok_for_set (~value)))
{
emit_insn (gen_andsi3 (operands[0], operands[1],
gen_rtx (CONST_INT, VOIDmode,
value | 0xffff)));
operands[1] = operands[0];
operands[2] = gen_rtx (CONST_INT, VOIDmode, value | 0xffff0000);
}
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r")
(and:SI (match_operand:SI 1 "arith32_operand" "%r,r")
(match_operand:SI 2 "arith32_operand" "rIJL,rn")))]
""
"* return output_and (operands);"
[(set_attr "type" "arith,marith")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))]
""
"and.c %d0,%d2,%d1\;and.c %0,%2,%1"
[(set_attr "type" "marith")])
(define_insn "anddi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (match_operand:DI 1 "arith64_operand" "%r")
(match_operand:DI 2 "arith64_operand" "rn")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = operand_subword (operands[0], 1, 0, DImode);
xoperands[1] = operand_subword (operands[1], 1, 0, DImode);
xoperands[2] = operand_subword (operands[2], 1, 0, DImode);
output_asm_insn (output_and (xoperands), xoperands);
operands[0] = operand_subword (operands[0], 0, 0, DImode);
operands[1] = operand_subword (operands[1], 0, 0, DImode);
operands[2] = operand_subword (operands[2], 0, 0, DImode);
return output_and (operands);
}"
[(set_attr "type" "marith")
(set_attr "length" "4")]) ; length is 2, 3, or 4.
;;- Bit set (inclusive or) instructions (with complement also)
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ior:SI (not:SI (match_operand:SI 1 "register_operand" "r"))
(match_operand:SI 2 "register_operand" "r")))]
""
"or.c %0,%2,%1")
(define_expand "iorsi3"
[(set (match_operand:SI 0 "register_operand" "")
(ior:SI (match_operand:SI 1 "arith32_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int value = INTVAL (operands[2]);
if (! (SMALL_INTVAL (value)
|| (value & 0xffff) == 0
|| integer_ok_for_set (value)))
{
emit_insn (gen_iorsi3 (operands[0], operands[1],
gen_rtx (CONST_INT, VOIDmode,
value & 0xffff0000)));
operands[1] = operands[0];
operands[2] = gen_rtx (CONST_INT, VOIDmode, value & 0xffff);
}
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
(ior:SI (match_operand:SI 1 "arith32_operand" "%r,r,r,r")
(match_operand:SI 2 "arith32_operand" "rI,L,M,n")))]
""
"@
or %0,%1,%2
or.u %0,%1,%X2
set %0,%1,%s2
or.u %0,%1,%X2\;or %0,%0,%x2"
[(set_attr "type" "arith,arith,bit,marith")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
(match_operand:DI 2 "register_operand" "r")))]
""
"or.c %d0,%d2,%d1\;or.c %0,%2,%1"
[(set_attr "type" "marith")])
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(ior:DI (match_operand:DI 1 "arith64_operand" "%r")
(match_operand:DI 2 "arith64_operand" "rn")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = operand_subword (operands[0], 1, 0, DImode);
xoperands[1] = operand_subword (operands[1], 1, 0, DImode);
xoperands[2] = operand_subword (operands[2], 1, 0, DImode);
output_asm_insn (output_ior (xoperands), xoperands);
operands[0] = operand_subword (operands[0], 0, 0, DImode);
operands[1] = operand_subword (operands[1], 0, 0, DImode);
operands[2] = operand_subword (operands[2], 0, 0, DImode);
return output_ior (operands);
}"
[(set_attr "type" "marith")
(set_attr "length" "4")]) ; length is 2, 3, or 4.
;;- xor instructions (with complement also)
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (xor:SI (match_operand:SI 1 "register_operand" "%r")
(match_operand:SI 2 "register_operand" "r"))))]
""
"xor.c %0,%1,%2")
(define_expand "xorsi3"
[(set (match_operand:SI 0 "register_operand" "")
(xor:SI (match_operand:SI 1 "arith32_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
int value = INTVAL (operands[2]);
if (! (SMALL_INTVAL (value)
|| (value & 0xffff) == 0))
{
emit_insn (gen_xorsi3 (operands[0], operands[1],
gen_rtx (CONST_INT, VOIDmode,
value & 0xffff0000)));
operands[1] = operands[0];
operands[2] = gen_rtx (CONST_INT, VOIDmode, value & 0xffff);
}
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r,r")
(xor:SI (match_operand:SI 1 "arith32_operand" "%r,r,r")
(match_operand:SI 2 "arith32_operand" "rI,L,n")))]
""
"@
xor %0,%1,%2
xor.u %0,%1,%X2
xor.u %0,%1,%X2\;xor %0,%0,%x2"
[(set_attr "type" "arith,arith,marith")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (xor:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "register_operand" "r"))))]
""
"xor.c %d0,%d1,%d2\;xor.c %0,%1,%2"
[(set_attr "type" "marith")])
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(xor:DI (match_operand:DI 1 "arith64_operand" "%r")
(match_operand:DI 2 "arith64_operand" "rn")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = operand_subword (operands[0], 1, 0, DImode);
xoperands[1] = operand_subword (operands[1], 1, 0, DImode);
xoperands[2] = operand_subword (operands[2], 1, 0, DImode);
output_asm_insn (output_xor (xoperands), xoperands);
operands[0] = operand_subword (operands[0], 0, 0, DImode);
operands[1] = operand_subword (operands[1], 0, 0, DImode);
operands[2] = operand_subword (operands[2], 0, 0, DImode);
return output_xor (operands);
}"
[(set_attr "type" "marith")
(set_attr "length" "4")]) ; length is 2, 3, or 4.
;;- ones complement instructions
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(not:SI (match_operand:SI 1 "register_operand" "r")))]
""
"xor.c %0,%1,%#r0")
(define_insn "one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (match_operand:DI 1 "register_operand" "r")))]
""
"xor.c %d0,%d1,%#r0\;xor.c %0,%1,%#r0"
[(set_attr "type" "marith")])
;; Optimized special cases of shifting.
;; Must precede the general case.
;; @@ What about HImode shifted by 8?
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24)))]
"! SCALED_ADDRESS_P (XEXP (operands[1], 0))"
"%V1ld.b\\t %0,%1"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 24)))]
"! SCALED_ADDRESS_P (XEXP (operands[1], 0))"
"%V1ld.bu\\t %0,%1"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 16)))]
"! SCALED_ADDRESS_P (XEXP (operands[1], 0))"
"%V1ld.h\\t %0,%1"
[(set_attr "type" "load")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (match_operand:SI 1 "memory_operand" "m")
(const_int 16)))]
"! SCALED_ADDRESS_P (XEXP (operands[1], 0))"
"%V1ld.hu\\t %0,%1"
[(set_attr "type" "load")])
;;- arithmetic shift instructions.
;; @@ Do the optimized patterns with -1 get used? Perhaps operand 1 should
;; be arith32_operand?
;; Use tbnd to support TARGET_TRAP_LARGE_SHIFT.
(define_insn "tbnd"
[(trap_if (gtu (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "arith_operand" "rI"))
7)]
""
"tbnd %r0,%1"
[(set_attr "type" "weird")])
;; Just in case the optimizer decides to fold away the test.
(define_insn ""
[(trap_if (const_int 1) 7)]
""
"tbnd %#r31,0"
[(set_attr "type" "weird")])
(define_expand "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "")
(ashift:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
if ((unsigned) INTVAL (operands[2]) > 31)
{
if (TARGET_TRAP_LARGE_SHIFT)
emit_insn (gen_tbnd (force_reg (SImode, operands[2]),
gen_rtx (CONST_INT, VOIDmode, 31)));
else
emit_move_insn (operands[0], const0_rtx);
DONE;
}
}
else if (TARGET_TRAP_LARGE_SHIFT)
emit_insn (gen_tbnd (operands[2], gen_rtx (CONST_INT, VOIDmode, 31)));
else if (TARGET_HANDLE_LARGE_SHIFT)
{
rtx reg = gen_reg_rtx (SImode);
emit_insn (gen_cmpsi (operands[2], gen_rtx (CONST_INT, VOIDmode, 31)));
emit_insn (gen_sleu (reg));
emit_insn (gen_andsi3 (reg, operands[1], reg));
operands[1] = reg;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ashift:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "arith5_operand" "r,K")))]
""
"@
mak %0,%1,%2
mak %0,%1,0<%2>"
[(set_attr "type" "bit")])
(define_expand "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
if ((unsigned) INTVAL (operands[2]) > 31)
{
if (TARGET_TRAP_LARGE_SHIFT)
{
emit_insn (gen_tbnd (force_reg (SImode, operands[2]),
gen_rtx (CONST_INT, VOIDmode, 31)));
DONE;
}
else
operands[2] = gen_rtx (CONST_INT, VOIDmode, 31);
}
}
else if (TARGET_TRAP_LARGE_SHIFT)
emit_insn (gen_tbnd (operands[2], gen_rtx (CONST_INT, VOIDmode, 31)));
else if (TARGET_HANDLE_LARGE_SHIFT)
{
rtx reg = gen_reg_rtx (SImode);
emit_insn (gen_cmpsi (operands[2], gen_rtx (CONST_INT, VOIDmode, 31)));
emit_insn (gen_sgtu (reg));
emit_insn (gen_iorsi3 (reg, operands[2], reg));
operands[2] = reg;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "arith5_operand" "r,K")))]
""
"@
ext %0,%1,%2
ext %0,%1,0<%2>"
[(set_attr "type" "bit")])
;;- logical shift instructions. Logical shift left becomes arithmetic
;; shift left.
(define_expand "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT)
{
if ((unsigned) INTVAL (operands[2]) > 31)
{
if (TARGET_TRAP_LARGE_SHIFT)
emit_insn (gen_tbnd (force_reg (SImode, operands[2]),
gen_rtx (CONST_INT, VOIDmode, 31)));
else
emit_move_insn (operands[0], const0_rtx);
DONE;
}
}
else if (TARGET_TRAP_LARGE_SHIFT)
emit_insn (gen_tbnd (operands[2], gen_rtx (CONST_INT, VOIDmode, 31)));
else if (TARGET_HANDLE_LARGE_SHIFT)
{
rtx reg = gen_reg_rtx (SImode);
emit_insn (gen_cmpsi (operands[2], gen_rtx (CONST_INT, VOIDmode, 31)));
emit_insn (gen_sleu (reg));
emit_insn (gen_andsi3 (reg, operands[1], reg));
operands[1] = reg;
}
}")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r,r")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
(match_operand:SI 2 "arith5_operand" "r,K")))]
""
"@
extu %0,%1,%2
extu %0,%1,0<%2>"
[(set_attr "type" "bit")])
;;- rotate instructions
(define_expand "rotlsi3"
[(set (match_operand:SI 0 "register_operand" "")
(rotatert:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith32_operand" "")))]
""
"
{
if (GET_CODE (operands[2]) == CONST_INT
&& (unsigned) INTVAL (operands[2]) >= 32)
operands[2] = gen_rtx (CONST_INT, VOIDmode,
(32 - INTVAL (operands[2])) % 32);
else
{
rtx op = gen_reg_rtx (SImode);
emit_insn (gen_negsi2 (op, operands[2]));
operands[2] = op;
}
}")
(define_insn "rotrsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
(rotatert:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "rI")))]
""
"rot %0,%1,%2"
[(set_attr "type" "bit")])
;; find first set.
;; The ff1 instruction searches from the most significant bit while ffs
;; searches from the least significant bit. The bit index and treatment of
;; zero also differ. This amazing sequence was discovered using the GNU
;; Superoptimizer.
(define_insn "ffssi2"
[(set (match_operand:SI 0 "register_operand" "=r,&r")
(ffs:SI (match_operand:SI 1 "register_operand" "0,r")))
(clobber (reg:CC 0))
(clobber (match_scratch:SI 2 "=r,X"))]
""
"@
subu.co %2,%#r0,%1\;and %2,%2,%1\;addu.ci %2,%2,%2\;ff1 %0,%2
subu.co %0,%#r0,%1\;and %0,%0,%1\;addu.ci %0,%0,%0\;ff1 %0,%0"
[(set_attr "type" "marith")
(set_attr "length" "4")])
;; Bit field instructions.
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")
(const_int 32)
(const_int 0)))]
""
"or %0,%#r0,%1")
(define_insn "extv"
[(set (match_operand:SI 0 "register_operand" "=r")
(sign_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "int5_operand" "")
(match_operand:SI 3 "int5_operand" "")))]
""
"*
{
operands[4] = gen_rtx (CONST_INT, SImode,
(32 - INTVAL (operands[2])) - INTVAL (operands[3]));
return \"ext %0,%1,%2<%4>\"; /* <(32-%2-%3)> */
}"
[(set_attr "type" "bit")])
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(const_int 32)
(const_int 0)))]
""
"or %0,%#r0,%1")
(define_insn "extzv"
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "int5_operand" "")
(match_operand:SI 3 "int5_operand" "")))]
""
"*
{
operands[4] = gen_rtx (CONST_INT, SImode,
(32 - INTVAL (operands[2])) - INTVAL (operands[3]));
return \"extu %0,%1,%2<%4>\"; /* <(32-%2-%3)> */
}"
[(set_attr "type" "bit")])
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
(match_operand:SI 1 "int5_operand" "")
(match_operand:SI 2 "int5_operand" ""))
(const_int 0))]
""
"*
{
operands[3] = gen_rtx (CONST_INT, SImode,
(32 - INTVAL (operands[1])) - INTVAL (operands[2]));
return \"clr %0,%0,%1<%3>\"; /* <(32-%1-%2)> */
}"
[(set_attr "type" "bit")])
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
(match_operand:SI 1 "int5_operand" "")
(match_operand:SI 2 "int5_operand" ""))
(const_int -1))]
""
"*
{
operands[3] = gen_rtx (CONST_INT, SImode,
(32 - INTVAL (operands[1])) - INTVAL (operands[2]));
return \"set %0,%0,%1<%3>\"; /* <(32-%1-%2)> */
}"
[(set_attr "type" "bit")])
(define_insn ""
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
(match_operand:SI 1 "int5_operand" "")
(match_operand:SI 2 "int5_operand" ""))
(match_operand:SI 3 "int32_operand" "n"))]
""
"*
{
int value = INTVAL (operands[3]);
if (INTVAL (operands[1]) < 32)
value &= (1 << INTVAL (operands[1])) - 1;
operands[2] = gen_rtx (CONST_INT, VOIDmode,
32 - (INTVAL(operands[1]) + INTVAL(operands[2])));
value <<= INTVAL (operands[2]);
operands[3] = gen_rtx (CONST_INT, VOIDmode, value);
if (SMALL_INTVAL (value))
return \"clr %0,%0,%1<%2>\;or %0,%0,%3\";
else if ((value & 0x0000ffff) == 0)
return \"clr %0,%0,%1<%2>\;or.u %0,%0,%X3\";
else
return \"clr %0,%0,%1<%2>\;or.u %0,%0,%X3\;or %0,%0,%x3\";
}"
[(set_attr "type" "marith")
(set_attr "length" "3")]) ; may be 2 or 3.
;; negate insns
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "arith_operand" "rI")))]
""
"subu %0,%#r0,%1")
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=r,x")
(float_truncate:SF (neg:DF (match_operand:DF 1 "register_operand" "r,x"))))]
""
"@
fsub.ssd %0,%#r0,%1
fsub.ssd %0,%#x0,%1"
[(set_attr "type" "dpadd")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=&r,r")
(neg:DF (match_operand:DF 1 "register_operand" "r,0")))]
""
"@
xor.u %0,%1,0x8000\;or %d0,%#r0,%d1
xor.u %0,%0,0x8000"
[(set_attr "type" "marith,arith")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(neg:SF (match_operand:SF 1 "register_operand" "r")))]
""
"xor.u %0,%1,0x8000")
;; absolute value insns for floating-point (integer abs can be done using the
;; machine-independent sequence).
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=&r,r")
(abs:DF (match_operand:DF 1 "register_operand" "r,0")))]
""
"@
and.u %0,%1,0x7fff\;or %d0,%#r0,%d1
and.u %0,%0,0x7fff"
[(set_attr "type" "marith,arith")])
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=r")
(abs:SF (match_operand:SF 1 "register_operand" "r")))]
""
"and.u %0,%1,0x7fff")
;; Subroutines of "casesi".
;; Operand 0 is index
;; operand 1 is the minimum bound
;; operand 2 is the maximum bound - minimum bound + 1
;; operand 3 is CODE_LABEL for the table;
;; operand 4 is the CODE_LABEL to go to if index out of range.
(define_expand "casesi"
;; We don't use these for generating the RTL, but we must describe
;; the operands here.
[(match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "immediate_operand" "")
(match_operand:SI 2 "immediate_operand" "")
(match_operand 3 "" "")
(match_operand 4 "" "")]
""
"
{
register rtx index_diff = gen_reg_rtx (SImode);
register rtx low = gen_rtx (CONST_INT, VOIDmode, -INTVAL (operands[1]));
register rtx label = gen_rtx (LABEL_REF, VOIDmode, operands[3]);
register rtx base;
if (! CASE_VECTOR_INSNS)
/* These instructions are likely to be scheduled and made loop invariant.
This decreases the cost of the dispatch at the expense of the default
case. */
base = force_reg (SImode, memory_address_noforce (SImode, label));
/* Compute the index difference and handle the default case. */
emit_insn (gen_addsi3 (index_diff,
force_reg (SImode, operands[0]),
ADD_INT (low) ? low : force_reg (SImode, low)));
emit_insn (gen_cmpsi (index_diff, operands[2]));
/* It's possible to replace this branch with sgtu/iorsi3 and adding a -1
entry to the table. However, that doesn't seem to win on the m88110. */
emit_jump_insn (gen_bgtu (operands[4]));
if (CASE_VECTOR_INSNS)
/* Call the jump that will branch to the appropriate case. */
emit_jump_insn (gen_casesi_enter (label, index_diff, operands[3]));
else
/* Load the table entry and jump to it. */
emit_jump_insn (gen_casesi_jump (gen_reg_rtx (SImode), base, index_diff));
/* Claim that flow drops into the table so it will be adjacent by not
emitting a barrier. */
DONE;
}")
(define_expand "casesi_jump"
[(set (match_operand:SI 0 "" "")
(mem:SI (plus:SI (match_operand:SI 1 "" "")
(mult:SI (match_operand:SI 2 "" "")
(const_int 4)))))
(set (pc) (match_dup 0))]
""
"")
;; The bsr.n instruction is directed to the END of the table. See
;; ASM_OUTPUT_CASE_END.
(define_insn "casesi_enter"
[(set (pc) (match_operand 0 "" ""))
(use (match_operand:SI 1 "register_operand" "r"))
;; The USE here is so that at least one jump-insn will refer to the label,
;; to keep it alive in jump_optimize.
(use (label_ref (match_operand 2 "" "")))
(clobber (reg:SI 1))]
""
"*
{
if (flag_delayed_branch)
return \"bsr.n %0e\;lda %#r1,%#r1[%1]\";
m88k_case_index = REGNO (operands[1]);
return \"bsr %0e\";
}"
[(set_attr "type" "weird")
(set_attr "length" "3")]) ; Including the "jmp r1".
;;- jump to subroutine
(define_expand "call"
[(parallel [(call (match_operand:SI 0 "" "")
(match_operand 1 "" ""))
(clobber (reg:SI 1))])]
""
"
{
if (GET_CODE (operands[0]) == MEM
&& ! call_address_operand (XEXP (operands[0], 0), SImode))
operands[0] = gen_rtx (MEM, GET_MODE (operands[0]),
force_reg (Pmode, XEXP (operands[0], 0)));
}")
(define_insn ""
[(parallel [(call (mem:SI (match_operand:SI 0 "call_address_operand" "rQ"))
(match_operand 1 "" ""))
(clobber (reg:SI 1))])]
""
"* return output_call (operands, operands[0]);"
[(set_attr "type" "call")])
(define_expand "call_value"
[(parallel [(set (match_operand 0 "register_operand" "")
(call (match_operand:SI 1 "" "")
(match_operand 2 "" "")))
(clobber (reg:SI 1))])]
""
"
{
if (GET_CODE (operands[1]) == MEM
&& ! call_address_operand (XEXP (operands[1], 0), SImode))
operands[1] = gen_rtx (MEM, GET_MODE (operands[1]),
force_reg (Pmode, XEXP (operands[1], 0)));
}")
(define_insn ""
[(parallel [(set (match_operand 0 "register_operand" "=r")
(call (mem:SI
(match_operand:SI 1 "call_address_operand" "rQ"))
(match_operand 2 "" "")))
(clobber (reg:SI 1))])]
""
"* return output_call (operands, operands[1]);"
[(set_attr "type" "call")])
;; Nop instruction and others
(define_insn "nop"
[(const_int 0)]
""
"ff0 %#r0,%#r0"
[(set_attr "type" "bit")])
(define_insn "return"
[(return)]
"reload_completed"
"jmp%. %#r1"
[(set_attr "type" "jump")])
(define_expand "prologue"
[(const_int 0)]
""
"m88k_expand_prologue (); DONE;")
(define_expand "epilogue"
[(return)]
"! null_prologue ()"
"m88k_expand_epilogue ();")
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 0)]
""
""
[(set_attr "length" "0")])
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "r"))]
""
"jmp%. %0"
[(set_attr "type" "jump")])
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"br%. %l0"
[(set_attr "type" "jump")])
;; This insn is used for some loop tests, typically loops reversed when
;; strength reduction is used. It is actually created when the instruction
;; combination phase combines the special loop test. Since this insn
;; is both a jump insn and has an output, it must deal with it's own
;; reloads, hence the `m' constraints. The `!' constraints direct reload
;; to not choose the register alternatives in the event a reload is needed.
(define_insn "decrement_and_branch_until_zero"
[(set (pc)
(if_then_else
(match_operator 0 "relop_no_unsigned"
[(match_operand:SI 1 "register_operand" "+!r,!r,m,m")
(const_int 0)])
(label_ref (match_operand 2 "" ""))
(pc)))
(set (match_dup 1)
(plus:SI (match_dup 1)
(match_operand:SI 3 "add_operand" "rI,J,rI,J")))
(clobber (match_scratch:SI 4 "=X,X,&r,&r"))
(clobber (match_scratch:SI 5 "=X,X,&r,&r"))]
"find_reg_note (insn, REG_NONNEG, 0)"
"@
bcnd.n %B0,%1,%2\;addu %1,%1,%3
bcnd.n %B0,%1,%2\;subu %1,%1,%n3
ld %4,%1\;addu %5,%4,%3\;bcnd.n %B0,%4,%2\;st %5,%1
ld %4,%1\;subu %5,%4,%n3\;bcnd.n %B0,%4,%2\;st %5,%1"
[(set_attr "type" "weird")
(set_attr "length" "2,2,4,4")])
;; Special insn to serve as the last insn of a define_expand. This insn
;; will generate no code.
(define_expand "dummy"
[(set (match_operand 0 "" "") (match_dup 0))]
""
"")