xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/microblaze/microblaze.md (revision fc4f42693f9b1c31f39f9cf50af1bf2010325808)
1;; microblaze.md -- Machine description for Xilinx MicroBlaze processors.
2;; Copyright (C) 2009-2015 Free Software Foundation, Inc.
3
4;; Contributed by Michael Eager <eager@eagercon.com>.
5
6;; This file is part of GCC.
7
8;; GCC is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 3, or (at your option)
11;; any later version.
12
13;; GCC is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with GCC; see the file COPYING3.  If not see
20;; <http://www.gnu.org/licenses/>.  */
21
22(include "constraints.md")
23(include "predicates.md")
24
25;;----------------------------------------------------
26;; Constants
27;;----------------------------------------------------
28(define_constants [
29  (R_SP        1)       ;; Stack pointer reg
30  (R_SR       15)       ;; Sub-routine return addr reg
31  (R_IR       14)       ;; Interrupt return addr reg
32  (R_DR       16)       ;; Debug trap return addr reg
33  (R_ER       17)       ;; Exception return addr reg
34  (R_TMP      18)       ;; Assembler temporary reg
35  (R_GOT      20)       ;; GOT ptr reg
36  (MB_PIPE_3   0)       ;; Microblaze 3-stage pipeline
37  (MB_PIPE_5   1)       ;; Microblaze 5-stage pipeline
38  (UNSPEC_SET_GOT       101)    ;;
39  (UNSPEC_GOTOFF        102)    ;; GOT offset
40  (UNSPEC_PLT           103)    ;; jump table
41  (UNSPEC_CMP		104)    ;; signed compare
42  (UNSPEC_CMPU		105)    ;; unsigned compare
43  (UNSPEC_TLS           106)    ;; jump table
44])
45
46
47;;----------------------------------------------------
48;; Instruction Attributes
49;;----------------------------------------------------
50
51;; Classification of each insn.
52;; branch	conditional branch
53;; jump		unconditional jump
54;; call		unconditional call
55;; load		load instruction(s)
56;; store	store instruction(s)
57;; move		data movement within same register set
58;; arith	integer arithmetic instruction
59;; darith	double precision integer arithmetic instructions
60;; imul		integer multiply
61;; idiv		integer divide
62;; icmp		integer compare
63;; Xfadd		floating point add/subtract
64;; Xfmul		floating point multiply
65;; Xfmadd	floating point multiply-add
66;; Xfdiv		floating point divide
67;; Xfabs		floating point absolute value
68;; Xfneg		floating point negation
69;; Xfcmp		floating point compare
70;; Xfcvt		floating point convert
71;; Xfsqrt	floating point square root
72;; multi	multiword sequence (or user asm statements)
73;; nop		no operation
74;; bshift 	Shift operations
75
76(define_attr "type"
77  "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"
78  (const_string "unknown"))
79
80;; Main data type used by the insn
81(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF" (const_string "unknown"))
82
83;; # instructions (4 bytes each)
84(define_attr "length" "" (const_int 4))
85
86(define_code_iterator any_return [return simple_return])
87
88;; <optab> expands to the name of the optab for a particular code.
89(define_code_attr optab [(return "return")
90			 (simple_return "simple_return")])
91
92
93;;----------------------------------------------------
94;; Attribute describing the processor.
95;;----------------------------------------------------
96
97;; Describe a user's asm statement.
98(define_asm_attributes
99  [(set_attr "type" "multi")])
100
101;; whether or not generating calls to position independent functions
102(define_attr "abicalls" "no,yes"
103  (const (symbol_ref "microblaze_abicalls_attr")))
104
105;;----------------------------------------------------------------
106;; Microblaze DFA Pipeline description
107;;----------------------------------------------------------------
108
109;;-----------------------------------------------------------------
110/*
111   This is description of pipeline hazards based on DFA.  The
112   following constructions can be used for this:
113
114   o define_cpu_unit string [string]) describes a cpu functional unit
115     (separated by comma).
116
117     1st operand: Names of cpu function units.
118     2nd operand: Name of automaton (see comments for
119     DEFINE_AUTOMATON).
120
121     All define_reservations and define_cpu_units should have unique
122     names which can not be "nothing".
123
124   o (exclusion_set string string) means that each CPU function unit
125     in the first string can not be reserved simultaneously with each
126     unit whose name is in the second string and vise versa.  CPU
127     units in the string are separated by commas. For example, it is
128     useful for description CPU with fully pipelined floating point
129     functional unit which can execute simultaneously only single
130     floating point insns or only double floating point insns.
131
132   o (presence_set string string) means that each CPU function unit in
133     the first string can not be reserved unless at least one of units
134     whose names are in the second string is reserved.  This is an
135     asymmetric relation.  CPU units in the string are separated by
136     commas.  For example, it is useful for description that slot1 is
137     reserved after slot0 reservation for a VLIW processor.
138
139   o (absence_set string string) means that each CPU function unit in
140     the first string can not be reserved only if each unit whose name
141     is in the second string is not reserved.  This is an asymmetric
142     relation (actually exclusion set is analogous to this one but it
143     is symmetric).  CPU units in the string are separated by commas.
144     For example, it is useful for description that slot0 can not be
145     reserved after slot1 or slot2 reservation for a VLIW processor.
146
147   o (define_bypass number out_insn_names in_insn_names) names bypass with
148     given latency (the first number) from insns given by the first
149     string (see define_insn_reservation) into insns given by the
150     second string.  Insn names in the strings are separated by
151     commas.
152
153   o (define_automaton string) describes names of an automaton
154     generated and used for pipeline hazards recognition.  The names
155     are separated by comma.  Actually it is possibly to generate the
156     single automaton but unfortunately it can be very large.  If we
157     use more one automata, the summary size of the automata usually
158     is less than the single one.  The automaton name is used in
159     define_cpu_unit.  All automata should have unique names.
160
161   o (define_reservation string string) names reservation (the first
162     string) of cpu functional units (the 2nd string).  Sometimes unit
163     reservations for different insns contain common parts.  In such
164     case, you describe common part and use one its name (the 1st
165     parameter) in regular expression in define_insn_reservation.  All
166     define_reservations, define results and define_cpu_units should
167     have unique names which can not be "nothing".
168
169   o (define_insn_reservation name default_latency condition regexpr)
170     describes reservation of cpu functional units (the 3nd operand)
171     for instruction which is selected by the condition (the 2nd
172     parameter).  The first parameter is used for output of debugging
173     information.  The reservations are described by a regular
174     expression according the following syntax:
175
176       regexp = regexp "," oneof
177              | oneof
178
179       oneof = oneof "|" allof
180             | allof
181
182       allof = allof "+" repeat
183             | repeat
184
185       repeat = element "*" number
186              | element
187
188       element = cpu_function_name
189               | reservation_name
190               | result_name
191               | "nothing"
192               | "(" regexp ")"
193
194       1. "," is used for describing start of the next cycle in
195          reservation.
196
197       2. "|" is used for describing the reservation described by the
198          first regular expression *or* the reservation described by
199          the second regular expression *or* etc.
200
201       3. "+" is used for describing the reservation described by the
202          first regular expression *and* the reservation described by
203          the second regular expression *and* etc.
204
205       4. "*" is used for convenience and simply means sequence in
206          which the regular expression are repeated NUMBER times with
207          cycle advancing (see ",").
208
209       5. cpu function unit name which means reservation.
210
211       6. reservation name -- see define_reservation.
212
213       7. string "nothing" means no units reservation.
214
215*/
216;;-----------------------------------------------------------------
217
218
219;;----------------------------------------------------------------
220;; Microblaze 5-stage pipeline description (v5.00.a and later)
221;;----------------------------------------------------------------
222
223(define_automaton   "mbpipe_5")
224(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")
225
226(define_insn_reservation "mb-integer" 1
227  (and (eq_attr "type" "branch,jump,call,arith,darith,icmp,nop,no_delay_arith")
228       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
229  "mb_issue,mb_iu,mb_wb")
230
231(define_insn_reservation "mb-special-move" 2
232  (and (eq_attr "type" "move")
233       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
234  "mb_issue,mb_iu*2,mb_wb")
235
236(define_insn_reservation "mb-mem-load" 3
237  (and (eq_attr "type" "load,no_delay_load")
238       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
239  "mb_issue,mb_iu,mb_wb")
240
241(define_insn_reservation "mb-mem-store" 1
242  (and (eq_attr "type" "store,no_delay_store")
243       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
244  "mb_issue,mb_iu,mb_wb")
245
246(define_insn_reservation "mb-mul" 3
247  (and (eq_attr "type" "imul,no_delay_imul")
248       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
249  "mb_issue,mb_mul,mb_mul_2*2,mb_wb")
250
251(define_insn_reservation "mb-div" 34
252  (and (eq_attr "type" "idiv")
253       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
254    "mb_issue,mb_div,mb_div_2*33,mb_wb")
255
256(define_insn_reservation "mb-bs" 2
257  (and (eq_attr "type" "bshift")
258       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
259   "mb_issue,mb_bs,mb_bs_2,mb_wb")
260
261(define_insn_reservation "mb-fpu-add-sub-mul" 6
262  (and (eq_attr "type" "fadd,frsub,fmul")
263       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
264  "mb_issue,mb_fpu,mb_fpu_2*5,mb_wb")
265
266(define_insn_reservation "mb-fpu-fcmp" 3
267  (and (eq_attr "type" "fcmp")
268       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
269  "mb_issue,mb_fpu,mb_fpu*2,mb_wb")
270
271(define_insn_reservation "mb-fpu-div" 30
272  (and (eq_attr "type" "fdiv")
273       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
274  "mb_issue,mb_fpu,mb_fpu_2*29,mb_wb")
275
276(define_insn_reservation "mb-fpu-sqrt" 30
277  (and (eq_attr "type" "fsqrt")
278       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
279  "mb_issue,mb_fpu,mb_fpu_2*29,mb_wb")
280
281(define_insn_reservation "mb-fpu-fcvt" 4
282  (and (eq_attr "type" "fcvt")
283       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_5)))
284  "mb_issue,mb_fpu,mb_fpu_2*3,mb_wb")
285
286;;----------------------------------------------------------------
287;; Microblaze 3-stage pipeline description (for v4.00.a and earlier)
288;;----------------------------------------------------------------
289
290(define_automaton   "mbpipe_3")
291(define_cpu_unit    "mb3_iu" "mbpipe_3")
292
293(define_insn_reservation "mb3-integer" 1
294  (and (eq_attr "type" "branch,jump,call,arith,darith,icmp,nop,no_delay_arith")
295       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
296  "mb3_iu")
297
298(define_insn_reservation "mb3-special-move" 2
299  (and (eq_attr "type" "move")
300       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
301  "mb3_iu*2")
302
303(define_insn_reservation "mb3-mem-load" 2
304  (and (eq_attr "type" "load,no_delay_load")
305       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
306  "mb3_iu")
307
308(define_insn_reservation "mb3-mem-store" 1
309  (and (eq_attr "type" "store,no_delay_store")
310       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
311  "mb3_iu")
312
313(define_insn_reservation "mb3-mul" 3
314  (and (eq_attr "type" "imul,no_delay_imul")
315       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
316  "mb3_iu")
317
318(define_insn_reservation "mb3-div" 34
319  (and (eq_attr "type" "idiv")
320       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
321    "mb3_iu")
322
323(define_insn_reservation "mb3-bs" 2
324  (and (eq_attr "type" "bshift")
325       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
326   "mb3_iu")
327
328(define_insn_reservation "mb3-fpu-add-sub-mul" 6
329  (and (eq_attr "type" "fadd,frsub,fmul")
330       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
331  "mb3_iu")
332
333(define_insn_reservation "mb3-fpu-fcmp" 3
334  (and (eq_attr "type" "fcmp")
335       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
336  "mb3_iu")
337
338(define_insn_reservation "mb3-fpu-div" 30
339  (and (eq_attr "type" "fdiv")
340       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
341  "mb3_iu")
342
343(define_insn_reservation "mb3-fpu-sqrt" 30
344  (and (eq_attr "type" "fsqrt")
345       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
346  "mb3_iu")
347
348(define_insn_reservation "mb3-fpu-fcvt" 4
349  (and (eq_attr "type" "fcvt")
350       (eq (symbol_ref  "microblaze_pipe") (const_int MB_PIPE_3)))
351  "mb3_iu")
352
353(automata_option "v")
354(automata_option "time")
355(automata_option "progress")
356
357(define_insn "bswapsi2"
358  [(set (match_operand:SI 0 "register_operand" "=r")
359        (bswap:SI (match_operand:SI 1 "register_operand" "r")))]
360  "TARGET_REORDER"
361  "swapb %0, %1"
362)
363
364(define_insn "bswaphi2"
365  [(set (match_operand:HI 0 "register_operand" "=r")
366        (bswap:HI (match_operand:HI 1 "register_operand" "r")))]
367  "TARGET_REORDER"
368  "swapb %0, %1
369   swaph %0, %0"
370)
371
372;;----------------------------------------------------------------
373;; Microblaze delay slot description
374;;----------------------------------------------------------------
375(define_delay (eq_attr "type" "branch,call,jump")
376  [(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")
377        (ior (not (match_test "microblaze_no_unsafe_delay"))
378             (eq_attr "type" "!fadd,frsub,fmul,fdiv,fcmp,store,load")
379             ))
380  (nil) (nil)])
381
382
383;;----------------------------------------------------------------
384;; Microblaze FPU
385;;----------------------------------------------------------------
386
387(define_insn "addsf3"
388  [(set (match_operand:SF 0 "register_operand" "=d")
389        (plus:SF (match_operand:SF 1 "register_operand" "d")
390                 (match_operand:SF 2 "register_operand" "d")))]
391  "TARGET_HARD_FLOAT"
392  "fadd\t%0,%1,%2"
393  [(set_attr "type"     "fadd")
394  (set_attr "mode"      "SF")
395  (set_attr "length"    "4")])
396
397(define_insn "subsf3"
398  [(set (match_operand:SF 0 "register_operand" "=d")
399        (minus:SF (match_operand:SF 1 "register_operand" "d")
400                  (match_operand:SF 2 "register_operand" "d")))]
401  "TARGET_HARD_FLOAT"
402  "frsub\t%0,%2,%1"
403  [(set_attr "type"     "frsub")
404  (set_attr "mode"      "SF")
405  (set_attr "length"    "4")])
406
407(define_insn "mulsf3"
408  [(set (match_operand:SF 0 "register_operand" "=d")
409        (mult:SF (match_operand:SF 1 "register_operand" "d")
410                 (match_operand:SF 2 "register_operand" "d")))]
411  "TARGET_HARD_FLOAT"
412  "fmul\t%0,%1,%2"
413  [(set_attr "type"     "fmul")
414  (set_attr "mode"      "SF")
415  (set_attr "length"    "4")])
416
417
418(define_insn "divsf3"
419  [(set (match_operand:SF 0 "register_operand" "=d")
420        (div:SF (match_operand:SF 1 "register_operand" "d")
421                (match_operand:SF 2 "register_operand" "d")))]
422  "TARGET_HARD_FLOAT"
423  "fdiv\t%0,%2,%1"
424  [(set_attr "type"     "fdiv")
425  (set_attr "mode"      "SF")
426  (set_attr "length"    "4")])
427
428(define_insn "sqrtsf2"
429  [(set (match_operand:SF 0 "register_operand" "=d")
430        (sqrt:SF (match_operand:SF 1 "register_operand" "d")))]
431  "TARGET_HARD_FLOAT && TARGET_FLOAT_SQRT"
432  "fsqrt\t%0,%1"
433  [(set_attr "type"     "fsqrt")
434  (set_attr "mode"      "SF")
435  (set_attr "length"    "4")])
436
437(define_insn "floatsisf2"
438  [(set (match_operand:SF 0 "register_operand" "=d")
439        (float:SF (match_operand:SI 1 "register_operand" "d")))]
440  "TARGET_HARD_FLOAT && TARGET_FLOAT_CONVERT"
441  "flt\t%0,%1"
442  [(set_attr "type"     "fcvt")
443  (set_attr "mode"      "SF")
444  (set_attr "length"    "4")])
445
446(define_insn "fix_truncsfsi2"
447  [(set (match_operand:SI 0 "register_operand" "=d")
448        (fix:SI (match_operand:SF 1 "register_operand" "d")))]
449  "TARGET_HARD_FLOAT && TARGET_FLOAT_CONVERT"
450  "fint\t%0,%1"
451  [(set_attr "type"     "fcvt")
452  (set_attr "mode"      "SF")
453  (set_attr "length"    "4")])
454
455;;----------------------------------------------------------------
456;; Add
457;;----------------------------------------------------------------
458
459;; Add 2 SImode integers [ src1 = reg ; src2 = arith ; dest = reg ]
460;; Leave carry as is
461(define_insn "addsi3"
462  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
463	(plus:SI (match_operand:SI 1 "reg_or_0_operand" "%dJ,dJ,dJ")
464		 (match_operand:SI 2 "arith_plus_operand" "d,I,i")))]
465  ""
466  "@
467   addk\t%0,%z1,%2
468   addik\t%0,%z1,%2
469   addik\t%0,%z1,%2"
470  [(set_attr "type"	"arith,arith,no_delay_arith")
471  (set_attr "mode"	"SI,SI,SI")
472  (set_attr "length"	"4,4,8")])
473
474;;----------------------------------------------------------------
475;; Double Precision Additions
476;;----------------------------------------------------------------
477
478;; reg_DI_dest = reg_DI_src1 + DI_src2
479
480;; Adding 2 DI operands in register or reg/imm
481
482(define_insn "adddi3"
483  [(set (match_operand:DI 0 "register_operand" "=d,d,d")
484	(plus:DI (match_operand:DI 1 "register_operand" "%d,d,d")
485		 (match_operand:DI 2 "arith_operand32" "d,P,N")))]
486  ""
487  "@
488  add\t%L0,%L1,%L2\;addc\t%M0,%M1,%M2
489  addi\t%L0,%L1,%2\;addc\t%M0,%M1,r0
490  addi\t%L0,%L1,%2\;addc\t%M0,%M1,r0\;addi\t%M0,%M0,-1"
491  [(set_attr "type"	"darith")
492  (set_attr "mode"	"DI")
493  (set_attr "length"	"8,8,12")])
494
495;;----------------------------------------------------------------
496;; Subtraction
497;;----------------------------------------------------------------
498
499(define_insn "subsi3"
500  [(set (match_operand:SI 0 "register_operand" "=d,d")
501	(minus:SI (match_operand:SI 1 "arith_operand" "d,d")
502		  (match_operand:SI 2 "arith_operand" "d,n")))]
503  ""
504  "@
505   rsubk\t%0,%2,%z1
506   addik\t%0,%z1,-%2"
507  [(set_attr "type"	"arith,no_delay_arith")
508  (set_attr "mode"	"SI")
509  (set_attr "length"	"4,8")])
510
511
512;;----------------------------------------------------------------
513;; Double Precision Subtraction
514;;----------------------------------------------------------------
515
516(define_insn "subdi3"
517  [(set (match_operand:DI 0 "register_operand" "=&d")
518	(minus:DI (match_operand:DI 1 "register_operand" "d")
519		  (match_operand:DI 2 "arith_operand32" "d")))]
520  ""
521  "rsub\t%L0,%L2,%L1\;rsubc\t%M0,%M2,%M1"
522  [(set_attr "type"	"darith")
523  (set_attr "mode"	"DI")
524  (set_attr "length"	"8")])
525
526
527;;----------------------------------------------------------------
528;; Multiplication
529;;----------------------------------------------------------------
530
531(define_insn "mulsi3"
532  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
533	(mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
534		 (match_operand:SI 2 "arith_operand" "d,I,i")))]
535  "!TARGET_SOFT_MUL"
536  "@
537  mul\t%0,%1,%2
538  muli\t%0,%1,%2
539  muli\t%0,%1,%2"
540  [(set_attr "type"	"imul,imul,no_delay_imul")
541  (set_attr "mode"	"SI")
542  (set_attr "length"	"4,4,8")])
543
544(define_insn "mulsidi3"
545  [(set (match_operand:DI 0 "register_operand" "=&d")
546        (mult:DI
547         (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
548         (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
549  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
550  "mul\t%L0,%1,%2\;mulh\t%M0,%1,%2"
551  [(set_attr "type"     "no_delay_arith")
552   (set_attr "mode"     "DI")
553   (set_attr "length"   "8")])
554
555(define_insn "umulsidi3"
556  [(set (match_operand:DI 0 "register_operand" "=&d")
557        (mult:DI
558         (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
559         (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
560  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
561  "mul\t%L0,%1,%2\;mulhu\t%M0,%1,%2"
562  [(set_attr "type"     "no_delay_arith")
563   (set_attr "mode"     "DI")
564   (set_attr "length"   "8")])
565
566(define_insn "usmulsidi3"
567  [(set (match_operand:DI 0 "register_operand" "=&d")
568        (mult:DI
569         (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
570         (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
571  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
572  "mul\t%L0,%1,%2\;mulhsu\t%M0,%2,%1"
573  [(set_attr "type"     "no_delay_arith")
574   (set_attr "mode"     "DI")
575   (set_attr "length"   "8")])
576
577(define_insn "*smulsi3_highpart"
578  [(set (match_operand:SI 0 "register_operand" "=d")
579        (truncate:SI
580         (lshiftrt:DI
581          (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand"  "d"))
582                   (sign_extend:DI (match_operand:SI 2 "register_operand"  "d")))
583          (const_int 32))))]
584  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
585  "mulh\t%0,%1,%2"
586  [(set_attr "type"     "imul")
587  (set_attr "mode"      "SI")
588  (set_attr "length"    "4")])
589
590(define_insn "*umulsi3_highpart"
591  [(set (match_operand:SI 0 "register_operand"                            "=d")
592        (truncate:SI
593         (lshiftrt:DI
594          (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"  "d"))
595                   (zero_extend:DI (match_operand:SI 2 "register_operand"  "d"))
596)
597          (const_int 32))))]
598  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
599  "mulhu\t%0,%1,%2"
600  [(set_attr "type"     "imul")
601  (set_attr "mode"      "SI")
602  (set_attr "length"    "4")])
603
604(define_insn "*usmulsi3_highpart"
605  [(set (match_operand:SI 0 "register_operand"                            "=d")
606        (truncate:SI
607         (lshiftrt:DI
608          (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"  "d"))
609                   (sign_extend:DI (match_operand:SI 2 "register_operand"  "d"))
610)
611          (const_int 32))))]
612  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
613  "mulhsu\t%0,%2,%1"
614  [(set_attr "type"     "imul")
615  (set_attr "mode"      "SI")
616  (set_attr "length"    "4")])
617
618
619;;----------------------------------------------------------------
620;; Division and remainder
621;;----------------------------------------------------------------
622(define_expand "divsi3"
623  [(set (match_operand:SI 0 "register_operand" "=d")
624	(div:SI (match_operand:SI 1 "register_operand" "d")
625                (match_operand:SI 2 "register_operand" "d")))
626  ]
627  "(!TARGET_SOFT_DIV) || (TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)"
628  {
629    if (TARGET_SOFT_DIV && TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)
630      {
631        microblaze_expand_divide (operands);
632        DONE;
633      }
634    else if (!TARGET_SOFT_DIV)
635      {
636        emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2]));
637        DONE;
638      }
639  }
640)
641
642
643(define_insn "divsi3_internal"
644  [(set (match_operand:SI 0 "register_operand" "=d")
645	(div:SI (match_operand:SI 1 "register_operand" "d")
646		(match_operand:SI 2 "register_operand" "d")))
647  ]
648  "!TARGET_SOFT_DIV"
649  "idiv\t%0,%2,%1"
650  [(set_attr "type"	"idiv")
651  (set_attr "mode"	"SI")
652  (set_attr "length"	"4")]
653)
654
655(define_insn "udivsi3"
656  [(set (match_operand:SI 0 "register_operand" "=d")
657	(udiv:SI (match_operand:SI 1 "register_operand" "d")
658                 (match_operand:SI 2 "register_operand" "d")))
659  ]
660  "!TARGET_SOFT_DIV"
661  "idivu\t%0,%2,%1"
662  [(set_attr "type"	"idiv")
663  (set_attr "mode"	"SI")
664  (set_attr "length"	"4")])
665
666
667;;----------------------------------------------------------------
668;; Negation and one's complement
669;;----------------------------------------------------------------
670
671(define_insn "negsi2"
672  [(set (match_operand:SI 0 "register_operand" "=d")
673	(neg:SI (match_operand:SI 1 "register_operand" "d")))]
674  ""
675  "rsubk\t%0,%1,r0"
676  [(set_attr "type"	"arith")
677  (set_attr "mode"	"SI")
678  (set_attr "length"	"4")])
679
680(define_insn "negdi2"
681  [(set (match_operand:DI 0 "register_operand" "=d")
682	(neg:DI (match_operand:DI 1 "register_operand" "d")))]
683  ""
684  "rsub\t%L0,%L1,r0\;rsubc\t%M0,%M1,r0"
685  [(set_attr "type"	"darith")
686  (set_attr "mode"	"DI")
687  (set_attr "length"	"8")])
688
689
690(define_insn "one_cmplsi2"
691  [(set (match_operand:SI 0 "register_operand" "=d")
692	(not:SI (match_operand:SI 1 "register_operand" "d")))]
693  ""
694  "xori\t%0,%1,-1"
695  [(set_attr "type"	"arith")
696  (set_attr "mode"	"SI")
697  (set_attr "length"	"4")])
698
699(define_insn "*one_cmpldi2"
700  [(set (match_operand:DI 0 "register_operand" "=d")
701	(not:DI (match_operand:DI 1 "register_operand" "d")))]
702  ""
703  "nor\t%M0,r0,%M1\;nor\t%L0,r0,%L1"
704  [(set_attr "type"	"darith")
705  (set_attr "mode"	"DI")
706  (set_attr "length"    "8")]
707)
708
709(define_split
710  [(set (match_operand:DI 0 "register_operand" "")
711	(not:DI (match_operand:DI 1 "register_operand" "")))]
712  "reload_completed
713   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
714   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
715
716  [(set (subreg:SI (match_dup 0) 0) (not:SI (subreg:SI (match_dup 1) 0)))
717  (set (subreg:SI (match_dup 0) 4) (not:SI (subreg:SI (match_dup 1) 4)))]
718  "")
719
720
721;;----------------------------------------------------------------
722;; Logical
723;;----------------------------------------------------------------
724
725(define_insn "andsi3"
726  [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
727	(and:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
728		(match_operand:SI 2 "arith_operand" "d,I,i,M")))]
729  ""
730  "@
731   and\t%0,%1,%2
732   andi\t%0,%1,%2 #and1
733   andi\t%0,%1,%2 #and2
734   andi\t%0,%1,%2 #and3"
735  [(set_attr "type"	"arith,arith,no_delay_arith,no_delay_arith")
736  (set_attr "mode"	"SI,SI,SI,SI")
737  (set_attr "length"	"4,8,8,8")])
738
739
740(define_insn "iorsi3"
741  [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
742	(ior:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
743		(match_operand:SI 2 "arith_operand" "d,I,M,i")))]
744  ""
745  "@
746   or\t%0,%1,%2
747   ori\t%0,%1,%2
748   ori\t%0,%1,%2
749   ori\t%0,%1,%2"
750  [(set_attr "type"	"arith,no_delay_arith,no_delay_arith,no_delay_arith")
751  (set_attr "mode"	"SI,SI,SI,SI")
752  (set_attr "length"	"4,8,8,8")])
753
754(define_insn "xorsi3"
755  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
756	(xor:SI (match_operand:SI 1 "arith_operand" "%d,d,d")
757		(match_operand:SI 2 "arith_operand" "d,I,i")))]
758  ""
759  "@
760   xor\t%0,%1,%2
761   xori\t%0,%1,%2
762   xori\t%0,%1,%2"
763  [(set_attr "type"	"arith,arith,no_delay_arith")
764  (set_attr "mode"	"SI,SI,SI")
765  (set_attr "length"	"4,8,8")])
766
767;;----------------------------------------------------------------
768;; Zero extension
769;;----------------------------------------------------------------
770
771(define_insn "zero_extendhisi2"
772  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
773	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
774  ""
775  "@
776  andi\t%0,%1,0xffff
777  lhu%i1\t%0,%1
778  lhu%i1\t%0,%1"
779  [(set_attr "type"	"no_delay_arith,load,no_delay_load")
780  (set_attr "mode"	"SI,SI,SI")
781  (set_attr "length"	"8,4,8")])
782
783(define_insn "zero_extendqihi2"
784  [(set (match_operand:HI 0 "register_operand" "=d,d,d")
785	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
786  ""
787  "@
788  andi\t%0,%1,0x00ff
789  lbu%i1\t%0,%1
790  lbu%i1\t%0,%1"
791  [(set_attr "type"	"arith,load,no_delay_load")
792  (set_attr "mode"	"HI")
793  (set_attr "length"	"4,4,8")])
794
795(define_insn "zero_extendqisi2"
796  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
797	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
798  ""
799  "@
800  andi\t%0,%1,0x00ff
801  lbu%i1\t%0,%1
802  lbu%i1\t%0,%1"
803  [(set_attr "type"	"arith,load,no_delay_load")
804  (set_attr "mode"	"SI,SI,SI")
805  (set_attr "length"	"4,4,8")])
806
807;;----------------------------------------------------------------
808;; Sign extension
809;;----------------------------------------------------------------
810
811;; basic Sign Extend Operations
812
813(define_insn "extendqisi2"
814  [(set (match_operand:SI 0 "register_operand" "=d")
815	(sign_extend:SI (match_operand:QI 1 "register_operand" "d")))]
816  ""
817  "sext8\t%0,%1"
818  [(set_attr "type"	"arith")
819  (set_attr "mode"	"SI")
820  (set_attr "length"	"4")])
821
822(define_insn "extendhisi2"
823  [(set (match_operand:SI 0 "register_operand" "=d")
824	(sign_extend:SI (match_operand:HI 1 "register_operand" "d")))]
825  ""
826  "sext16\t%0,%1"
827  [(set_attr "type"	"arith")
828  (set_attr "mode"	"SI")
829  (set_attr "length"	"4")])
830
831;; Those for integer source operand are ordered
832;; widest source type first.
833
834(define_insn "extendsidi2"
835  [(set (match_operand:DI 0 "register_operand" "=d,d,d")
836	(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
837  ""
838  {
839     if (which_alternative == 0)
840       output_asm_insn ("addk\t%L0,r0,%1", operands);
841     else
842       output_asm_insn ("lw%i1\t%L0,%1", operands);
843
844     output_asm_insn ("add\t%M0,%L0,%L0", operands);
845     output_asm_insn ("addc\t%M0,r0,r0", operands);
846     output_asm_insn ("beqi\t%M0,.+8", operands);
847     return "addi\t%M0,r0,0xffffffff";
848  }
849  [(set_attr "type"	"multi,multi,multi")
850  (set_attr "mode"	"DI")
851  (set_attr "length"	"20,20,20")])
852
853;;----------------------------------------------------------------
854;; Data movement
855;;----------------------------------------------------------------
856
857;; 64-bit integer moves
858
859;; Unlike most other insns, the move insns can't be split with
860;; different predicates, because register spilling and other parts of
861;; the compiler, have memoized the insn number already.
862
863(define_expand "movdi"
864  [(set (match_operand:DI 0 "nonimmediate_operand" "")
865	(match_operand:DI 1 "general_operand" ""))]
866  ""
867  {
868    /* If operands[1] is a constant address illegal for pic, then we need to
869       handle it just like microblaze_legitimize_address does.  */
870    if (flag_pic && pic_address_needs_scratch (operands[1]))
871    {
872        rtx temp = force_reg (DImode, XEXP (XEXP (operands[1], 0), 0));
873        rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
874        emit_move_insn (operands[0], gen_rtx_PLUS (DImode, temp, temp2));
875        DONE;
876    }
877
878
879    if ((reload_in_progress | reload_completed) == 0
880        && !register_operand (operands[0], DImode)
881        && !register_operand (operands[1], DImode)
882        && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
883	       && operands[1] != CONST0_RTX (DImode))))
884    {
885
886      rtx temp = force_reg (DImode, operands[1]);
887      emit_move_insn (operands[0], temp);
888      DONE;
889    }
890  }
891)
892
893
894
895(define_insn "*movdi_internal"
896  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,o")
897	(match_operand:DI 1 "general_operand"      " d,i,J,R,o,d,d"))]
898  ""
899  {
900    switch (which_alternative)
901    {
902      case 0:
903        return "addk\t%0,%1\n\taddk\t%D0,%d1";
904      case 1:
905	return "addik\t%M0,r0,%h1\n\taddik\t%L0,r0,%j1 #li => la";
906      case 2:
907	  return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
908      case 3:
909      case 4:
910        if (reg_mentioned_p (operands[0], operands[1]))
911          return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
912	else
913	  return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
914      case 5:
915      case 6:
916        return "swi\t%1,%0\n\tswi\t%D1,%o0";
917    }
918    return "unreachable";
919  }
920  [(set_attr "type"	"no_delay_move,no_delay_arith,no_delay_arith,no_delay_load,no_delay_load,no_delay_store,no_delay_store")
921  (set_attr "mode"	"DI")
922  (set_attr "length"   "8,8,8,8,12,8,12")])
923
924(define_split
925  [(set (match_operand:DI 0 "register_operand" "")
926	(match_operand:DI 1 "register_operand" ""))]
927  "reload_completed
928   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
929   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
930   && (REGNO(operands[0]) == (REGNO(operands[1]) + 1))"
931
932  [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
933  (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
934  "")
935
936(define_split
937  [(set (match_operand:DI 0 "register_operand" "")
938	(match_operand:DI 1 "register_operand" ""))]
939  "reload_completed
940   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
941   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
942   && (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
943
944  [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
945  (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
946  "")
947
948;; Unlike most other insns, the move insns can't be split with
949;; different predicates, because register spilling and other parts of
950;; the compiler, have memoized the insn number already.
951
952(define_expand "movsi"
953  [(set (match_operand:SI 0 "nonimmediate_operand" "")
954	(match_operand:SI 1 "general_operand" ""))]
955  ""
956  {
957    if (microblaze_expand_move (SImode, operands)) DONE;
958  }
959)
960
961;; Added for status registers
962(define_insn "movsi_status"
963  [(set (match_operand:SI 0 "register_operand" "=d,d,z")
964        (match_operand:SI 1 "register_operand" "z,d,d"))]
965  "microblaze_is_interrupt_variant ()"
966  "@
967	mfs\t%0,%1  #mfs
968	addk\t%0,%1,r0 #add movsi
969	mts\t%0,%1  #mts"
970  [(set_attr "type" "move")
971  (set_attr "mode" "SI")
972  (set_attr "length" "12")])
973
974;; This move will be not be moved to delay slot.
975(define_insn "*movsi_internal3"
976  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d")
977	(match_operand:SI 1 "immediate_operand" "J,I,Mnis"))]
978  "(register_operand (operands[0], SImode) &&
979           (GET_CODE (operands[1]) == CONST_INT &&
980                 (INTVAL (operands[1]) <= 32767 && INTVAL (operands[1]) >= -32768)))"
981  "@
982   addk\t%0,r0,r0
983   addik\t%0,r0,%1\t# %X1
984   addik\t%0,r0,%1\t# %X1"
985  [(set_attr "type"	"arith,arith,no_delay_arith")
986  (set_attr "mode"	"SI")
987  (set_attr "length"	"4")])
988
989;; This move may be used for PLT label operand
990(define_insn "*movsi_internal5_pltop"
991  [(set (match_operand:SI 0 "register_operand" "=d,d")
992	(match_operand:SI 1 "call_insn_operand" ""))]
993  "(register_operand (operands[0], Pmode) &&
994           PLT_ADDR_P (operands[1]))"
995  {
996     gcc_unreachable ();
997  }
998  [(set_attr "type"	"load")
999  (set_attr "mode"	"SI")
1000  (set_attr "length"	"4")])
1001
1002(define_insn "*movsi_internal2"
1003  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,   d,d,R,m")
1004	(match_operand:SI 1 "move_src_operand"         " d,I,Mnis,R,m,dJ,dJ"))]
1005  ""
1006  "@
1007   addk\t%0,%1,r0
1008   addik\t%0,r0,%1\t# %X1
1009   addik\t%0,%a1
1010   lw%i1\t%0,%1
1011   lw%i1\t%0,%1
1012   sw%i0\t%z1,%0
1013   sw%i0\t%z1,%0"
1014  [(set_attr "type"	"load,load,no_delay_load,load,no_delay_load,store,no_delay_store")
1015  (set_attr "mode"	"SI")
1016  (set_attr "length"	"4,4,8,4,8,4,8")])
1017
1018
1019;; 16-bit Integer moves
1020
1021;; Unlike most other insns, the move insns can't be split with
1022;; different predicates, because register spilling and other parts of
1023;; the compiler, have memoized the insn number already.
1024;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
1025
1026(define_expand "movhi"
1027  [(set (match_operand:HI 0 "nonimmediate_operand" "")
1028	(match_operand:HI 1 "general_operand" ""))]
1029  ""
1030  {
1031    if ((reload_in_progress | reload_completed) == 0
1032        && !register_operand (operands[0], HImode)
1033        && !register_operand (operands[1], HImode)
1034        && ((GET_CODE (operands[1]) != CONST_INT
1035  	    || INTVAL (operands[1]) != 0)))
1036    {
1037        rtx temp = force_reg (HImode, operands[1]);
1038        emit_move_insn (operands[0], temp);
1039        DONE;
1040    }
1041  }
1042)
1043
1044(define_insn "*movhi_internal2"
1045  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m")
1046	(match_operand:HI 1 "general_operand"       "I,d,R,m,dJ,dJ"))]
1047  ""
1048  "@
1049   addik\t%0,r0,%1\t# %X1
1050   addk\t%0,%1,r0
1051   lhui\t%0,%1
1052   lhui\t%0,%1
1053   sh%i0\t%z1,%0
1054   sh%i0\t%z1,%0"
1055  [(set_attr "type"	"arith,move,load,no_delay_load,store,no_delay_store")
1056  (set_attr "mode"	"HI")
1057  (set_attr "length"	"4,4,4,8,8,8")])
1058
1059;; 8-bit Integer moves
1060
1061;; Unlike most other insns, the move insns can't be split with
1062;; different predicates, because register spilling and other parts of
1063;; the compiler, have memoized the insn number already.
1064;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
1065
1066(define_expand "movqi"
1067  [(set (match_operand:QI 0 "nonimmediate_operand" "")
1068	(match_operand:QI 1 "general_operand" ""))]
1069  ""
1070  {
1071    if ((reload_in_progress | reload_completed) == 0
1072        && !register_operand (operands[0], QImode)
1073        && !register_operand (operands[1], QImode)
1074        && ((GET_CODE (operands[1]) != CONST_INT
1075            || INTVAL (operands[1]) != 0)))
1076    {
1077        rtx temp = force_reg (QImode, operands[1]);
1078        emit_move_insn (operands[0], temp);
1079        DONE;
1080    }
1081  }
1082)
1083
1084(define_insn "*movqi_internal2"
1085  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
1086	(match_operand:QI 1 "general_operand"       "J,I,d,R,m,dJ,dJ"))]
1087  ""
1088  "@
1089   addk\t%0,r0,%z1
1090   addik\t%0,r0,%1\t# %X1
1091   addk\t%0,%1,r0
1092   lbu%i1\t%0,%1
1093   lbu%i1\t%0,%1
1094   sb%i0\t%z1,%0
1095   sbi\t%z1,%0"
1096  [(set_attr "type"	"arith,arith,move,load,no_delay_load,store,no_delay_store")
1097  (set_attr "mode"	"QI")
1098  (set_attr "length"	"4,4,8,4,8,4,8")])
1099
1100;; Block moves, see microblaze.c for more details.
1101;; Argument 0 is the destination
1102;; Argument 1 is the source
1103;; Argument 2 is the length
1104;; Argument 3 is the alignment
1105
1106(define_expand "movmemsi"
1107  [(parallel [(set (match_operand:BLK 0 "general_operand")
1108		   (match_operand:BLK 1 "general_operand"))
1109	      (use (match_operand:SI 2 ""))
1110	      (use (match_operand:SI 3 "const_int_operand"))])]
1111  ""
1112  {
1113    if (microblaze_expand_block_move (operands[0], operands[1],
1114				      operands[2], operands[3]))
1115        DONE;
1116    else
1117        FAIL;
1118  }
1119)
1120
1121;;Load and store reverse
1122(define_insn "movsi4_rev"
1123  [(set (match_operand:SI 0 "reg_or_mem_operand" "=r,Q")
1124        (bswap:SI (match_operand:SF 1 "reg_or_mem_operand" "Q,r")))]
1125  "TARGET_REORDER"
1126  "@
1127   lwr\t%0,%y1,r0
1128   swr\t%1,%y0,r0"
1129  [(set_attr "type"     "load,store")
1130  (set_attr "mode"      "SI")
1131  (set_attr "length"    "4,4")])
1132
1133;; 32-bit floating point moves
1134
1135(define_expand "movsf"
1136  [(set (match_operand:SF 0 "nonimmediate_operand" "")
1137        (match_operand:SF 1 "general_operand" ""))]
1138  ""
1139  {
1140    if ((reload_in_progress | reload_completed) == 0
1141        && !register_operand (operands[0], SFmode)
1142        && !register_operand (operands[1], SFmode)
1143        && ( ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
1144                 && operands[1] != CONST0_RTX (SFmode))))
1145    {
1146        rtx temp = force_reg (SFmode, operands[1]);
1147        emit_move_insn (operands[0], temp);
1148        DONE;
1149    }
1150  }
1151)
1152
1153;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
1154;;
1155(define_insn "*movsf_internal"
1156  [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
1157        (match_operand:SF 1 "general_operand" "G,d,R,F,m,d,d"))]
1158  "(register_operand (operands[0], SFmode)
1159       || register_operand (operands[1], SFmode)
1160       || operands[1] == CONST0_RTX (SFmode))"
1161  "@
1162   addk\t%0,r0,r0
1163   addk\t%0,%1,r0
1164   lw%i1\t%0,%1
1165   addik\t%0,r0,%F1
1166   lw%i1\t%0,%1
1167   sw%i0\t%z1,%0
1168   swi\t%z1,%0"
1169  [(set_attr "type"     "move,no_delay_load,load,no_delay_load,no_delay_load,store,no_delay_store")
1170  (set_attr "mode"      "SF")
1171  (set_attr "length"    "4,4,4,4,4,4,4")])
1172
1173;; 64-bit floating point moves
1174(define_expand "movdf"
1175  [(set (match_operand:DF 0 "nonimmediate_operand" "")
1176        (match_operand:DF 1 "general_operand" ""))]
1177  ""
1178  {
1179    if (flag_pic == 2) {
1180      if (GET_CODE (operands[1]) == MEM
1181          && !microblaze_legitimate_address_p (DFmode, XEXP (operands[1],0), 0))
1182      {
1183        rtx ptr_reg;
1184        rtx result;
1185        ptr_reg = force_reg (Pmode, XEXP (operands[1],0));
1186        result = gen_rtx_MEM (DFmode, ptr_reg);
1187        emit_move_insn (operands[0], result);
1188        DONE;
1189      }
1190    }
1191    if ((reload_in_progress | reload_completed) == 0
1192        && !register_operand (operands[0], DFmode)
1193        && !register_operand (operands[1], DFmode)
1194        && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
1195                 && operands[1] != CONST0_RTX (DFmode))))
1196    {
1197        rtx temp = force_reg (DFmode, operands[1]);
1198        emit_move_insn (operands[0], temp);
1199        DONE;
1200    }
1201  }
1202)
1203
1204;; movdf_internal
1205;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
1206;;
1207(define_insn "*movdf_internal"
1208  [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,o")
1209        (match_operand:DF 1 "general_operand" "dG,o,F,T,d"))]
1210  ""
1211  {
1212    switch (which_alternative)
1213    {
1214      case 0:
1215	return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
1216      case 1:
1217      case 3:
1218	if (reg_mentioned_p (operands[0], operands[1]))
1219          return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
1220        else
1221	  return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
1222      case 2:
1223      {
1224	return "addik\t%0,r0,%h1 \n\taddik\t%D0,r0,%j1 #Xfer Lo";
1225      }
1226      case 4:
1227	return "swi\t%1,%0\n\tswi\t%D1,%o0";
1228    }
1229    gcc_unreachable ();
1230  }
1231  [(set_attr "type"     "no_delay_move,no_delay_load,no_delay_load,no_delay_load,no_delay_store")
1232  (set_attr "mode"      "DF")
1233  (set_attr "length"    "4,8,8,16,8")])
1234
1235(define_split
1236  [(set (match_operand:DF 0 "register_operand" "")
1237        (match_operand:DF 1 "register_operand" ""))]
1238  "reload_completed
1239   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
1240   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
1241   && (REGNO (operands[0]) == (REGNO (operands[1]) + 1))"
1242  [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
1243  (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
1244  "")
1245
1246(define_split
1247  [(set (match_operand:DF 0 "register_operand" "")
1248        (match_operand:DF 1 "register_operand" ""))]
1249  "reload_completed
1250   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
1251   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
1252   && (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
1253  [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
1254  (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
1255  "")
1256
1257;;----------------------------------------------------------------
1258;; Shifts
1259;;----------------------------------------------------------------
1260
1261;;----------------------------------------------------------------
1262;; 32-bit left shifts
1263;;----------------------------------------------------------------
1264(define_expand "ashlsi3"
1265  [(set (match_operand:SI 0 "register_operand" "=&d")
1266	(ashift:SI (match_operand:SI 1 "register_operand" "d")
1267		   (match_operand:SI 2 "arith_operand" "")))]
1268  ""
1269  {
1270    /* Avoid recursion for trivial cases. */
1271    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1272      if (microblaze_expand_shift (operands))
1273        DONE;
1274  }
1275)
1276
1277;; Irrespective of if we have a barrel-shifter or not, we want to match
1278;; shifts by 1 with a special pattern. When a barrel shifter is present,
1279;; saves a cycle. If not, allows us to annotate the instruction for delay
1280;; slot optimization
1281(define_insn "*ashlsi3_byone"
1282  [(set (match_operand:SI 0 "register_operand" "=d")
1283	(ashift:SI (match_operand:SI 1 "register_operand" "d")
1284                   (match_operand:SI 2 "arith_operand"    "I")))]
1285  "(INTVAL (operands[2]) == 1)"
1286  "addk\t%0,%1,%1"
1287  [(set_attr "type"	"arith")
1288   (set_attr "mode"	"SI")
1289   (set_attr "length"	"4")]
1290)
1291
1292;; Barrel shift left
1293(define_insn "ashlsi3_bshift"
1294  [(set (match_operand:SI 0 "register_operand" "=d,d")
1295	(ashift:SI (match_operand:SI 1 "register_operand" "d,d")
1296                   (match_operand:SI 2 "arith_operand"    "I,d")))]
1297  "TARGET_BARREL_SHIFT"
1298  "@
1299  bslli\t%0,%1,%2
1300  bsll\t%0,%1,%2"
1301  [(set_attr "type"	"bshift,bshift")
1302  (set_attr "mode"	"SI,SI")
1303  (set_attr "length"	"4,4")]
1304)
1305
1306;; The following patterns apply when there is no barrel shifter present
1307
1308(define_insn "*ashlsi3_with_mul_delay"
1309  [(set (match_operand:SI 0 "register_operand" "=d")
1310	(ashift:SI (match_operand:SI 1 "register_operand"  "d")
1311                   (match_operand:SI 2 "immediate_operand" "I")))]
1312  "!TARGET_SOFT_MUL
1313   && ((1 << INTVAL (operands[2])) <= 32767 && (1 << INTVAL (operands[2])) >= -32768)"
1314  "muli\t%0,%1,%m2"
1315  ;; This MUL will not generate an imm. Can go into a delay slot.
1316  [(set_attr "type"	"arith")
1317   (set_attr "mode"	"SI")
1318   (set_attr "length"	"4")]
1319)
1320
1321(define_insn "*ashlsi3_with_mul_nodelay"
1322  [(set (match_operand:SI 0 "register_operand" "=d")
1323	(ashift:SI (match_operand:SI 1 "register_operand"  "d")
1324                   (match_operand:SI 2 "immediate_operand" "I")))]
1325  "!TARGET_SOFT_MUL"
1326  "muli\t%0,%1,%m2"
1327  ;; This MUL will generate an IMM. Cannot go into a delay slot
1328  [(set_attr "type"	"no_delay_arith")
1329   (set_attr "mode"	"SI")
1330   (set_attr "length"	"8")]
1331)
1332
1333(define_insn "*ashlsi3_with_size_opt"
1334  [(set (match_operand:SI 0 "register_operand" "=&d")
1335       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1336                   (match_operand:SI 2 "immediate_operand" "I")))]
1337  "(INTVAL (operands[2]) > 5 && optimize_size)"
1338  {
1339    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1340
1341    output_asm_insn ("ori\t%3,r0,%2", operands);
1342    if (REGNO (operands[0]) != REGNO (operands[1]))
1343        output_asm_insn ("addk\t%0,%1,r0", operands);
1344
1345    output_asm_insn ("addik\t%3,%3,-1", operands);
1346    output_asm_insn ("bneid\t%3,.-4", operands);
1347    return "addk\t%0,%0,%0";
1348  }
1349  [(set_attr "type"    "multi")
1350   (set_attr "mode"    "SI")
1351   (set_attr "length"  "20")]
1352)
1353
1354(define_insn "*ashlsi3_with_rotate"
1355  [(set (match_operand:SI 0 "register_operand" "=&d")
1356       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1357                   (match_operand:SI 2 "immediate_operand" "I")))]
1358  "(INTVAL (operands[2]) > 17 && !optimize_size)"
1359  {
1360    int i, nshift;
1361
1362    nshift = INTVAL (operands[2]);
1363    operands[3] = gen_int_mode (0xFFFFFFFF << nshift, SImode);
1364
1365    /* We do one extra shift so that the first bit (carry) coming into the MSB
1366       will be masked out */
1367    output_asm_insn ("src\t%0,%1", operands);
1368    for (i = 0; i < (32 - nshift); i++)
1369       output_asm_insn ("src\t%0,%0", operands);
1370
1371    return "andi\t%0,%0,%3";
1372  }
1373  [(set_attr "type"    "multi")
1374  (set_attr "mode"     "SI")
1375  (set_attr "length"   "80")]
1376)
1377
1378(define_insn "*ashlsi_inline"
1379  [(set (match_operand:SI 0 "register_operand" "=&d")
1380       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1381                   (match_operand:SI 2 "immediate_operand" "I")))]
1382  ""
1383  {
1384    int i;
1385    int nshift = INTVAL (operands[2]);
1386    if (REGNO (operands[0]) != REGNO (operands[1]))
1387      output_asm_insn ("addk\t%0,r0,%1", operands);
1388    output_asm_insn ("addk\t%0,%1,%1", operands);
1389    for (i = 0; i < (nshift - 2); i++)
1390      output_asm_insn ("addk\t%0,%0,%0", operands);
1391    return "addk\t%0,%0,%0";
1392  }
1393  [(set_attr "type"    "multi")
1394  (set_attr "mode"     "SI")
1395  (set_attr "length"   "124")]
1396)
1397
1398(define_insn "*ashlsi_reg"
1399  [(set (match_operand:SI 0 "register_operand" "=&d")
1400       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1401                   (match_operand:SI 2 "register_operand" "d")))]
1402  ""
1403  {
1404    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1405    output_asm_insn ("andi\t%3,%2,31", operands);
1406    if (REGNO (operands[0]) != REGNO (operands[1]))
1407      output_asm_insn ("addk\t%0,r0,%1", operands);
1408    /* Exit the loop if zero shift. */
1409    output_asm_insn ("beqid\t%3,.+20", operands);
1410    /* Emit the loop.  */
1411    output_asm_insn ("addk\t%0,%0,r0", operands);
1412    output_asm_insn ("addik\t%3,%3,-1", operands);
1413    output_asm_insn ("bneid\t%3,.-4", operands);
1414    return "addk\t%0,%0,%0";
1415  }
1416  [(set_attr "type"    "multi")
1417  (set_attr "mode"     "SI")
1418  (set_attr "length"   "28")]
1419)
1420
1421
1422;;----------------------------------------------------------------
1423;; 32-bit right shifts
1424;;----------------------------------------------------------------
1425(define_expand "ashrsi3"
1426  [(set (match_operand:SI 0 "register_operand" "=&d")
1427	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
1428                     (match_operand:SI 2 "arith_operand" "")))]
1429  ""
1430  {
1431    /* Avoid recursion for trivial cases. */
1432    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1433      if (microblaze_expand_shift (operands))
1434        DONE;
1435  }
1436)
1437
1438;; Irrespective of if we have a barrel-shifter or not, we want to match
1439;; shifts by 1 with a special pattern. When a barrel shifter is present,
1440;; saves a cycle. If not, allows us to annotate the instruction for delay
1441;; slot optimization
1442(define_insn "*ashrsi3_byone"
1443  [(set (match_operand:SI 0 "register_operand" "=d")
1444	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
1445                     (match_operand:SI 2 "arith_operand"    "I")))]
1446  "(INTVAL (operands[2]) == 1)"
1447  "sra\t%0,%1"
1448  [(set_attr "type"	"arith")
1449   (set_attr "mode"	"SI")
1450   (set_attr "length"	"4")]
1451)
1452
1453;; Barrel shift right logical
1454(define_insn "*ashrsi3_bshift"
1455  [(set (match_operand:SI 0 "register_operand" "=d,d")
1456	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
1457                     (match_operand:SI 2 "arith_operand"    "I,d")))]
1458  "TARGET_BARREL_SHIFT"
1459  "@
1460  bsrai\t%0,%1,%2
1461  bsra\t%0,%1,%2"
1462  [(set_attr "type"	"bshift,bshift")
1463  (set_attr "mode"	"SI,SI")
1464  (set_attr "length"	"4,4")]
1465)
1466
1467(define_insn "*ashrsi_inline"
1468  [(set (match_operand:SI 0 "register_operand" "=&d")
1469       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1470                   (match_operand:SI 2 "immediate_operand" "I")))]
1471  ""
1472  {
1473    int i;
1474    int nshift = INTVAL (operands[2]);
1475    if (REGNO (operands[0]) != REGNO (operands[1]))
1476      output_asm_insn ("addk\t%0,r0,%1", operands);
1477    output_asm_insn ("sra\t%0,%1", operands);
1478    for (i = 0; i < (nshift - 2); i++)
1479      output_asm_insn ("sra\t%0,%0", operands);
1480    return "sra\t%0,%0";
1481  }
1482  [(set_attr "type"    "multi")
1483  (set_attr "mode"     "SI")
1484  (set_attr "length"   "124")]
1485)
1486
1487(define_insn "*ashrsi_reg"
1488  [(set (match_operand:SI 0 "register_operand" "=&d")
1489       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1490                   (match_operand:SI 2 "register_operand" "d")))]
1491  ""
1492  {
1493    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1494    output_asm_insn ("andi\t%3,%2,31", operands);
1495    if (REGNO (operands[0]) != REGNO (operands[1]))
1496      output_asm_insn ("addk\t%0,r0,%1", operands);
1497    /* Exit the loop if zero shift. */
1498    output_asm_insn ("beqid\t%3,.+20", operands);
1499    /* Emit the loop.  */
1500    output_asm_insn ("addk\t%0,%0,r0", operands);
1501    output_asm_insn ("addik\t%3,%3,-1", operands);
1502    output_asm_insn ("bneid\t%3,.-4", operands);
1503    return "sra\t%0,%0";
1504  }
1505  [(set_attr "type"    "multi")
1506  (set_attr "mode"     "SI")
1507  (set_attr "length"   "28")]
1508)
1509
1510;;----------------------------------------------------------------
1511;; 32-bit right shifts (logical)
1512;;----------------------------------------------------------------
1513
1514(define_expand "lshrsi3"
1515  [(set (match_operand:SI 0 "register_operand" "=&d")
1516	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
1517                     (match_operand:SI 2 "arith_operand" "")))]
1518  ""
1519  {
1520    /* Avoid recursion for trivial cases. */
1521    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1522      if (microblaze_expand_shift (operands))
1523        DONE;
1524  }
1525)
1526
1527;; Irrespective of if we have a barrel-shifter or not, we want to match
1528;; shifts by 1 with a special pattern. When a barrel shifter is present,
1529;; saves a cycle. If not, allows us to annotate the instruction for delay
1530;; slot optimization
1531(define_insn "*lshrsi3_byone"
1532  [(set (match_operand:SI 0 "register_operand" "=d")
1533	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
1534                     (match_operand:SI 2 "arith_operand"    "I")))]
1535  "(INTVAL (operands[2]) == 1)"
1536  "srl\t%0,%1"
1537  [(set_attr "type"	"arith")
1538   (set_attr "mode"	"SI")
1539   (set_attr "length"	"4")]
1540)
1541
1542;; Barrel shift right logical
1543(define_insn "*lshrsi3_bshift"
1544  [(set (match_operand:SI 0 "register_operand" "=d,d")
1545	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
1546                     (match_operand:SI 2 "arith_operand"    "I,d")))]
1547  "TARGET_BARREL_SHIFT"
1548  "@
1549  bsrli\t%0,%1,%2
1550  bsrl\t%0,%1,%2"
1551  [(set_attr "type"	"bshift,bshift")
1552  (set_attr "mode"	"SI,SI")
1553  (set_attr "length"	"4,4")]
1554)
1555
1556(define_insn "*lshrsi_inline"
1557  [(set (match_operand:SI 0 "register_operand" "=&d")
1558       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1559                   (match_operand:SI 2 "immediate_operand" "I")))]
1560  ""
1561  {
1562    int i;
1563    int nshift = INTVAL (operands[2]);
1564    if (REGNO (operands[0]) != REGNO (operands[1]))
1565      output_asm_insn ("addk\t%0,r0,%1", operands);
1566    output_asm_insn ("srl\t%0,%1", operands);
1567    for (i = 0; i < (nshift - 2); i++)
1568      output_asm_insn ("srl\t%0,%0", operands);
1569    return "srl\t%0,%0";
1570  }
1571  [(set_attr "type"    "multi")
1572  (set_attr "mode"     "SI")
1573  (set_attr "length"   "124")]
1574)
1575
1576(define_insn "*lshrsi_reg"
1577  [(set (match_operand:SI 0 "register_operand" "=&d")
1578       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1579                   (match_operand:SI 2 "register_operand" "d")))]
1580  ""
1581  {
1582    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1583    output_asm_insn ("andi\t%3,%2,31", operands);
1584    if (REGNO (operands[0]) != REGNO (operands[1]))
1585      output_asm_insn ("addk\t%0,r0,%1", operands);
1586    /* Exit the loop if zero shift. */
1587    output_asm_insn ("beqid\t%3,.+20", operands);
1588    /* Emit the loop.  */
1589    output_asm_insn ("addk\t%0,%0,r0", operands);
1590    output_asm_insn ("addik\t%3,%3,-1", operands);
1591    output_asm_insn ("bneid\t%3,.-4", operands);
1592    return "srl\t%0,%0";
1593  }
1594  [(set_attr "type"    "multi")
1595  (set_attr "mode"     "SI")
1596  (set_attr "length"   "28")]
1597)
1598
1599;;----------------------------------------------------------------
1600;; Setting a register from an integer comparison.
1601;;----------------------------------------------------------------
1602(define_expand "cstoresi4"
1603   [(set (match_operand:SI 0 "register_operand")
1604        (match_operator:SI 1 "ordered_comparison_operator"
1605	      [(match_operand:SI 2 "register_operand")
1606	       (match_operand:SI 3 "register_operand")]))]
1607  "TARGET_PATTERN_COMPARE"
1608  "if (GET_CODE (operand1) != EQ && GET_CODE (operand1) != NE)
1609     FAIL;
1610  "
1611)
1612
1613(define_insn "seq_internal_pat"
1614  [(set (match_operand:SI 0 "register_operand" "=d")
1615	(eq:SI
1616	       (match_operand:SI 1 "register_operand" "d")
1617	       (match_operand:SI 2 "register_operand" "d")))]
1618  "TARGET_PATTERN_COMPARE"
1619  "pcmpeq\t%0,%1,%2"
1620  [(set_attr "type"	"arith")
1621   (set_attr "mode"	"SI")
1622   (set_attr "length"	"4")]
1623)
1624
1625(define_insn "sne_internal_pat"
1626  [(set (match_operand:SI 0 "register_operand" "=d")
1627	(ne:SI
1628	       (match_operand:SI 1 "register_operand" "d")
1629	       (match_operand:SI 2 "register_operand" "d")))]
1630  "TARGET_PATTERN_COMPARE"
1631  "pcmpne\t%0,%1,%2"
1632  [(set_attr "type"	"arith")
1633  (set_attr "mode"	"SI")
1634  (set_attr "length"	"4")]
1635)
1636
1637;;----------------------------------------------------------------
1638;; Setting a register from an floating point comparison.
1639;;----------------------------------------------------------------
1640(define_insn "cstoresf4"
1641   [(set (match_operand:SI 0 "register_operand" "=r")
1642        (match_operator:SI 1 "ordered_comparison_operator"
1643	      [(match_operand:SF 2 "register_operand" "r")
1644	       (match_operand:SF 3 "register_operand" "r")]))]
1645  "TARGET_HARD_FLOAT"
1646  "fcmp.%C1\t%0,%3,%2"
1647  [(set_attr "type"     "fcmp")
1648   (set_attr "mode"      "SF")
1649   (set_attr "length"    "4")]
1650)
1651
1652;;----------------------------------------------------------------
1653;; Conditional branches
1654;;----------------------------------------------------------------
1655
1656(define_expand "cbranchsi4"
1657  [(set (pc)
1658	(if_then_else (match_operator 0 "ordered_comparison_operator"
1659		       [(match_operand:SI 1 "register_operand")
1660		        (match_operand:SI 2 "arith_operand")])
1661		      (label_ref (match_operand 3 ""))
1662		      (pc)))]
1663  ""
1664{
1665  microblaze_expand_conditional_branch (SImode, operands);
1666  DONE;
1667})
1668
1669(define_expand "cbranchsf4"
1670  [(set (pc)
1671	(if_then_else (match_operator 0 "ordered_comparison_operator"
1672		       [(match_operand:SF 1 "register_operand")
1673		        (match_operand:SF 2 "register_operand")])
1674		      (label_ref (match_operand 3 ""))
1675		      (pc)))]
1676  "TARGET_HARD_FLOAT"
1677{
1678  microblaze_expand_conditional_branch_sf (operands);
1679  DONE;
1680
1681})
1682
1683;; Used to implement comparison instructions
1684(define_expand "condjump"
1685  [(set (pc)
1686	(if_then_else (match_operand 0)
1687		      (label_ref (match_operand 1))
1688		      (pc)))])
1689
1690(define_insn "branch_zero"
1691  [(set (pc)
1692	(if_then_else (match_operator:SI 0 "ordered_comparison_operator"
1693  				 [(match_operand:SI 1 "register_operand" "d")
1694                                  (const_int 0)])
1695                      (match_operand:SI 2 "pc_or_label_operand" "")
1696                      (match_operand:SI 3 "pc_or_label_operand" "")))
1697  ]
1698  ""
1699  {
1700    if (operands[3] == pc_rtx)
1701      return "b%C0i%?\t%z1,%2";
1702    else
1703      return "b%N0i%?\t%z1,%3";
1704  }
1705  [(set_attr "type"	"branch")
1706   (set_attr "mode"	"none")
1707   (set_attr "length"	"4")]
1708)
1709
1710(define_insn "branch_compare"
1711  [(set (pc)
1712        (if_then_else (match_operator:SI 0 "cmp_op"
1713                                         [(match_operand:SI 1 "register_operand" "d")
1714                                          (match_operand:SI 2 "register_operand" "d")
1715                                         ])
1716                      (label_ref (match_operand 3))
1717                      (pc)))
1718  (clobber(reg:SI R_TMP))]
1719  ""
1720  {
1721    operands[4] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1722    enum rtx_code code = GET_CODE (operands[0]);
1723
1724    if (code == GT || code == LE)
1725      {
1726        output_asm_insn ("cmp\tr18,%z1,%z2", operands);
1727        code = swap_condition (code);
1728      }
1729    else if (code == GTU || code == LEU)
1730      {
1731        output_asm_insn ("cmpu\tr18,%z1,%z2", operands);
1732        code = swap_condition (code);
1733      }
1734    else if (code == GE || code == LT)
1735      {
1736        output_asm_insn ("cmp\tr18,%z2,%z1", operands);
1737      }
1738    else if (code == GEU || code == LTU)
1739      {
1740        output_asm_insn ("cmpu\tr18,%z2,%z1", operands);
1741      }
1742
1743    operands[0] = gen_rtx_fmt_ee (signed_condition (code), SImode, operands[4], const0_rtx);
1744    return "b%C0i%?\tr18,%3";
1745  }
1746  [(set_attr "type"     "branch")
1747   (set_attr "mode"     "none")
1748   (set_attr "length"   "12")]
1749)
1750
1751;;----------------------------------------------------------------
1752;; Unconditional branches
1753;;----------------------------------------------------------------
1754(define_insn "jump"
1755  [(set (pc)
1756	(label_ref (match_operand 0 "" "")))]
1757  ""
1758  {
1759    if (GET_CODE (operands[0]) == REG)
1760        return "br%?\t%0";
1761    else
1762        return "bri%?\t%l0";
1763  }
1764  [(set_attr "type"	"jump")
1765  (set_attr "mode"	"none")
1766  (set_attr "length"	"4")])
1767
1768(define_expand "indirect_jump"
1769  [(set (pc) (match_operand 0 "register_operand" "d"))]
1770  ""
1771  {
1772    rtx dest = operands[0];
1773    if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode)
1774      operands[0] = copy_to_mode_reg (Pmode, dest);
1775
1776    emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
1777    DONE;
1778  }
1779)
1780
1781;; Indirect jumps. Jump to register values. Assuming absolute jumps
1782
1783(define_insn "indirect_jump_internal1"
1784  [(set (pc) (match_operand:SI 0 "register_operand" "d"))]
1785  ""
1786  "bra%?\t%0"
1787  [(set_attr "type"	"jump")
1788  (set_attr "mode"	"none")
1789  (set_attr "length"	"4")])
1790
1791(define_expand "tablejump"
1792  [(set (pc)
1793	(match_operand 0 "register_operand" "d"))
1794  (use (label_ref (match_operand 1 "" "")))]
1795  ""
1796  {
1797    gcc_assert (GET_MODE (operands[0]) == Pmode);
1798
1799    if (!flag_pic)
1800      emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
1801    else
1802      emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
1803    DONE;
1804  }
1805)
1806
1807(define_insn "tablejump_internal1"
1808  [(set (pc)
1809	(match_operand:SI 0 "register_operand" "d"))
1810  (use (label_ref (match_operand 1 "" "")))]
1811  ""
1812  "bra%?\t%0 "
1813  [(set_attr "type"	"jump")
1814  (set_attr "mode"	"none")
1815  (set_attr "length"	"4")])
1816
1817(define_expand "tablejump_internal3"
1818  [(parallel [(set (pc)
1819		   (plus:SI (match_operand:SI 0 "register_operand" "d")
1820			    (label_ref:SI (match_operand:SI 1 "" ""))))
1821             (use (label_ref:SI (match_dup 1)))])]
1822  ""
1823  ""
1824)
1825
1826;; need to change for MicroBlaze PIC
1827(define_insn ""
1828 [(set (pc)
1829	(plus:SI (match_operand:SI 0 "register_operand" "d")
1830		 (label_ref:SI (match_operand 1 "" ""))))
1831  (use (label_ref:SI (match_dup 1)))]
1832 "NEXT_INSN (as_a <rtx_insn *> (operands[1])) != 0
1833  && GET_CODE (PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])))) == ADDR_DIFF_VEC
1834  && flag_pic"
1835  {
1836    output_asm_insn ("addk\t%0,%0,r20",operands);
1837    return "bra%?\t%0";
1838}
1839 [(set_attr "type"	"jump")
1840  (set_attr "mode"	"none")
1841  (set_attr "length"	"4")])
1842
1843(define_expand "tablejump_internal4"
1844  [(parallel [(set (pc)
1845		   (plus:DI (match_operand:DI 0 "register_operand" "d")
1846			    (label_ref:DI (match_operand:SI 1 "" ""))))
1847             (use (label_ref:DI (match_dup 1)))])]
1848  ""
1849  ""
1850)
1851
1852;;----------------------------------------------------------------
1853;; Function prologue/epilogue and stack allocation
1854;;----------------------------------------------------------------
1855(define_expand "prologue"
1856  [(const_int 1)]
1857  ""
1858  {
1859      microblaze_expand_prologue ();
1860      DONE;
1861  }
1862)
1863
1864(define_expand "epilogue"
1865  [(use (const_int 0))]
1866  ""
1867  {
1868      microblaze_expand_epilogue ();
1869      DONE;
1870  }
1871)
1872
1873;; An insn to allocate new stack space for dynamic use (e.g., alloca).
1874;; We copy the return address, decrement the stack pointer and save the
1875;; return address again at the new stack top
1876
1877(define_expand "allocate_stack"
1878  [(set (match_operand 0 "register_operand" "=r")
1879	(minus (reg 1) (match_operand 1 "register_operand" "")))
1880   (set (reg 1)
1881	(minus (reg 1) (match_dup 1)))]
1882  ""
1883  {
1884    rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
1885    rtx rtmp    = gen_rtx_REG (SImode, R_TMP);
1886    rtx neg_op0;
1887
1888    emit_move_insn (rtmp, retaddr);
1889    if (GET_CODE (operands[1]) != CONST_INT)
1890    {
1891        neg_op0 = gen_reg_rtx (Pmode);
1892	emit_insn (gen_negsi2 (neg_op0, operands[1]));
1893    } else
1894        neg_op0 = GEN_INT (- INTVAL (operands[1]));
1895
1896    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
1897    emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), rtmp);
1898    emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
1899    emit_insn (gen_rtx_CLOBBER (SImode, rtmp));
1900    DONE;
1901  }
1902)
1903
1904(define_expand "save_stack_block"
1905  [(match_operand 0 "register_operand" "")
1906   (match_operand 1 "register_operand" "")]
1907  ""
1908  {
1909    emit_move_insn (operands[0], operands[1]);
1910    DONE;
1911  }
1912)
1913
1914(define_expand "restore_stack_block"
1915  [(match_operand 0 "register_operand" "")
1916   (match_operand 1 "register_operand" "")]
1917  ""
1918  {
1919    rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
1920    rtx rtmp    = gen_rtx_REG (SImode, R_TMP);
1921
1922    /* Move the retaddr.  */
1923    emit_move_insn (rtmp, retaddr);
1924    emit_move_insn (operands[0], operands[1]);
1925    emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), rtmp);
1926    DONE;
1927  }
1928)
1929
1930;; Trivial return.  Make it look like a normal return insn as that
1931;; allows jump optimizations to work better .
1932(define_expand "return"
1933  [(simple_return)]
1934  "microblaze_can_use_return_insn ()"
1935  {}
1936)
1937
1938(define_expand "simple_return"
1939  [(simple_return)]
1940  ""
1941  {}
1942)
1943
1944(define_insn "*<optab>"
1945  [(any_return)]
1946  ""
1947  {
1948    if (microblaze_is_break_handler ())
1949        return "rtbd\tr16, 8\;%#";
1950    else if (microblaze_is_interrupt_variant ())
1951        return "rtid\tr14, 0\;%#";
1952    else
1953        return "rtsd\tr15, 8\;%#";
1954  }
1955  [(set_attr "type"	"jump")
1956  (set_attr "mode"	"none")
1957  (set_attr "length"	"4")]
1958)
1959
1960;; Normal return.
1961
1962(define_insn "<optab>_internal"
1963  [(any_return)
1964   (use (match_operand:SI 0 "register_operand" ""))]
1965  ""
1966  {
1967    if (microblaze_is_break_handler ())
1968        return "rtbd\tr16,8\;%#";
1969    else if (microblaze_is_interrupt_variant ())
1970        return "rtid\tr14,0 \;%#";
1971    else
1972        return "rtsd\tr15,8 \;%#";
1973  }
1974  [(set_attr "type"	"jump")
1975  (set_attr "mode"	"none")
1976  (set_attr "length"	"4")])
1977
1978
1979;; Block any insns from across this point
1980;; Useful to group sequences together.
1981(define_insn "blockage"
1982  [(unspec_volatile [(const_int 0)] 0)]
1983  ""
1984  ""
1985  [(set_attr "type"	"unknown")
1986  (set_attr "mode"	"none")
1987  (set_attr "length"	"0")])
1988
1989
1990;;----------------------------------------------------------------
1991;; Function calls
1992;;----------------------------------------------------------------
1993
1994(define_expand "call"
1995  [(parallel [(call (match_operand 0 "memory_operand" "m")
1996		    (match_operand 1 "" "i"))
1997             (clobber (reg:SI R_SR))
1998             (use (match_operand 2 "" ""))
1999             (use (match_operand 3 "" ""))])]
2000  ""
2001  {
2002    rtx addr = XEXP (operands[0], 0);
2003
2004    if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
2005	&& !SYMBOL_REF_LOCAL_P (addr))
2006      {
2007        rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
2008        XEXP (operands[0], 0) = temp;
2009      }
2010
2011    if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
2012	|| !call_insn_operand (addr, VOIDmode))
2013      XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
2014
2015    if (GET_CODE (XEXP (operands[0], 0)) == UNSPEC)
2016      emit_call_insn (gen_call_internal_plt0 (operands[0], operands[1],
2017                        gen_rtx_REG (SImode,
2018				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
2019                               	     pic_offset_table_rtx));
2020    else
2021      emit_call_insn (gen_call_internal0 (operands[0], operands[1],
2022                        gen_rtx_REG (SImode,
2023				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2024
2025        DONE;
2026  }
2027)
2028
2029(define_expand "call_internal0"
2030  [(parallel [(call (match_operand 0 "" "")
2031		    (match_operand 1 "" ""))
2032             (clobber (match_operand:SI 2 "" ""))])]
2033  ""
2034  {
2035  }
2036)
2037
2038(define_expand "call_internal_plt0"
2039  [(parallel [(call (match_operand 0 "" "")
2040		    (match_operand 1 "" ""))
2041             (clobber (match_operand:SI 2 "" ""))
2042             (use (match_operand:SI 3 "" ""))])]
2043  ""
2044  {
2045  }
2046)
2047
2048(define_insn "call_internal_plt"
2049  [(call (mem (match_operand:SI 0 "call_insn_plt_operand" ""))
2050	 (match_operand:SI 1 "" "i"))
2051  (clobber (reg:SI R_SR))
2052  (use (reg:SI R_GOT))]
2053  "flag_pic"
2054  {
2055    register rtx target2 = gen_rtx_REG (Pmode,
2056			      GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2057    gen_rtx_CLOBBER (VOIDmode, target2);
2058    return "brlid\tr15,%0\;%#";
2059  }
2060  [(set_attr "type"	"call")
2061  (set_attr "mode"	"none")
2062  (set_attr "length"	"4")])
2063
2064(define_insn "call_internal1"
2065  [(call (mem (match_operand:VOID 0 "call_insn_simple_operand" "ri"))
2066	 (match_operand:SI 1 "" "i"))
2067  (clobber (reg:SI R_SR))]
2068  ""
2069  {
2070    register rtx target = operands[0];
2071    register rtx target2 = gen_rtx_REG (Pmode,
2072			      GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2073    if (GET_CODE (target) == SYMBOL_REF) {
2074        if (microblaze_break_function_p (SYMBOL_REF_DECL (target))) {
2075            gen_rtx_CLOBBER (VOIDmode, target2);
2076            return "brki\tr16,%0\;%#";
2077        }
2078        else {
2079            gen_rtx_CLOBBER (VOIDmode, target2);
2080            return "brlid\tr15,%0\;%#";
2081        }
2082    } else if (GET_CODE (target) == CONST_INT)
2083        return "la\t%@,r0,%0\;brald\tr15,%@\;%#";
2084    else if (GET_CODE (target) == REG)
2085        return "brald\tr15,%0\;%#";
2086    else {
2087        fprintf (stderr,"Unsupported call insn\n");
2088        return NULL;
2089    }
2090  }
2091  [(set_attr "type"	"call")
2092  (set_attr "mode"	"none")
2093  (set_attr "length"	"4")])
2094
2095;; calls.c now passes a fourth argument, make saber happy
2096
2097(define_expand "call_value"
2098  [(parallel [(set (match_operand 0 "register_operand" "=d")
2099		   (call (match_operand 1 "memory_operand" "m")
2100			 (match_operand 2 "" "i")))
2101             (clobber (reg:SI R_SR))
2102             (use (match_operand 3 "" ""))])] ;; next_arg_reg
2103  ""
2104  {
2105    rtx addr = XEXP (operands[1], 0);
2106
2107    if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
2108	&& !SYMBOL_REF_LOCAL_P (addr))
2109      {
2110        rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
2111        XEXP (operands[1], 0) = temp;
2112      }
2113
2114    if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
2115        || !call_insn_operand (addr, VOIDmode))
2116      XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
2117
2118    if (GET_CODE (XEXP (operands[1], 0)) == UNSPEC)
2119      emit_call_insn (gen_call_value_intern_plt0 (operands[0], operands[1],
2120			operands[2],
2121                        gen_rtx_REG (SImode,
2122				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
2123				     pic_offset_table_rtx));
2124    else
2125      emit_call_insn (gen_call_value_internal (operands[0], operands[1],
2126			operands[2],
2127                        gen_rtx_REG (SImode,
2128				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2129
2130    DONE;
2131  }
2132)
2133
2134
2135(define_expand "call_value_internal"
2136  [(parallel [(set (match_operand 0 "" "")
2137		   (call (match_operand 1 "" "")
2138			 (match_operand 2 "" "")))
2139             (clobber (match_operand:SI 3 "" ""))
2140             ])]
2141  ""
2142  {}
2143)
2144
2145(define_expand "call_value_intern_plt0"
2146  [(parallel[(set (match_operand 0 "" "")
2147                  (call (match_operand 1 "" "")
2148                        (match_operand 2 "" "")))
2149             (clobber (match_operand:SI 3 "" ""))
2150             (use (match_operand:SI 4 "" ""))])]
2151  "flag_pic"
2152  {}
2153)
2154
2155(define_insn "call_value_intern_plt"
2156  [(set (match_operand:VOID 0 "register_operand" "=d")
2157        (call (mem (match_operand:SI 1 "call_insn_plt_operand" ""))
2158              (match_operand:SI 2 "" "i")))
2159   (clobber (match_operand:SI 3 "register_operand" "=d"))
2160   (use (match_operand:SI 4 "register_operand"))]
2161  "flag_pic"
2162  {
2163    register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2164
2165    gen_rtx_CLOBBER (VOIDmode,target2);
2166    return "brlid\tr15,%1\;%#";
2167  }
2168  [(set_attr "type"	"call")
2169  (set_attr "mode"	"none")
2170  (set_attr "length"	"4")])
2171
2172(define_insn "call_value_intern"
2173  [(set (match_operand:VOID 0 "register_operand" "=d")
2174        (call (mem (match_operand:VOID 1 "call_insn_operand" "ri"))
2175              (match_operand:SI 2 "" "i")))
2176   (clobber (match_operand:SI 3 "register_operand" "=d"))]
2177  ""
2178  {
2179    register rtx target = operands[1];
2180    register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2181
2182    if (GET_CODE (target) == SYMBOL_REF)
2183    {
2184      gen_rtx_CLOBBER (VOIDmode,target2);
2185      if (microblaze_break_function_p (SYMBOL_REF_DECL (target)))
2186        return "brki\tr16,%1\;%#";
2187      else if (SYMBOL_REF_FLAGS (target) & SYMBOL_FLAG_FUNCTION)
2188        {
2189	  return "brlid\tr15,%1\;%#";
2190        }
2191      else
2192        {
2193	    return "bralid\tr15,%1\;%#";
2194        }
2195    }
2196    else if (GET_CODE (target) == CONST_INT)
2197        return "la\t%@,r0,%1\;brald\tr15,%@\;%#";
2198    else if (GET_CODE (target) == REG)
2199        return "brald\tr15,%1\;%#";
2200    else
2201        return "Unsupported call insn\n";
2202  }
2203  [(set_attr "type"	"call")
2204  (set_attr "mode"	"none")
2205  (set_attr "length"	"4")])
2206
2207
2208;; Call subroutine returning any type.
2209(define_expand "untyped_call"
2210  [(parallel [(call (match_operand 0 "" "")
2211		    (const_int 0))
2212             (match_operand 1 "" "")
2213             (match_operand 2 "" "")])]
2214  ""
2215  {
2216    if (operands[0])		/* silence statement not reached warnings */
2217    {
2218        int i;
2219
2220        emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
2221
2222        for (i = 0; i < XVECLEN (operands[2], 0); i++)
2223	{
2224	    rtx set = XVECEXP (operands[2], 0, i);
2225	    emit_move_insn (SET_DEST (set), SET_SRC (set));
2226	}
2227
2228        emit_insn (gen_blockage ());
2229        DONE;
2230      }
2231  }
2232)
2233
2234;;----------------------------------------------------------------
2235;; Misc.
2236;;----------------------------------------------------------------
2237
2238(define_insn "nop"
2239  [(const_int 0)]
2240  ""
2241  "nop"
2242  [(set_attr "type"	"nop")
2243  (set_attr "mode"	"none")
2244  (set_attr "length"	"4")])
2245
2246;; Trap instruction pattern for __builtin_trap. Same as the glibc ABORT_INSTRUCTION
2247(define_insn "trap"
2248  [(trap_if (const_int 1) (const_int 0))]
2249  ""
2250  "brki\tr0,-1"
2251 [(set_attr "type" "trap")]
2252)
2253
2254;; The insn to set GOT. The hardcoded number "8" accounts for $pc difference
2255;; between "mfs" and "addik" instructions.
2256(define_insn "set_got"
2257  [(set (match_operand:SI 0 "register_operand" "=r")
2258    (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))]
2259  ""
2260  "mfs\t%0,rpc\n\taddik\t%0,%0,_GLOBAL_OFFSET_TABLE_+8"
2261  [(set_attr "type" "multi")
2262   (set_attr "length" "12")])
2263
2264;; This insn gives the count of leading number of zeros for the second
2265;; operand and stores the result in first operand.
2266(define_insn "clzsi2"
2267  [(set (match_operand:SI 0 "register_operand" "=r")
2268        (clz:SI (match_operand:SI 1 "register_operand" "r")))]
2269  "TARGET_HAS_CLZ"
2270  "clz\t%0,%1"
2271  [(set_attr "type"     "arith")
2272  (set_attr "mode"      "SI")
2273  (set_attr "length"    "4")])
2274
2275(include "sync.md")
2276