]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/nios2/nios2.md
nios2-protos.h (nios2_expand_return): Declare.
[thirdparty/gcc.git] / gcc / config / nios2 / nios2.md
1 ;; Machine Description for Altera Nios II.
2 ;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
3 ;; Contributed by Jonah Graham (jgraham@altera.com) and
4 ;; Will Reece (wreece@altera.com).
5 ;; Contributed by Mentor Graphics, Inc.
6 ;;
7 ;; This file is part of GCC.
8 ;;
9 ;; GCC is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; any later version.
13 ;;
14 ;; GCC is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18 ;;
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GCC; see the file COPYING3. If not see
21 ;; <http://www.gnu.org/licenses/>.
22
23 ;; Register numbers
24 (define_constants
25 [
26 (FIRST_RETVAL_REGNO 2) ; Return value registers
27 (LAST_RETVAL_REGNO 3) ;
28 (FIRST_ARG_REGNO 4) ; Argument registers
29 (LAST_ARG_REGNO 7) ;
30
31 (TP_REGNO 23) ; Thread pointer register
32 (GP_REGNO 26) ; Global pointer register
33 (SP_REGNO 27) ; Stack pointer register
34 (FP_REGNO 28) ; Frame pointer register
35 (EA_REGNO 29) ; Exception return address register
36 (RA_REGNO 31) ; Return address register
37 (LAST_GP_REG 31) ; Last general purpose register
38
39 ;; Target register definitions
40 (STATIC_CHAIN_REGNUM 12)
41 (STACK_POINTER_REGNUM 27)
42 (HARD_FRAME_POINTER_REGNUM 28)
43 (PC_REGNUM 37)
44 (FRAME_POINTER_REGNUM 38)
45 (ARG_POINTER_REGNUM 39)
46 (FIRST_PSEUDO_REGISTER 40)
47 ]
48 )
49
50 ;; Enumeration of UNSPECs
51
52 (define_c_enum "unspecv" [
53 UNSPECV_BLOCKAGE
54 UNSPECV_WRCTL
55 UNSPECV_RDCTL
56 UNSPECV_FWRX
57 UNSPECV_FWRY
58 UNSPECV_FRDXLO
59 UNSPECV_FRDXHI
60 UNSPECV_FRDY
61 UNSPECV_CUSTOM_NXX
62 UNSPECV_CUSTOM_XNXX
63 UNSPECV_LDXIO
64 UNSPECV_STXIO
65 ])
66
67 (define_c_enum "unspec" [
68 UNSPEC_FCOS
69 UNSPEC_FSIN
70 UNSPEC_FTAN
71 UNSPEC_FATAN
72 UNSPEC_FEXP
73 UNSPEC_FLOG
74 UNSPEC_ROUND
75 UNSPEC_LOAD_GOT_REGISTER
76 UNSPEC_PIC_SYM
77 UNSPEC_PIC_CALL_SYM
78 UNSPEC_PIC_GOTOFF_SYM
79 UNSPEC_LOAD_TLS_IE
80 UNSPEC_ADD_TLS_LE
81 UNSPEC_ADD_TLS_GD
82 UNSPEC_ADD_TLS_LDM
83 UNSPEC_ADD_TLS_LDO
84 UNSPEC_EH_RETURN
85 UNSPEC_SYNC
86 ])
87
88 \f
89 ;; Instruction scheduler
90
91 ; No schedule info is currently available, using an assumption that no
92 ; instruction can use the results of the previous instruction without
93 ; incuring a stall.
94
95 ; length of an instruction (in bytes)
96 (define_attr "length" ""
97 (if_then_else (match_test "nios2_cdx_narrow_form_p (insn)")
98 (const_int 2)
99 (const_int 4)))
100
101 (define_attr "type"
102 "unknown,complex,control,alu,cond_alu,st,ld,stwm,ldwm,push,pop,mul,div,\
103 custom,add,sub,mov,and,or,xor,neg,not,sll,srl,sra,rol,ror,nop"
104 (const_string "complex"))
105
106 (define_asm_attributes
107 [(set_attr "length" "4")
108 (set_attr "type" "complex")])
109
110 (define_automaton "nios2")
111 (automata_option "v")
112 ;(automata_option "no-minimization")
113 (automata_option "ndfa")
114
115 ; The nios2 pipeline is fairly straightforward for the fast model.
116 ; Every alu operation is pipelined so that an instruction can
117 ; be issued every cycle. However, there are still potential
118 ; stalls which this description tries to deal with.
119
120 (define_cpu_unit "cpu" "nios2")
121
122 (define_insn_reservation "complex" 1
123 (eq_attr "type" "complex")
124 "cpu")
125
126 (define_insn_reservation "control" 1
127 (eq_attr "type" "control,pop")
128 "cpu")
129
130 (define_insn_reservation "alu" 1
131 (eq_attr "type" "alu,add,sub,mov,and,or,xor,neg,not")
132 "cpu")
133
134 (define_insn_reservation "cond_alu" 1
135 (eq_attr "type" "cond_alu")
136 "cpu")
137
138 (define_insn_reservation "st" 1
139 (eq_attr "type" "st,stwm,push")
140 "cpu")
141
142 (define_insn_reservation "custom" 1
143 (eq_attr "type" "custom")
144 "cpu")
145
146 ; shifts, muls and lds have three cycle latency
147 (define_insn_reservation "ld" 3
148 (eq_attr "type" "ld,ldwm")
149 "cpu")
150
151 (define_insn_reservation "shift" 3
152 (eq_attr "type" "sll,srl,sra,rol,ror")
153 "cpu")
154
155 (define_insn_reservation "mul" 3
156 (eq_attr "type" "mul")
157 "cpu")
158
159 (define_insn_reservation "div" 1
160 (eq_attr "type" "div")
161 "cpu")
162
163 (include "predicates.md")
164 (include "constraints.md")
165
166 \f
167 ;; Move instructions
168
169 (define_mode_iterator M [QI HI SI])
170
171 (define_expand "mov<mode>"
172 [(set (match_operand:M 0 "nonimmediate_operand" "")
173 (match_operand:M 1 "general_operand" ""))]
174 ""
175 {
176 if (nios2_emit_move_sequence (operands, <MODE>mode))
177 DONE;
178 })
179
180 (define_insn "*high"
181 [(set (match_operand:SI 0 "register_operand" "=r")
182 (high:SI (match_operand:SI 1 "immediate_operand" "i")))]
183 ""
184 "movhi\\t%0, %H1"
185 [(set_attr "type" "alu")])
186
187 (define_insn "*lo_sum"
188 [(set (match_operand:SI 0 "register_operand" "=r")
189 (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
190 (match_operand:SI 2 "immediate_operand" "i")))]
191 ""
192 "addi\\t%0, %1, %L2"
193 [(set_attr "type" "alu")])
194
195 (define_insn "movqi_internal"
196 [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r")
197 (match_operand:QI 1 "general_operand" "rM,m,rI"))]
198 "(register_operand (operands[0], QImode)
199 || reg_or_0_operand (operands[1], QImode))"
200 {
201 switch (which_alternative)
202 {
203 case 0:
204 if (get_attr_length (insn) != 2)
205 return "stb%o0\\t%z1, %0";
206 else if (const_0_operand (operands[1], QImode))
207 return "stbz.n\\t%z1, %0";
208 else
209 return "stb.n\\t%z1, %0";
210 case 1:
211 return "ldbu%o1%.\\t%0, %1";
212 case 2:
213 return "mov%i1%.\\t%0, %z1";
214 default:
215 gcc_unreachable ();
216 }
217 }
218 [(set_attr "type" "st,ld,mov")])
219
220 (define_insn "movhi_internal"
221 [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r")
222 (match_operand:HI 1 "general_operand" "rM,m,rI"))]
223 "(register_operand (operands[0], HImode)
224 || reg_or_0_operand (operands[1], HImode))"
225 "@
226 sth%o0%.\\t%z1, %0
227 ldhu%o1%.\\t%0, %1
228 mov%i1%.\\t%0, %z1"
229 [(set_attr "type" "st,ld,mov")])
230
231 (define_insn "movsi_internal"
232 [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r")
233 (match_operand:SI 1 "general_operand" "rM,m,rIJK,S"))]
234 "(register_operand (operands[0], SImode)
235 || reg_or_0_operand (operands[1], SImode))"
236 {
237 switch (which_alternative)
238 {
239 case 0:
240 if (get_attr_length (insn) != 2)
241 return "stw%o0\\t%z1, %0";
242 else if (stack_memory_operand (operands[0], SImode))
243 return "stwsp.n\\t%z1, %0";
244 else if (const_0_operand (operands[1], SImode))
245 return "stwz.n\\t%z1, %0";
246 else
247 return "stw.n\\t%z1, %0";
248 case 1:
249 if (get_attr_length (insn) != 2)
250 return "ldw%o1\\t%0, %1";
251 else if (stack_memory_operand (operands[1], SImode))
252 return "ldwsp.n\\t%0, %1";
253 else
254 return "ldw.n\\t%0, %1";
255 case 2:
256 return "mov%i1%.\\t%0, %z1";
257 case 3:
258 return "addi\\t%0, gp, %%gprel(%1)";
259 default:
260 gcc_unreachable ();
261 }
262 }
263 [(set_attr "type" "st,ld,mov,alu")])
264
265 (define_mode_iterator BH [QI HI])
266 (define_mode_iterator BHW [QI HI SI])
267 (define_mode_attr bh [(QI "b") (HI "h")])
268 (define_mode_attr bhw [(QI "b") (HI "h") (SI "w")])
269 (define_mode_attr bhw_uns [(QI "bu") (HI "hu") (SI "w")])
270
271 (define_insn "ld<bhw_uns>io"
272 [(set (match_operand:BHW 0 "register_operand" "=r")
273 (unspec_volatile:BHW
274 [(match_operand:BHW 1 "ldstio_memory_operand" "w")] UNSPECV_LDXIO))]
275 ""
276 "ld<bhw_uns>io\\t%0, %1"
277 [(set_attr "type" "ld")])
278
279 (define_expand "ld<bh>io"
280 [(set (match_operand:BH 0 "register_operand" "=r")
281 (match_operand:BH 1 "ldstio_memory_operand" "w"))]
282 ""
283 {
284 rtx tmp = gen_reg_rtx (SImode);
285 emit_insn (gen_ld<bh>io_signed (tmp, operands[1]));
286 emit_insn (gen_mov<mode> (operands[0], gen_lowpart (<MODE>mode, tmp)));
287 DONE;
288 })
289
290 (define_insn "ld<bh>io_signed"
291 [(set (match_operand:SI 0 "register_operand" "=r")
292 (sign_extend:SI
293 (unspec_volatile:BH
294 [(match_operand:BH 1 "ldstio_memory_operand" "w")] UNSPECV_LDXIO)))]
295 ""
296 "ld<bh>io\\t%0, %1"
297 [(set_attr "type" "ld")])
298
299 (define_insn "st<bhw>io"
300 [(set (match_operand:BHW 0 "ldstio_memory_operand" "=w")
301 (unspec_volatile:BHW
302 [(match_operand:BHW 1 "reg_or_0_operand" "rM")] UNSPECV_STXIO))]
303 ""
304 "st<bhw>io\\t%z1, %0"
305 [(set_attr "type" "st")])
306
307 \f
308 ;; QI to [HI, SI] extension patterns are collected together
309 (define_mode_iterator QX [HI SI])
310
311 ;; Zero extension patterns
312 (define_insn "zero_extendhisi2"
313 [(set (match_operand:SI 0 "register_operand" "=r,r")
314 (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
315 ""
316 "@
317 andi%.\\t%0, %1, 0xffff
318 ldhu%o1%.\\t%0, %1"
319 [(set_attr "type" "and,ld")])
320
321 (define_insn "zero_extendqi<mode>2"
322 [(set (match_operand:QX 0 "register_operand" "=r,r")
323 (zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
324 ""
325 "@
326 andi%.\\t%0, %1, 0xff
327 ldbu%o1%.\\t%0, %1"
328 [(set_attr "type" "and,ld")])
329
330 ;; Sign extension patterns
331
332 (define_insn "extendhisi2"
333 [(set (match_operand:SI 0 "register_operand" "=r,r")
334 (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
335 ""
336 "@
337 #
338 ldh%o1%.\\t%0, %1"
339 [(set_attr "type" "alu,ld")])
340
341 (define_insn "extendqi<mode>2"
342 [(set (match_operand:QX 0 "register_operand" "=r,r")
343 (sign_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
344 ""
345 "@
346 #
347 ldb%o1%.\\t%0, %1"
348 [(set_attr "type" "alu,ld")])
349
350 ;; Split patterns for register alternative cases.
351 (define_split
352 [(set (match_operand:SI 0 "register_operand" "")
353 (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
354 "reload_completed"
355 [(set (match_dup 0)
356 (and:SI (match_dup 1) (const_int 65535)))
357 (set (match_dup 0)
358 (xor:SI (match_dup 0) (const_int 32768)))
359 (set (match_dup 0)
360 (plus:SI (match_dup 0) (const_int -32768)))]
361 "operands[1] = gen_lowpart (SImode, operands[1]);")
362
363 (define_split
364 [(set (match_operand:QX 0 "register_operand" "")
365 (sign_extend:QX (match_operand:QI 1 "register_operand" "")))]
366 "reload_completed"
367 [(set (match_dup 0)
368 (and:SI (match_dup 1) (const_int 255)))
369 (set (match_dup 0)
370 (xor:SI (match_dup 0) (const_int 128)))
371 (set (match_dup 0)
372 (plus:SI (match_dup 0) (const_int -128)))]
373 "operands[0] = gen_lowpart (SImode, operands[0]);
374 operands[1] = gen_lowpart (SImode, operands[1]);")
375
376 \f
377 ;; Arithmetic Operations
378
379 (define_insn "addsi3"
380 [(set (match_operand:SI 0 "register_operand" "=r")
381 (plus:SI (match_operand:SI 1 "register_operand" "%r")
382 (match_operand:SI 2 "add_regimm_operand" "rIT")))]
383 ""
384 {
385 return nios2_add_insn_asm (insn, operands);
386 }
387 [(set_attr "type" "add")])
388
389 (define_insn "subsi3"
390 [(set (match_operand:SI 0 "register_operand" "=r")
391 (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
392 (match_operand:SI 2 "register_operand" "r")))]
393 ""
394 "sub%.\\t%0, %z1, %2"
395 [(set_attr "type" "sub")])
396
397 (define_insn "mulsi3"
398 [(set (match_operand:SI 0 "register_operand" "=r")
399 (mult:SI (match_operand:SI 1 "register_operand" "%r")
400 (match_operand:SI 2 "arith_operand" "rI")))]
401 "TARGET_HAS_MUL"
402 "mul%i2\\t%0, %1, %z2"
403 [(set_attr "type" "mul")])
404
405 (define_expand "divsi3"
406 [(set (match_operand:SI 0 "register_operand" "=r")
407 (div:SI (match_operand:SI 1 "register_operand" "r")
408 (match_operand:SI 2 "register_operand" "r")))]
409 ""
410 {
411 if (!TARGET_HAS_DIV)
412 {
413 if (TARGET_FAST_SW_DIV)
414 {
415 nios2_emit_expensive_div (operands, SImode);
416 DONE;
417 }
418 else
419 FAIL;
420 }
421 })
422
423 (define_insn "divsi3_insn"
424 [(set (match_operand:SI 0 "register_operand" "=r")
425 (div:SI (match_operand:SI 1 "register_operand" "r")
426 (match_operand:SI 2 "register_operand" "r")))]
427 "TARGET_HAS_DIV"
428 "div\\t%0, %1, %2"
429 [(set_attr "type" "div")])
430
431 (define_insn "udivsi3"
432 [(set (match_operand:SI 0 "register_operand" "=r")
433 (udiv:SI (match_operand:SI 1 "register_operand" "r")
434 (match_operand:SI 2 "register_operand" "r")))]
435 "TARGET_HAS_DIV"
436 "divu\\t%0, %1, %2"
437 [(set_attr "type" "div")])
438
439 (define_code_iterator EXTEND [sign_extend zero_extend])
440 (define_code_attr us [(sign_extend "s") (zero_extend "u")])
441 (define_code_attr mul [(sign_extend "mul") (zero_extend "umul")])
442
443 (define_insn "<us>mulsi3_highpart"
444 [(set (match_operand:SI 0 "register_operand" "=r")
445 (truncate:SI
446 (lshiftrt:DI
447 (mult:DI (EXTEND:DI (match_operand:SI 1 "register_operand" "r"))
448 (EXTEND:DI (match_operand:SI 2 "register_operand" "r")))
449 (const_int 32))))]
450 "TARGET_HAS_MULX"
451 "mulx<us><us>\\t%0, %1, %2"
452 [(set_attr "type" "mul")])
453
454 (define_expand "<mul>sidi3"
455 [(set (match_operand:DI 0 "register_operand" "")
456 (mult:DI (EXTEND:DI (match_operand:SI 1 "register_operand" ""))
457 (EXTEND:DI (match_operand:SI 2 "register_operand" ""))))]
458 "TARGET_HAS_MULX"
459 {
460 rtx hi = gen_reg_rtx (SImode);
461 rtx lo = gen_reg_rtx (SImode);
462
463 emit_insn (gen_<us>mulsi3_highpart (hi, operands[1], operands[2]));
464 emit_insn (gen_mulsi3 (lo, operands[1], operands[2]));
465 emit_move_insn (gen_lowpart (SImode, operands[0]), lo);
466 emit_move_insn (gen_highpart (SImode, operands[0]), hi);
467 DONE;
468 })
469
470 \f
471 ;; Negate and ones complement
472
473 (define_insn "negsi2"
474 [(set (match_operand:SI 0 "register_operand" "=r")
475 (neg:SI (match_operand:SI 1 "register_operand" "r")))]
476 ""
477 {
478 if (get_attr_length (insn) == 2)
479 return "neg.n\\t%0, %1";
480 else
481 return "sub\\t%0, zero, %1";
482 }
483 [(set_attr "type" "neg")])
484
485 (define_insn "one_cmplsi2"
486 [(set (match_operand:SI 0 "register_operand" "=r")
487 (not:SI (match_operand:SI 1 "register_operand" "r")))]
488 ""
489 {
490 if (get_attr_length (insn) == 2)
491 return "not.n\\t%0, %1";
492 else
493 return "nor\\t%0, zero, %1";
494 }
495 [(set_attr "type" "not")])
496
497 \f
498 ;; Integer logical Operations
499
500 (define_insn "andsi3"
501 [(set (match_operand:SI 0 "register_operand" "=r")
502 (and:SI (match_operand:SI 1 "register_operand" "%r")
503 (match_operand:SI 2 "and_operand" "rJKP")))]
504 ""
505 "and%x2%.\\t%0, %1, %y2"
506 [(set_attr "type" "and")])
507
508 (define_code_iterator LOGICAL [ior xor])
509 (define_code_attr logical_asm [(ior "or") (xor "xor")])
510
511 (define_insn "<code>si3"
512 [(set (match_operand:SI 0 "register_operand" "=r")
513 (LOGICAL:SI (match_operand:SI 1 "register_operand" "%r")
514 (match_operand:SI 2 "logical_operand" "rJK")))]
515 ""
516 "<logical_asm>%x2%.\\t%0, %1, %y2"
517 [(set_attr "type" "<logical_asm>")])
518
519 (define_insn "*norsi3"
520 [(set (match_operand:SI 0 "register_operand" "=r")
521 (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
522 (not:SI (match_operand:SI 2 "register_operand" "r"))))]
523 ""
524 "nor\\t%0, %1, %2"
525 [(set_attr "type" "alu")])
526
527 \f
528 ;; Shift instructions
529
530 (define_code_iterator SHIFT [ashift ashiftrt lshiftrt rotate])
531 (define_code_attr shift_op [(ashift "ashl") (ashiftrt "ashr")
532 (lshiftrt "lshr") (rotate "rotl")])
533 (define_code_attr shift_asm [(ashift "sll") (ashiftrt "sra")
534 (lshiftrt "srl") (rotate "rol")])
535
536 (define_insn "<shift_op>si3"
537 [(set (match_operand:SI 0 "register_operand" "=r")
538 (SHIFT:SI (match_operand:SI 1 "register_operand" "r")
539 (match_operand:SI 2 "shift_operand" "rL")))]
540 ""
541 "<shift_asm>%i2%.\\t%0, %1, %z2"
542 [(set_attr "type" "<shift_asm>")])
543
544 (define_insn "rotrsi3"
545 [(set (match_operand:SI 0 "register_operand" "=r")
546 (rotatert:SI (match_operand:SI 1 "register_operand" "r")
547 (match_operand:SI 2 "register_operand" "r")))]
548 ""
549 "ror\\t%0, %1, %2"
550 [(set_attr "type" "ror")])
551
552 ;; Nios II R2 Bit Manipulation Extension (BMX), provides
553 ;; bit merge/insertion/extraction instructions.
554
555 (define_insn "*merge"
556 [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
557 (match_operand:SI 1 "const_shift_operand" "L")
558 (match_operand:SI 2 "const_shift_operand" "L"))
559 (zero_extract:SI (match_operand:SI 3 "register_operand" "r")
560 (match_dup 1) (match_dup 2)))]
561 "TARGET_HAS_BMX"
562 {
563 operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
564 return "merge\\t%0, %3, %4, %2";
565 }
566 [(set_attr "type" "alu")])
567
568 (define_insn "extzv"
569 [(set (match_operand:SI 0 "register_operand" "=r")
570 (zero_extract:SI (match_operand:SI 1 "register_operand" "r")
571 (match_operand:SI 2 "const_shift_operand" "L")
572 (match_operand:SI 3 "const_shift_operand" "L")))]
573 "TARGET_HAS_BMX"
574 {
575 operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]) - 1);
576 return "extract\\t%0, %1, %4, %3";
577 }
578 [(set_attr "type" "alu")])
579
580 (define_insn "insv"
581 [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r")
582 (match_operand:SI 1 "const_shift_operand" "L")
583 (match_operand:SI 2 "const_shift_operand" "L"))
584 (match_operand:SI 3 "reg_or_0_operand" "rM"))]
585 "TARGET_HAS_BMX"
586 {
587 operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2]) - 1);
588 return "insert\\t%0, %z3, %4, %2";
589 }
590 [(set_attr "type" "alu")])
591
592
593 \f
594 ;; Floating point instructions
595
596 ;; Mode iterator for single/double float
597 (define_mode_iterator F [SF DF])
598 (define_mode_attr f [(SF "s") (DF "d")])
599
600 ;; Basic arithmetic instructions
601 (define_code_iterator FOP3 [plus minus mult div])
602 (define_code_attr fop3 [(plus "add") (minus "sub") (mult "mul") (div "div")])
603
604 (define_insn "<fop3><mode>3"
605 [(set (match_operand:F 0 "register_operand" "=r")
606 (FOP3:F (match_operand:F 1 "register_operand" "r")
607 (match_operand:F 2 "register_operand" "r")))]
608 "nios2_fpu_insn_enabled (n2fpu_f<fop3><f>)"
609 { return nios2_fpu_insn_asm (n2fpu_f<fop3><f>); }
610 [(set_attr "type" "custom")])
611
612 ;; Floating point min/max operations
613 (define_code_iterator SMINMAX [smin smax])
614 (define_code_attr minmax [(smin "min") (smax "max")])
615 (define_insn "<code><mode>3"
616 [(set (match_operand:F 0 "register_operand" "=r")
617 (SMINMAX:F (match_operand:F 1 "register_operand" "r")
618 (match_operand:F 2 "register_operand" "r")))]
619 "nios2_fpu_insn_enabled (n2fpu_f<minmax><f>)"
620 { return nios2_fpu_insn_asm (n2fpu_f<minmax><f>); }
621 [(set_attr "type" "custom")])
622
623 ;; These 2-operand FP operations can be collected together
624 (define_code_iterator FOP2 [abs neg sqrt])
625 (define_insn "<code><mode>2"
626 [(set (match_operand:F 0 "register_operand" "=r")
627 (FOP2:F (match_operand:F 1 "register_operand" "r")))]
628 "nios2_fpu_insn_enabled (n2fpu_f<code><f>)"
629 { return nios2_fpu_insn_asm (n2fpu_f<code><f>); }
630 [(set_attr "type" "custom")])
631
632 ;; X, Y register access instructions
633 (define_insn "nios2_fwrx"
634 [(unspec_volatile [(match_operand:DF 0 "register_operand" "r")] UNSPECV_FWRX)]
635 "nios2_fpu_insn_enabled (n2fpu_fwrx)"
636 { return nios2_fpu_insn_asm (n2fpu_fwrx); }
637 [(set_attr "type" "custom")])
638
639 (define_insn "nios2_fwry"
640 [(unspec_volatile [(match_operand:SF 0 "register_operand" "r")] UNSPECV_FWRY)]
641 "nios2_fpu_insn_enabled (n2fpu_fwry)"
642 { return nios2_fpu_insn_asm (n2fpu_fwry); }
643 [(set_attr "type" "custom")])
644
645 ;; The X, Y read insns uses an int iterator
646 (define_int_iterator UNSPEC_READ_XY [UNSPECV_FRDXLO UNSPECV_FRDXHI
647 UNSPECV_FRDY])
648 (define_int_attr read_xy [(UNSPECV_FRDXLO "frdxlo") (UNSPECV_FRDXHI "frdxhi")
649 (UNSPECV_FRDY "frdy")])
650 (define_insn "nios2_<read_xy>"
651 [(set (match_operand:SF 0 "register_operand" "=r")
652 (unspec_volatile:SF [(const_int 0)] UNSPEC_READ_XY))]
653 "nios2_fpu_insn_enabled (n2fpu_<read_xy>)"
654 { return nios2_fpu_insn_asm (n2fpu_<read_xy>); }
655 [(set_attr "type" "custom")])
656
657 ;; Various math functions
658 (define_int_iterator MATHFUNC
659 [UNSPEC_FCOS UNSPEC_FSIN UNSPEC_FTAN UNSPEC_FATAN UNSPEC_FEXP UNSPEC_FLOG])
660 (define_int_attr mathfunc [(UNSPEC_FCOS "cos") (UNSPEC_FSIN "sin")
661 (UNSPEC_FTAN "tan") (UNSPEC_FATAN "atan")
662 (UNSPEC_FEXP "exp") (UNSPEC_FLOG "log")])
663
664 (define_insn "<mathfunc><mode>2"
665 [(set (match_operand:F 0 "register_operand" "=r")
666 (unspec:F [(match_operand:F 1 "register_operand" "r")] MATHFUNC))]
667 "nios2_fpu_insn_enabled (n2fpu_f<mathfunc><f>)"
668 { return nios2_fpu_insn_asm (n2fpu_f<mathfunc><f>); }
669 [(set_attr "type" "custom")])
670
671 ;; Converting between floating point and fixed point
672
673 (define_code_iterator FLOAT [float unsigned_float])
674 (define_code_iterator FIX [fix unsigned_fix])
675
676 (define_code_attr conv_op [(float "float") (unsigned_float "floatuns")
677 (fix "fix") (unsigned_fix "fixuns")])
678 (define_code_attr i [(float "i") (unsigned_float "u")
679 (fix "i") (unsigned_fix "u")])
680
681 ;; Integer to float conversions
682 (define_insn "<conv_op>si<mode>2"
683 [(set (match_operand:F 0 "register_operand" "=r")
684 (FLOAT:F (match_operand:SI 1 "register_operand" "r")))]
685 "nios2_fpu_insn_enabled (n2fpu_float<i><f>)"
686 { return nios2_fpu_insn_asm (n2fpu_float<i><f>); }
687 [(set_attr "type" "custom")])
688
689 ;; Float to integer conversions
690 (define_insn "<conv_op>_trunc<mode>si2"
691 [(set (match_operand:SI 0 "register_operand" "=r")
692 (FIX:SI (match_operand:F 1 "general_operand" "r")))]
693 "nios2_fpu_insn_enabled (n2fpu_fix<f><i>)"
694 { return nios2_fpu_insn_asm (n2fpu_fix<f><i>); }
695 [(set_attr "type" "custom")])
696
697 (define_insn "lroundsfsi2"
698 [(set (match_operand:SI 0 "register_operand" "=r")
699 (unspec:SI [(match_operand:SF 1 "general_operand" "r")] UNSPEC_ROUND))]
700 "nios2_fpu_insn_enabled (n2fpu_round)"
701 { return nios2_fpu_insn_asm (n2fpu_round); }
702 [(set_attr "type" "custom")])
703
704 (define_insn "extendsfdf2"
705 [(set (match_operand:DF 0 "register_operand" "=r")
706 (float_extend:DF (match_operand:SF 1 "general_operand" "r")))]
707 "nios2_fpu_insn_enabled (n2fpu_fextsd)"
708 { return nios2_fpu_insn_asm (n2fpu_fextsd); }
709 [(set_attr "type" "custom")])
710
711 (define_insn "truncdfsf2"
712 [(set (match_operand:SF 0 "register_operand" "=r")
713 (float_truncate:SF (match_operand:DF 1 "general_operand" "r")))]
714 "nios2_fpu_insn_enabled (n2fpu_ftruncds)"
715 { return nios2_fpu_insn_asm (n2fpu_ftruncds); }
716 [(set_attr "type" "custom")])
717
718
719 \f
720 ;; Prologue, Epilogue and Return
721
722 (define_expand "prologue"
723 [(const_int 1)]
724 ""
725 {
726 nios2_expand_prologue ();
727 DONE;
728 })
729
730 (define_expand "epilogue"
731 [(return)]
732 ""
733 {
734 nios2_expand_epilogue (false);
735 DONE;
736 })
737
738 (define_expand "sibcall_epilogue"
739 [(return)]
740 ""
741 {
742 nios2_expand_epilogue (true);
743 DONE;
744 })
745
746 (define_expand "return"
747 [(simple_return)]
748 "nios2_can_use_return_insn ()"
749 {
750 if (nios2_expand_return ())
751 DONE;
752 })
753
754 (define_insn "simple_return"
755 [(simple_return)]
756 ""
757 "ret%."
758 [(set_attr "type" "control")])
759
760 ;; Block any insns from being moved before this point, since the
761 ;; profiling call to mcount can use various registers that aren't
762 ;; saved or used to pass arguments.
763
764 (define_insn "blockage"
765 [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
766 ""
767 ""
768 [(set_attr "type" "unknown")
769 (set_attr "length" "0")])
770
771 ;; This is used in compiling the unwind routines.
772 (define_expand "eh_return"
773 [(use (match_operand 0 "general_operand"))]
774 ""
775 {
776 if (GET_MODE (operands[0]) != Pmode)
777 operands[0] = convert_to_mode (Pmode, operands[0], 0);
778 emit_insn (gen_eh_set_ra (operands[0]));
779 DONE;
780 })
781
782 ;; Modify the return address for EH return. We can't expand this
783 ;; until we know where it will be put in the stack frame.
784
785 (define_insn_and_split "eh_set_ra"
786 [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN)
787 (clobber (match_scratch:SI 1 "=&r"))]
788 ""
789 "#"
790 "reload_completed"
791 [(const_int 0)]
792 {
793 nios2_set_return_address (operands[0], operands[1]);
794 DONE;
795 })
796
797 \f
798 ;; Jumps and calls
799
800 ; Note that the assembler fixes up any out-of-range branch instructions not
801 ; caught by the compiler branch shortening code. The sequence emitted by
802 ; the assembler can be very inefficient, but it is correct for PIC code.
803 ; For non-PIC we are better off converting to an absolute JMPI.
804 ;
805 ; Direct calls and sibcalls use the CALL and JMPI instructions, respectively.
806 ; These instructions have an immediate operand that specifies the low 28 bits
807 ; of the PC, effectively allowing direct calls within a 256MB memory segment.
808 ; Per the Nios II Processor Reference Handbook, the linker is not required to
809 ; check or adjust for overflow.
810
811 (define_insn "indirect_jump"
812 [(set (pc) (match_operand:SI 0 "register_operand" "c"))]
813 ""
814 "jmp%!\\t%0"
815 [(set_attr "type" "control")])
816
817 (define_insn "jump"
818 [(set (pc)
819 (label_ref (match_operand 0 "" "")))]
820 ""
821 {
822 if (get_attr_length (insn) == 2)
823 return "br.n\\t%0";
824 else if (get_attr_length (insn) == 4)
825 return "br\\t%0";
826 else
827 return "jmpi\\t%0";
828 }
829 [(set_attr "type" "control")
830 (set (attr "length")
831 (if_then_else
832 (and (match_test "TARGET_HAS_CDX")
833 (and (ge (minus (match_dup 0) (pc)) (const_int -1022))
834 (le (minus (match_dup 0) (pc)) (const_int 1022))))
835 (const_int 2)
836 (if_then_else
837 (ior (match_test "flag_pic")
838 (and (ge (minus (match_dup 0) (pc)) (const_int -32764))
839 (le (minus (match_dup 0) (pc)) (const_int 32764))))
840 (const_int 4)
841 (const_int 8))))])
842
843 (define_expand "call"
844 [(parallel [(call (match_operand 0 "" "")
845 (match_operand 1 "" ""))
846 (clobber (reg:SI RA_REGNO))])]
847 ""
848 "nios2_adjust_call_address (&operands[0], NULL_RTX);")
849
850 (define_expand "call_value"
851 [(parallel [(set (match_operand 0 "" "")
852 (call (match_operand 1 "" "")
853 (match_operand 2 "" "")))
854 (clobber (reg:SI RA_REGNO))])]
855 ""
856 "nios2_adjust_call_address (&operands[1], NULL_RTX);")
857
858 (define_insn "*call"
859 [(call (mem:QI (match_operand:SI 0 "call_operand" "i,r"))
860 (match_operand 1 "" ""))
861 (clobber (reg:SI RA_REGNO))]
862 ""
863 "@
864 call\\t%0
865 callr%.\\t%0"
866 [(set_attr "type" "control")])
867
868 (define_insn "*call_value"
869 [(set (match_operand 0 "" "")
870 (call (mem:QI (match_operand:SI 1 "call_operand" "i,r"))
871 (match_operand 2 "" "")))
872 (clobber (reg:SI RA_REGNO))]
873 ""
874 "@
875 call\\t%1
876 callr%.\\t%1"
877 [(set_attr "type" "control")])
878
879 (define_expand "sibcall"
880 [(parallel [(call (match_operand 0 "" "")
881 (match_operand 1 "" ""))
882 (return)])]
883 ""
884 "nios2_adjust_call_address (&operands[0], NULL_RTX);")
885
886 (define_expand "sibcall_value"
887 [(parallel [(set (match_operand 0 "" "")
888 (call (match_operand 1 "" "")
889 (match_operand 2 "" "")))
890 (return)])]
891 ""
892 "nios2_adjust_call_address (&operands[1], NULL_RTX);")
893
894 (define_insn "sibcall_internal"
895 [(call (mem:QI (match_operand:SI 0 "call_operand" "i,j"))
896 (match_operand 1 "" ""))
897 (return)]
898 ""
899 "@
900 jmpi\\t%0
901 jmp%!\\t%0"
902 [(set_attr "type" "control")])
903
904 (define_insn "sibcall_value_internal"
905 [(set (match_operand 0 "register_operand" "")
906 (call (mem:QI (match_operand:SI 1 "call_operand" "i,j"))
907 (match_operand 2 "" "")))
908 (return)]
909 ""
910 "@
911 jmpi\\t%1
912 jmp%!\\t%1"
913 [(set_attr "type" "control")])
914
915 (define_expand "tablejump"
916 [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
917 (use (label_ref (match_operand 1 "" "")))])]
918 ""
919 {
920 if (flag_pic)
921 {
922 /* Hopefully, CSE will eliminate this copy. */
923 rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1]));
924 rtx reg2 = gen_reg_rtx (SImode);
925
926 emit_insn (gen_addsi3 (reg2, operands[0], reg1));
927 operands[0] = reg2;
928 }
929 })
930
931 (define_insn "*tablejump"
932 [(set (pc)
933 (match_operand:SI 0 "register_operand" "c"))
934 (use (label_ref (match_operand 1 "" "")))]
935 ""
936 "jmp%!\\t%0"
937 [(set_attr "type" "control")])
938
939 \f
940 ;; cstore, cbranch patterns
941
942 (define_mode_iterator CM [SI SF DF])
943
944 (define_expand "cstore<mode>4"
945 [(set (match_operand:SI 0 "register_operand" "=r")
946 (match_operator:SI 1 "expandable_comparison_operator"
947 [(match_operand:CM 2 "register_operand")
948 (match_operand:CM 3 "nonmemory_operand")]))]
949 ""
950 {
951 if (!nios2_validate_compare (<MODE>mode, &operands[1], &operands[2],
952 &operands[3]))
953 FAIL;
954 })
955
956 (define_expand "cbranch<mode>4"
957 [(set (pc)
958 (if_then_else
959 (match_operator 0 "expandable_comparison_operator"
960 [(match_operand:CM 1 "register_operand")
961 (match_operand:CM 2 "nonmemory_operand")])
962 (label_ref (match_operand 3 ""))
963 (pc)))]
964 ""
965 {
966 if (!nios2_validate_compare (<MODE>mode, &operands[0], &operands[1],
967 &operands[2]))
968 FAIL;
969 if (GET_MODE_CLASS (<MODE>mode) == MODE_FLOAT
970 || !reg_or_0_operand (operands[2], <MODE>mode))
971 {
972 rtx condreg = gen_reg_rtx (SImode);
973 emit_insn (gen_cstore<mode>4
974 (condreg, operands[0], operands[1], operands[2]));
975 operands[1] = condreg;
976 operands[2] = const0_rtx;
977 operands[0] = gen_rtx_fmt_ee (NE, VOIDmode, condreg, const0_rtx);
978 }
979 })
980
981 (define_insn "nios2_cbranch"
982 [(set (pc)
983 (if_then_else
984 (match_operator 0 "ordered_comparison_operator"
985 [(match_operand:SI 1 "reg_or_0_operand" "rM")
986 (match_operand:SI 2 "reg_or_0_operand" "rM")])
987 (label_ref (match_operand 3 "" ""))
988 (pc)))]
989 ""
990 {
991 if (get_attr_length (insn) == 2)
992 return "b%0z.n\t%z1, %l3";
993 else if (get_attr_length (insn) == 4)
994 return "b%0\t%z1, %z2, %l3";
995 else if (get_attr_length (insn) == 6)
996 return "b%R0z.n\t%z1, .+6;jmpi\t%l3";
997 else
998 return "b%R0\t%z1, %z2, .+8;jmpi\t%l3";
999 }
1000 [(set_attr "type" "control")
1001 (set (attr "length")
1002 (cond
1003 [(and (match_test "nios2_cdx_narrow_form_p (insn)")
1004 (ge (minus (match_dup 3) (pc)) (const_int -126))
1005 (le (minus (match_dup 3) (pc)) (const_int 126)))
1006 (const_int 2)
1007 (ior (match_test "flag_pic")
1008 (and (ge (minus (match_dup 3) (pc)) (const_int -32764))
1009 (le (minus (match_dup 3) (pc)) (const_int 32764))))
1010 (const_int 4)
1011 (match_test "nios2_cdx_narrow_form_p (insn)")
1012 (const_int 6)]
1013 (const_int 8)))])
1014
1015 ;; Floating point comparisons
1016 (define_code_iterator FCMP [eq ne gt ge le lt])
1017 (define_insn "nios2_s<code><mode>"
1018 [(set (match_operand:SI 0 "register_operand" "=r")
1019 (FCMP:SI (match_operand:F 1 "register_operand" "r")
1020 (match_operand:F 2 "register_operand" "r")))]
1021 "nios2_fpu_insn_enabled (n2fpu_fcmp<code><f>)"
1022 { return nios2_fpu_insn_asm (n2fpu_fcmp<code><f>); }
1023 [(set_attr "type" "custom")])
1024
1025 ;; Integer comparisons
1026
1027 (define_code_iterator EQNE [eq ne])
1028 (define_insn "nios2_cmp<code>"
1029 [(set (match_operand:SI 0 "register_operand" "=r")
1030 (EQNE:SI (match_operand:SI 1 "register_operand" "%r")
1031 (match_operand:SI 2 "arith_operand" "rI")))]
1032 ""
1033 "cmp<code>%i2\\t%0, %1, %z2"
1034 [(set_attr "type" "alu")])
1035
1036 (define_code_iterator SCMP [ge lt])
1037 (define_insn "nios2_cmp<code>"
1038 [(set (match_operand:SI 0 "register_operand" "=r")
1039 (SCMP:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
1040 (match_operand:SI 2 "arith_operand" "rI")))]
1041 ""
1042 "cmp<code>%i2\\t%0, %z1, %z2"
1043 [(set_attr "type" "alu")])
1044
1045 (define_code_iterator UCMP [geu ltu])
1046 (define_insn "nios2_cmp<code>"
1047 [(set (match_operand:SI 0 "register_operand" "=r")
1048 (UCMP:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
1049 (match_operand:SI 2 "uns_arith_operand" "rJ")))]
1050 ""
1051 "cmp<code>%u2\\t%0, %z1, %z2"
1052 [(set_attr "type" "alu")])
1053
1054
1055 \f
1056 ;; Custom instruction patterns. The operands are intentionally
1057 ;; mode-less, to serve as generic carriers of all Altera defined
1058 ;; built-in instruction/function types.
1059
1060 (define_insn "custom_nxx"
1061 [(unspec_volatile [(match_operand 0 "custom_insn_opcode" "N")
1062 (match_operand 1 "reg_or_0_operand" "rM")
1063 (match_operand 2 "reg_or_0_operand" "rM")]
1064 UNSPECV_CUSTOM_NXX)]
1065 ""
1066 "custom\\t%0, zero, %z1, %z2"
1067 [(set_attr "type" "custom")])
1068
1069 (define_insn "custom_xnxx"
1070 [(set (match_operand 0 "register_operand" "=r")
1071 (unspec_volatile [(match_operand 1 "custom_insn_opcode" "N")
1072 (match_operand 2 "reg_or_0_operand" "rM")
1073 (match_operand 3 "reg_or_0_operand" "rM")]
1074 UNSPECV_CUSTOM_XNXX))]
1075 ""
1076 "custom\\t%1, %0, %z2, %z3"
1077 [(set_attr "type" "custom")])
1078
1079 \f
1080 ;; Misc. patterns
1081
1082 (define_insn "nop"
1083 [(const_int 0)]
1084 ""
1085 "nop%."
1086 [(set_attr "type" "nop")])
1087
1088 ;; Connect 'sync' to 'memory_barrier' standard expand name
1089 (define_expand "memory_barrier"
1090 [(const_int 0)]
1091 ""
1092 {
1093 emit_insn (gen_sync ());
1094 DONE;
1095 })
1096
1097 ;; For the nios2 __builtin_sync built-in function
1098 (define_expand "sync"
1099 [(set (match_dup 0)
1100 (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
1101 ""
1102 {
1103 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode));
1104 MEM_VOLATILE_P (operands[0]) = 1;
1105 })
1106
1107 (define_insn "*sync_insn"
1108 [(set (match_operand:BLK 0 "" "")
1109 (unspec:BLK [(match_dup 0)] UNSPEC_SYNC))]
1110 ""
1111 "sync"
1112 [(set_attr "type" "control")])
1113
1114 (define_insn "rdctl"
1115 [(set (match_operand:SI 0 "register_operand" "=r")
1116 (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")]
1117 UNSPECV_RDCTL))]
1118 ""
1119 "rdctl\\t%0, ctl%1"
1120 [(set_attr "type" "control")])
1121
1122 (define_insn "wrctl"
1123 [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O")
1124 (match_operand:SI 1 "reg_or_0_operand" "rM")]
1125 UNSPECV_WRCTL)]
1126 ""
1127 "wrctl\\tctl%0, %z1"
1128 [(set_attr "type" "control")])
1129
1130 ;; Trap patterns
1131 (define_insn "trap"
1132 [(trap_if (const_int 1) (const_int 3))]
1133 ""
1134 "trap%.\\t3"
1135 [(set_attr "type" "control")])
1136
1137 (define_insn "ctrapsi4"
1138 [(trap_if (match_operator 0 "ordered_comparison_operator"
1139 [(match_operand:SI 1 "reg_or_0_operand" "rM")
1140 (match_operand:SI 2 "reg_or_0_operand" "rM")])
1141 (match_operand 3 "const_int_operand" "i"))]
1142 ""
1143 {
1144 if (get_attr_length (insn) == 6)
1145 return "b%R0\\t%z1, %z2, 1f\;trap.n\\t%3\;1:";
1146 else
1147 return "b%R0\\t%z1, %z2, 1f\;trap\\t%3\;1:";
1148 }
1149 [(set_attr "type" "control")
1150 (set (attr "length")
1151 (if_then_else (match_test "nios2_cdx_narrow_form_p (insn)")
1152 (const_int 6) (const_int 8)))])
1153
1154 ;; Load the GOT register.
1155 (define_insn "load_got_register"
1156 [(set (match_operand:SI 0 "register_operand" "=&r")
1157 (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))
1158 (set (match_operand:SI 1 "register_operand" "=r")
1159 (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))]
1160 ""
1161 "nextpc\\t%0
1162 \\t1:
1163 \\tmovhi\\t%1, %%hiadj(_gp_got - 1b)
1164 \\taddi\\t%1, %1, %%lo(_gp_got - 1b)"
1165 [(set_attr "length" "12")])
1166
1167 ;; Read thread pointer register
1168 (define_expand "get_thread_pointersi"
1169 [(match_operand:SI 0 "register_operand" "=r")]
1170 "TARGET_LINUX_ABI"
1171 {
1172 emit_move_insn (operands[0], gen_rtx_REG (Pmode, TP_REGNO));
1173 DONE;
1174 })
1175 ;; Include the ldwm/stwm/push.n/pop.n patterns and peepholes.
1176 (include "ldstwm.md")
1177