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