7144 lines
215 KiB
Markdown
7144 lines
215 KiB
Markdown
|
;; Mips.md Machine Description for MIPS based processors
|
|||
|
;; Contributed by A. Lichnewsky, lich@inria.inria.fr
|
|||
|
;; Changes by Michael Meissner, meissner@osf.org
|
|||
|
;; 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and
|
|||
|
;; Brendan Eich, brendan@microunity.com.
|
|||
|
;; Copyright (C) 1989, 90-96, 1997 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, 59 Temple Place - Suite 330,
|
|||
|
;; Boston, MA 02111-1307, USA.
|
|||
|
|
|||
|
;; ??? Currently does not have define_function_unit support for the R8000.
|
|||
|
;; Must include new entries for fmadd in addition to existing entries.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; 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
|
|||
|
;; fmadd floating point multiply-add
|
|||
|
;; 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
|
|||
|
|
|||
|
(define_attr "type"
|
|||
|
"unknown,branch,jump,call,load,store,move,xfer,hilo,arith,darith,imul,idiv,icmp,fadd,fmul,fmadd,fdiv,fabs,fneg,fcmp,fcvt,fsqrt,multi,nop"
|
|||
|
(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")
|
|||
|
(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"))))
|
|||
|
|
|||
|
;; ??? Fix everything that tests this attribute.
|
|||
|
(define_attr "cpu"
|
|||
|
"default,r3000,r6000,r4000,r4100,r4300,r4600,r4650,r5000,r8000"
|
|||
|
(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")])
|
|||
|
|
|||
|
;; whether or not generating calls to position independent functions
|
|||
|
(define_attr "abicalls" "no,yes"
|
|||
|
(const (symbol_ref "mips_abicalls_attr")))
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; .........................
|
|||
|
;;
|
|||
|
;; 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" "jump")
|
|||
|
[(and (eq_attr "dslot" "no") (eq_attr "length" "1"))
|
|||
|
(nil)
|
|||
|
(nil)])
|
|||
|
|
|||
|
(define_delay (and (eq_attr "type" "call") (eq_attr "abicalls" "no"))
|
|||
|
[(and (eq_attr "dslot" "no") (eq_attr "length" "1"))
|
|||
|
(nil)
|
|||
|
(nil)])
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; .........................
|
|||
|
;;
|
|||
|
;; Functional units
|
|||
|
;;
|
|||
|
;; .........................
|
|||
|
|
|||
|
; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
|
|||
|
; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
|
|||
|
|
|||
|
;; Make the default case (PROCESSOR_DEFAULT) handle the worst case
|
|||
|
|
|||
|
(define_function_unit "memory" 1 0
|
|||
|
(and (eq_attr "type" "load")
|
|||
|
(eq_attr "cpu" "!r3000,r4600,r4650,r4100,r4300,r5000"))
|
|||
|
3 0)
|
|||
|
|
|||
|
(define_function_unit "memory" 1 0
|
|||
|
(and (eq_attr "type" "load")
|
|||
|
(eq_attr "cpu" "r3000,r4600,r4650,r4100,r4300,r5000"))
|
|||
|
2 0)
|
|||
|
|
|||
|
(define_function_unit "memory" 1 0 (eq_attr "type" "store") 1 0)
|
|||
|
|
|||
|
(define_function_unit "memory" 1 0 (eq_attr "type" "xfer") 2 0)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(eq_attr "type" "hilo")
|
|||
|
1 3)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul")
|
|||
|
(eq_attr "cpu" "!r3000,r4000,r4600,r4650,r4100,r4300,r5000"))
|
|||
|
17 17)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul") (eq_attr "cpu" "r3000"))
|
|||
|
12 12)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul") (eq_attr "cpu" "r4000,r4600"))
|
|||
|
10 10)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul") (eq_attr "cpu" "r4650"))
|
|||
|
4 4)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul")
|
|||
|
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
|
|||
|
1 1)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul")
|
|||
|
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
|
|||
|
4 4)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul")
|
|||
|
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300,r5000")))
|
|||
|
5 5)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul")
|
|||
|
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
|
|||
|
8 8)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "imul")
|
|||
|
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
|
|||
|
9 9)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(eq_attr "cpu" "!r3000,r4000,r4600,r4650,r4100,r4300,r5000"))
|
|||
|
38 38)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv") (eq_attr "cpu" "r3000"))
|
|||
|
35 35)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv") (eq_attr "cpu" "r4600"))
|
|||
|
42 42)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv") (eq_attr "cpu" "r4650"))
|
|||
|
36 36)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv") (eq_attr "cpu" "r4000"))
|
|||
|
69 69)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r4100")))
|
|||
|
35 35)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r4100")))
|
|||
|
67 67)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r4300")))
|
|||
|
37 37)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r4300")))
|
|||
|
69 69)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(and (eq_attr "mode" "SI") (eq_attr "cpu" "r5000")))
|
|||
|
36 36)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "idiv")
|
|||
|
(and (eq_attr "mode" "DI") (eq_attr "cpu" "r5000")))
|
|||
|
68 68)
|
|||
|
|
|||
|
;; The R4300 does *NOT* have a seperate Floating Point Unit, instead
|
|||
|
;; the FP hardware is part of the normal ALU circuitry. This means FP
|
|||
|
;; instructions affect the pipe-line, and no functional unit
|
|||
|
;; parallelism can occur on R4300 processors. To force GCC into coding
|
|||
|
;; for only a single functional unit, we force the R4300 FP
|
|||
|
;; instructions to be processed in the "imuldiv" unit.
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fcmp") (eq_attr "cpu" "!r3000,r6000,r4300,r5000"))
|
|||
|
3 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fcmp") (eq_attr "cpu" "r3000,r6000"))
|
|||
|
2 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fcmp") (eq_attr "cpu" "r5000"))
|
|||
|
1 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fadd") (eq_attr "cpu" "!r3000,r6000,r4300"))
|
|||
|
4 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fadd") (eq_attr "cpu" "r3000"))
|
|||
|
2 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fadd") (eq_attr "cpu" "r6000"))
|
|||
|
3 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fabs,fneg")
|
|||
|
(eq_attr "cpu" "!r3000,r4600,r4650,r4300,r5000"))
|
|||
|
2 0)
|
|||
|
|
|||
|
(define_function_unit "adder" 1 1
|
|||
|
(and (eq_attr "type" "fabs,fneg") (eq_attr "cpu" "r3000,r4600,r4650,r5000"))
|
|||
|
1 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "SF")
|
|||
|
(eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300,r5000")))
|
|||
|
7 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000,r5000")))
|
|||
|
4 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
|
|||
|
5 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
|
|||
|
8 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "!r3000,r6000,r4300,r5000")))
|
|||
|
8 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000,r5000")))
|
|||
|
5 0)
|
|||
|
|
|||
|
(define_function_unit "mult" 1 1
|
|||
|
(and (eq_attr "type" "fmul")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
|
|||
|
6 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "SF")
|
|||
|
(eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300,r5000")))
|
|||
|
23 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r3000")))
|
|||
|
12 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r6000")))
|
|||
|
15 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
|
|||
|
32 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000")))
|
|||
|
21 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "DF")
|
|||
|
(eq_attr "cpu" "!r3000,r6000,r4600,r4650,r4300")))
|
|||
|
36 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r3000")))
|
|||
|
19 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r6000")))
|
|||
|
16 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fdiv")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
|
|||
|
61 0)
|
|||
|
|
|||
|
;;; ??? Is this number right?
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fsqrt")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
|
|||
|
54 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fsqrt")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r4600,r4650")))
|
|||
|
31 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fsqrt")
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r5000")))
|
|||
|
21 0)
|
|||
|
|
|||
|
;;; ??? Is this number right?
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fsqrt")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "!r4600,r4650,r4300,r5000")))
|
|||
|
112 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fsqrt")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r4600,r4650")))
|
|||
|
60 0)
|
|||
|
|
|||
|
(define_function_unit "divide" 1 1
|
|||
|
(and (eq_attr "type" "fsqrt")
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r5000")))
|
|||
|
36 0)
|
|||
|
|
|||
|
;; R4300 FP instruction classes treated as part of the "imuldiv"
|
|||
|
;; functional unit:
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "fadd") (eq_attr "cpu" "r4300"))
|
|||
|
3 3)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "fcmp,fabs,fneg") (eq_attr "cpu" "r4300"))
|
|||
|
1 1)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "SF") (eq_attr "cpu" "r4300")))
|
|||
|
5 5)
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (eq_attr "type" "fmul") (and (eq_attr "mode" "DF") (eq_attr "cpu" "r4300")))
|
|||
|
8 8)
|
|||
|
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt"))
|
|||
|
(and (eq_attr "mode" "SF") (eq_attr "cpu" "r4300")))
|
|||
|
29 29)
|
|||
|
(define_function_unit "imuldiv" 1 0
|
|||
|
(and (and (eq_attr "type" "fdiv") (eq_attr "type" "fsqrt"))
|
|||
|
(and (eq_attr "mode" "DF") (eq_attr "cpu" "r4300")))
|
|||
|
58 58)
|
|||
|
|
|||
|
;; 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") 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 0)
|
|||
|
;; (define_function_unit "imuldiv" 1 1 (eq_attr "type" "idiv") 38 0)
|
|||
|
;;
|
|||
|
;; (define_function_unit "adder" 1 1 (eq_attr "type" "fadd") 4 0)
|
|||
|
;; (define_function_unit "adder" 1 1 (eq_attr "type" "fabs,fneg") 2 0)
|
|||
|
;;
|
|||
|
;; (define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (eq_attr "mode" "SF")) 7 0)
|
|||
|
;; (define_function_unit "mult" 1 1 (and (eq_attr "type" "fmul") (eq_attr "mode" "DF")) 8 0)
|
|||
|
;;
|
|||
|
;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "SF")) 23 0)
|
|||
|
;; (define_function_unit "divide" 1 1 (and (eq_attr "type" "fdiv") (eq_attr "mode" "DF")) 36 0)
|
|||
|
;;
|
|||
|
;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "SF")) 54 0)
|
|||
|
;; (define_function_unit "sqrt" 1 1 (and (eq_attr "type" "fsqrt") (eq_attr "mode" "DF")) 112 0)
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; 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 && TARGET_DOUBLE_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_expand "addsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768)
|
|||
|
operands[2] = force_reg (SImode, operands[2]);
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "addsi3_internal"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
|||
|
"GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768"
|
|||
|
"addu\\t%0,%z1,%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 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "")))
|
|||
|
(clobber (match_dup 3))])]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768)
|
|||
|
operands[2] = force_reg (DImode, operands[2]);
|
|||
|
|
|||
|
if (TARGET_64BIT)
|
|||
|
{
|
|||
|
emit_insn (gen_adddi3_internal_3 (operands[0], operands[1],
|
|||
|
operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
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_64BIT && !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_64BIT && !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_64BIT && !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_64BIT && !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_64BIT && !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_64BIT && !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)))]
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "adddi3_internal_3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(plus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)"
|
|||
|
"*
|
|||
|
{
|
|||
|
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
|
|||
|
? \"dsubu\\t%0,%z1,%n2\"
|
|||
|
: \"daddu\\t%0,%z1,%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
(define_insn "addsi3_internal_2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(sign_extend:DI (plus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI"))))]
|
|||
|
"TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)"
|
|||
|
"*
|
|||
|
{
|
|||
|
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
|
|||
|
? \"subu\\t%0,%z1,%n2\"
|
|||
|
: \"addu\\t%0,%z1,%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; 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 && TARGET_DOUBLE_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_expand "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")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == -32768)
|
|||
|
operands[2] = force_reg (SImode, operands[2]);
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "subsi3_internal"
|
|||
|
[(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")))]
|
|||
|
"GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768"
|
|||
|
"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 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(clobber (match_dup 3))])]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
{
|
|||
|
emit_insn (gen_subdi3_internal_3 (operands[0], operands[1],
|
|||
|
operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
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_64BIT && !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_64BIT && !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_64BIT && !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_64BIT && !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_64BIT && !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_64BIT && !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)))]
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "subdi3_internal_3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(minus:DI (match_operand:DI 1 "se_reg_or_0_operand" "dJ")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)"
|
|||
|
"*
|
|||
|
{
|
|||
|
return (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
|
|||
|
? \"daddu\\t%0,%z1,%n2\"
|
|||
|
: \"dsubu\\t%0,%z1,%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
(define_insn "subsi3_internal_2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(sign_extend:DI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "dJ")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI"))))]
|
|||
|
"TARGET_64BIT && (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != -32768)"
|
|||
|
"*
|
|||
|
{
|
|||
|
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" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; MULTIPLICATION
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
|
|||
|
;; Early Vr4300 silicon has a CPU bug where multiplies with certain
|
|||
|
;; operands may corrupt immediately following multiplies. This is a
|
|||
|
;; simple fix to insert NOPs.
|
|||
|
|
|||
|
(define_expand "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 && TARGET_DOUBLE_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (mips_cpu != PROCESSOR_R4300)
|
|||
|
emit_insn (gen_muldf3_internal (operands[0], operands[1], operands[2]));
|
|||
|
else
|
|||
|
emit_insn (gen_muldf3_r4300 (operands[0], operands[1], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "muldf3_internal"
|
|||
|
[(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 && TARGET_DOUBLE_FLOAT && mips_cpu != PROCESSOR_R4300"
|
|||
|
"mul.d\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "fmul")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "muldf3_r4300"
|
|||
|
[(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 && TARGET_DOUBLE_FLOAT && mips_cpu == PROCESSOR_R4300"
|
|||
|
"*
|
|||
|
{
|
|||
|
output_asm_insn (\"mul.d\\t%0,%1,%2\", operands);
|
|||
|
if (TARGET_4300_MUL_FIX)
|
|||
|
output_asm_insn (\"nop\", operands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "fmul")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "2")]) ;; mul.d + nop
|
|||
|
|
|||
|
(define_expand "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"
|
|||
|
"
|
|||
|
{
|
|||
|
if (mips_cpu != PROCESSOR_R4300)
|
|||
|
emit_insn( gen_mulsf3_internal (operands[0], operands[1], operands[2]));
|
|||
|
else
|
|||
|
emit_insn( gen_mulsf3_r4300 (operands[0], operands[1], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "mulsf3_internal"
|
|||
|
[(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 && mips_cpu != PROCESSOR_R4300"
|
|||
|
"mul.s\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "fmul")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "mulsf3_r4300"
|
|||
|
[(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 && mips_cpu == PROCESSOR_R4300"
|
|||
|
"*
|
|||
|
{
|
|||
|
output_asm_insn (\"mul.s\\t%0,%1,%2\", operands);
|
|||
|
if (TARGET_4300_MUL_FIX)
|
|||
|
output_asm_insn (\"nop\", operands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "fmul")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "2")]) ;; mul.s + nop
|
|||
|
|
|||
|
;; ??? The R4000 (only) has a cpu bug. If a double-word shift executes while
|
|||
|
;; a multiply is in progress, it may give an incorrect result. Avoid
|
|||
|
;; this by keeping the mflo with the mult on the R4000.
|
|||
|
|
|||
|
(define_expand "mulsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=l")
|
|||
|
(mult:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(clobber (match_scratch:SI 3 "=h"))
|
|||
|
(clobber (match_scratch:SI 4 "=a"))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_MAD)
|
|||
|
emit_insn (gen_mulsi3_r4650 (operands[0], operands[1], operands[2]));
|
|||
|
else if (mips_cpu != PROCESSOR_R4000)
|
|||
|
emit_insn (gen_mulsi3_internal (operands[0], operands[1], operands[2]));
|
|||
|
else
|
|||
|
emit_insn (gen_mulsi3_r4000 (operands[0], operands[1], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "mulsi3_internal"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=l")
|
|||
|
(mult:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(clobber (match_scratch:SI 3 "=h"))
|
|||
|
(clobber (match_scratch:SI 4 "=a"))]
|
|||
|
"mips_cpu != PROCESSOR_R4000"
|
|||
|
"mult\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "mulsi3_r4000"
|
|||
|
[(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 (match_scratch:SI 3 "=h"))
|
|||
|
(clobber (match_scratch:SI 4 "=l"))
|
|||
|
(clobber (match_scratch:SI 5 "=a"))]
|
|||
|
"mips_cpu == PROCESSOR_R4000"
|
|||
|
"*
|
|||
|
{
|
|||
|
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, FALSE), xoperands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "3")]) ;; mult + mflo + delay
|
|||
|
|
|||
|
(define_insn "mulsi3_r4650"
|
|||
|
[(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 (match_scratch:SI 3 "=h"))
|
|||
|
(clobber (match_scratch:SI 4 "=l"))
|
|||
|
(clobber (match_scratch:SI 5 "=a"))]
|
|||
|
"TARGET_MAD"
|
|||
|
"mul\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "muldi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=l")
|
|||
|
(mult:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "register_operand" "d")))
|
|||
|
(clobber (match_scratch:DI 3 "=h"))
|
|||
|
(clobber (match_scratch:DI 4 "=a"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (mips_cpu != PROCESSOR_R4000)
|
|||
|
emit_insn (gen_muldi3_internal (operands[0], operands[1], operands[2]));
|
|||
|
else
|
|||
|
emit_insn (gen_muldi3_r4000 (operands[0], operands[1], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; Don't accept both operands using se_register_operand, because if
|
|||
|
;; both operands are sign extended we would prefer to use mult in the
|
|||
|
;; mulsidi3 pattern. Commutativity should permit either operand to be
|
|||
|
;; sign extended.
|
|||
|
|
|||
|
(define_insn "muldi3_internal"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=l")
|
|||
|
(mult:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "register_operand" "d")))
|
|||
|
(clobber (match_scratch:DI 3 "=h"))
|
|||
|
(clobber (match_scratch:DI 4 "=a"))]
|
|||
|
"TARGET_64BIT && mips_cpu != PROCESSOR_R4000"
|
|||
|
"dmult\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "muldi3_r4000"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(mult:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "register_operand" "d")))
|
|||
|
(clobber (match_scratch:DI 3 "=h"))
|
|||
|
(clobber (match_scratch:DI 4 "=l"))
|
|||
|
(clobber (match_scratch:DI 5 "=a"))]
|
|||
|
"TARGET_64BIT && mips_cpu == PROCESSOR_R4000"
|
|||
|
"*
|
|||
|
{
|
|||
|
rtx xoperands[10];
|
|||
|
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = gen_rtx (REG, DImode, LO_REGNUM);
|
|||
|
|
|||
|
output_asm_insn (\"dmult\\t%1,%2\", operands);
|
|||
|
output_asm_insn (mips_move_1word (xoperands, insn, FALSE), xoperands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "3")]) ;; mult + mflo + delay
|
|||
|
|
|||
|
;; ??? We could define a mulditi3 pattern when TARGET_64BIT.
|
|||
|
|
|||
|
(define_expand "mulsidi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
|||
|
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
emit_insn (gen_mulsidi3_64bit (operands[0], operands[1], operands[2]));
|
|||
|
else
|
|||
|
emit_insn (gen_mulsidi3_internal (operands[0], operands[1], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "mulsidi3_internal"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
|||
|
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
|||
|
(clobber (match_scratch:SI 3 "=a"))]
|
|||
|
"!TARGET_64BIT"
|
|||
|
"mult\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "mulsidi3_64bit"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=a")
|
|||
|
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"mult\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "smulsi3_highpart"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=h")
|
|||
|
(truncate:SI
|
|||
|
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(sign_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
|||
|
(const_int 32))))
|
|||
|
(clobber (match_scratch:SI 3 "=l"))
|
|||
|
(clobber (match_scratch:SI 4 "=a"))]
|
|||
|
""
|
|||
|
"mult\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "umulsidi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
|||
|
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
emit_insn (gen_umulsidi3_64bit (operands[0], operands[1], operands[2]));
|
|||
|
else
|
|||
|
emit_insn (gen_umulsidi3_internal (operands[0], operands[1], operands[2]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "umulsidi3_internal"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=x")
|
|||
|
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
|||
|
(clobber (match_scratch:SI 3 "=a"))]
|
|||
|
"!TARGET_64BIT"
|
|||
|
"multu\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "umulsidi3_64bit"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=a")
|
|||
|
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"multu\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "umulsi3_highpart"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=h")
|
|||
|
(truncate:SI
|
|||
|
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(zero_extend:DI (match_operand:SI 2 "register_operand" "d")))
|
|||
|
(const_int 32))))
|
|||
|
(clobber (match_scratch:SI 3 "=l"))
|
|||
|
(clobber (match_scratch:SI 4 "=a"))]
|
|||
|
""
|
|||
|
"multu\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "smuldi3_highpart"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=h")
|
|||
|
(truncate:DI
|
|||
|
(lshiftrt:TI (mult:TI (sign_extend:TI (match_operand:DI 1 "se_register_operand" "d"))
|
|||
|
(sign_extend:TI (match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(const_int 64))))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=a"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"dmult\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "umuldi3_highpart"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=h")
|
|||
|
(truncate:DI
|
|||
|
(lshiftrt:TI (mult:TI (zero_extend:TI (match_operand:DI 1 "se_register_operand" "d"))
|
|||
|
(zero_extend:TI (match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(const_int 64))))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=a"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"dmultu\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; The R4650 supports a 32 bit multiply/ 64 bit accumulate
|
|||
|
;; instruction. The HI/LO registers are used as a 64 bit accumulator.
|
|||
|
|
|||
|
(define_insn "madsi"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "+l")
|
|||
|
(plus:SI (mult:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d"))
|
|||
|
(match_dup 0)))
|
|||
|
(clobber (match_scratch:SI 3 "=h"))
|
|||
|
(clobber (match_scratch:SI 4 "=a"))]
|
|||
|
"TARGET_MAD"
|
|||
|
"mad\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "maddi"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "+x")
|
|||
|
(plus:DI (mult:DI (sign_extend:DI
|
|||
|
(match_operand:SI 1 "register_operand" "d"))
|
|||
|
(sign_extend:DI
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(match_dup 0)))
|
|||
|
(clobber (match_scratch:SI 3 "=a"))]
|
|||
|
"TARGET_MAD && ! TARGET_64BIT"
|
|||
|
"mad\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "maddi_64bit"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "+a")
|
|||
|
(plus:DI (mult:DI (sign_extend:DI
|
|||
|
(match_operand:SI 1 "register_operand" "d"))
|
|||
|
(sign_extend:DI
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(match_dup 0)))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))]
|
|||
|
"TARGET_MAD && TARGET_64BIT"
|
|||
|
"mad\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "umaddi"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "+x")
|
|||
|
(plus:DI (mult:DI (zero_extend:DI
|
|||
|
(match_operand:SI 1 "register_operand" "d"))
|
|||
|
(zero_extend:DI
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(match_dup 0)))
|
|||
|
(clobber (match_scratch:SI 3 "=a"))]
|
|||
|
"TARGET_MAD && ! TARGET_64BIT"
|
|||
|
"madu\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "umaddi_64bit"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "+a")
|
|||
|
(plus:DI (mult:DI (zero_extend:DI
|
|||
|
(match_operand:SI 1 "register_operand" "d"))
|
|||
|
(zero_extend:DI
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(match_dup 0)))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))]
|
|||
|
"TARGET_MAD && TARGET_64BIT"
|
|||
|
"madu\\t%1,%2"
|
|||
|
[(set_attr "type" "imul")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; Floating point multiply accumulate instructions.
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(plus:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f"))
|
|||
|
(match_operand:DF 3 "register_operand" "f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"madd.d\\t%0,%3,%1,%2"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(plus:SF (mult:SF (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f"))
|
|||
|
(match_operand:SF 3 "register_operand" "f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"madd.s\\t%0,%3,%1,%2"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(minus:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f"))
|
|||
|
(match_operand:DF 3 "register_operand" "f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"msub.d\\t%0,%3,%1,%2"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(minus:SF (mult:SF (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f"))
|
|||
|
(match_operand:SF 3 "register_operand" "f")))]
|
|||
|
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"msub.s\\t%0,%3,%1,%2"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(neg:DF (plus:DF (mult:DF (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f"))
|
|||
|
(match_operand:DF 3 "register_operand" "f"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"nmadd.d\\t%0,%3,%1,%2"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(neg:SF (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f"))
|
|||
|
(match_operand:SF 3 "register_operand" "f"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"nmadd.s\\t%0,%3,%1,%2"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(minus:DF (match_operand:DF 1 "register_operand" "f")
|
|||
|
(mult:DF (match_operand:DF 2 "register_operand" "f")
|
|||
|
(match_operand:DF 3 "register_operand" "f"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"nmsub.d\\t%0,%1,%2,%3"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(minus:SF (match_operand:SF 1 "register_operand" "f")
|
|||
|
(mult:SF (match_operand:SF 2 "register_operand" "f")
|
|||
|
(match_operand:SF 3 "register_operand" "f"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"nmsub.s\\t%0,%1,%2,%3"
|
|||
|
[(set_attr "type" "fmadd")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; 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 && TARGET_DOUBLE_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")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(div:DF (match_operand:DF 1 "const_float_1_operand" "")
|
|||
|
(match_operand:DF 2 "register_operand" "f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_fast_math"
|
|||
|
"recip.d\\t%0,%2"
|
|||
|
[(set_attr "type" "fdiv")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(div:SF (match_operand:SF 1 "const_float_1_operand" "")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && flag_fast_math"
|
|||
|
"recip.s\\t%0,%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
|
|||
|
|
|||
|
;; ??? We can't accept constants here, because the MIPS assembler will replace
|
|||
|
;; a divide by power of 2 with a shift, and then the remainder is no longer
|
|||
|
;; available.
|
|||
|
|
|||
|
(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 (match_scratch:SI 4 "=l"))
|
|||
|
(clobber (match_scratch:SI 5 "=h"))
|
|||
|
(clobber (match_scratch:SI 6 "=a"))]
|
|||
|
"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" "14")]) ;; various tests for dividing by 0 and such
|
|||
|
|
|||
|
(define_insn "divmoddi4"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(div:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(set (match_operand:DI 3 "register_operand" "=d")
|
|||
|
(mod:DI (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(clobber (match_scratch:DI 4 "=l"))
|
|||
|
(clobber (match_scratch:DI 5 "=h"))
|
|||
|
(clobber (match_scratch:DI 6 "=a"))]
|
|||
|
"TARGET_64BIT && optimize"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (find_reg_note (insn, REG_UNUSED, operands[3]))
|
|||
|
return \"ddiv\\t%0,%1,%2\";
|
|||
|
|
|||
|
if (find_reg_note (insn, REG_UNUSED, operands[0]))
|
|||
|
return \"drem\\t%3,%1,%2\";
|
|||
|
|
|||
|
return \"ddiv\\t%0,%1,%2\;mfhi\\t%3\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "15")]) ;; 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 (match_scratch:SI 4 "=l"))
|
|||
|
(clobber (match_scratch:SI 5 "=h"))
|
|||
|
(clobber (match_scratch:SI 6 "=a"))]
|
|||
|
"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" "8")]) ;; various tests for dividing by 0 and such
|
|||
|
|
|||
|
(define_insn "udivmoddi4"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(udiv:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(set (match_operand:DI 3 "register_operand" "=d")
|
|||
|
(umod:DI (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(clobber (match_scratch:DI 4 "=l"))
|
|||
|
(clobber (match_scratch:DI 5 "=h"))
|
|||
|
(clobber (match_scratch:DI 6 "=a"))]
|
|||
|
"TARGET_64BIT && optimize"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (find_reg_note (insn, REG_UNUSED, operands[3]))
|
|||
|
return \"ddivu\\t%0,%1,%2\";
|
|||
|
|
|||
|
if (find_reg_note (insn, REG_UNUSED, operands[0]))
|
|||
|
return \"dremu\\t%3,%1,%2\";
|
|||
|
|
|||
|
return \"ddivu\\t%0,%1,%2\;mfhi\\t%3\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "8")]) ;; 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 "nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:SI 3 "=l"))
|
|||
|
(clobber (match_scratch:SI 4 "=h"))
|
|||
|
(clobber (match_scratch:SI 6 "=a"))]
|
|||
|
"!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 "divdi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(div:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))
|
|||
|
(clobber (match_scratch:DI 6 "=a"))]
|
|||
|
"TARGET_64BIT && !optimize"
|
|||
|
"ddiv\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "14")]) ;; 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 "nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:SI 3 "=l"))
|
|||
|
(clobber (match_scratch:SI 4 "=h"))
|
|||
|
(clobber (match_scratch:SI 6 "=a"))]
|
|||
|
"!optimize"
|
|||
|
"rem\\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 "moddi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(mod:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))
|
|||
|
(clobber (match_scratch:DI 6 "=a"))]
|
|||
|
"TARGET_64BIT && !optimize"
|
|||
|
"drem\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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 "nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:SI 3 "=l"))
|
|||
|
(clobber (match_scratch:SI 4 "=h"))
|
|||
|
(clobber (match_scratch:SI 6 "=a"))]
|
|||
|
"!optimize"
|
|||
|
"divu\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "7")]) ;; various tests for dividing by 0 and such
|
|||
|
|
|||
|
(define_insn "udivdi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(udiv:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))
|
|||
|
(clobber (match_scratch:DI 6 "=a"))]
|
|||
|
"TARGET_64BIT && !optimize"
|
|||
|
"ddivu\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "7")]) ;; 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 "nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:SI 3 "=l"))
|
|||
|
(clobber (match_scratch:SI 4 "=h"))
|
|||
|
(clobber (match_scratch:SI 6 "=a"))]
|
|||
|
"!optimize"
|
|||
|
"remu\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "7")]) ;; various tests for dividing by 0 and such
|
|||
|
|
|||
|
(define_insn "umoddi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(umod:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_nonmemory_operand" "di")))
|
|||
|
(clobber (match_scratch:DI 3 "=l"))
|
|||
|
(clobber (match_scratch:DI 4 "=h"))
|
|||
|
(clobber (match_scratch:DI 6 "=a"))]
|
|||
|
"TARGET_64BIT && !optimize"
|
|||
|
"dremu\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "idiv")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "7")]) ;; 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() && TARGET_DOUBLE_FLOAT"
|
|||
|
"sqrt.d\\t%0,%1"
|
|||
|
[(set_attr "type" "fsqrt")
|
|||
|
(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" "fsqrt")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(div:DF (match_operand:DF 1 "const_float_1_operand" "")
|
|||
|
(sqrt:DF (match_operand:DF 2 "register_operand" "f"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && flag_fast_math"
|
|||
|
"rsqrt.d\\t%0,%2"
|
|||
|
[(set_attr "type" "fsqrt")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(div:SF (match_operand:SF 1 "const_float_1_operand" "")
|
|||
|
(sqrt:SF (match_operand:SF 2 "register_operand" "f"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && flag_fast_math"
|
|||
|
"rsqrt.s\\t%0,%2"
|
|||
|
[(set_attr "type" "fsqrt")
|
|||
|
(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;
|
|||
|
|
|||
|
if (REGNO (operands[0]) == REGNO (operands[1]))
|
|||
|
{
|
|||
|
if (mips_isa >= 2)
|
|||
|
return \"%(bltzl\\t%1,1f\\n\\tsubu\\t%0,%z2,%0\\n1:%)\";
|
|||
|
else
|
|||
|
return \"bgez\\t%1,1f%#\\n\\tsubu\\t%0,%z2,%0\\n1:\";
|
|||
|
}
|
|||
|
else
|
|||
|
return \"%(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 "absdi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(abs:DI (match_operand:DI 1 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
dslots_jump_total++;
|
|||
|
dslots_jump_filled++;
|
|||
|
operands[2] = const0_rtx;
|
|||
|
|
|||
|
if (REGNO (operands[0]) == REGNO (operands[1]))
|
|||
|
return \"%(bltzl\\t%1,1f\\n\\tdsubu\\t%0,%z2,%0\\n1:%)\";
|
|||
|
else
|
|||
|
return \"%(bgez\\t%1,1f\\n\\tmove\\t%0,%1\\n\\tdsubu\\t%0,%z2,%0\\n1:%)\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "multi")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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 && TARGET_DOUBLE_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")])
|
|||
|
|
|||
|
(define_insn "ffsdi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=&d")
|
|||
|
(ffs:DI (match_operand:DI 1 "se_register_operand" "d")))
|
|||
|
(clobber (match_scratch:DI 2 "=&d"))
|
|||
|
(clobber (match_scratch:DI 3 "=&d"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
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\\
|
|||
|
\\tdaddu\\t%0,%0,1\\n\\
|
|||
|
\\tbeq\\t%2,%z4,1b\\n\\
|
|||
|
\\tdsrl\\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\\
|
|||
|
\\tdaddu\\t%0,%0,1\\n\\
|
|||
|
\\tbeq\\t%2,%z4,1b\\n\\
|
|||
|
\\tdsrl\\t%3,%3,1\\n\\
|
|||
|
2:%)\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "multi")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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 "negdi2"
|
|||
|
[(parallel [(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(neg:DI (match_operand:DI 1 "se_register_operand" "d")))
|
|||
|
(clobber (match_dup 2))])]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
{
|
|||
|
emit_insn (gen_negdi2_internal_2 (operands[0], operands[1]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
operands[2] = gen_reg_rtx (SImode);
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "negdi2_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_64BIT && !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 "negdi2_internal_2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(neg:DI (match_operand:DI 1 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
operands[2] = const0_rtx;
|
|||
|
return \"dsubu\\t%0,%z2,%1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "negdf2"
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(neg:DF (match_operand:DF 1 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_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:DI (match_operand:DI 1 "se_register_operand" "d")))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
operands[2] = const0_rtx;
|
|||
|
if (TARGET_64BIT)
|
|||
|
return \"nor\\t%0,%z2,%1\";
|
|||
|
return \"nor\\t%M0,%z2,%M1\;nor\\t%L0,%z2,%L1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set (attr "length")
|
|||
|
(if_then_else (ge (symbol_ref "mips_isa") (const_int 3))
|
|||
|
(const_int 1)
|
|||
|
(const_int 2)))])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(not:DI (match_operand:DI 1 "register_operand" "")))]
|
|||
|
"reload_completed && !TARGET_64BIT && !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)))]
|
|||
|
"")
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; LOGICAL
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
|
|||
|
(define_insn "andsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
|||
|
(and:SI (match_operand:SI 1 "uns_arith_operand" "%d,d")
|
|||
|
(match_operand:SI 2 "uns_arith_operand" "d,K")))]
|
|||
|
""
|
|||
|
"@
|
|||
|
and\\t%0,%1,%2
|
|||
|
andi\\t%0,%1,%x2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "anddi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(and:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
return \"and\\t%0,%1,%2\";
|
|||
|
return \"and\\t%M0,%M1,%M2\;and\\t%L0,%L1,%L2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set (attr "length")
|
|||
|
(if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0))
|
|||
|
(const_int 1)
|
|||
|
(const_int 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_64BIT && !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 "anddi3_internal1"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(and:DI (match_operand:DI 1 "se_register_operand" "%d,d")
|
|||
|
(match_operand:DI 2 "se_uns_arith_operand" "d,K")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"@
|
|||
|
and\\t%0,%1,%2
|
|||
|
andi\\t%0,%1,%x2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "iorsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
|||
|
(ior:SI (match_operand:SI 1 "uns_arith_operand" "%d,d")
|
|||
|
(match_operand:SI 2 "uns_arith_operand" "d,K")))]
|
|||
|
""
|
|||
|
"@
|
|||
|
or\\t%0,%1,%2
|
|||
|
ori\\t%0,%1,%x2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;;; ??? There is no iordi3 pattern which accepts 'K' constants when
|
|||
|
;;; TARGET_64BIT
|
|||
|
|
|||
|
(define_insn "iordi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(ior:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
return \"or\\t%0,%1,%2\";
|
|||
|
return \"or\\t%M0,%M1,%M2\;or\\t%L0,%L1,%L2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set (attr "length")
|
|||
|
(if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0))
|
|||
|
(const_int 1)
|
|||
|
(const_int 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_64BIT && !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")
|
|||
|
(xor:SI (match_operand:SI 1 "uns_arith_operand" "%d,d")
|
|||
|
(match_operand:SI 2 "uns_arith_operand" "d,K")))]
|
|||
|
""
|
|||
|
"@
|
|||
|
xor\\t%0,%1,%2
|
|||
|
xori\\t%0,%1,%x2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; ??? If delete the 32-bit long long patterns, then could merge this with
|
|||
|
;; the following xordi3_internal pattern.
|
|||
|
(define_insn "xordi3"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(xor:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
return \"xor\\t%0,%1,%2\";
|
|||
|
return \"xor\\t%M0,%M1,%M2\;xor\\t%L0,%L1,%L2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set (attr "length")
|
|||
|
(if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0))
|
|||
|
(const_int 1)
|
|||
|
(const_int 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_64BIT && !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)))]
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "xordi3_immed"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "d")
|
|||
|
(xor:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_uns_arith_operand" "K")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"xori\\t%0,%1,%x2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "*norsi3"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(and:SI (not:SI (match_operand:SI 1 "register_operand" "d"))
|
|||
|
(not:SI (match_operand:SI 2 "register_operand" "d"))))]
|
|||
|
""
|
|||
|
"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")
|
|||
|
(and:DI (not:DI (match_operand:DI 1 "se_register_operand" "d"))
|
|||
|
(not:DI (match_operand:DI 2 "se_register_operand" "d"))))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
return \"nor\\t%0,%z1,%z2\";
|
|||
|
return \"nor\\t%M0,%M1,%M2\;nor\\t%L0,%L1,%L2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set (attr "length")
|
|||
|
(if_then_else (ne (symbol_ref "TARGET_64BIT") (const_int 0))
|
|||
|
(const_int 1)
|
|||
|
(const_int 2)))])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(and:DI (not:DI (match_operand:DI 1 "register_operand" ""))
|
|||
|
(not:DI (match_operand:DI 2 "register_operand" ""))))]
|
|||
|
"reload_completed && !TARGET_64BIT && !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 (not:SI (subreg:SI (match_dup 1) 0)) (not:SI (subreg:SI (match_dup 2) 0))))
|
|||
|
(set (subreg:SI (match_dup 0) 1) (and:SI (not:SI (subreg:SI (match_dup 1) 1)) (not:SI (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 && TARGET_DOUBLE_FLOAT"
|
|||
|
"cvt.s.d\\t%0,%1"
|
|||
|
[(set_attr "type" "fcvt")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "truncdisi2"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(truncate:SI (match_operand:DI 1 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"dsll\\t%0,%1,32\;dsra\\t%0,%0,32"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn "truncdihi2"
|
|||
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
|||
|
(truncate:HI (match_operand:DI 1 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"andi\\t%0,%1,0xffff"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "HI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "truncdiqi2"
|
|||
|
[(set (match_operand:QI 0 "register_operand" "=d")
|
|||
|
(truncate:QI (match_operand:DI 1 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"andi\\t%0,%1,0x00ff"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "QI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; Combiner patterns to optimize shift/truncate combinations.
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(truncate:SI (ashiftrt:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "small_int" "I"))))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
int shift_amt = INTVAL (operands[2]) & 0x3f;
|
|||
|
|
|||
|
if (shift_amt < 32)
|
|||
|
{
|
|||
|
operands[2] = GEN_INT (32 - shift_amt);
|
|||
|
return \"dsll\\t%0,%1,%2\;dsra\\t%0,%0,32\";
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
operands[2] = GEN_INT (shift_amt);
|
|||
|
return \"dsra\\t%0,%1,%2\";
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(truncate:SI (lshiftrt:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "small_int" "I"))))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
int shift_amt = INTVAL (operands[2]) & 0x3f;
|
|||
|
|
|||
|
if (shift_amt < 32)
|
|||
|
{
|
|||
|
operands[2] = GEN_INT (32 - shift_amt);
|
|||
|
return \"dsll\\t%0,%1,%2\;dsra\\t%0,%0,32\";
|
|||
|
}
|
|||
|
else if (shift_amt == 32)
|
|||
|
return \"dsra\\t%0,%1,32\";
|
|||
|
else
|
|||
|
{
|
|||
|
operands[2] = GEN_INT (shift_amt);
|
|||
|
return \"dsrl\\t%0,%1,%2\";
|
|||
|
}
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(truncate:SI (ashift:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "small_int" "I"))))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
int shift_amt = INTVAL (operands[2]) & 0x3f;
|
|||
|
|
|||
|
if (shift_amt < 32)
|
|||
|
{
|
|||
|
operands[2] = GEN_INT (32 + shift_amt);
|
|||
|
return \"dsll\\t%0,%1,%2\;dsra\\t%0,%0,32\";
|
|||
|
}
|
|||
|
else
|
|||
|
return \"move\\t%0,%.\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
;; Combiner patterns to optimize truncate/zero_extend combinations.
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(zero_extend:SI (truncate:HI
|
|||
|
(match_operand:DI 1 "se_register_operand" "d"))))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"andi\\t%0,%1,0xffff"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(zero_extend:SI (truncate:QI
|
|||
|
(match_operand:DI 1 "se_register_operand" "d"))))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"andi\\t%0,%1,0xff"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:HI 0 "register_operand" "=d")
|
|||
|
(zero_extend:HI (truncate:QI
|
|||
|
(match_operand:DI 1 "se_register_operand" "d"))))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"andi\\t%0,%1,0xff"
|
|||
|
[(set_attr "type" "darith")
|
|||
|
(set_attr "mode" "HI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; ZERO EXTENSION
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
|
|||
|
;; Extension insns.
|
|||
|
;; Those for integer source operand are ordered widest source type first.
|
|||
|
|
|||
|
(define_expand "zero_extendsidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (optimize && GET_CODE (operands[1]) == MEM)
|
|||
|
operands[1] = force_not_mem (operands[1]);
|
|||
|
|
|||
|
if (GET_CODE (operands[1]) != MEM)
|
|||
|
{
|
|||
|
rtx op1 = gen_lowpart (DImode, operands[1]);
|
|||
|
rtx temp = gen_reg_rtx (DImode);
|
|||
|
rtx shift = gen_rtx (CONST_INT, VOIDmode, 32);
|
|||
|
|
|||
|
emit_insn (gen_ashldi3 (temp, op1, shift));
|
|||
|
emit_insn (gen_lshrdi3 (operands[0], temp, shift));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "zero_extendsidi2_internal"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(zero_extend:DI (match_operand:SI 1 "memory_operand" "R,m")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"* return mips_move_1word (operands, insn, TRUE);"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1,2")])
|
|||
|
|
|||
|
(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_extendhidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
|
|||
|
(zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
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" "DI")
|
|||
|
(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")])
|
|||
|
|
|||
|
(define_insn "zero_extendqidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
|
|||
|
(zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
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" "DI")
|
|||
|
(set_attr "length" "1,1,2")])
|
|||
|
|
|||
|
;; These can be created when a paradoxical subreg operand with an implicit
|
|||
|
;; sign_extend operator is reloaded. Because of the subreg, this is really
|
|||
|
;; a zero extend.
|
|||
|
;; ??? It might be possible to eliminate the need for these patterns by adding
|
|||
|
;; more support to reload for implicit sign_extend operators.
|
|||
|
(define_insn "*paradoxical_extendhidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(sign_extend:DI
|
|||
|
(subreg:SI (match_operand:HI 1 "memory_operand" "R,m") 0)))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_move_1word (operands, insn, TRUE);
|
|||
|
}"
|
|||
|
[(set_attr "type" "load,load")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1,2")])
|
|||
|
|
|||
|
(define_insn "*paradoxical_extendqidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(sign_extend:DI
|
|||
|
(subreg:SI (match_operand:QI 1 "memory_operand" "R,m") 0)))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_move_1word (operands, insn, TRUE);
|
|||
|
}"
|
|||
|
[(set_attr "type" "load,load")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1,2")])
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; SIGN EXTENSION
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
|
|||
|
;; Extension insns.
|
|||
|
;; Those for integer source operand are ordered widest source type first.
|
|||
|
|
|||
|
;; In 64 bit mode, 32 bit values in general registers are always
|
|||
|
;; correctly sign extended. That means that if the target is a
|
|||
|
;; general register, we can sign extend from SImode to DImode just by
|
|||
|
;; doing a move.
|
|||
|
|
|||
|
(define_insn "extendsidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,*d,d,d")
|
|||
|
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,*x,R,m")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "move,hilo,load,load")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1,1,1,2")])
|
|||
|
|
|||
|
;; 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 "extendhidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (optimize && GET_CODE (operands[1]) == MEM)
|
|||
|
operands[1] = force_not_mem (operands[1]);
|
|||
|
|
|||
|
if (GET_CODE (operands[1]) != MEM)
|
|||
|
{
|
|||
|
rtx op1 = gen_lowpart (DImode, operands[1]);
|
|||
|
rtx temp = gen_reg_rtx (DImode);
|
|||
|
rtx shift = gen_rtx (CONST_INT, VOIDmode, 48);
|
|||
|
|
|||
|
emit_insn (gen_ashldi3 (temp, op1, shift));
|
|||
|
emit_insn (gen_ashrdi3 (operands[0], temp, shift));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "extendhidi2_internal"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(sign_extend:DI (match_operand:HI 1 "memory_operand" "R,m")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1,2")])
|
|||
|
|
|||
|
(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_expand "extendqidi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(sign_extend:DI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (optimize && GET_CODE (operands[1]) == MEM)
|
|||
|
operands[1] = force_not_mem (operands[1]);
|
|||
|
|
|||
|
if (GET_CODE (operands[1]) != MEM)
|
|||
|
{
|
|||
|
rtx op1 = gen_lowpart (DImode, operands[1]);
|
|||
|
rtx temp = gen_reg_rtx (DImode);
|
|||
|
rtx shift = gen_rtx (CONST_INT, VOIDmode, 56);
|
|||
|
|
|||
|
emit_insn (gen_ashldi3 (temp, op1, shift));
|
|||
|
emit_insn (gen_ashrdi3 (operands[0], temp, shift));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "extendqidi2_insn"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(sign_extend:DI (match_operand:QI 1 "memory_operand" "R,m")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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 && TARGET_DOUBLE_FLOAT"
|
|||
|
"cvt.d.s\\t%0,%1"
|
|||
|
[(set_attr "type" "fcvt")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; CONVERSIONS
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
|
|||
|
;; The SImode scratch register can not be shared with address regs used for
|
|||
|
;; operand zero, because then the address in the move instruction will be
|
|||
|
;; clobbered. We mark the scratch register as early clobbered to prevent this.
|
|||
|
|
|||
|
;; We need the ?X in alternative 1 so that it will be choosen only if the
|
|||
|
;; destination is a floating point register. Otherwise, alternative 1 can
|
|||
|
;; have lower cost than alternative 0 (because there is one less loser), and
|
|||
|
;; can be choosen when it won't work (because integral reloads into FP
|
|||
|
;; registers are not supported).
|
|||
|
|
|||
|
(define_insn "fix_truncdfsi2"
|
|||
|
[(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_scratch:SI 2 "=d,*d,&d,&d"))
|
|||
|
(clobber (match_scratch:DF 3 "=f,?*X,f,f"))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_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" "11,9,10,11")])
|
|||
|
|
|||
|
|
|||
|
(define_insn "fix_truncsfsi2"
|
|||
|
[(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_scratch:SI 2 "=d,*d,&d,&d"))
|
|||
|
(clobber (match_scratch:SF 3 "=f,?*X,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" "11,9,10,11")])
|
|||
|
|
|||
|
|
|||
|
;;; ??? trunc.l.d is mentioned in the appendix of the 1993 r4000/r4600 manuals
|
|||
|
;;; but not in the chapter that describes the FPU. It is not mentioned at all
|
|||
|
;;; in the 1991 manuals. The r4000 at Cygnus does not have this instruction.
|
|||
|
|
|||
|
;;; Deleting this means that we now need two libgcc2.a libraries. One for
|
|||
|
;;; the 32 bit calling convention and one for the 64 bit calling convention.
|
|||
|
|
|||
|
;;; If this is disabled, then fixuns_truncdfdi2 must be disabled also.
|
|||
|
|
|||
|
(define_insn "fix_truncdfdi2"
|
|||
|
[(set (match_operand:DI 0 "general_operand" "=d,*f,R,o")
|
|||
|
(fix:DI (match_operand:DF 1 "register_operand" "f,*f,f,f")))
|
|||
|
(clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
rtx xoperands[10];
|
|||
|
|
|||
|
if (which_alternative == 1)
|
|||
|
return \"trunc.l.d %0,%1\";
|
|||
|
|
|||
|
output_asm_insn (\"trunc.l.d %2,%1\", operands);
|
|||
|
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = operands[2];
|
|||
|
output_asm_insn (mips_move_2words (xoperands, insn, FALSE), xoperands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcvt")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "2,1,2,3")])
|
|||
|
|
|||
|
|
|||
|
;;; ??? trunc.l.s is mentioned in the appendix of the 1993 r4000/r4600 manuals
|
|||
|
;;; but not in the chapter that describes the FPU. It is not mentioned at all
|
|||
|
;;; in the 1991 manuals. The r4000 at Cygnus does not have this instruction.
|
|||
|
(define_insn "fix_truncsfdi2"
|
|||
|
[(set (match_operand:DI 0 "general_operand" "=d,*f,R,o")
|
|||
|
(fix:DI (match_operand:SF 1 "register_operand" "f,*f,f,f")))
|
|||
|
(clobber (match_scratch:DF 2 "=f,?*X,f,f"))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
rtx xoperands[10];
|
|||
|
|
|||
|
if (which_alternative == 1)
|
|||
|
return \"trunc.l.s %0,%1\";
|
|||
|
|
|||
|
output_asm_insn (\"trunc.l.s %2,%1\", operands);
|
|||
|
|
|||
|
xoperands[0] = operands[0];
|
|||
|
xoperands[1] = operands[2];
|
|||
|
output_asm_insn (mips_move_2words (xoperands, insn, FALSE), xoperands);
|
|||
|
return \"\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcvt")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "2,1,2,3")])
|
|||
|
|
|||
|
|
|||
|
(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 && TARGET_DOUBLE_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 "floatdidf2"
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f,f,f")
|
|||
|
(float:DF (match_operand:DI 1 "se_nonimmediate_operand" "d,R,m")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
dslots_load_total++;
|
|||
|
if (GET_CODE (operands[1]) == MEM)
|
|||
|
return \"l.d\\t%0,%1%#\;cvt.d.l\\t%0,%0\";
|
|||
|
|
|||
|
return \"dmtc1\\t%1,%0%#\;cvt.d.l\\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_insn "floatdisf2"
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f,f")
|
|||
|
(float:SF (match_operand:DI 1 "se_nonimmediate_operand" "d,R,m")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
dslots_load_total++;
|
|||
|
if (GET_CODE (operands[1]) == MEM)
|
|||
|
return \"l.d\\t%0,%1%#\;cvt.s.l\\t%0,%0\";
|
|||
|
|
|||
|
return \"dmtc1\\t%1,%0%#\;cvt.s.l\\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 && TARGET_DOUBLE_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 */
|
|||
|
{
|
|||
|
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_truncdfdi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(unsigned_fix:DI (match_operand:DF 1 "register_operand" "")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
rtx reg1 = gen_reg_rtx (DFmode);
|
|||
|
rtx reg2 = gen_reg_rtx (DFmode);
|
|||
|
rtx reg3 = gen_reg_rtx (DImode);
|
|||
|
rtx label1 = gen_label_rtx ();
|
|||
|
rtx label2 = gen_label_rtx ();
|
|||
|
REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 63);
|
|||
|
|
|||
|
if (reg1) /* turn off complaints about unreached code */
|
|||
|
{
|
|||
|
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_truncdfdi2 (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_ashldi3 (reg3, reg3, GEN_INT (32)));
|
|||
|
|
|||
|
emit_insn (gen_fix_truncdfdi2 (operands[0], reg2));
|
|||
|
emit_insn (gen_iordi3 (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 */
|
|||
|
{
|
|||
|
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;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
|
|||
|
(define_expand "fixuns_truncsfdi2"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(unsigned_fix:DI (match_operand:SF 1 "register_operand" "")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_64BIT && TARGET_DOUBLE_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
rtx reg1 = gen_reg_rtx (SFmode);
|
|||
|
rtx reg2 = gen_reg_rtx (SFmode);
|
|||
|
rtx reg3 = gen_reg_rtx (DImode);
|
|||
|
rtx label1 = gen_label_rtx ();
|
|||
|
rtx label2 = gen_label_rtx ();
|
|||
|
REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (1.0, 63);
|
|||
|
|
|||
|
if (reg1) /* turn off complaints about unreached code */
|
|||
|
{
|
|||
|
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_truncsfdi2 (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_ashldi3 (reg3, reg3, GEN_INT (32)));
|
|||
|
|
|||
|
emit_insn (gen_fix_truncsfdi2 (operands[0], reg2));
|
|||
|
emit_insn (gen_iordi3 (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
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
|
|||
|
;; Bit field extract patterns which use lwl/lwr.
|
|||
|
|
|||
|
;; ??? There should be DImode variants for 64 bit code, but the current
|
|||
|
;; bitfield scheme can't handle that. We would need to add new optabs
|
|||
|
;; in order to make that work.
|
|||
|
|
|||
|
;; ??? There could be HImode variants for the ulh/ulhu/ush macros.
|
|||
|
;; It isn't clear whether this will give better code.
|
|||
|
|
|||
|
(define_expand "extv"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(sign_extract:SI (match_operand:QI 1 "memory_operand" "")
|
|||
|
(match_operand:SI 2 "immediate_operand" "")
|
|||
|
(match_operand:SI 3 "immediate_operand" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
/* If this isn't a 32 bit field, and it doesn't start on a byte boundary
|
|||
|
then fail. */
|
|||
|
if (INTVAL (operands[2]) != 32 || (INTVAL (operands[3]) % 8) != 0)
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* This can happen for a 64 bit target, when extracting a value from
|
|||
|
a 64 bit union member. extract_bit_field doesn't verify that our
|
|||
|
source matches the predicate, so we force it to be a MEM here. */
|
|||
|
if (GET_CODE (operands[1]) != MEM)
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* Otherwise, emit a lwl/lwr pair to load the value. */
|
|||
|
emit_insn (gen_movsi_ulw (operands[0], operands[1]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "extzv"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(zero_extract:SI (match_operand:QI 1 "memory_operand" "")
|
|||
|
(match_operand:SI 2 "immediate_operand" "")
|
|||
|
(match_operand:SI 3 "immediate_operand" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
/* If this isn't a 32 bit field, and it doesn't start on a byte boundary
|
|||
|
then fail. */
|
|||
|
if (INTVAL (operands[2]) != 32 || (INTVAL (operands[3]) % 8) != 0)
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* This can happen for a 64 bit target, when extracting a value from
|
|||
|
a 64 bit union member. extract_bit_field doesn't verify that our
|
|||
|
source matches the predicate, so we force it to be a MEM here. */
|
|||
|
if (GET_CODE (operands[1]) != MEM)
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* Otherwise, emit a lwl/lwr pair to load the value. */
|
|||
|
emit_insn (gen_movsi_ulw (operands[0], operands[1]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "insv"
|
|||
|
[(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "")
|
|||
|
(match_operand:SI 1 "immediate_operand" "")
|
|||
|
(match_operand:SI 2 "immediate_operand" ""))
|
|||
|
(match_operand:SI 3 "register_operand" ""))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
/* If this isn't a 32 bit field, and it doesn't start on a byte boundary
|
|||
|
then fail. */
|
|||
|
if (INTVAL (operands[1]) != 32 || (INTVAL (operands[2]) % 8) != 0)
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* This can happen for a 64 bit target, when storing into a 32 bit union
|
|||
|
member. store_bit_field doesn't verify that our target matches the
|
|||
|
predicate, so we force it to be a MEM here. */
|
|||
|
if (GET_CODE (operands[0]) != MEM)
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* Otherwise, emit a swl/swr pair to load the value. */
|
|||
|
emit_insn (gen_movsi_usw (operands[0], operands[3]));
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; unaligned word moves generated by the bit field patterns
|
|||
|
|
|||
|
(define_insn "movsi_ulw"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=&d,&d")
|
|||
|
(unspec [(match_operand:QI 1 "general_operand" "R,o")] 0))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
rtx offset = const0_rtx;
|
|||
|
rtx addr = XEXP (operands[1], 0);
|
|||
|
rtx mem_addr = eliminate_constant_term (addr, &offset);
|
|||
|
char *ret;
|
|||
|
|
|||
|
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. */
|
|||
|
|
|||
|
if ((INTVAL (offset) & 3) == 0
|
|||
|
&& (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx))
|
|||
|
ret = \"lw\\t%0,%1\";
|
|||
|
else
|
|||
|
ret = \"ulw\\t%0,%1\";
|
|||
|
|
|||
|
return mips_fill_delay_slot (ret, DELAY_LOAD, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "load,load")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2,4")])
|
|||
|
|
|||
|
(define_insn "movsi_usw"
|
|||
|
[(set (match_operand:QI 0 "memory_operand" "=R,o")
|
|||
|
(unspec [(match_operand:SI 1 "reg_or_0_operand" "dJ,dJ")] 1))]
|
|||
|
""
|
|||
|
"*
|
|||
|
{
|
|||
|
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) & 3) == 0
|
|||
|
&& (mem_addr == stack_pointer_rtx || mem_addr == frame_pointer_rtx))
|
|||
|
return \"sw\\t%1,%0\";
|
|||
|
|
|||
|
return \"usw\\t%z1,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "store")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2,4")])
|
|||
|
|
|||
|
;; These two patterns support loading addresses with two instructions instead
|
|||
|
;; of using the macro instruction la.
|
|||
|
|
|||
|
;; ??? mips_move_1word has support for HIGH, so this pattern may be
|
|||
|
;; unnecessary.
|
|||
|
|
|||
|
(define_insn "high"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|||
|
(high:SI (match_operand:SI 1 "immediate_operand" "")))]
|
|||
|
"mips_split_addresses"
|
|||
|
"lui\\t%0,%%hi(%1) # high"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "low"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=r")
|
|||
|
(lo_sum:SI (match_operand:SI 1 "register_operand" "r")
|
|||
|
(match_operand:SI 2 "immediate_operand" "")))]
|
|||
|
"mips_split_addresses"
|
|||
|
"addiu\\t%0,%1,%%lo(%2) # low"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; 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_expand "movdi"
|
|||
|
[(set (match_operand:DI 0 "nonimmediate_operand" "")
|
|||
|
(match_operand:DI 1 "general_operand" ""))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (mips_split_addresses && mips_check_split (operands[1], DImode))
|
|||
|
{
|
|||
|
enum machine_mode mode = GET_MODE (operands[0]);
|
|||
|
rtx tem = ((reload_in_progress | reload_completed)
|
|||
|
? operands[0] : gen_reg_rtx (mode));
|
|||
|
|
|||
|
emit_insn (gen_rtx (SET, VOIDmode, tem,
|
|||
|
gen_rtx (HIGH, mode, operands[1])));
|
|||
|
|
|||
|
operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
|
|||
|
}
|
|||
|
|
|||
|
/* If we are generating embedded PIC code, and we are referring to a
|
|||
|
symbol in the .text section, we must use an offset from the start
|
|||
|
of the function. */
|
|||
|
if (TARGET_EMBEDDED_PIC
|
|||
|
&& (GET_CODE (operands[1]) == LABEL_REF
|
|||
|
|| (GET_CODE (operands[1]) == SYMBOL_REF
|
|||
|
&& ! SYMBOL_REF_FLAG (operands[1]))))
|
|||
|
{
|
|||
|
rtx temp;
|
|||
|
|
|||
|
temp = embedded_pic_offset (operands[1]);
|
|||
|
temp = gen_rtx (PLUS, Pmode, embedded_pic_fnaddr_rtx,
|
|||
|
force_reg (DImode, temp));
|
|||
|
emit_move_insn (operands[0], force_reg (DImode, temp));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
/* If operands[1] is a constant address illegal for pic, then we need to
|
|||
|
handle it just like LEGITIMIZE_ADDRESS does. */
|
|||
|
if (flag_pic && pic_address_needs_scratch (operands[1]))
|
|||
|
{
|
|||
|
rtx temp = force_reg (DImode, XEXP (XEXP (operands[1], 0), 0));
|
|||
|
rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
|
|||
|
|
|||
|
if (! SMALL_INT (temp2))
|
|||
|
temp2 = force_reg (DImode, temp2);
|
|||
|
|
|||
|
emit_move_insn (operands[0], gen_rtx (PLUS, DImode, temp, temp2));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
if ((reload_in_progress | reload_completed) == 0
|
|||
|
&& !register_operand (operands[0], DImode)
|
|||
|
&& !register_operand (operands[1], DImode)
|
|||
|
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
|
|||
|
&& operands[1] != CONST0_RTX (DImode))
|
|||
|
{
|
|||
|
rtx temp = force_reg (DImode, operands[1]);
|
|||
|
emit_move_insn (operands[0], temp);
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "movdi_internal"
|
|||
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,R,o,*x,*d,*x")
|
|||
|
(match_operand:DI 1 "general_operand" "d,iF,R,o,d,d,J,*x,*d"))]
|
|||
|
"!TARGET_64BIT
|
|||
|
&& (register_operand (operands[0], DImode)
|
|||
|
|| register_operand (operands[1], DImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (DImode))"
|
|||
|
"* return mips_move_2words (operands, insn); "
|
|||
|
[(set_attr "type" "move,arith,load,load,store,store,hilo,hilo,hilo")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "2,4,2,4,2,4,2,2,2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(match_operand:DI 1 "register_operand" ""))]
|
|||
|
"reload_completed && !TARGET_64BIT && !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))]
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "movdi_internal2"
|
|||
|
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*x,*d,*x,*a")
|
|||
|
(match_operand:DI 1 "movdi_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,J,*x,*d,*J"))]
|
|||
|
"TARGET_64BIT
|
|||
|
&& (register_operand (operands[0], DImode)
|
|||
|
|| se_register_operand (operands[1], DImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (DImode))"
|
|||
|
"* return mips_move_2words (operands, insn); "
|
|||
|
[(set_attr "type" "move,load,arith,arith,load,load,store,store,hilo,hilo,hilo,hilo")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,2")])
|
|||
|
|
|||
|
;; Handle input reloads in DImode.
|
|||
|
;; This is mainly to handle reloading HILO_REGNUM. Note that we may
|
|||
|
;; see it as the source or the destination, depending upon which way
|
|||
|
;; reload handles the instruction.
|
|||
|
;; Making the second operand TImode is a trick. The compiler may
|
|||
|
;; reuse the same register for operand 0 and operand 2. Using TImode
|
|||
|
;; gives us two registers, so we can always use the one which is not
|
|||
|
;; used.
|
|||
|
|
|||
|
(define_expand "reload_indi"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=b")
|
|||
|
(match_operand:DI 1 "movdi_operand" "b"))
|
|||
|
(clobber (match_operand:TI 2 "register_operand" "=&d"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
rtx scratch = gen_rtx (REG, DImode,
|
|||
|
(REGNO (operands[0]) == REGNO (operands[2])
|
|||
|
? REGNO (operands[2]) + 1
|
|||
|
: REGNO (operands[2])));
|
|||
|
|
|||
|
if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM)
|
|||
|
{
|
|||
|
if (GET_CODE (operands[1]) == MEM)
|
|||
|
{
|
|||
|
rtx memword, offword, hiword, loword;
|
|||
|
|
|||
|
scratch = gen_rtx (REG, SImode, REGNO (scratch));
|
|||
|
memword = change_address (operands[1], SImode, NULL_RTX);
|
|||
|
offword = change_address (adj_offsettable_operand (operands[1], 4),
|
|||
|
SImode, NULL_RTX);
|
|||
|
if (BYTES_BIG_ENDIAN)
|
|||
|
{
|
|||
|
hiword = memword;
|
|||
|
loword = offword;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hiword = offword;
|
|||
|
loword = memword;
|
|||
|
}
|
|||
|
emit_move_insn (scratch, hiword);
|
|||
|
emit_move_insn (gen_rtx (REG, SImode, 64), scratch);
|
|||
|
emit_move_insn (scratch, loword);
|
|||
|
emit_move_insn (gen_rtx (REG, SImode, 65), scratch);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
emit_insn (gen_ashrdi3 (scratch, operands[1], GEN_INT (32)));
|
|||
|
emit_insn (gen_movdi (gen_rtx (REG, DImode, 64), scratch));
|
|||
|
emit_insn (gen_ashldi3 (scratch, operands[1], GEN_INT (32)));
|
|||
|
emit_insn (gen_ashrdi3 (scratch, scratch, GEN_INT (32)));
|
|||
|
emit_insn (gen_movdi (gen_rtx (REG, DImode, 65), scratch));
|
|||
|
}
|
|||
|
DONE;
|
|||
|
}
|
|||
|
if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM)
|
|||
|
{
|
|||
|
emit_insn (gen_movdi (scratch, gen_rtx (REG, DImode, 65)));
|
|||
|
emit_insn (gen_ashldi3 (scratch, scratch, GEN_INT (32)));
|
|||
|
emit_insn (gen_lshrdi3 (scratch, scratch, GEN_INT (32)));
|
|||
|
emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 64)));
|
|||
|
emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
|
|||
|
emit_insn (gen_iordi3 (operands[0], operands[0], scratch));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
/* This handles moves between a float register and HI/LO. */
|
|||
|
emit_move_insn (scratch, operands[1]);
|
|||
|
emit_move_insn (operands[0], scratch);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; Handle output reloads in DImode.
|
|||
|
|
|||
|
(define_expand "reload_outdi"
|
|||
|
[(set (match_operand:DI 0 "general_operand" "=b")
|
|||
|
(match_operand:DI 1 "se_register_operand" "b"))
|
|||
|
(clobber (match_operand:DI 2 "register_operand" "=&d"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM)
|
|||
|
{
|
|||
|
emit_insn (gen_ashrdi3 (operands[2], operands[1], GEN_INT (32)));
|
|||
|
emit_insn (gen_movdi (gen_rtx (REG, DImode, 64), operands[2]));
|
|||
|
emit_insn (gen_ashldi3 (operands[2], operands[1], GEN_INT (32)));
|
|||
|
emit_insn (gen_ashrdi3 (operands[2], operands[2], GEN_INT (32)));
|
|||
|
emit_insn (gen_movdi (gen_rtx (REG, DImode, 65), operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == HILO_REGNUM)
|
|||
|
{
|
|||
|
if (GET_CODE (operands[0]) == MEM)
|
|||
|
{
|
|||
|
rtx scratch, memword, offword, hiword, loword;
|
|||
|
|
|||
|
scratch = gen_rtx (REG, SImode, REGNO (operands[2]));
|
|||
|
memword = change_address (operands[0], SImode, NULL_RTX);
|
|||
|
offword = change_address (adj_offsettable_operand (operands[0], 4),
|
|||
|
SImode, NULL_RTX);
|
|||
|
if (BYTES_BIG_ENDIAN)
|
|||
|
{
|
|||
|
hiword = memword;
|
|||
|
loword = offword;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
hiword = offword;
|
|||
|
loword = memword;
|
|||
|
}
|
|||
|
emit_move_insn (scratch, gen_rtx (REG, SImode, 64));
|
|||
|
emit_move_insn (hiword, scratch);
|
|||
|
emit_move_insn (scratch, gen_rtx (REG, SImode, 65));
|
|||
|
emit_move_insn (loword, scratch);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
emit_insn (gen_movdi (operands[2], gen_rtx (REG, DImode, 65)));
|
|||
|
emit_insn (gen_ashldi3 (operands[2], operands[2], GEN_INT (32)));
|
|||
|
emit_insn (gen_lshrdi3 (operands[2], operands[2], GEN_INT (32)));
|
|||
|
emit_insn (gen_movdi (operands[0], gen_rtx (REG, DImode, 64)));
|
|||
|
emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
|
|||
|
emit_insn (gen_iordi3 (operands[0], operands[0], operands[2]));
|
|||
|
}
|
|||
|
DONE;
|
|||
|
}
|
|||
|
/* This handles moves between a float register and HI/LO. */
|
|||
|
emit_move_insn (operands[2], operands[1]);
|
|||
|
emit_move_insn (operands[0], operands[2]);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; 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 (mips_split_addresses && mips_check_split (operands[1], SImode))
|
|||
|
{
|
|||
|
enum machine_mode mode = GET_MODE (operands[0]);
|
|||
|
rtx tem = ((reload_in_progress | reload_completed)
|
|||
|
? operands[0] : gen_reg_rtx (mode));
|
|||
|
|
|||
|
emit_insn (gen_rtx (SET, VOIDmode, tem,
|
|||
|
gen_rtx (HIGH, mode, operands[1])));
|
|||
|
|
|||
|
operands[1] = gen_rtx (LO_SUM, mode, tem, operands[1]);
|
|||
|
}
|
|||
|
|
|||
|
/* If we are generating embedded PIC code, and we are referring to a
|
|||
|
symbol in the .text section, we must use an offset from the start
|
|||
|
of the function. */
|
|||
|
if (TARGET_EMBEDDED_PIC
|
|||
|
&& (GET_CODE (operands[1]) == LABEL_REF
|
|||
|
|| (GET_CODE (operands[1]) == SYMBOL_REF
|
|||
|
&& ! SYMBOL_REF_FLAG (operands[1]))))
|
|||
|
{
|
|||
|
rtx temp;
|
|||
|
|
|||
|
temp = embedded_pic_offset (operands[1]);
|
|||
|
temp = gen_rtx (PLUS, Pmode, embedded_pic_fnaddr_rtx,
|
|||
|
force_reg (SImode, temp));
|
|||
|
emit_move_insn (operands[0], force_reg (SImode, temp));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
/* If operands[1] is a constant address invalid for pic, then we need to
|
|||
|
handle it just like LEGITIMIZE_ADDRESS does. */
|
|||
|
if (flag_pic && pic_address_needs_scratch (operands[1]))
|
|||
|
{
|
|||
|
rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
|
|||
|
rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
|
|||
|
|
|||
|
if (! SMALL_INT (temp2))
|
|||
|
temp2 = force_reg (SImode, temp2);
|
|||
|
|
|||
|
emit_move_insn (operands[0], gen_rtx (PLUS, SImode, temp, temp2));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
if ((reload_in_progress | reload_completed) == 0
|
|||
|
&& !register_operand (operands[0], SImode)
|
|||
|
&& !register_operand (operands[1], SImode)
|
|||
|
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
|
|||
|
{
|
|||
|
rtx temp = force_reg (SImode, operands[1]);
|
|||
|
emit_move_insn (operands[0], temp);
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;; The difference between these two is whether or not ints are allowed
|
|||
|
;; in FP registers (off by default, use -mdebugh to enable).
|
|||
|
|
|||
|
(define_insn "movsi_internal1"
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*f*z,*f,*f,*f,*R,*m,*x,*x,*d,*d")
|
|||
|
(match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*f*z,*d,*f,*R,*m,*f,*f,J,*d,*x,*a"))]
|
|||
|
"TARGET_DEBUG_H_MODE
|
|||
|
&& (register_operand (operands[0], SImode)
|
|||
|
|| register_operand (operands[1], SImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,move,load,load,store,store,hilo,hilo,hilo,hilo")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,1,2,1,2,1,1,1,1")])
|
|||
|
|
|||
|
(define_insn "movsi_internal2"
|
|||
|
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,d,d,d,R,m,*d,*z,*x,*d,*x,*d")
|
|||
|
(match_operand:SI 1 "move_operand" "d,S,IKL,Mnis,R,m,dJ,dJ,*z,*d,J,*x,*d,*a"))]
|
|||
|
"!TARGET_DEBUG_H_MODE
|
|||
|
&& (register_operand (operands[0], SImode)
|
|||
|
|| register_operand (operands[1], SImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "move,load,arith,arith,load,load,store,store,xfer,xfer,hilo,hilo,hilo,hilo")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "1,2,1,2,1,2,1,2,1,1,1,1,1,1")])
|
|||
|
|
|||
|
;; Reload HILO_REGNUM in SI mode. This needs a scratch register in
|
|||
|
;; order to set the sign bit correctly in the HI register.
|
|||
|
|
|||
|
(define_expand "reload_outsi"
|
|||
|
[(set (match_operand:SI 0 "general_operand" "=b")
|
|||
|
(match_operand:SI 1 "register_operand" "d"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=&d"))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == HILO_REGNUM)
|
|||
|
{
|
|||
|
emit_insn (gen_movsi (gen_rtx (REG, SImode, 65), operands[1]));
|
|||
|
emit_insn (gen_ashrsi3 (operands[2], operands[1], GEN_INT (31)));
|
|||
|
emit_insn (gen_movsi (gen_rtx (REG, SImode, 64), operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
/* This handles moves between a float register and HI/LO. */
|
|||
|
emit_move_insn (operands[2], operands[1]);
|
|||
|
emit_move_insn (operands[0], operands[2]);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; This insn handles moving CCmode values. It's really just a
|
|||
|
;; slightly simplified copy of movsi_internal2, with additional cases
|
|||
|
;; to move a condition register to a general register and to move
|
|||
|
;; between the general registers and the floating point registers.
|
|||
|
|
|||
|
(define_insn "movcc"
|
|||
|
[(set (match_operand:CC 0 "nonimmediate_operand" "=d,*d,*d,*d,*R,*m,*d,*f,*f,*f,*f,*R,*m")
|
|||
|
(match_operand:CC 1 "general_operand" "z,*d,*R,*m,*d,*d,*f,*d,*f,*R,*m,*f,*f"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "move,move,load,load,store,store,xfer,xfer,move,load,load,store,store")
|
|||
|
(set_attr "mode" "SI")
|
|||
|
(set_attr "length" "2,1,1,2,1,2,1,1,1,1,2,1,2")])
|
|||
|
|
|||
|
;; Reload condition code registers. These need scratch registers.
|
|||
|
|
|||
|
(define_expand "reload_incc"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(match_operand:CC 1 "general_operand" "z"))
|
|||
|
(clobber (match_operand:TF 2 "register_operand" "=&f"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
rtx source;
|
|||
|
rtx fp1, fp2;
|
|||
|
|
|||
|
/* This is called when are copying some value into a condition code
|
|||
|
register. Operand 0 is the condition code register. Operand 1
|
|||
|
is the source. Operand 2 is a scratch register; we use TFmode
|
|||
|
because we actually need two floating point registers. */
|
|||
|
if (! ST_REG_P (true_regnum (operands[0]))
|
|||
|
|| ! FP_REG_P (true_regnum (operands[2])))
|
|||
|
abort ();
|
|||
|
|
|||
|
/* We need to get the source in SFmode so that the insn is
|
|||
|
recognized. */
|
|||
|
if (GET_CODE (operands[1]) == MEM)
|
|||
|
source = change_address (operands[1], SFmode, NULL_RTX);
|
|||
|
else if (GET_CODE (operands[1]) == REG || GET_CODE (operands[1]) == SUBREG)
|
|||
|
source = gen_rtx (REG, SFmode, true_regnum (operands[1]));
|
|||
|
else
|
|||
|
source = operands[1];
|
|||
|
|
|||
|
fp1 = gen_rtx (REG, SFmode, REGNO (operands[2]));
|
|||
|
fp2 = gen_rtx (REG, SFmode, REGNO (operands[2]) + 1);
|
|||
|
|
|||
|
emit_insn (gen_move_insn (fp1, source));
|
|||
|
emit_insn (gen_move_insn (fp2, gen_rtx (REG, SFmode, 0)));
|
|||
|
emit_insn (gen_rtx (SET, VOIDmode, operands[0],
|
|||
|
gen_rtx (LT, CCmode, fp2, fp1)));
|
|||
|
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "reload_outcc"
|
|||
|
[(set (match_operand:CC 0 "general_operand" "=z")
|
|||
|
(match_operand:CC 1 "register_operand" "z"))
|
|||
|
(clobber (match_operand:CC 2 "register_operand" "=&d"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
/* This is called when we are copying a condition code register out
|
|||
|
to save it somewhere. Operand 0 should be the location we are
|
|||
|
going to save it to. Operand 1 should be the condition code
|
|||
|
register. Operand 2 should be a scratch general purpose register
|
|||
|
created for us by reload. The mips_secondary_reload_class
|
|||
|
function should have told reload that we don't need a scratch
|
|||
|
register if the destination is a general purpose register anyhow. */
|
|||
|
if (ST_REG_P (true_regnum (operands[0]))
|
|||
|
|| GP_REG_P (true_regnum (operands[0]))
|
|||
|
|| ! ST_REG_P (true_regnum (operands[1]))
|
|||
|
|| ! GP_REG_P (true_regnum (operands[2])))
|
|||
|
abort ();
|
|||
|
|
|||
|
/* All we have to do is copy the value from the condition code to
|
|||
|
the data register, which movcc can handle, and then store the
|
|||
|
value into the real final destination. */
|
|||
|
emit_insn (gen_move_insn (operands[2], operands[1]));
|
|||
|
emit_insn (gen_move_insn (operands[0], operands[2]));
|
|||
|
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
;; MIPS4 supports loading and storing a floating point register from
|
|||
|
;; the sum of two general registers. We use two versions for each of
|
|||
|
;; these four instructions: one where the two general registers are
|
|||
|
;; SImode, and one where they are DImode. This is because general
|
|||
|
;; registers will be in SImode when they hold 32 bit values, but,
|
|||
|
;; since the 32 bit values are always sign extended, the [ls][wd]xc1
|
|||
|
;; instructions will still work correctly.
|
|||
|
|
|||
|
;; ??? Perhaps it would be better to support these instructions by
|
|||
|
;; modifying GO_IF_LEGITIMATE_ADDRESS and friends. However, since
|
|||
|
;; these instructions can only be used to load and store floating
|
|||
|
;; point registers, that would probably cause trouble in reload.
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"lwxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f")
|
|||
|
(mem:SF (plus:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"lwxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"ldxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f")
|
|||
|
(mem:DF (plus:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d"))))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"ldxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "load")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (mem:SF (plus:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(match_operand:SF 0 "register_operand" "=f"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"swxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "store")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (mem:SF (plus:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(match_operand:SF 0 "register_operand" "=f"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"swxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "store")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (mem:DF (plus:SI (match_operand:SI 1 "register_operand" "d")
|
|||
|
(match_operand:SI 2 "register_operand" "d")))
|
|||
|
(match_operand:DF 0 "register_operand" "=f"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"sdxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "store")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (mem:DF (plus:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))
|
|||
|
(match_operand:DF 0 "register_operand" "=f"))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"sdxc1\\t%0,%1(%2)"
|
|||
|
[(set_attr "type" "store")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "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_expand "movhi"
|
|||
|
[(set (match_operand:HI 0 "nonimmediate_operand" "")
|
|||
|
(match_operand:HI 1 "general_operand" ""))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if ((reload_in_progress | reload_completed) == 0
|
|||
|
&& !register_operand (operands[0], HImode)
|
|||
|
&& !register_operand (operands[1], HImode)
|
|||
|
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
|
|||
|
{
|
|||
|
rtx temp = force_reg (HImode, operands[1]);
|
|||
|
emit_move_insn (operands[0], temp);
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;; The difference between these two is whether or not ints are allowed
|
|||
|
;; in FP registers (off by default, use -mdebugh to enable).
|
|||
|
|
|||
|
(define_insn "movhi_internal1"
|
|||
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f,*f*z,*x,*d")
|
|||
|
(match_operand:HI 1 "general_operand" "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
|
|||
|
"TARGET_DEBUG_H_MODE
|
|||
|
&& (register_operand (operands[0], HImode)
|
|||
|
|| register_operand (operands[1], HImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
|
|||
|
"* 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")])
|
|||
|
|
|||
|
(define_insn "movhi_internal2"
|
|||
|
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d")
|
|||
|
(match_operand:HI 1 "general_operand" "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))]
|
|||
|
"!TARGET_DEBUG_H_MODE
|
|||
|
&& (register_operand (operands[0], HImode)
|
|||
|
|| register_operand (operands[1], HImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
|
|||
|
"* return mips_move_1word (operands, insn, TRUE);"
|
|||
|
[(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,hilo,hilo")
|
|||
|
(set_attr "mode" "HI")
|
|||
|
(set_attr "length" "1,1,1,2,1,2,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_expand "movqi"
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "")
|
|||
|
(match_operand:QI 1 "general_operand" ""))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if ((reload_in_progress | reload_completed) == 0
|
|||
|
&& !register_operand (operands[0], QImode)
|
|||
|
&& !register_operand (operands[1], QImode)
|
|||
|
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
|
|||
|
{
|
|||
|
rtx temp = force_reg (QImode, operands[1]);
|
|||
|
emit_move_insn (operands[0], temp);
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;; The difference between these two is whether or not ints are allowed
|
|||
|
;; in FP registers (off by default, use -mdebugh to enable).
|
|||
|
|
|||
|
(define_insn "movqi_internal1"
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*f*z,*f,*x,*d")
|
|||
|
(match_operand:QI 1 "general_operand" "d,IK,R,m,dJ,dJ,*f*z,*d,*f,*d,*x"))]
|
|||
|
"TARGET_DEBUG_H_MODE
|
|||
|
&& (register_operand (operands[0], QImode)
|
|||
|
|| register_operand (operands[1], QImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
|
|||
|
"* 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")])
|
|||
|
|
|||
|
(define_insn "movqi_internal2"
|
|||
|
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,R,m,*d,*z,*x,*d")
|
|||
|
(match_operand:QI 1 "general_operand" "d,IK,R,m,dJ,dJ,*z,*d,*d,*x"))]
|
|||
|
"!TARGET_DEBUG_H_MODE
|
|||
|
&& (register_operand (operands[0], QImode)
|
|||
|
|| register_operand (operands[1], QImode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
|
|||
|
"* return mips_move_1word (operands, insn, TRUE);"
|
|||
|
[(set_attr "type" "move,arith,load,load,store,store,xfer,xfer,hilo,hilo")
|
|||
|
(set_attr "mode" "QI")
|
|||
|
(set_attr "length" "1,1,1,2,1,2,1,1,1,1")])
|
|||
|
|
|||
|
|
|||
|
;; 32-bit floating point moves
|
|||
|
|
|||
|
(define_expand "movsf"
|
|||
|
[(set (match_operand:SF 0 "nonimmediate_operand" "")
|
|||
|
(match_operand:SF 1 "general_operand" ""))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if ((reload_in_progress | reload_completed) == 0
|
|||
|
&& !register_operand (operands[0], SFmode)
|
|||
|
&& !register_operand (operands[1], SFmode)
|
|||
|
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
|
|||
|
&& operands[1] != CONST0_RTX (SFmode))
|
|||
|
{
|
|||
|
rtx temp = force_reg (SFmode, operands[1]);
|
|||
|
emit_move_insn (operands[0], temp);
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "movsf_internal1"
|
|||
|
[(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,Fm,fG,fG,*d,*f,*G*d,*R,*F*m,*d,*d"))]
|
|||
|
"TARGET_HARD_FLOAT
|
|||
|
&& (register_operand (operands[0], SFmode)
|
|||
|
|| register_operand (operands[1], SFmode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (SFmode))"
|
|||
|
"* 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")])
|
|||
|
|
|||
|
|
|||
|
(define_insn "movsf_internal2"
|
|||
|
[(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,R,m")
|
|||
|
(match_operand:SF 1 "general_operand" " Gd,R,Fm,d,d"))]
|
|||
|
"TARGET_SOFT_FLOAT
|
|||
|
&& (register_operand (operands[0], SFmode)
|
|||
|
|| register_operand (operands[1], SFmode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (SFmode))"
|
|||
|
"* return mips_move_1word (operands, insn, FALSE);"
|
|||
|
[(set_attr "type" "move,load,load,store,store")
|
|||
|
(set_attr "mode" "SF")
|
|||
|
(set_attr "length" "1,1,2,1,2")])
|
|||
|
|
|||
|
|
|||
|
;; 64-bit floating point moves
|
|||
|
|
|||
|
(define_expand "movdf"
|
|||
|
[(set (match_operand:DF 0 "nonimmediate_operand" "")
|
|||
|
(match_operand:DF 1 "general_operand" ""))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if ((reload_in_progress | reload_completed) == 0
|
|||
|
&& !register_operand (operands[0], DFmode)
|
|||
|
&& !register_operand (operands[1], DFmode)
|
|||
|
&& (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
|
|||
|
&& operands[1] != CONST0_RTX (DFmode))
|
|||
|
{
|
|||
|
rtx temp = force_reg (DFmode, operands[1]);
|
|||
|
emit_move_insn (operands[0], temp);
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "movdf_internal1"
|
|||
|
[(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,F,*d,*f,*d*G,*R,*o*F,*d,*d"))]
|
|||
|
"TARGET_HARD_FLOAT && !(TARGET_FLOAT64 && !TARGET_64BIT)
|
|||
|
&& TARGET_DOUBLE_FLOAT
|
|||
|
&& (register_operand (operands[0], DFmode)
|
|||
|
|| register_operand (operands[1], DFmode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (DFmode))"
|
|||
|
"* 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_insn "movdf_internal1a"
|
|||
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,R,R,o,o,f,*d,*d,*d,*o,*R")
|
|||
|
(match_operand:DF 1 "general_operand" " f,o,f,G,f,G,F,*F,*o,*R,*d,*d"))]
|
|||
|
"TARGET_HARD_FLOAT && (TARGET_FLOAT64 && !TARGET_64BIT)
|
|||
|
&& TARGET_DOUBLE_FLOAT
|
|||
|
&& (register_operand (operands[0], DFmode)
|
|||
|
|| register_operand (operands[1], DFmode))
|
|||
|
|| (GET_CODE (operands [0]) == MEM
|
|||
|
&& ((GET_CODE (operands[1]) == CONST_INT
|
|||
|
&& INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (DFmode)))"
|
|||
|
"* return mips_move_2words (operands, insn); "
|
|||
|
[(set_attr "type" "move,load,store,store,store,store,load,load,load,load,store,store")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "1,2,1,1,2,2,2,2,2,1,2,1")])
|
|||
|
|
|||
|
(define_insn "movdf_internal2"
|
|||
|
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,R,o")
|
|||
|
(match_operand:DF 1 "general_operand" "dG,R,oF,d,d"))]
|
|||
|
"(TARGET_SOFT_FLOAT || TARGET_SINGLE_FLOAT)
|
|||
|
&& (register_operand (operands[0], DFmode)
|
|||
|
|| register_operand (operands[1], DFmode)
|
|||
|
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0)
|
|||
|
|| operands[1] == CONST0_RTX (DFmode))"
|
|||
|
"* return mips_move_2words (operands, insn); "
|
|||
|
[(set_attr "type" "move,load,load,store,store")
|
|||
|
(set_attr "mode" "DF")
|
|||
|
(set_attr "length" "2,2,4,2,4")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DF 0 "register_operand" "")
|
|||
|
(match_operand:DF 1 "register_operand" ""))]
|
|||
|
"reload_completed && !TARGET_64BIT && !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))]
|
|||
|
"")
|
|||
|
|
|||
|
;; Instructions to load the global pointer register.
|
|||
|
;; This is volatile to make sure that the scheduler won't move any symbol_ref
|
|||
|
;; uses in front of it. All symbol_refs implicitly use the gp reg.
|
|||
|
|
|||
|
(define_insn "loadgp"
|
|||
|
[(set (reg:DI 28)
|
|||
|
(unspec_volatile [(match_operand:DI 0 "address_operand" "")] 2))
|
|||
|
(clobber (reg:DI 1))]
|
|||
|
""
|
|||
|
"%[lui\\t$1,%%hi(%%neg(%%gp_rel(%a0)))\\n\\taddiu\\t$1,$1,%%lo(%%neg(%%gp_rel(%a0)))\\n\\tdaddu\\t$gp,$1,$25%]"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "3")])
|
|||
|
|
|||
|
;; 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" "=o") ;; destination
|
|||
|
(match_operand:BLK 1 "memory_operand" "o")) ;; 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" "=o") ;; destination
|
|||
|
(match_operand:BLK 1 "memory_operand" "o")) ;; 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 move
|
|||
|
""
|
|||
|
"* 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, INTVAL (operands[2]) & 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 "se_register_operand" "")
|
|||
|
(match_operand:SI 2 "arith_operand" "")))
|
|||
|
(clobber (match_dup 3))])]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
{
|
|||
|
emit_insn (gen_ashldi3_internal4 (operands[0], operands[1],
|
|||
|
operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
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_64BIT && !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_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0"
|
|||
|
"*
|
|||
|
{
|
|||
|
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 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_64BIT && !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, INTVAL (operands[2]) & 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_64BIT && !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, INTVAL (operands[2]) & 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_64BIT && !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_64BIT && !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_64BIT && !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 "ashldi3_internal4"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(ashift:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT)
|
|||
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|||
|
|
|||
|
return \"dsll\\t%0,%1,%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
(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, INTVAL (operands[2]) & 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 "se_register_operand" "")
|
|||
|
(match_operand:SI 2 "arith_operand" "")))
|
|||
|
(clobber (match_dup 3))])]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
{
|
|||
|
emit_insn (gen_ashrdi3_internal4 (operands[0], operands[1],
|
|||
|
operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
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_64BIT && !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_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0"
|
|||
|
"*
|
|||
|
{
|
|||
|
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 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_64BIT && !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, INTVAL (operands[2]) & 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_64BIT && !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, INTVAL (operands[2]) & 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_64BIT && !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_64BIT && !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_64BIT && !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 "ashrdi3_internal4"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(ashiftrt:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT)
|
|||
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|||
|
|
|||
|
return \"dsra\\t%0,%1,%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
(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, INTVAL (operands[2]) & 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 "se_register_operand" "")
|
|||
|
(match_operand:SI 2 "arith_operand" "")))
|
|||
|
(clobber (match_dup 3))])]
|
|||
|
"TARGET_64BIT || !TARGET_DEBUG_G_MODE"
|
|||
|
"
|
|||
|
{
|
|||
|
if (TARGET_64BIT)
|
|||
|
{
|
|||
|
emit_insn (gen_lshrdi3_internal4 (operands[0], operands[1],
|
|||
|
operands[2]));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
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_64BIT && !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_64BIT && !TARGET_DEBUG_G_MODE && (INTVAL (operands[2]) & 32) != 0"
|
|||
|
"*
|
|||
|
{
|
|||
|
operands[2] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 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_64BIT && !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, INTVAL (operands[2]) & 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_64BIT && !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, INTVAL (operands[2]) & 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_64BIT && !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_64BIT && !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_64BIT && !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));
|
|||
|
}")
|
|||
|
|
|||
|
|
|||
|
(define_insn "lshrdi3_internal4"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(lshiftrt:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:SI 2 "arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (GET_CODE (operands[2]) == CONST_INT)
|
|||
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
|||
|
|
|||
|
return \"dsrl\\t%0,%1,%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; COMPARISONS
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
|
|||
|
;; Flow here is rather complex:
|
|||
|
;;
|
|||
|
;; 1) The cmp{si,di,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 "cmpdi"
|
|||
|
[(set (cc0)
|
|||
|
(compare:CC (match_operand:DI 0 "se_register_operand" "")
|
|||
|
(match_operand:DI 1 "se_arith_operand" "")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (operands[0]) /* avoid unused code message */
|
|||
|
{
|
|||
|
branch_cmp[0] = operands[0];
|
|||
|
branch_cmp[1] = operands[1];
|
|||
|
branch_type = CMP_DI;
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "tstdi"
|
|||
|
[(set (cc0)
|
|||
|
(match_operand:DI 0 "se_register_operand" ""))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"
|
|||
|
{
|
|||
|
if (operands[0]) /* avoid unused code message */
|
|||
|
{
|
|||
|
branch_cmp[0] = operands[0];
|
|||
|
branch_cmp[1] = const0_rtx;
|
|||
|
branch_type = CMP_DI;
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "cmpdf"
|
|||
|
[(set (cc0)
|
|||
|
(compare:CC (match_operand:DF 0 "register_operand" "")
|
|||
|
(match_operand:DF 1 "register_operand" "")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_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 (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 (match_operand:CC 0 "register_operand" "z")
|
|||
|
(const_int 0))
|
|||
|
(match_operand 1 "pc_or_label_operand" "")
|
|||
|
(match_operand 2 "pc_or_label_operand" "")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
|
|||
|
return (operands[1] != pc_rtx) ? \"%*bc1t%?\\t%Z0%1\" : \"%*bc1f%?\\t%Z0%2\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "branch")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "branch_fp_eq"
|
|||
|
[(set (pc)
|
|||
|
(if_then_else (eq:CC (match_operand:CC 0 "register_operand" "z")
|
|||
|
(const_int 0))
|
|||
|
(match_operand 1 "pc_or_label_operand" "")
|
|||
|
(match_operand 2 "pc_or_label_operand" "")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
mips_branch_likely = (final_sequence && INSN_ANNULLED_BRANCH_P (insn));
|
|||
|
return (operands[1] != pc_rtx) ? \"%*bc1f%?\\t%Z0%1\" : \"%*bc1t%?\\t%Z0%2\";
|
|||
|
}"
|
|||
|
[(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 "register_operand" "d")
|
|||
|
(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));
|
|||
|
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 \"%*bne%?\\t%.,%.,%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 \"%*beq%?\\t%.,%.,%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_zero_di"
|
|||
|
[(set (pc)
|
|||
|
(if_then_else (match_operator:DI 0 "cmp_op"
|
|||
|
[(match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(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));
|
|||
|
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 \"%*bne%?\\t%.,%.,%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 \"%*beq%?\\t%.,%.,%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_insn "branch_equality_di"
|
|||
|
[(set (pc)
|
|||
|
(if_then_else (match_operator:DI 0 "equality_op"
|
|||
|
[(match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_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 (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 (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)))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_di_zero"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(eq:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(const_int 0)))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"sltu\\t%0,%1,1"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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_insn "seq_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(eq:DI (match_operand:DI 1 "se_register_operand" "%d,d")
|
|||
|
(match_operand:DI 2 "se_uns_arith_operand" "d,K")))]
|
|||
|
"TARGET_64BIT && 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" "DI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(eq:DI (match_operand:DI 1 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_uns_arith_operand" "")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE
|
|||
|
&& (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)"
|
|||
|
[(set (match_dup 0)
|
|||
|
(xor:DI (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(set (match_dup 0)
|
|||
|
(ltu:DI (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)))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_di_zero"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(ne:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(const_int 0)))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"sltu\\t%0,%.,%1"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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_insn "sne_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(ne:DI (match_operand:DI 1 "se_register_operand" "%d,d")
|
|||
|
(match_operand:DI 2 "se_uns_arith_operand" "d,K")))]
|
|||
|
"TARGET_64BIT && 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" "DI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(ne:DI (match_operand:DI 1 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_uns_arith_operand" "")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE
|
|||
|
&& (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0)"
|
|||
|
[(set (match_dup 0)
|
|||
|
(xor:DI (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(set (match_dup 0)
|
|||
|
(gtu:DI (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)))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_insn "sgt_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(gt:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_reg_or_0_operand" "dJ")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"slt\\t%0,%z2,%1"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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 && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_insn "sge_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(ge:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE"
|
|||
|
"slt\\t%0,%1,%2\;xori\\t%0,%0,0x0001"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(ge:DI (match_operand:DI 1 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
|
|||
|
[(set (match_dup 0)
|
|||
|
(lt:DI (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(set (match_dup 0)
|
|||
|
(xor:DI (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 && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_insn "slt_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(lt:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"slt\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "sle"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(le:SI (match_dup 1)
|
|||
|
(match_dup 2)))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_di_const"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(le:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "small_int" "I")))]
|
|||
|
"TARGET_64BIT && 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" "DI")
|
|||
|
(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_insn "sle_di_reg"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(le:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE"
|
|||
|
"slt\\t%0,%z2,%1\;xori\\t%0,%0,0x0001"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(le:DI (match_operand:DI 1 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_register_operand" "")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
|
|||
|
[(set (match_dup 0)
|
|||
|
(lt:DI (match_dup 2)
|
|||
|
(match_dup 1)))
|
|||
|
(set (match_dup 0)
|
|||
|
(xor:DI (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)))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_insn "sgtu_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(gtu:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_reg_or_0_operand" "dJ")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"sltu\\t%0,%z2,%1"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(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 && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_insn "sgeu_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(geu:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE"
|
|||
|
"sltu\\t%0,%1,%2\;xori\\t%0,%0,0x0001"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(geu:DI (match_operand:DI 1 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
|
|||
|
[(set (match_dup 0)
|
|||
|
(ltu:DI (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(set (match_dup 0)
|
|||
|
(xor:DI (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 && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_insn "sltu_di"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(ltu:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_arith_operand" "dI")))]
|
|||
|
"TARGET_64BIT"
|
|||
|
"sltu\\t%0,%1,%2"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "sleu"
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d")
|
|||
|
(leu:SI (match_dup 1)
|
|||
|
(match_dup 2)))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (branch_type != CMP_SI && (!TARGET_64BIT || branch_type != CMP_DI))
|
|||
|
FAIL;
|
|||
|
|
|||
|
/* set up operands from compare. */
|
|||
|
operands[1] = branch_cmp[0];
|
|||
|
operands[2] = branch_cmp[1];
|
|||
|
|
|||
|
if (TARGET_64BIT || !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_di_const"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(leu:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "small_int" "I")))]
|
|||
|
"TARGET_64BIT && 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" "DI")
|
|||
|
(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)))]
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "sleu_di_reg"
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d")
|
|||
|
(leu:DI (match_operand:DI 1 "se_register_operand" "d")
|
|||
|
(match_operand:DI 2 "se_register_operand" "d")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE"
|
|||
|
"sltu\\t%0,%z2,%1\;xori\\t%0,%0,0x0001"
|
|||
|
[(set_attr "type" "arith")
|
|||
|
(set_attr "mode" "DI")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_split
|
|||
|
[(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(leu:DI (match_operand:DI 1 "se_register_operand" "")
|
|||
|
(match_operand:DI 2 "se_register_operand" "")))]
|
|||
|
"TARGET_64BIT && TARGET_DEBUG_C_MODE && !TARGET_DEBUG_D_MODE"
|
|||
|
[(set (match_dup 0)
|
|||
|
(ltu:DI (match_dup 2)
|
|||
|
(match_dup 1)))
|
|||
|
(set (match_dup 0)
|
|||
|
(xor:DI (match_dup 0)
|
|||
|
(const_int 1)))]
|
|||
|
"")
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; FLOATING POINT COMPARISONS
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
|
|||
|
(define_insn "seq_df"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(eq:CC (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.eq.d\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "slt_df"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(lt:CC (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.lt.d\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "sle_df"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(le:CC (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.le.d\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "sgt_df"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(gt:CC (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.lt.d\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "sge_df"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(ge:CC (match_operand:DF 1 "register_operand" "f")
|
|||
|
(match_operand:DF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.le.d\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "seq_sf"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(eq:CC (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.eq.s\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "slt_sf"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(lt:CC (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.lt.s\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "sle_sf"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(le:CC (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.le.s\\t%Z0%1,%2\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "sgt_sf"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(gt:CC (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.lt.s\\t%Z0%2,%1\", DELAY_FCMP, operands, insn);
|
|||
|
}"
|
|||
|
[(set_attr "type" "fcmp")
|
|||
|
(set_attr "mode" "FPSW")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "sge_sf"
|
|||
|
[(set (match_operand:CC 0 "register_operand" "=z")
|
|||
|
(ge:CC (match_operand:SF 1 "register_operand" "f")
|
|||
|
(match_operand:SF 2 "register_operand" "f")))]
|
|||
|
"TARGET_HARD_FLOAT"
|
|||
|
"*
|
|||
|
{
|
|||
|
return mips_fill_delay_slot (\"c.le.s\\t%Z0%2,%1\", DELAY_FCMP, operands, 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\";
|
|||
|
/* ??? I don't know why this is necessary. This works around an
|
|||
|
assembler problem that appears when a label is defined, then referenced
|
|||
|
in a switch table, then used in a `j' instruction. */
|
|||
|
else if (mips_abi != ABI_32)
|
|||
|
return \"%*b\\t%l0\";
|
|||
|
else
|
|||
|
return \"%*j\\t%l0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "indirect_jump"
|
|||
|
[(set (pc) (match_operand 0 "register_operand" "d"))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx dest;
|
|||
|
|
|||
|
if (operands[0]) /* eliminate unused code warnings */
|
|||
|
{
|
|||
|
dest = operands[0];
|
|||
|
if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode)
|
|||
|
operands[0] = copy_to_mode_reg (Pmode, dest);
|
|||
|
|
|||
|
if (!TARGET_LONG64)
|
|||
|
emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
|
|||
|
else
|
|||
|
emit_jump_insn (gen_indirect_jump_internal2 (operands[0]));
|
|||
|
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "indirect_jump_internal1"
|
|||
|
[(set (pc) (match_operand:SI 0 "register_operand" "d"))]
|
|||
|
"!TARGET_LONG64"
|
|||
|
"%*j\\t%0"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "indirect_jump_internal2"
|
|||
|
[(set (pc) (match_operand:DI 0 "se_register_operand" "d"))]
|
|||
|
"TARGET_LONG64"
|
|||
|
"%*j\\t%0"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "tablejump"
|
|||
|
[(set (pc)
|
|||
|
(match_operand 0 "register_operand" "d"))
|
|||
|
(use (label_ref (match_operand 1 "" "")))]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx dest;
|
|||
|
|
|||
|
if (operands[0]) /* eliminate unused code warnings */
|
|||
|
{
|
|||
|
if (GET_MODE (operands[0]) != Pmode)
|
|||
|
abort ();
|
|||
|
|
|||
|
if (! flag_pic)
|
|||
|
{
|
|||
|
if (!TARGET_LONG64)
|
|||
|
emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
|
|||
|
else
|
|||
|
emit_jump_insn (gen_tablejump_internal2 (operands[0], operands[1]));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!TARGET_LONG64)
|
|||
|
emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
|
|||
|
else
|
|||
|
emit_jump_insn (gen_tablejump_internal4 (operands[0], operands[1]));
|
|||
|
}
|
|||
|
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_insn "tablejump_internal1"
|
|||
|
[(set (pc)
|
|||
|
(match_operand:SI 0 "register_operand" "d"))
|
|||
|
(use (label_ref (match_operand 1 "" "")))]
|
|||
|
"!TARGET_LONG64"
|
|||
|
"%*j\\t%0"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "tablejump_internal2"
|
|||
|
[(set (pc)
|
|||
|
(match_operand:DI 0 "se_register_operand" "d"))
|
|||
|
(use (label_ref (match_operand 1 "" "")))]
|
|||
|
"TARGET_LONG64"
|
|||
|
"%*j\\t%0"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_expand "tablejump_internal3"
|
|||
|
[(set (pc)
|
|||
|
(plus:SI (match_operand:SI 0 "register_operand" "d")
|
|||
|
(label_ref:SI (match_operand:SI 1 "" ""))))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise
|
|||
|
;;; it is not valid.
|
|||
|
|
|||
|
;;; ??? The length depends on the ABI. It is two for o32, and one for n32.
|
|||
|
;;; We just use the conservative number here.
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (pc)
|
|||
|
(plus:SI (match_operand:SI 0 "register_operand" "d")
|
|||
|
(label_ref:SI (match_operand:SI 1 "" ""))))]
|
|||
|
"!TARGET_LONG64 && next_active_insn (insn) != 0
|
|||
|
&& GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
|
|||
|
&& PREV_INSN (next_active_insn (insn)) == operands[1]"
|
|||
|
"*
|
|||
|
{
|
|||
|
/* .cpadd expands to add REG,REG,$gp when pic, and nothing when not pic. */
|
|||
|
if (mips_abi == ABI_32)
|
|||
|
output_asm_insn (\".cpadd\\t%0\", operands);
|
|||
|
return \"%*j\\t%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_expand "tablejump_internal4"
|
|||
|
[(set (pc)
|
|||
|
(plus:DI (match_operand:DI 0 "se_register_operand" "d")
|
|||
|
(label_ref:DI (match_operand:SI 1 "" ""))))]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
;;; Make sure that this only matches the insn before ADDR_DIFF_VEC. Otherwise
|
|||
|
;;; it is not valid.
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (pc)
|
|||
|
(plus:DI (match_operand:DI 0 "se_register_operand" "d")
|
|||
|
(label_ref:DI (match_operand:SI 1 "" ""))))]
|
|||
|
"TARGET_LONG64 && next_active_insn (insn) != 0
|
|||
|
&& GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
|
|||
|
&& PREV_INSN (next_active_insn (insn)) == operands[1]"
|
|||
|
"%*j\\t%0"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; Implement a switch statement when generating embedded PIC code.
|
|||
|
;; Switches are implemented by `tablejump' when not using -membedded-pic.
|
|||
|
|
|||
|
(define_expand "casesi"
|
|||
|
[(set (match_dup 5)
|
|||
|
(minus:SI (match_operand:SI 0 "register_operand" "d")
|
|||
|
(match_operand:SI 1 "arith_operand" "dI")))
|
|||
|
(set (cc0)
|
|||
|
(compare:CC (match_dup 5)
|
|||
|
(match_operand:SI 2 "arith_operand" "")))
|
|||
|
(set (pc)
|
|||
|
(if_then_else (gtu (cc0)
|
|||
|
(const_int 0))
|
|||
|
(label_ref (match_operand 4 "" ""))
|
|||
|
(pc)))
|
|||
|
(parallel
|
|||
|
[(set (pc)
|
|||
|
(mem:SI (plus:SI (mult:SI (match_dup 5)
|
|||
|
(const_int 4))
|
|||
|
(label_ref (match_operand 3 "" "")))))
|
|||
|
(clobber (match_scratch:SI 6 ""))
|
|||
|
(clobber (reg:SI 31))])]
|
|||
|
"TARGET_EMBEDDED_PIC"
|
|||
|
"
|
|||
|
{
|
|||
|
/* We need slightly different code for eight byte table entries. */
|
|||
|
if (TARGET_LONG64)
|
|||
|
abort ();
|
|||
|
|
|||
|
if (operands[0])
|
|||
|
{
|
|||
|
rtx reg = gen_reg_rtx (SImode);
|
|||
|
|
|||
|
/* If the index is too large, go to the default label. */
|
|||
|
emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
|
|||
|
emit_insn (gen_cmpsi (reg, operands[2]));
|
|||
|
emit_insn (gen_bgtu (operands[4]));
|
|||
|
|
|||
|
/* Do the PIC jump. */
|
|||
|
emit_insn (gen_casesi_internal (reg, operands[3], gen_reg_rtx (SImode)));
|
|||
|
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;; An embedded PIC switch statement looks like this:
|
|||
|
;; bal $LS1
|
|||
|
;; sll $reg,$index,2
|
|||
|
;; $LS1:
|
|||
|
;; addu $reg,$reg,$31
|
|||
|
;; lw $reg,$L1-$LS1($reg)
|
|||
|
;; addu $reg,$reg,$31
|
|||
|
;; j $reg
|
|||
|
;; $L1:
|
|||
|
;; .word case1-$LS1
|
|||
|
;; .word case2-$LS1
|
|||
|
;; ...
|
|||
|
|
|||
|
(define_insn "casesi_internal"
|
|||
|
[(set (pc)
|
|||
|
(mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "d")
|
|||
|
(const_int 4))
|
|||
|
(label_ref (match_operand 1 "" "")))))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "d"))
|
|||
|
(clobber (reg:SI 31))]
|
|||
|
"TARGET_EMBEDDED_PIC"
|
|||
|
"*
|
|||
|
{
|
|||
|
output_asm_insn (\"%(bal\\t%S1\;sll\\t%0,2\\n%S1:\", operands);
|
|||
|
output_asm_insn (\"addu\\t%0,%0,$31%)\", operands);
|
|||
|
output_asm_insn (\"lw\\t%0,%1-%S1(%0)\;addu\\t%0,%0,$31\", operands);
|
|||
|
return \"j\\t%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "6")])
|
|||
|
|
|||
|
;; ??? This is a hack to work around a problem with expand_builtin_setjmp.
|
|||
|
;; It restores the frame pointer, and then does a call to restore the global
|
|||
|
;; pointer (gp) register. The call insn implicitly (via the assembler) reloads
|
|||
|
;; gp from the stack. However, call insns do not depend on $fp, so it is
|
|||
|
;; possible for the instruction scheduler to move the fp restore after the
|
|||
|
;; call, which then causes gp to be corrupted. We fix this by emitting a
|
|||
|
;; scheduler barrier. A better fix is to put code here that restores the
|
|||
|
;; $gp, and then the call is unnecessary. This is only a problem when PIC
|
|||
|
;; (TARGET_ABICALLS), and only when the gp register is caller-saved
|
|||
|
;; (irix5/o32, but not irix6/n32/n64).
|
|||
|
|
|||
|
(define_expand "nonlocal_goto_receiver"
|
|||
|
[(const_int 0)]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
emit_insn (gen_blockage ());
|
|||
|
}")
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; Function prologue/epilogue
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
|
|||
|
(define_expand "prologue"
|
|||
|
[(const_int 1)]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (mips_isa >= 0) /* avoid unused code warnings */
|
|||
|
{
|
|||
|
mips_expand_prologue ();
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;; Block any insns from being moved before this point, since the
|
|||
|
;; profiling call to mcount can use various registers that aren't
|
|||
|
;; saved or used to pass arguments.
|
|||
|
|
|||
|
(define_insn "blockage"
|
|||
|
[(unspec_volatile [(const_int 0)] 0)]
|
|||
|
""
|
|||
|
""
|
|||
|
[(set_attr "type" "unknown")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "0")])
|
|||
|
|
|||
|
(define_expand "epilogue"
|
|||
|
[(const_int 2)]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (mips_isa >= 0) /* avoid unused code warnings */
|
|||
|
{
|
|||
|
mips_expand_epilogue ();
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;; Trivial return. Make it look like a normal return insn as that
|
|||
|
;; allows jump optimizations to work better .
|
|||
|
(define_insn "return"
|
|||
|
[(return)]
|
|||
|
"mips_can_use_return_insn ()"
|
|||
|
"%*j\\t$31"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; Normal return.
|
|||
|
(define_insn "return_internal"
|
|||
|
[(use (reg:SI 31))
|
|||
|
(return)]
|
|||
|
""
|
|||
|
"%*j\\t$31"
|
|||
|
[(set_attr "type" "jump")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; When generating embedded PIC code we need to get the address of the
|
|||
|
;; current function. This specialized instruction does just that.
|
|||
|
|
|||
|
(define_insn "get_fnaddr"
|
|||
|
[(set (match_operand 0 "register_operand" "=d")
|
|||
|
(unspec [(match_operand 1 "" "")] 1))
|
|||
|
(clobber (reg:SI 31))]
|
|||
|
"TARGET_EMBEDDED_PIC
|
|||
|
&& GET_CODE (operands[1]) == SYMBOL_REF"
|
|||
|
"%($LF%= = . + 8\;bal\\t$LF%=\;la\\t%0,%1-$LF%=%)\;addu\\t%0,%0,$31"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "4")])
|
|||
|
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; 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 (reg:SI 31))
|
|||
|
(use (match_operand 2 "" "")) ;; next_arg_reg
|
|||
|
(use (match_operand 3 "" ""))])] ;; struct_value_size_rtx
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx addr;
|
|||
|
|
|||
|
if (operands[0]) /* eliminate unused code warnings */
|
|||
|
{
|
|||
|
addr = XEXP (operands[0], 0);
|
|||
|
if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
|
|||
|
|| ! call_insn_operand (addr, VOIDmode))
|
|||
|
XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
|
|||
|
|
|||
|
/* In order to pass small structures by value in registers
|
|||
|
compatibly with the MIPS compiler, we need to shift the value
|
|||
|
into the high part of the register. Function_arg has encoded
|
|||
|
a PARALLEL rtx, holding a vector of adjustments to be made
|
|||
|
as the next_arg_reg variable, so we split up the insns,
|
|||
|
and emit them separately. */
|
|||
|
|
|||
|
if (operands[2] != (rtx)0 && GET_CODE (operands[2]) == PARALLEL)
|
|||
|
{
|
|||
|
rtvec adjust = XVEC (operands[2], 0);
|
|||
|
int num = GET_NUM_ELEM (adjust);
|
|||
|
int i;
|
|||
|
|
|||
|
for (i = 0; i < num; i++)
|
|||
|
emit_insn (RTVEC_ELT (adjust, i));
|
|||
|
}
|
|||
|
|
|||
|
emit_call_insn (gen_call_internal0 (operands[0], operands[1],
|
|||
|
gen_rtx (REG, SImode, GP_REG_FIRST + 31)));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "call_internal0"
|
|||
|
[(parallel [(call (match_operand 0 "" "")
|
|||
|
(match_operand 1 "" ""))
|
|||
|
(clobber (match_operand:SI 2 "" ""))])]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "call_internal1"
|
|||
|
[(call (mem (match_operand 0 "call_insn_operand" "ri"))
|
|||
|
(match_operand 1 "" "i"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=d"))]
|
|||
|
"!TARGET_ABICALLS && !TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
register rtx target = operands[0];
|
|||
|
|
|||
|
if (GET_CODE (target) == SYMBOL_REF)
|
|||
|
return \"%*jal\\t%0\";
|
|||
|
else if (GET_CODE (target) == CONST_INT)
|
|||
|
return \"%[li\\t%@,%0\\n\\t%*jal\\t%2,%@%]\";
|
|||
|
else
|
|||
|
return \"%*jal\\t%2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "call_internal2"
|
|||
|
[(call (mem (match_operand 0 "call_insn_operand" "ri"))
|
|||
|
(match_operand 1 "" "i"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=d"))]
|
|||
|
"TARGET_ABICALLS && !TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
register rtx target = operands[0];
|
|||
|
|
|||
|
if (GET_CODE (target) == SYMBOL_REF)
|
|||
|
{
|
|||
|
if (GET_MODE (target) == SImode)
|
|||
|
return \"la\\t%^,%0\\n\\tjal\\t%2,%^\";
|
|||
|
else
|
|||
|
return \"dla\\t%^,%0\\n\\tjal\\t%2,%^\";
|
|||
|
}
|
|||
|
else if (GET_CODE (target) == CONST_INT)
|
|||
|
return \"li\\t%^,%0\\n\\tjal\\t%2,%^\";
|
|||
|
else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%0\\n\\tjal\\t%2,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn "call_internal3a"
|
|||
|
[(call (mem:SI (match_operand:SI 0 "register_operand" "r"))
|
|||
|
(match_operand 1 "" "i"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=d"))]
|
|||
|
"!TARGET_LONG64 && !TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"%*jal\\t%2,%0"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "call_internal3b"
|
|||
|
[(call (mem:DI (match_operand:DI 0 "se_register_operand" "r"))
|
|||
|
(match_operand 1 "" "i"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=d"))]
|
|||
|
"TARGET_LONG64 && !TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"%*jal\\t%2,%0"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "call_internal4a"
|
|||
|
[(call (mem:SI (match_operand:SI 0 "register_operand" "r"))
|
|||
|
(match_operand 1 "" "i"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=d"))]
|
|||
|
"!TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (REGNO (operands[0]) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%0\\n\\tjal\\t%2,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn "call_internal4b"
|
|||
|
[(call (mem:DI (match_operand:DI 0 "se_register_operand" "r"))
|
|||
|
(match_operand 1 "" "i"))
|
|||
|
(clobber (match_operand:SI 2 "register_operand" "=d"))]
|
|||
|
"TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (REGNO (operands[0]) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%0\\n\\tjal\\t%2,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%2,%0\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
;; 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 (reg:SI 31))
|
|||
|
(use (match_operand 3 "" ""))])] ;; next_arg_reg
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
rtx addr;
|
|||
|
|
|||
|
if (operands[0]) /* eliminate unused code warning */
|
|||
|
{
|
|||
|
addr = XEXP (operands[1], 0);
|
|||
|
if ((GET_CODE (addr) != REG && (!CONSTANT_ADDRESS_P (addr) || TARGET_LONG_CALLS))
|
|||
|
|| ! call_insn_operand (addr, VOIDmode))
|
|||
|
XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
|
|||
|
|
|||
|
/* In order to pass small structures by value in registers
|
|||
|
compatibly with the MIPS compiler, we need to shift the value
|
|||
|
into the high part of the register. Function_arg has encoded
|
|||
|
a PARALLEL rtx, holding a vector of adjustments to be made
|
|||
|
as the next_arg_reg variable, so we split up the insns,
|
|||
|
and emit them separately. */
|
|||
|
|
|||
|
if (operands[3] != (rtx)0 && GET_CODE (operands[3]) == PARALLEL)
|
|||
|
{
|
|||
|
rtvec adjust = XVEC (operands[3], 0);
|
|||
|
int num = GET_NUM_ELEM (adjust);
|
|||
|
int i;
|
|||
|
|
|||
|
for (i = 0; i < num; i++)
|
|||
|
emit_insn (RTVEC_ELT (adjust, i));
|
|||
|
}
|
|||
|
|
|||
|
/* Handle Irix6 function calls that have multiple non-contiguous
|
|||
|
results. */
|
|||
|
if (GET_CODE (operands[0]) == PARALLEL && XVECLEN (operands[0], 0) > 1)
|
|||
|
{
|
|||
|
emit_call_insn (gen_call_value_multiple_internal0
|
|||
|
(XEXP (XVECEXP (operands[0], 0, 0), 0),
|
|||
|
operands[1], operands[2],
|
|||
|
XEXP (XVECEXP (operands[0], 0, 1), 0),
|
|||
|
gen_rtx (REG, SImode, GP_REG_FIRST + 31)));
|
|||
|
DONE;
|
|||
|
}
|
|||
|
|
|||
|
/* We have a call returning a DImode structure in an FP reg.
|
|||
|
Strip off the now unnecessary PARALLEL. */
|
|||
|
if (GET_CODE (operands[0]) == PARALLEL)
|
|||
|
operands[0] = XEXP (XVECEXP (operands[0], 0, 0), 0);
|
|||
|
|
|||
|
emit_call_insn (gen_call_value_internal0 (operands[0], operands[1], operands[2],
|
|||
|
gen_rtx (REG, SImode, GP_REG_FIRST + 31)));
|
|||
|
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "call_value_internal0"
|
|||
|
[(parallel [(set (match_operand 0 "" "")
|
|||
|
(call (match_operand 1 "" "")
|
|||
|
(match_operand 2 "" "")))
|
|||
|
(clobber (match_operand:SI 3 "" ""))])]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
(define_insn "call_value_internal1"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem (match_operand 1 "call_insn_operand" "ri"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(clobber (match_operand:SI 3 "register_operand" "=d"))]
|
|||
|
"!TARGET_ABICALLS && !TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
register rtx target = operands[1];
|
|||
|
|
|||
|
if (GET_CODE (target) == SYMBOL_REF)
|
|||
|
return \"%*jal\\t%1\";
|
|||
|
else if (GET_CODE (target) == CONST_INT)
|
|||
|
return \"%[li\\t%@,%1\\n\\t%*jal\\t%3,%@%]\";
|
|||
|
else
|
|||
|
return \"%*jal\\t%3,%1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "call_value_internal2"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem (match_operand 1 "call_insn_operand" "ri"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(clobber (match_operand:SI 3 "register_operand" "=d"))]
|
|||
|
"TARGET_ABICALLS && !TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
register rtx target = operands[1];
|
|||
|
|
|||
|
if (GET_CODE (target) == SYMBOL_REF)
|
|||
|
{
|
|||
|
if (GET_MODE (target) == SImode)
|
|||
|
return \"la\\t%^,%1\\n\\tjal\\t%3,%^\";
|
|||
|
else
|
|||
|
return \"dla\\t%^,%1\\n\\tjal\\t%3,%^\";
|
|||
|
}
|
|||
|
else if (GET_CODE (target) == CONST_INT)
|
|||
|
return \"li\\t%^,%1\\n\\tjal\\t%3,%^\";
|
|||
|
else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%1\\n\\tjal\\t%3,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%3,%1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn "call_value_internal3a"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem:SI (match_operand:SI 1 "register_operand" "r"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(clobber (match_operand:SI 3 "register_operand" "=d"))]
|
|||
|
"!TARGET_LONG64 && !TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"%*jal\\t%3,%1"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "call_value_internal3b"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem:DI (match_operand:DI 1 "se_register_operand" "r"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(clobber (match_operand:SI 3 "register_operand" "=d"))]
|
|||
|
"TARGET_LONG64 && !TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"%*jal\\t%3,%1"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
(define_insn "call_value_internal4a"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem:SI (match_operand:SI 1 "register_operand" "r"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(clobber (match_operand:SI 3 "register_operand" "=d"))]
|
|||
|
"!TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (REGNO (operands[1]) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%1\\n\\tjal\\t%3,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%3,%1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_insn "call_value_internal4b"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem:DI (match_operand:DI 1 "se_register_operand" "r"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(clobber (match_operand:SI 3 "register_operand" "=d"))]
|
|||
|
"TARGET_LONG64 && TARGET_ABICALLS && TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
if (REGNO (operands[1]) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%1\\n\\tjal\\t%3,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%3,%1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
(define_expand "call_value_multiple_internal0"
|
|||
|
[(parallel [(set (match_operand 0 "" "")
|
|||
|
(call (match_operand 1 "" "")
|
|||
|
(match_operand 2 "" "")))
|
|||
|
(set (match_operand 3 "" "")
|
|||
|
(call (match_dup 1)
|
|||
|
(match_dup 2)))
|
|||
|
(clobber (match_operand:SI 4 "" ""))])]
|
|||
|
""
|
|||
|
"")
|
|||
|
|
|||
|
;; ??? May eventually need all 6 versions of the call patterns with multiple
|
|||
|
;; return values.
|
|||
|
|
|||
|
(define_insn "call_value_multiple_internal2"
|
|||
|
[(set (match_operand 0 "register_operand" "=df")
|
|||
|
(call (mem (match_operand 1 "call_insn_operand" "ri"))
|
|||
|
(match_operand 2 "" "i")))
|
|||
|
(set (match_operand 3 "register_operand" "=df")
|
|||
|
(call (mem (match_dup 1))
|
|||
|
(match_dup 2)))
|
|||
|
(clobber (match_operand:SI 4 "register_operand" "=d"))]
|
|||
|
"TARGET_ABICALLS && !TARGET_LONG_CALLS"
|
|||
|
"*
|
|||
|
{
|
|||
|
register rtx target = operands[1];
|
|||
|
|
|||
|
if (GET_CODE (target) == SYMBOL_REF)
|
|||
|
{
|
|||
|
if (GET_MODE (target) == SImode)
|
|||
|
return \"la\\t%^,%1\\n\\tjal\\t%4,%^\";
|
|||
|
else
|
|||
|
return \"la\\t%^,%1\\n\\tjal\\t%4,%^\";
|
|||
|
}
|
|||
|
else if (GET_CODE (target) == CONST_INT)
|
|||
|
return \"li\\t%^,%1\\n\\tjal\\t%4,%^\";
|
|||
|
else if (REGNO (target) != PIC_FUNCTION_ADDR_REGNUM)
|
|||
|
return \"move\\t%^,%1\\n\\tjal\\t%4,%^\";
|
|||
|
else
|
|||
|
return \"jal\\t%4,%1\";
|
|||
|
}"
|
|||
|
[(set_attr "type" "call")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "2")])
|
|||
|
|
|||
|
|
|||
|
;; Call subroutine returning any type.
|
|||
|
|
|||
|
(define_expand "untyped_call"
|
|||
|
[(parallel [(call (match_operand 0 "" "")
|
|||
|
(const_int 0))
|
|||
|
(match_operand 1 "" "")
|
|||
|
(match_operand 2 "" "")])]
|
|||
|
""
|
|||
|
"
|
|||
|
{
|
|||
|
if (operands[0]) /* silence statement not reached warnings */
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
|
|||
|
|
|||
|
for (i = 0; i < XVECLEN (operands[2], 0); i++)
|
|||
|
{
|
|||
|
rtx set = XVECEXP (operands[2], 0, i);
|
|||
|
emit_move_insn (SET_DEST (set), SET_SRC (set));
|
|||
|
}
|
|||
|
|
|||
|
emit_insn (gen_blockage ());
|
|||
|
DONE;
|
|||
|
}
|
|||
|
}")
|
|||
|
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
;; MISC.
|
|||
|
;;
|
|||
|
;; ....................
|
|||
|
;;
|
|||
|
|
|||
|
(define_insn "nop"
|
|||
|
[(const_int 0)]
|
|||
|
""
|
|||
|
"%(nop%)"
|
|||
|
[(set_attr "type" "nop")
|
|||
|
(set_attr "mode" "none")
|
|||
|
(set_attr "length" "1")])
|
|||
|
|
|||
|
;; The MIPS chip does not seem to require stack probes.
|
|||
|
;;
|
|||
|
;; (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 */
|
|||
|
;; }")
|
|||
|
;;
|
|||
|
|
|||
|
;;
|
|||
|
;; MIPS4 Conditional move instructions.
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
|||
|
(if_then_else:SI
|
|||
|
(match_operator 4 "equality_op"
|
|||
|
[(match_operand:SI 1 "register_operand" "d,d")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:SI 2 "reg_or_0_operand" "dJ,0")
|
|||
|
(match_operand:SI 3 "reg_or_0_operand" "0,dJ")))]
|
|||
|
"mips_isa >= 4"
|
|||
|
"@
|
|||
|
mov%B4\\t%0,%z2,%1
|
|||
|
mov%b4\\t%0,%z3,%1"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "SI")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
|||
|
(if_then_else:SI
|
|||
|
(match_operator 4 "equality_op"
|
|||
|
[(match_operand:DI 1 "se_register_operand" "d,d")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:SI 2 "reg_or_0_operand" "dJ,0")
|
|||
|
(match_operand:SI 3 "reg_or_0_operand" "0,dJ")))]
|
|||
|
"mips_isa >= 4"
|
|||
|
"@
|
|||
|
mov%B4\\t%0,%z2,%1
|
|||
|
mov%b4\\t%0,%z3,%1"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "SI")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SI 0 "register_operand" "=d,d")
|
|||
|
(if_then_else:SI
|
|||
|
(match_operator 3 "equality_op" [(match_operand:CC 4
|
|||
|
"register_operand"
|
|||
|
"z,z")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:SI 1 "reg_or_0_operand" "dJ,0")
|
|||
|
(match_operand:SI 2 "reg_or_0_operand" "0,dJ")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"@
|
|||
|
mov%T3\\t%0,%z1,%4
|
|||
|
mov%t3\\t%0,%z2,%4"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "SI")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(if_then_else:DI
|
|||
|
(match_operator 4 "equality_op"
|
|||
|
[(match_operand:SI 1 "register_operand" "d,d")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:DI 2 "se_reg_or_0_operand" "dJ,0")
|
|||
|
(match_operand:DI 3 "se_reg_or_0_operand" "0,dJ")))]
|
|||
|
"mips_isa >= 4"
|
|||
|
"@
|
|||
|
mov%B4\\t%0,%z2,%1
|
|||
|
mov%b4\\t%0,%z3,%1"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "DI")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(if_then_else:DI
|
|||
|
(match_operator 4 "equality_op"
|
|||
|
[(match_operand:DI 1 "se_register_operand" "d,d")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:DI 2 "se_reg_or_0_operand" "dJ,0")
|
|||
|
(match_operand:DI 3 "se_reg_or_0_operand" "0,dJ")))]
|
|||
|
"mips_isa >= 4"
|
|||
|
"@
|
|||
|
mov%B4\\t%0,%z2,%1
|
|||
|
mov%b4\\t%0,%z3,%1"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "DI")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DI 0 "register_operand" "=d,d")
|
|||
|
(if_then_else:DI
|
|||
|
(match_operator 3 "equality_op" [(match_operand:CC 4
|
|||
|
"register_operand"
|
|||
|
"z,z")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:DI 1 "se_reg_or_0_operand" "dJ,0")
|
|||
|
(match_operand:DI 2 "se_reg_or_0_operand" "0,dJ")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"@
|
|||
|
mov%T3\\t%0,%z1,%4
|
|||
|
mov%t3\\t%0,%z2,%4"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "DI")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(if_then_else:SF
|
|||
|
(match_operator 4 "equality_op"
|
|||
|
[(match_operand:SI 1 "register_operand" "d,d")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:SF 2 "register_operand" "f,0")
|
|||
|
(match_operand:SF 3 "register_operand" "0,f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"@
|
|||
|
mov%B4.s\\t%0,%2,%1
|
|||
|
mov%b4.s\\t%0,%3,%1"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "SF")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:SF 0 "register_operand" "=f,f")
|
|||
|
(if_then_else:SF
|
|||
|
(match_operator 3 "equality_op" [(match_operand:CC 4
|
|||
|
"register_operand"
|
|||
|
"z,z")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:SF 1 "register_operand" "f,0")
|
|||
|
(match_operand:SF 2 "register_operand" "0,f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"@
|
|||
|
mov%T3.s\\t%0,%1,%4
|
|||
|
mov%t3.s\\t%0,%2,%4"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "SF")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
|||
|
(if_then_else:DF
|
|||
|
(match_operator 4 "equality_op"
|
|||
|
[(match_operand:SI 1 "register_operand" "d,d")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:DF 2 "register_operand" "f,0")
|
|||
|
(match_operand:DF 3 "register_operand" "0,f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"@
|
|||
|
mov%B4.d\\t%0,%2,%1
|
|||
|
mov%b4.d\\t%0,%3,%1"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "DF")])
|
|||
|
|
|||
|
(define_insn ""
|
|||
|
[(set (match_operand:DF 0 "register_operand" "=f,f")
|
|||
|
(if_then_else:DF
|
|||
|
(match_operator 3 "equality_op" [(match_operand:CC 4
|
|||
|
"register_operand"
|
|||
|
"z,z")
|
|||
|
(const_int 0)])
|
|||
|
(match_operand:DF 1 "register_operand" "f,0")
|
|||
|
(match_operand:DF 2 "register_operand" "0,f")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"@
|
|||
|
mov%T3.d\\t%0,%1,%4
|
|||
|
mov%t3.d\\t%0,%2,%4"
|
|||
|
[(set_attr "type" "move")
|
|||
|
(set_attr "mode" "DF")])
|
|||
|
|
|||
|
;; These are the main define_expand's used to make conditional moves.
|
|||
|
|
|||
|
(define_expand "movsicc"
|
|||
|
[(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
|
|||
|
(set (match_operand:SI 0 "register_operand" "")
|
|||
|
(if_then_else:SI (match_dup 5)
|
|||
|
(match_operand:SI 2 "reg_or_0_operand" "")
|
|||
|
(match_operand:SI 3 "reg_or_0_operand" "")))]
|
|||
|
"mips_isa >= 4"
|
|||
|
"
|
|||
|
{
|
|||
|
gen_conditional_move (operands);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "movdicc"
|
|||
|
[(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
|
|||
|
(set (match_operand:DI 0 "register_operand" "")
|
|||
|
(if_then_else:DI (match_dup 5)
|
|||
|
(match_operand:DI 2 "se_reg_or_0_operand" "")
|
|||
|
(match_operand:DI 3 "se_reg_or_0_operand" "")))]
|
|||
|
"mips_isa >= 4"
|
|||
|
"
|
|||
|
{
|
|||
|
gen_conditional_move (operands);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "movsfcc"
|
|||
|
[(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
|
|||
|
(set (match_operand:SF 0 "register_operand" "")
|
|||
|
(if_then_else:SF (match_dup 5)
|
|||
|
(match_operand:SF 2 "register_operand" "")
|
|||
|
(match_operand:SF 3 "register_operand" "")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
gen_conditional_move (operands);
|
|||
|
DONE;
|
|||
|
}")
|
|||
|
|
|||
|
(define_expand "movdfcc"
|
|||
|
[(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
|
|||
|
(set (match_operand:DF 0 "register_operand" "")
|
|||
|
(if_then_else:DF (match_dup 5)
|
|||
|
(match_operand:DF 2 "register_operand" "")
|
|||
|
(match_operand:DF 3 "register_operand" "")))]
|
|||
|
"mips_isa >= 4 && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
|
|||
|
"
|
|||
|
{
|
|||
|
gen_conditional_move (operands);
|
|||
|
DONE;
|
|||
|
}")
|