gcc/ada/
[official-gcc.git] / gcc / config / nds32 / nds32-md-auxiliary.c
blobca78283f5da3a08016ad2f7bb5e71289ea6542b9
1 /* Auxiliary functions for output asm template or expand rtl
2 pattern of Andes NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2014 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 "tm.h"
28 #include "tree.h"
29 #include "stor-layout.h"
30 #include "varasm.h"
31 #include "calls.h"
32 #include "rtl.h"
33 #include "regs.h"
34 #include "hard-reg-set.h"
35 #include "insn-config.h" /* Required by recog.h. */
36 #include "conditions.h"
37 #include "output.h"
38 #include "insn-attr.h" /* For DFA state_t. */
39 #include "insn-codes.h" /* For CODE_FOR_xxx. */
40 #include "reload.h" /* For push_reload(). */
41 #include "flags.h"
42 #include "hashtab.h"
43 #include "hash-set.h"
44 #include "vec.h"
45 #include "machmode.h"
46 #include "input.h"
47 #include "function.h"
48 #include "expr.h"
49 #include "recog.h"
50 #include "diagnostic-core.h"
51 #include "dominance.h"
52 #include "cfg.h"
53 #include "cfgrtl.h"
54 #include "cfganal.h"
55 #include "lcm.h"
56 #include "cfgbuild.h"
57 #include "cfgcleanup.h"
58 #include "predict.h"
59 #include "basic-block.h"
60 #include "df.h"
61 #include "tm_p.h"
62 #include "tm-constrs.h"
63 #include "optabs.h" /* For GEN_FCN. */
64 #include "target.h"
65 #include "target-def.h"
66 #include "langhooks.h" /* For add_builtin_function(). */
67 #include "ggc.h"
68 #include "builtins.h"
70 /* ------------------------------------------------------------------------ */
72 /* A helper function to return character based on byte size. */
73 static char
74 nds32_byte_to_size (int byte)
76 switch (byte)
78 case 4:
79 return 'w';
80 case 2:
81 return 'h';
82 case 1:
83 return 'b';
84 default:
85 /* Normally it should not be here. */
86 gcc_unreachable ();
90 /* A helper function to return memory format. */
91 enum nds32_16bit_address_type
92 nds32_mem_format (rtx op)
94 machine_mode mode_test;
95 int val;
96 int regno;
98 if (!TARGET_16_BIT)
99 return ADDRESS_NOT_16BIT_FORMAT;
101 mode_test = GET_MODE (op);
103 op = XEXP (op, 0);
105 /* 45 format. */
106 if (GET_CODE (op) == REG && (mode_test == SImode))
107 return ADDRESS_REG;
109 /* 333 format for QI/HImode. */
110 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
111 return ADDRESS_LO_REG_IMM3U;
113 /* post_inc 333 format. */
114 if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
116 regno = REGNO(XEXP (op, 0));
118 if (regno < 8)
119 return ADDRESS_POST_INC_LO_REG_IMM3U;
122 /* post_inc 333 format. */
123 if ((GET_CODE (op) == POST_MODIFY)
124 && (mode_test == SImode)
125 && (REG_P (XEXP (XEXP (op, 1), 0)))
126 && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
128 regno = REGNO (XEXP (XEXP (op, 1), 0));
129 val = INTVAL (XEXP (XEXP (op, 1), 1));
130 if (regno < 8 && val < 32)
131 return ADDRESS_POST_INC_LO_REG_IMM3U;
134 if ((GET_CODE (op) == PLUS)
135 && (GET_CODE (XEXP (op, 0)) == REG)
136 && (GET_CODE (XEXP (op, 1)) == CONST_INT))
138 val = INTVAL (XEXP (op, 1));
140 regno = REGNO(XEXP (op, 0));
142 if (regno > 7
143 && regno != SP_REGNUM
144 && regno != FP_REGNUM)
145 return ADDRESS_NOT_16BIT_FORMAT;
147 switch (mode_test)
149 case QImode:
150 /* 333 format. */
151 if (val >= 0 && val < 8 && regno < 8)
152 return ADDRESS_LO_REG_IMM3U;
153 break;
155 case HImode:
156 /* 333 format. */
157 if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
158 return ADDRESS_LO_REG_IMM3U;
159 break;
161 case SImode:
162 case SFmode:
163 case DFmode:
164 /* fp imply 37 format. */
165 if ((regno == FP_REGNUM) &&
166 (val >= 0 && val < 512 && (val % 4 == 0)))
167 return ADDRESS_FP_IMM7U;
168 /* sp imply 37 format. */
169 else if ((regno == SP_REGNUM) &&
170 (val >= 0 && val < 512 && (val % 4 == 0)))
171 return ADDRESS_SP_IMM7U;
172 /* 333 format. */
173 else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
174 return ADDRESS_LO_REG_IMM3U;
175 break;
177 default:
178 break;
182 return ADDRESS_NOT_16BIT_FORMAT;
185 /* Output 16-bit store. */
186 const char *
187 nds32_output_16bit_store (rtx *operands, int byte)
189 char pattern[100];
190 char size;
191 rtx code = XEXP (operands[0], 0);
193 size = nds32_byte_to_size (byte);
195 switch (nds32_mem_format (operands[0]))
197 case ADDRESS_REG:
198 operands[0] = code;
199 output_asm_insn ("swi450\t%1, [%0]", operands);
200 break;
201 case ADDRESS_LO_REG_IMM3U:
202 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
203 output_asm_insn (pattern, operands);
204 break;
205 case ADDRESS_POST_INC_LO_REG_IMM3U:
206 snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
207 output_asm_insn (pattern, operands);
208 break;
209 case ADDRESS_FP_IMM7U:
210 output_asm_insn ("swi37\t%1, %0", operands);
211 break;
212 case ADDRESS_SP_IMM7U:
213 /* Get immediate value and set back to operands[1]. */
214 operands[0] = XEXP (code, 1);
215 output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
216 break;
217 default:
218 break;
221 return "";
224 /* Output 16-bit load. */
225 const char *
226 nds32_output_16bit_load (rtx *operands, int byte)
228 char pattern[100];
229 unsigned char size;
230 rtx code = XEXP (operands[1], 0);
232 size = nds32_byte_to_size (byte);
234 switch (nds32_mem_format (operands[1]))
236 case ADDRESS_REG:
237 operands[1] = code;
238 output_asm_insn ("lwi450\t%0, [%1]", operands);
239 break;
240 case ADDRESS_LO_REG_IMM3U:
241 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
242 output_asm_insn (pattern, operands);
243 break;
244 case ADDRESS_POST_INC_LO_REG_IMM3U:
245 snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
246 output_asm_insn (pattern, operands);
247 break;
248 case ADDRESS_FP_IMM7U:
249 output_asm_insn ("lwi37\t%0, %1", operands);
250 break;
251 case ADDRESS_SP_IMM7U:
252 /* Get immediate value and set back to operands[0]. */
253 operands[1] = XEXP (code, 1);
254 output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
255 break;
256 default:
257 break;
260 return "";
263 /* Output 32-bit store. */
264 const char *
265 nds32_output_32bit_store (rtx *operands, int byte)
267 char pattern[100];
268 unsigned char size;
269 rtx code = XEXP (operands[0], 0);
271 size = nds32_byte_to_size (byte);
273 switch (GET_CODE (code))
275 case REG:
276 /* (mem (reg X))
277 => access location by using register,
278 use "sbi / shi / swi" */
279 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
280 break;
282 case SYMBOL_REF:
283 case CONST:
284 /* (mem (symbol_ref X))
285 (mem (const (...)))
286 => access global variables,
287 use "sbi.gp / shi.gp / swi.gp" */
288 operands[0] = XEXP (operands[0], 0);
289 snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
290 break;
292 case POST_INC:
293 /* (mem (post_inc reg))
294 => access location by using register which will be post increment,
295 use "sbi.bi / shi.bi / swi.bi" */
296 snprintf (pattern, sizeof (pattern),
297 "s%ci.bi\t%%1, %%0, %d", size, byte);
298 break;
300 case POST_DEC:
301 /* (mem (post_dec reg))
302 => access location by using register which will be post decrement,
303 use "sbi.bi / shi.bi / swi.bi" */
304 snprintf (pattern, sizeof (pattern),
305 "s%ci.bi\t%%1, %%0, -%d", size, byte);
306 break;
308 case POST_MODIFY:
309 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
311 case REG:
312 case SUBREG:
313 /* (mem (post_modify (reg) (plus (reg) (reg))))
314 => access location by using register which will be
315 post modified with reg,
316 use "sb.bi/ sh.bi / sw.bi" */
317 snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
318 break;
319 case CONST_INT:
320 /* (mem (post_modify (reg) (plus (reg) (const_int))))
321 => access location by using register which will be
322 post modified with const_int,
323 use "sbi.bi/ shi.bi / swi.bi" */
324 snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
325 break;
326 default:
327 abort ();
329 break;
331 case PLUS:
332 switch (GET_CODE (XEXP (code, 1)))
334 case REG:
335 case SUBREG:
336 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
337 => access location by adding two registers,
338 use "sb / sh / sw" */
339 snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
340 break;
341 case CONST_INT:
342 /* (mem (plus reg const_int))
343 => access location by adding one register with const_int,
344 use "sbi / shi / swi" */
345 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
346 break;
347 default:
348 abort ();
350 break;
352 case LO_SUM:
353 operands[2] = XEXP (code, 1);
354 operands[0] = XEXP (code, 0);
355 snprintf (pattern, sizeof (pattern),
356 "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
357 break;
359 default:
360 abort ();
363 output_asm_insn (pattern, operands);
364 return "";
367 /* Output 32-bit load. */
368 const char *
369 nds32_output_32bit_load (rtx *operands, int byte)
371 char pattern[100];
372 unsigned char size;
373 rtx code;
375 code = XEXP (operands[1], 0);
377 size = nds32_byte_to_size (byte);
379 switch (GET_CODE (code))
381 case REG:
382 /* (mem (reg X))
383 => access location by using register,
384 use "lbi / lhi / lwi" */
385 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
386 break;
388 case SYMBOL_REF:
389 case CONST:
390 /* (mem (symbol_ref X))
391 (mem (const (...)))
392 => access global variables,
393 use "lbi.gp / lhi.gp / lwi.gp" */
394 operands[1] = XEXP (operands[1], 0);
395 snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
396 break;
398 case POST_INC:
399 /* (mem (post_inc reg))
400 => access location by using register which will be post increment,
401 use "lbi.bi / lhi.bi / lwi.bi" */
402 snprintf (pattern, sizeof (pattern),
403 "l%ci.bi\t%%0, %%1, %d", size, byte);
404 break;
406 case POST_DEC:
407 /* (mem (post_dec reg))
408 => access location by using register which will be post decrement,
409 use "lbi.bi / lhi.bi / lwi.bi" */
410 snprintf (pattern, sizeof (pattern),
411 "l%ci.bi\t%%0, %%1, -%d", size, byte);
412 break;
414 case POST_MODIFY:
415 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
417 case REG:
418 case SUBREG:
419 /* (mem (post_modify (reg) (plus (reg) (reg))))
420 => access location by using register which will be
421 post modified with reg,
422 use "lb.bi/ lh.bi / lw.bi" */
423 snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
424 break;
425 case CONST_INT:
426 /* (mem (post_modify (reg) (plus (reg) (const_int))))
427 => access location by using register which will be
428 post modified with const_int,
429 use "lbi.bi/ lhi.bi / lwi.bi" */
430 snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
431 break;
432 default:
433 abort ();
435 break;
437 case PLUS:
438 switch (GET_CODE (XEXP (code, 1)))
440 case REG:
441 case SUBREG:
442 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
443 use "lb / lh / lw" */
444 snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
445 break;
446 case CONST_INT:
447 /* (mem (plus reg const_int))
448 => access location by adding one register with const_int,
449 use "lbi / lhi / lwi" */
450 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
451 break;
452 default:
453 abort ();
455 break;
457 case LO_SUM:
458 operands[2] = XEXP (code, 1);
459 operands[1] = XEXP (code, 0);
460 snprintf (pattern, sizeof (pattern),
461 "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
462 break;
464 default:
465 abort ();
468 output_asm_insn (pattern, operands);
469 return "";
472 /* Output 32-bit load with signed extension. */
473 const char *
474 nds32_output_32bit_load_s (rtx *operands, int byte)
476 char pattern[100];
477 unsigned char size;
478 rtx code;
480 code = XEXP (operands[1], 0);
482 size = nds32_byte_to_size (byte);
484 switch (GET_CODE (code))
486 case REG:
487 /* (mem (reg X))
488 => access location by using register,
489 use "lbsi / lhsi" */
490 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
491 break;
493 case SYMBOL_REF:
494 case CONST:
495 /* (mem (symbol_ref X))
496 (mem (const (...)))
497 => access global variables,
498 use "lbsi.gp / lhsi.gp" */
499 operands[1] = XEXP (operands[1], 0);
500 snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
501 break;
503 case POST_INC:
504 /* (mem (post_inc reg))
505 => access location by using register which will be post increment,
506 use "lbsi.bi / lhsi.bi" */
507 snprintf (pattern, sizeof (pattern),
508 "l%csi.bi\t%%0, %%1, %d", size, byte);
509 break;
511 case POST_DEC:
512 /* (mem (post_dec reg))
513 => access location by using register which will be post decrement,
514 use "lbsi.bi / lhsi.bi" */
515 snprintf (pattern, sizeof (pattern),
516 "l%csi.bi\t%%0, %%1, -%d", size, byte);
517 break;
519 case POST_MODIFY:
520 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
522 case REG:
523 case SUBREG:
524 /* (mem (post_modify (reg) (plus (reg) (reg))))
525 => access location by using register which will be
526 post modified with reg,
527 use "lbs.bi/ lhs.bi" */
528 snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
529 break;
530 case CONST_INT:
531 /* (mem (post_modify (reg) (plus (reg) (const_int))))
532 => access location by using register which will be
533 post modified with const_int,
534 use "lbsi.bi/ lhsi.bi" */
535 snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
536 break;
537 default:
538 abort ();
540 break;
542 case PLUS:
543 switch (GET_CODE (XEXP (code, 1)))
545 case REG:
546 case SUBREG:
547 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
548 use "lbs / lhs" */
549 snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
550 break;
551 case CONST_INT:
552 /* (mem (plus reg const_int))
553 => access location by adding one register with const_int,
554 use "lbsi / lhsi" */
555 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
556 break;
557 default:
558 abort ();
560 break;
562 case LO_SUM:
563 operands[2] = XEXP (code, 1);
564 operands[1] = XEXP (code, 0);
565 snprintf (pattern, sizeof (pattern),
566 "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
567 break;
569 default:
570 abort ();
573 output_asm_insn (pattern, operands);
574 return "";
577 /* Function to output stack push operation.
578 We need to deal with normal stack push multiple or stack v3push. */
579 const char *
580 nds32_output_stack_push (rtx par_rtx)
582 /* A string pattern for output_asm_insn(). */
583 char pattern[100];
584 /* The operands array which will be used in output_asm_insn(). */
585 rtx operands[3];
586 /* Pick up varargs first regno and last regno for further use. */
587 int rb_va_args = cfun->machine->va_args_first_regno;
588 int re_va_args = cfun->machine->va_args_last_regno;
589 int last_argument_regno = NDS32_FIRST_GPR_REGNUM
590 + NDS32_MAX_GPR_REGS_FOR_ARGS
591 - 1;
592 /* Pick up callee-saved first regno and last regno for further use. */
593 int rb_callee_saved = cfun->machine->callee_saved_regs_first_regno;
594 int re_callee_saved = cfun->machine->callee_saved_regs_last_regno;
596 /* First we need to check if we are pushing argument registers not used
597 for the named arguments. If so, we have to create 'smw.adm' (push.s)
598 instruction. */
599 if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx))
601 /* Set operands[0] and operands[1]. */
602 operands[0] = gen_rtx_REG (SImode, rb_va_args);
603 operands[1] = gen_rtx_REG (SImode, re_va_args);
604 /* Create assembly code pattern: "Rb, Re, { }". */
605 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
606 /* We use output_asm_insn() to output assembly code by ourself. */
607 output_asm_insn (pattern, operands);
608 return "";
611 /* If we step here, we are going to do v3push or multiple push operation. */
613 /* The v3push/v3pop instruction should only be applied on
614 none-isr and none-variadic function. */
615 if (TARGET_V3PUSH
616 && !nds32_isr_function_p (current_function_decl)
617 && (cfun->machine->va_args_size == 0))
619 /* For stack v3push:
620 operands[0]: Re
621 operands[1]: imm8u */
623 /* This variable is to check if 'push25 Re,imm8u' is available. */
624 int sp_adjust;
626 /* Set operands[0]. */
627 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
629 /* Check if we can generate 'push25 Re,imm8u',
630 otherwise, generate 'push25 Re,0'. */
631 sp_adjust = cfun->machine->local_size
632 + cfun->machine->out_args_size
633 + cfun->machine->callee_saved_area_padding_bytes;
634 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
635 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
636 operands[1] = GEN_INT (sp_adjust);
637 else
638 operands[1] = GEN_INT (0);
640 /* Create assembly code pattern. */
641 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
643 else
645 /* For normal stack push multiple:
646 operands[0]: Rb
647 operands[1]: Re
648 operands[2]: En4 */
650 /* This variable is used to check if we only need to generate En4 field.
651 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
652 int push_en4_only_p = 0;
654 /* Set operands[0] and operands[1]. */
655 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
656 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
658 /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
659 if (!cfun->machine->fp_size
660 && !cfun->machine->gp_size
661 && !cfun->machine->lp_size
662 && REGNO (operands[0]) == SP_REGNUM
663 && REGNO (operands[1]) == SP_REGNUM)
665 /* No need to generate instruction. */
666 return "";
668 else
670 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
671 if (REGNO (operands[0]) == SP_REGNUM
672 && REGNO (operands[1]) == SP_REGNUM)
673 push_en4_only_p = 1;
675 /* Create assembly code pattern.
676 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
677 snprintf (pattern, sizeof (pattern),
678 "push.s\t%s{%s%s%s }",
679 push_en4_only_p ? "" : "%0, %1, ",
680 cfun->machine->fp_size ? " $fp" : "",
681 cfun->machine->gp_size ? " $gp" : "",
682 cfun->machine->lp_size ? " $lp" : "");
686 /* We use output_asm_insn() to output assembly code by ourself. */
687 output_asm_insn (pattern, operands);
688 return "";
691 /* Function to output stack pop operation.
692 We need to deal with normal stack pop multiple or stack v3pop. */
693 const char *
694 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
696 /* A string pattern for output_asm_insn(). */
697 char pattern[100];
698 /* The operands array which will be used in output_asm_insn(). */
699 rtx operands[3];
700 /* Pick up callee-saved first regno and last regno for further use. */
701 int rb_callee_saved = cfun->machine->callee_saved_regs_first_regno;
702 int re_callee_saved = cfun->machine->callee_saved_regs_last_regno;
704 /* If we step here, we are going to do v3pop or multiple pop operation. */
706 /* The v3push/v3pop instruction should only be applied on
707 none-isr and none-variadic function. */
708 if (TARGET_V3PUSH
709 && !nds32_isr_function_p (current_function_decl)
710 && (cfun->machine->va_args_size == 0))
712 /* For stack v3pop:
713 operands[0]: Re
714 operands[1]: imm8u */
716 /* This variable is to check if 'pop25 Re,imm8u' is available. */
717 int sp_adjust;
719 /* Set operands[0]. */
720 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
722 /* Check if we can generate 'pop25 Re,imm8u',
723 otherwise, generate 'pop25 Re,0'.
724 We have to consider alloca issue as well.
725 If the function does call alloca(), the stack pointer is not fixed.
726 In that case, we cannot use 'pop25 Re,imm8u' directly.
727 We have to caculate stack pointer from frame pointer
728 and then use 'pop25 Re,0'. */
729 sp_adjust = cfun->machine->local_size
730 + cfun->machine->out_args_size
731 + cfun->machine->callee_saved_area_padding_bytes;
732 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
733 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
734 && !cfun->calls_alloca)
735 operands[1] = GEN_INT (sp_adjust);
736 else
737 operands[1] = GEN_INT (0);
739 /* Create assembly code pattern. */
740 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
742 else
744 /* For normal stack pop multiple:
745 operands[0]: Rb
746 operands[1]: Re
747 operands[2]: En4 */
749 /* This variable is used to check if we only need to generate En4 field.
750 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
751 int pop_en4_only_p = 0;
753 /* Set operands[0] and operands[1]. */
754 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
755 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
757 /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
758 if (!cfun->machine->fp_size
759 && !cfun->machine->gp_size
760 && !cfun->machine->lp_size
761 && REGNO (operands[0]) == SP_REGNUM
762 && REGNO (operands[1]) == SP_REGNUM)
764 /* No need to generate instruction. */
765 return "";
767 else
769 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
770 if (REGNO (operands[0]) == SP_REGNUM
771 && REGNO (operands[1]) == SP_REGNUM)
772 pop_en4_only_p = 1;
774 /* Create assembly code pattern.
775 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
776 snprintf (pattern, sizeof (pattern),
777 "pop.s\t%s{%s%s%s }",
778 pop_en4_only_p ? "" : "%0, %1, ",
779 cfun->machine->fp_size ? " $fp" : "",
780 cfun->machine->gp_size ? " $gp" : "",
781 cfun->machine->lp_size ? " $lp" : "");
785 /* We use output_asm_insn() to output assembly code by ourself. */
786 output_asm_insn (pattern, operands);
787 return "";
790 /* Function to generate PC relative jump table.
791 Refer to nds32.md for more details.
793 The following is the sample for the case that diff value
794 can be presented in '.short' size.
796 addi $r1, $r1, -(case_lower_bound)
797 slti $ta, $r1, (case_number)
798 beqz $ta, .L_skip_label
800 la $ta, .L35 ! get jump table address
801 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
802 addi $ta, $r1, $ta
803 jr5 $ta
805 ! jump table entry
806 L35:
807 .short .L25-.L35
808 .short .L26-.L35
809 .short .L27-.L35
810 .short .L28-.L35
811 .short .L29-.L35
812 .short .L30-.L35
813 .short .L31-.L35
814 .short .L32-.L35
815 .short .L33-.L35
816 .short .L34-.L35 */
817 const char *
818 nds32_output_casesi_pc_relative (rtx *operands)
820 machine_mode mode;
821 rtx diff_vec;
823 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
825 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
827 /* Step C: "t <-- operands[1]". */
828 output_asm_insn ("la\t$ta, %l1", operands);
830 /* Get the mode of each element in the difference vector. */
831 mode = GET_MODE (diff_vec);
833 /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
834 where m is 0, 1, or 2 to load address-diff value from table. */
835 switch (mode)
837 case QImode:
838 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
839 break;
840 case HImode:
841 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
842 break;
843 case SImode:
844 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
845 break;
846 default:
847 gcc_unreachable ();
850 /* Step E: "t <-- z + t".
851 Add table label_ref with address-diff value to
852 obtain target case address. */
853 output_asm_insn ("add\t$ta, %2, $ta", operands);
855 /* Step F: jump to target with register t. */
856 if (TARGET_16_BIT)
857 return "jr5\t$ta";
858 else
859 return "jr\t$ta";
862 /* Function to generate normal jump table. */
863 const char *
864 nds32_output_casesi (rtx *operands)
866 /* Step C: "t <-- operands[1]". */
867 output_asm_insn ("la\t$ta, %l1", operands);
869 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
870 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
872 /* No need to perform Step E, which is only used for
873 pc relative jump table. */
875 /* Step F: jump to target with register z. */
876 if (TARGET_16_BIT)
877 return "jr5\t%2";
878 else
879 return "jr\t%2";
882 /* ------------------------------------------------------------------------ */