Files
2024-02-19 00:24:47 -05:00

3997 lines
113 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;; Mips.md Machine Description for MIPS based processors
;; Contributed by A. Lichnewsky, lich@inria.inria.fr
;; Changes by Michael Meissner, meissner@osf.org
;; Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
;; This file is part of GNU CC.
;; GNU CC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; GNU CC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU CC; see the file COPYING. If not, write to
;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;; ....................
;;
;; Attributes
;;
;; ....................
;; Classification of each insn.
;; branch conditional branch
;; jump unconditional jump
;; call unconditional call
;; load load instruction(s)
;; store store instruction(s)
;; move data movement within same register set
;; xfer transfer to/from coprocessor
;; hilo transfer of hi/lo registers
;; arith integer arithmetic instruction
;; darith double precision integer arithmetic instructions
;; imul integer multiply
;; idiv integer divide
;; icmp integer compare
;; fadd floating point add/subtract
;; fmul floating point multiply
;; fdiv floating point divide
;; fabs floating point absolute value
;; fneg floating point negation
;; fcmp floating point compare
;; fcvt floating point convert
;; fsqrt floating point square root
;; multi multiword sequence (or user asm statements)
;; nop no operation
;; pic OSF/rose half pic load
(define_attr "type"
"unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,idiv,icmp,fadd,fmul,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop,pic"
(const_string "unknown"))
;; Main data type used by the insn
(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF,FPSW" (const_string "unknown"))
;; # instructions (4 bytes each)
(define_attr "length" "" (const_int 1))
;; whether or not an instruction has a mandatory delay slot
(define_attr "dslot" "no,yes"
(if_then_else (eq_attr "type" "branch,jump,call,load,xfer,hilo,fcmp,pic")
(const_string "yes")
(const_string "no")))
;; Attribute describing the processor. This attribute must match exactly
;; with the processor_type enumeration in mips.h.
;; Attribute describing the processor
;; (define_attr "cpu" "default,r3000,r6000,r4000"
;; (const
;; (cond [(eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R3000")) (const_string "r3000")
;; (eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R4000")) (const_string "r4000")
;; (eq (symbol_ref "mips_cpu") (symbol_ref "PROCESSOR_R6000")) (const_string "r6000")]
;; (const_string "default"))))
(define_attr "cpu" "default,r3000,r6000,r4000"
(const (symbol_ref "mips_cpu_attr")))
;; Attribute defining whether or not we can use the branch-likely instructions
;; (MIPS ISA level 2)
(define_attr "branch_likely" "no,yes"
(const
(if_then_else (ge (symbol_ref "mips_isa") (const_int 2))
(const_string "yes")
(const_string "no"))))
;; Describe a user's asm statement.
(define_asm_attributes
[(set_attr "type" "multi")])
;; .........................
;;
;; Delay slots, can't describe load/fcmp/xfer delay slots here
;;
;; .........................
(define_delay (eq_attr "type" "branch")
[(and (eq_attr "dslot" "no") (eq_attr "length" "1"))
(nil)
(and (eq_attr "branch_likely" "yes") (and (eq_attr "dslot" "no") (eq_attr "length" "1")))])
(define_delay (eq_attr "type" "call,jump")
[(and (eq_attr "dslot" "no") (eq_attr "length" "1"))
(nil)
(nil)])
;; .........................
;;
;; Functional units
;;
;; .........................
; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
; TEST READY-DELAY BUSY-DELAY [CONFLICT-LIST])
;; Make the default case (PROCESSOR_DEFAULT) handle the worst case
(define_function_unit "memory" 1 0
(and (eq_attr "type" "load,pic") (eq_attr "cpu" "!r3000"))
3 0)
(define_function_unit "memory" 1 0
(and (eq_attr "type" "load,pic") (eq_attr "cpu" "r3000"))
2 0)
(define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0)
(define_function_unit "addr" 1 0 (eq_attr "type" "fcmp") 2 0)
(define_function_unit "memory" 1 0 (eq_attr "type" "xfer") 2 0)
(define_function_unit "memory" 1 0 (eq_attr "type" "hilo") 3 0)
(define_function_unit "imuldiv" 1 1
(and (eq_attr "type" "imul") (eq_attr "cpu" "!r3000,r4000"))
17 34)
(define_function_unit "imuldiv" 1 1
(and (eq_attr "type" "imul") (eq_attr "cpu" "r3000"))
12 24)
(define_function_unit "imuldiv" 1 1
(and (eq_attr "type" "imul") (eq_attr "cpu" "r4000"))
10 20)
(define_function_unit "imuldiv" 1 1
(and (eq_attr "type" "idiv") (eq_attr "cpu" "!r3000,r4000"))
38 76)
(define_function_unit "imuldiv" 1 1
(and (eq_attr "type" "idiv") (eq_attr "cpu" "r3000"))
35 70)
(define_function_unit "imuldiv" 1 1
(and (eq_attr "type" "idiv") (eq_attr "cpu" "r4000"))
69 138)
(define_function_unit "adder" 1 1
(and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r6000"))
4 8)
(define_function_unit "adder" 1 1
(and (eq_attr "type" "fadd") (eq_attr "cpu" "r3000"))
2 4)
(define_function_unit "adder" 1 1
(and (eq_attr "type" "fadd") (eq_attr "cpu" "r6000"))
3 6)
(define_function_unit "adder" 1 1
(and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "!r3000"))
2 4)
(define_function_unit "adder" 1 1
(and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000"))
1 2)
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000")))
7 14)
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000")))
4 8)
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
5 10)
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000")))
8 16)
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000")))
5 10)
(define_function_unit "mult" 1 1
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
6 12)
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "!r3000,r6000")))
23 46)
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000")))
12 24)
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
15 30)
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000")))
36 72)
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000")))
19 34)
(define_function_unit "divide" 1 1
(and (eq_attr "type" "fdiv") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
16 32)
(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 108)
(define_function_unit "divide" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 224)
;; The following functional units do not use the cpu type, and use
;; much less memory in genattrtab.c.
;; (define_function_unit "memory" 1 0 (eq_attr "type" "load,pic") 3 0)
;; (define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0)
;;
;; (define_function_unit "fp_comp" 1 0 (eq_attr "type" "fcmp") 2 0)
;;
;; (define_function_unit "transfer" 1 0 (eq_attr "type" "xfer") 2 0)
;; (define_function_unit "transfer" 1 0 (eq_attr "type" "hilo") 3 0)
;;
;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "imul") 17 34)
;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "idiv") 38 76)
;;
;; (define_function_unit "adder" 1 1 (eq_attr "type" "fadd") 4 8)
;; (define_function_unit "adder" 1 1 (eq_attr "type" "fabs,fneg") 2 4)
;;
;; (define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (eq_attr "mode" "SF")) 7 14)
;; (define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (eq_attr "mode" "DF")) 8 16)
;;
;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "SF")) 23 46)
;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "DF")) 36 72)
;;
;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 108)
;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 224)
;;
;; ....................
;;
;; ADDITION
;;
;; ....................
;;
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"add.d\\t%0,%1,%2"
[(set_attr "type" "fadd")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"add.s\\t%0,%1,%2"
[(set_attr "type" "fadd")
(set_attr "mode" "SF")
(set_attr "length" "1")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(plus:SI (match_operand:SI 1 "arith_operand" "%d")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"*
{
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
? \"subu\\t%0,%1,%n2\"
: \"addu\\t%0,%1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "adddi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "arith_operand" "")))
(clobber (match_dup 3))])]
"!TARGET_DEBUG_G_MODE"
"
{
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768)
operands[2] = force_reg (SImode, operands[2]);
operands[3] = gen_reg_rtx (SImode);
}")
(define_insn "adddi3_internal_1"
[(set (match_operand:DI 0 "register_operand" "=d,&d")
(plus:DI (match_operand:DI 1 "register_operand" "0,d")
(match_operand:DI 2 "register_operand" "d,d")))
(clobber (match_operand:SI 3 "register_operand" "=d,d"))]
"!TARGET_DEBUG_G_MODE"
"*
{
return (REGNO (operands[0]) == REGNO (operands[1])
&& REGNO (operands[0]) == REGNO (operands[2]))
? \"srl\\t%3,%L0,31\;sll\\t%M0,%M0,1\;sll\\t%L0,%L1,1\;addu\\t%M0,%M0,%3\"
: \"addu\\t%L0,%L1,%L2\;sltu\\t%3,%L0,%L2\;addu\\t%M0,%M1,%M2\;addu\\t%M0,%M0,%3\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))
&& (REGNO (operands[0]) != REGNO (operands[1])
|| REGNO (operands[0]) != REGNO (operands[2]))"
[(set (subreg:SI (match_dup 0) 0)
(plus:SI (subreg:SI (match_dup 1) 0)
(subreg:SI (match_dup 2) 0)))
(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 0) 0)
(subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 1)
(plus:SI (subreg:SI (match_dup 1) 1)
(subreg:SI (match_dup 2) 1)))
(set (subreg:SI (match_dup 0) 1)
(plus:SI (subreg:SI (match_dup 0) 1)
(match_dup 3)))]
"")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))
&& (REGNO (operands[0]) != REGNO (operands[1])
|| REGNO (operands[0]) != REGNO (operands[2]))"
[(set (subreg:SI (match_dup 0) 1)
(plus:SI (subreg:SI (match_dup 1) 1)
(subreg:SI (match_dup 2) 1)))
(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 0) 1)
(subreg:SI (match_dup 2) 1)))
(set (subreg:SI (match_dup 0) 0)
(plus:SI (subreg:SI (match_dup 1) 0)
(subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 0)
(plus:SI (subreg:SI (match_dup 0) 0)
(match_dup 3)))]
"")
(define_insn "adddi3_internal_2"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(plus:DI (match_operand:DI 1 "register_operand" "%d,%d,%d")
(match_operand:DI 2 "small_int" "P,J,N")))
(clobber (match_operand:SI 3 "register_operand" "=d,d,d"))]
"!TARGET_DEBUG_G_MODE && INTVAL (operands[2]) != -32768"
"@
addu\\t%L0,%L1,%2\;sltu\\t%3,%L0,%2\;addu\\t%M0,%M1,%3
move\\t%L0,%L1\;move\\t%M0,%M1
subu\\t%L0,%L1,%n2\;sltu\\t%3,%L0,%2\;subu\\t%M0,%M1,1\;addu\\t%M0,%M0,%3"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "3,2,4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& INTVAL (operands[2]) > 0"
[(set (subreg:SI (match_dup 0) 0)
(plus:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))
(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 0) 0)
(match_dup 2)))
(set (subreg:SI (match_dup 0) 1)
(plus:SI (subreg:SI (match_dup 1) 1)
(match_dup 3)))]
"")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(plus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& INTVAL (operands[2]) > 0"
[(set (subreg:SI (match_dup 0) 1)
(plus:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))
(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 0) 1)
(match_dup 2)))
(set (subreg:SI (match_dup 0) 0)
(plus:SI (subreg:SI (match_dup 1) 0)
(match_dup 3)))]
"")
;;
;; ....................
;;
;; SUBTRACTION
;;
;; ....................
;;
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"sub.d\\t%0,%1,%2"
[(set_attr "type" "fadd")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(minus:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"sub.s\\t%0,%1,%2"
[(set_attr "type" "fadd")
(set_attr "mode" "SF")
(set_attr "length" "1")])
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"*
{
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
? \"addu\\t%0,%z1,%n2\"
: \"subu\\t%0,%z1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "subdi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "=d")
(minus:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))
(clobber (match_dup 3))])]
"!TARGET_DEBUG_G_MODE"
"operands[3] = gen_reg_rtx (SImode);")
(define_insn "subdi3_internal"
[(set (match_operand:DI 0 "register_operand" "=d")
(minus:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE"
"sltu\\t%3,%L1,%L2\;subu\\t%L0,%L1,%L2\;subu\\t%M0,%M1,%M2\;subu\\t%M0,%M0,%3"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
[(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 1) 0)
(subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 0)
(minus:SI (subreg:SI (match_dup 1) 0)
(subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 1)
(minus:SI (subreg:SI (match_dup 1) 1)
(subreg:SI (match_dup 2) 1)))
(set (subreg:SI (match_dup 0) 1)
(minus:SI (subreg:SI (match_dup 0) 1)
(match_dup 3)))]
"")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
[(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 1) 1)
(subreg:SI (match_dup 2) 1)))
(set (subreg:SI (match_dup 0) 1)
(minus:SI (subreg:SI (match_dup 1) 1)
(subreg:SI (match_dup 2) 1)))
(set (subreg:SI (match_dup 0) 0)
(minus:SI (subreg:SI (match_dup 1) 0)
(subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 0)
(minus:SI (subreg:SI (match_dup 0) 0)
(match_dup 3)))]
"")
(define_insn "subdi3_internal_2"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(minus:DI (match_operand:DI 1 "register_operand" "d,d,d")
(match_operand:DI 2 "small_int" "P,J,N")))
(clobber (match_operand:SI 3 "register_operand" "=d,d,d"))]
"!TARGET_DEBUG_G_MODE && INTVAL (operands[2]) != -32768"
"@
sltu\\t%3,%L1,%2\;subu\\t%L0,%L1,%2\;subu\\t%M0,%M1,%3
move\\t%L0,%L1\;move\\t%M0,%M1
sltu\\t%3,%L1,%2\;subu\\t%L0,%L1,%2\;subu\\t%M0,%M1,1\;subu\\t%M0,%M0,%3"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "3,2,4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& INTVAL (operands[2]) > 0"
[(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))
(set (subreg:SI (match_dup 0) 0)
(minus:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))
(set (subreg:SI (match_dup 0) 1)
(minus:SI (subreg:SI (match_dup 1) 1)
(match_dup 3)))]
"")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(minus:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& INTVAL (operands[2]) > 0"
[(set (match_dup 3)
(ltu:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))
(set (subreg:SI (match_dup 0) 1)
(minus:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))
(set (subreg:SI (match_dup 0) 0)
(minus:SI (subreg:SI (match_dup 1) 0)
(match_dup 3)))]
"")
;;
;; ....................
;;
;; MULTIPLICATION
;;
;; ....................
;;
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"mul.d\\t%0,%1,%2"
[(set_attr "type" "fmul")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"mul.s\\t%0,%1,%2"
[(set_attr "type" "fmul")
(set_attr "mode" "SF")
(set_attr "length" "1")])
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(mult:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
""
"*
{
rtx xoperands[10];
xoperands[0] = operands[0];
xoperands[1] = gen_rtx (REG, SImode, LO_REGNUM);
output_asm_insn (\"mult\\t%1,%2\", operands);
output_asm_insn (mips_move_1word (xoperands, insn), xoperands);
return \"\";
}"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "3")]) ;; mult + mflo + delay
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(mult:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "")))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"!TARGET_DEBUG_D_MODE"
[(parallel [(set (reg:SI 65) ;; low register
(mult:SI (match_dup 1)
(match_dup 2)))
(clobber (reg:SI 64))])
(set (match_dup 0)
(reg:SI 65))]
"")
(define_insn "mulsi3_internal"
[(set (reg:SI 65) ;; low register
(mult:SI (match_operand:SI 0 "register_operand" "d")
(match_operand:SI 1 "register_operand" "d")))
(clobber (reg:SI 64))]
""
"mult\\t%0,%1"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "mulsidi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))
(clobber (reg:DI 64))]
""
"*
{
rtx xoperands[10];
xoperands[0] = operands[0];
xoperands[1] = gen_rtx (REG, DImode, MD_REG_FIRST);
output_asm_insn (\"mult\\t%1,%2\", operands);
output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
return \"\";
}"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "4")]) ;; mult + mflo + mfhi + delay
(define_insn "umulsidi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
(zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))
(clobber (reg:DI 64))]
""
"*
{
rtx xoperands[10];
xoperands[0] = operands[0];
xoperands[1] = gen_rtx (REG, DImode, MD_REG_FIRST);
output_asm_insn (\"multu\\t%1,%2\", operands);
output_asm_insn (mips_move_2words (xoperands, insn), xoperands);
return \"\";
}"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "4")]) ;; mult + mflo + mfhi + delay
;;
;; ....................
;;
;; DIVISION and REMAINDER
;;
;; ....................
;;
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "register_operand" "f")
(match_operand:DF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"div.d\\t%0,%1,%2"
[(set_attr "type" "fdiv")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(div:SF (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"div.s\\t%0,%1,%2"
[(set_attr "type" "fdiv")
(set_attr "mode" "SF")
(set_attr "length" "1")])
;; If optimizing, prefer the divmod functions over separate div and
;; mod functions, since this will allow using one instruction for both
;; the quotient and remainder. At present, the divmod is not moved out
;; of loops if it is constant within the loop, so allow -mdebugc to
;; use the old method of doing things.
;; 64 is the multiply/divide hi register
;; 65 is the multiply/divide lo register
(define_insn "divmodsi4"
[(set (match_operand:SI 0 "register_operand" "=d")
(div:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(set (match_operand:SI 3 "register_operand" "=d")
(mod:SI (match_dup 1)
(match_dup 2)))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"optimize"
"*
{
if (find_reg_note (insn, REG_UNUSED, operands[3]))
return \"div\\t%0,%1,%2\";
if (find_reg_note (insn, REG_UNUSED, operands[0]))
return \"rem\\t%3,%1,%2\";
return \"div\\t%0,%1,%2\;mfhi\\t%3\";
}"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "13")]) ;; various tests for dividing by 0 and such
(define_insn "udivmodsi4"
[(set (match_operand:SI 0 "register_operand" "=d")
(udiv:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(set (match_operand:SI 3 "register_operand" "=d")
(umod:SI (match_dup 1)
(match_dup 2)))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"optimize"
"*
{
if (find_reg_note (insn, REG_UNUSED, operands[3]))
return \"divu\\t%0,%1,%2\";
if (find_reg_note (insn, REG_UNUSED, operands[0]))
return \"remu\\t%3,%1,%2\";
return \"divu\\t%0,%1,%2\;mfhi\\t%3\";
}"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "13")]) ;; various tests for dividing by 0 and such
(define_insn "divsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(div:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"!optimize"
"div\\t%0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "13")]) ;; various tests for dividing by 0 and such
(define_insn "modsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(mod:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"!optimize"
"rem\\t%0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "14")]) ;; various tests for dividing by 0 and such
(define_insn "udivsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(udiv:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"!optimize"
"divu\\t%0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "14")]) ;; various tests for dividing by 0 and such
(define_insn "umodsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(umod:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (reg:SI 64))
(clobber (reg:SI 65))]
"!optimize"
"remu\\t%0,%1,%2"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "14")]) ;; various tests for dividing by 0 and such
;;
;; ....................
;;
;; SQUARE ROOT
;;
;; ....................
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(sqrt:DF (match_operand:DF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT && HAVE_SQRT_P()"
"sqrt.d\\t%0,%1"
[(set_attr "type" "fabs")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT && HAVE_SQRT_P()"
"sqrt.s\\t%0,%1"
[(set_attr "type" "fabs")
(set_attr "mode" "SF")
(set_attr "length" "1")])
;;
;; ....................
;;
;; ABSOLUTE VALUE
;;
;; ....................
;; Do not use the integer abs macro instruction, since that signals an
;; exception on -2147483648 (sigh).
(define_insn "abssi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(abs:SI (match_operand:SI 1 "register_operand" "d")))]
""
"*
{
dslots_jump_total++;
dslots_jump_filled++;
operands[2] = const0_rtx;
return (REGNO (operands[0]) == REGNO (operands[1]))
? \"bgez\\t%1,1f%#\\n\\tsubu\\t%0,%z2,%0\\n1:\"
: \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tsubu\\t%0,%z2,%0\\n1:%)\";
}"
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "3")])
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"abs.d\\t%0,%1"
[(set_attr "type" "fabs")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(abs:SF (match_operand:SF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"abs.s\\t%0,%1"
[(set_attr "type" "fabs")
(set_attr "mode" "SF")
(set_attr "length" "1")])
;;
;; ....................
;;
;; FIND FIRST BIT INSTRUCTION
;;
;; ....................
;;
(define_insn "ffssi2"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ffs:SI (match_operand:SI 1 "register_operand" "d")))
(clobber (match_scratch:SI 2 "d"))
(clobber (match_scratch:SI 3 "d"))]
""
"*
{
dslots_jump_total += 2;
dslots_jump_filled += 2;
operands[4] = const0_rtx;
if (optimize && find_reg_note (insn, REG_DEAD, operands[1]))
return \"%(\\
move\\t%0,%z4\\n\\
\\tbeq\\t%1,%z4,2f\\n\\
1:\\tand\\t%2,%1,0x0001\\n\\
\\taddu\\t%0,%0,1\\n\\
\\tbeq\\t%2,%z4,1b\\n\\
\\tsrl\\t%1,%1,1\\n\\
2:%)\";
return \"%(\\
move\\t%0,%z4\\n\\
\\tmove\\t%3,%1\\n\\
\\tbeq\\t%3,%z4,2f\\n\\
1:\\tand\\t%2,%3,0x0001\\n\\
\\taddu\\t%0,%0,1\\n\\
\\tbeq\\t%2,%z4,1b\\n\\
\\tsrl\\t%3,%3,1\\n\\
2:%)\";
}"
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "6")])
;;
;; ....................
;;
;; NEGATION and ONE'S COMPLEMENT
;;
;; ....................
(define_insn "negsi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(neg:SI (match_operand:SI 1 "register_operand" "d")))]
""
"*
{
operands[2] = const0_rtx;
return \"subu\\t%0,%z2,%1\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "negdi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "=d")
(neg:DI (match_operand:DI 1 "register_operand" "d")))
(clobber (match_dup 2))])]
"!TARGET_DEBUG_G_MODE"
"operands[2] = gen_reg_rtx (SImode);")
(define_insn "negdi3_internal"
[(set (match_operand:DI 0 "register_operand" "=d")
(neg:DI (match_operand:DI 1 "register_operand" "d")))
(clobber (match_operand:SI 2 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE"
"*
{
operands[3] = const0_rtx;
return \"subu\\t%L0,%z3,%L1\;subu\\t%M0,%z3,%M1\;sltu\\t%2,%z3,%L0\;subu\\t%M0,%M0,%2\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "4")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"neg.d\\t%0,%1"
[(set_attr "type" "fneg")
(set_attr "mode" "DF")
(set_attr "length" "1")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"neg.s\\t%0,%1"
[(set_attr "type" "fneg")
(set_attr "mode" "SF")
(set_attr "length" "1")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(not:SI (match_operand:SI 1 "register_operand" "d")))]
""
"*
{
operands[2] = const0_rtx;
return \"nor\\t%0,%z2,%1\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "=d")
(not:SI (match_operand:DI 1 "register_operand" "d")))]
""
"*
{
operands[2] = const0_rtx;
return \"nor\\t%M0,%z2,%M1\;nor\\t%L0,%z2,%L1\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(not:DI (match_operand:DI 1 "register_operand" "")))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
[(set (subreg:SI (match_dup 0) 0) (not:SI (subreg:SI (match_dup 1) 0)))
(set (subreg:SI (match_dup 0) 1) (not:SI (subreg:SI (match_dup 1) 1)))]
"")
;; Simple hack to recognize the "nor" instruction on the MIPS
;; This must appear before the normal or patterns, so that the
;; combiner will correctly fold things.
(define_insn "norsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(not:SI (ior:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
(match_operand:SI 2 "reg_or_0_operand" "dJ"))))]
""
"nor\\t%0,%z1,%z2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "nordi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(not:DI (ior:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d"))))]
""
"nor\\t%M0,%M1,%M2\;nor\\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(not:DI (ior:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" ""))))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
[(set (subreg:SI (match_dup 0) 0) (not:SI (ior:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))))
(set (subreg:SI (match_dup 0) 1) (not:SI (ior:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1))))]
"")
;;
;; ....................
;;
;; LOGICAL
;;
;; ....................
;;
;; Be more liberal in allowing logical operations than the machine actually
;; supports. This causes better code to be generated for bitfields, since
;; the optimizer can fold things together, at the expense of not moving the
;; constant out of loops.
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,?d,?d")
(and:SI (match_operand:SI 1 "arith32_operand" "%d,d,d,d")
(match_operand:SI 2 "arith32_operand" "d,K,I,M")))]
""
"@
and\\t%0,%1,%2
andi\\t%0,%1,%x2
%[li\\t%@,%X2\;and\\t%0,%1,%@%]
%[li\\t%@,%X2\;and\\t%0,%1,%@%]"
[(set_attr "type" "arith,arith,multi,multi")
(set_attr "mode" "SI")
(set_attr "length" "1,1,2,3")])
(define_insn "anddi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))]
"!TARGET_DEBUG_G_MODE"
"and\\t%M0,%M1,%M2\;and\\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(and:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
[(set (subreg:SI (match_dup 0) 0) (and:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 1) (and:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))]
"")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,?d,?d")
(ior:SI (match_operand:SI 1 "arith32_operand" "%d,d,d,d")
(match_operand:SI 2 "arith32_operand" "d,K,I,M")))]
""
"@
or\\t%0,%1,%2
ori\\t%0,%1,%x2
%[li\\t%@,%X2\;or\\t%0,%1,%@%]
%[li\\t%@,%X2\;or\\t%0,%1,%@%]"
[(set_attr "type" "arith,arith,multi,multi")
(set_attr "mode" "SI")
(set_attr "length" "1,1,2,3")])
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(ior:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))]
"!TARGET_DEBUG_G_MODE"
"or\\t%M0,%M1,%M2\;or\\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ior:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
[(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 1) (ior:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))]
"")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,?d,?d")
(xor:SI (match_operand:SI 1 "arith32_operand" "%d,d,d,d")
(match_operand:SI 2 "arith32_operand" "d,K,I,M")))]
""
"@
xor\\t%0,%1,%2
xori\\t%0,%1,%x2
%[li\\t%@,%X2\;xor\\t%0,%1,%@%]
%[li\\t%@,%X2\;xor\\t%0,%1,%@%]"
[(set_attr "type" "arith,arith,multi,multi")
(set_attr "mode" "SI")
(set_attr "length" "1,1,2,3")])
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(xor:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))]
"!TARGET_DEBUG_G_MODE"
"xor\\t%M0,%M1,%M2\;xor\\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(xor:DI (match_operand:DI 1 "register_operand" "")
(match_operand:DI 2 "register_operand" "")))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
[(set (subreg:SI (match_dup 0) 0) (xor:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0)))
(set (subreg:SI (match_dup 0) 1) (xor:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))]
"")
;;
;; ....................
;;
;; TRUNCATION
;;
;; ....................
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float_truncate:SF (match_operand:DF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"cvt.s.d\\t%0,%1"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")
(set_attr "length" "1")])
;;
;; ....................
;;
;; ZERO EXTENSION
;;
;; ....................
;; Extension insns.
;; Those for integer source operand
;; are ordered widest source type first.
(define_insn "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
""
"*
{
if (which_alternative == 0)
return \"andi\\t%0,%1,0xffff\";
else
return mips_move_1word (operands, insn, TRUE);
}"
[(set_attr "type" "arith,load,load")
(set_attr "mode" "SI")
(set_attr "length" "1,1,2")])
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "=d,d,d")
(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
""
"*
{
if (which_alternative == 0)
return \"andi\\t%0,%1,0x00ff\";
else
return mips_move_1word (operands, insn, TRUE);
}"
[(set_attr "type" "arith,load,load")
(set_attr "mode" "HI")
(set_attr "length" "1,1,2")])
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
""
"*
{
if (which_alternative == 0)
return \"andi\\t%0,%1,0x00ff\";
else
return mips_move_1word (operands, insn, TRUE);
}"
[(set_attr "type" "arith,load,load")
(set_attr "mode" "SI")
(set_attr "length" "1,1,2")])
;;
;; ....................
;;
;; SIGN EXTENSION
;;
;; ....................
;; Extension insns.
;; Those for integer source operand
;; are ordered widest source type first.
;; These patterns originally accepted general_operands, however, slightly
;; better code is generated by only accepting register_operands, and then
;; letting combine generate the lh and lb insns.
(define_expand "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
""
"
{
if (optimize && GET_CODE (operands[1]) == MEM)
operands[1] = force_not_mem (operands[1]);
if (GET_CODE (operands[1]) != MEM)
{
rtx op1 = gen_lowpart (SImode, operands[1]);
rtx temp = gen_reg_rtx (SImode);
rtx shift = gen_rtx (CONST_INT, VOIDmode, 16);
emit_insn (gen_ashlsi3 (temp, op1, shift));
emit_insn (gen_ashrsi3 (operands[0], temp, shift));
DONE;
}
}")
(define_insn "extendhisi2_internal"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(sign_extend:SI (match_operand:HI 1 "memory_operand" "R,m")))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
(set_attr "mode" "SI")
(set_attr "length" "1,2")])
(define_expand "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
"
{
if (optimize && GET_CODE (operands[1]) == MEM)
operands[1] = force_not_mem (operands[1]);
if (GET_CODE (operands[1]) != MEM)
{
rtx op0 = gen_lowpart (SImode, operands[0]);
rtx op1 = gen_lowpart (SImode, operands[1]);
rtx temp = gen_reg_rtx (SImode);
rtx shift = gen_rtx (CONST_INT, VOIDmode, 24);
emit_insn (gen_ashlsi3 (temp, op1, shift));
emit_insn (gen_ashrsi3 (op0, temp, shift));
DONE;
}
}")
(define_insn "extendqihi2_internal"
[(set (match_operand:HI 0 "register_operand" "=d,d")
(sign_extend:HI (match_operand:QI 1 "memory_operand" "R,m")))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
(set_attr "mode" "SI")
(set_attr "length" "1,2")])
(define_expand "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
""
"
{
if (optimize && GET_CODE (operands[1]) == MEM)
operands[1] = force_not_mem (operands[1]);
if (GET_CODE (operands[1]) != MEM)
{
rtx op1 = gen_lowpart (SImode, operands[1]);
rtx temp = gen_reg_rtx (SImode);
rtx shift = gen_rtx (CONST_INT, VOIDmode, 24);
emit_insn (gen_ashlsi3 (temp, op1, shift));
emit_insn (gen_ashrsi3 (operands[0], temp, shift));
DONE;
}
}")
(define_insn "extendqisi2_insn"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(sign_extend:SI (match_operand:QI 1 "memory_operand" "R,m")))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "load")
(set_attr "mode" "SI")
(set_attr "length" "1,2")])
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
"TARGET_HARD_FLOAT"
"cvt.d.s\\t%0,%1"
[(set_attr "type" "fcvt")
(set_attr "mode" "DF")
(set_attr "length" "1")])
;;
;; ....................
;;
;; CONVERSIONS
;;
;; ....................
(define_insn "fix_truncdfsi2_internal"
[(set (match_operand:SI 0 "general_operand" "=d,*f,R,o")
(fix:SI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
(clobber (match_operand:SI 2 "register_operand" "d,*d,d,d"))
(clobber (match_operand:DF 3 "register_operand" "f,*f,f,f"))]
"TARGET_HARD_FLOAT"
"*
{
rtx xoperands[10];
if (which_alternative == 1)
return \"trunc.w.d %0,%1,%2\";
output_asm_insn (\"trunc.w.d %3,%1,%2\", operands);
xoperands[0] = operands[0];
xoperands[1] = operands[3];
output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
return \"\";
}"
[(set_attr "type" "fcvt")
(set_attr "mode" "DF")
(set_attr "length" "14,12,13,14")])
(define_expand "fix_truncdfsi2"
[(parallel [(set (match_operand:SI 0 "register_operand" "=d")
(fix:SI (match_operand:DF 1 "register_operand" "f")))
(clobber (match_dup 2))
(clobber (match_dup 3))])]
"TARGET_HARD_FLOAT"
"
{
operands[2] = gen_reg_rtx (SImode); /* gp reg that saves FP status bits */
operands[3] = gen_reg_rtx (DFmode); /* fp reg that gets the conversion */
/* Fall through and generate default code */
}")
(define_insn "fix_truncsfsi2_internal"
[(set (match_operand:SI 0 "general_operand" "=d,*f,R,o")
(fix:SI (match_operand:SF 1 "register_operand" "f,*f,f,f")))
(clobber (match_operand:SI 2 "register_operand" "d,*d,d,d"))
(clobber (match_operand:SF 3 "register_operand" "f,*f,f,f"))]
"TARGET_HARD_FLOAT"
"*
{
rtx xoperands[10];
if (which_alternative == 1)
return \"trunc.w.s %0,%1,%2\";
output_asm_insn (\"trunc.w.s %3,%1,%2\", operands);
xoperands[0] = operands[0];
xoperands[1] = operands[3];
output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
return \"\";
}"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")
(set_attr "length" "14,12,13,14")])
(define_expand "fix_truncsfsi2"
[(parallel [(set (match_operand:SI 0 "register_operand" "=f")
(fix:SI (match_operand:SF 1 "register_operand" "f")))
(clobber (match_dup 2))
(clobber (match_dup 3))])]
"TARGET_HARD_FLOAT"
"
{
operands[2] = gen_reg_rtx (SImode); /* gp reg that saves FP status bits */
operands[3] = gen_reg_rtx (SFmode); /* fp reg that gets the conversion */
/* Fall through and generate default code */
}")
(define_insn "floatsidf2"
[(set (match_operand:DF 0 "register_operand" "=f,f,f")
(float:DF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
"TARGET_HARD_FLOAT"
"*
{
dslots_load_total++;
if (GET_CODE (operands[1]) == MEM)
return \"l.s\\t%0,%1%#\;cvt.d.w\\t%0,%0\";
return \"mtc1\\t%1,%0%#\;cvt.d.w\\t%0,%0\";
}"
[(set_attr "type" "fcvt")
(set_attr "mode" "DF")
(set_attr "length" "3,4,3")])
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=f,f,f")
(float:SF (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
"TARGET_HARD_FLOAT"
"*
{
dslots_load_total++;
if (GET_CODE (operands[1]) == MEM)
return \"l.s\\t%0,%1%#\;cvt.s.w\\t%0,%0\";
return \"mtc1\\t%1,%0%#\;cvt.s.w\\t%0,%0\";
}"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")
(set_attr "length" "3,4,3")])
(define_expand "fixuns_truncdfsi2"
[(set (match_operand:SI 0 "register_operand" "")
(unsigned_fix:SI (match_operand:DF 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
"
{
rtx reg1 = gen_reg_rtx (DFmode);
rtx reg2 = gen_reg_rtx (DFmode);
rtx reg3 = gen_reg_rtx (SImode);
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31);
if (reg1) /* turn off complaints about unreached code */
{
extern rtx gen_cmpdf ();
emit_move_insn (reg1, immed_real_const_1 (offset, DFmode));
do_pending_stack_adjust ();
emit_insn (gen_cmpdf (operands[1], reg1));
emit_jump_insn (gen_bge (label1));
emit_insn (gen_fix_truncdfsi2 (operands[0], operands[1]));
emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
gen_rtx (LABEL_REF, VOIDmode, label2)));
emit_barrier ();
emit_label (label1);
emit_move_insn (reg2, gen_rtx (MINUS, DFmode, operands[1], reg1));
emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000));
emit_insn (gen_fix_truncdfsi2 (operands[0], reg2));
emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
emit_label (label2);
/* allow REG_NOTES to be set on last insn (labels don't have enough
fields, and can't be used for REG_NOTES anyway). */
emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx));
DONE;
}
}")
(define_expand "fixuns_truncsfsi2"
[(set (match_operand:SI 0 "register_operand" "")
(unsigned_fix:SI (match_operand:SF 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
"
{
rtx reg1 = gen_reg_rtx (SFmode);
rtx reg2 = gen_reg_rtx (SFmode);
rtx reg3 = gen_reg_rtx (SImode);
rtx label1 = gen_label_rtx ();
rtx label2 = gen_label_rtx ();
REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 31);
if (reg1) /* turn off complaints about unreached code */
{
extern rtx gen_cmpsf ();
emit_move_insn (reg1, immed_real_const_1 (offset, SFmode));
do_pending_stack_adjust ();
emit_insn (gen_cmpsf (operands[1], reg1));
emit_jump_insn (gen_bge (label1));
emit_insn (gen_fix_truncsfsi2 (operands[0], operands[1]));
emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx,
gen_rtx (LABEL_REF, VOIDmode, label2)));
emit_barrier ();
emit_label (label1);
emit_move_insn (reg2, gen_rtx (MINUS, SFmode, operands[1], reg1));
emit_move_insn (reg3, gen_rtx (CONST_INT, VOIDmode, 0x80000000));
emit_insn (gen_fix_truncsfsi2 (operands[0], reg2));
emit_insn (gen_iorsi3 (operands[0], operands[0], reg3));
emit_label (label2);
/* allow REG_NOTES to be set on last insn (labels don't have enough
fields, and can't be used for REG_NOTES anyway). */
emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx));
DONE;
}
}")
;;
;; ....................
;;
;; DATA MOVEMENT
;;
;; ....................
;; unaligned word moves generated by the block moves.
(define_expand "movsi_unaligned"
[(set (match_operand:SI 0 "general_operand" "")
(unspec [(match_operand:SI 1 "general_operand" "")] 0))]
""
"
{
extern rtx gen_movsi_ulw ();
extern rtx gen_movsi ();
/* Handle loads. */
if (GET_CODE (operands[0]) == MEM)
{
rtx reg = gen_reg_rtx (SImode);
rtx insn = emit_insn (gen_movsi_ulw (reg, operands[1]));
rtx addr = XEXP (operands[0], 0);
if (CONSTANT_P (addr))
REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUIV, addr, REG_NOTES (insn));
if (reg_or_0_operand (operands[1], SImode))
DONE;
operands[1] = reg;
}
/* Generate appropriate load, store. If not a load or store,
do a normal movsi. */
if (GET_CODE (operands[0]) != MEM && GET_CODE (operands[1]) != MEM)
{
emit_insn (gen_movsi (operands[0], operands[1]));
DONE;
}
/* Fall through and generate normal code. */
}")
(define_insn "movsi_ulw"
[(set (match_operand:SI 0 "register_operand" "=&d,&d,d,d")
(unspec [(match_operand:SI 1 "general_operand" "R,o,dIKL,M")] 0))]
""
"*
{
extern rtx eliminate_constant_term ();
enum rtx_code code;
char *ret;
rtx offset;
rtx addr;
rtx mem_addr;
if (which_alternative != 0)
return mips_move_1word (operands, insn, FALSE);
if (TARGET_STATS)
mips_count_memory_refs (operands[1], 2);
/* The stack/frame pointers are always aligned, so we can convert
to the faster lw if we are referencing an aligned stack location. */
offset = const0_rtx;
addr = XEXP (operands[1], 0);
mem_addr = eliminate_constant_term (addr, &offset);
if ((INTVAL (offset) & (UNITS_PER_WORD-1)) == 0
&& (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx))
ret = \"lw\\t%0,%1\";
else
{
ret = \"ulw\\t%0,%1\";
if (TARGET_GAS)
{
enum rtx_code code = GET_CODE (addr);
if (code == CONST || code == SYMBOL_REF || code == LABEL_REF)
{
operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 1);
ret = \"%[la\\t%2,%1\;ulw\\t%0,0(%2)%]\";
}
}
}
return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn);
}"
[(set_attr "type" "load,load,move,arith")
(set_attr "mode" "SI")
(set_attr "length" "2,4,1,2")])
(define_insn "movsi_usw"
[(set (match_operand:SI 0 "memory_operand" "=R,o")
(unspec [(match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")] 0))]
""
"*
{
extern rtx eliminate_constant_term ();
rtx offset = const0_rtx;
rtx addr = XEXP (operands[0], 0);
rtx mem_addr = eliminate_constant_term (addr, &offset);
if (TARGET_STATS)
mips_count_memory_refs (operands[0], 2);
/* The stack/frame pointers are always aligned, so we can convert
to the faster sw if we are referencing an aligned stack location. */
if ((INTVAL (offset) & (UNITS_PER_WORD-1)) == 0
&& (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx))
return \"sw\\t%1,%0\";
if (TARGET_GAS)
{
enum rtx_code code = GET_CODE (XEXP (operands[0], 0));
if (code == CONST || code == SYMBOL_REF || code == LABEL_REF)
{
operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 1);
return \"%[la\\t%2,%0\;usw\\t%z1,0(%2)%]\";
}
}
return \"usw\\t%z1,%0\";
}"
[(set_attr "type" "store")
(set_attr "mode" "SI")
(set_attr "length" "2,4")])
;; 64-bit integer moves
;; Unlike most other insns, the move insns can't be split with
;; different predicates, because register spilling and other parts of
;; the compiler, have memoized the insn number already.
(define_insn "movdi"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*d,*x")
(match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,*x,*d"))]
""
"* return mips_move_2words (operands, insn); "
[(set_attr "type" "move,arith,load,load,store,store,hilo,hilo")
(set_attr "mode" "DI")
(set_attr "length" "2,4,2,4,2,4,2,2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
[(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
(set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))]
"")
;; 32-bit Integer moves
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "large_int" ""))]
"!TARGET_DEBUG_D_MODE"
[(set (match_dup 0)
(match_dup 2))
(set (match_dup 0)
(ior:SI (match_dup 0)
(match_dup 3)))]
"
{
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) & 0xffff0000);
operands[3] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[1]) & 0x0000ffff);
}")
;; Unlike most other insns, the move insns can't be split with
;; different predicates, because register spilling and other parts of
;; the compiler, have memoized the insn number already.
(define_expand "movsi"
[(set (match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
"
{
/* If this is a half-pic address being moved to a register, convert the
address into a load, so that scheduling and stuff works properly. */
if (HALF_PIC_P()
&& GET_CODE (operands[0]) == REG
&& GET_CODE (operands[1]) == SYMBOL_REF
&& HALF_PIC_ADDRESS_P (operands[1]))
{
rtx ptr = HALF_PIC_PTR (operands[1]);
if (XSTR (ptr, 0) != XSTR (operands[1], 0))
{
emit_move_insn (operands[0], gen_rtx (MEM, Pmode, ptr));
DONE;
}
}
}")
(define_insn "movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*fz,*f,*f,*f,*R,*m,*x,*d")
(match_operand:SI 1 "general_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*fz,*d,*f,*R,*m,*f,*f,*d,*x"))]
""
"* return mips_move_1word (operands, insn, TRUE);"
[(set_attr "type" "move,pic,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo")
(set_attr "mode" "SI")
(set_attr "length" "1,4,1,2,1,2,1,2,1,1,1,1,2,1,2,1,1")])
;; 16-bit Integer moves
;; Unlike most other insns, the move insns can't be split with
;; different predicates, because register spilling and other parts of
;; the compiler, have memoized the insn number already.
;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
(define_insn "movhi"
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f,*f,*x,*d")
(match_operand:HI 1 "general_operand" "d,IK,R,m,dJ,dJ,*fz,*d,*f,*d,*x"))]
""
"* return mips_move_1word (operands, insn, TRUE);"
[(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo")
(set_attr "mode" "HI")
(set_attr "length" "1,1,1,2,1,2,1,1,1,1,1")])
;; 8-bit Integer moves
;; Unlike most other insns, the move insns can't be split with
;; different predicates, because register spilling and other parts of
;; the compiler, have memoized the insn number already.
;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
(define_insn "movqi"
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f,*f,*x,*d")
(match_operand:QI 1 "general_operand" "d,IK,R,m,dJ,dJ,*fz,*d,*f,*d,*x"))]
""
"* return mips_move_1word (operands, insn, TRUE);"
[(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,move,hilo,hilo")
(set_attr "mode" "QI")
(set_attr "length" "1,1,1,2,1,2,1,1,1,1,1")])
;; 32-bit floating point moves
(define_insn "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,f,f,R,m,*f,*d,*d,*d,*d,*R,*m")
(match_operand:SF 1 "general_operand" "f,G,R,Em,fG,fG,*d,*f,*Gd,*R,*Em,*d,*d"))]
""
"* return mips_move_1word (operands, insn, FALSE);"
[(set_attr "type" "move,xfer,load,load,store,store,xfer,xfer,move,load,load,store,store")
(set_attr "mode" "SF")
(set_attr "length" "1,1,1,2,1,2,1,1,1,1,2,1,2")])
;; 64-bit floating point moves
(define_insn "movdf"
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,R,o,f,*f,*d,*d,*d,*d,*R,*o")
(match_operand:DF 1 "general_operand" "f,R,o,fG,fG,E,*d,*f,*dG,*R,*oE,*d,*d"))]
""
"* return mips_move_2words (operands, insn); "
[(set_attr "type" "move,load,load,store,store,load,xfer,xfer,move,load,load,store,store")
(set_attr "mode" "DF")
(set_attr "length" "1,2,4,2,4,4,2,2,2,2,4,2,4")])
(define_split
[(set (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "register_operand" ""))]
"reload_completed && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
[(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
(set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))]
"")
;; Block moves, see mips.c for more details.
;; Argument 0 is the destination
;; Argument 1 is the source
;; Argument 2 is the length
;; Argument 3 is the alignment
(define_expand "movstrsi"
[(parallel [(set (mem:BLK (match_operand:BLK 0 "general_operand" ""))
(mem:BLK (match_operand:BLK 1 "general_operand" "")))
(use (match_operand:SI 2 "arith32_operand" ""))
(use (match_operand:SI 3 "immediate_operand" ""))])]
""
"
{
if (operands[0]) /* avoid unused code messages */
{
expand_block_move (operands);
DONE;
}
}")
;; Insn generated by block moves
(define_insn "movstrsi_internal"
[(set (match_operand:BLK 0 "memory_operand" "=Ro") ;; destination
(match_operand:BLK 1 "memory_operand" "Ro")) ;; source
(clobber (match_scratch:SI 4 "=&d")) ;; temp 1
(clobber (match_scratch:SI 5 "=&d")) ;; temp 2
(clobber (match_scratch:SI 6 "=&d")) ;; temp 3
(clobber (match_scratch:SI 7 "=&d")) ;; temp 4
(use (match_operand:SI 2 "small_int" "I")) ;; # bytes to move
(use (match_operand:SI 3 "small_int" "I")) ;; alignment
(use (const_int 0))] ;; normal block move
""
"* return output_block_move (insn, operands, 4, BLOCK_MOVE_NORMAL);"
[(set_attr "type" "multi")
(set_attr "mode" "none")
(set_attr "length" "20")])
;; Split a block move into 2 parts, the first part is everything
;; except for the last move, and the second part is just the last
;; store, which is exactly 1 instruction (ie, not a usw), so it can
;; fill a delay slot. This also prevents a bug in delayed branches
;; from showing up, which reuses one of the registers in our clobbers.
(define_split
[(set (mem:BLK (match_operand:SI 0 "register_operand" ""))
(mem:BLK (match_operand:SI 1 "register_operand" "")))
(clobber (match_operand:SI 4 "register_operand" ""))
(clobber (match_operand:SI 5 "register_operand" ""))
(clobber (match_operand:SI 6 "register_operand" ""))
(clobber (match_operand:SI 7 "register_operand" ""))
(use (match_operand:SI 2 "small_int" ""))
(use (match_operand:SI 3 "small_int" ""))
(use (const_int 0))]
"reload_completed && !TARGET_DEBUG_D_MODE && INTVAL (operands[2]) > 0"
;; All but the last move
[(parallel [(set (mem:BLK (match_dup 0))
(mem:BLK (match_dup 1)))
(clobber (match_dup 4))
(clobber (match_dup 5))
(clobber (match_dup 6))
(clobber (match_dup 7))
(use (match_dup 2))
(use (match_dup 3))
(use (const_int 1))])
;; The last store, so it can fill a delay slot
(parallel [(set (mem:BLK (match_dup 0))
(mem:BLK (match_dup 1)))
(clobber (match_dup 4))
(clobber (match_dup 5))
(clobber (match_dup 6))
(clobber (match_dup 7))
(use (match_dup 2))
(use (match_dup 3))
(use (const_int 2))])]
"")
(define_insn "movstrsi_internal2"
[(set (match_operand:BLK 0 "memory_operand" "=Ro") ;; destination
(match_operand:BLK 1 "memory_operand" "Ro")) ;; source
(clobber (match_scratch:SI 4 "=&d")) ;; temp 1
(clobber (match_scratch:SI 5 "=&d")) ;; temp 2
(clobber (match_scratch:SI 6 "=&d")) ;; temp 3
(clobber (match_scratch:SI 7 "=&d")) ;; temp 4
(use (match_operand:SI 2 "small_int" "I")) ;; # bytes to move
(use (match_operand:SI 3 "small_int" "I")) ;; alignment
(use (const_int 1))] ;; all but last store
""
"* return output_block_move (insn, operands, 4, BLOCK_MOVE_NOT_LAST);"
[(set_attr "type" "multi")
(set_attr "mode" "none")
(set_attr "length" "20")])
(define_insn "movstrsi_internal3"
[(set (match_operand:BLK 0 "memory_operand" "=Ro") ;; destination
(match_operand:BLK 1 "memory_operand" "Ro")) ;; source
(clobber (match_scratch:SI 4 "=&d")) ;; temp 1
(clobber (match_scratch:SI 5 "=&d")) ;; temp 2
(clobber (match_scratch:SI 6 "=&d")) ;; temp 3
(clobber (match_scratch:SI 7 "=&d")) ;; temp 4
(use (match_operand:SI 2 "small_int" "I")) ;; # bytes to move
(use (match_operand:SI 3 "small_int" "I")) ;; alignment
(use (const_int 2))] ;; just last store of block mvoe
""
"* return output_block_move (insn, operands, 4, BLOCK_MOVE_LAST);"
[(set_attr "type" "store")
(set_attr "mode" "none")
(set_attr "length" "1")])
;;
;; ....................
;;
;; SHIFTS
;;
;; ....................
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT)
operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);
return \"sll\\t%0,%1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "ashldi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "")
(ashift:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "arith_operand" "")))
(clobber (match_dup 3))])]
"!TARGET_DEBUG_G_MODE"
"operands[3] = gen_reg_rtx (SImode);")
(define_insn "ashldi3_internal"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE"
"*
{
operands[4] = const0_rtx;
dslots_jump_total += 3;
dslots_jump_filled += 2;
return \"sll\\t%3,%2,26\\n\\
\\tbgez\\t%3,1f\\n\\
\\tsll\\t%M0,%L1,%2\\n\\
\\t%(b\\t3f\\n\\
\\tmove\\t%L0,%z4%)\\n\\
\\n\\
1:\\n\\
\\t%(beq\\t%3,%z4,2f\\n\\
\\tsll\\t%M0,%M1,%2%)\\n\\
\\n\\
\\tsubu\\t%3,%z4,%2\\n\\
\\tsrl\\t%3,%L1,%3\\n\\
\\tor\\t%M0,%M0,%3\\n\\
2:\\n\\
\\tsll\\t%L0,%L1,%2\\n\\
3:\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "SI")
(set_attr "length" "12")])
(define_insn "ashldi3_internal2"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "IJK")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0"
"*
{
operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);
operands[4] = const0_rtx;
return \"sll\\t%M0,%L1,%2\;move\\t%L0,%z4\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashift:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 32) != 0"
[(set (subreg:SI (match_dup 0) 1) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))
(set (subreg:SI (match_dup 0) 0) (const_int 0))]
"operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashift:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 32) != 0"
[(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 1) (match_dup 2)))
(set (subreg:SI (match_dup 0) 1) (const_int 0))]
"operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);")
(define_insn "ashldi3_internal3"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashift:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "IJK")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
"*
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = const0_rtx;
operands[5] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
return \"sll\\t%M0,%M1,%2\;srl\\t%3,%L1,%5\;or\\t%M0,%M0,%3\;sll\\t%L0,%L1,%2\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashift:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
[(set (subreg:SI (match_dup 0) 1)
(ashift:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))
(set (match_dup 3)
(lshiftrt:SI (subreg:SI (match_dup 1) 0)
(match_dup 4)))
(set (subreg:SI (match_dup 0) 1)
(ior:SI (subreg:SI (match_dup 0) 1)
(match_dup 3)))
(set (subreg:SI (match_dup 0) 0)
(ashift:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))]
"
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
}")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashift:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
[(set (subreg:SI (match_dup 0) 0)
(ashift:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))
(set (match_dup 3)
(lshiftrt:SI (subreg:SI (match_dup 1) 1)
(match_dup 4)))
(set (subreg:SI (match_dup 0) 0)
(ior:SI (subreg:SI (match_dup 0) 0)
(match_dup 3)))
(set (subreg:SI (match_dup 0) 1)
(ashift:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))]
"
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
}")
(define_insn "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT)
operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);
return \"sra\\t%0,%1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "ashrdi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "arith_operand" "")))
(clobber (match_dup 3))])]
"!TARGET_DEBUG_G_MODE"
"operands[3] = gen_reg_rtx (SImode);")
(define_insn "ashrdi3_internal"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE"
"*
{
operands[4] = const0_rtx;
dslots_jump_total += 3;
dslots_jump_filled += 2;
return \"sll\\t%3,%2,26\\n\\
\\tbgez\\t%3,1f\\n\\
\\tsra\\t%L0,%M1,%2\\n\\
\\t%(b\\t3f\\n\\
\\tsra\\t%M0,%M1,31%)\\n\\
\\n\\
1:\\n\\
\\t%(beq\\t%3,%z4,2f\\n\\
\\tsrl\\t%L0,%L1,%2%)\\n\\
\\n\\
\\tsubu\\t%3,%z4,%2\\n\\
\\tsll\\t%3,%M1,%3\\n\\
\\tor\\t%L0,%L0,%3\\n\\
2:\\n\\
\\tsra\\t%M0,%M1,%2\\n\\
3:\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "12")])
(define_insn "ashrdi3_internal2"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "IJK")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0"
"*
{
operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);
return \"sra\\t%L0,%M1,%2\;sra\\t%M0,%M1,31\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 32) != 0"
[(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 1) (match_dup 2)))
(set (subreg:SI (match_dup 0) 1) (ashiftrt:SI (subreg:SI (match_dup 1) 1) (const_int 31)))]
"operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 32) != 0"
[(set (subreg:SI (match_dup 0) 1) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))
(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (const_int 31)))]
"operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);")
(define_insn "ashrdi3_internal3"
[(set (match_operand:DI 0 "register_operand" "=d")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "IJK")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
"*
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
return \"srl\\t%L0,%L1,%2\;sll\\t%3,%M1,%4\;or\\t%L0,%L0,%3\;sra\\t%M0,%M1,%2\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
[(set (subreg:SI (match_dup 0) 0)
(lshiftrt:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))
(set (match_dup 3)
(ashift:SI (subreg:SI (match_dup 1) 1)
(match_dup 4)))
(set (subreg:SI (match_dup 0) 0)
(ior:SI (subreg:SI (match_dup 0) 0)
(match_dup 3)))
(set (subreg:SI (match_dup 0) 1)
(ashiftrt:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))]
"
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
}")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
[(set (subreg:SI (match_dup 0) 1)
(lshiftrt:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))
(set (match_dup 3)
(ashift:SI (subreg:SI (match_dup 1) 0)
(match_dup 4)))
(set (subreg:SI (match_dup 0) 1)
(ior:SI (subreg:SI (match_dup 0) 1)
(match_dup 3)))
(set (subreg:SI (match_dup 0) 0)
(ashiftrt:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))]
"
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
}")
(define_insn "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"*
{
if (GET_CODE (operands[2]) == CONST_INT)
operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);
return \"srl\\t%0,%1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "lshrdi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "arith_operand" "")))
(clobber (match_dup 3))])]
"!TARGET_DEBUG_G_MODE"
"operands[3] = gen_reg_rtx (SImode);")
(define_insn "lshrdi3_internal"
[(set (match_operand:DI 0 "register_operand" "=&d")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE"
"*
{
operands[4] = const0_rtx;
dslots_jump_total += 3;
dslots_jump_filled += 2;
return \"sll\\t%3,%2,26\\n\\
\\tbgez\\t%3,1f\\n\\
\\tsrl\\t%L0,%M1,%2\\n\\
\\t%(b\\t3f\\n\\
\\tmove\\t%M0,%z4%)\\n\\
\\n\\
1:\\n\\
\\t%(beq\\t%3,%z4,2f\\n\\
\\tsrl\\t%L0,%L1,%2%)\\n\\
\\n\\
\\tsubu\\t%3,%z4,%2\\n\\
\\tsll\\t%3,%M1,%3\\n\\
\\tor\\t%L0,%L0,%3\\n\\
2:\\n\\
\\tsrl\\t%M0,%M1,%2\\n\\
3:\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "12")])
(define_insn "lshrdi3_internal2"
[(set (match_operand:DI 0 "register_operand" "=d")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "IJK")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0"
"*
{
operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);
operands[4] = const0_rtx;
return \"srl\\t%L0,%M1,%2\;move\\t%M0,%z4\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 32) != 0"
[(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 1) (match_dup 2)))
(set (subreg:SI (match_dup 0) 1) (const_int 0))]
"operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 32) != 0"
[(set (subreg:SI (match_dup 0) 1) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2)))
(set (subreg:SI (match_dup 0) 0) (const_int 0))]
"operands[2] = gen_rtx (CONST_INT, VOIDmode, (XINT (operands[2], 0))& 0x1f);")
(define_insn "lshrdi3_internal3"
[(set (match_operand:DI 0 "register_operand" "=d")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "IJK")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
"!TARGET_DEBUG_G_MODE
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
"*
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
return \"srl\\t%L0,%L1,%2\;sll\\t%3,%M1,%4\;or\\t%L0,%L0,%3\;srl\\t%M0,%M1,%2\";
}"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "4")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && !WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
[(set (subreg:SI (match_dup 0) 0)
(lshiftrt:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))
(set (match_dup 3)
(ashift:SI (subreg:SI (match_dup 1) 1)
(match_dup 4)))
(set (subreg:SI (match_dup 0) 0)
(ior:SI (subreg:SI (match_dup 0) 0)
(match_dup 3)))
(set (subreg:SI (match_dup 0) 1)
(lshiftrt:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))]
"
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
}")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
(match_operand:SI 2 "small_int" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
"reload_completed && WORDS_BIG_ENDIAN && !TARGET_DEBUG_D_MODE && !TARGET_DEBUG_G_MODE
&& GET_CODE (operands[0]) == REG && REGNO (operands[0]) < FIRST_PSEUDO_REGISTER
&& GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER
&& (INTVAL (operands[2]) & 63) < 32
&& (INTVAL (operands[2]) & 63) != 0"
[(set (subreg:SI (match_dup 0) 1)
(lshiftrt:SI (subreg:SI (match_dup 1) 1)
(match_dup 2)))
(set (match_dup 3)
(ashift:SI (subreg:SI (match_dup 1) 0)
(match_dup 4)))
(set (subreg:SI (match_dup 0) 1)
(ior:SI (subreg:SI (match_dup 0) 1)
(match_dup 3)))
(set (subreg:SI (match_dup 0) 0)
(lshiftrt:SI (subreg:SI (match_dup 1) 0)
(match_dup 2)))]
"
{
int amount = INTVAL (operands[2]);
operands[2] = gen_rtx (CONST_INT, VOIDmode, (amount & 31));
operands[4] = gen_rtx (CONST_INT, VOIDmode, ((-amount) & 31));
}")
;;
;; ....................
;;
;; COMPARISONS
;;
;; ....................
;; Flow here is rather complex:
;;
;; 1) The cmp{si,sf,df} routine is called. It deposits the
;; arguments into the branch_cmp array, and the type into
;; branch_type. No RTL is generated.
;;
;; 2) The appropriate branch define_expand is called, which then
;; creates the appropriate RTL for the comparison and branch.
;; Different CC modes are used, based on what type of branch is
;; done, so that we can constrain things appropriately. There
;; are assumptions in the rest of GCC that break if we fold the
;; operands into the branchs for integer operations, and use cc0
;; for floating point, so we use the fp status register instead.
;; If needed, an appropriate temporary is created to hold the
;; of the integer compare.
(define_expand "cmpsi"
[(set (cc0)
(compare:CC (match_operand:SI 0 "register_operand" "")
(match_operand:SI 1 "arith_operand" "")))]
""
"
{
if (operands[0]) /* avoid unused code message */
{
branch_cmp[0] = operands[0];
branch_cmp[1] = operands[1];
branch_type = CMP_SI;
DONE;
}
}")
(define_expand "tstsi"
[(set (cc0)
(match_operand:SI 0 "register_operand" ""))]
""
"
{
if (operands[0]) /* avoid unused code message */
{
branch_cmp[0] = operands[0];
branch_cmp[1] = const0_rtx;
branch_type = CMP_SI;
DONE;
}
}")
(define_expand "cmpdf"
[(set (cc0)
(compare:CC_FP (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
"
{
if (operands[0]) /* avoid unused code message */
{
branch_cmp[0] = operands[0];
branch_cmp[1] = operands[1];
branch_type = CMP_DF;
DONE;
}
}")
(define_expand "cmpsf"
[(set (cc0)
(compare:CC_FP (match_operand:SF 0 "register_operand" "")
(match_operand:SF 1 "register_operand" "")))]
"TARGET_HARD_FLOAT"
"
{
if (operands[0]) /* avoid unused code message */
{
branch_cmp[0] = operands[0];
branch_cmp[1] = operands[1];
branch_type = CMP_SF;
DONE;
}
}")
;;
;; ....................
;;
;; CONDITIONAL BRANCHES
;;
;; ....................
(define_insn "branch_fp_ne"
[(set (pc)
(if_then_else (ne:CC_FP (reg:CC_FP 66)
(const_int 0))
(match_operand 0 "pc_or_label_operand" "")
(match_operand 1 "pc_or_label_operand" "")))]
""
"*
{
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return (operands[0] != pc_rtx) ? \"%*bc1t%?\\t%0\" : \"%*bc1f%?\\t%1\";
}"
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "branch_fp_ne_rev"
[(set (pc)
(if_then_else (ne:CC_REV_FP (reg:CC_REV_FP 66)
(const_int 0))
(match_operand 0 "pc_or_label_operand" "")
(match_operand 1 "pc_or_label_operand" "")))]
""
"*
{
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return (operands[0] != pc_rtx) ? \"%*bc1f%?\\t%0\" : \"%*bc1t%?\\t%1\";
}"
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "branch_fp_eq"
[(set (pc)
(if_then_else (eq:CC_FP (reg:CC_FP 66)
(const_int 0))
(match_operand 0 "pc_or_label_operand" "")
(match_operand 1 "pc_or_label_operand" "")))]
""
"*
{
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return (operands[0] != pc_rtx) ? \"%*bc1f%?\\t%0\" : \"%*bc1t%?\\t%1\";
}"
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "branch_fp_eq_rev"
[(set (pc)
(if_then_else (eq:CC_REV_FP (reg:CC_REV_FP 66)
(const_int 0))
(match_operand 0 "pc_or_label_operand" "")
(match_operand 1 "pc_or_label_operand" "")))]
""
"*
{
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return (operands[0] != pc_rtx) ? \"%*bc1t%?\\t%0\" : \"%*bc1f%?\\t%1\";
}"
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "branch_zero"
[(set (pc)
(if_then_else (match_operator:SI 0 "cmp_op"
[(match_operand:SI 1 "arith32_operand" "rn")
(const_int 0)])
(match_operand 2 "pc_or_label_operand" "")
(match_operand 3 "pc_or_label_operand" "")))]
""
"*
{
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
/* Handle places where CSE has folded a constant into the register operand. */
if (GET_CODE (operands[1]) == CONST_INT)
{
int value = INTVAL (operands[1]);
int truth = 0;
switch (GET_CODE (operands[0]))
{
default: abort ();
case EQ: truth = (value == 0); break;
case NE: truth = (value != 0); break;
case GT: truth = (value > 0); break;
case GE: truth = (value >= 0); break;
case LT: truth = (value < 0); break;
case LE: truth = (value <= 0); break;
case GTU: truth = (((unsigned)value) > 0); break;
case GEU: truth = 1; break;
case LTU: truth = 0; break;
case LEU: truth = (((unsigned)value) <= 0); break;
}
if (operands[2] != pc_rtx)
return (truth) ? \"%*beq%?\\t%.,%.,%2\" : \"%*bne%?\\t%.,%.,%2\";
else
return (truth) ? \"%*bne%?\\t%.,%.,%2\" : \"%*beq%?\\t%.,%.,%2\";
}
if (operands[2] != pc_rtx)
{ /* normal jump */
switch (GET_CODE (operands[0]))
{
case EQ: return \"%*beq%?\\t%z1,%.,%2\";
case NE: return \"%*bne%?\\t%z1,%.,%2\";
case GTU: return \"%*bne%?\\t%z1,%.,%2\";
case LEU: return \"%*beq%?\\t%z1,%.,%2\";
case GEU: return \"%*j\\t%2\";
case LTU: return \"#%*bltuz\\t%z1,%2\";
}
return \"%*b%C0z%?\\t%z1,%2\";
}
else
{ /* inverted jump */
switch (GET_CODE (operands[0]))
{
case EQ: return \"%*bne%?\\t%z1,%.,%3\";
case NE: return \"%*beq%?\\t%z1,%.,%3\";
case GTU: return \"%*beq%?\\t%z1,%.,%3\";
case LEU: return \"%*bne%?\\t%z1,%.,%3\";
case GEU: return \"#%*bgeuz\\t%z1,%3\";
case LTU: return \"%*j\\t%3\";
}
return \"%*b%N0z%?\\t%z1,%3\";
}
}"
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "branch_equality"
[(set (pc)
(if_then_else (match_operator:SI 0 "equality_op"
[(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")])
(match_operand 3 "pc_or_label_operand" "")
(match_operand 4 "pc_or_label_operand" "")))]
""
"*
{
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
return (operands[3] != pc_rtx)
? \"%*b%C0%?\\t%z1,%z2,%3\"
: \"%*b%N0%?\\t%z1,%z2,%4\";
}"
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_expand "beq"
[(set (pc)
(if_then_else (eq:CC_EQ (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, EQ);
DONE;
}
}")
(define_expand "bne"
[(set (pc)
(if_then_else (ne:CC_EQ (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, NE);
DONE;
}
}")
(define_expand "bgt"
[(set (pc)
(if_then_else (gt:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, GT);
DONE;
}
}")
(define_expand "bge"
[(set (pc)
(if_then_else (ge:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, GE);
DONE;
}
}")
(define_expand "blt"
[(set (pc)
(if_then_else (lt:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, LT);
DONE;
}
}")
(define_expand "ble"
[(set (pc)
(if_then_else (le:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, LE);
DONE;
}
}")
(define_expand "bgtu"
[(set (pc)
(if_then_else (gtu:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, GTU);
DONE;
}
}")
(define_expand "bgeu"
[(set (pc)
(if_then_else (geu:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, GEU);
DONE;
}
}")
(define_expand "bltu"
[(set (pc)
(if_then_else (ltu:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, LTU);
DONE;
}
}")
(define_expand "bleu"
[(set (pc)
(if_then_else (leu:CC (cc0)
(const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
"
{
if (operands[0]) /* avoid unused code warning */
{
gen_conditional_branch (operands, LEU);
DONE;
}
}")
;;
;; ....................
;;
;; SETTING A REGISTER FROM A COMPARISON
;;
;; ....................
(define_expand "seq"
[(set (match_operand:SI 0 "register_operand" "=d")
(eq:SI (match_dup 1)
(match_dup 2)))]
""
"
{
extern rtx force_reg ();
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (EQ, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
operands[2] = force_reg (SImode, operands[2]);
/* fall through and generate default code */
}")
(define_insn "seq_si_zero"
[(set (match_operand:SI 0 "register_operand" "=d")
(eq:SI (match_operand:SI 1 "register_operand" "d")
(const_int 0)))]
""
"sltu\\t%0,%1,1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "seq_si"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(eq:SI (match_operand:SI 1 "register_operand" "%d,d")
(match_operand:SI 2 "uns_arith_operand" "d,K")))]
"TARGET_DEBUG_C_MODE"
"@
xor\\t%0,%1,%2\;sltu\\t%0,%0,1
xori\\t%0,%1,%2\;sltu\\t%0,%0,1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(eq:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "uns_arith_operand" "")))]
"TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE
&& (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)"
[(set (match_dup 0)
(xor:SI (match_dup 1)
(match_dup 2)))
(set (match_dup 0)
(ltu:SI (match_dup 0)
(const_int 1)))]
"")
(define_expand "sne"
[(set (match_operand:SI 0 "register_operand" "=d")
(ne:SI (match_dup 1)
(match_dup 2)))]
""
"
{
extern rtx force_reg ();
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (NE, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
operands[2] = force_reg (SImode, operands[2]);
/* fall through and generate default code */
}")
(define_insn "sne_si_zero"
[(set (match_operand:SI 0 "register_operand" "=d")
(ne:SI (match_operand:SI 1 "register_operand" "d")
(const_int 0)))]
""
"sltu\\t%0,%.,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "sne_si"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(ne:SI (match_operand:SI 1 "register_operand" "%d,d")
(match_operand:SI 2 "uns_arith_operand" "d,K")))]
"TARGET_DEBUG_C_MODE"
"@
xor\\t%0,%1,%2\;sltu\\t%0,%.,%0
xori\\t%0,%1,%x2\;sltu\\t%0,%.,%0"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(ne:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "uns_arith_operand" "")))]
"TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE
&& (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)"
[(set (match_dup 0)
(xor:SI (match_dup 1)
(match_dup 2)))
(set (match_dup 0)
(gtu:SI (match_dup 0)
(const_int 0)))]
"")
(define_expand "sgt"
[(set (match_operand:SI 0 "register_operand" "=d")
(gt:SI (match_dup 1)
(match_dup 2)))]
""
"
{
extern rtx force_reg ();
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (GT, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
operands[2] = force_reg (SImode, operands[2]);
/* fall through and generate default code */
}")
(define_insn "sgt_si"
[(set (match_operand:SI 0 "register_operand" "=d")
(gt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "reg_or_0_operand" "dJ")))]
""
"slt\\t%0,%z2,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "sge"
[(set (match_operand:SI 0 "register_operand" "=d")
(ge:SI (match_dup 1)
(match_dup 2)))]
""
"
{
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (GE, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
/* fall through and generate default code */
}")
(define_insn "sge_si"
[(set (match_operand:SI 0 "register_operand" "=d")
(ge:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
"TARGET_DEBUG_C_MODE"
"slt\\t%0,%1,%2\;xori\\t%0,%0,0x0001"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(ge:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith_operand" "")))]
"TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
[(set (match_dup 0)
(lt:SI (match_dup 1)
(match_dup 2)))
(set (match_dup 0)
(xor:SI (match_dup 0)
(const_int 1)))]
"")
(define_expand "slt"
[(set (match_operand:SI 0 "register_operand" "=d")
(lt:SI (match_dup 1)
(match_dup 2)))]
""
"
{
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (LT, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
/* fall through and generate default code */
}")
(define_insn "slt_si"
[(set (match_operand:SI 0 "register_operand" "=d")
(lt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"slt\\t%0,%1,%2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "sle"
[(set (match_operand:SI 0 "register_operand" "=d")
(le:SI (match_dup 1)
(match_dup 2)))]
""
"
{
extern rtx force_reg ();
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (LE, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32767)
operands[2] = force_reg (SImode, operands[2]);
/* fall through and generate default code */
}")
(define_insn "sle_si_const"
[(set (match_operand:SI 0 "register_operand" "=d")
(le:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "I")))]
"INTVAL (operands[2]) < 32767"
"*
{
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2])+1);
return \"slt\\t%0,%1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "sle_si_reg"
[(set (match_operand:SI 0 "register_operand" "=d")
(le:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
"TARGET_DEBUG_C_MODE"
"slt\\t%0,%z2,%1\;xori\\t%0,%0,0x0001"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(le:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "")))]
"TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
[(set (match_dup 0)
(lt:SI (match_dup 2)
(match_dup 1)))
(set (match_dup 0)
(xor:SI (match_dup 0)
(const_int 1)))]
"")
(define_expand "sgtu"
[(set (match_operand:SI 0 "register_operand" "=d")
(gtu:SI (match_dup 1)
(match_dup 2)))]
""
"
{
extern rtx force_reg ();
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (GTU, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
operands[2] = force_reg (SImode, operands[2]);
/* fall through and generate default code */
}")
(define_insn "sgtu_si"
[(set (match_operand:SI 0 "register_operand" "=d")
(gtu:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "reg_or_0_operand" "dJ")))]
""
"sltu\\t%0,%z2,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "sgeu"
[(set (match_operand:SI 0 "register_operand" "=d")
(geu:SI (match_dup 1)
(match_dup 2)))]
""
"
{
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (GEU, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
/* fall through and generate default code */
}")
(define_insn "sgeu_si"
[(set (match_operand:SI 0 "register_operand" "=d")
(geu:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
"TARGET_DEBUG_C_MODE"
"sltu\\t%0,%1,%2\;xori\\t%0,%0,0x0001"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(geu:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "arith_operand" "")))]
"TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
[(set (match_dup 0)
(ltu:SI (match_dup 1)
(match_dup 2)))
(set (match_dup 0)
(xor:SI (match_dup 0)
(const_int 1)))]
"")
(define_expand "sltu"
[(set (match_operand:SI 0 "register_operand" "=d")
(ltu:SI (match_dup 1)
(match_dup 2)))]
""
"
{
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (LTU, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
/* fall through and generate default code */
}")
(define_insn "sltu_si"
[(set (match_operand:SI 0 "register_operand" "=d")
(ltu:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "dI")))]
""
"sltu\\t%0,%1,%2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_expand "sleu"
[(set (match_operand:SI 0 "register_operand" "=d")
(leu:SI (match_dup 1)
(match_dup 2)))]
""
"
{
extern rtx force_reg ();
if (branch_type != CMP_SI)
FAIL;
/* set up operands from compare. */
operands[1] = branch_cmp[0];
operands[2] = branch_cmp[1];
if (!TARGET_DEBUG_C_MODE)
{
gen_int_relational (LEU, operands[0], operands[1], operands[2], (int *)0);
DONE;
}
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 32767)
operands[2] = force_reg (SImode, operands[2]);
/* fall through and generate default code */
}")
(define_insn "sleu_si_const"
[(set (match_operand:SI 0 "register_operand" "=d")
(leu:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "small_int" "I")))]
"INTVAL (operands[2]) < 32767"
"*
{
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2])+1);
return \"sltu\\t%0,%1,%2\";
}"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "1")])
(define_insn "sleu_si_reg"
[(set (match_operand:SI 0 "register_operand" "=d")
(leu:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
"TARGET_DEBUG_C_MODE"
"sltu\\t%0,%z2,%1\;xori\\t%0,%0,0x0001"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "2")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(leu:SI (match_operand:SI 1 "register_operand" "")
(match_operand:SI 2 "register_operand" "")))]
"TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
[(set (match_dup 0)
(ltu:SI (match_dup 2)
(match_dup 1)))
(set (match_dup 0)
(xor:SI (match_dup 0)
(const_int 1)))]
"")
;;
;; ....................
;;
;; FLOATING POINT COMPARISONS
;;
;; ....................
(define_insn "seq_df"
[(set (reg:CC_FP 66)
(eq:CC_FP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.eq.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sne_df"
[(set (reg:CC_REV_FP 66)
(ne:CC_REV_FP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.eq.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "slt_df"
[(set (reg:CC_FP 66)
(lt:CC_FP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.lt.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sle_df"
[(set (reg:CC_FP 66)
(le:CC_FP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.le.d\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sgt_df"
[(set (reg:CC_FP 66)
(gt:CC_FP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.lt.d\\t%1,%0\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sge_df"
[(set (reg:CC_FP 66)
(ge:CC_FP (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.le.d\\t%1,%0\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "seq_sf"
[(set (reg:CC_FP 66)
(eq:CC_FP (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.eq.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sne_sf"
[(set (reg:CC_REV_FP 66)
(ne:CC_REV_FP (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.eq.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "slt_sf"
[(set (reg:CC_FP 66)
(lt:CC_FP (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.lt.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sle_sf"
[(set (reg:CC_FP 66)
(le:CC_FP (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.le.s\\t%0,%1\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sgt_sf"
[(set (reg:CC_FP 66)
(gt:CC_FP (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.lt.s\\t%1,%0\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
(define_insn "sge_sf"
[(set (reg:CC_FP 66)
(ge:CC_FP (match_operand:SF 0 "register_operand" "f")
(match_operand:SF 1 "register_operand" "f")))]
""
"*
{
rtx xoperands[10];
xoperands[0] = gen_rtx (REG, CC_FPmode, FPSW_REGNUM);
xoperands[1] = operands[0];
xoperands[2] = operands[1];
return mips_fill_delay_slot (\"c.le.s\\t%1,%0\", DELAY_FCMP, xoperands, insn);
}"
[(set_attr "type" "fcmp")
(set_attr "mode" "FPSW")
(set_attr "length" "1")])
;;
;; ....................
;;
;; UNCONDITIONAL BRANCHES
;;
;; ....................
;; Unconditional branches.
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
"*
{
if (GET_CODE (operands[0]) == REG)
return \"%*j\\t%0\";
else
return \"%*j\\t%l0\";
}"
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "indirect_jump"
[(set (pc) (match_operand:SI 0 "register_operand" "d"))]
""
"%*j\\t%0"
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_insn "tablejump"
[(set (pc)
(match_operand:SI 0 "register_operand" "d"))
(use (label_ref (match_operand 1 "" "")))]
""
"%*j\\t%0"
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "1")])
;; Function return, only allow after optimization, so that we can
;; eliminate jumps to jumps if no stack space is used.
(define_insn "return"
[(return)]
"null_epilogue ()"
"*
{
operands[0] = gen_rtx (REG, SImode, GP_REG_FIRST + 31);
return \"%*j\\t%0\";
}"
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "1")])
;;
;; ....................
;;
;; FUNCTION CALLS
;;
;; ....................
;; calls.c now passes a third argument, make saber happy
(define_expand "call"
[(parallel [(call (match_operand 0 "memory_operand" "m")
(match_operand 1 "" "i"))
(clobber (match_operand 2 "" ""))])] ;; overwrite op2 with $31
""
"
{
rtx addr;
operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 31);
addr = XEXP (operands[0], 0);
if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
XEXP (operands[0], 0) = force_reg (FUNCTION_MODE, addr);
}")
(define_insn "call_internal"
[(call (match_operand 0 "memory_operand" "m")
(match_operand 1 "" "i"))
(clobber (match_operand:SI 2 "register_operand" "=d"))]
""
"*
{
register rtx target = XEXP (operands[0], 0);
if (GET_CODE (target) == SYMBOL_REF)
return \"%*jal\\t%0\";
else
{
operands[0] = target;
operands[1] = gen_rtx (REG, SImode, GP_REG_FIRST + 31);
return \"%*jal\\t%1,%0\";
}
}"
[(set_attr "type" "call")
(set_attr "mode" "none")
(set_attr "length" "1")])
;; calls.c now passes a fourth argument, make saber happy
(define_expand "call_value"
[(parallel [(set (match_operand 0 "register_operand" "=df")
(call (match_operand 1 "memory_operand" "m")
(match_operand 2 "" "i")))
(clobber (match_operand 3 "" ""))])] ;; overwrite op3 with $31
""
"
{
rtx addr;
operands[3] = gen_rtx (REG, SImode, GP_REG_FIRST + 31);
addr = XEXP (operands[1], 0);
if (GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
XEXP (operands[1], 0) = force_reg (FUNCTION_MODE, addr);
}")
(define_insn "call_value_internal"
[(set (match_operand 0 "register_operand" "=df")
(call (match_operand 1 "memory_operand" "m")
(match_operand 2 "" "i")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
""
"*
{
register rtx target = XEXP (operands[1], 0);
if (GET_CODE (target) == SYMBOL_REF)
return \"%*jal\\t%1\";
else
{
operands[1] = target;
operands[2] = gen_rtx (REG, SImode, GP_REG_FIRST + 31);
return \"%*jal\\t%2,%1\";
}
}"
[(set_attr "type" "call")
(set_attr "mode" "none")
(set_attr "length" "1")])
;;
;; ....................
;;
;; MISC.
;;
;; ....................
;;
(define_insn "nop"
[(const_int 0)]
""
"%(nop%)"
[(set_attr "type" "nop")
(set_attr "mode" "none")
(set_attr "length" "1")])
(define_expand "probe"
[(set (match_dup 0)
(match_dup 1))]
""
"
{
operands[0] = gen_reg_rtx (SImode);
operands[1] = gen_rtx (MEM, SImode, stack_pointer_rtx);
MEM_VOLATILE_P (operands[1]) = TRUE;
/* fall through and generate default code */
}")
;;
;; Local variables:
;; mode:emacs-lisp
;; comment-start: ";; "
;; eval: (set-syntax-table (copy-sequence (syntax-table)))
;; eval: (modify-syntax-entry ?[ "(]")
;; eval: (modify-syntax-entry ?] ")[")
;; eval: (modify-syntax-entry ?{ "(}")
;; eval: (modify-syntax-entry ?} "){")
;; End: