119 KiB
;;- Machine description for the Motorola 88000 for GNU C compiler ;;; Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. ;; Contributed by Michael Tiemann (tiemann@mcc.com) ;; Currently maintained by (gcc@dg-rtp.dg.com)
;; This file is part of GNU CC.
;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version.
;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA.
;;- 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.1.1.2.2.2> $"; 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 errata 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 (-2147483648) is divided by negative 1. ;; ;; There is an unfounded silicon errata 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, operands[3]));
/* 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))))) (parallel [(set (pc) (match_dup 0)) (use (label_ref (match_operand 3 "" "")))])] "" "")
(define_insn "" [(set (pc) (match_operand:SI 0 "register_operand" "r")) (use (label_ref (match_operand 1 "" "")))] "" "jmp%. %0" [(set_attr "type" "jump")])
;; 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_expand "decrement_and_branch_until_zero" [(parallel [(set (pc) (if_then_else (match_operator 0 "relop_no_unsigned" [(match_operand:SI 1 "register_operand" "") (const_int 0)]) (label_ref (match_operand 2 "" "")) (pc))) (set (match_dup 1) (plus:SI (match_dup 1) (match_operand:SI 3 "add_operand" ""))) (clobber (match_scratch:SI 4 "")) (clobber (match_scratch:SI 5 "=X,X,&r,&r"))])] "" "")
(define_insn "" [(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))] "" "")