xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/microblaze/microblaze.md (revision b83ebeba7f767758d2778bb0f9d7a76534253621)
1;; microblaze.md -- Machine description for Xilinx MicroBlaze processors.
2;; Copyright (C) 2009-2013 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  "@
522   rsub\t%L0,%L2,%L1\;rsubc\t%M0,%M2,%M1"
523  [(set_attr "type"	"darith")
524  (set_attr "mode"	"DI")
525  (set_attr "length"	"8")])
526
527
528;;----------------------------------------------------------------
529;; Multiplication
530;;----------------------------------------------------------------
531
532(define_insn "mulsi3"
533  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
534	(mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
535		 (match_operand:SI 2 "arith_operand" "d,I,i")))]
536  "!TARGET_SOFT_MUL"
537  "@
538  mul\t%0,%1,%2
539  muli\t%0,%1,%2
540  muli\t%0,%1,%2"
541  [(set_attr "type"	"imul,imul,no_delay_imul")
542  (set_attr "mode"	"SI")
543  (set_attr "length"	"4,4,8")])
544
545(define_insn "mulsidi3"
546  [(set (match_operand:DI 0 "register_operand" "=&d")
547        (mult:DI
548         (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
549         (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
550  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
551  "mul\t%L0,%1,%2\;mulh\t%M0,%1,%2"
552  [(set_attr "type"     "no_delay_arith")
553   (set_attr "mode"     "DI")
554   (set_attr "length"   "8")])
555
556(define_insn "umulsidi3"
557  [(set (match_operand:DI 0 "register_operand" "=&d")
558        (mult:DI
559         (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
560         (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
561  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
562  "mul\t%L0,%1,%2\;mulhu\t%M0,%1,%2"
563  [(set_attr "type"     "no_delay_arith")
564   (set_attr "mode"     "DI")
565   (set_attr "length"   "8")])
566
567(define_insn "usmulsidi3"
568  [(set (match_operand:DI 0 "register_operand" "=&d")
569        (mult:DI
570         (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
571         (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
572  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
573  "mul\t%L0,%1,%2\;mulhsu\t%M0,%2,%1"
574  [(set_attr "type"     "no_delay_arith")
575   (set_attr "mode"     "DI")
576   (set_attr "length"   "8")])
577
578(define_insn "*smulsi3_highpart"
579  [(set (match_operand:SI 0 "register_operand" "=d")
580        (truncate:SI
581         (lshiftrt:DI
582          (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand"  "d"))
583                   (sign_extend:DI (match_operand:SI 2 "register_operand"  "d")))
584          (const_int 32))))]
585  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
586  "mulh\t%0,%1,%2"
587  [(set_attr "type"     "imul")
588  (set_attr "mode"      "SI")
589  (set_attr "length"    "4")])
590
591(define_insn "*umulsi3_highpart"
592  [(set (match_operand:SI 0 "register_operand"                            "=d")
593        (truncate:SI
594         (lshiftrt:DI
595          (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"  "d"))
596                   (zero_extend:DI (match_operand:SI 2 "register_operand"  "d"))
597)
598          (const_int 32))))]
599  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
600  "mulhu\t%0,%1,%2"
601  [(set_attr "type"     "imul")
602  (set_attr "mode"      "SI")
603  (set_attr "length"    "4")])
604
605(define_insn "*usmulsi3_highpart"
606  [(set (match_operand:SI 0 "register_operand"                            "=d")
607        (truncate:SI
608         (lshiftrt:DI
609          (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand"  "d"))
610                   (sign_extend:DI (match_operand:SI 2 "register_operand"  "d"))
611)
612          (const_int 32))))]
613  "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
614  "mulhsu\t%0,%2,%1"
615  [(set_attr "type"     "imul")
616  (set_attr "mode"      "SI")
617  (set_attr "length"    "4")])
618
619
620;;----------------------------------------------------------------
621;; Division and remainder
622;;----------------------------------------------------------------
623(define_expand "divsi3"
624  [(set (match_operand:SI 0 "register_operand" "=d")
625	(div:SI (match_operand:SI 1 "register_operand" "d")
626                (match_operand:SI 2 "register_operand" "d")))
627  ]
628  "(!TARGET_SOFT_DIV) || (TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)"
629  {
630    if (TARGET_SOFT_DIV && TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)
631      {
632        microblaze_expand_divide (operands);
633        DONE;
634      }
635    else if (!TARGET_SOFT_DIV)
636      {
637        emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2]));
638        DONE;
639      }
640  }
641)
642
643
644(define_insn "divsi3_internal"
645  [(set (match_operand:SI 0 "register_operand" "=d")
646	(div:SI (match_operand:SI 1 "register_operand" "d")
647		(match_operand:SI 2 "register_operand" "d")))
648  ]
649  "!TARGET_SOFT_DIV"
650  "idiv\t%0,%2,%1"
651  [(set_attr "type"	"idiv")
652  (set_attr "mode"	"SI")
653  (set_attr "length"	"4")]
654)
655
656(define_insn "udivsi3"
657  [(set (match_operand:SI 0 "register_operand" "=d")
658	(udiv:SI (match_operand:SI 1 "register_operand" "d")
659                 (match_operand:SI 2 "register_operand" "d")))
660  ]
661  "!TARGET_SOFT_DIV"
662  "idivu\t%0,%2,%1"
663  [(set_attr "type"	"idiv")
664  (set_attr "mode"	"SI")
665  (set_attr "length"	"4")])
666
667
668;;----------------------------------------------------------------
669;; Negation and one's complement
670;;----------------------------------------------------------------
671
672(define_insn "negsi2"
673  [(set (match_operand:SI 0 "register_operand" "=d")
674	(neg:SI (match_operand:SI 1 "register_operand" "d")))]
675  ""
676  "rsubk\t%0,%1,r0"
677  [(set_attr "type"	"arith")
678  (set_attr "mode"	"SI")
679  (set_attr "length"	"4")])
680
681(define_insn "negdi2"
682  [(set (match_operand:DI 0 "register_operand" "=d")
683	(neg:DI (match_operand:DI 1 "register_operand" "d")))]
684  ""
685  "rsub\t%L0,%L1,r0\;rsubc\t%M0,%M1,r0"
686  [(set_attr "type"	"darith")
687  (set_attr "mode"	"DI")
688  (set_attr "length"	"8")])
689
690
691(define_insn "one_cmplsi2"
692  [(set (match_operand:SI 0 "register_operand" "=d")
693	(not:SI (match_operand:SI 1 "register_operand" "d")))]
694  ""
695  "xori\t%0,%1,-1"
696  [(set_attr "type"	"arith")
697  (set_attr "mode"	"SI")
698  (set_attr "length"	"4")])
699
700(define_insn "*one_cmpldi2"
701  [(set (match_operand:DI 0 "register_operand" "=d")
702	(not:DI (match_operand:DI 1 "register_operand" "d")))]
703  ""
704  "nor\t%M0,r0,%M1\;nor\t%L0,r0,%L1"
705  [(set_attr "type"	"darith")
706  (set_attr "mode"	"DI")
707  (set_attr "length"    "8")]
708)
709
710(define_split
711  [(set (match_operand:DI 0 "register_operand" "")
712	(not:DI (match_operand:DI 1 "register_operand" "")))]
713  "reload_completed
714   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
715   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
716
717  [(set (subreg:SI (match_dup 0) 0) (not:SI (subreg:SI (match_dup 1) 0)))
718  (set (subreg:SI (match_dup 0) 4) (not:SI (subreg:SI (match_dup 1) 4)))]
719  "")
720
721
722;;----------------------------------------------------------------
723;; Logical
724;;----------------------------------------------------------------
725
726(define_insn "andsi3"
727  [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
728	(and:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
729		(match_operand:SI 2 "arith_operand" "d,I,i,M")))]
730  ""
731  "@
732   and\t%0,%1,%2
733   andi\t%0,%1,%2 #and1
734   andi\t%0,%1,%2 #and2
735   andi\t%0,%1,%2 #and3"
736  [(set_attr "type"	"arith,arith,no_delay_arith,no_delay_arith")
737  (set_attr "mode"	"SI,SI,SI,SI")
738  (set_attr "length"	"4,8,8,8")])
739
740
741(define_insn "iorsi3"
742  [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
743	(ior:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
744		(match_operand:SI 2 "arith_operand" "d,I,M,i")))]
745  ""
746  "@
747   or\t%0,%1,%2
748   ori\t%0,%1,%2
749   ori\t%0,%1,%2
750   ori\t%0,%1,%2"
751  [(set_attr "type"	"arith,no_delay_arith,no_delay_arith,no_delay_arith")
752  (set_attr "mode"	"SI,SI,SI,SI")
753  (set_attr "length"	"4,8,8,8")])
754
755(define_insn "xorsi3"
756  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
757	(xor:SI (match_operand:SI 1 "arith_operand" "%d,d,d")
758		(match_operand:SI 2 "arith_operand" "d,I,i")))]
759  ""
760  "@
761   xor\t%0,%1,%2
762   xori\t%0,%1,%2
763   xori\t%0,%1,%2"
764  [(set_attr "type"	"arith,arith,no_delay_arith")
765  (set_attr "mode"	"SI,SI,SI")
766  (set_attr "length"	"4,8,8")])
767
768;;----------------------------------------------------------------
769;; Zero extension
770;;----------------------------------------------------------------
771
772(define_insn "zero_extendhisi2"
773  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
774	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
775  ""
776  "@
777  andi\t%0,%1,0xffff
778  lhu%i1\t%0,%1
779  lhu%i1\t%0,%1"
780  [(set_attr "type"	"no_delay_arith,load,no_delay_load")
781  (set_attr "mode"	"SI,SI,SI")
782  (set_attr "length"	"8,4,8")])
783
784(define_insn "zero_extendqihi2"
785  [(set (match_operand:HI 0 "register_operand" "=d,d,d")
786	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
787  ""
788  "@
789  andi\t%0,%1,0x00ff
790  lbu%i1\t%0,%1
791  lbu%i1\t%0,%1"
792  [(set_attr "type"	"arith,load,no_delay_load")
793  (set_attr "mode"	"HI")
794  (set_attr "length"	"4,4,8")])
795
796(define_insn "zero_extendqisi2"
797  [(set (match_operand:SI 0 "register_operand" "=d,d,d")
798	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
799  ""
800  "@
801  andi\t%0,%1,0x00ff
802  lbu%i1\t%0,%1
803  lbu%i1\t%0,%1"
804  [(set_attr "type"	"arith,load,no_delay_load")
805  (set_attr "mode"	"SI,SI,SI")
806  (set_attr "length"	"4,4,8")])
807
808;;----------------------------------------------------------------
809;; Sign extension
810;;----------------------------------------------------------------
811
812;; basic Sign Extend Operations
813
814(define_insn "extendqisi2"
815  [(set (match_operand:SI 0 "register_operand" "=d")
816	(sign_extend:SI (match_operand:QI 1 "register_operand" "d")))]
817  ""
818  "sext8\t%0,%1"
819  [(set_attr "type"	"arith")
820  (set_attr "mode"	"SI")
821  (set_attr "length"	"4")])
822
823(define_insn "extendhisi2"
824  [(set (match_operand:SI 0 "register_operand" "=d")
825	(sign_extend:SI (match_operand:HI 1 "register_operand" "d")))]
826  ""
827  "sext16\t%0,%1"
828  [(set_attr "type"	"arith")
829  (set_attr "mode"	"SI")
830  (set_attr "length"	"4")])
831
832;; Those for integer source operand are ordered
833;; widest source type first.
834
835(define_insn "extendsidi2"
836  [(set (match_operand:DI 0 "register_operand" "=d,d,d")
837	(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
838  ""
839  {
840     if (which_alternative == 0)
841       output_asm_insn ("addk\t%L0,r0,%1", operands);
842     else
843       output_asm_insn ("lw%i1\t%L0,%1", operands);
844
845     output_asm_insn ("add\t%M0,%L0,%L0", operands);
846     output_asm_insn ("addc\t%M0,r0,r0", operands);
847     output_asm_insn ("beqi\t%M0,.+8", operands);
848     return "addi\t%M0,r0,0xffffffff";
849  }
850  [(set_attr "type"	"multi,multi,multi")
851  (set_attr "mode"	"DI")
852  (set_attr "length"	"20,20,20")])
853
854;;----------------------------------------------------------------
855;; Data movement
856;;----------------------------------------------------------------
857
858;; 64-bit integer moves
859
860;; Unlike most other insns, the move insns can't be split with
861;; different predicates, because register spilling and other parts of
862;; the compiler, have memoized the insn number already.
863
864(define_expand "movdi"
865  [(set (match_operand:DI 0 "nonimmediate_operand" "")
866	(match_operand:DI 1 "general_operand" ""))]
867  ""
868  {
869    /* If operands[1] is a constant address illegal for pic, then we need to
870       handle it just like microblaze_legitimize_address does.  */
871    if (flag_pic && pic_address_needs_scratch (operands[1]))
872    {
873        rtx temp = force_reg (DImode, XEXP (XEXP (operands[1], 0), 0));
874        rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
875        emit_move_insn (operands[0], gen_rtx_PLUS (DImode, temp, temp2));
876        DONE;
877    }
878
879
880    if ((reload_in_progress | reload_completed) == 0
881        && !register_operand (operands[0], DImode)
882        && !register_operand (operands[1], DImode)
883        && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
884	       && operands[1] != CONST0_RTX (DImode))))
885    {
886
887      rtx temp = force_reg (DImode, operands[1]);
888      emit_move_insn (operands[0], temp);
889      DONE;
890    }
891  }
892)
893
894
895
896(define_insn "*movdi_internal"
897  [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,o")
898	(match_operand:DI 1 "general_operand"      " d,i,J,R,o,d,d"))]
899  ""
900  {
901    switch (which_alternative)
902    {
903      case 0:
904        return "addk\t%0,%1\n\taddk\t%D0,%d1";
905      case 1:
906	return "addik\t%M0,r0,%h1\n\taddik\t%L0,r0,%j1 #li => la";
907      case 2:
908	  return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
909      case 3:
910      case 4:
911        if (reg_mentioned_p (operands[0], operands[1]))
912          return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
913	else
914	  return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
915      case 5:
916      case 6:
917        return "swi\t%1,%0\n\tswi\t%D1,%o0";
918    }
919    return "unreachable";
920  }
921  [(set_attr "type"	"no_delay_move,no_delay_arith,no_delay_arith,no_delay_load,no_delay_load,no_delay_store,no_delay_store")
922  (set_attr "mode"	"DI")
923  (set_attr "length"   "8,8,8,8,12,8,12")])
924
925(define_split
926  [(set (match_operand:DI 0 "register_operand" "")
927	(match_operand:DI 1 "register_operand" ""))]
928  "reload_completed
929   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
930   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
931   && (REGNO(operands[0]) == (REGNO(operands[1]) + 1))"
932
933  [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
934  (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
935  "")
936
937(define_split
938  [(set (match_operand:DI 0 "register_operand" "")
939	(match_operand:DI 1 "register_operand" ""))]
940  "reload_completed
941   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
942   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
943   && (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
944
945  [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
946  (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
947  "")
948
949;; Unlike most other insns, the move insns can't be split with
950;; different predicates, because register spilling and other parts of
951;; the compiler, have memoized the insn number already.
952
953(define_expand "movsi"
954  [(set (match_operand:SI 0 "nonimmediate_operand" "")
955	(match_operand:SI 1 "general_operand" ""))]
956  ""
957  {
958    if (microblaze_expand_move (SImode, operands)) DONE;
959  }
960)
961
962;; Added for status registers
963(define_insn "movsi_status"
964  [(set (match_operand:SI 0 "register_operand" "=d,d,z")
965        (match_operand:SI 1 "register_operand" "z,d,d"))]
966  "microblaze_is_interrupt_variant ()"
967  "@
968	mfs\t%0,%1  #mfs
969	addk\t%0,%1,r0 #add movsi
970	mts\t%0,%1  #mts"
971  [(set_attr "type" "move")
972  (set_attr "mode" "SI")
973  (set_attr "length" "12")])
974
975;; This move will be not be moved to delay slot.
976(define_insn "*movsi_internal3"
977  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d")
978	(match_operand:SI 1 "immediate_operand" "J,I,Mnis"))]
979  "(register_operand (operands[0], SImode) &&
980           (GET_CODE (operands[1]) == CONST_INT &&
981                 (INTVAL (operands[1]) <= 32767 && INTVAL (operands[1]) >= -32768)))"
982  "@
983   addk\t%0,r0,r0
984   addik\t%0,r0,%1\t# %X1
985   addik\t%0,r0,%1\t# %X1"
986  [(set_attr "type"	"arith,arith,no_delay_arith")
987  (set_attr "mode"	"SI")
988  (set_attr "length"	"4")])
989
990;; This move may be used for PLT label operand
991(define_insn "*movsi_internal5_pltop"
992  [(set (match_operand:SI 0 "register_operand" "=d,d")
993	(match_operand:SI 1 "call_insn_operand" ""))]
994  "(register_operand (operands[0], Pmode) &&
995           PLT_ADDR_P (operands[1]))"
996  {
997     gcc_unreachable ();
998  }
999  [(set_attr "type"	"load")
1000  (set_attr "mode"	"SI")
1001  (set_attr "length"	"4")])
1002
1003(define_insn "*movsi_internal2"
1004  [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d,   d,d,R,m")
1005	(match_operand:SI 1 "move_src_operand"         " d,I,Mnis,R,m,dJ,dJ"))]
1006  ""
1007  "@
1008   addk\t%0,%1,r0
1009   addik\t%0,r0,%1\t# %X1
1010   addik\t%0,%a1
1011   lw%i1\t%0,%1
1012   lw%i1\t%0,%1
1013   sw%i0\t%z1,%0
1014   sw%i0\t%z1,%0"
1015  [(set_attr "type"	"load,load,no_delay_load,load,no_delay_load,store,no_delay_store")
1016  (set_attr "mode"	"SI")
1017  (set_attr "length"	"4,4,8,4,8,4,8")])
1018
1019
1020;; 16-bit Integer moves
1021
1022;; Unlike most other insns, the move insns can't be split with
1023;; different predicates, because register spilling and other parts of
1024;; the compiler, have memoized the insn number already.
1025;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
1026
1027(define_expand "movhi"
1028  [(set (match_operand:HI 0 "nonimmediate_operand" "")
1029	(match_operand:HI 1 "general_operand" ""))]
1030  ""
1031  {
1032    if ((reload_in_progress | reload_completed) == 0
1033        && !register_operand (operands[0], HImode)
1034        && !register_operand (operands[1], HImode)
1035        && ((GET_CODE (operands[1]) != CONST_INT
1036  	    || INTVAL (operands[1]) != 0)))
1037    {
1038        rtx temp = force_reg (HImode, operands[1]);
1039        emit_move_insn (operands[0], temp);
1040        DONE;
1041    }
1042  }
1043)
1044
1045(define_insn "*movhi_internal2"
1046  [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m")
1047	(match_operand:HI 1 "general_operand"       "I,d,R,m,dJ,dJ"))]
1048  ""
1049  "@
1050   addik\t%0,r0,%1\t# %X1
1051   addk\t%0,%1,r0
1052   lhui\t%0,%1
1053   lhui\t%0,%1
1054   sh%i0\t%z1,%0
1055   sh%i0\t%z1,%0"
1056  [(set_attr "type"	"arith,move,load,no_delay_load,store,no_delay_store")
1057  (set_attr "mode"	"HI")
1058  (set_attr "length"	"4,4,4,8,8,8")])
1059
1060;; 8-bit Integer moves
1061
1062;; Unlike most other insns, the move insns can't be split with
1063;; different predicates, because register spilling and other parts of
1064;; the compiler, have memoized the insn number already.
1065;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
1066
1067(define_expand "movqi"
1068  [(set (match_operand:QI 0 "nonimmediate_operand" "")
1069	(match_operand:QI 1 "general_operand" ""))]
1070  ""
1071  {
1072    if ((reload_in_progress | reload_completed) == 0
1073        && !register_operand (operands[0], QImode)
1074        && !register_operand (operands[1], QImode)
1075        && ((GET_CODE (operands[1]) != CONST_INT
1076            || INTVAL (operands[1]) != 0)))
1077    {
1078        rtx temp = force_reg (QImode, operands[1]);
1079        emit_move_insn (operands[0], temp);
1080        DONE;
1081    }
1082  }
1083)
1084
1085(define_insn "*movqi_internal2"
1086  [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
1087	(match_operand:QI 1 "general_operand"       "J,I,d,R,m,dJ,dJ"))]
1088  ""
1089  "@
1090   addk\t%0,r0,%z1
1091   addik\t%0,r0,%1\t# %X1
1092   addk\t%0,%1,r0
1093   lbu%i1\t%0,%1
1094   lbu%i1\t%0,%1
1095   sb%i0\t%z1,%0
1096   sbi\t%z1,%0"
1097  [(set_attr "type"	"arith,arith,move,load,no_delay_load,store,no_delay_store")
1098  (set_attr "mode"	"QI")
1099  (set_attr "length"	"4,4,8,4,8,4,8")])
1100
1101;; Block moves, see microblaze.c for more details.
1102;; Argument 0 is the destination
1103;; Argument 1 is the source
1104;; Argument 2 is the length
1105;; Argument 3 is the alignment
1106
1107(define_expand "movmemsi"
1108  [(parallel [(set (match_operand:BLK 0 "general_operand")
1109		   (match_operand:BLK 1 "general_operand"))
1110	      (use (match_operand:SI 2 ""))
1111	      (use (match_operand:SI 3 "const_int_operand"))])]
1112  ""
1113  {
1114    if (microblaze_expand_block_move (operands[0], operands[1],
1115				      operands[2], operands[3]))
1116        DONE;
1117    else
1118        FAIL;
1119  }
1120)
1121
1122;; 32-bit floating point moves
1123
1124(define_expand "movsf"
1125  [(set (match_operand:SF 0 "nonimmediate_operand" "")
1126        (match_operand:SF 1 "general_operand" ""))]
1127  ""
1128  {
1129    if ((reload_in_progress | reload_completed) == 0
1130        && !register_operand (operands[0], SFmode)
1131        && !register_operand (operands[1], SFmode)
1132        && ( ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
1133                 && operands[1] != CONST0_RTX (SFmode))))
1134    {
1135        rtx temp = force_reg (SFmode, operands[1]);
1136        emit_move_insn (operands[0], temp);
1137        DONE;
1138    }
1139  }
1140)
1141
1142;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
1143;;
1144(define_insn "*movsf_internal"
1145  [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
1146        (match_operand:SF 1 "general_operand" "G,d,R,F,m,d,d"))]
1147  "(register_operand (operands[0], SFmode)
1148       || register_operand (operands[1], SFmode)
1149       || operands[1] == CONST0_RTX (SFmode))"
1150  "@
1151   addk\t%0,r0,r0
1152   addk\t%0,%1,r0
1153   lw%i1\t%0,%1
1154   addik\t%0,r0,%F1
1155   lw%i1\t%0,%1
1156   sw%i0\t%z1,%0
1157   swi\t%z1,%0"
1158  [(set_attr "type"     "move,no_delay_load,load,no_delay_load,no_delay_load,store,no_delay_store")
1159  (set_attr "mode"      "SF")
1160  (set_attr "length"    "4,4,4,4,4,4,4")])
1161
1162;; 64-bit floating point moves
1163(define_expand "movdf"
1164  [(set (match_operand:DF 0 "nonimmediate_operand" "")
1165        (match_operand:DF 1 "general_operand" ""))]
1166  ""
1167  {
1168    if (flag_pic == 2) {
1169      if (GET_CODE (operands[1]) == MEM
1170          && !microblaze_legitimate_address_p (DFmode, XEXP (operands[1],0), 0))
1171      {
1172        rtx ptr_reg;
1173        rtx result;
1174        ptr_reg = force_reg (Pmode, XEXP (operands[1],0));
1175        result = gen_rtx_MEM (DFmode, ptr_reg);
1176        emit_move_insn (operands[0], result);
1177        DONE;
1178      }
1179    }
1180    if ((reload_in_progress | reload_completed) == 0
1181        && !register_operand (operands[0], DFmode)
1182        && !register_operand (operands[1], DFmode)
1183        && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
1184                 && operands[1] != CONST0_RTX (DFmode))))
1185    {
1186        rtx temp = force_reg (DFmode, operands[1]);
1187        emit_move_insn (operands[0], temp);
1188        DONE;
1189    }
1190  }
1191)
1192
1193;; movdf_internal
1194;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
1195;;
1196(define_insn "*movdf_internal"
1197  [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,o")
1198        (match_operand:DF 1 "general_operand" "dG,o,F,T,d"))]
1199  ""
1200  {
1201    switch (which_alternative)
1202    {
1203      case 0:
1204	return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
1205      case 1:
1206      case 3:
1207	if (reg_mentioned_p (operands[0], operands[1]))
1208          return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
1209        else
1210	  return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
1211      case 2:
1212      {
1213	return "addik\t%0,r0,%h1 \n\taddik\t%D0,r0,%j1 #Xfer Lo";
1214      }
1215      case 4:
1216	return "swi\t%1,%0\n\tswi\t%D1,%o0";
1217    }
1218    gcc_unreachable ();
1219  }
1220  [(set_attr "type"     "no_delay_move,no_delay_load,no_delay_load,no_delay_load,no_delay_store")
1221  (set_attr "mode"      "DF")
1222  (set_attr "length"    "4,8,8,16,8")])
1223
1224(define_split
1225  [(set (match_operand:DF 0 "register_operand" "")
1226        (match_operand:DF 1 "register_operand" ""))]
1227  "reload_completed
1228   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
1229   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
1230   && (REGNO (operands[0]) == (REGNO (operands[1]) + 1))"
1231  [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
1232  (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
1233  "")
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) 0) (subreg:SI (match_dup 1) 0))
1243  (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
1244  "")
1245
1246;;----------------------------------------------------------------
1247;; Shifts
1248;;----------------------------------------------------------------
1249
1250;;----------------------------------------------------------------
1251;; 32-bit left shifts
1252;;----------------------------------------------------------------
1253(define_expand "ashlsi3"
1254  [(set (match_operand:SI 0 "register_operand" "=&d")
1255	(ashift:SI (match_operand:SI 1 "register_operand" "d")
1256		   (match_operand:SI 2 "arith_operand" "")))]
1257  ""
1258  {
1259    /* Avoid recursion for trivial cases. */
1260    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1261      if (microblaze_expand_shift (operands))
1262        DONE;
1263  }
1264)
1265
1266;; Irrespective of if we have a barrel-shifter or not, we want to match
1267;; shifts by 1 with a special pattern. When a barrel shifter is present,
1268;; saves a cycle. If not, allows us to annotate the instruction for delay
1269;; slot optimization
1270(define_insn "*ashlsi3_byone"
1271  [(set (match_operand:SI 0 "register_operand" "=d")
1272	(ashift:SI (match_operand:SI 1 "register_operand" "d")
1273                   (match_operand:SI 2 "arith_operand"    "I")))]
1274  "(INTVAL (operands[2]) == 1)"
1275  "addk\t%0,%1,%1"
1276  [(set_attr "type"	"arith")
1277   (set_attr "mode"	"SI")
1278   (set_attr "length"	"4")]
1279)
1280
1281;; Barrel shift left
1282(define_insn "ashlsi3_bshift"
1283  [(set (match_operand:SI 0 "register_operand" "=d,d")
1284	(ashift:SI (match_operand:SI 1 "register_operand" "d,d")
1285                   (match_operand:SI 2 "arith_operand"    "I,d")))]
1286  "TARGET_BARREL_SHIFT"
1287  "@
1288  bslli\t%0,%1,%2
1289  bsll\t%0,%1,%2"
1290  [(set_attr "type"	"bshift,bshift")
1291  (set_attr "mode"	"SI,SI")
1292  (set_attr "length"	"4,4")]
1293)
1294
1295;; The following patterns apply when there is no barrel shifter present
1296
1297(define_insn "*ashlsi3_with_mul_delay"
1298  [(set (match_operand:SI 0 "register_operand" "=d")
1299	(ashift:SI (match_operand:SI 1 "register_operand"  "d")
1300                   (match_operand:SI 2 "immediate_operand" "I")))]
1301  "!TARGET_SOFT_MUL
1302   && ((1 << INTVAL (operands[2])) <= 32767 && (1 << INTVAL (operands[2])) >= -32768)"
1303  "muli\t%0,%1,%m2"
1304  ;; This MUL will not generate an imm. Can go into a delay slot.
1305  [(set_attr "type"	"arith")
1306   (set_attr "mode"	"SI")
1307   (set_attr "length"	"4")]
1308)
1309
1310(define_insn "*ashlsi3_with_mul_nodelay"
1311  [(set (match_operand:SI 0 "register_operand" "=d")
1312	(ashift:SI (match_operand:SI 1 "register_operand"  "d")
1313                   (match_operand:SI 2 "immediate_operand" "I")))]
1314  "!TARGET_SOFT_MUL"
1315  "muli\t%0,%1,%m2"
1316  ;; This MUL will generate an IMM. Cannot go into a delay slot
1317  [(set_attr "type"	"no_delay_arith")
1318   (set_attr "mode"	"SI")
1319   (set_attr "length"	"8")]
1320)
1321
1322(define_insn "*ashlsi3_with_size_opt"
1323  [(set (match_operand:SI 0 "register_operand" "=&d")
1324       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1325                   (match_operand:SI 2 "immediate_operand" "I")))]
1326  "(INTVAL (operands[2]) > 5 && optimize_size)"
1327  {
1328    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1329
1330    output_asm_insn ("ori\t%3,r0,%2", operands);
1331    if (REGNO (operands[0]) != REGNO (operands[1]))
1332        output_asm_insn ("addk\t%0,%1,r0", operands);
1333
1334    output_asm_insn ("addik\t%3,%3,-1", operands);
1335    output_asm_insn ("bneid\t%3,.-4", operands);
1336    return "addk\t%0,%0,%0";
1337  }
1338  [(set_attr "type"    "multi")
1339   (set_attr "mode"    "SI")
1340   (set_attr "length"  "20")]
1341)
1342
1343(define_insn "*ashlsi3_with_rotate"
1344  [(set (match_operand:SI 0 "register_operand" "=&d")
1345       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1346                   (match_operand:SI 2 "immediate_operand" "I")))]
1347  "(INTVAL (operands[2]) > 17 && !optimize_size)"
1348  {
1349    int i, nshift;
1350
1351    nshift = INTVAL (operands[2]);
1352    operands[3] = gen_int_mode (0xFFFFFFFF << nshift, SImode);
1353
1354    /* We do one extra shift so that the first bit (carry) coming into the MSB
1355       will be masked out */
1356    output_asm_insn ("src\t%0,%1", operands);
1357    for (i = 0; i < (32 - nshift); i++)
1358       output_asm_insn ("src\t%0,%0", operands);
1359
1360    return "andi\t%0,%0,%3";
1361  }
1362  [(set_attr "type"    "multi")
1363  (set_attr "mode"     "SI")
1364  (set_attr "length"   "80")]
1365)
1366
1367(define_insn "*ashlsi_inline"
1368  [(set (match_operand:SI 0 "register_operand" "=&d")
1369       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1370                   (match_operand:SI 2 "immediate_operand" "I")))]
1371  ""
1372  {
1373    int i;
1374    int nshift = INTVAL (operands[2]);
1375    if (REGNO (operands[0]) != REGNO (operands[1]))
1376      output_asm_insn ("addk\t%0,r0,%1", operands);
1377    output_asm_insn ("addk\t%0,%1,%1", operands);
1378    for (i = 0; i < (nshift - 2); i++)
1379      output_asm_insn ("addk\t%0,%0,%0", operands);
1380    return "addk\t%0,%0,%0";
1381  }
1382  [(set_attr "type"    "multi")
1383  (set_attr "mode"     "SI")
1384  (set_attr "length"   "124")]
1385)
1386
1387(define_insn "*ashlsi_reg"
1388  [(set (match_operand:SI 0 "register_operand" "=&d")
1389       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1390                   (match_operand:SI 2 "register_operand" "d")))]
1391  ""
1392  {
1393    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1394    output_asm_insn ("andi\t%3,%2,31", operands);
1395    if (REGNO (operands[0]) != REGNO (operands[1]))
1396      output_asm_insn ("addk\t%0,r0,%1", operands);
1397    /* Exit the loop if zero shift. */
1398    output_asm_insn ("beqid\t%3,.+20", operands);
1399    /* Emit the loop.  */
1400    output_asm_insn ("addk\t%0,%0,r0", operands);
1401    output_asm_insn ("addik\t%3,%3,-1", operands);
1402    output_asm_insn ("bneid\t%3,.-4", operands);
1403    return "addk\t%0,%0,%0";
1404  }
1405  [(set_attr "type"    "multi")
1406  (set_attr "mode"     "SI")
1407  (set_attr "length"   "28")]
1408)
1409
1410
1411;;----------------------------------------------------------------
1412;; 32-bit right shifts
1413;;----------------------------------------------------------------
1414(define_expand "ashrsi3"
1415  [(set (match_operand:SI 0 "register_operand" "=&d")
1416	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
1417                     (match_operand:SI 2 "arith_operand" "")))]
1418  ""
1419  {
1420    /* Avoid recursion for trivial cases. */
1421    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1422      if (microblaze_expand_shift (operands))
1423        DONE;
1424  }
1425)
1426
1427;; Irrespective of if we have a barrel-shifter or not, we want to match
1428;; shifts by 1 with a special pattern. When a barrel shifter is present,
1429;; saves a cycle. If not, allows us to annotate the instruction for delay
1430;; slot optimization
1431(define_insn "*ashrsi3_byone"
1432  [(set (match_operand:SI 0 "register_operand" "=d")
1433	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
1434                     (match_operand:SI 2 "arith_operand"    "I")))]
1435  "(INTVAL (operands[2]) == 1)"
1436  "sra\t%0,%1"
1437  [(set_attr "type"	"arith")
1438   (set_attr "mode"	"SI")
1439   (set_attr "length"	"4")]
1440)
1441
1442;; Barrel shift right logical
1443(define_insn "*ashrsi3_bshift"
1444  [(set (match_operand:SI 0 "register_operand" "=d,d")
1445	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
1446                     (match_operand:SI 2 "arith_operand"    "I,d")))]
1447  "TARGET_BARREL_SHIFT"
1448  "@
1449  bsrai\t%0,%1,%2
1450  bsra\t%0,%1,%2"
1451  [(set_attr "type"	"bshift,bshift")
1452  (set_attr "mode"	"SI,SI")
1453  (set_attr "length"	"4,4")]
1454)
1455
1456(define_insn "*ashrsi_inline"
1457  [(set (match_operand:SI 0 "register_operand" "=&d")
1458       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1459                   (match_operand:SI 2 "immediate_operand" "I")))]
1460  ""
1461  {
1462    int i;
1463    int nshift = INTVAL (operands[2]);
1464    if (REGNO (operands[0]) != REGNO (operands[1]))
1465      output_asm_insn ("addk\t%0,r0,%1", operands);
1466    output_asm_insn ("sra\t%0,%1", operands);
1467    for (i = 0; i < (nshift - 2); i++)
1468      output_asm_insn ("sra\t%0,%0", operands);
1469    return "sra\t%0,%0";
1470  }
1471  [(set_attr "type"    "multi")
1472  (set_attr "mode"     "SI")
1473  (set_attr "length"   "124")]
1474)
1475
1476(define_insn "*ashrsi_reg"
1477  [(set (match_operand:SI 0 "register_operand" "=&d")
1478       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1479                   (match_operand:SI 2 "register_operand" "d")))]
1480  ""
1481  {
1482    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1483    output_asm_insn ("andi\t%3,%2,31", operands);
1484    if (REGNO (operands[0]) != REGNO (operands[1]))
1485      output_asm_insn ("addk\t%0,r0,%1", operands);
1486    /* Exit the loop if zero shift. */
1487    output_asm_insn ("beqid\t%3,.+20", operands);
1488    /* Emit the loop.  */
1489    output_asm_insn ("addk\t%0,%0,r0", operands);
1490    output_asm_insn ("addik\t%3,%3,-1", operands);
1491    output_asm_insn ("bneid\t%3,.-4", operands);
1492    return "sra\t%0,%0";
1493  }
1494  [(set_attr "type"    "multi")
1495  (set_attr "mode"     "SI")
1496  (set_attr "length"   "28")]
1497)
1498
1499;;----------------------------------------------------------------
1500;; 32-bit right shifts (logical)
1501;;----------------------------------------------------------------
1502
1503(define_expand "lshrsi3"
1504  [(set (match_operand:SI 0 "register_operand" "=&d")
1505	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
1506                     (match_operand:SI 2 "arith_operand" "")))]
1507  ""
1508  {
1509    /* Avoid recursion for trivial cases. */
1510    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1511      if (microblaze_expand_shift (operands))
1512        DONE;
1513  }
1514)
1515
1516;; Irrespective of if we have a barrel-shifter or not, we want to match
1517;; shifts by 1 with a special pattern. When a barrel shifter is present,
1518;; saves a cycle. If not, allows us to annotate the instruction for delay
1519;; slot optimization
1520(define_insn "*lshrsi3_byone"
1521  [(set (match_operand:SI 0 "register_operand" "=d")
1522	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
1523                     (match_operand:SI 2 "arith_operand"    "I")))]
1524  "(INTVAL (operands[2]) == 1)"
1525  "srl\t%0,%1"
1526  [(set_attr "type"	"arith")
1527   (set_attr "mode"	"SI")
1528   (set_attr "length"	"4")]
1529)
1530
1531;; Barrel shift right logical
1532(define_insn "*lshrsi3_bshift"
1533  [(set (match_operand:SI 0 "register_operand" "=d,d")
1534	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
1535                     (match_operand:SI 2 "arith_operand"    "I,d")))]
1536  "TARGET_BARREL_SHIFT"
1537  "@
1538  bsrli\t%0,%1,%2
1539  bsrl\t%0,%1,%2"
1540  [(set_attr "type"	"bshift,bshift")
1541  (set_attr "mode"	"SI,SI")
1542  (set_attr "length"	"4,4")]
1543)
1544
1545(define_insn "*lshrsi_inline"
1546  [(set (match_operand:SI 0 "register_operand" "=&d")
1547       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1548                   (match_operand:SI 2 "immediate_operand" "I")))]
1549  ""
1550  {
1551    int i;
1552    int nshift = INTVAL (operands[2]);
1553    if (REGNO (operands[0]) != REGNO (operands[1]))
1554      output_asm_insn ("addk\t%0,r0,%1", operands);
1555    output_asm_insn ("srl\t%0,%1", operands);
1556    for (i = 0; i < (nshift - 2); i++)
1557      output_asm_insn ("srl\t%0,%0", operands);
1558    return "srl\t%0,%0";
1559  }
1560  [(set_attr "type"    "multi")
1561  (set_attr "mode"     "SI")
1562  (set_attr "length"   "124")]
1563)
1564
1565(define_insn "*lshrsi_reg"
1566  [(set (match_operand:SI 0 "register_operand" "=&d")
1567       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1568                   (match_operand:SI 2 "register_operand" "d")))]
1569  ""
1570  {
1571    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1572    output_asm_insn ("andi\t%3,%2,31", operands);
1573    if (REGNO (operands[0]) != REGNO (operands[1]))
1574      output_asm_insn ("addk\t%0,r0,%1", operands);
1575    /* Exit the loop if zero shift. */
1576    output_asm_insn ("beqid\t%3,.+20", operands);
1577    /* Emit the loop.  */
1578    output_asm_insn ("addk\t%0,%0,r0", operands);
1579    output_asm_insn ("addik\t%3,%3,-1", operands);
1580    output_asm_insn ("bneid\t%3,.-4", operands);
1581    return "srl\t%0,%0";
1582  }
1583  [(set_attr "type"    "multi")
1584  (set_attr "mode"     "SI")
1585  (set_attr "length"   "28")]
1586)
1587
1588;;----------------------------------------------------------------
1589;; Setting a register from an integer comparison.
1590;;----------------------------------------------------------------
1591(define_expand "cstoresi4"
1592   [(set (match_operand:SI 0 "register_operand")
1593        (match_operator:SI 1 "ordered_comparison_operator"
1594	      [(match_operand:SI 2 "register_operand")
1595	       (match_operand:SI 3 "register_operand")]))]
1596  "TARGET_PATTERN_COMPARE"
1597  "if (GET_CODE (operand1) != EQ && GET_CODE (operand1) != NE)
1598     FAIL;
1599  "
1600)
1601
1602(define_insn "seq_internal_pat"
1603  [(set (match_operand:SI 0 "register_operand" "=d")
1604	(eq:SI
1605	       (match_operand:SI 1 "register_operand" "d")
1606	       (match_operand:SI 2 "register_operand" "d")))]
1607  "TARGET_PATTERN_COMPARE"
1608  "pcmpeq\t%0,%1,%2"
1609  [(set_attr "type"	"arith")
1610   (set_attr "mode"	"SI")
1611   (set_attr "length"	"4")]
1612)
1613
1614(define_insn "sne_internal_pat"
1615  [(set (match_operand:SI 0 "register_operand" "=d")
1616	(ne:SI
1617	       (match_operand:SI 1 "register_operand" "d")
1618	       (match_operand:SI 2 "register_operand" "d")))]
1619  "TARGET_PATTERN_COMPARE"
1620  "pcmpne\t%0,%1,%2"
1621  [(set_attr "type"	"arith")
1622  (set_attr "mode"	"SI")
1623  (set_attr "length"	"4")]
1624)
1625
1626;;----------------------------------------------------------------
1627;; Setting a register from an floating point comparison.
1628;;----------------------------------------------------------------
1629(define_insn "cstoresf4"
1630   [(set (match_operand:SI 0 "register_operand" "=r")
1631        (match_operator:SI 1 "ordered_comparison_operator"
1632	      [(match_operand:SF 2 "register_operand" "r")
1633	       (match_operand:SF 3 "register_operand" "r")]))]
1634  "TARGET_HARD_FLOAT"
1635  "fcmp.%C1\t%0,%3,%2"
1636  [(set_attr "type"     "fcmp")
1637   (set_attr "mode"      "SF")
1638   (set_attr "length"    "4")]
1639)
1640
1641;;----------------------------------------------------------------
1642;; Conditional branches
1643;;----------------------------------------------------------------
1644
1645(define_expand "cbranchsi4"
1646  [(set (pc)
1647	(if_then_else (match_operator 0 "ordered_comparison_operator"
1648		       [(match_operand:SI 1 "register_operand")
1649		        (match_operand:SI 2 "arith_operand")])
1650		      (label_ref (match_operand 3 ""))
1651		      (pc)))]
1652  ""
1653{
1654  microblaze_expand_conditional_branch (SImode, operands);
1655  DONE;
1656})
1657
1658(define_expand "cbranchsf4"
1659  [(set (pc)
1660	(if_then_else (match_operator 0 "ordered_comparison_operator"
1661		       [(match_operand:SF 1 "register_operand")
1662		        (match_operand:SF 2 "register_operand")])
1663		      (label_ref (match_operand 3 ""))
1664		      (pc)))]
1665  "TARGET_HARD_FLOAT"
1666{
1667  microblaze_expand_conditional_branch_sf (operands);
1668  DONE;
1669
1670})
1671
1672;; Used to implement comparison instructions
1673(define_expand "condjump"
1674  [(set (pc)
1675	(if_then_else (match_operand 0)
1676		      (label_ref (match_operand 1))
1677		      (pc)))])
1678
1679(define_insn "branch_zero"
1680  [(set (pc)
1681	(if_then_else (match_operator:SI 0 "ordered_comparison_operator"
1682  				 [(match_operand:SI 1 "register_operand" "d")
1683                                  (const_int 0)])
1684                      (match_operand:SI 2 "pc_or_label_operand" "")
1685                      (match_operand:SI 3 "pc_or_label_operand" "")))
1686  ]
1687  ""
1688  {
1689    if (operands[3] == pc_rtx)
1690      return "b%C0i%?\t%z1,%2";
1691    else
1692      return "b%N0i%?\t%z1,%3";
1693  }
1694  [(set_attr "type"	"branch")
1695   (set_attr "mode"	"none")
1696   (set_attr "length"	"4")]
1697)
1698
1699(define_insn "branch_compare"
1700  [(set (pc)
1701        (if_then_else (match_operator:SI 0 "cmp_op"
1702                                         [(match_operand:SI 1 "register_operand" "d")
1703                                          (match_operand:SI 2 "register_operand" "d")
1704                                         ])
1705                      (label_ref (match_operand 3))
1706                      (pc)))
1707  (clobber(reg:SI R_TMP))]
1708  ""
1709  {
1710    operands[4] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1711    enum rtx_code code = GET_CODE (operands[0]);
1712
1713    if (code == GT || code == LE)
1714      {
1715        output_asm_insn ("cmp\tr18,%z1,%z2", operands);
1716        code = swap_condition (code);
1717      }
1718    else if (code == GTU || code == LEU)
1719      {
1720        output_asm_insn ("cmpu\tr18,%z1,%z2", operands);
1721        code = swap_condition (code);
1722      }
1723    else if (code == GE || code == LT)
1724      {
1725        output_asm_insn ("cmp\tr18,%z2,%z1", operands);
1726      }
1727    else if (code == GEU || code == LTU)
1728      {
1729        output_asm_insn ("cmpu\tr18,%z2,%z1", operands);
1730      }
1731
1732    operands[0] = gen_rtx_fmt_ee (signed_condition (code), SImode, operands[4], const0_rtx);
1733    return "b%C0i%?\tr18,%3";
1734  }
1735  [(set_attr "type"     "branch")
1736   (set_attr "mode"     "none")
1737   (set_attr "length"   "12")]
1738)
1739
1740;;----------------------------------------------------------------
1741;; Unconditional branches
1742;;----------------------------------------------------------------
1743(define_insn "jump"
1744  [(set (pc)
1745	(label_ref (match_operand 0 "" "")))]
1746  ""
1747  {
1748    if (GET_CODE (operands[0]) == REG)
1749        return "br%?\t%0";
1750    else
1751        return "bri%?\t%l0";
1752  }
1753  [(set_attr "type"	"jump")
1754  (set_attr "mode"	"none")
1755  (set_attr "length"	"4")])
1756
1757(define_expand "indirect_jump"
1758  [(set (pc) (match_operand 0 "register_operand" "d"))]
1759  ""
1760  {
1761    rtx dest = operands[0];
1762    if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode)
1763      operands[0] = copy_to_mode_reg (Pmode, dest);
1764
1765    emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
1766    DONE;
1767  }
1768)
1769
1770;; Indirect jumps. Jump to register values. Assuming absolute jumps
1771
1772(define_insn "indirect_jump_internal1"
1773  [(set (pc) (match_operand:SI 0 "register_operand" "d"))]
1774  ""
1775  "bra%?\t%0"
1776  [(set_attr "type"	"jump")
1777  (set_attr "mode"	"none")
1778  (set_attr "length"	"4")])
1779
1780(define_expand "tablejump"
1781  [(set (pc)
1782	(match_operand 0 "register_operand" "d"))
1783  (use (label_ref (match_operand 1 "" "")))]
1784  ""
1785  {
1786    gcc_assert (GET_MODE (operands[0]) == Pmode);
1787
1788    if (!flag_pic)
1789      emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
1790    else
1791      emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
1792    DONE;
1793  }
1794)
1795
1796(define_insn "tablejump_internal1"
1797  [(set (pc)
1798	(match_operand:SI 0 "register_operand" "d"))
1799  (use (label_ref (match_operand 1 "" "")))]
1800  ""
1801  "bra%?\t%0 "
1802  [(set_attr "type"	"jump")
1803  (set_attr "mode"	"none")
1804  (set_attr "length"	"4")])
1805
1806(define_expand "tablejump_internal3"
1807  [(parallel [(set (pc)
1808		   (plus:SI (match_operand:SI 0 "register_operand" "d")
1809			    (label_ref:SI (match_operand:SI 1 "" ""))))
1810             (use (label_ref:SI (match_dup 1)))])]
1811  ""
1812  ""
1813)
1814
1815;; need to change for MicroBlaze PIC
1816(define_insn ""
1817 [(set (pc)
1818	(plus:SI (match_operand:SI 0 "register_operand" "d")
1819		 (label_ref:SI (match_operand 1 "" ""))))
1820  (use (label_ref:SI (match_dup 1)))]
1821 "next_active_insn (insn) != 0
1822  && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
1823  && PREV_INSN (next_active_insn (insn)) == operands[1]
1824  && flag_pic"
1825  {
1826    output_asm_insn ("addk\t%0,%0,r20",operands);
1827    return "bra%?\t%0";
1828}
1829 [(set_attr "type"	"jump")
1830  (set_attr "mode"	"none")
1831  (set_attr "length"	"4")])
1832
1833(define_expand "tablejump_internal4"
1834  [(parallel [(set (pc)
1835		   (plus:DI (match_operand:DI 0 "register_operand" "d")
1836			    (label_ref:DI (match_operand:SI 1 "" ""))))
1837             (use (label_ref:DI (match_dup 1)))])]
1838  ""
1839  ""
1840)
1841
1842;;----------------------------------------------------------------
1843;; Function prologue/epilogue and stack allocation
1844;;----------------------------------------------------------------
1845(define_expand "prologue"
1846  [(const_int 1)]
1847  ""
1848  {
1849      microblaze_expand_prologue ();
1850      DONE;
1851  }
1852)
1853
1854(define_expand "epilogue"
1855  [(use (const_int 0))]
1856  ""
1857  {
1858      microblaze_expand_epilogue ();
1859      DONE;
1860  }
1861)
1862
1863;; An insn to allocate new stack space for dynamic use (e.g., alloca).
1864;; We copy the return address, decrement the stack pointer and save the
1865;; return address again at the new stack top
1866
1867(define_expand "allocate_stack"
1868  [(set (match_operand 0 "register_operand" "=r")
1869	(minus (reg 1) (match_operand 1 "register_operand" "")))
1870   (set (reg 1)
1871	(minus (reg 1) (match_dup 1)))]
1872  ""
1873  {
1874    rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
1875    rtx rtmp    = gen_rtx_REG (SImode, R_TMP);
1876    rtx neg_op0;
1877
1878    emit_move_insn (rtmp, retaddr);
1879    if (GET_CODE (operands[1]) != CONST_INT)
1880    {
1881        neg_op0 = gen_reg_rtx (Pmode);
1882	emit_insn (gen_negsi2 (neg_op0, operands[1]));
1883    } else
1884        neg_op0 = GEN_INT (- INTVAL (operands[1]));
1885
1886    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
1887    emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), rtmp);
1888    emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
1889    emit_insn (gen_rtx_CLOBBER (SImode, rtmp));
1890    DONE;
1891  }
1892)
1893
1894(define_expand "save_stack_block"
1895  [(match_operand 0 "register_operand" "")
1896   (match_operand 1 "register_operand" "")]
1897  ""
1898  {
1899    emit_move_insn (operands[0], operands[1]);
1900    DONE;
1901  }
1902)
1903
1904(define_expand "restore_stack_block"
1905  [(match_operand 0 "register_operand" "")
1906   (match_operand 1 "register_operand" "")]
1907  ""
1908  {
1909    rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
1910    rtx rtmp    = gen_rtx_REG (SImode, R_TMP);
1911
1912    /* Move the retaddr.  */
1913    emit_move_insn (rtmp, retaddr);
1914    emit_move_insn (operands[0], operands[1]);
1915    emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), rtmp);
1916    DONE;
1917  }
1918)
1919
1920;; Trivial return.  Make it look like a normal return insn as that
1921;; allows jump optimizations to work better .
1922(define_expand "return"
1923  [(simple_return)]
1924  "microblaze_can_use_return_insn ()"
1925  {}
1926)
1927
1928(define_expand "simple_return"
1929  [(simple_return)]
1930  ""
1931  {}
1932)
1933
1934(define_insn "*<optab>"
1935  [(any_return)]
1936  ""
1937  {
1938    if (microblaze_is_interrupt_variant ())
1939        return "rtid\tr14, 0\;%#";
1940    else
1941        return "rtsd\tr15, 8\;%#";
1942  }
1943  [(set_attr "type"	"jump")
1944  (set_attr "mode"	"none")
1945  (set_attr "length"	"4")]
1946)
1947
1948;; Normal return.
1949
1950(define_insn "<optab>_internal"
1951  [(any_return)
1952   (use (match_operand:SI 0 "register_operand" ""))]
1953  ""
1954  {
1955    if (microblaze_is_interrupt_variant ())
1956        return "rtid\tr14,0 \;%#";
1957    else
1958        return "rtsd\tr15,8 \;%#";
1959  }
1960  [(set_attr "type"	"jump")
1961  (set_attr "mode"	"none")
1962  (set_attr "length"	"4")])
1963
1964
1965;; Block any insns from across this point
1966;; Useful to group sequences together.
1967(define_insn "blockage"
1968  [(unspec_volatile [(const_int 0)] 0)]
1969  ""
1970  ""
1971  [(set_attr "type"	"unknown")
1972  (set_attr "mode"	"none")
1973  (set_attr "length"	"0")])
1974
1975
1976;;----------------------------------------------------------------
1977;; Function calls
1978;;----------------------------------------------------------------
1979
1980(define_expand "call"
1981  [(parallel [(call (match_operand 0 "memory_operand" "m")
1982		    (match_operand 1 "" "i"))
1983             (clobber (reg:SI R_SR))
1984             (use (match_operand 2 "" ""))
1985             (use (match_operand 3 "" ""))])]
1986  ""
1987  {
1988    rtx addr = XEXP (operands[0], 0);
1989
1990    if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
1991	&& !SYMBOL_REF_LOCAL_P (addr))
1992      {
1993        rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
1994        XEXP (operands[0], 0) = temp;
1995      }
1996
1997    if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
1998	|| !call_insn_operand (addr, VOIDmode))
1999      XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
2000
2001    if (GET_CODE (XEXP (operands[0], 0)) == UNSPEC)
2002      emit_call_insn (gen_call_internal_plt0 (operands[0], operands[1],
2003                        gen_rtx_REG (SImode,
2004				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
2005                               	     pic_offset_table_rtx));
2006    else
2007      emit_call_insn (gen_call_internal0 (operands[0], operands[1],
2008                        gen_rtx_REG (SImode,
2009				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2010
2011        DONE;
2012  }
2013)
2014
2015(define_expand "call_internal0"
2016  [(parallel [(call (match_operand 0 "" "")
2017		    (match_operand 1 "" ""))
2018             (clobber (match_operand:SI 2 "" ""))])]
2019  ""
2020  {
2021  }
2022)
2023
2024(define_expand "call_internal_plt0"
2025  [(parallel [(call (match_operand 0 "" "")
2026		    (match_operand 1 "" ""))
2027             (clobber (match_operand:SI 2 "" ""))
2028             (use (match_operand:SI 3 "" ""))])]
2029  ""
2030  {
2031  }
2032)
2033
2034(define_insn "call_internal_plt"
2035  [(call (mem (match_operand:SI 0 "call_insn_plt_operand" ""))
2036	 (match_operand:SI 1 "" "i"))
2037  (clobber (reg:SI R_SR))
2038  (use (reg:SI R_GOT))]
2039  "flag_pic"
2040  {
2041    register rtx target2 = gen_rtx_REG (Pmode,
2042			      GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2043    gen_rtx_CLOBBER (VOIDmode, target2);
2044    return "brlid\tr15,%0\;%#";
2045  }
2046  [(set_attr "type"	"call")
2047  (set_attr "mode"	"none")
2048  (set_attr "length"	"4")])
2049
2050(define_insn "call_internal1"
2051  [(call (mem (match_operand:SI 0 "call_insn_simple_operand" "ri"))
2052	 (match_operand:SI 1 "" "i"))
2053  (clobber (reg:SI R_SR))]
2054  ""
2055  {
2056    register rtx target = operands[0];
2057    register rtx target2 = gen_rtx_REG (Pmode,
2058			      GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2059    if (GET_CODE (target) == SYMBOL_REF) {
2060        gen_rtx_CLOBBER (VOIDmode, target2);
2061        return "brlid\tr15,%0\;%#";
2062    } else if (GET_CODE (target) == CONST_INT)
2063        return "la\t%@,r0,%0\;brald\tr15,%@\;%#";
2064    else if (GET_CODE (target) == REG)
2065        return "brald\tr15,%0\;%#";
2066    else {
2067        fprintf (stderr,"Unsupported call insn\n");
2068        return NULL;
2069    }
2070  }
2071  [(set_attr "type"	"call")
2072  (set_attr "mode"	"none")
2073  (set_attr "length"	"4")])
2074
2075;; calls.c now passes a fourth argument, make saber happy
2076
2077(define_expand "call_value"
2078  [(parallel [(set (match_operand 0 "register_operand" "=d")
2079		   (call (match_operand 1 "memory_operand" "m")
2080			 (match_operand 2 "" "i")))
2081             (clobber (reg:SI R_SR))
2082             (use (match_operand 3 "" ""))])] ;; next_arg_reg
2083  ""
2084  {
2085    rtx addr = XEXP (operands[1], 0);
2086
2087    if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
2088	&& !SYMBOL_REF_LOCAL_P (addr))
2089      {
2090        rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
2091        XEXP (operands[1], 0) = temp;
2092      }
2093
2094    if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
2095        || !call_insn_operand (addr, VOIDmode))
2096      XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
2097
2098    if (GET_CODE (XEXP (operands[1], 0)) == UNSPEC)
2099      emit_call_insn (gen_call_value_intern_plt0 (operands[0], operands[1],
2100			operands[2],
2101                        gen_rtx_REG (SImode,
2102				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
2103				     pic_offset_table_rtx));
2104    else
2105      emit_call_insn (gen_call_value_internal (operands[0], operands[1],
2106			operands[2],
2107                        gen_rtx_REG (SImode,
2108				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2109
2110    DONE;
2111  }
2112)
2113
2114
2115(define_expand "call_value_internal"
2116  [(parallel [(set (match_operand 0 "" "")
2117		   (call (match_operand 1 "" "")
2118			 (match_operand 2 "" "")))
2119             (clobber (match_operand:SI 3 "" ""))
2120             ])]
2121  ""
2122  {}
2123)
2124
2125(define_expand "call_value_intern_plt0"
2126  [(parallel[(set (match_operand 0 "" "")
2127                  (call (match_operand 1 "" "")
2128                        (match_operand 2 "" "")))
2129             (clobber (match_operand:SI 3 "" ""))
2130             (use (match_operand:SI 4 "" ""))])]
2131  "flag_pic"
2132  {}
2133)
2134
2135(define_insn "call_value_intern_plt"
2136  [(set (match_operand:VOID 0 "register_operand" "=d")
2137        (call (mem (match_operand:SI 1 "call_insn_plt_operand" ""))
2138              (match_operand:SI 2 "" "i")))
2139   (clobber (match_operand:SI 3 "register_operand" "=d"))
2140   (use (match_operand:SI 4 "register_operand"))]
2141  "flag_pic"
2142  {
2143    register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2144
2145    gen_rtx_CLOBBER (VOIDmode,target2);
2146    return "brlid\tr15,%1\;%#";
2147  }
2148  [(set_attr "type"	"call")
2149  (set_attr "mode"	"none")
2150  (set_attr "length"	"4")])
2151
2152(define_insn "call_value_intern"
2153  [(set (match_operand:VOID 0 "register_operand" "=d")
2154        (call (mem (match_operand:VOID 1 "call_insn_operand" "ri"))
2155              (match_operand:SI 2 "" "i")))
2156   (clobber (match_operand:SI 3 "register_operand" "=d"))]
2157  ""
2158  {
2159    register rtx target = operands[1];
2160    register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2161
2162    if (GET_CODE (target) == SYMBOL_REF)
2163    {
2164      gen_rtx_CLOBBER (VOIDmode,target2);
2165      if (SYMBOL_REF_FLAGS (target) & SYMBOL_FLAG_FUNCTION)
2166        {
2167	  return "brlid\tr15,%1\;%#";
2168        }
2169      else
2170        {
2171	  return "bralid\tr15,%1\;%#";
2172        }
2173    }
2174    else if (GET_CODE (target) == CONST_INT)
2175        return "la\t%@,r0,%1\;brald\tr15,%@\;%#";
2176    else if (GET_CODE (target) == REG)
2177        return "brald\tr15,%1\;%#";
2178    else
2179        return "Unsupported call insn\n";
2180  }
2181  [(set_attr "type"	"call")
2182  (set_attr "mode"	"none")
2183  (set_attr "length"	"4")])
2184
2185
2186;; Call subroutine returning any type.
2187(define_expand "untyped_call"
2188  [(parallel [(call (match_operand 0 "" "")
2189		    (const_int 0))
2190             (match_operand 1 "" "")
2191             (match_operand 2 "" "")])]
2192  ""
2193  {
2194    if (operands[0])		/* silence statement not reached warnings */
2195    {
2196        int i;
2197
2198        emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
2199
2200        for (i = 0; i < XVECLEN (operands[2], 0); i++)
2201	{
2202	    rtx set = XVECEXP (operands[2], 0, i);
2203	    emit_move_insn (SET_DEST (set), SET_SRC (set));
2204	}
2205
2206        emit_insn (gen_blockage ());
2207        DONE;
2208      }
2209  }
2210)
2211
2212;;----------------------------------------------------------------
2213;; Misc.
2214;;----------------------------------------------------------------
2215
2216(define_insn "nop"
2217  [(const_int 0)]
2218  ""
2219  "nop"
2220  [(set_attr "type"	"nop")
2221  (set_attr "mode"	"none")
2222  (set_attr "length"	"4")])
2223
2224;; Trap instruction pattern for __builtin_trap. Same as the glibc ABORT_INSTRUCTION
2225(define_insn "trap"
2226  [(trap_if (const_int 1) (const_int 0))]
2227  ""
2228  "brki\tr0,-1"
2229 [(set_attr "type" "trap")]
2230)
2231
2232;; The insn to set GOT. The hardcoded number "8" accounts for $pc difference
2233;; between "mfs" and "addik" instructions.
2234(define_insn "set_got"
2235  [(set (match_operand:SI 0 "register_operand" "=r")
2236    (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))]
2237  ""
2238  "mfs\t%0,rpc\n\taddik\t%0,%0,_GLOBAL_OFFSET_TABLE_+8"
2239  [(set_attr "type" "multi")
2240   (set_attr "length" "12")])
2241
2242;; This insn gives the count of leading number of zeros for the second
2243;; operand and stores the result in first operand.
2244(define_insn "clzsi2"
2245  [(set (match_operand:SI 0 "register_operand" "=r")
2246        (clz:SI (match_operand:SI 1 "register_operand" "r")))]
2247  "TARGET_HAS_CLZ"
2248  "clz\t%0,%1"
2249  [(set_attr "type"     "arith")
2250  (set_attr "mode"      "SI")
2251  (set_attr "length"    "4")])
2252