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