Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS hook.
[official-gcc.git] / gcc / config / nds32 / nds32-md-auxiliary.c
blobf231563cbcec36d1aa6f39d60fd6096d17951090
1 /* Auxiliary functions for output asm template or expand rtl
2 pattern of Andes NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2015 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 "input.h"
29 #include "alias.h"
30 #include "symtab.h"
31 #include "tree.h"
32 #include "stor-layout.h"
33 #include "varasm.h"
34 #include "calls.h"
35 #include "rtl.h"
36 #include "regs.h"
37 #include "hard-reg-set.h"
38 #include "insn-config.h" /* Required by recog.h. */
39 #include "conditions.h"
40 #include "output.h"
41 #include "insn-attr.h" /* For DFA state_t. */
42 #include "insn-codes.h" /* For CODE_FOR_xxx. */
43 #include "reload.h" /* For push_reload(). */
44 #include "flags.h"
45 #include "function.h"
46 #include "insn-config.h"
47 #include "expmed.h"
48 #include "dojump.h"
49 #include "explow.h"
50 #include "emit-rtl.h"
51 #include "stmt.h"
52 #include "expr.h"
53 #include "recog.h"
54 #include "diagnostic-core.h"
55 #include "dominance.h"
56 #include "cfg.h"
57 #include "cfgrtl.h"
58 #include "cfganal.h"
59 #include "lcm.h"
60 #include "cfgbuild.h"
61 #include "cfgcleanup.h"
62 #include "predict.h"
63 #include "basic-block.h"
64 #include "df.h"
65 #include "tm_p.h"
66 #include "tm-constrs.h"
67 #include "optabs.h" /* For GEN_FCN. */
68 #include "target.h"
69 #include "target-def.h"
70 #include "langhooks.h" /* For add_builtin_function(). */
71 #include "builtins.h"
73 /* ------------------------------------------------------------------------ */
75 /* A helper function to return character based on byte size. */
76 static char
77 nds32_byte_to_size (int byte)
79 switch (byte)
81 case 4:
82 return 'w';
83 case 2:
84 return 'h';
85 case 1:
86 return 'b';
87 default:
88 /* Normally it should not be here. */
89 gcc_unreachable ();
93 /* A helper function to return memory format. */
94 enum nds32_16bit_address_type
95 nds32_mem_format (rtx op)
97 machine_mode mode_test;
98 int val;
99 int regno;
101 if (!TARGET_16_BIT)
102 return ADDRESS_NOT_16BIT_FORMAT;
104 mode_test = GET_MODE (op);
106 op = XEXP (op, 0);
108 /* 45 format. */
109 if (GET_CODE (op) == REG && (mode_test == SImode))
110 return ADDRESS_REG;
112 /* 333 format for QI/HImode. */
113 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
114 return ADDRESS_LO_REG_IMM3U;
116 /* post_inc 333 format. */
117 if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
119 regno = REGNO(XEXP (op, 0));
121 if (regno < 8)
122 return ADDRESS_POST_INC_LO_REG_IMM3U;
125 /* post_inc 333 format. */
126 if ((GET_CODE (op) == POST_MODIFY)
127 && (mode_test == SImode)
128 && (REG_P (XEXP (XEXP (op, 1), 0)))
129 && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
131 regno = REGNO (XEXP (XEXP (op, 1), 0));
132 val = INTVAL (XEXP (XEXP (op, 1), 1));
133 if (regno < 8 && val < 32)
134 return ADDRESS_POST_INC_LO_REG_IMM3U;
137 if ((GET_CODE (op) == PLUS)
138 && (GET_CODE (XEXP (op, 0)) == REG)
139 && (GET_CODE (XEXP (op, 1)) == CONST_INT))
141 val = INTVAL (XEXP (op, 1));
143 regno = REGNO(XEXP (op, 0));
145 if (regno > 7
146 && regno != SP_REGNUM
147 && regno != FP_REGNUM)
148 return ADDRESS_NOT_16BIT_FORMAT;
150 switch (mode_test)
152 case QImode:
153 /* 333 format. */
154 if (val >= 0 && val < 8 && regno < 8)
155 return ADDRESS_LO_REG_IMM3U;
156 break;
158 case HImode:
159 /* 333 format. */
160 if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
161 return ADDRESS_LO_REG_IMM3U;
162 break;
164 case SImode:
165 case SFmode:
166 case DFmode:
167 /* fp imply 37 format. */
168 if ((regno == FP_REGNUM) &&
169 (val >= 0 && val < 512 && (val % 4 == 0)))
170 return ADDRESS_FP_IMM7U;
171 /* sp imply 37 format. */
172 else if ((regno == SP_REGNUM) &&
173 (val >= 0 && val < 512 && (val % 4 == 0)))
174 return ADDRESS_SP_IMM7U;
175 /* 333 format. */
176 else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
177 return ADDRESS_LO_REG_IMM3U;
178 break;
180 default:
181 break;
185 return ADDRESS_NOT_16BIT_FORMAT;
188 /* Output 16-bit store. */
189 const char *
190 nds32_output_16bit_store (rtx *operands, int byte)
192 char pattern[100];
193 char size;
194 rtx code = XEXP (operands[0], 0);
196 size = nds32_byte_to_size (byte);
198 switch (nds32_mem_format (operands[0]))
200 case ADDRESS_REG:
201 operands[0] = code;
202 output_asm_insn ("swi450\t%1, [%0]", operands);
203 break;
204 case ADDRESS_LO_REG_IMM3U:
205 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
206 output_asm_insn (pattern, operands);
207 break;
208 case ADDRESS_POST_INC_LO_REG_IMM3U:
209 snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
210 output_asm_insn (pattern, operands);
211 break;
212 case ADDRESS_FP_IMM7U:
213 output_asm_insn ("swi37\t%1, %0", operands);
214 break;
215 case ADDRESS_SP_IMM7U:
216 /* Get immediate value and set back to operands[1]. */
217 operands[0] = XEXP (code, 1);
218 output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
219 break;
220 default:
221 break;
224 return "";
227 /* Output 16-bit load. */
228 const char *
229 nds32_output_16bit_load (rtx *operands, int byte)
231 char pattern[100];
232 unsigned char size;
233 rtx code = XEXP (operands[1], 0);
235 size = nds32_byte_to_size (byte);
237 switch (nds32_mem_format (operands[1]))
239 case ADDRESS_REG:
240 operands[1] = code;
241 output_asm_insn ("lwi450\t%0, [%1]", operands);
242 break;
243 case ADDRESS_LO_REG_IMM3U:
244 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
245 output_asm_insn (pattern, operands);
246 break;
247 case ADDRESS_POST_INC_LO_REG_IMM3U:
248 snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
249 output_asm_insn (pattern, operands);
250 break;
251 case ADDRESS_FP_IMM7U:
252 output_asm_insn ("lwi37\t%0, %1", operands);
253 break;
254 case ADDRESS_SP_IMM7U:
255 /* Get immediate value and set back to operands[0]. */
256 operands[1] = XEXP (code, 1);
257 output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
258 break;
259 default:
260 break;
263 return "";
266 /* Output 32-bit store. */
267 const char *
268 nds32_output_32bit_store (rtx *operands, int byte)
270 char pattern[100];
271 unsigned char size;
272 rtx code = XEXP (operands[0], 0);
274 size = nds32_byte_to_size (byte);
276 switch (GET_CODE (code))
278 case REG:
279 /* (mem (reg X))
280 => access location by using register,
281 use "sbi / shi / swi" */
282 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
283 break;
285 case SYMBOL_REF:
286 case CONST:
287 /* (mem (symbol_ref X))
288 (mem (const (...)))
289 => access global variables,
290 use "sbi.gp / shi.gp / swi.gp" */
291 operands[0] = XEXP (operands[0], 0);
292 snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
293 break;
295 case POST_INC:
296 /* (mem (post_inc reg))
297 => access location by using register which will be post increment,
298 use "sbi.bi / shi.bi / swi.bi" */
299 snprintf (pattern, sizeof (pattern),
300 "s%ci.bi\t%%1, %%0, %d", size, byte);
301 break;
303 case POST_DEC:
304 /* (mem (post_dec reg))
305 => access location by using register which will be post decrement,
306 use "sbi.bi / shi.bi / swi.bi" */
307 snprintf (pattern, sizeof (pattern),
308 "s%ci.bi\t%%1, %%0, -%d", size, byte);
309 break;
311 case POST_MODIFY:
312 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
314 case REG:
315 case SUBREG:
316 /* (mem (post_modify (reg) (plus (reg) (reg))))
317 => access location by using register which will be
318 post modified with reg,
319 use "sb.bi/ sh.bi / sw.bi" */
320 snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
321 break;
322 case CONST_INT:
323 /* (mem (post_modify (reg) (plus (reg) (const_int))))
324 => access location by using register which will be
325 post modified with const_int,
326 use "sbi.bi/ shi.bi / swi.bi" */
327 snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
328 break;
329 default:
330 abort ();
332 break;
334 case PLUS:
335 switch (GET_CODE (XEXP (code, 1)))
337 case REG:
338 case SUBREG:
339 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
340 => access location by adding two registers,
341 use "sb / sh / sw" */
342 snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
343 break;
344 case CONST_INT:
345 /* (mem (plus reg const_int))
346 => access location by adding one register with const_int,
347 use "sbi / shi / swi" */
348 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
349 break;
350 default:
351 abort ();
353 break;
355 case LO_SUM:
356 operands[2] = XEXP (code, 1);
357 operands[0] = XEXP (code, 0);
358 snprintf (pattern, sizeof (pattern),
359 "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
360 break;
362 default:
363 abort ();
366 output_asm_insn (pattern, operands);
367 return "";
370 /* Output 32-bit load. */
371 const char *
372 nds32_output_32bit_load (rtx *operands, int byte)
374 char pattern[100];
375 unsigned char size;
376 rtx code;
378 code = XEXP (operands[1], 0);
380 size = nds32_byte_to_size (byte);
382 switch (GET_CODE (code))
384 case REG:
385 /* (mem (reg X))
386 => access location by using register,
387 use "lbi / lhi / lwi" */
388 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
389 break;
391 case SYMBOL_REF:
392 case CONST:
393 /* (mem (symbol_ref X))
394 (mem (const (...)))
395 => access global variables,
396 use "lbi.gp / lhi.gp / lwi.gp" */
397 operands[1] = XEXP (operands[1], 0);
398 snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
399 break;
401 case POST_INC:
402 /* (mem (post_inc reg))
403 => access location by using register which will be post increment,
404 use "lbi.bi / lhi.bi / lwi.bi" */
405 snprintf (pattern, sizeof (pattern),
406 "l%ci.bi\t%%0, %%1, %d", size, byte);
407 break;
409 case POST_DEC:
410 /* (mem (post_dec reg))
411 => access location by using register which will be post decrement,
412 use "lbi.bi / lhi.bi / lwi.bi" */
413 snprintf (pattern, sizeof (pattern),
414 "l%ci.bi\t%%0, %%1, -%d", size, byte);
415 break;
417 case POST_MODIFY:
418 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
420 case REG:
421 case SUBREG:
422 /* (mem (post_modify (reg) (plus (reg) (reg))))
423 => access location by using register which will be
424 post modified with reg,
425 use "lb.bi/ lh.bi / lw.bi" */
426 snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
427 break;
428 case CONST_INT:
429 /* (mem (post_modify (reg) (plus (reg) (const_int))))
430 => access location by using register which will be
431 post modified with const_int,
432 use "lbi.bi/ lhi.bi / lwi.bi" */
433 snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
434 break;
435 default:
436 abort ();
438 break;
440 case PLUS:
441 switch (GET_CODE (XEXP (code, 1)))
443 case REG:
444 case SUBREG:
445 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
446 use "lb / lh / lw" */
447 snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
448 break;
449 case CONST_INT:
450 /* (mem (plus reg const_int))
451 => access location by adding one register with const_int,
452 use "lbi / lhi / lwi" */
453 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
454 break;
455 default:
456 abort ();
458 break;
460 case LO_SUM:
461 operands[2] = XEXP (code, 1);
462 operands[1] = XEXP (code, 0);
463 snprintf (pattern, sizeof (pattern),
464 "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
465 break;
467 default:
468 abort ();
471 output_asm_insn (pattern, operands);
472 return "";
475 /* Output 32-bit load with signed extension. */
476 const char *
477 nds32_output_32bit_load_s (rtx *operands, int byte)
479 char pattern[100];
480 unsigned char size;
481 rtx code;
483 code = XEXP (operands[1], 0);
485 size = nds32_byte_to_size (byte);
487 switch (GET_CODE (code))
489 case REG:
490 /* (mem (reg X))
491 => access location by using register,
492 use "lbsi / lhsi" */
493 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
494 break;
496 case SYMBOL_REF:
497 case CONST:
498 /* (mem (symbol_ref X))
499 (mem (const (...)))
500 => access global variables,
501 use "lbsi.gp / lhsi.gp" */
502 operands[1] = XEXP (operands[1], 0);
503 snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
504 break;
506 case POST_INC:
507 /* (mem (post_inc reg))
508 => access location by using register which will be post increment,
509 use "lbsi.bi / lhsi.bi" */
510 snprintf (pattern, sizeof (pattern),
511 "l%csi.bi\t%%0, %%1, %d", size, byte);
512 break;
514 case POST_DEC:
515 /* (mem (post_dec reg))
516 => access location by using register which will be post decrement,
517 use "lbsi.bi / lhsi.bi" */
518 snprintf (pattern, sizeof (pattern),
519 "l%csi.bi\t%%0, %%1, -%d", size, byte);
520 break;
522 case POST_MODIFY:
523 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
525 case REG:
526 case SUBREG:
527 /* (mem (post_modify (reg) (plus (reg) (reg))))
528 => access location by using register which will be
529 post modified with reg,
530 use "lbs.bi/ lhs.bi" */
531 snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
532 break;
533 case CONST_INT:
534 /* (mem (post_modify (reg) (plus (reg) (const_int))))
535 => access location by using register which will be
536 post modified with const_int,
537 use "lbsi.bi/ lhsi.bi" */
538 snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
539 break;
540 default:
541 abort ();
543 break;
545 case PLUS:
546 switch (GET_CODE (XEXP (code, 1)))
548 case REG:
549 case SUBREG:
550 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
551 use "lbs / lhs" */
552 snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
553 break;
554 case CONST_INT:
555 /* (mem (plus reg const_int))
556 => access location by adding one register with const_int,
557 use "lbsi / lhsi" */
558 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
559 break;
560 default:
561 abort ();
563 break;
565 case LO_SUM:
566 operands[2] = XEXP (code, 1);
567 operands[1] = XEXP (code, 0);
568 snprintf (pattern, sizeof (pattern),
569 "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
570 break;
572 default:
573 abort ();
576 output_asm_insn (pattern, operands);
577 return "";
580 /* Function to output stack push operation.
581 We need to deal with normal stack push multiple or stack v3push. */
582 const char *
583 nds32_output_stack_push (rtx par_rtx)
585 /* A string pattern for output_asm_insn(). */
586 char pattern[100];
587 /* The operands array which will be used in output_asm_insn(). */
588 rtx operands[3];
589 /* Pick up varargs first regno and last regno for further use. */
590 int rb_va_args = cfun->machine->va_args_first_regno;
591 int re_va_args = cfun->machine->va_args_last_regno;
592 int last_argument_regno = NDS32_FIRST_GPR_REGNUM
593 + NDS32_MAX_GPR_REGS_FOR_ARGS
594 - 1;
595 /* Pick up callee-saved first regno and last regno for further use. */
596 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
597 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
599 /* First we need to check if we are pushing argument registers not used
600 for the named arguments. If so, we have to create 'smw.adm' (push.s)
601 instruction. */
602 if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx))
604 /* Set operands[0] and operands[1]. */
605 operands[0] = gen_rtx_REG (SImode, rb_va_args);
606 operands[1] = gen_rtx_REG (SImode, re_va_args);
607 /* Create assembly code pattern: "Rb, Re, { }". */
608 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
609 /* We use output_asm_insn() to output assembly code by ourself. */
610 output_asm_insn (pattern, operands);
611 return "";
614 /* If we step here, we are going to do v3push or multiple push operation. */
616 /* The v3push/v3pop instruction should only be applied on
617 none-isr and none-variadic function. */
618 if (TARGET_V3PUSH
619 && !nds32_isr_function_p (current_function_decl)
620 && (cfun->machine->va_args_size == 0))
622 /* For stack v3push:
623 operands[0]: Re
624 operands[1]: imm8u */
626 /* This variable is to check if 'push25 Re,imm8u' is available. */
627 int sp_adjust;
629 /* Set operands[0]. */
630 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
632 /* Check if we can generate 'push25 Re,imm8u',
633 otherwise, generate 'push25 Re,0'. */
634 sp_adjust = cfun->machine->local_size
635 + cfun->machine->out_args_size
636 + cfun->machine->callee_saved_area_gpr_padding_bytes;
637 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
638 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
639 operands[1] = GEN_INT (sp_adjust);
640 else
641 operands[1] = GEN_INT (0);
643 /* Create assembly code pattern. */
644 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
646 else
648 /* For normal stack push multiple:
649 operands[0]: Rb
650 operands[1]: Re
651 operands[2]: En4 */
653 /* This variable is used to check if we only need to generate En4 field.
654 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
655 int push_en4_only_p = 0;
657 /* Set operands[0] and operands[1]. */
658 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
659 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
661 /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
662 if (!cfun->machine->fp_size
663 && !cfun->machine->gp_size
664 && !cfun->machine->lp_size
665 && REGNO (operands[0]) == SP_REGNUM
666 && REGNO (operands[1]) == SP_REGNUM)
668 /* No need to generate instruction. */
669 return "";
671 else
673 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
674 if (REGNO (operands[0]) == SP_REGNUM
675 && REGNO (operands[1]) == SP_REGNUM)
676 push_en4_only_p = 1;
678 /* Create assembly code pattern.
679 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
680 snprintf (pattern, sizeof (pattern),
681 "push.s\t%s{%s%s%s }",
682 push_en4_only_p ? "" : "%0, %1, ",
683 cfun->machine->fp_size ? " $fp" : "",
684 cfun->machine->gp_size ? " $gp" : "",
685 cfun->machine->lp_size ? " $lp" : "");
689 /* We use output_asm_insn() to output assembly code by ourself. */
690 output_asm_insn (pattern, operands);
691 return "";
694 /* Function to output stack pop operation.
695 We need to deal with normal stack pop multiple or stack v3pop. */
696 const char *
697 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
699 /* A string pattern for output_asm_insn(). */
700 char pattern[100];
701 /* The operands array which will be used in output_asm_insn(). */
702 rtx operands[3];
703 /* Pick up callee-saved first regno and last regno for further use. */
704 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
705 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
707 /* If we step here, we are going to do v3pop or multiple pop operation. */
709 /* The v3push/v3pop instruction should only be applied on
710 none-isr and none-variadic function. */
711 if (TARGET_V3PUSH
712 && !nds32_isr_function_p (current_function_decl)
713 && (cfun->machine->va_args_size == 0))
715 /* For stack v3pop:
716 operands[0]: Re
717 operands[1]: imm8u */
719 /* This variable is to check if 'pop25 Re,imm8u' is available. */
720 int sp_adjust;
722 /* Set operands[0]. */
723 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
725 /* Check if we can generate 'pop25 Re,imm8u',
726 otherwise, generate 'pop25 Re,0'.
727 We have to consider alloca issue as well.
728 If the function does call alloca(), the stack pointer is not fixed.
729 In that case, we cannot use 'pop25 Re,imm8u' directly.
730 We have to caculate stack pointer from frame pointer
731 and then use 'pop25 Re,0'. */
732 sp_adjust = cfun->machine->local_size
733 + cfun->machine->out_args_size
734 + cfun->machine->callee_saved_area_gpr_padding_bytes;
735 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
736 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
737 && !cfun->calls_alloca)
738 operands[1] = GEN_INT (sp_adjust);
739 else
740 operands[1] = GEN_INT (0);
742 /* Create assembly code pattern. */
743 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
745 else
747 /* For normal stack pop multiple:
748 operands[0]: Rb
749 operands[1]: Re
750 operands[2]: En4 */
752 /* This variable is used to check if we only need to generate En4 field.
753 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
754 int pop_en4_only_p = 0;
756 /* Set operands[0] and operands[1]. */
757 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
758 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
760 /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
761 if (!cfun->machine->fp_size
762 && !cfun->machine->gp_size
763 && !cfun->machine->lp_size
764 && REGNO (operands[0]) == SP_REGNUM
765 && REGNO (operands[1]) == SP_REGNUM)
767 /* No need to generate instruction. */
768 return "";
770 else
772 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
773 if (REGNO (operands[0]) == SP_REGNUM
774 && REGNO (operands[1]) == SP_REGNUM)
775 pop_en4_only_p = 1;
777 /* Create assembly code pattern.
778 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
779 snprintf (pattern, sizeof (pattern),
780 "pop.s\t%s{%s%s%s }",
781 pop_en4_only_p ? "" : "%0, %1, ",
782 cfun->machine->fp_size ? " $fp" : "",
783 cfun->machine->gp_size ? " $gp" : "",
784 cfun->machine->lp_size ? " $lp" : "");
788 /* We use output_asm_insn() to output assembly code by ourself. */
789 output_asm_insn (pattern, operands);
790 return "";
793 /* Function to generate PC relative jump table.
794 Refer to nds32.md for more details.
796 The following is the sample for the case that diff value
797 can be presented in '.short' size.
799 addi $r1, $r1, -(case_lower_bound)
800 slti $ta, $r1, (case_number)
801 beqz $ta, .L_skip_label
803 la $ta, .L35 ! get jump table address
804 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
805 addi $ta, $r1, $ta
806 jr5 $ta
808 ! jump table entry
809 L35:
810 .short .L25-.L35
811 .short .L26-.L35
812 .short .L27-.L35
813 .short .L28-.L35
814 .short .L29-.L35
815 .short .L30-.L35
816 .short .L31-.L35
817 .short .L32-.L35
818 .short .L33-.L35
819 .short .L34-.L35 */
820 const char *
821 nds32_output_casesi_pc_relative (rtx *operands)
823 machine_mode mode;
824 rtx diff_vec;
826 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
828 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
830 /* Step C: "t <-- operands[1]". */
831 output_asm_insn ("la\t$ta, %l1", operands);
833 /* Get the mode of each element in the difference vector. */
834 mode = GET_MODE (diff_vec);
836 /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
837 where m is 0, 1, or 2 to load address-diff value from table. */
838 switch (mode)
840 case QImode:
841 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
842 break;
843 case HImode:
844 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
845 break;
846 case SImode:
847 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
848 break;
849 default:
850 gcc_unreachable ();
853 /* Step E: "t <-- z + t".
854 Add table label_ref with address-diff value to
855 obtain target case address. */
856 output_asm_insn ("add\t$ta, %2, $ta", operands);
858 /* Step F: jump to target with register t. */
859 if (TARGET_16_BIT)
860 return "jr5\t$ta";
861 else
862 return "jr\t$ta";
865 /* Function to generate normal jump table. */
866 const char *
867 nds32_output_casesi (rtx *operands)
869 /* Step C: "t <-- operands[1]". */
870 output_asm_insn ("la\t$ta, %l1", operands);
872 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
873 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
875 /* No need to perform Step E, which is only used for
876 pc relative jump table. */
878 /* Step F: jump to target with register z. */
879 if (TARGET_16_BIT)
880 return "jr5\t%2";
881 else
882 return "jr\t%2";
885 /* ------------------------------------------------------------------------ */