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