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