996a5f59fb
From-SVN: r7016
4017 lines
118 KiB
Markdown
4017 lines
118 KiB
Markdown
;;- 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))]
|
||
""
|
||
"")
|