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