PR tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with...
[official-gcc.git] / gcc / config / nds32 / nds32-md-auxiliary.c
blob62bc4ff50bb6680185321c49f22c7eacc5a4361e
1 /* Auxiliary functions for output asm template or expand rtl
2 pattern of Andes NDS32 cpu for GNU compiler
3 Copyright (C) 2012-2018 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 #define IN_TARGET_CODE 1
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "backend.h"
30 #include "target.h"
31 #include "rtl.h"
32 #include "tree.h"
33 #include "memmodel.h"
34 #include "tm_p.h"
35 #include "optabs.h" /* For GEN_FCN. */
36 #include "recog.h"
37 #include "output.h"
38 #include "tm-constrs.h"
40 /* ------------------------------------------------------------------------ */
42 /* A helper function to return character based on byte size. */
43 static char
44 nds32_byte_to_size (int byte)
46 switch (byte)
48 case 4:
49 return 'w';
50 case 2:
51 return 'h';
52 case 1:
53 return 'b';
54 default:
55 /* Normally it should not be here. */
56 gcc_unreachable ();
60 /* A helper function to return memory format. */
61 enum nds32_16bit_address_type
62 nds32_mem_format (rtx op)
64 machine_mode mode_test;
65 int val;
66 int regno;
68 if (!TARGET_16_BIT)
69 return ADDRESS_NOT_16BIT_FORMAT;
71 mode_test = GET_MODE (op);
73 op = XEXP (op, 0);
75 /* 45 format. */
76 if (GET_CODE (op) == REG && (mode_test == SImode))
77 return ADDRESS_REG;
79 /* 333 format for QI/HImode. */
80 if (GET_CODE (op) == REG && (REGNO (op) < R8_REGNUM))
81 return ADDRESS_LO_REG_IMM3U;
83 /* post_inc 333 format. */
84 if ((GET_CODE (op) == POST_INC) && (mode_test == SImode))
86 regno = REGNO(XEXP (op, 0));
88 if (regno < 8)
89 return ADDRESS_POST_INC_LO_REG_IMM3U;
92 /* post_inc 333 format. */
93 if ((GET_CODE (op) == POST_MODIFY)
94 && (mode_test == SImode)
95 && (REG_P (XEXP (XEXP (op, 1), 0)))
96 && (CONST_INT_P (XEXP (XEXP (op, 1), 1))))
98 regno = REGNO (XEXP (XEXP (op, 1), 0));
99 val = INTVAL (XEXP (XEXP (op, 1), 1));
100 if (regno < 8 && val < 32)
101 return ADDRESS_POST_INC_LO_REG_IMM3U;
104 if ((GET_CODE (op) == PLUS)
105 && (GET_CODE (XEXP (op, 0)) == REG)
106 && (GET_CODE (XEXP (op, 1)) == CONST_INT))
108 val = INTVAL (XEXP (op, 1));
110 regno = REGNO(XEXP (op, 0));
112 if (regno > 7
113 && regno != SP_REGNUM
114 && regno != FP_REGNUM)
115 return ADDRESS_NOT_16BIT_FORMAT;
117 switch (mode_test)
119 case E_QImode:
120 /* 333 format. */
121 if (val >= 0 && val < 8 && regno < 8)
122 return ADDRESS_LO_REG_IMM3U;
123 break;
125 case E_HImode:
126 /* 333 format. */
127 if (val >= 0 && val < 16 && (val % 2 == 0) && regno < 8)
128 return ADDRESS_LO_REG_IMM3U;
129 break;
131 case E_SImode:
132 case E_SFmode:
133 case E_DFmode:
134 /* fp imply 37 format. */
135 if ((regno == FP_REGNUM) &&
136 (val >= 0 && val < 512 && (val % 4 == 0)))
137 return ADDRESS_FP_IMM7U;
138 /* sp imply 37 format. */
139 else if ((regno == SP_REGNUM) &&
140 (val >= 0 && val < 512 && (val % 4 == 0)))
141 return ADDRESS_SP_IMM7U;
142 /* 333 format. */
143 else if (val >= 0 && val < 32 && (val % 4 == 0) && regno < 8)
144 return ADDRESS_LO_REG_IMM3U;
145 break;
147 default:
148 break;
152 return ADDRESS_NOT_16BIT_FORMAT;
155 /* Output 16-bit store. */
156 const char *
157 nds32_output_16bit_store (rtx *operands, int byte)
159 char pattern[100];
160 char size;
161 rtx code = XEXP (operands[0], 0);
163 size = nds32_byte_to_size (byte);
165 switch (nds32_mem_format (operands[0]))
167 case ADDRESS_REG:
168 operands[0] = code;
169 output_asm_insn ("swi450\t%1, [%0]", operands);
170 break;
171 case ADDRESS_LO_REG_IMM3U:
172 snprintf (pattern, sizeof (pattern), "s%ci333\t%%1, %%0", size);
173 output_asm_insn (pattern, operands);
174 break;
175 case ADDRESS_POST_INC_LO_REG_IMM3U:
176 snprintf (pattern, sizeof (pattern), "s%ci333.bi\t%%1, %%0", size);
177 output_asm_insn (pattern, operands);
178 break;
179 case ADDRESS_FP_IMM7U:
180 output_asm_insn ("swi37\t%1, %0", operands);
181 break;
182 case ADDRESS_SP_IMM7U:
183 /* Get immediate value and set back to operands[1]. */
184 operands[0] = XEXP (code, 1);
185 output_asm_insn ("swi37.sp\t%1, [ + (%0)]", operands);
186 break;
187 default:
188 break;
191 return "";
194 /* Output 16-bit load. */
195 const char *
196 nds32_output_16bit_load (rtx *operands, int byte)
198 char pattern[100];
199 unsigned char size;
200 rtx code = XEXP (operands[1], 0);
202 size = nds32_byte_to_size (byte);
204 switch (nds32_mem_format (operands[1]))
206 case ADDRESS_REG:
207 operands[1] = code;
208 output_asm_insn ("lwi450\t%0, [%1]", operands);
209 break;
210 case ADDRESS_LO_REG_IMM3U:
211 snprintf (pattern, sizeof (pattern), "l%ci333\t%%0, %%1", size);
212 output_asm_insn (pattern, operands);
213 break;
214 case ADDRESS_POST_INC_LO_REG_IMM3U:
215 snprintf (pattern, sizeof (pattern), "l%ci333.bi\t%%0, %%1", size);
216 output_asm_insn (pattern, operands);
217 break;
218 case ADDRESS_FP_IMM7U:
219 output_asm_insn ("lwi37\t%0, %1", operands);
220 break;
221 case ADDRESS_SP_IMM7U:
222 /* Get immediate value and set back to operands[0]. */
223 operands[1] = XEXP (code, 1);
224 output_asm_insn ("lwi37.sp\t%0, [ + (%1)]", operands);
225 break;
226 default:
227 break;
230 return "";
233 /* Output 32-bit store. */
234 const char *
235 nds32_output_32bit_store (rtx *operands, int byte)
237 char pattern[100];
238 unsigned char size;
239 rtx code = XEXP (operands[0], 0);
241 size = nds32_byte_to_size (byte);
243 switch (GET_CODE (code))
245 case REG:
246 /* (mem (reg X))
247 => access location by using register,
248 use "sbi / shi / swi" */
249 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
250 break;
252 case SYMBOL_REF:
253 case CONST:
254 /* (mem (symbol_ref X))
255 (mem (const (...)))
256 => access global variables,
257 use "sbi.gp / shi.gp / swi.gp" */
258 operands[0] = XEXP (operands[0], 0);
259 snprintf (pattern, sizeof (pattern), "s%ci.gp\t%%1, [ + %%0]", size);
260 break;
262 case POST_INC:
263 /* (mem (post_inc reg))
264 => access location by using register which will be post increment,
265 use "sbi.bi / shi.bi / swi.bi" */
266 snprintf (pattern, sizeof (pattern),
267 "s%ci.bi\t%%1, %%0, %d", size, byte);
268 break;
270 case POST_DEC:
271 /* (mem (post_dec reg))
272 => access location by using register which will be post decrement,
273 use "sbi.bi / shi.bi / swi.bi" */
274 snprintf (pattern, sizeof (pattern),
275 "s%ci.bi\t%%1, %%0, -%d", size, byte);
276 break;
278 case POST_MODIFY:
279 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
281 case REG:
282 case SUBREG:
283 /* (mem (post_modify (reg) (plus (reg) (reg))))
284 => access location by using register which will be
285 post modified with reg,
286 use "sb.bi/ sh.bi / sw.bi" */
287 snprintf (pattern, sizeof (pattern), "s%c.bi\t%%1, %%0", size);
288 break;
289 case CONST_INT:
290 /* (mem (post_modify (reg) (plus (reg) (const_int))))
291 => access location by using register which will be
292 post modified with const_int,
293 use "sbi.bi/ shi.bi / swi.bi" */
294 snprintf (pattern, sizeof (pattern), "s%ci.bi\t%%1, %%0", size);
295 break;
296 default:
297 abort ();
299 break;
301 case PLUS:
302 switch (GET_CODE (XEXP (code, 1)))
304 case REG:
305 case SUBREG:
306 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
307 => access location by adding two registers,
308 use "sb / sh / sw" */
309 snprintf (pattern, sizeof (pattern), "s%c\t%%1, %%0", size);
310 break;
311 case CONST_INT:
312 /* (mem (plus reg const_int))
313 => access location by adding one register with const_int,
314 use "sbi / shi / swi" */
315 snprintf (pattern, sizeof (pattern), "s%ci\t%%1, %%0", size);
316 break;
317 default:
318 abort ();
320 break;
322 case LO_SUM:
323 operands[2] = XEXP (code, 1);
324 operands[0] = XEXP (code, 0);
325 snprintf (pattern, sizeof (pattern),
326 "s%ci\t%%1, [%%0 + lo12(%%2)]", size);
327 break;
329 default:
330 abort ();
333 output_asm_insn (pattern, operands);
334 return "";
337 /* Output 32-bit load. */
338 const char *
339 nds32_output_32bit_load (rtx *operands, int byte)
341 char pattern[100];
342 unsigned char size;
343 rtx code;
345 code = XEXP (operands[1], 0);
347 size = nds32_byte_to_size (byte);
349 switch (GET_CODE (code))
351 case REG:
352 /* (mem (reg X))
353 => access location by using register,
354 use "lbi / lhi / lwi" */
355 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
356 break;
358 case SYMBOL_REF:
359 case CONST:
360 /* (mem (symbol_ref X))
361 (mem (const (...)))
362 => access global variables,
363 use "lbi.gp / lhi.gp / lwi.gp" */
364 operands[1] = XEXP (operands[1], 0);
365 snprintf (pattern, sizeof (pattern), "l%ci.gp\t%%0, [ + %%1]", size);
366 break;
368 case POST_INC:
369 /* (mem (post_inc reg))
370 => access location by using register which will be post increment,
371 use "lbi.bi / lhi.bi / lwi.bi" */
372 snprintf (pattern, sizeof (pattern),
373 "l%ci.bi\t%%0, %%1, %d", size, byte);
374 break;
376 case POST_DEC:
377 /* (mem (post_dec reg))
378 => access location by using register which will be post decrement,
379 use "lbi.bi / lhi.bi / lwi.bi" */
380 snprintf (pattern, sizeof (pattern),
381 "l%ci.bi\t%%0, %%1, -%d", size, byte);
382 break;
384 case POST_MODIFY:
385 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
387 case REG:
388 case SUBREG:
389 /* (mem (post_modify (reg) (plus (reg) (reg))))
390 => access location by using register which will be
391 post modified with reg,
392 use "lb.bi/ lh.bi / lw.bi" */
393 snprintf (pattern, sizeof (pattern), "l%c.bi\t%%0, %%1", size);
394 break;
395 case CONST_INT:
396 /* (mem (post_modify (reg) (plus (reg) (const_int))))
397 => access location by using register which will be
398 post modified with const_int,
399 use "lbi.bi/ lhi.bi / lwi.bi" */
400 snprintf (pattern, sizeof (pattern), "l%ci.bi\t%%0, %%1", size);
401 break;
402 default:
403 abort ();
405 break;
407 case PLUS:
408 switch (GET_CODE (XEXP (code, 1)))
410 case REG:
411 case SUBREG:
412 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
413 use "lb / lh / lw" */
414 snprintf (pattern, sizeof (pattern), "l%c\t%%0, %%1", size);
415 break;
416 case CONST_INT:
417 /* (mem (plus reg const_int))
418 => access location by adding one register with const_int,
419 use "lbi / lhi / lwi" */
420 snprintf (pattern, sizeof (pattern), "l%ci\t%%0, %%1", size);
421 break;
422 default:
423 abort ();
425 break;
427 case LO_SUM:
428 operands[2] = XEXP (code, 1);
429 operands[1] = XEXP (code, 0);
430 snprintf (pattern, sizeof (pattern),
431 "l%ci\t%%0, [%%1 + lo12(%%2)]", size);
432 break;
434 default:
435 abort ();
438 output_asm_insn (pattern, operands);
439 return "";
442 /* Output 32-bit load with signed extension. */
443 const char *
444 nds32_output_32bit_load_s (rtx *operands, int byte)
446 char pattern[100];
447 unsigned char size;
448 rtx code;
450 code = XEXP (operands[1], 0);
452 size = nds32_byte_to_size (byte);
454 switch (GET_CODE (code))
456 case REG:
457 /* (mem (reg X))
458 => access location by using register,
459 use "lbsi / lhsi" */
460 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
461 break;
463 case SYMBOL_REF:
464 case CONST:
465 /* (mem (symbol_ref X))
466 (mem (const (...)))
467 => access global variables,
468 use "lbsi.gp / lhsi.gp" */
469 operands[1] = XEXP (operands[1], 0);
470 snprintf (pattern, sizeof (pattern), "l%csi.gp\t%%0, [ + %%1]", size);
471 break;
473 case POST_INC:
474 /* (mem (post_inc reg))
475 => access location by using register which will be post increment,
476 use "lbsi.bi / lhsi.bi" */
477 snprintf (pattern, sizeof (pattern),
478 "l%csi.bi\t%%0, %%1, %d", size, byte);
479 break;
481 case POST_DEC:
482 /* (mem (post_dec reg))
483 => access location by using register which will be post decrement,
484 use "lbsi.bi / lhsi.bi" */
485 snprintf (pattern, sizeof (pattern),
486 "l%csi.bi\t%%0, %%1, -%d", size, byte);
487 break;
489 case POST_MODIFY:
490 switch (GET_CODE (XEXP (XEXP (code, 1), 1)))
492 case REG:
493 case SUBREG:
494 /* (mem (post_modify (reg) (plus (reg) (reg))))
495 => access location by using register which will be
496 post modified with reg,
497 use "lbs.bi/ lhs.bi" */
498 snprintf (pattern, sizeof (pattern), "l%cs.bi\t%%0, %%1", size);
499 break;
500 case CONST_INT:
501 /* (mem (post_modify (reg) (plus (reg) (const_int))))
502 => access location by using register which will be
503 post modified with const_int,
504 use "lbsi.bi/ lhsi.bi" */
505 snprintf (pattern, sizeof (pattern), "l%csi.bi\t%%0, %%1", size);
506 break;
507 default:
508 abort ();
510 break;
512 case PLUS:
513 switch (GET_CODE (XEXP (code, 1)))
515 case REG:
516 case SUBREG:
517 /* (mem (plus reg reg)) or (mem (plus (mult reg const_int) reg))
518 use "lbs / lhs" */
519 snprintf (pattern, sizeof (pattern), "l%cs\t%%0, %%1", size);
520 break;
521 case CONST_INT:
522 /* (mem (plus reg const_int))
523 => access location by adding one register with const_int,
524 use "lbsi / lhsi" */
525 snprintf (pattern, sizeof (pattern), "l%csi\t%%0, %%1", size);
526 break;
527 default:
528 abort ();
530 break;
532 case LO_SUM:
533 operands[2] = XEXP (code, 1);
534 operands[1] = XEXP (code, 0);
535 snprintf (pattern, sizeof (pattern),
536 "l%csi\t%%0, [%%1 + lo12(%%2)]", size);
537 break;
539 default:
540 abort ();
543 output_asm_insn (pattern, operands);
544 return "";
547 /* Function to output stack push operation.
548 We need to deal with normal stack push multiple or stack v3push. */
549 const char *
550 nds32_output_stack_push (rtx par_rtx)
552 /* A string pattern for output_asm_insn(). */
553 char pattern[100];
554 /* The operands array which will be used in output_asm_insn(). */
555 rtx operands[3];
556 /* Pick up varargs first regno and last regno for further use. */
557 int rb_va_args = cfun->machine->va_args_first_regno;
558 int re_va_args = cfun->machine->va_args_last_regno;
559 int last_argument_regno = NDS32_FIRST_GPR_REGNUM
560 + NDS32_MAX_GPR_REGS_FOR_ARGS
561 - 1;
562 /* Pick up callee-saved first regno and last regno for further use. */
563 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
564 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
566 /* First we need to check if we are pushing argument registers not used
567 for the named arguments. If so, we have to create 'smw.adm' (push.s)
568 instruction. */
569 if (reg_mentioned_p (gen_rtx_REG (SImode, last_argument_regno), par_rtx))
571 /* Set operands[0] and operands[1]. */
572 operands[0] = gen_rtx_REG (SImode, rb_va_args);
573 operands[1] = gen_rtx_REG (SImode, re_va_args);
574 /* Create assembly code pattern: "Rb, Re, { }". */
575 snprintf (pattern, sizeof (pattern), "push.s\t%s", "%0, %1, { }");
576 /* We use output_asm_insn() to output assembly code by ourself. */
577 output_asm_insn (pattern, operands);
578 return "";
581 /* If we step here, we are going to do v3push or multiple push operation. */
583 /* The v3push/v3pop instruction should only be applied on
584 none-isr and none-variadic function. */
585 if (TARGET_V3PUSH
586 && !nds32_isr_function_p (current_function_decl)
587 && (cfun->machine->va_args_size == 0))
589 /* For stack v3push:
590 operands[0]: Re
591 operands[1]: imm8u */
593 /* This variable is to check if 'push25 Re,imm8u' is available. */
594 int sp_adjust;
596 /* Set operands[0]. */
597 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
599 /* Check if we can generate 'push25 Re,imm8u',
600 otherwise, generate 'push25 Re,0'. */
601 sp_adjust = cfun->machine->local_size
602 + cfun->machine->out_args_size
603 + cfun->machine->callee_saved_area_gpr_padding_bytes;
604 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
605 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust))
606 operands[1] = GEN_INT (sp_adjust);
607 else
608 operands[1] = GEN_INT (0);
610 /* Create assembly code pattern. */
611 snprintf (pattern, sizeof (pattern), "push25\t%%0, %%1");
613 else
615 /* For normal stack push multiple:
616 operands[0]: Rb
617 operands[1]: Re
618 operands[2]: En4 */
620 /* This variable is used to check if we only need to generate En4 field.
621 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
622 int push_en4_only_p = 0;
624 /* Set operands[0] and operands[1]. */
625 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
626 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
628 /* 'smw.adm $sp,[$sp],$sp,0' means push nothing. */
629 if (!cfun->machine->fp_size
630 && !cfun->machine->gp_size
631 && !cfun->machine->lp_size
632 && REGNO (operands[0]) == SP_REGNUM
633 && REGNO (operands[1]) == SP_REGNUM)
635 /* No need to generate instruction. */
636 return "";
638 else
640 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
641 if (REGNO (operands[0]) == SP_REGNUM
642 && REGNO (operands[1]) == SP_REGNUM)
643 push_en4_only_p = 1;
645 /* Create assembly code pattern.
646 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
647 snprintf (pattern, sizeof (pattern),
648 "push.s\t%s{%s%s%s }",
649 push_en4_only_p ? "" : "%0, %1, ",
650 cfun->machine->fp_size ? " $fp" : "",
651 cfun->machine->gp_size ? " $gp" : "",
652 cfun->machine->lp_size ? " $lp" : "");
656 /* We use output_asm_insn() to output assembly code by ourself. */
657 output_asm_insn (pattern, operands);
658 return "";
661 /* Function to output stack pop operation.
662 We need to deal with normal stack pop multiple or stack v3pop. */
663 const char *
664 nds32_output_stack_pop (rtx par_rtx ATTRIBUTE_UNUSED)
666 /* A string pattern for output_asm_insn(). */
667 char pattern[100];
668 /* The operands array which will be used in output_asm_insn(). */
669 rtx operands[3];
670 /* Pick up callee-saved first regno and last regno for further use. */
671 int rb_callee_saved = cfun->machine->callee_saved_first_gpr_regno;
672 int re_callee_saved = cfun->machine->callee_saved_last_gpr_regno;
674 /* If we step here, we are going to do v3pop or multiple pop operation. */
676 /* The v3push/v3pop instruction should only be applied on
677 none-isr and none-variadic function. */
678 if (TARGET_V3PUSH
679 && !nds32_isr_function_p (current_function_decl)
680 && (cfun->machine->va_args_size == 0))
682 /* For stack v3pop:
683 operands[0]: Re
684 operands[1]: imm8u */
686 /* This variable is to check if 'pop25 Re,imm8u' is available. */
687 int sp_adjust;
689 /* Set operands[0]. */
690 operands[0] = gen_rtx_REG (SImode, re_callee_saved);
692 /* Check if we can generate 'pop25 Re,imm8u',
693 otherwise, generate 'pop25 Re,0'.
694 We have to consider alloca issue as well.
695 If the function does call alloca(), the stack pointer is not fixed.
696 In that case, we cannot use 'pop25 Re,imm8u' directly.
697 We have to caculate stack pointer from frame pointer
698 and then use 'pop25 Re,0'. */
699 sp_adjust = cfun->machine->local_size
700 + cfun->machine->out_args_size
701 + cfun->machine->callee_saved_area_gpr_padding_bytes;
702 if (satisfies_constraint_Iu08 (GEN_INT (sp_adjust))
703 && NDS32_DOUBLE_WORD_ALIGN_P (sp_adjust)
704 && !cfun->calls_alloca)
705 operands[1] = GEN_INT (sp_adjust);
706 else
707 operands[1] = GEN_INT (0);
709 /* Create assembly code pattern. */
710 snprintf (pattern, sizeof (pattern), "pop25\t%%0, %%1");
712 else
714 /* For normal stack pop multiple:
715 operands[0]: Rb
716 operands[1]: Re
717 operands[2]: En4 */
719 /* This variable is used to check if we only need to generate En4 field.
720 As long as Rb==Re=SP_REGNUM, we set this variable to 1. */
721 int pop_en4_only_p = 0;
723 /* Set operands[0] and operands[1]. */
724 operands[0] = gen_rtx_REG (SImode, rb_callee_saved);
725 operands[1] = gen_rtx_REG (SImode, re_callee_saved);
727 /* 'lmw.bim $sp,[$sp],$sp,0' means pop nothing. */
728 if (!cfun->machine->fp_size
729 && !cfun->machine->gp_size
730 && !cfun->machine->lp_size
731 && REGNO (operands[0]) == SP_REGNUM
732 && REGNO (operands[1]) == SP_REGNUM)
734 /* No need to generate instruction. */
735 return "";
737 else
739 /* If Rb==Re=SP_REGNUM, we only need to generate En4 field. */
740 if (REGNO (operands[0]) == SP_REGNUM
741 && REGNO (operands[1]) == SP_REGNUM)
742 pop_en4_only_p = 1;
744 /* Create assembly code pattern.
745 We need to handle the form: "Rb, Re, { $fp $gp $lp }". */
746 snprintf (pattern, sizeof (pattern),
747 "pop.s\t%s{%s%s%s }",
748 pop_en4_only_p ? "" : "%0, %1, ",
749 cfun->machine->fp_size ? " $fp" : "",
750 cfun->machine->gp_size ? " $gp" : "",
751 cfun->machine->lp_size ? " $lp" : "");
755 /* We use output_asm_insn() to output assembly code by ourself. */
756 output_asm_insn (pattern, operands);
757 return "";
760 /* Function to generate PC relative jump table.
761 Refer to nds32.md for more details.
763 The following is the sample for the case that diff value
764 can be presented in '.short' size.
766 addi $r1, $r1, -(case_lower_bound)
767 slti $ta, $r1, (case_number)
768 beqz $ta, .L_skip_label
770 la $ta, .L35 ! get jump table address
771 lh $r1, [$ta + $r1 << 1] ! load symbol diff from jump table entry
772 addi $ta, $r1, $ta
773 jr5 $ta
775 ! jump table entry
776 L35:
777 .short .L25-.L35
778 .short .L26-.L35
779 .short .L27-.L35
780 .short .L28-.L35
781 .short .L29-.L35
782 .short .L30-.L35
783 .short .L31-.L35
784 .short .L32-.L35
785 .short .L33-.L35
786 .short .L34-.L35 */
787 const char *
788 nds32_output_casesi_pc_relative (rtx *operands)
790 machine_mode mode;
791 rtx diff_vec;
793 diff_vec = PATTERN (NEXT_INSN (as_a <rtx_insn *> (operands[1])));
795 gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
797 /* Step C: "t <-- operands[1]". */
798 output_asm_insn ("la\t$ta, %l1", operands);
800 /* Get the mode of each element in the difference vector. */
801 mode = GET_MODE (diff_vec);
803 /* Step D: "z <-- (mem (plus (operands[0] << m) t))",
804 where m is 0, 1, or 2 to load address-diff value from table. */
805 switch (mode)
807 case E_QImode:
808 output_asm_insn ("lb\t%2, [$ta + %0 << 0]", operands);
809 break;
810 case E_HImode:
811 output_asm_insn ("lh\t%2, [$ta + %0 << 1]", operands);
812 break;
813 case E_SImode:
814 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
815 break;
816 default:
817 gcc_unreachable ();
820 /* Step E: "t <-- z + t".
821 Add table label_ref with address-diff value to
822 obtain target case address. */
823 output_asm_insn ("add\t$ta, %2, $ta", operands);
825 /* Step F: jump to target with register t. */
826 if (TARGET_16_BIT)
827 return "jr5\t$ta";
828 else
829 return "jr\t$ta";
832 /* Function to generate normal jump table. */
833 const char *
834 nds32_output_casesi (rtx *operands)
836 /* Step C: "t <-- operands[1]". */
837 output_asm_insn ("la\t$ta, %l1", operands);
839 /* Step D: "z <-- (mem (plus (operands[0] << 2) t))". */
840 output_asm_insn ("lw\t%2, [$ta + %0 << 2]", operands);
842 /* No need to perform Step E, which is only used for
843 pc relative jump table. */
845 /* Step F: jump to target with register z. */
846 if (TARGET_16_BIT)
847 return "jr5\t%2";
848 else
849 return "jr\t%2";
852 /* ------------------------------------------------------------------------ */