xref: /netbsd-src/external/gpl3/gcc/dist/gcc/config/microblaze/microblaze.md (revision d11b170b9000ada93db553723522a63d5deac310)
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;;Load and store reverse
1123(define_insn "movsi4_rev"
1124  [(set (match_operand:SI 0 "reg_or_mem_operand" "=r,Q")
1125        (bswap:SI (match_operand:SF 1 "reg_or_mem_operand" "Q,r")))]
1126  "TARGET_REORDER"
1127  "@
1128   lwr\t%0,%y1,r0
1129   swr\t%1,%y0,r0"
1130  [(set_attr "type"     "load,store")
1131  (set_attr "mode"      "SI")
1132  (set_attr "length"    "4,4")])
1133
1134;; 32-bit floating point moves
1135
1136(define_expand "movsf"
1137  [(set (match_operand:SF 0 "nonimmediate_operand" "")
1138        (match_operand:SF 1 "general_operand" ""))]
1139  ""
1140  {
1141    if ((reload_in_progress | reload_completed) == 0
1142        && !register_operand (operands[0], SFmode)
1143        && !register_operand (operands[1], SFmode)
1144        && ( ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
1145                 && operands[1] != CONST0_RTX (SFmode))))
1146    {
1147        rtx temp = force_reg (SFmode, operands[1]);
1148        emit_move_insn (operands[0], temp);
1149        DONE;
1150    }
1151  }
1152)
1153
1154;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
1155;;
1156(define_insn "*movsf_internal"
1157  [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
1158        (match_operand:SF 1 "general_operand" "G,d,R,F,m,d,d"))]
1159  "(register_operand (operands[0], SFmode)
1160       || register_operand (operands[1], SFmode)
1161       || operands[1] == CONST0_RTX (SFmode))"
1162  "@
1163   addk\t%0,r0,r0
1164   addk\t%0,%1,r0
1165   lw%i1\t%0,%1
1166   addik\t%0,r0,%F1
1167   lw%i1\t%0,%1
1168   sw%i0\t%z1,%0
1169   swi\t%z1,%0"
1170  [(set_attr "type"     "move,no_delay_load,load,no_delay_load,no_delay_load,store,no_delay_store")
1171  (set_attr "mode"      "SF")
1172  (set_attr "length"    "4,4,4,4,4,4,4")])
1173
1174;; 64-bit floating point moves
1175(define_expand "movdf"
1176  [(set (match_operand:DF 0 "nonimmediate_operand" "")
1177        (match_operand:DF 1 "general_operand" ""))]
1178  ""
1179  {
1180    if (flag_pic == 2) {
1181      if (GET_CODE (operands[1]) == MEM
1182          && !microblaze_legitimate_address_p (DFmode, XEXP (operands[1],0), 0))
1183      {
1184        rtx ptr_reg;
1185        rtx result;
1186        ptr_reg = force_reg (Pmode, XEXP (operands[1],0));
1187        result = gen_rtx_MEM (DFmode, ptr_reg);
1188        emit_move_insn (operands[0], result);
1189        DONE;
1190      }
1191    }
1192    if ((reload_in_progress | reload_completed) == 0
1193        && !register_operand (operands[0], DFmode)
1194        && !register_operand (operands[1], DFmode)
1195        && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
1196                 && operands[1] != CONST0_RTX (DFmode))))
1197    {
1198        rtx temp = force_reg (DFmode, operands[1]);
1199        emit_move_insn (operands[0], temp);
1200        DONE;
1201    }
1202  }
1203)
1204
1205;; movdf_internal
1206;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
1207;;
1208(define_insn "*movdf_internal"
1209  [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,o")
1210        (match_operand:DF 1 "general_operand" "dG,o,F,T,d"))]
1211  ""
1212  {
1213    switch (which_alternative)
1214    {
1215      case 0:
1216	return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
1217      case 1:
1218      case 3:
1219	if (reg_mentioned_p (operands[0], operands[1]))
1220          return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
1221        else
1222	  return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
1223      case 2:
1224      {
1225	return "addik\t%0,r0,%h1 \n\taddik\t%D0,r0,%j1 #Xfer Lo";
1226      }
1227      case 4:
1228	return "swi\t%1,%0\n\tswi\t%D1,%o0";
1229    }
1230    gcc_unreachable ();
1231  }
1232  [(set_attr "type"     "no_delay_move,no_delay_load,no_delay_load,no_delay_load,no_delay_store")
1233  (set_attr "mode"      "DF")
1234  (set_attr "length"    "4,8,8,16,8")])
1235
1236(define_split
1237  [(set (match_operand:DF 0 "register_operand" "")
1238        (match_operand:DF 1 "register_operand" ""))]
1239  "reload_completed
1240   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
1241   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
1242   && (REGNO (operands[0]) == (REGNO (operands[1]) + 1))"
1243  [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
1244  (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
1245  "")
1246
1247(define_split
1248  [(set (match_operand:DF 0 "register_operand" "")
1249        (match_operand:DF 1 "register_operand" ""))]
1250  "reload_completed
1251   && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
1252   && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
1253   && (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
1254  [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
1255  (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
1256  "")
1257
1258;;----------------------------------------------------------------
1259;; Shifts
1260;;----------------------------------------------------------------
1261
1262;;----------------------------------------------------------------
1263;; 32-bit left shifts
1264;;----------------------------------------------------------------
1265(define_expand "ashlsi3"
1266  [(set (match_operand:SI 0 "register_operand" "=&d")
1267	(ashift:SI (match_operand:SI 1 "register_operand" "d")
1268		   (match_operand:SI 2 "arith_operand" "")))]
1269  ""
1270  {
1271    /* Avoid recursion for trivial cases. */
1272    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1273      if (microblaze_expand_shift (operands))
1274        DONE;
1275  }
1276)
1277
1278;; Irrespective of if we have a barrel-shifter or not, we want to match
1279;; shifts by 1 with a special pattern. When a barrel shifter is present,
1280;; saves a cycle. If not, allows us to annotate the instruction for delay
1281;; slot optimization
1282(define_insn "*ashlsi3_byone"
1283  [(set (match_operand:SI 0 "register_operand" "=d")
1284	(ashift:SI (match_operand:SI 1 "register_operand" "d")
1285                   (match_operand:SI 2 "arith_operand"    "I")))]
1286  "(INTVAL (operands[2]) == 1)"
1287  "addk\t%0,%1,%1"
1288  [(set_attr "type"	"arith")
1289   (set_attr "mode"	"SI")
1290   (set_attr "length"	"4")]
1291)
1292
1293;; Barrel shift left
1294(define_insn "ashlsi3_bshift"
1295  [(set (match_operand:SI 0 "register_operand" "=d,d")
1296	(ashift:SI (match_operand:SI 1 "register_operand" "d,d")
1297                   (match_operand:SI 2 "arith_operand"    "I,d")))]
1298  "TARGET_BARREL_SHIFT"
1299  "@
1300  bslli\t%0,%1,%2
1301  bsll\t%0,%1,%2"
1302  [(set_attr "type"	"bshift,bshift")
1303  (set_attr "mode"	"SI,SI")
1304  (set_attr "length"	"4,4")]
1305)
1306
1307;; The following patterns apply when there is no barrel shifter present
1308
1309(define_insn "*ashlsi3_with_mul_delay"
1310  [(set (match_operand:SI 0 "register_operand" "=d")
1311	(ashift:SI (match_operand:SI 1 "register_operand"  "d")
1312                   (match_operand:SI 2 "immediate_operand" "I")))]
1313  "!TARGET_SOFT_MUL
1314   && ((1 << INTVAL (operands[2])) <= 32767 && (1 << INTVAL (operands[2])) >= -32768)"
1315  "muli\t%0,%1,%m2"
1316  ;; This MUL will not generate an imm. Can go into a delay slot.
1317  [(set_attr "type"	"arith")
1318   (set_attr "mode"	"SI")
1319   (set_attr "length"	"4")]
1320)
1321
1322(define_insn "*ashlsi3_with_mul_nodelay"
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  "!TARGET_SOFT_MUL"
1327  "muli\t%0,%1,%m2"
1328  ;; This MUL will generate an IMM. Cannot go into a delay slot
1329  [(set_attr "type"	"no_delay_arith")
1330   (set_attr "mode"	"SI")
1331   (set_attr "length"	"8")]
1332)
1333
1334(define_insn "*ashlsi3_with_size_opt"
1335  [(set (match_operand:SI 0 "register_operand" "=&d")
1336       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1337                   (match_operand:SI 2 "immediate_operand" "I")))]
1338  "(INTVAL (operands[2]) > 5 && optimize_size)"
1339  {
1340    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1341
1342    output_asm_insn ("ori\t%3,r0,%2", operands);
1343    if (REGNO (operands[0]) != REGNO (operands[1]))
1344        output_asm_insn ("addk\t%0,%1,r0", operands);
1345
1346    output_asm_insn ("addik\t%3,%3,-1", operands);
1347    output_asm_insn ("bneid\t%3,.-4", operands);
1348    return "addk\t%0,%0,%0";
1349  }
1350  [(set_attr "type"    "multi")
1351   (set_attr "mode"    "SI")
1352   (set_attr "length"  "20")]
1353)
1354
1355(define_insn "*ashlsi3_with_rotate"
1356  [(set (match_operand:SI 0 "register_operand" "=&d")
1357       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1358                   (match_operand:SI 2 "immediate_operand" "I")))]
1359  "(INTVAL (operands[2]) > 17 && !optimize_size)"
1360  {
1361    int i, nshift;
1362
1363    nshift = INTVAL (operands[2]);
1364    operands[3] = gen_int_mode (0xFFFFFFFF << nshift, SImode);
1365
1366    /* We do one extra shift so that the first bit (carry) coming into the MSB
1367       will be masked out */
1368    output_asm_insn ("src\t%0,%1", operands);
1369    for (i = 0; i < (32 - nshift); i++)
1370       output_asm_insn ("src\t%0,%0", operands);
1371
1372    return "andi\t%0,%0,%3";
1373  }
1374  [(set_attr "type"    "multi")
1375  (set_attr "mode"     "SI")
1376  (set_attr "length"   "80")]
1377)
1378
1379(define_insn "*ashlsi_inline"
1380  [(set (match_operand:SI 0 "register_operand" "=&d")
1381       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1382                   (match_operand:SI 2 "immediate_operand" "I")))]
1383  ""
1384  {
1385    int i;
1386    int nshift = INTVAL (operands[2]);
1387    if (REGNO (operands[0]) != REGNO (operands[1]))
1388      output_asm_insn ("addk\t%0,r0,%1", operands);
1389    output_asm_insn ("addk\t%0,%1,%1", operands);
1390    for (i = 0; i < (nshift - 2); i++)
1391      output_asm_insn ("addk\t%0,%0,%0", operands);
1392    return "addk\t%0,%0,%0";
1393  }
1394  [(set_attr "type"    "multi")
1395  (set_attr "mode"     "SI")
1396  (set_attr "length"   "124")]
1397)
1398
1399(define_insn "*ashlsi_reg"
1400  [(set (match_operand:SI 0 "register_operand" "=&d")
1401       (ashift:SI (match_operand:SI 1 "register_operand"  "d")
1402                   (match_operand:SI 2 "register_operand" "d")))]
1403  ""
1404  {
1405    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1406    output_asm_insn ("andi\t%3,%2,31", operands);
1407    if (REGNO (operands[0]) != REGNO (operands[1]))
1408      output_asm_insn ("addk\t%0,r0,%1", operands);
1409    /* Exit the loop if zero shift. */
1410    output_asm_insn ("beqid\t%3,.+20", operands);
1411    /* Emit the loop.  */
1412    output_asm_insn ("addk\t%0,%0,r0", operands);
1413    output_asm_insn ("addik\t%3,%3,-1", operands);
1414    output_asm_insn ("bneid\t%3,.-4", operands);
1415    return "addk\t%0,%0,%0";
1416  }
1417  [(set_attr "type"    "multi")
1418  (set_attr "mode"     "SI")
1419  (set_attr "length"   "28")]
1420)
1421
1422
1423;;----------------------------------------------------------------
1424;; 32-bit right shifts
1425;;----------------------------------------------------------------
1426(define_expand "ashrsi3"
1427  [(set (match_operand:SI 0 "register_operand" "=&d")
1428	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
1429                     (match_operand:SI 2 "arith_operand" "")))]
1430  ""
1431  {
1432    /* Avoid recursion for trivial cases. */
1433    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1434      if (microblaze_expand_shift (operands))
1435        DONE;
1436  }
1437)
1438
1439;; Irrespective of if we have a barrel-shifter or not, we want to match
1440;; shifts by 1 with a special pattern. When a barrel shifter is present,
1441;; saves a cycle. If not, allows us to annotate the instruction for delay
1442;; slot optimization
1443(define_insn "*ashrsi3_byone"
1444  [(set (match_operand:SI 0 "register_operand" "=d")
1445	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
1446                     (match_operand:SI 2 "arith_operand"    "I")))]
1447  "(INTVAL (operands[2]) == 1)"
1448  "sra\t%0,%1"
1449  [(set_attr "type"	"arith")
1450   (set_attr "mode"	"SI")
1451   (set_attr "length"	"4")]
1452)
1453
1454;; Barrel shift right logical
1455(define_insn "*ashrsi3_bshift"
1456  [(set (match_operand:SI 0 "register_operand" "=d,d")
1457	(ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
1458                     (match_operand:SI 2 "arith_operand"    "I,d")))]
1459  "TARGET_BARREL_SHIFT"
1460  "@
1461  bsrai\t%0,%1,%2
1462  bsra\t%0,%1,%2"
1463  [(set_attr "type"	"bshift,bshift")
1464  (set_attr "mode"	"SI,SI")
1465  (set_attr "length"	"4,4")]
1466)
1467
1468(define_insn "*ashrsi_inline"
1469  [(set (match_operand:SI 0 "register_operand" "=&d")
1470       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1471                   (match_operand:SI 2 "immediate_operand" "I")))]
1472  ""
1473  {
1474    int i;
1475    int nshift = INTVAL (operands[2]);
1476    if (REGNO (operands[0]) != REGNO (operands[1]))
1477      output_asm_insn ("addk\t%0,r0,%1", operands);
1478    output_asm_insn ("sra\t%0,%1", operands);
1479    for (i = 0; i < (nshift - 2); i++)
1480      output_asm_insn ("sra\t%0,%0", operands);
1481    return "sra\t%0,%0";
1482  }
1483  [(set_attr "type"    "multi")
1484  (set_attr "mode"     "SI")
1485  (set_attr "length"   "124")]
1486)
1487
1488(define_insn "*ashrsi_reg"
1489  [(set (match_operand:SI 0 "register_operand" "=&d")
1490       (ashiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1491                   (match_operand:SI 2 "register_operand" "d")))]
1492  ""
1493  {
1494    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1495    output_asm_insn ("andi\t%3,%2,31", operands);
1496    if (REGNO (operands[0]) != REGNO (operands[1]))
1497      output_asm_insn ("addk\t%0,r0,%1", operands);
1498    /* Exit the loop if zero shift. */
1499    output_asm_insn ("beqid\t%3,.+20", operands);
1500    /* Emit the loop.  */
1501    output_asm_insn ("addk\t%0,%0,r0", operands);
1502    output_asm_insn ("addik\t%3,%3,-1", operands);
1503    output_asm_insn ("bneid\t%3,.-4", operands);
1504    return "sra\t%0,%0";
1505  }
1506  [(set_attr "type"    "multi")
1507  (set_attr "mode"     "SI")
1508  (set_attr "length"   "28")]
1509)
1510
1511;;----------------------------------------------------------------
1512;; 32-bit right shifts (logical)
1513;;----------------------------------------------------------------
1514
1515(define_expand "lshrsi3"
1516  [(set (match_operand:SI 0 "register_operand" "=&d")
1517	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
1518                     (match_operand:SI 2 "arith_operand" "")))]
1519  ""
1520  {
1521    /* Avoid recursion for trivial cases. */
1522    if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
1523      if (microblaze_expand_shift (operands))
1524        DONE;
1525  }
1526)
1527
1528;; Irrespective of if we have a barrel-shifter or not, we want to match
1529;; shifts by 1 with a special pattern. When a barrel shifter is present,
1530;; saves a cycle. If not, allows us to annotate the instruction for delay
1531;; slot optimization
1532(define_insn "*lshrsi3_byone"
1533  [(set (match_operand:SI 0 "register_operand" "=d")
1534	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
1535                     (match_operand:SI 2 "arith_operand"    "I")))]
1536  "(INTVAL (operands[2]) == 1)"
1537  "srl\t%0,%1"
1538  [(set_attr "type"	"arith")
1539   (set_attr "mode"	"SI")
1540   (set_attr "length"	"4")]
1541)
1542
1543;; Barrel shift right logical
1544(define_insn "*lshrsi3_bshift"
1545  [(set (match_operand:SI 0 "register_operand" "=d,d")
1546	(lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
1547                     (match_operand:SI 2 "arith_operand"    "I,d")))]
1548  "TARGET_BARREL_SHIFT"
1549  "@
1550  bsrli\t%0,%1,%2
1551  bsrl\t%0,%1,%2"
1552  [(set_attr "type"	"bshift,bshift")
1553  (set_attr "mode"	"SI,SI")
1554  (set_attr "length"	"4,4")]
1555)
1556
1557(define_insn "*lshrsi_inline"
1558  [(set (match_operand:SI 0 "register_operand" "=&d")
1559       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1560                   (match_operand:SI 2 "immediate_operand" "I")))]
1561  ""
1562  {
1563    int i;
1564    int nshift = INTVAL (operands[2]);
1565    if (REGNO (operands[0]) != REGNO (operands[1]))
1566      output_asm_insn ("addk\t%0,r0,%1", operands);
1567    output_asm_insn ("srl\t%0,%1", operands);
1568    for (i = 0; i < (nshift - 2); i++)
1569      output_asm_insn ("srl\t%0,%0", operands);
1570    return "srl\t%0,%0";
1571  }
1572  [(set_attr "type"    "multi")
1573  (set_attr "mode"     "SI")
1574  (set_attr "length"   "124")]
1575)
1576
1577(define_insn "*lshrsi_reg"
1578  [(set (match_operand:SI 0 "register_operand" "=&d")
1579       (lshiftrt:SI (match_operand:SI 1 "register_operand"  "d")
1580                   (match_operand:SI 2 "register_operand" "d")))]
1581  ""
1582  {
1583    operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1584    output_asm_insn ("andi\t%3,%2,31", operands);
1585    if (REGNO (operands[0]) != REGNO (operands[1]))
1586      output_asm_insn ("addk\t%0,r0,%1", operands);
1587    /* Exit the loop if zero shift. */
1588    output_asm_insn ("beqid\t%3,.+20", operands);
1589    /* Emit the loop.  */
1590    output_asm_insn ("addk\t%0,%0,r0", operands);
1591    output_asm_insn ("addik\t%3,%3,-1", operands);
1592    output_asm_insn ("bneid\t%3,.-4", operands);
1593    return "srl\t%0,%0";
1594  }
1595  [(set_attr "type"    "multi")
1596  (set_attr "mode"     "SI")
1597  (set_attr "length"   "28")]
1598)
1599
1600;;----------------------------------------------------------------
1601;; Setting a register from an integer comparison.
1602;;----------------------------------------------------------------
1603(define_expand "cstoresi4"
1604   [(set (match_operand:SI 0 "register_operand")
1605        (match_operator:SI 1 "ordered_comparison_operator"
1606	      [(match_operand:SI 2 "register_operand")
1607	       (match_operand:SI 3 "register_operand")]))]
1608  "TARGET_PATTERN_COMPARE"
1609  "if (GET_CODE (operand1) != EQ && GET_CODE (operand1) != NE)
1610     FAIL;
1611  "
1612)
1613
1614(define_insn "seq_internal_pat"
1615  [(set (match_operand:SI 0 "register_operand" "=d")
1616	(eq:SI
1617	       (match_operand:SI 1 "register_operand" "d")
1618	       (match_operand:SI 2 "register_operand" "d")))]
1619  "TARGET_PATTERN_COMPARE"
1620  "pcmpeq\t%0,%1,%2"
1621  [(set_attr "type"	"arith")
1622   (set_attr "mode"	"SI")
1623   (set_attr "length"	"4")]
1624)
1625
1626(define_insn "sne_internal_pat"
1627  [(set (match_operand:SI 0 "register_operand" "=d")
1628	(ne:SI
1629	       (match_operand:SI 1 "register_operand" "d")
1630	       (match_operand:SI 2 "register_operand" "d")))]
1631  "TARGET_PATTERN_COMPARE"
1632  "pcmpne\t%0,%1,%2"
1633  [(set_attr "type"	"arith")
1634  (set_attr "mode"	"SI")
1635  (set_attr "length"	"4")]
1636)
1637
1638;;----------------------------------------------------------------
1639;; Setting a register from an floating point comparison.
1640;;----------------------------------------------------------------
1641(define_insn "cstoresf4"
1642   [(set (match_operand:SI 0 "register_operand" "=r")
1643        (match_operator:SI 1 "ordered_comparison_operator"
1644	      [(match_operand:SF 2 "register_operand" "r")
1645	       (match_operand:SF 3 "register_operand" "r")]))]
1646  "TARGET_HARD_FLOAT"
1647  "fcmp.%C1\t%0,%3,%2"
1648  [(set_attr "type"     "fcmp")
1649   (set_attr "mode"      "SF")
1650   (set_attr "length"    "4")]
1651)
1652
1653;;----------------------------------------------------------------
1654;; Conditional branches
1655;;----------------------------------------------------------------
1656
1657(define_expand "cbranchsi4"
1658  [(set (pc)
1659	(if_then_else (match_operator 0 "ordered_comparison_operator"
1660		       [(match_operand:SI 1 "register_operand")
1661		        (match_operand:SI 2 "arith_operand")])
1662		      (label_ref (match_operand 3 ""))
1663		      (pc)))]
1664  ""
1665{
1666  microblaze_expand_conditional_branch (SImode, operands);
1667  DONE;
1668})
1669
1670(define_expand "cbranchsf4"
1671  [(set (pc)
1672	(if_then_else (match_operator 0 "ordered_comparison_operator"
1673		       [(match_operand:SF 1 "register_operand")
1674		        (match_operand:SF 2 "register_operand")])
1675		      (label_ref (match_operand 3 ""))
1676		      (pc)))]
1677  "TARGET_HARD_FLOAT"
1678{
1679  microblaze_expand_conditional_branch_sf (operands);
1680  DONE;
1681
1682})
1683
1684;; Used to implement comparison instructions
1685(define_expand "condjump"
1686  [(set (pc)
1687	(if_then_else (match_operand 0)
1688		      (label_ref (match_operand 1))
1689		      (pc)))])
1690
1691(define_insn "branch_zero"
1692  [(set (pc)
1693	(if_then_else (match_operator:SI 0 "ordered_comparison_operator"
1694  				 [(match_operand:SI 1 "register_operand" "d")
1695                                  (const_int 0)])
1696                      (match_operand:SI 2 "pc_or_label_operand" "")
1697                      (match_operand:SI 3 "pc_or_label_operand" "")))
1698  ]
1699  ""
1700  {
1701    if (operands[3] == pc_rtx)
1702      return "b%C0i%?\t%z1,%2";
1703    else
1704      return "b%N0i%?\t%z1,%3";
1705  }
1706  [(set_attr "type"	"branch")
1707   (set_attr "mode"	"none")
1708   (set_attr "length"	"4")]
1709)
1710
1711(define_insn "branch_compare"
1712  [(set (pc)
1713        (if_then_else (match_operator:SI 0 "cmp_op"
1714                                         [(match_operand:SI 1 "register_operand" "d")
1715                                          (match_operand:SI 2 "register_operand" "d")
1716                                         ])
1717                      (label_ref (match_operand 3))
1718                      (pc)))
1719  (clobber(reg:SI R_TMP))]
1720  ""
1721  {
1722    operands[4] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
1723    enum rtx_code code = GET_CODE (operands[0]);
1724
1725    if (code == GT || code == LE)
1726      {
1727        output_asm_insn ("cmp\tr18,%z1,%z2", operands);
1728        code = swap_condition (code);
1729      }
1730    else if (code == GTU || code == LEU)
1731      {
1732        output_asm_insn ("cmpu\tr18,%z1,%z2", operands);
1733        code = swap_condition (code);
1734      }
1735    else if (code == GE || code == LT)
1736      {
1737        output_asm_insn ("cmp\tr18,%z2,%z1", operands);
1738      }
1739    else if (code == GEU || code == LTU)
1740      {
1741        output_asm_insn ("cmpu\tr18,%z2,%z1", operands);
1742      }
1743
1744    operands[0] = gen_rtx_fmt_ee (signed_condition (code), SImode, operands[4], const0_rtx);
1745    return "b%C0i%?\tr18,%3";
1746  }
1747  [(set_attr "type"     "branch")
1748   (set_attr "mode"     "none")
1749   (set_attr "length"   "12")]
1750)
1751
1752;;----------------------------------------------------------------
1753;; Unconditional branches
1754;;----------------------------------------------------------------
1755(define_insn "jump"
1756  [(set (pc)
1757	(label_ref (match_operand 0 "" "")))]
1758  ""
1759  {
1760    if (GET_CODE (operands[0]) == REG)
1761        return "br%?\t%0";
1762    else
1763        return "bri%?\t%l0";
1764  }
1765  [(set_attr "type"	"jump")
1766  (set_attr "mode"	"none")
1767  (set_attr "length"	"4")])
1768
1769(define_expand "indirect_jump"
1770  [(set (pc) (match_operand 0 "register_operand" "d"))]
1771  ""
1772  {
1773    rtx dest = operands[0];
1774    if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode)
1775      operands[0] = copy_to_mode_reg (Pmode, dest);
1776
1777    emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
1778    DONE;
1779  }
1780)
1781
1782;; Indirect jumps. Jump to register values. Assuming absolute jumps
1783
1784(define_insn "indirect_jump_internal1"
1785  [(set (pc) (match_operand:SI 0 "register_operand" "d"))]
1786  ""
1787  "bra%?\t%0"
1788  [(set_attr "type"	"jump")
1789  (set_attr "mode"	"none")
1790  (set_attr "length"	"4")])
1791
1792(define_expand "tablejump"
1793  [(set (pc)
1794	(match_operand 0 "register_operand" "d"))
1795  (use (label_ref (match_operand 1 "" "")))]
1796  ""
1797  {
1798    gcc_assert (GET_MODE (operands[0]) == Pmode);
1799
1800    if (!flag_pic)
1801      emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
1802    else
1803      emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
1804    DONE;
1805  }
1806)
1807
1808(define_insn "tablejump_internal1"
1809  [(set (pc)
1810	(match_operand:SI 0 "register_operand" "d"))
1811  (use (label_ref (match_operand 1 "" "")))]
1812  ""
1813  "bra%?\t%0 "
1814  [(set_attr "type"	"jump")
1815  (set_attr "mode"	"none")
1816  (set_attr "length"	"4")])
1817
1818(define_expand "tablejump_internal3"
1819  [(parallel [(set (pc)
1820		   (plus:SI (match_operand:SI 0 "register_operand" "d")
1821			    (label_ref:SI (match_operand:SI 1 "" ""))))
1822             (use (label_ref:SI (match_dup 1)))])]
1823  ""
1824  ""
1825)
1826
1827;; need to change for MicroBlaze PIC
1828(define_insn ""
1829 [(set (pc)
1830	(plus:SI (match_operand:SI 0 "register_operand" "d")
1831		 (label_ref:SI (match_operand 1 "" ""))))
1832  (use (label_ref:SI (match_dup 1)))]
1833 "next_active_insn (insn) != 0
1834  && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
1835  && PREV_INSN (next_active_insn (insn)) == operands[1]
1836  && flag_pic"
1837  {
1838    output_asm_insn ("addk\t%0,%0,r20",operands);
1839    return "bra%?\t%0";
1840}
1841 [(set_attr "type"	"jump")
1842  (set_attr "mode"	"none")
1843  (set_attr "length"	"4")])
1844
1845(define_expand "tablejump_internal4"
1846  [(parallel [(set (pc)
1847		   (plus:DI (match_operand:DI 0 "register_operand" "d")
1848			    (label_ref:DI (match_operand:SI 1 "" ""))))
1849             (use (label_ref:DI (match_dup 1)))])]
1850  ""
1851  ""
1852)
1853
1854;;----------------------------------------------------------------
1855;; Function prologue/epilogue and stack allocation
1856;;----------------------------------------------------------------
1857(define_expand "prologue"
1858  [(const_int 1)]
1859  ""
1860  {
1861      microblaze_expand_prologue ();
1862      DONE;
1863  }
1864)
1865
1866(define_expand "epilogue"
1867  [(use (const_int 0))]
1868  ""
1869  {
1870      microblaze_expand_epilogue ();
1871      DONE;
1872  }
1873)
1874
1875;; An insn to allocate new stack space for dynamic use (e.g., alloca).
1876;; We copy the return address, decrement the stack pointer and save the
1877;; return address again at the new stack top
1878
1879(define_expand "allocate_stack"
1880  [(set (match_operand 0 "register_operand" "=r")
1881	(minus (reg 1) (match_operand 1 "register_operand" "")))
1882   (set (reg 1)
1883	(minus (reg 1) (match_dup 1)))]
1884  ""
1885  {
1886    rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
1887    rtx rtmp    = gen_rtx_REG (SImode, R_TMP);
1888    rtx neg_op0;
1889
1890    emit_move_insn (rtmp, retaddr);
1891    if (GET_CODE (operands[1]) != CONST_INT)
1892    {
1893        neg_op0 = gen_reg_rtx (Pmode);
1894	emit_insn (gen_negsi2 (neg_op0, operands[1]));
1895    } else
1896        neg_op0 = GEN_INT (- INTVAL (operands[1]));
1897
1898    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
1899    emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), rtmp);
1900    emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
1901    emit_insn (gen_rtx_CLOBBER (SImode, rtmp));
1902    DONE;
1903  }
1904)
1905
1906(define_expand "save_stack_block"
1907  [(match_operand 0 "register_operand" "")
1908   (match_operand 1 "register_operand" "")]
1909  ""
1910  {
1911    emit_move_insn (operands[0], operands[1]);
1912    DONE;
1913  }
1914)
1915
1916(define_expand "restore_stack_block"
1917  [(match_operand 0 "register_operand" "")
1918   (match_operand 1 "register_operand" "")]
1919  ""
1920  {
1921    rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
1922    rtx rtmp    = gen_rtx_REG (SImode, R_TMP);
1923
1924    /* Move the retaddr.  */
1925    emit_move_insn (rtmp, retaddr);
1926    emit_move_insn (operands[0], operands[1]);
1927    emit_move_insn (gen_rtx_MEM (Pmode, operands[0]), rtmp);
1928    DONE;
1929  }
1930)
1931
1932;; Trivial return.  Make it look like a normal return insn as that
1933;; allows jump optimizations to work better .
1934(define_expand "return"
1935  [(simple_return)]
1936  "microblaze_can_use_return_insn ()"
1937  {}
1938)
1939
1940(define_expand "simple_return"
1941  [(simple_return)]
1942  ""
1943  {}
1944)
1945
1946(define_insn "*<optab>"
1947  [(any_return)]
1948  ""
1949  {
1950    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_interrupt_variant ())
1968        return "rtid\tr14,0 \;%#";
1969    else
1970        return "rtsd\tr15,8 \;%#";
1971  }
1972  [(set_attr "type"	"jump")
1973  (set_attr "mode"	"none")
1974  (set_attr "length"	"4")])
1975
1976
1977;; Block any insns from across this point
1978;; Useful to group sequences together.
1979(define_insn "blockage"
1980  [(unspec_volatile [(const_int 0)] 0)]
1981  ""
1982  ""
1983  [(set_attr "type"	"unknown")
1984  (set_attr "mode"	"none")
1985  (set_attr "length"	"0")])
1986
1987
1988;;----------------------------------------------------------------
1989;; Function calls
1990;;----------------------------------------------------------------
1991
1992(define_expand "call"
1993  [(parallel [(call (match_operand 0 "memory_operand" "m")
1994		    (match_operand 1 "" "i"))
1995             (clobber (reg:SI R_SR))
1996             (use (match_operand 2 "" ""))
1997             (use (match_operand 3 "" ""))])]
1998  ""
1999  {
2000    rtx addr = XEXP (operands[0], 0);
2001
2002    if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
2003	&& !SYMBOL_REF_LOCAL_P (addr))
2004      {
2005        rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
2006        XEXP (operands[0], 0) = temp;
2007      }
2008
2009    if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
2010	|| !call_insn_operand (addr, VOIDmode))
2011      XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
2012
2013    if (GET_CODE (XEXP (operands[0], 0)) == UNSPEC)
2014      emit_call_insn (gen_call_internal_plt0 (operands[0], operands[1],
2015                        gen_rtx_REG (SImode,
2016				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
2017                               	     pic_offset_table_rtx));
2018    else
2019      emit_call_insn (gen_call_internal0 (operands[0], operands[1],
2020                        gen_rtx_REG (SImode,
2021				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2022
2023        DONE;
2024  }
2025)
2026
2027(define_expand "call_internal0"
2028  [(parallel [(call (match_operand 0 "" "")
2029		    (match_operand 1 "" ""))
2030             (clobber (match_operand:SI 2 "" ""))])]
2031  ""
2032  {
2033  }
2034)
2035
2036(define_expand "call_internal_plt0"
2037  [(parallel [(call (match_operand 0 "" "")
2038		    (match_operand 1 "" ""))
2039             (clobber (match_operand:SI 2 "" ""))
2040             (use (match_operand:SI 3 "" ""))])]
2041  ""
2042  {
2043  }
2044)
2045
2046(define_insn "call_internal_plt"
2047  [(call (mem (match_operand:SI 0 "call_insn_plt_operand" ""))
2048	 (match_operand:SI 1 "" "i"))
2049  (clobber (reg:SI R_SR))
2050  (use (reg:SI R_GOT))]
2051  "flag_pic"
2052  {
2053    register rtx target2 = gen_rtx_REG (Pmode,
2054			      GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2055    gen_rtx_CLOBBER (VOIDmode, target2);
2056    return "brlid\tr15,%0\;%#";
2057  }
2058  [(set_attr "type"	"call")
2059  (set_attr "mode"	"none")
2060  (set_attr "length"	"4")])
2061
2062(define_insn "call_internal1"
2063  [(call (mem (match_operand:SI 0 "call_insn_simple_operand" "ri"))
2064	 (match_operand:SI 1 "" "i"))
2065  (clobber (reg:SI R_SR))]
2066  ""
2067  {
2068    register rtx target = operands[0];
2069    register rtx target2 = gen_rtx_REG (Pmode,
2070			      GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2071    if (GET_CODE (target) == SYMBOL_REF) {
2072        gen_rtx_CLOBBER (VOIDmode, target2);
2073        return "brlid\tr15,%0\;%#";
2074    } else if (GET_CODE (target) == CONST_INT)
2075        return "la\t%@,r0,%0\;brald\tr15,%@\;%#";
2076    else if (GET_CODE (target) == REG)
2077        return "brald\tr15,%0\;%#";
2078    else {
2079        fprintf (stderr,"Unsupported call insn\n");
2080        return NULL;
2081    }
2082  }
2083  [(set_attr "type"	"call")
2084  (set_attr "mode"	"none")
2085  (set_attr "length"	"4")])
2086
2087;; calls.c now passes a fourth argument, make saber happy
2088
2089(define_expand "call_value"
2090  [(parallel [(set (match_operand 0 "register_operand" "=d")
2091		   (call (match_operand 1 "memory_operand" "m")
2092			 (match_operand 2 "" "i")))
2093             (clobber (reg:SI R_SR))
2094             (use (match_operand 3 "" ""))])] ;; next_arg_reg
2095  ""
2096  {
2097    rtx addr = XEXP (operands[1], 0);
2098
2099    if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
2100	&& !SYMBOL_REF_LOCAL_P (addr))
2101      {
2102        rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
2103        XEXP (operands[1], 0) = temp;
2104      }
2105
2106    if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
2107        || !call_insn_operand (addr, VOIDmode))
2108      XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
2109
2110    if (GET_CODE (XEXP (operands[1], 0)) == UNSPEC)
2111      emit_call_insn (gen_call_value_intern_plt0 (operands[0], operands[1],
2112			operands[2],
2113                        gen_rtx_REG (SImode,
2114				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
2115				     pic_offset_table_rtx));
2116    else
2117      emit_call_insn (gen_call_value_internal (operands[0], operands[1],
2118			operands[2],
2119                        gen_rtx_REG (SImode,
2120				     GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
2121
2122    DONE;
2123  }
2124)
2125
2126
2127(define_expand "call_value_internal"
2128  [(parallel [(set (match_operand 0 "" "")
2129		   (call (match_operand 1 "" "")
2130			 (match_operand 2 "" "")))
2131             (clobber (match_operand:SI 3 "" ""))
2132             ])]
2133  ""
2134  {}
2135)
2136
2137(define_expand "call_value_intern_plt0"
2138  [(parallel[(set (match_operand 0 "" "")
2139                  (call (match_operand 1 "" "")
2140                        (match_operand 2 "" "")))
2141             (clobber (match_operand:SI 3 "" ""))
2142             (use (match_operand:SI 4 "" ""))])]
2143  "flag_pic"
2144  {}
2145)
2146
2147(define_insn "call_value_intern_plt"
2148  [(set (match_operand:VOID 0 "register_operand" "=d")
2149        (call (mem (match_operand:SI 1 "call_insn_plt_operand" ""))
2150              (match_operand:SI 2 "" "i")))
2151   (clobber (match_operand:SI 3 "register_operand" "=d"))
2152   (use (match_operand:SI 4 "register_operand"))]
2153  "flag_pic"
2154  {
2155    register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2156
2157    gen_rtx_CLOBBER (VOIDmode,target2);
2158    return "brlid\tr15,%1\;%#";
2159  }
2160  [(set_attr "type"	"call")
2161  (set_attr "mode"	"none")
2162  (set_attr "length"	"4")])
2163
2164(define_insn "call_value_intern"
2165  [(set (match_operand:VOID 0 "register_operand" "=d")
2166        (call (mem (match_operand:VOID 1 "call_insn_operand" "ri"))
2167              (match_operand:SI 2 "" "i")))
2168   (clobber (match_operand:SI 3 "register_operand" "=d"))]
2169  ""
2170  {
2171    register rtx target = operands[1];
2172    register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
2173
2174    if (GET_CODE (target) == SYMBOL_REF)
2175    {
2176      gen_rtx_CLOBBER (VOIDmode,target2);
2177      if (SYMBOL_REF_FLAGS (target) & SYMBOL_FLAG_FUNCTION)
2178        {
2179	  return "brlid\tr15,%1\;%#";
2180        }
2181      else
2182        {
2183	  return "bralid\tr15,%1\;%#";
2184        }
2185    }
2186    else if (GET_CODE (target) == CONST_INT)
2187        return "la\t%@,r0,%1\;brald\tr15,%@\;%#";
2188    else if (GET_CODE (target) == REG)
2189        return "brald\tr15,%1\;%#";
2190    else
2191        return "Unsupported call insn\n";
2192  }
2193  [(set_attr "type"	"call")
2194  (set_attr "mode"	"none")
2195  (set_attr "length"	"4")])
2196
2197
2198;; Call subroutine returning any type.
2199(define_expand "untyped_call"
2200  [(parallel [(call (match_operand 0 "" "")
2201		    (const_int 0))
2202             (match_operand 1 "" "")
2203             (match_operand 2 "" "")])]
2204  ""
2205  {
2206    if (operands[0])		/* silence statement not reached warnings */
2207    {
2208        int i;
2209
2210        emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
2211
2212        for (i = 0; i < XVECLEN (operands[2], 0); i++)
2213	{
2214	    rtx set = XVECEXP (operands[2], 0, i);
2215	    emit_move_insn (SET_DEST (set), SET_SRC (set));
2216	}
2217
2218        emit_insn (gen_blockage ());
2219        DONE;
2220      }
2221  }
2222)
2223
2224;;----------------------------------------------------------------
2225;; Misc.
2226;;----------------------------------------------------------------
2227
2228(define_insn "nop"
2229  [(const_int 0)]
2230  ""
2231  "nop"
2232  [(set_attr "type"	"nop")
2233  (set_attr "mode"	"none")
2234  (set_attr "length"	"4")])
2235
2236;; Trap instruction pattern for __builtin_trap. Same as the glibc ABORT_INSTRUCTION
2237(define_insn "trap"
2238  [(trap_if (const_int 1) (const_int 0))]
2239  ""
2240  "brki\tr0,-1"
2241 [(set_attr "type" "trap")]
2242)
2243
2244;; The insn to set GOT. The hardcoded number "8" accounts for $pc difference
2245;; between "mfs" and "addik" instructions.
2246(define_insn "set_got"
2247  [(set (match_operand:SI 0 "register_operand" "=r")
2248    (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))]
2249  ""
2250  "mfs\t%0,rpc\n\taddik\t%0,%0,_GLOBAL_OFFSET_TABLE_+8"
2251  [(set_attr "type" "multi")
2252   (set_attr "length" "12")])
2253
2254;; This insn gives the count of leading number of zeros for the second
2255;; operand and stores the result in first operand.
2256(define_insn "clzsi2"
2257  [(set (match_operand:SI 0 "register_operand" "=r")
2258        (clz:SI (match_operand:SI 1 "register_operand" "r")))]
2259  "TARGET_HAS_CLZ"
2260  "clz\t%0,%1"
2261  [(set_attr "type"     "arith")
2262  (set_attr "mode"      "SI")
2263  (set_attr "length"    "4")])
2264