* gcc-interface/trans.c (process_freeze_entity): Be prepared for a
[official-gcc.git] / gcc / config / nds32 / nds32-md-auxiliary.c
blob5888438ffd43fa03fa745d536858d862230a90be
1 /* Auxiliary functions for output asm template or expand rtl
2 pattern of Andes NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2017 Free Software Foundation, Inc.
4 Contributed by Andes Technology Corporation.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published
10 by the Free Software Foundation; either version 3, or (at your
11 option) any later version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
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/>. */
22 /* ------------------------------------------------------------------------ */
24 #include "config.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "backend.h"
28 #include "target.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "memmodel.h"
32 #include "tm_p.h"
33 #include "optabs.h" /* For GEN_FCN. */
34 #include "recog.h"
35 #include "output.h"
36 #include "tm-constrs.h"
38 /* ------------------------------------------------------------------------ */
40 /* A helper function to return character based on byte size. */
41 static char
42 nds32_byte_to_size (int byte)
44 switch (byte)
46 case 4:
47 return 'w';
48 case 2:
49 return 'h';
50 case 1:
51 return 'b';
52 default:
53 /* Normally it should not be here. */
54 gcc_unreachable ();
58 /* A helper function to return memory format. */
59 enum nds32_16bit_address_type
60 nds32_mem_format (rtx op)
62 machine_mode mode_test;
63 int val;
64 int regno;
66 if (!TARGET_16_BIT)
67 return ADDRESS_NOT_16BIT_FORMAT;
69 mode_test = GET_MODE (op);
71 op = XEXP (op, 0);
73 /* 45 format. */
74 if (GET_CODE (op) == REG && (mode_test == SImode))
75 return ADDRESS_REG;
77 /* 333 format for QI/HImode. */
78 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
79 return ADDRESS_LO_REG_IMM3U;
81 /* post_inc 333 format. */
82 if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
84 regno = REGNO(XEXP (op, 0));
86 if (regno < 8)
87 return ADDRESS_POST_INC_LO_REG_IMM3U;
90 /* post_inc 333 format. */
91 if ((GET_CODE (op) == POST_MODIFY)
92 && (mode_test == SImode)
93 && (REG_P (XEXP (XEXP (op, 1), 0)))
94 && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
96 regno = REGNO (XEXP (XEXP (op, 1), 0));
97 val = INTVAL (XEXP (XEXP (op, 1), 1));
98 if (regno < 8 && val < 32)
99 return ADDRESS_POST_INC_LO_REG_IMM3U;
102 if ((GET_CODE (op) == PLUS)
103 && (GET_CODE (XEXP (op, 0)) == REG)
104 && (GET_CODE (XEXP (op, 1)) == CONST_INT))
106 val = INTVAL (XEXP (op, 1));
108 regno = REGNO(XEXP (op, 0));
110 if (regno > 7
111 && regno != SP_REGNUM
112 && regno != FP_REGNUM)
113 return ADDRESS_NOT_16BIT_FORMAT;
115 switch (mode_test)
117 case E_QImode:
118 /* 333 format. */
119 if (val >= 0 && val < 8 && regno < 8)
120 return ADDRESS_LO_REG_IMM3U;
121 break;
123 case E_HImode:
124 /* 333 format. */
125 if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
126 return ADDRESS_LO_REG_IMM3U;
127 break;
129 case E_SImode:
130 case E_SFmode:
131 case E_DFmode:
132 /* fp imply 37 format. */
133 if ((regno == FP_REGNUM) &&
134 (val >= 0 && val < 512 && (val % 4 == 0)))
135 return ADDRESS_FP_IMM7U;
136 /* sp imply 37 format. */
137 else if ((regno == SP_REGNUM) &&
138 (val >= 0 && val < 512 && (val % 4 == 0)))
139 return ADDRESS_SP_IMM7U;
140 /* 333 format. */
141 else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
142 return ADDRESS_LO_REG_IMM3U;
143 break;
145 default:
146 break;
150 return ADDRESS_NOT_16BIT_FORMAT;
153 /* Output 16-bit store. */
154 const char *
155 nds32_output_16bit_store (rtx *operands, int byte)
157 char pattern[100];
158 char size;
159 rtx code = XEXP (operands[0], 0);
161 size = nds32_byte_to_size (byte);
163 switch (nds32_mem_format (operands[0]))
165 case ADDRESS_REG:
166 operands[0] = code;
167 output_asm_insn ("swi450\t%1, [%0]", operands);
168 break;
169 case ADDRESS_LO_REG_IMM3U:
170 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
171 output_asm_insn (pattern, operands);
172 break;
173 case ADDRESS_POST_INC_LO_REG_IMM3U:
174 snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
175 output_asm_insn (pattern, operands);
176 break;
177 case ADDRESS_FP_IMM7U:
178 output_asm_insn ("swi37\t%1, %0", operands);
179 break;
180 case ADDRESS_SP_IMM7U:
181 /* Get immediate value and set back to operands[1]. */
182 operands[0] = XEXP (code, 1);
183 output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
184 break;
185 default:
186 break;
189 return "";
192 /* Output 16-bit load. */
193 const char *
194 nds32_output_16bit_load (rtx *operands, int byte)
196 char pattern[100];
197 unsigned char size;
198 rtx code = XEXP (operands[1], 0);
200 size = nds32_byte_to_size (byte);
202 switch (nds32_mem_format (operands[1]))
204 case ADDRESS_REG:
205 operands[1] = code;
206 output_asm_insn ("lwi450\t%0, [%1]", operands);
207 break;
208 case ADDRESS_LO_REG_IMM3U:
209 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
210 output_asm_insn (pattern, operands);
211 break;
212 case ADDRESS_POST_INC_LO_REG_IMM3U:
213 snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
214 output_asm_insn (pattern, operands);
215 break;
216 case ADDRESS_FP_IMM7U:
217 output_asm_insn ("lwi37\t%0, %1", operands);
218 break;
219 case ADDRESS_SP_IMM7U:
220 /* Get immediate value and set back to operands[0]. */
221 operands[1] = XEXP (code, 1);
222 output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
223 break;
224 default:
225 break;
228 return "";
231 /* Output 32-bit store. */
232 const char *
233 nds32_output_32bit_store (rtx *operands, int byte)
235 char pattern[100];
236 unsigned char size;
237 rtx code = XEXP (operands[0], 0);
239 size = nds32_byte_to_size (byte);
241 switch (GET_CODE (code))
243 case REG:
244 /* (mem (reg X))
245 => access location by using register,
246 use "sbi / shi / swi" */
247 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
248 break;
250 case SYMBOL_REF:
251 case CONST:
252 /* (mem (symbol_ref X))
253 (mem (const (...)))
254 => access global variables,
255 use "sbi.gp / shi.gp / swi.gp" */
256 operands[0] = XEXP (operands[0], 0);
257 snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
258 break;
260 case POST_INC:
261 /* (mem (post_inc reg))
262 => access location by using register which will be post increment,
263 use "sbi.bi / shi.bi / swi.bi" */
264 snprintf (pattern, sizeof (pattern),
265 "s%ci.bi\t%%1, %%0, %d", size, byte);
266 break;
268 case POST_DEC:
269 /* (mem (post_dec reg))
270 => access location by using register which will be post decrement,
271 use "sbi.bi / shi.bi / swi.bi" */
272 snprintf (pattern, sizeof (pattern),
273 "s%ci.bi\t%%1, %%0, -%d", size, byte);
274 break;
276 case POST_MODIFY:
277 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
279 case REG:
280 case SUBREG:
281 /* (mem (post_modify (reg) (plus (reg) (reg))))
282 => access location by using register which will be
283 post modified with reg,
284 use "sb.bi/ sh.bi / sw.bi" */
285 snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
286 break;
287 case CONST_INT:
288 /* (mem (post_modify (reg) (plus (reg) (const_int))))
289 => access location by using register which will be
290 post modified with const_int,
291 use "sbi.bi/ shi.bi / swi.bi" */
292 snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
293 break;
294 default:
295 abort ();
297 break;
299 case PLUS:
300 switch (GET_CODE (XEXP (code, 1)))
302 case REG:
303 case SUBREG:
304 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
305 => access location by adding two registers,
306 use "sb / sh / sw" */
307 snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
308 break;
309 case CONST_INT:
310 /* (mem (plus reg const_int))
311 => access location by adding one register with const_int,
312 use "sbi / shi / swi" */
313 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
314 break;
315 default:
316 abort ();
318 break;
320 case LO_SUM:
321 operands[2] = XEXP (code, 1);
322 operands[0] = XEXP (code, 0);
323 snprintf (pattern, sizeof (pattern),
324 "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
325 break;
327 default:
328 abort ();
331 output_asm_insn (pattern, operands);
332 return "";
335 /* Output 32-bit load. */
336 const char *
337 nds32_output_32bit_load (rtx *operands, int byte)
339 char pattern[100];
340 unsigned char size;
341 rtx code;
343 code = XEXP (operands[1], 0);
345 size = nds32_byte_to_size (byte);
347 switch (GET_CODE (code))
349 case REG:
350 /* (mem (reg X))
351 => access location by using register,
352 use "lbi / lhi / lwi" */
353 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
354 break;
356 case SYMBOL_REF:
357 case CONST:
358 /* (mem (symbol_ref X))
359 (mem (const (...)))
360 => access global variables,
361 use "lbi.gp / lhi.gp / lwi.gp" */
362 operands[1] = XEXP (operands[1], 0);
363 snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
364 break;
366 case POST_INC:
367 /* (mem (post_inc reg))
368 => access location by using register which will be post increment,
369 use "lbi.bi / lhi.bi / lwi.bi" */
370 snprintf (pattern, sizeof (pattern),
371 "l%ci.bi\t%%0, %%1, %d", size, byte);
372 break;
374 case POST_DEC:
375 /* (mem (post_dec reg))
376 => access location by using register which will be post decrement,
377 use "lbi.bi / lhi.bi / lwi.bi" */
378 snprintf (pattern, sizeof (pattern),
379 "l%ci.bi\t%%0, %%1, -%d", size, byte);
380 break;
382 case POST_MODIFY:
383 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
385 case REG:
386 case SUBREG:
387 /* (mem (post_modify (reg) (plus (reg) (reg))))
388 => access location by using register which will be
389 post modified with reg,
390 use "lb.bi/ lh.bi / lw.bi" */
391 snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
392 break;
393 case CONST_INT:
394 /* (mem (post_modify (reg) (plus (reg) (const_int))))
395 => access location by using register which will be
396 post modified with const_int,
397 use "lbi.bi/ lhi.bi / lwi.bi" */
398 snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
399 break;
400 default:
401 abort ();
403 break;
405 case PLUS:
406 switch (GET_CODE (XEXP (code, 1)))
408 case REG:
409 case SUBREG:
410 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
411 use "lb / lh / lw" */
412 snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
413 break;
414 case CONST_INT:
415 /* (mem (plus reg const_int))
416 => access location by adding one register with const_int,
417 use "lbi / lhi / lwi" */
418 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
419 break;
420 default:
421 abort ();
423 break;
425 case LO_SUM:
426 operands[2] = XEXP (code, 1);
427 operands[1] = XEXP (code, 0);
428 snprintf (pattern, sizeof (pattern),
429 "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
430 break;
432 default:
433 abort ();
436 output_asm_insn (pattern, operands);
437 return "";
440 /* Output 32-bit load with signed extension. */
441 const char *
442 nds32_output_32bit_load_s (rtx *operands, int byte)
444 char pattern[100];
445 unsigned char size;
446 rtx code;
448 code = XEXP (operands[1], 0);
450 size = nds32_byte_to_size (byte);
452 switch (GET_CODE (code))
454 case REG:
455 /* (mem (reg X))
456 => access location by using register,
457 use "lbsi / lhsi" */
458 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
459 break;
461 case SYMBOL_REF:
462 case CONST:
463 /* (mem (symbol_ref X))
464 (mem (const (...)))
465 => access global variables,
466 use "lbsi.gp / lhsi.gp" */
467 operands[1] = XEXP (operands[1], 0);
468 snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
469 break;
471 case POST_INC:
472 /* (mem (post_inc reg))
473 => access location by using register which will be post increment,
474 use "lbsi.bi / lhsi.bi" */
475 snprintf (pattern, sizeof (pattern),
476 "l%csi.bi\t%%0, %%1, %d", size, byte);
477 break;
479 case POST_DEC:
480 /* (mem (post_dec reg))
481 => access location by using register which will be post decrement,
482 use "lbsi.bi / lhsi.bi" */
483 snprintf (pattern, sizeof (pattern),
484 "l%csi.bi\t%%0, %%1, -%d", size, byte);
485 break;
487 case POST_MODIFY:
488 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
490 case REG:
491 case SUBREG:
492 /* (mem (post_modify (reg) (plus (reg) (reg))))
493 => access location by using register which will be
494 post modified with reg,
495 use "lbs.bi/ lhs.bi" */
496 snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
497 break;
498 case CONST_INT:
499 /* (mem (post_modify (reg) (plus (reg) (const_int))))
500 => access location by using register which will be
501 post modified with const_int,
502 use "lbsi.bi/ lhsi.bi" */
503 snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
504 break;
505 default:
506 abort ();
508 break;
510 case PLUS:
511 switch (GET_CODE (XEXP (code, 1)))
513 case REG:
514 case SUBREG:
515 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
516 use "lbs / lhs" */
517 snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
518 break;
519 case CONST_INT:
520 /* (mem (plus reg const_int))
521 => access location by adding one register with const_int,
522 use "lbsi / lhsi" */
523 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
524 break;
525 default:
526 abort ();
528 break;
530 case LO_SUM:
531 operands[2] = XEXP (code, 1);
532 operands[1] = XEXP (code, 0);
533 snprintf (pattern, sizeof (pattern),
534 "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
535 break;
537 default:
538 abort ();
541 output_asm_insn (pattern, operands);
542 return "";
545 /* Function to output stack push operation.
546 We need to deal with normal stack push multiple or stack v3push. */
547 const char *
548 nds32_output_stack_push (rtx par_rtx)
550 /* A string pattern for output_asm_insn(). */
551 char pattern[100];
552 /* The operands array which will be used in output_asm_insn(). */
553 rtx operands[3];
554 /* Pick up varargs first regno and last regno for further use. */
555 int rb_va_args = cfun->machine->va_args_first_regno;
556 int re_va_args = cfun->machine->va_args_last_regno;
557 int last_argument_regno = NDS32_FIRST_GPR_REGNUM
558 + NDS32_MAX_GPR_REGS_FOR_ARGS
559 - 1;
560 /* Pick up callee-saved first regno and last regno for further use. */
561 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
562 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
564 /* First we need to check if we are pushing argument registers not used
565 for the named arguments. If so, we have to create 'smw.adm' (push.s)
566 instruction. */
567 if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx))
569 /* Set operands[0] and operands[1]. */
570 operands[0] = gen_rtx_REG (SImode, rb_va_args);
571 operands[1] = gen_rtx_REG (SImode, re_va_args);
572 /* Create assembly code pattern: "Rb, Re, { }". */
573 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
574 /* We use output_asm_insn() to output assembly code by ourself. */
575 output_asm_insn (pattern, operands);
576 return "";
579 /* If we step here, we are going to do v3push or multiple push operation. */
581 /* The v3push/v3pop instruction should only be applied on
582 none-isr and none-variadic function. */
583 if (TARGET_V3PUSH
584 && !nds32_isr_function_p (current_function_decl)
585 && (cfun->machine->va_args_size == 0))
587 /* For stack v3push:
588 operands[0]: Re
589 operands[1]: imm8u */
591 /* This variable is to check if 'push25 Re,imm8u' is available. */
592 int sp_adjust;
594 /* Set operands[0]. */
595 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
597 /* Check if we can generate 'push25 Re,imm8u',
598 otherwise, generate 'push25 Re,0'. */
599 sp_adjust = cfun->machine->local_size
600 + cfun->machine->out_args_size
601 + cfun->machine->callee_saved_area_gpr_padding_bytes;
602 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
603 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
604 operands[1] = GEN_INT (sp_adjust);
605 else
606 operands[1] = GEN_INT (0);
608 /* Create assembly code pattern. */
609 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
611 else
613 /* For normal stack push multiple:
614 operands[0]: Rb
615 operands[1]: Re
616 operands[2]: En4 */
618 /* This variable is used to check if we only need to generate En4 field.
619 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
620 int push_en4_only_p = 0;
622 /* Set operands[0] and operands[1]. */
623 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
624 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
626 /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
627 if (!cfun->machine->fp_size
628 && !cfun->machine->gp_size
629 && !cfun->machine->lp_size
630 && REGNO (operands[0]) == SP_REGNUM
631 && REGNO (operands[1]) == SP_REGNUM)
633 /* No need to generate instruction. */
634 return "";
636 else
638 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
639 if (REGNO (operands[0]) == SP_REGNUM
640 && REGNO (operands[1]) == SP_REGNUM)
641 push_en4_only_p = 1;
643 /* Create assembly code pattern.
644 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
645 snprintf (pattern, sizeof (pattern),
646 "push.s\t%s{%s%s%s }",
647 push_en4_only_p ? "" : "%0, %1, ",
648 cfun->machine->fp_size ? " $fp" : "",
649 cfun->machine->gp_size ? " $gp" : "",
650 cfun->machine->lp_size ? " $lp" : "");
654 /* We use output_asm_insn() to output assembly code by ourself. */
655 output_asm_insn (pattern, operands);
656 return "";
659 /* Function to output stack pop operation.
660 We need to deal with normal stack pop multiple or stack v3pop. */
661 const char *
662 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
664 /* A string pattern for output_asm_insn(). */
665 char pattern[100];
666 /* The operands array which will be used in output_asm_insn(). */
667 rtx operands[3];
668 /* Pick up callee-saved first regno and last regno for further use. */
669 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
670 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
672 /* If we step here, we are going to do v3pop or multiple pop operation. */
674 /* The v3push/v3pop instruction should only be applied on
675 none-isr and none-variadic function. */
676 if (TARGET_V3PUSH
677 && !nds32_isr_function_p (current_function_decl)
678 && (cfun->machine->va_args_size == 0))
680 /* For stack v3pop:
681 operands[0]: Re
682 operands[1]: imm8u */
684 /* This variable is to check if 'pop25 Re,imm8u' is available. */
685 int sp_adjust;
687 /* Set operands[0]. */
688 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
690 /* Check if we can generate 'pop25 Re,imm8u',
691 otherwise, generate 'pop25 Re,0'.
692 We have to consider alloca issue as well.
693 If the function does call alloca(), the stack pointer is not fixed.
694 In that case, we cannot use 'pop25 Re,imm8u' directly.
695 We have to caculate stack pointer from frame pointer
696 and then use 'pop25 Re,0'. */
697 sp_adjust = cfun->machine->local_size
698 + cfun->machine->out_args_size
699 + cfun->machine->callee_saved_area_gpr_padding_bytes;
700 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
701 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
702 && !cfun->calls_alloca)
703 operands[1] = GEN_INT (sp_adjust);
704 else
705 operands[1] = GEN_INT (0);
707 /* Create assembly code pattern. */
708 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
710 else
712 /* For normal stack pop multiple:
713 operands[0]: Rb
714 operands[1]: Re
715 operands[2]: En4 */
717 /* This variable is used to check if we only need to generate En4 field.
718 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
719 int pop_en4_only_p = 0;
721 /* Set operands[0] and operands[1]. */
722 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
723 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
725 /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
726 if (!cfun->machine->fp_size
727 && !cfun->machine->gp_size
728 && !cfun->machine->lp_size
729 && REGNO (operands[0]) == SP_REGNUM
730 && REGNO (operands[1]) == SP_REGNUM)
732 /* No need to generate instruction. */
733 return "";
735 else
737 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
738 if (REGNO (operands[0]) == SP_REGNUM
739 && REGNO (operands[1]) == SP_REGNUM)
740 pop_en4_only_p = 1;
742 /* Create assembly code pattern.
743 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
744 snprintf (pattern, sizeof (pattern),
745 "pop.s\t%s{%s%s%s }",
746 pop_en4_only_p ? "" : "%0, %1, ",
747 cfun->machine->fp_size ? " $fp" : "",
748 cfun->machine->gp_size ? " $gp" : "",
749 cfun->machine->lp_size ? " $lp" : "");
753 /* We use output_asm_insn() to output assembly code by ourself. */
754 output_asm_insn (pattern, operands);
755 return "";
758 /* Function to generate PC relative jump table.
759 Refer to nds32.md for more details.
761 The following is the sample for the case that diff value
762 can be presented in '.short' size.
764 addi $r1, $r1, -(case_lower_bound)
765 slti $ta, $r1, (case_number)
766 beqz $ta, .L_skip_label
768 la $ta, .L35 ! get jump table address
769 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
770 addi $ta, $r1, $ta
771 jr5 $ta
773 ! jump table entry
774 L35:
775 .short .L25-.L35
776 .short .L26-.L35
777 .short .L27-.L35
778 .short .L28-.L35
779 .short .L29-.L35
780 .short .L30-.L35
781 .short .L31-.L35
782 .short .L32-.L35
783 .short .L33-.L35
784 .short .L34-.L35 */
785 const char *
786 nds32_output_casesi_pc_relative (rtx *operands)
788 machine_mode mode;
789 rtx diff_vec;
791 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
793 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
795 /* Step C: "t <-- operands[1]". */
796 output_asm_insn ("la\t$ta, %l1", operands);
798 /* Get the mode of each element in the difference vector. */
799 mode = GET_MODE (diff_vec);
801 /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
802 where m is 0, 1, or 2 to load address-diff value from table. */
803 switch (mode)
805 case E_QImode:
806 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
807 break;
808 case E_HImode:
809 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
810 break;
811 case E_SImode:
812 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
813 break;
814 default:
815 gcc_unreachable ();
818 /* Step E: "t <-- z + t".
819 Add table label_ref with address-diff value to
820 obtain target case address. */
821 output_asm_insn ("add\t$ta, %2, $ta", operands);
823 /* Step F: jump to target with register t. */
824 if (TARGET_16_BIT)
825 return "jr5\t$ta";
826 else
827 return "jr\t$ta";
830 /* Function to generate normal jump table. */
831 const char *
832 nds32_output_casesi (rtx *operands)
834 /* Step C: "t <-- operands[1]". */
835 output_asm_insn ("la\t$ta, %l1", operands);
837 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
838 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
840 /* No need to perform Step E, which is only used for
841 pc relative jump table. */
843 /* Step F: jump to target with register z. */
844 if (TARGET_16_BIT)
845 return "jr5\t%2";
846 else
847 return "jr\t%2";
850 /* ------------------------------------------------------------------------ */