URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [config/] [microblaze/] [microblaze.md] - Rev 709
Compare with Previous | Blame | View Log
;; microblaze.md -- Machine description for Xilinx MicroBlaze processors.
;; Copyright 2009, 2010 Free Software Foundation, Inc.
;; Contributed by Michael Eager <eager@eagercon.com>.
;; This file is part of GCC.
;; GCC 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 3, or (at your option)
;; any later version.
;; GCC 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 GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>. */
(include "constraints.md")
(include "predicates.md")
;;----------------------------------------------------
;; Constants
;;----------------------------------------------------
(define_constants [
(R_SP 1) ;; Stack pointer reg
(R_SR 15) ;; Sub-routine return addr reg
(R_IR 14) ;; Interrupt return addr reg
(R_DR 16) ;; Debug trap return addr reg
(R_ER 17) ;; Exception return addr reg
(R_TMP 18) ;; Assembler temporary reg
(R_GOT 20) ;; GOT ptr reg
(MB_PIPE_3 0) ;; Microblaze 3-stage pipeline
(MB_PIPE_5 1) ;; Microblaze 5-stage pipeline
(UNSPEC_SET_GOT 101) ;;
(UNSPEC_GOTOFF 102) ;; GOT offset
(UNSPEC_PLT 103) ;; jump table
(UNSPEC_CMP 104) ;; signed compare
(UNSPEC_CMPU 105) ;; unsigned compare
])
;;----------------------------------------------------
;; Instruction 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
;; arith integer arithmetic instruction
;; darith double precision integer arithmetic instructions
;; imul integer multiply
;; idiv integer divide
;; icmp integer compare
;; Xfadd floating point add/subtract
;; Xfmul floating point multiply
;; Xfmadd floating point multiply-add
;; Xfdiv floating point divide
;; Xfabs floating point absolute value
;; Xfneg floating point negation
;; Xfcmp floating point compare
;; Xfcvt floating point convert
;; Xfsqrt floating point square root
;; multi multiword sequence (or user asm statements)
;; nop no operation
;; bshift Shift operations
(define_attr "type"
"unknown,branch,jump,call,load,store,move,arith,darith,imul,idiv,icmp,multi,nop,no_delay_arith,no_delay_load,no_delay_store,no_delay_imul,no_delay_move,bshift,fadd,frsub,fmul,fdiv,fcmp,fsl,fsqrt,fcvt"
(const_string "unknown"))
;; Main data type used by the insn
(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF" (const_string "unknown"))
;; # instructions (4 bytes each)
(define_attr "length" "" (const_int 4))
(define_code_iterator any_return [return simple_return])
;; <optab> expands to the name of the optab for a particular code.
(define_code_attr optab [(return "return")
(simple_return "simple_return")])
;;----------------------------------------------------
;; Attribute describing the processor.
;;----------------------------------------------------
;; 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 "microblaze_abicalls_attr")))
;;----------------------------------------------------------------
;; Microblaze DFA Pipeline description
;;----------------------------------------------------------------
;;-----------------------------------------------------------------
/*
This is description of pipeline hazards based on DFA. The
following constructions can be used for this:
o define_cpu_unit string [string]) describes a cpu functional unit
(separated by comma).
1st operand: Names of cpu function units.
2nd operand: Name of automaton (see comments for
DEFINE_AUTOMATON).
All define_reservations and define_cpu_units should have unique
names which can not be "nothing".
o (exclusion_set string string) means that each CPU function unit
in the first string can not be reserved simultaneously with each
unit whose name is in the second string and vise versa. CPU
units in the string are separated by commas. For example, it is
useful for description CPU with fully pipelined floating point
functional unit which can execute simultaneously only single
floating point insns or only double floating point insns.
o (presence_set string string) means that each CPU function unit in
the first string can not be reserved unless at least one of units
whose names are in the second string is reserved. This is an
asymmetric relation. CPU units in the string are separated by
commas. For example, it is useful for description that slot1 is
reserved after slot0 reservation for a VLIW processor.
o (absence_set string string) means that each CPU function unit in
the first string can not be reserved only if each unit whose name
is in the second string is not reserved. This is an asymmetric
relation (actually exclusion set is analogous to this one but it
is symmetric). CPU units in the string are separated by commas.
For example, it is useful for description that slot0 can not be
reserved after slot1 or slot2 reservation for a VLIW processor.
o (define_bypass number out_insn_names in_insn_names) names bypass with
given latency (the first number) from insns given by the first
string (see define_insn_reservation) into insns given by the
second string. Insn names in the strings are separated by
commas.
o (define_automaton string) describes names of an automaton
generated and used for pipeline hazards recognition. The names
are separated by comma. Actually it is possibly to generate the
single automaton but unfortunately it can be very large. If we
use more one automata, the summary size of the automata usually
is less than the single one. The automaton name is used in
define_cpu_unit. All automata should have unique names.
o (define_reservation string string) names reservation (the first
string) of cpu functional units (the 2nd string). Sometimes unit
reservations for different insns contain common parts. In such
case, you describe common part and use one its name (the 1st
parameter) in regular expression in define_insn_reservation. All
define_reservations, define results and define_cpu_units should
have unique names which can not be "nothing".
o (define_insn_reservation name default_latency condition regexpr)
describes reservation of cpu functional units (the 3nd operand)
for instruction which is selected by the condition (the 2nd
parameter). The first parameter is used for output of debugging
information. The reservations are described by a regular
expression according the following syntax:
regexp = regexp "," oneof
| oneof
oneof = oneof "|" allof
| allof
allof = allof "+" repeat
| repeat
repeat = element "*" number
| element
element = cpu_function_name
| reservation_name
| result_name
| "nothing"
| "(" regexp ")"
1. "," is used for describing start of the next cycle in
reservation.
2. "|" is used for describing the reservation described by the
first regular expression *or* the reservation described by
the second regular expression *or* etc.
3. "+" is used for describing the reservation described by the
first regular expression *and* the reservation described by
the second regular expression *and* etc.
4. "*" is used for convenience and simply means sequence in
which the regular expression are repeated NUMBER times with
cycle advancing (see ",").
5. cpu function unit name which means reservation.
6. reservation name -- see define_reservation.
7. string "nothing" means no units reservation.
*/
;;-----------------------------------------------------------------
;;----------------------------------------------------------------
;; Microblaze 5-stage pipeline description (v5.00.a and later)
;;----------------------------------------------------------------
(define_automaton "mbpipe_5")
(define_cpu_unit "mb_issue,mb_iu,mb_wb,mb_fpu,mb_fpu_2,mb_mul,mb_mul_2,mb_div,mb_div_2,mb_bs,mb_bs_2" "mbpipe_5")
(define_insn_reservation "mb-integer" 1
(and (eq_attr "type" "branch,jump,call,arith,darith,icmp,nop,no_delay_arith")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_iu,mb_wb")
(define_insn_reservation "mb-special-move" 2
(and (eq_attr "type" "move")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_iu*2,mb_wb")
(define_insn_reservation "mb-mem-load" 3
(and (eq_attr "type" "load,no_delay_load")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_iu,mb_wb")
(define_insn_reservation "mb-mem-store" 1
(and (eq_attr "type" "store,no_delay_store")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_iu,mb_wb")
(define_insn_reservation "mb-mul" 3
(and (eq_attr "type" "imul,no_delay_imul")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_mul,mb_mul_2*2,mb_wb")
(define_insn_reservation "mb-div" 34
(and (eq_attr "type" "idiv")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_div,mb_div_2*33,mb_wb")
(define_insn_reservation "mb-bs" 2
(and (eq_attr "type" "bshift")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_bs,mb_bs_2,mb_wb")
(define_insn_reservation "mb-fpu-add-sub-mul" 6
(and (eq_attr "type" "fadd,frsub,fmul")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_fpu,mb_fpu_2*5,mb_wb")
(define_insn_reservation "mb-fpu-fcmp" 3
(and (eq_attr "type" "fcmp")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_fpu,mb_fpu*2,mb_wb")
(define_insn_reservation "mb-fpu-div" 30
(and (eq_attr "type" "fdiv")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_fpu,mb_fpu_2*29,mb_wb")
(define_insn_reservation "mb-fpu-sqrt" 30
(and (eq_attr "type" "fsqrt")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_fpu,mb_fpu_2*29,mb_wb")
(define_insn_reservation "mb-fpu-fcvt" 4
(and (eq_attr "type" "fcvt")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
"mb_issue,mb_fpu,mb_fpu_2*3,mb_wb")
;;----------------------------------------------------------------
;; Microblaze 3-stage pipeline description (for v4.00.a and earlier)
;;----------------------------------------------------------------
(define_automaton "mbpipe_3")
(define_cpu_unit "mb3_iu" "mbpipe_3")
(define_insn_reservation "mb3-integer" 1
(and (eq_attr "type" "branch,jump,call,arith,darith,icmp,nop,no_delay_arith")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-special-move" 2
(and (eq_attr "type" "move")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu*2")
(define_insn_reservation "mb3-mem-load" 2
(and (eq_attr "type" "load,no_delay_load")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-mem-store" 1
(and (eq_attr "type" "store,no_delay_store")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-mul" 3
(and (eq_attr "type" "imul,no_delay_imul")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-div" 34
(and (eq_attr "type" "idiv")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-bs" 2
(and (eq_attr "type" "bshift")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-fpu-add-sub-mul" 6
(and (eq_attr "type" "fadd,frsub,fmul")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-fpu-fcmp" 3
(and (eq_attr "type" "fcmp")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-fpu-div" 30
(and (eq_attr "type" "fdiv")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-fpu-sqrt" 30
(and (eq_attr "type" "fsqrt")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(define_insn_reservation "mb3-fpu-fcvt" 4
(and (eq_attr "type" "fcvt")
(eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
"mb3_iu")
(automata_option "v")
(automata_option "time")
(automata_option "progress")
;;----------------------------------------------------------------
;; Microblaze delay slot description
;;----------------------------------------------------------------
(define_delay (eq_attr "type" "branch,call,jump")
[(and (eq_attr "type" "!branch,call,jump,icmp,multi,no_delay_arith,no_delay_load,no_delay_store,no_delay_imul,no_delay_move,darith")
(ior (not (match_test "microblaze_no_unsafe_delay"))
(eq_attr "type" "!fadd,frsub,fmul,fdiv,fcmp,store,load")
))
(nil) (nil)])
;;----------------------------------------------------------------
;; Microblaze FPU
;;----------------------------------------------------------------
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=d")
(plus:SF (match_operand:SF 1 "register_operand" "d")
(match_operand:SF 2 "register_operand" "d")))]
"TARGET_HARD_FLOAT"
"fadd\t%0,%1,%2"
[(set_attr "type" "fadd")
(set_attr "mode" "SF")
(set_attr "length" "4")])
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=d")
(minus:SF (match_operand:SF 1 "register_operand" "d")
(match_operand:SF 2 "register_operand" "d")))]
"TARGET_HARD_FLOAT"
"frsub\t%0,%2,%1"
[(set_attr "type" "frsub")
(set_attr "mode" "SF")
(set_attr "length" "4")])
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=d")
(mult:SF (match_operand:SF 1 "register_operand" "d")
(match_operand:SF 2 "register_operand" "d")))]
"TARGET_HARD_FLOAT"
"fmul\t%0,%1,%2"
[(set_attr "type" "fmul")
(set_attr "mode" "SF")
(set_attr "length" "4")])
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=d")
(div:SF (match_operand:SF 1 "register_operand" "d")
(match_operand:SF 2 "register_operand" "d")))]
"TARGET_HARD_FLOAT"
"fdiv\t%0,%2,%1"
[(set_attr "type" "fdiv")
(set_attr "mode" "SF")
(set_attr "length" "4")])
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=d")
(sqrt:SF (match_operand:SF 1 "register_operand" "d")))]
"TARGET_HARD_FLOAT && TARGET_FLOAT_SQRT"
"fsqrt\t%0,%1"
[(set_attr "type" "fsqrt")
(set_attr "mode" "SF")
(set_attr "length" "4")])
(define_insn "floatsisf2"
[(set (match_operand:SF 0 "register_operand" "=d")
(float:SF (match_operand:SI 1 "register_operand" "d")))]
"TARGET_HARD_FLOAT && TARGET_FLOAT_CONVERT"
"flt\t%0,%1"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")
(set_attr "length" "4")])
(define_insn "fix_truncsfsi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(fix:SI (match_operand:SF 1 "register_operand" "d")))]
"TARGET_HARD_FLOAT && TARGET_FLOAT_CONVERT"
"fint\t%0,%1"
[(set_attr "type" "fcvt")
(set_attr "mode" "SF")
(set_attr "length" "4")])
;;----------------------------------------------------------------
;; Add
;;----------------------------------------------------------------
;; Add 2 SImode integers [ src1 = reg ; src2 = arith ; dest = reg ]
;; Leave carry as is
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "%dJ,dJ,dJ")
(match_operand:SI 2 "arith_operand" "d,I,i")))]
""
"@
addk\t%0,%z1,%2
addik\t%0,%z1,%2
addik\t%0,%z1,%2"
[(set_attr "type" "arith,arith,no_delay_arith")
(set_attr "mode" "SI,SI,SI")
(set_attr "length" "4,4,8")])
;;----------------------------------------------------------------
;; Double Precision Additions
;;----------------------------------------------------------------
;; reg_DI_dest = reg_DI_src1 + DI_src2
;; Adding 2 DI operands in register or reg/imm
(define_insn "adddi3"
[(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 "arith_operand32" "d,P,N")))]
""
"@
add\t%L0,%L1,%L2\;addc\t%M0,%M1,%M2
addi\t%L0,%L1,%2\;addc\t%M0,%M1,r0
addi\t%L0,%L1,%2\;addc\t%M0,%M1,r0\;addi\t%M0,%M0,-1"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8,8,12")])
;;----------------------------------------------------------------
;; Subtraction
;;----------------------------------------------------------------
(define_insn "subsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(minus:SI (match_operand:SI 1 "arith_operand" "d,d")
(match_operand:SI 2 "arith_operand" "d,n")))]
""
"@
rsubk\t%0,%2,%z1
addik\t%0,%z1,-%2"
[(set_attr "type" "arith,no_delay_arith")
(set_attr "mode" "SI")
(set_attr "length" "4,8")])
;;----------------------------------------------------------------
;; Double Precision Subtraction
;;----------------------------------------------------------------
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=&d")
(minus:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "arith_operand32" "d")))]
""
"@
rsub\t%L0,%L2,%L1\;rsubc\t%M0,%M2,%M1"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8")])
;;----------------------------------------------------------------
;; Multiplication
;;----------------------------------------------------------------
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
(mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
(match_operand:SI 2 "arith_operand" "d,I,i")))]
"!TARGET_SOFT_MUL"
"@
mul\t%0,%1,%2
muli\t%0,%1,%2
muli\t%0,%1,%2"
[(set_attr "type" "imul,imul,no_delay_imul")
(set_attr "mode" "SI")
(set_attr "length" "4,4,8")])
(define_insn "mulsidi3"
[(set (match_operand:DI 0 "register_operand" "=&d")
(mult:DI
(sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
"!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
"mul\t%L0,%1,%2\;mulh\t%M0,%1,%2"
[(set_attr "type" "no_delay_arith")
(set_attr "mode" "DI")
(set_attr "length" "8")])
(define_insn "umulsidi3"
[(set (match_operand:DI 0 "register_operand" "=&d")
(mult:DI
(zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
(zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
"!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
"mul\t%L0,%1,%2\;mulhu\t%M0,%1,%2"
[(set_attr "type" "no_delay_arith")
(set_attr "mode" "DI")
(set_attr "length" "8")])
(define_insn "usmulsidi3"
[(set (match_operand:DI 0 "register_operand" "=&d")
(mult:DI
(zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
"!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
"mul\t%L0,%1,%2\;mulhsu\t%M0,%2,%1"
[(set_attr "type" "no_delay_arith")
(set_attr "mode" "DI")
(set_attr "length" "8")])
(define_insn "*smulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
(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))))]
"!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
"mulh\t%0,%1,%2"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "*umulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
(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))))]
"!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
"mulhu\t%0,%1,%2"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "*usmulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
(truncate:SI
(lshiftrt:DI
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "d"))
)
(const_int 32))))]
"!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
"mulhsu\t%0,%2,%1"
[(set_attr "type" "imul")
(set_attr "mode" "SI")
(set_attr "length" "4")])
;;----------------------------------------------------------------
;; Division and remainder
;;----------------------------------------------------------------
(define_expand "divsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(div:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
]
"(!TARGET_SOFT_DIV) || (TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)"
{
if (TARGET_SOFT_DIV && TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)
{
microblaze_expand_divide (operands);
DONE;
}
else if (!TARGET_SOFT_DIV)
{
emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2]));
DONE;
}
}
)
(define_insn "divsi3_internal"
[(set (match_operand:SI 0 "register_operand" "=d")
(div:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
]
"!TARGET_SOFT_DIV"
"idiv\t%0,%2,%1"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
(define_insn "udivsi3"
[(set (match_operand:SI 0 "register_operand" "=d")
(udiv:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))
]
"!TARGET_SOFT_DIV"
"idivu\t%0,%2,%1"
[(set_attr "type" "idiv")
(set_attr "mode" "SI")
(set_attr "length" "4")])
;;----------------------------------------------------------------
;; 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")))]
""
"rsubk\t%0,%1,r0"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "negdi2"
[(set (match_operand:DI 0 "register_operand" "=d")
(neg:DI (match_operand:DI 1 "register_operand" "d")))]
""
"rsub\t%L0,%L1,r0\;rsubc\t%M0,%M1,r0"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(not:SI (match_operand:SI 1 "register_operand" "d")))]
""
"xori\t%0,%1,-1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "*one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "=d")
(not:DI (match_operand:DI 1 "register_operand" "d")))]
""
"nor\t%M0,r0,%M1\;nor\t%L0,r0,%L1"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8")]
)
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(not:DI (match_operand:DI 1 "register_operand" "")))]
"reload_completed
&& 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) 4) (not:SI (subreg:SI (match_dup 1) 4)))]
"")
;;----------------------------------------------------------------
;; Logical
;;----------------------------------------------------------------
(define_insn "andsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
(and:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
(match_operand:SI 2 "arith_operand" "d,I,i,M")))]
""
"@
and\t%0,%1,%2
andi\t%0,%1,%2 #and1
andi\t%0,%1,%2 #and2
andi\t%0,%1,%2 #and3"
[(set_attr "type" "arith,arith,no_delay_arith,no_delay_arith")
(set_attr "mode" "SI,SI,SI,SI")
(set_attr "length" "4,8,8,8")])
(define_insn "anddi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(and:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))]
""
"and\t%M0,%M1,%M2\;and\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8")])
(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
&& 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) 4) (and:SI (subreg:SI (match_dup 1) 4)
(subreg:SI (match_dup 2) 4)))]
"")
(define_insn "iorsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
(ior:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
(match_operand:SI 2 "arith_operand" "d,I,M,i")))]
""
"@
or\t%0,%1,%2
ori\t%0,%1,%2
ori\t%0,%1,%2
ori\t%0,%1,%2"
[(set_attr "type" "arith,no_delay_arith,no_delay_arith,no_delay_arith")
(set_attr "mode" "SI,SI,SI,SI")
(set_attr "length" "4,8,8,8")])
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(ior:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))]
""
"or\t%M0,%M1,%M2\;or\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8")]
)
(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
&& 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) 4) (ior:SI (subreg:SI (match_dup 1) 4)
(subreg:SI (match_dup 2) 4)))]
"")
(define_insn "xorsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
(xor:SI (match_operand:SI 1 "arith_operand" "%d,d,d")
(match_operand:SI 2 "arith_operand" "d,I,i")))]
""
"@
xor\t%0,%1,%2
xori\t%0,%1,%2
xori\t%0,%1,%2"
[(set_attr "type" "arith,arith,no_delay_arith")
(set_attr "mode" "SI,SI,SI")
(set_attr "length" "4,8,8")])
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=d")
(xor:DI (match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")))]
""
"xor\t%M0,%M1,%M2\;xor\t%L0,%L1,%L2"
[(set_attr "type" "darith")
(set_attr "mode" "DI")
(set_attr "length" "8")]
)
(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
&& 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) 4) (xor:SI (subreg:SI (match_dup 1) 4)
(subreg:SI (match_dup 2) 4)))]
"")
;;----------------------------------------------------------------
;; Zero extension
;;----------------------------------------------------------------
(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")))]
""
"@
andi\t%0,%1,0xffff
lhu%i1\t%0,%1
lhu%i1\t%0,%1"
[(set_attr "type" "no_delay_arith,load,no_delay_load")
(set_attr "mode" "SI,SI,SI")
(set_attr "length" "8,4,8")])
(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")))]
""
"@
andi\t%0,%1,0x00ff
lbu%i1\t%0,%1
lbu%i1\t%0,%1"
[(set_attr "type" "arith,load,no_delay_load")
(set_attr "mode" "HI")
(set_attr "length" "4,4,8")])
(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")))]
""
"@
andi\t%0,%1,0x00ff
lbu%i1\t%0,%1
lbu%i1\t%0,%1"
[(set_attr "type" "arith,load,no_delay_load")
(set_attr "mode" "SI,SI,SI")
(set_attr "length" "4,4,8")])
;;----------------------------------------------------------------
;; Sign extension
;;----------------------------------------------------------------
;; basic Sign Extend Operations
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(sign_extend:SI (match_operand:QI 1 "register_operand" "d")))]
""
"sext8\t%0,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=d")
(sign_extend:SI (match_operand:HI 1 "register_operand" "d")))]
""
"sext16\t%0,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
;; Those for integer source operand are ordered
;; widest source type first.
(define_insn "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=d,d,d")
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
""
{
if (which_alternative == 0)
output_asm_insn ("addk\t%D0,r0,%1", operands);
else
output_asm_insn ("lw%i1\t%D0,%1", operands);
output_asm_insn ("add\t%0,%D0,%D0", operands);
output_asm_insn ("addc\t%0,r0,r0", operands);
output_asm_insn ("beqi\t%0,.+8", operands);
return "addi\t%0,r0,0xffffffff";
}
[(set_attr "type" "multi,multi,multi")
(set_attr "mode" "DI")
(set_attr "length" "20,20,20")])
;;----------------------------------------------------------------
;; Data movement
;;----------------------------------------------------------------
;; 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 operands[1] is a constant address illegal for pic, then we need to
handle it just like microblaze_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);
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,d,R,m")
(match_operand:DI 1 "general_operand" " d,i,J,R,m,d,d"))]
""
{
switch (which_alternative)
{
case 0:
return "addk\t%0,%1\n\taddk\t%D0,%d1";
case 1:
return "addik\t%0,r0,%h1\n\taddik\t%D0,r0,%j1 #li => la";
case 2:
return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
case 3:
case 4:
if (reg_mentioned_p (operands[0], operands[1]))
return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
else
return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
case 5:
case 6:
return "swi\t%1,%0\n\tswi\t%D1,%o0";
}
return "unreachable";
}
[(set_attr "type" "no_delay_move,no_delay_arith,no_delay_arith,no_delay_load,no_delay_load,no_delay_store,no_delay_store")
(set_attr "mode" "DI")
(set_attr "length" "8,8,8,8,12,8,12")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"reload_completed
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& (REGNO(operands[0]) == (REGNO(operands[1]) + 1))"
[(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
"")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
(match_operand:DI 1 "register_operand" ""))]
"reload_completed
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
[(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
"")
;; 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 (microblaze_expand_move (SImode, operands)) DONE;
}
)
;; Added for status resgisters
(define_insn "movsi_status"
[(set (match_operand:SI 0 "register_operand" "=d,d,z")
(match_operand:SI 1 "register_operand" "z,d,d"))]
"interrupt_handler"
"@
mfs\t%0,%1 #mfs
addk\t%0,%1,r0 #add movsi
mts\t%0,%1 #mts"
[(set_attr "type" "move")
(set_attr "mode" "SI")
(set_attr "length" "12")])
;; This move will be not be moved to delay slot.
(define_insn "*movsi_internal3"
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d")
(match_operand:SI 1 "immediate_operand" "J,I,Mnis"))]
"(register_operand (operands[0], SImode) &&
(GET_CODE (operands[1]) == CONST_INT &&
(INTVAL (operands[1]) <= 32767 && INTVAL (operands[1]) >= -32768)))"
"@
addk\t%0,r0,r0
addik\t%0,r0,%1\t# %X1
addik\t%0,r0,%1\t# %X1"
[(set_attr "type" "arith,arith,no_delay_arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
;; This move may be used for PLT label operand
(define_insn "*movsi_internal5_pltop"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(match_operand:SI 1 "call_insn_operand" ""))]
"(register_operand (operands[0], Pmode) &&
PLT_ADDR_P (operands[1]))"
{
gcc_unreachable ();
}
[(set_attr "type" "load")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "*movsi_internal2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d, d,d,R, T")
(match_operand:SI 1 "move_operand" " d,I,Mnis,R,m,dJ,dJ"))]
"(register_operand (operands[0], SImode)
|| register_operand (operands[1], SImode)
|| (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))
&& (flag_pic != 2 || (GET_CODE (operands[1]) != SYMBOL_REF
&& GET_CODE (operands[1]) != LABEL_REF))"
"@
addk\t%0,%1,r0
addik\t%0,r0,%1\t# %X1
addik\t%0,%a1
lw%i1\t%0,%1
lw%i1\t%0,%1
sw%i0\t%z1,%0
sw%i0\t%z1,%0"
[(set_attr "type" "load,load,no_delay_load,load,no_delay_load,store,no_delay_store")
(set_attr "mode" "SI")
(set_attr "length" "4,4,8,4,8,4,8")])
;; 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;
}
}
)
(define_insn "*movhi_internal2"
[(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m")
(match_operand:HI 1 "general_operand" "I,d,R,m,dJ,dJ"))]
""
"@
addik\t%0,r0,%1\t# %X1
addk\t%0,%1,r0
lhui\t%0,%1
lhui\t%0,%1
sh%i0\t%z1,%0
sh%i0\t%z1,%0"
[(set_attr "type" "arith,move,load,no_delay_load,store,no_delay_store")
(set_attr "mode" "HI")
(set_attr "length" "4,4,4,8,8,8")])
;; 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;
}
}
)
(define_insn "*movqi_internal2"
[(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
(match_operand:QI 1 "general_operand" "J,I,d,R,m,dJ,dJ"))]
""
"@
addk\t%0,r0,%z1
addik\t%0,r0,%1\t# %X1
addk\t%0,%1,r0
lbu%i1\t%0,%1
lbu%i1\t%0,%1
sb%i0\t%z1,%0
sbi\t%z1,%0"
[(set_attr "type" "arith,arith,move,load,no_delay_load,store,no_delay_store")
(set_attr "mode" "QI")
(set_attr "length" "4,4,8,4,8,4,8")])
;; Block moves, see microblaze.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 "movmemsi"
[(parallel [(set (match_operand:BLK 0 "general_operand")
(match_operand:BLK 1 "general_operand"))
(use (match_operand:SI 2 ""))
(use (match_operand:SI 3 "const_int_operand"))])]
""
{
if (microblaze_expand_block_move (operands[0], operands[1],
operands[2], operands[3]))
DONE;
else
FAIL;
}
)
;; 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;
}
}
)
;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
;;
(define_insn "*movsf_internal"
[(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
(match_operand:SF 1 "general_operand" "G,d,R,F,m,d,d"))]
"(register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode)
|| operands[1] == CONST0_RTX (SFmode))"
"@
addk\t%0,r0,r0
addk\t%0,%1,r0
lw%i1\t%0,%1
addik\t%0,r0,%F1
lw%i1\t%0,%1
sw%i0\t%z1,%0
swi\t%z1,%0"
[(set_attr "type" "move,no_delay_load,load,no_delay_load,no_delay_load,store,no_delay_store")
(set_attr "mode" "SF")
(set_attr "length" "4,4,4,4,4,4,4")])
;; 64-bit floating point moves
(define_expand "movdf"
[(set (match_operand:DF 0 "nonimmediate_operand" "")
(match_operand:DF 1 "general_operand" ""))]
""
{
if (flag_pic == 2) {
if (GET_CODE (operands[1]) == MEM
&& !microblaze_legitimate_address_p (DFmode, XEXP (operands[1],0), 0))
{
rtx ptr_reg;
rtx result;
ptr_reg = force_reg (Pmode, XEXP (operands[1],0));
result = gen_rtx_MEM (DFmode, ptr_reg);
emit_move_insn (operands[0], result);
DONE;
}
}
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;
}
}
)
;; movdf_internal
;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
;;
(define_insn "*movdf_internal"
[(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,To")
(match_operand:DF 1 "general_operand" "dG,o,F,T,d"))]
""
{
switch (which_alternative)
{
case 0:
return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
case 1:
case 3:
if (reg_mentioned_p (operands[0], operands[1]))
return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
else
return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
case 2:
{
return "addik\t%0,r0,%h1 \n\taddik\t%D0,r0,%j1 #Xfer Lo";
}
case 4:
return "swi\t%1,%0\n\tswi\t%D1,%o0";
}
gcc_unreachable ();
}
[(set_attr "type" "no_delay_move,no_delay_load,no_delay_load,no_delay_load,no_delay_store")
(set_attr "mode" "DF")
(set_attr "length" "4,8,8,16,8")])
(define_split
[(set (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "register_operand" ""))]
"reload_completed
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& (REGNO (operands[0]) == (REGNO (operands[1]) + 1))"
[(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
"")
(define_split
[(set (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "register_operand" ""))]
"reload_completed
&& GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
&& GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
&& (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
[(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
"")
;;----------------------------------------------------------------
;; Shifts
;;----------------------------------------------------------------
;;----------------------------------------------------------------
;; 32-bit left shifts
;;----------------------------------------------------------------
(define_expand "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "")))]
""
{
/* Avoid recursion for trivial cases. */
if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
if (microblaze_expand_shift (operands))
DONE;
}
)
;; Irrespective of if we have a barrel-shifter or not, we want to match
;; shifts by 1 with a special pattern. When a barrel shifter is present,
;; saves a cycle. If not, allows us to annotate the instruction for delay
;; slot optimization
(define_insn "*ashlsi3_byone"
[(set (match_operand:SI 0 "register_operand" "=d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "I")))]
"(INTVAL (operands[2]) == 1)"
"addk\t%0,%1,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
;; Barrel shift left
(define_insn "ashlsi3_bshift"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(ashift:SI (match_operand:SI 1 "register_operand" "d,d")
(match_operand:SI 2 "arith_operand" "I,d")))]
"TARGET_BARREL_SHIFT"
"@
bslli\t%0,%1,%2
bsll\t%0,%1,%2"
[(set_attr "type" "bshift,bshift")
(set_attr "mode" "SI,SI")
(set_attr "length" "4,4")]
)
;; The following patterns apply when there is no barrel shifter present
(define_insn "*ashlsi3_with_mul_delay"
[(set (match_operand:SI 0 "register_operand" "=d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
"!TARGET_SOFT_MUL
&& ((1 << INTVAL (operands[2])) <= 32767 && (1 << INTVAL (operands[2])) >= -32768)"
"muli\t%0,%1,%m2"
;; This MUL will not generate an imm. Can go into a delay slot.
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
(define_insn "*ashlsi3_with_mul_nodelay"
[(set (match_operand:SI 0 "register_operand" "=d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
"!TARGET_SOFT_MUL"
"muli\t%0,%1,%m2"
;; This MUL will generate an IMM. Cannot go into a delay slot
[(set_attr "type" "no_delay_arith")
(set_attr "mode" "SI")
(set_attr "length" "8")]
)
(define_insn "*ashlsi3_with_size_opt"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
"(INTVAL (operands[2]) > 5 && optimize_size)"
{
operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
output_asm_insn ("ori\t%3,r0,%2", operands);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,%1,r0", operands);
output_asm_insn ("addik\t%3,%3,-1", operands);
output_asm_insn ("bneid\t%3,.-4", operands);
return "addk\t%0,%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "20")]
)
(define_insn "*ashlsi3_with_rotate"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
"(INTVAL (operands[2]) > 17 && !optimize_size)"
{
int i, nshift;
nshift = INTVAL (operands[2]);
operands[3] = gen_int_mode (0xFFFFFFFF << nshift, SImode);
/* We do one extra shift so that the first bit (carry) coming into the MSB
will be masked out */
output_asm_insn ("src\t%0,%1", operands);
for (i = 0; i < (32 - nshift); i++)
output_asm_insn ("src\t%0,%0", operands);
return "andi\t%0,%0,%3";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "80")]
)
(define_insn "*ashlsi_inline"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
""
{
int i;
int nshift = INTVAL (operands[2]);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,r0,%1", operands);
output_asm_insn ("addk\t%0,%1,%1", operands);
for (i = 0; i < (nshift - 2); i++)
output_asm_insn ("addk\t%0,%0,%0", operands);
return "addk\t%0,%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "124")]
)
(define_insn "*ashlsi_reg"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashift:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
""
{
operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
output_asm_insn ("andi\t%3,%2,31", operands);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,r0,%1", operands);
/* Exit the loop if zero shift. */
output_asm_insn ("beqid\t%3,.+20", operands);
/* Emit the loop. */
output_asm_insn ("addk\t%0,%0,r0", operands);
output_asm_insn ("addik\t%3,%3,-1", operands);
output_asm_insn ("bneid\t%3,.-4", operands);
return "addk\t%0,%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "28")]
)
;;----------------------------------------------------------------
;; 32-bit right shifts
;;----------------------------------------------------------------
(define_expand "ashrsi3"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "")))]
""
{
/* Avoid recursion for trivial cases. */
if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
if (microblaze_expand_shift (operands))
DONE;
}
)
;; Irrespective of if we have a barrel-shifter or not, we want to match
;; shifts by 1 with a special pattern. When a barrel shifter is present,
;; saves a cycle. If not, allows us to annotate the instruction for delay
;; slot optimization
(define_insn "*ashrsi3_byone"
[(set (match_operand:SI 0 "register_operand" "=d")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "I")))]
"(INTVAL (operands[2]) == 1)"
"sra\t%0,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
;; Barrel shift right logical
(define_insn "*ashrsi3_bshift"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
(match_operand:SI 2 "arith_operand" "I,d")))]
"TARGET_BARREL_SHIFT"
"@
bsrai\t%0,%1,%2
bsra\t%0,%1,%2"
[(set_attr "type" "bshift,bshift")
(set_attr "mode" "SI,SI")
(set_attr "length" "4,4")]
)
(define_insn "*ashrsi_inline"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
""
{
int i;
int nshift = INTVAL (operands[2]);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,r0,%1", operands);
output_asm_insn ("sra\t%0,%1", operands);
for (i = 0; i < (nshift - 2); i++)
output_asm_insn ("sra\t%0,%0", operands);
return "sra\t%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "124")]
)
(define_insn "*ashlri_reg"
[(set (match_operand:SI 0 "register_operand" "=&d")
(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
""
{
operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
output_asm_insn ("andi\t%3,%2,31", operands);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,r0,%1", operands);
/* Exit the loop if zero shift. */
output_asm_insn ("beqid\t%3,.+20", operands);
/* Emit the loop. */
output_asm_insn ("addk\t%0,%0,r0", operands);
output_asm_insn ("addik\t%3,%3,-1", operands);
output_asm_insn ("bneid\t%3,.-4", operands);
return "sra\t%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "28")]
)
;;----------------------------------------------------------------
;; 32-bit right shifts (logical)
;;----------------------------------------------------------------
(define_expand "lshrsi3"
[(set (match_operand:SI 0 "register_operand" "=&d")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "")))]
""
{
/* Avoid recursion for trivial cases. */
if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
if (microblaze_expand_shift (operands))
DONE;
}
)
;; Irrespective of if we have a barrel-shifter or not, we want to match
;; shifts by 1 with a special pattern. When a barrel shifter is present,
;; saves a cycle. If not, allows us to annotate the instruction for delay
;; slot optimization
(define_insn "*lshrsi3_byone"
[(set (match_operand:SI 0 "register_operand" "=d")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "arith_operand" "I")))]
"(INTVAL (operands[2]) == 1)"
"srl\t%0,%1"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
;; Barrel shift right logical
(define_insn "*lshrsi3_bshift"
[(set (match_operand:SI 0 "register_operand" "=d,d")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
(match_operand:SI 2 "arith_operand" "I,d")))]
"TARGET_BARREL_SHIFT"
"@
bsrli\t%0,%1,%2
bsrl\t%0,%1,%2"
[(set_attr "type" "bshift,bshift")
(set_attr "mode" "SI,SI")
(set_attr "length" "4,4")]
)
(define_insn "*lshrsi_inline"
[(set (match_operand:SI 0 "register_operand" "=&d")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "immediate_operand" "I")))]
""
{
int i;
int nshift = INTVAL (operands[2]);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,r0,%1", operands);
output_asm_insn ("srl\t%0,%1", operands);
for (i = 0; i < (nshift - 2); i++)
output_asm_insn ("srl\t%0,%0", operands);
return "srl\t%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "124")]
)
(define_insn "*lshlri_reg"
[(set (match_operand:SI 0 "register_operand" "=&d")
(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
""
{
operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
output_asm_insn ("andi\t%3,%2,31", operands);
if (REGNO (operands[0]) != REGNO (operands[1]))
output_asm_insn ("addk\t%0,r0,%1", operands);
/* Exit the loop if zero shift. */
output_asm_insn ("beqid\t%3,.+20", operands);
/* Emit the loop. */
output_asm_insn ("addk\t%0,%0,r0", operands);
output_asm_insn ("addik\t%3,%3,-1", operands);
output_asm_insn ("bneid\t%3,.-4", operands);
return "srl\t%0,%0";
}
[(set_attr "type" "multi")
(set_attr "mode" "SI")
(set_attr "length" "28")]
)
;;----------------------------------------------------------------
;; Setting a register from an integer comparison.
;;----------------------------------------------------------------
(define_expand "cstoresi4"
[(set (match_operand:SI 0 "register_operand")
(match_operator:SI 1 "ordered_comparison_operator"
[(match_operand:SI 2 "register_operand")
(match_operand:SI 3 "register_operand")]))]
"TARGET_PATTERN_COMPARE"
"if (GET_CODE (operand1) != EQ && GET_CODE (operand1) != NE)
FAIL;
"
)
(define_insn "seq_internal_pat"
[(set (match_operand:SI 0 "register_operand" "=d")
(eq:SI
(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
"TARGET_PATTERN_COMPARE"
"pcmpeq\t%0,%1,%2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
(define_insn "sne_internal_pat"
[(set (match_operand:SI 0 "register_operand" "=d")
(ne:SI
(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")))]
"TARGET_PATTERN_COMPARE"
"pcmpne\t%0,%1,%2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")]
)
(define_insn "signed_compare"
[(set (match_operand:SI 0 "register_operand" "=d")
(unspec
[(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")] UNSPEC_CMP))]
""
"cmp\t%0,%1,%2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
(define_insn "unsigned_compare"
[(set (match_operand:SI 0 "register_operand" "=d")
(unspec
[(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")] UNSPEC_CMPU))]
""
"cmpu\t%0,%1,%2"
[(set_attr "type" "arith")
(set_attr "mode" "SI")
(set_attr "length" "4")])
;;----------------------------------------------------------------
;; Setting a register from an floating point comparison.
;;----------------------------------------------------------------
(define_insn "cstoresf4"
[(set (match_operand:SI 0 "register_operand")
(match_operator:SI 1 "ordered_comparison_operator"
[(match_operand:SF 2 "register_operand")
(match_operand:SF 3 "register_operand")]))]
"TARGET_HARD_FLOAT"
"fcmp.%C1\t%0,%3,%2"
[(set_attr "type" "fcmp")
(set_attr "mode" "SF")
(set_attr "length" "4")]
)
;;----------------------------------------------------------------
;; Conditional branches
;;----------------------------------------------------------------
(define_expand "cbranchsi4"
[(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator"
[(match_operand:SI 1 "register_operand")
(match_operand:SI 2 "arith_operand")])
(label_ref (match_operand 3 ""))
(pc)))]
""
{
microblaze_expand_conditional_branch (SImode, operands);
DONE;
})
(define_expand "cbranchsf4"
[(set (pc)
(if_then_else (match_operator:SI 0 "ordered_comparison_operator"
[(match_operand:SF 1 "register_operand")
(match_operand:SF 2 "register_operand")])
(label_ref (match_operand 3 ""))
(pc)))]
"TARGET_HARD_FLOAT"
{
microblaze_expand_conditional_branch_sf (operands);
DONE;
})
;; Used to implement comparison instructions
(define_expand "condjump"
[(set (pc)
(if_then_else (match_operand 0)
(label_ref (match_operand 1))
(pc)))])
(define_insn "branch_zero"
[(set (pc)
(if_then_else (match_operator:SI 0 "ordered_comparison_operator"
[(match_operand:SI 1 "register_operand" "d")
(const_int 0)])
(match_operand:SI 2 "pc_or_label_operand" "")
(match_operand:SI 3 "pc_or_label_operand" "")))
]
""
{
if (operands[3] == pc_rtx)
return "b%C0i%?\t%z1,%2";
else
return "b%N0i%?\t%z1,%3";
}
[(set_attr "type" "branch")
(set_attr "mode" "none")
(set_attr "length" "4")]
)
;;----------------------------------------------------------------
;; Unconditional branches
;;----------------------------------------------------------------
(define_insn "jump"
[(set (pc)
(label_ref (match_operand 0 "" "")))]
""
{
if (GET_CODE (operands[0]) == REG)
return "br%?\t%0";
else
return "bri%?\t%l0";
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "4")])
(define_expand "indirect_jump"
[(set (pc) (match_operand 0 "register_operand" "d"))]
""
{
rtx dest = operands[0];
if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode)
operands[0] = copy_to_mode_reg (Pmode, dest);
emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
DONE;
}
)
;; Indirect jumps. Jump to register values. Assuming absolute jumps
(define_insn "indirect_jump_internal1"
[(set (pc) (match_operand:SI 0 "register_operand" "d"))]
""
"bra%?\t%0"
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "4")])
(define_expand "tablejump"
[(set (pc)
(match_operand 0 "register_operand" "d"))
(use (label_ref (match_operand 1 "" "")))]
""
{
gcc_assert (GET_MODE (operands[0]) == Pmode);
if (!flag_pic)
emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
else
emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
DONE;
}
)
(define_insn "tablejump_internal1"
[(set (pc)
(match_operand:SI 0 "register_operand" "d"))
(use (label_ref (match_operand 1 "" "")))]
""
"bra%?\t%0 "
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "4")])
(define_expand "tablejump_internal3"
[(parallel [(set (pc)
(plus:SI (match_operand:SI 0 "register_operand" "d")
(label_ref:SI (match_operand:SI 1 "" ""))))
(use (label_ref:SI (match_dup 1)))])]
""
""
)
;; need to change for MicroBlaze PIC
(define_insn ""
[(set (pc)
(plus:SI (match_operand:SI 0 "register_operand" "d")
(label_ref:SI (match_operand 1 "" ""))))
(use (label_ref:SI (match_dup 1)))]
"next_active_insn (insn) != 0
&& GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
&& PREV_INSN (next_active_insn (insn)) == operands[1]
&& flag_pic"
{
output_asm_insn ("addk\t%0,%0,r20",operands);
return "bra%?\t%0";
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "4")])
(define_expand "tablejump_internal4"
[(parallel [(set (pc)
(plus:DI (match_operand:DI 0 "register_operand" "d")
(label_ref:DI (match_operand:SI 1 "" ""))))
(use (label_ref:DI (match_dup 1)))])]
""
""
)
;;----------------------------------------------------------------
;; Function prologue/epilogue and stack allocation
;;----------------------------------------------------------------
(define_expand "prologue"
[(const_int 1)]
""
{
microblaze_expand_prologue ();
DONE;
}
)
(define_expand "epilogue"
[(use (const_int 0))]
""
{
microblaze_expand_epilogue ();
DONE;
}
)
;; An insn to allocate new stack space for dynamic use (e.g., alloca).
;; We copy the return address, decrement the stack pointer and save the
;; return address again at the new stack top
(define_expand "allocate_stack"
[(set (match_operand 0 "register_operand" "=r")
(minus (reg 1) (match_operand 1 "register_operand" "")))
(set (reg 1)
(minus (reg 1) (match_dup 1)))]
""
{
rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
rtx rtmp = gen_rtx_REG (SImode, R_TMP);
rtx neg_op0;
emit_move_insn (rtmp, retaddr);
if (GET_CODE (operands[1]) != CONST_INT)
{
neg_op0 = gen_reg_rtx (Pmode);
emit_insn (gen_negsi2 (neg_op0, operands[1]));
} else
neg_op0 = GEN_INT (- INTVAL (operands[1]));
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), rtmp);
emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
emit_insn (gen_rtx_CLOBBER (SImode, rtmp));
DONE;
}
)
;; Trivial return. Make it look like a normal return insn as that
;; allows jump optimizations to work better .
(define_expand "return"
[(simple_return)]
"microblaze_can_use_return_insn ()"
{}
)
(define_expand "simple_return"
[(simple_return)]
""
{}
)
(define_insn "*<optab>"
[(any_return)]
""
{
if (microblaze_is_interrupt_handler ())
return "rtid\tr14, 0\;%#";
else
return "rtsd\tr15, 8\;%#";
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "4")]
)
;; Normal return.
(define_insn "<optab>_internal"
[(any_return)
(use (match_operand:SI 0 "register_operand" ""))]
""
{
if (microblaze_is_interrupt_handler ())
return "rtid\tr14,0 \;%#";
else
return "rtsd\tr15,8 \;%#";
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set_attr "length" "4")])
;; Block any insns from across this point
;; Useful to group sequences together.
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 0)]
""
""
[(set_attr "type" "unknown")
(set_attr "mode" "none")
(set_attr "length" "0")])
;;----------------------------------------------------------------
;; Function calls
;;----------------------------------------------------------------
(define_expand "call"
[(parallel [(call (match_operand 0 "memory_operand" "m")
(match_operand 1 "" "i"))
(clobber (reg:SI R_SR))
(use (match_operand 2 "" ""))
(use (match_operand 3 "" ""))])]
""
{
rtx addr = XEXP (operands[0], 0);
if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
&& !SYMBOL_REF_LOCAL_P (addr))
{
rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
XEXP (operands[0], 0) = temp;
}
if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
|| !call_insn_operand (addr, VOIDmode))
XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
if (GET_CODE (XEXP (operands[0], 0)) == UNSPEC)
emit_call_insn (gen_call_internal_plt0 (operands[0], operands[1],
gen_rtx_REG (SImode,
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
pic_offset_table_rtx));
else
emit_call_insn (gen_call_internal0 (operands[0], operands[1],
gen_rtx_REG (SImode,
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
DONE;
}
)
(define_expand "call_internal0"
[(parallel [(call (match_operand 0 "" "")
(match_operand 1 "" ""))
(clobber (match_operand:SI 2 "" ""))])]
""
{
}
)
(define_expand "call_internal_plt0"
[(parallel [(call (match_operand 0 "" "")
(match_operand 1 "" ""))
(clobber (match_operand:SI 2 "" ""))
(use (match_operand:SI 3 "" ""))])]
""
{
}
)
(define_insn "call_internal_plt"
[(call (mem (match_operand:SI 0 "call_insn_plt_operand" ""))
(match_operand:SI 1 "" "i"))
(clobber (reg:SI R_SR))
(use (reg:SI R_GOT))]
"flag_pic"
{
register rtx target2 = gen_rtx_REG (Pmode,
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
gen_rtx_CLOBBER (VOIDmode, target2);
return "brlid\tr15,%0\;%#";
}
[(set_attr "type" "call")
(set_attr "mode" "none")
(set_attr "length" "4")])
(define_insn "call_internal1"
[(call (mem (match_operand:SI 0 "call_insn_operand" "ri"))
(match_operand:SI 1 "" "i"))
(clobber (reg:SI R_SR))]
""
{
register rtx target = operands[0];
register rtx target2 = gen_rtx_REG (Pmode,
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
if (GET_CODE (target) == SYMBOL_REF) {
gen_rtx_CLOBBER (VOIDmode, target2);
return "brlid\tr15,%0\;%#";
} else if (GET_CODE (target) == CONST_INT)
return "la\t%@,r0,%0\;brald\tr15,%@\;%#";
else if (GET_CODE (target) == REG)
return "brald\tr15,%0\;%#";
else {
fprintf (stderr,"Unsupported call insn\n");
return NULL;
}
}
[(set_attr "type" "call")
(set_attr "mode" "none")
(set_attr "length" "4")])
;; calls.c now passes a fourth argument, make saber happy
(define_expand "call_value"
[(parallel [(set (match_operand 0 "register_operand" "=d")
(call (match_operand 1 "memory_operand" "m")
(match_operand 2 "" "i")))
(clobber (reg:SI R_SR))
(use (match_operand 3 "" ""))])] ;; next_arg_reg
""
{
rtx addr = XEXP (operands[1], 0);
if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
&& !SYMBOL_REF_LOCAL_P (addr))
{
rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
XEXP (operands[1], 0) = temp;
}
if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
|| !call_insn_operand (addr, VOIDmode))
XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
if (GET_CODE (XEXP (operands[1], 0)) == UNSPEC)
emit_call_insn (gen_call_value_intern_plt0 (operands[0], operands[1],
operands[2],
gen_rtx_REG (SImode,
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
pic_offset_table_rtx));
else
emit_call_insn (gen_call_value_internal (operands[0], operands[1],
operands[2],
gen_rtx_REG (SImode,
GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
DONE;
}
)
(define_expand "call_value_internal"
[(parallel [(set (match_operand 0 "" "")
(call (match_operand 1 "" "")
(match_operand 2 "" "")))
(clobber (match_operand:SI 3 "" ""))
])]
""
{}
)
(define_expand "call_value_intern_plt0"
[(parallel[(set (match_operand 0 "" "")
(call (match_operand 1 "" "")
(match_operand 2 "" "")))
(clobber (match_operand:SI 3 "" ""))
(use (match_operand:SI 4 "" ""))])]
"flag_pic"
{}
)
(define_insn "call_value_intern_plt"
[(set (match_operand:VOID 0 "register_operand" "=d")
(call (mem (match_operand:SI 1 "call_insn_plt_operand" ""))
(match_operand:SI 2 "" "i")))
(clobber (match_operand:SI 3 "register_operand" "=d"))
(use (match_operand:SI 4 "register_operand"))]
"flag_pic"
{
register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
gen_rtx_CLOBBER (VOIDmode,target2);
return "brlid\tr15,%1\;%#";
}
[(set_attr "type" "call")
(set_attr "mode" "none")
(set_attr "length" "4")])
(define_insn "call_value_intern"
[(set (match_operand:VOID 0 "register_operand" "=d")
(call (mem (match_operand:VOID 1 "call_insn_operand" "ri"))
(match_operand:SI 2 "" "i")))
(clobber (match_operand:SI 3 "register_operand" "=d"))]
""
{
register rtx target = operands[1];
register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
if (GET_CODE (target) == SYMBOL_REF){
gen_rtx_CLOBBER (VOIDmode,target2);
return "brlid\tr15,%1\;%#";
}
else if (GET_CODE (target) == CONST_INT)
return "la\t%@,r0,%1\;brald\tr15,%@\;%#";
else if (GET_CODE (target) == REG)
return "brald\tr15,%1\;%#";
else
return "Unsupported call insn\n";
}
[(set_attr "type" "call")
(set_attr "mode" "none")
(set_attr "length" "4")])
;; 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" "4")])
;; The insn to set GOT. The hardcoded number "8" accounts for $pc difference
;; between "mfs" and "addik" instructions.
(define_insn "set_got"
[(set (match_operand:SI 0 "register_operand" "=r")
(unspec:SI [(const_int 0)] UNSPEC_SET_GOT))]
""
"mfs\t%0,rpc\n\taddik\t%0,%0,_GLOBAL_OFFSET_TABLE_+8"
[(set_attr "type" "multi")
(set_attr "length" "12")])