aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/config/microblaze/microblaze.md
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/config/microblaze/microblaze.md
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/config/microblaze/microblaze.md')
-rw-r--r--gcc-4.9/gcc/config/microblaze/microblaze.md2264
1 files changed, 2264 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/config/microblaze/microblaze.md b/gcc-4.9/gcc/config/microblaze/microblaze.md
new file mode 100644
index 000000000..815d6b5d7
--- /dev/null
+++ b/gcc-4.9/gcc/config/microblaze/microblaze.md
@@ -0,0 +1,2264 @@
+;; microblaze.md -- Machine description for Xilinx MicroBlaze processors.
+;; Copyright (C) 2009-2014 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
+ (UNSPEC_TLS 106) ;; jump table
+])
+
+
+;;----------------------------------------------------
+;; 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,trap"
+ (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")
+
+(define_insn "bswapsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
+ "TARGET_REORDER"
+ "swapb %0, %1"
+)
+
+(define_insn "bswaphi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
+ "TARGET_REORDER"
+ "swapb %0, %1
+ swaph %0, %0"
+)
+
+;;----------------------------------------------------------------
+;; 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_plus_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 "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 "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")])
+
+;;----------------------------------------------------------------
+;; 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%L0,r0,%1", operands);
+ else
+ output_asm_insn ("lw%i1\t%L0,%1", operands);
+
+ output_asm_insn ("add\t%M0,%L0,%L0", operands);
+ output_asm_insn ("addc\t%M0,r0,r0", operands);
+ output_asm_insn ("beqi\t%M0,.+8", operands);
+ return "addi\t%M0,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,o")
+ (match_operand:DI 1 "general_operand" " d,i,J,R,o,d,d"))]
+ ""
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return "addk\t%0,%1\n\taddk\t%D0,%d1";
+ case 1:
+ return "addik\t%M0,r0,%h1\n\taddik\t%L0,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 registers
+(define_insn "movsi_status"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,z")
+ (match_operand:SI 1 "register_operand" "z,d,d"))]
+ "microblaze_is_interrupt_variant ()"
+ "@
+ 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,m")
+ (match_operand:SI 1 "move_src_operand" " d,I,Mnis,R,m,dJ,dJ"))]
+ ""
+ "@
+ 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;
+ }
+)
+
+;;Load and store reverse
+(define_insn "movsi4_rev"
+ [(set (match_operand:SI 0 "reg_or_mem_operand" "=r,Q")
+ (bswap:SI (match_operand:SF 1 "reg_or_mem_operand" "Q,r")))]
+ "TARGET_REORDER"
+ "@
+ lwr\t%0,%y1,r0
+ swr\t%1,%y0,r0"
+ [(set_attr "type" "load,store")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4,4")])
+
+;; 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,o")
+ (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 "*ashrsi_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 "*lshrsi_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")]
+)
+
+;;----------------------------------------------------------------
+;; Setting a register from an floating point comparison.
+;;----------------------------------------------------------------
+(define_insn "cstoresf4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")]))]
+ "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 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")]
+)
+
+(define_insn "branch_compare"
+ [(set (pc)
+ (if_then_else (match_operator:SI 0 "cmp_op"
+ [(match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")
+ ])
+ (label_ref (match_operand 3))
+ (pc)))
+ (clobber(reg:SI R_TMP))]
+ ""
+ {
+ operands[4] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
+ enum rtx_code code = GET_CODE (operands[0]);
+
+ if (code == GT || code == LE)
+ {
+ output_asm_insn ("cmp\tr18,%z1,%z2", operands);
+ code = swap_condition (code);
+ }
+ else if (code == GTU || code == LEU)
+ {
+ output_asm_insn ("cmpu\tr18,%z1,%z2", operands);
+ code = swap_condition (code);
+ }
+ else if (code == GE || code == LT)
+ {
+ output_asm_insn ("cmp\tr18,%z2,%z1", operands);
+ }
+ else if (code == GEU || code == LTU)
+ {
+ output_asm_insn ("cmpu\tr18,%z2,%z1", operands);
+ }
+
+ operands[0] = gen_rtx_fmt_ee (signed_condition (code), SImode, operands[4], const0_rtx);
+ return "b%C0i%?\tr18,%3";
+ }
+ [(set_attr "type" "branch")
+ (set_attr "mode" "none")
+ (set_attr "length" "12")]
+)
+
+;;----------------------------------------------------------------
+;; 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_INSN (operands[1]) != 0
+ && GET_CODE (PATTERN (NEXT_INSN (operands[1]))) == ADDR_DIFF_VEC
+ && 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;
+ }
+)
+
+(define_expand "save_stack_block"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")]
+ ""
+ {
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+ }
+)
+
+(define_expand "restore_stack_block"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")]
+ ""
+ {
+ rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
+ rtx rtmp = gen_rtx_REG (SImode, R_TMP);
+
+ /* Move the retaddr. */
+ emit_move_insn (rtmp, retaddr);
+ emit_move_insn (operands[0], operands[1]);
+ emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), 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_variant ())
+ 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_variant ())
+ 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_simple_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);
+ if (SYMBOL_REF_FLAGS (target) & SYMBOL_FLAG_FUNCTION)
+ {
+ return "brlid\tr15,%1\;%#";
+ }
+ else
+ {
+ return "bralid\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")])
+
+;; Trap instruction pattern for __builtin_trap. Same as the glibc ABORT_INSTRUCTION
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 0))]
+ ""
+ "brki\tr0,-1"
+ [(set_attr "type" "trap")]
+)
+
+;; 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")])
+
+;; This insn gives the count of leading number of zeros for the second
+;; operand and stores the result in first operand.
+(define_insn "clzsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (clz:SI (match_operand:SI 1 "register_operand" "r")))]
+ "TARGET_HAS_CLZ"
+ "clz\t%0,%1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(include "sync.md")