]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/rx/rx.c
2011-03-24 Paolo Bonzini <bonzini@gnu.org>
[thirdparty/gcc.git] / gcc / config / rx / rx.c
CommitLineData
24833e1a 1/* Subroutines used for code generation on Renesas RX processors.
95272799 2 Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
24833e1a 3 Contributed by Red Hat.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21/* To Do:
22
23 * Re-enable memory-to-memory copies and fix up reload. */
24
25#include "config.h"
26#include "system.h"
27#include "coretypes.h"
28#include "tm.h"
29#include "tree.h"
30#include "rtl.h"
31#include "regs.h"
32#include "hard-reg-set.h"
24833e1a 33#include "insn-config.h"
34#include "conditions.h"
35#include "output.h"
36#include "insn-attr.h"
37#include "flags.h"
38#include "function.h"
39#include "expr.h"
40#include "optabs.h"
41#include "libfuncs.h"
42#include "recog.h"
0b205f4c 43#include "diagnostic-core.h"
24833e1a 44#include "toplev.h"
45#include "reload.h"
46#include "df.h"
47#include "ggc.h"
48#include "tm_p.h"
49#include "debug.h"
50#include "target.h"
51#include "target-def.h"
52#include "langhooks.h"
fba5dd52 53#include "opts.h"
24833e1a 54\f
6bb30542 55static void rx_print_operand (FILE *, rtx, int);
56
ccfccd66 57#define CC_FLAG_S (1 << 0)
58#define CC_FLAG_Z (1 << 1)
59#define CC_FLAG_O (1 << 2)
60#define CC_FLAG_C (1 << 3)
61#define CC_FLAG_FP (1 << 4) /* fake, to differentiate CC_Fmode */
62
63static unsigned int flags_from_mode (enum machine_mode mode);
64static unsigned int flags_from_code (enum rtx_code code);
65
67e66e16 66enum rx_cpu_types rx_cpu_type = RX600;
67\f
24833e1a 68/* Return true if OP is a reference to an object in a small data area. */
69
70static bool
71rx_small_data_operand (rtx op)
72{
73 if (rx_small_data_limit == 0)
74 return false;
75
76 if (GET_CODE (op) == SYMBOL_REF)
77 return SYMBOL_REF_SMALL_P (op);
78
79 return false;
80}
81
82static bool
83rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED)
84{
85 if (RTX_OK_FOR_BASE (x, strict))
86 /* Register Indirect. */
87 return true;
88
89 if (GET_MODE_SIZE (mode) == 4
90 && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC))
91 /* Pre-decrement Register Indirect or
92 Post-increment Register Indirect. */
93 return RTX_OK_FOR_BASE (XEXP (x, 0), strict);
94
95 if (GET_CODE (x) == PLUS)
96 {
97 rtx arg1 = XEXP (x, 0);
98 rtx arg2 = XEXP (x, 1);
99 rtx index = NULL_RTX;
100
101 if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, strict))
102 index = arg2;
103 else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, strict))
104 index = arg1;
105 else
106 return false;
107
108 switch (GET_CODE (index))
109 {
110 case CONST_INT:
111 {
112 /* Register Relative: REG + INT.
113 Only positive, mode-aligned, mode-sized
114 displacements are allowed. */
115 HOST_WIDE_INT val = INTVAL (index);
116 int factor;
117
118 if (val < 0)
119 return false;
120
121 switch (GET_MODE_SIZE (mode))
122 {
123 default:
124 case 4: factor = 4; break;
125 case 2: factor = 2; break;
126 case 1: factor = 1; break;
127 }
128
129 if (val > (65535 * factor))
130 return false;
131 return (val % factor) == 0;
132 }
133
134 case REG:
135 /* Unscaled Indexed Register Indirect: REG + REG
136 Size has to be "QI", REG has to be valid. */
137 return GET_MODE_SIZE (mode) == 1 && RTX_OK_FOR_BASE (index, strict);
138
139 case MULT:
140 {
141 /* Scaled Indexed Register Indirect: REG + (REG * FACTOR)
142 Factor has to equal the mode size, REG has to be valid. */
143 rtx factor;
144
145 factor = XEXP (index, 1);
146 index = XEXP (index, 0);
147
148 return REG_P (index)
149 && RTX_OK_FOR_BASE (index, strict)
150 && CONST_INT_P (factor)
151 && GET_MODE_SIZE (mode) == INTVAL (factor);
152 }
153
154 default:
155 return false;
156 }
157 }
158
159 /* Small data area accesses turn into register relative offsets. */
160 return rx_small_data_operand (x);
161}
162
163/* Returns TRUE for simple memory addreses, ie ones
164 that do not involve register indirect addressing
165 or pre/post increment/decrement. */
166
167bool
168rx_is_restricted_memory_address (rtx mem, enum machine_mode mode)
169{
170 rtx base, index;
171
172 if (! rx_is_legitimate_address
173 (mode, mem, reload_in_progress || reload_completed))
174 return false;
175
176 switch (GET_CODE (mem))
177 {
178 case REG:
179 /* Simple memory addresses are OK. */
180 return true;
181
182 case PRE_DEC:
183 case POST_INC:
184 return false;
185
186 case PLUS:
187 /* Only allow REG+INT addressing. */
188 base = XEXP (mem, 0);
189 index = XEXP (mem, 1);
190
191 return RX_REG_P (base) && CONST_INT_P (index);
192
193 case SYMBOL_REF:
194 /* Can happen when small data is being supported.
195 Assume that it will be resolved into GP+INT. */
196 return true;
197
198 default:
199 gcc_unreachable ();
200 }
201}
202
5afe50d9 203/* Implement TARGET_MODE_DEPENDENT_ADDRESS_P. */
204
205static bool
206rx_mode_dependent_address_p (const_rtx addr)
24833e1a 207{
208 if (GET_CODE (addr) == CONST)
209 addr = XEXP (addr, 0);
210
211 switch (GET_CODE (addr))
212 {
213 /* --REG and REG++ only work in SImode. */
214 case PRE_DEC:
215 case POST_INC:
216 return true;
217
218 case MINUS:
219 case PLUS:
220 if (! REG_P (XEXP (addr, 0)))
221 return true;
222
223 addr = XEXP (addr, 1);
224
225 switch (GET_CODE (addr))
226 {
227 case REG:
228 /* REG+REG only works in SImode. */
229 return true;
230
231 case CONST_INT:
232 /* REG+INT is only mode independent if INT is a
233 multiple of 4, positive and will fit into 8-bits. */
234 if (((INTVAL (addr) & 3) == 0)
235 && IN_RANGE (INTVAL (addr), 4, 252))
236 return false;
237 return true;
238
239 case SYMBOL_REF:
240 case LABEL_REF:
241 return true;
242
243 case MULT:
244 gcc_assert (REG_P (XEXP (addr, 0)));
245 gcc_assert (CONST_INT_P (XEXP (addr, 1)));
246 /* REG+REG*SCALE is always mode dependent. */
247 return true;
248
249 default:
250 /* Not recognized, so treat as mode dependent. */
251 return true;
252 }
253
254 case CONST_INT:
255 case SYMBOL_REF:
256 case LABEL_REF:
257 case REG:
258 /* These are all mode independent. */
259 return false;
260
261 default:
262 /* Everything else is unrecognized,
263 so treat as mode dependent. */
264 return true;
265 }
266}
267\f
24833e1a 268/* A C compound statement to output to stdio stream FILE the
269 assembler syntax for an instruction operand that is a memory
270 reference whose address is ADDR. */
271
6bb30542 272static void
24833e1a 273rx_print_operand_address (FILE * file, rtx addr)
274{
275 switch (GET_CODE (addr))
276 {
277 case REG:
278 fprintf (file, "[");
279 rx_print_operand (file, addr, 0);
280 fprintf (file, "]");
281 break;
282
283 case PRE_DEC:
284 fprintf (file, "[-");
285 rx_print_operand (file, XEXP (addr, 0), 0);
286 fprintf (file, "]");
287 break;
288
289 case POST_INC:
290 fprintf (file, "[");
291 rx_print_operand (file, XEXP (addr, 0), 0);
292 fprintf (file, "+]");
293 break;
294
295 case PLUS:
296 {
297 rtx arg1 = XEXP (addr, 0);
298 rtx arg2 = XEXP (addr, 1);
299 rtx base, index;
300
301 if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, true))
302 base = arg1, index = arg2;
303 else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, true))
304 base = arg2, index = arg1;
305 else
306 {
307 rx_print_operand (file, arg1, 0);
308 fprintf (file, " + ");
309 rx_print_operand (file, arg2, 0);
310 break;
311 }
312
313 if (REG_P (index) || GET_CODE (index) == MULT)
314 {
315 fprintf (file, "[");
316 rx_print_operand (file, index, 'A');
317 fprintf (file, ",");
318 }
319 else /* GET_CODE (index) == CONST_INT */
320 {
321 rx_print_operand (file, index, 'A');
322 fprintf (file, "[");
323 }
324 rx_print_operand (file, base, 0);
325 fprintf (file, "]");
326 break;
327 }
328
95272799 329 case CONST:
330 if (GET_CODE (XEXP (addr, 0)) == UNSPEC)
331 {
332 addr = XEXP (addr, 0);
333 gcc_assert (XINT (addr, 1) == UNSPEC_CONST);
334
335 addr = XVECEXP (addr, 0, 0);
336 gcc_assert (CONST_INT_P (addr));
337 }
338 /* Fall through. */
24833e1a 339 case LABEL_REF:
340 case SYMBOL_REF:
24833e1a 341 fprintf (file, "#");
95272799 342
24833e1a 343 default:
344 output_addr_const (file, addr);
345 break;
346 }
347}
348
349static void
350rx_print_integer (FILE * file, HOST_WIDE_INT val)
351{
352 if (IN_RANGE (val, -64, 64))
353 fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
354 else
355 fprintf (file,
356 TARGET_AS100_SYNTAX
357 ? "0%" HOST_WIDE_INT_PRINT "xH" : HOST_WIDE_INT_PRINT_HEX,
358 val);
359}
360
361static bool
362rx_assemble_integer (rtx x, unsigned int size, int is_aligned)
363{
364 const char * op = integer_asm_op (size, is_aligned);
365
366 if (! CONST_INT_P (x))
367 return default_assemble_integer (x, size, is_aligned);
368
369 if (op == NULL)
370 return false;
371 fputs (op, asm_out_file);
372
373 rx_print_integer (asm_out_file, INTVAL (x));
374 fputc ('\n', asm_out_file);
375 return true;
376}
377
378
24833e1a 379/* Handles the insertion of a single operand into the assembler output.
380 The %<letter> directives supported are:
381
382 %A Print an operand without a leading # character.
383 %B Print an integer comparison name.
384 %C Print a control register name.
385 %F Print a condition code flag name.
386 %H Print high part of a DImode register, integer or address.
387 %L Print low part of a DImode register, integer or address.
6bb30542 388 %N Print the negation of the immediate value.
24833e1a 389 %Q If the operand is a MEM, then correctly generate
390 register indirect or register relative addressing. */
391
6bb30542 392static void
24833e1a 393rx_print_operand (FILE * file, rtx op, int letter)
394{
395 switch (letter)
396 {
397 case 'A':
398 /* Print an operand without a leading #. */
399 if (MEM_P (op))
400 op = XEXP (op, 0);
401
402 switch (GET_CODE (op))
403 {
404 case LABEL_REF:
405 case SYMBOL_REF:
406 output_addr_const (file, op);
407 break;
408 case CONST_INT:
409 fprintf (file, "%ld", (long) INTVAL (op));
410 break;
411 default:
412 rx_print_operand (file, op, 0);
413 break;
414 }
415 break;
416
417 case 'B':
ccfccd66 418 {
419 enum rtx_code code = GET_CODE (op);
420 enum machine_mode mode = GET_MODE (XEXP (op, 0));
421 const char *ret;
422
423 if (mode == CC_Fmode)
424 {
425 /* C flag is undefined, and O flag carries unordered. None of the
426 branch combinations that include O use it helpfully. */
427 switch (code)
428 {
429 case ORDERED:
430 ret = "no";
431 break;
432 case UNORDERED:
433 ret = "o";
434 break;
435 case LT:
436 ret = "n";
437 break;
438 case GE:
439 ret = "pz";
440 break;
441 case EQ:
442 ret = "eq";
443 break;
444 case NE:
445 ret = "ne";
446 break;
447 default:
448 gcc_unreachable ();
449 }
450 }
451 else
452 {
24ad6c43 453 unsigned int flags = flags_from_mode (mode);
ccfccd66 454 switch (code)
455 {
456 case LT:
24ad6c43 457 ret = (flags & CC_FLAG_O ? "lt" : "n");
ccfccd66 458 break;
459 case GE:
24ad6c43 460 ret = (flags & CC_FLAG_O ? "ge" : "pz");
ccfccd66 461 break;
462 case GT:
463 ret = "gt";
464 break;
465 case LE:
466 ret = "le";
467 break;
468 case GEU:
469 ret = "geu";
470 break;
471 case LTU:
472 ret = "ltu";
473 break;
474 case GTU:
475 ret = "gtu";
476 break;
477 case LEU:
478 ret = "leu";
479 break;
480 case EQ:
481 ret = "eq";
482 break;
483 case NE:
484 ret = "ne";
485 break;
486 default:
487 gcc_unreachable ();
488 }
24ad6c43 489 gcc_checking_assert ((flags_from_code (code) & ~flags) == 0);
ccfccd66 490 }
491 fputs (ret, file);
492 break;
493 }
24833e1a 494
495 case 'C':
496 gcc_assert (CONST_INT_P (op));
497 switch (INTVAL (op))
498 {
499 case 0: fprintf (file, "psw"); break;
500 case 2: fprintf (file, "usp"); break;
501 case 3: fprintf (file, "fpsw"); break;
502 case 4: fprintf (file, "cpen"); break;
503 case 8: fprintf (file, "bpsw"); break;
504 case 9: fprintf (file, "bpc"); break;
505 case 0xa: fprintf (file, "isp"); break;
506 case 0xb: fprintf (file, "fintv"); break;
507 case 0xc: fprintf (file, "intb"); break;
508 default:
98cb9b5b 509 warning (0, "unreocgnized control register number: %d - using 'psw'",
6bb30542 510 (int) INTVAL (op));
98cb9b5b 511 fprintf (file, "psw");
512 break;
24833e1a 513 }
514 break;
515
516 case 'F':
517 gcc_assert (CONST_INT_P (op));
518 switch (INTVAL (op))
519 {
520 case 0: case 'c': case 'C': fprintf (file, "C"); break;
521 case 1: case 'z': case 'Z': fprintf (file, "Z"); break;
522 case 2: case 's': case 'S': fprintf (file, "S"); break;
523 case 3: case 'o': case 'O': fprintf (file, "O"); break;
524 case 8: case 'i': case 'I': fprintf (file, "I"); break;
525 case 9: case 'u': case 'U': fprintf (file, "U"); break;
526 default:
527 gcc_unreachable ();
528 }
529 break;
530
531 case 'H':
6bb30542 532 switch (GET_CODE (op))
24833e1a 533 {
6bb30542 534 case REG:
535 fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 0 : 1)]);
536 break;
537 case CONST_INT:
538 {
539 HOST_WIDE_INT v = INTVAL (op);
67e66e16 540
6bb30542 541 fprintf (file, "#");
542 /* Trickery to avoid problems with shifting 32 bits at a time. */
543 v = v >> 16;
544 v = v >> 16;
545 rx_print_integer (file, v);
546 break;
547 }
548 case CONST_DOUBLE:
24833e1a 549 fprintf (file, "#");
6bb30542 550 rx_print_integer (file, CONST_DOUBLE_HIGH (op));
551 break;
552 case MEM:
24833e1a 553 if (! WORDS_BIG_ENDIAN)
554 op = adjust_address (op, SImode, 4);
555 output_address (XEXP (op, 0));
6bb30542 556 break;
557 default:
558 gcc_unreachable ();
24833e1a 559 }
560 break;
561
562 case 'L':
6bb30542 563 switch (GET_CODE (op))
24833e1a 564 {
6bb30542 565 case REG:
566 fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 1 : 0)]);
567 break;
568 case CONST_INT:
24833e1a 569 fprintf (file, "#");
570 rx_print_integer (file, INTVAL (op) & 0xffffffff);
6bb30542 571 break;
572 case CONST_DOUBLE:
573 fprintf (file, "#");
574 rx_print_integer (file, CONST_DOUBLE_LOW (op));
575 break;
576 case MEM:
24833e1a 577 if (WORDS_BIG_ENDIAN)
578 op = adjust_address (op, SImode, 4);
579 output_address (XEXP (op, 0));
6bb30542 580 break;
581 default:
582 gcc_unreachable ();
24833e1a 583 }
584 break;
585
39349585 586 case 'N':
587 gcc_assert (CONST_INT_P (op));
588 fprintf (file, "#");
589 rx_print_integer (file, - INTVAL (op));
590 break;
591
24833e1a 592 case 'Q':
593 if (MEM_P (op))
594 {
595 HOST_WIDE_INT offset;
596
597 op = XEXP (op, 0);
598
599 if (REG_P (op))
600 offset = 0;
601 else if (GET_CODE (op) == PLUS)
602 {
603 rtx displacement;
604
605 if (REG_P (XEXP (op, 0)))
606 {
607 displacement = XEXP (op, 1);
608 op = XEXP (op, 0);
609 }
610 else
611 {
612 displacement = XEXP (op, 0);
613 op = XEXP (op, 1);
614 gcc_assert (REG_P (op));
615 }
616
617 gcc_assert (CONST_INT_P (displacement));
618 offset = INTVAL (displacement);
619 gcc_assert (offset >= 0);
620
621 fprintf (file, "%ld", offset);
622 }
623 else
624 gcc_unreachable ();
625
626 fprintf (file, "[");
627 rx_print_operand (file, op, 0);
628 fprintf (file, "].");
629
630 switch (GET_MODE_SIZE (GET_MODE (op)))
631 {
632 case 1:
633 gcc_assert (offset < 65535 * 1);
634 fprintf (file, "B");
635 break;
636 case 2:
637 gcc_assert (offset % 2 == 0);
638 gcc_assert (offset < 65535 * 2);
639 fprintf (file, "W");
640 break;
641 default:
642 gcc_assert (offset % 4 == 0);
643 gcc_assert (offset < 65535 * 4);
644 fprintf (file, "L");
645 break;
646 }
647 break;
648 }
649
650 /* Fall through. */
651
652 default:
653 switch (GET_CODE (op))
654 {
655 case MULT:
656 /* Should be the scaled part of an
657 indexed register indirect address. */
658 {
659 rtx base = XEXP (op, 0);
660 rtx index = XEXP (op, 1);
661
662 /* Check for a swaped index register and scaling factor.
663 Not sure if this can happen, but be prepared to handle it. */
664 if (CONST_INT_P (base) && REG_P (index))
665 {
666 rtx tmp = base;
667 base = index;
668 index = tmp;
669 }
670
671 gcc_assert (REG_P (base));
672 gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER);
673 gcc_assert (CONST_INT_P (index));
674 /* Do not try to verify the value of the scalar as it is based
675 on the mode of the MEM not the mode of the MULT. (Which
676 will always be SImode). */
677 fprintf (file, "%s", reg_names [REGNO (base)]);
678 break;
679 }
680
681 case MEM:
682 output_address (XEXP (op, 0));
683 break;
684
685 case PLUS:
686 output_address (op);
687 break;
688
689 case REG:
690 gcc_assert (REGNO (op) < FIRST_PSEUDO_REGISTER);
691 fprintf (file, "%s", reg_names [REGNO (op)]);
692 break;
693
694 case SUBREG:
695 gcc_assert (subreg_regno (op) < FIRST_PSEUDO_REGISTER);
696 fprintf (file, "%s", reg_names [subreg_regno (op)]);
697 break;
698
699 /* This will only be single precision.... */
700 case CONST_DOUBLE:
701 {
702 unsigned long val;
703 REAL_VALUE_TYPE rv;
704
705 REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
706 REAL_VALUE_TO_TARGET_SINGLE (rv, val);
707 fprintf (file, TARGET_AS100_SYNTAX ? "#0%lxH" : "#0x%lx", val);
708 break;
709 }
710
711 case CONST_INT:
712 fprintf (file, "#");
713 rx_print_integer (file, INTVAL (op));
714 break;
715
716 case SYMBOL_REF:
717 case CONST:
718 case LABEL_REF:
719 case CODE_LABEL:
720 case UNSPEC:
721 rx_print_operand_address (file, op);
722 break;
723
724 default:
725 gcc_unreachable ();
726 }
727 break;
728 }
729}
730
731/* Returns an assembler template for a move instruction. */
732
733char *
734rx_gen_move_template (rtx * operands, bool is_movu)
735{
6bb30542 736 static char out_template [64];
24833e1a 737 const char * extension = TARGET_AS100_SYNTAX ? ".L" : "";
738 const char * src_template;
739 const char * dst_template;
740 rtx dest = operands[0];
741 rtx src = operands[1];
742
743 /* Decide which extension, if any, should be given to the move instruction. */
744 switch (CONST_INT_P (src) ? GET_MODE (dest) : GET_MODE (src))
745 {
746 case QImode:
747 /* The .B extension is not valid when
748 loading an immediate into a register. */
749 if (! REG_P (dest) || ! CONST_INT_P (src))
750 extension = ".B";
751 break;
752 case HImode:
753 if (! REG_P (dest) || ! CONST_INT_P (src))
754 /* The .W extension is not valid when
755 loading an immediate into a register. */
756 extension = ".W";
757 break;
758 case SFmode:
759 case SImode:
760 extension = ".L";
761 break;
762 case VOIDmode:
763 /* This mode is used by constants. */
764 break;
765 default:
766 debug_rtx (src);
767 gcc_unreachable ();
768 }
769
770 if (MEM_P (src) && rx_small_data_operand (XEXP (src, 0)))
771 src_template = "%%gp(%A1)[r13]";
772 else
773 src_template = "%1";
774
775 if (MEM_P (dest) && rx_small_data_operand (XEXP (dest, 0)))
776 dst_template = "%%gp(%A0)[r13]";
777 else
778 dst_template = "%0";
779
6bb30542 780 sprintf (out_template, "%s%s\t%s, %s", is_movu ? "movu" : "mov",
24833e1a 781 extension, src_template, dst_template);
6bb30542 782 return out_template;
24833e1a 783}
24833e1a 784\f
785/* Return VALUE rounded up to the next ALIGNMENT boundary. */
786
787static inline unsigned int
788rx_round_up (unsigned int value, unsigned int alignment)
789{
790 alignment -= 1;
791 return (value + alignment) & (~ alignment);
792}
793
794/* Return the number of bytes in the argument registers
795 occupied by an argument of type TYPE and mode MODE. */
796
ee4e8428 797static unsigned int
24833e1a 798rx_function_arg_size (Mmode mode, const_tree type)
799{
800 unsigned int num_bytes;
801
802 num_bytes = (mode == BLKmode)
803 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
804 return rx_round_up (num_bytes, UNITS_PER_WORD);
805}
806
807#define NUM_ARG_REGS 4
808#define MAX_NUM_ARG_BYTES (NUM_ARG_REGS * UNITS_PER_WORD)
809
810/* Return an RTL expression describing the register holding a function
811 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
812 be passed on the stack. CUM describes the previous parameters to the
813 function and NAMED is false if the parameter is part of a variable
814 parameter list, or the last named parameter before the start of a
815 variable parameter list. */
816
ee4e8428 817static rtx
24833e1a 818rx_function_arg (Fargs * cum, Mmode mode, const_tree type, bool named)
819{
820 unsigned int next_reg;
821 unsigned int bytes_so_far = *cum;
822 unsigned int size;
823 unsigned int rounded_size;
824
825 /* An exploded version of rx_function_arg_size. */
826 size = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
6bb30542 827 /* If the size is not known it cannot be passed in registers. */
828 if (size < 1)
829 return NULL_RTX;
24833e1a 830
831 rounded_size = rx_round_up (size, UNITS_PER_WORD);
832
833 /* Don't pass this arg via registers if there
834 are insufficient registers to hold all of it. */
835 if (rounded_size + bytes_so_far > MAX_NUM_ARG_BYTES)
836 return NULL_RTX;
837
838 /* Unnamed arguments and the last named argument in a
839 variadic function are always passed on the stack. */
840 if (!named)
841 return NULL_RTX;
842
843 /* Structures must occupy an exact number of registers,
844 otherwise they are passed on the stack. */
845 if ((type == NULL || AGGREGATE_TYPE_P (type))
846 && (size % UNITS_PER_WORD) != 0)
847 return NULL_RTX;
848
849 next_reg = (bytes_so_far / UNITS_PER_WORD) + 1;
850
851 return gen_rtx_REG (mode, next_reg);
852}
853
ee4e8428 854static void
855rx_function_arg_advance (Fargs * cum, Mmode mode, const_tree type,
856 bool named ATTRIBUTE_UNUSED)
857{
858 *cum += rx_function_arg_size (mode, type);
859}
860
bd99ba64 861static unsigned int
862rx_function_arg_boundary (Mmode mode ATTRIBUTE_UNUSED,
863 const_tree type ATTRIBUTE_UNUSED)
864{
865 return 32;
866}
867
24833e1a 868/* Return an RTL describing where a function return value of type RET_TYPE
869 is held. */
870
871static rtx
872rx_function_value (const_tree ret_type,
873 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
874 bool outgoing ATTRIBUTE_UNUSED)
875{
bd7d2835 876 enum machine_mode mode = TYPE_MODE (ret_type);
877
878 /* RX ABI specifies that small integer types are
879 promoted to int when returned by a function. */
02f06d23 880 if (GET_MODE_SIZE (mode) > 0
881 && GET_MODE_SIZE (mode) < 4
882 && ! COMPLEX_MODE_P (mode)
883 )
bd7d2835 884 return gen_rtx_REG (SImode, FUNC_RETURN_REGNUM);
885
886 return gen_rtx_REG (mode, FUNC_RETURN_REGNUM);
887}
888
889/* TARGET_PROMOTE_FUNCTION_MODE must behave in the same way with
890 regard to function returns as does TARGET_FUNCTION_VALUE. */
891
892static enum machine_mode
893rx_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
894 enum machine_mode mode,
0318c61a 895 int * punsignedp ATTRIBUTE_UNUSED,
bd7d2835 896 const_tree funtype ATTRIBUTE_UNUSED,
897 int for_return)
898{
899 if (for_return != 1
900 || GET_MODE_SIZE (mode) >= 4
02f06d23 901 || COMPLEX_MODE_P (mode)
bd7d2835 902 || GET_MODE_SIZE (mode) < 1)
903 return mode;
904
905 return SImode;
24833e1a 906}
907
908static bool
909rx_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
910{
911 HOST_WIDE_INT size;
912
913 if (TYPE_MODE (type) != BLKmode
914 && ! AGGREGATE_TYPE_P (type))
915 return false;
916
917 size = int_size_in_bytes (type);
918 /* Large structs and those whose size is not an
919 exact multiple of 4 are returned in memory. */
920 return size < 1
921 || size > 16
922 || (size % UNITS_PER_WORD) != 0;
923}
924
925static rtx
926rx_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED,
927 int incoming ATTRIBUTE_UNUSED)
928{
929 return gen_rtx_REG (Pmode, STRUCT_VAL_REGNUM);
930}
931
932static bool
933rx_return_in_msb (const_tree valtype)
934{
935 return TARGET_BIG_ENDIAN_DATA
936 && (AGGREGATE_TYPE_P (valtype) || TREE_CODE (valtype) == COMPLEX_TYPE);
937}
938
939/* Returns true if the provided function has the specified attribute. */
940
941static inline bool
942has_func_attr (const_tree decl, const char * func_attr)
943{
944 if (decl == NULL_TREE)
945 decl = current_function_decl;
946
947 return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
948}
949
67e66e16 950/* Returns true if the provided function has the "fast_interrupt" attribute. */
24833e1a 951
952static inline bool
953is_fast_interrupt_func (const_tree decl)
954{
67e66e16 955 return has_func_attr (decl, "fast_interrupt");
24833e1a 956}
957
67e66e16 958/* Returns true if the provided function has the "interrupt" attribute. */
24833e1a 959
960static inline bool
67e66e16 961is_interrupt_func (const_tree decl)
24833e1a 962{
67e66e16 963 return has_func_attr (decl, "interrupt");
24833e1a 964}
965
966/* Returns true if the provided function has the "naked" attribute. */
967
968static inline bool
969is_naked_func (const_tree decl)
970{
971 return has_func_attr (decl, "naked");
972}
973\f
974static bool use_fixed_regs = false;
975
b2d7ede1 976static void
24833e1a 977rx_conditional_register_usage (void)
978{
979 static bool using_fixed_regs = false;
980
981 if (rx_small_data_limit > 0)
982 fixed_regs[GP_BASE_REGNUM] = call_used_regs [GP_BASE_REGNUM] = 1;
983
984 if (use_fixed_regs != using_fixed_regs)
985 {
986 static char saved_fixed_regs[FIRST_PSEUDO_REGISTER];
987 static char saved_call_used_regs[FIRST_PSEUDO_REGISTER];
988
989 if (use_fixed_regs)
990 {
24833e1a 991 unsigned int r;
992
24833e1a 993 memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs);
994 memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs);
e4d9e8e5 995
996 /* This is for fast interrupt handlers. Any register in
997 the range r10 to r13 (inclusive) that is currently
998 marked as fixed is now a viable, call-used register. */
24833e1a 999 for (r = 10; r <= 13; r++)
1000 if (fixed_regs[r])
1001 {
1002 fixed_regs[r] = 0;
1003 call_used_regs[r] = 1;
24833e1a 1004 }
1005
e4d9e8e5 1006 /* Mark r7 as fixed. This is just a hack to avoid
1007 altering the reg_alloc_order array so that the newly
1008 freed r10-r13 registers are the preferred registers. */
1009 fixed_regs[7] = call_used_regs[7] = 1;
24833e1a 1010 }
1011 else
1012 {
1013 /* Restore the normal register masks. */
1014 memcpy (fixed_regs, saved_fixed_regs, sizeof fixed_regs);
1015 memcpy (call_used_regs, saved_call_used_regs, sizeof call_used_regs);
1016 }
1017
1018 using_fixed_regs = use_fixed_regs;
1019 }
1020}
1021
1022/* Perform any actions necessary before starting to compile FNDECL.
1023 For the RX we use this to make sure that we have the correct
1024 set of register masks selected. If FNDECL is NULL then we are
1025 compiling top level things. */
1026
1027static void
1028rx_set_current_function (tree fndecl)
1029{
1030 /* Remember the last target of rx_set_current_function. */
1031 static tree rx_previous_fndecl;
67e66e16 1032 bool prev_was_fast_interrupt;
1033 bool current_is_fast_interrupt;
24833e1a 1034
1035 /* Only change the context if the function changes. This hook is called
1036 several times in the course of compiling a function, and we don't want
1037 to slow things down too much or call target_reinit when it isn't safe. */
1038 if (fndecl == rx_previous_fndecl)
1039 return;
1040
67e66e16 1041 prev_was_fast_interrupt
24833e1a 1042 = rx_previous_fndecl
1043 ? is_fast_interrupt_func (rx_previous_fndecl) : false;
67e66e16 1044
1045 current_is_fast_interrupt
24833e1a 1046 = fndecl ? is_fast_interrupt_func (fndecl) : false;
1047
67e66e16 1048 if (prev_was_fast_interrupt != current_is_fast_interrupt)
24833e1a 1049 {
67e66e16 1050 use_fixed_regs = current_is_fast_interrupt;
24833e1a 1051 target_reinit ();
1052 }
67e66e16 1053
24833e1a 1054 rx_previous_fndecl = fndecl;
1055}
1056\f
1057/* Typical stack layout should looks like this after the function's prologue:
1058
1059 | |
1060 -- ^
1061 | | \ |
1062 | | arguments saved | Increasing
1063 | | on the stack | addresses
1064 PARENT arg pointer -> | | /
1065 -------------------------- ---- -------------------
1066 CHILD |ret | return address
1067 --
1068 | | \
1069 | | call saved
1070 | | registers
1071 | | /
1072 --
1073 | | \
1074 | | local
1075 | | variables
1076 frame pointer -> | | /
1077 --
1078 | | \
1079 | | outgoing | Decreasing
1080 | | arguments | addresses
1081 current stack pointer -> | | / |
1082 -------------------------- ---- ------------------ V
1083 | | */
1084
1085static unsigned int
1086bit_count (unsigned int x)
1087{
1088 const unsigned int m1 = 0x55555555;
1089 const unsigned int m2 = 0x33333333;
1090 const unsigned int m4 = 0x0f0f0f0f;
1091
1092 x -= (x >> 1) & m1;
1093 x = (x & m2) + ((x >> 2) & m2);
1094 x = (x + (x >> 4)) & m4;
1095 x += x >> 8;
1096
1097 return (x + (x >> 16)) & 0x3f;
1098}
1099
e4d9e8e5 1100#define MUST_SAVE_ACC_REGISTER \
1101 (TARGET_SAVE_ACC_REGISTER \
1102 && (is_interrupt_func (NULL_TREE) \
1103 || is_fast_interrupt_func (NULL_TREE)))
1104
24833e1a 1105/* Returns either the lowest numbered and highest numbered registers that
1106 occupy the call-saved area of the stack frame, if the registers are
1107 stored as a contiguous block, or else a bitmask of the individual
1108 registers if they are stored piecemeal.
1109
1110 Also computes the size of the frame and the size of the outgoing
1111 arguments block (in bytes). */
1112
1113static void
1114rx_get_stack_layout (unsigned int * lowest,
1115 unsigned int * highest,
1116 unsigned int * register_mask,
1117 unsigned int * frame_size,
1118 unsigned int * stack_size)
1119{
1120 unsigned int reg;
1121 unsigned int low;
1122 unsigned int high;
1123 unsigned int fixed_reg = 0;
1124 unsigned int save_mask;
1125 unsigned int pushed_mask;
1126 unsigned int unneeded_pushes;
1127
e4d9e8e5 1128 if (is_naked_func (NULL_TREE))
24833e1a 1129 {
1130 /* Naked functions do not create their own stack frame.
e4d9e8e5 1131 Instead the programmer must do that for us. */
24833e1a 1132 * lowest = 0;
1133 * highest = 0;
1134 * register_mask = 0;
1135 * frame_size = 0;
1136 * stack_size = 0;
1137 return;
1138 }
1139
9d2f1b03 1140 for (save_mask = high = low = 0, reg = 1; reg < CC_REGNUM; reg++)
24833e1a 1141 {
21cde6ec 1142 if ((df_regs_ever_live_p (reg)
382ffb70 1143 /* Always save all call clobbered registers inside non-leaf
1144 interrupt handlers, even if they are not live - they may
1145 be used in (non-interrupt aware) routines called from this one. */
1146 || (call_used_regs[reg]
1147 && is_interrupt_func (NULL_TREE)
1148 && ! current_function_is_leaf))
24833e1a 1149 && (! call_used_regs[reg]
1150 /* Even call clobbered registered must
67e66e16 1151 be pushed inside interrupt handlers. */
e4d9e8e5 1152 || is_interrupt_func (NULL_TREE)
1153 /* Likewise for fast interrupt handlers, except registers r10 -
1154 r13. These are normally call-saved, but may have been set
1155 to call-used by rx_conditional_register_usage. If so then
1156 they can be used in the fast interrupt handler without
1157 saving them on the stack. */
1158 || (is_fast_interrupt_func (NULL_TREE)
1159 && ! IN_RANGE (reg, 10, 13))))
24833e1a 1160 {
1161 if (low == 0)
1162 low = reg;
1163 high = reg;
1164
1165 save_mask |= 1 << reg;
1166 }
1167
1168 /* Remember if we see a fixed register
1169 after having found the low register. */
1170 if (low != 0 && fixed_reg == 0 && fixed_regs [reg])
1171 fixed_reg = reg;
1172 }
1173
e4d9e8e5 1174 /* If we have to save the accumulator register, make sure
1175 that at least two registers are pushed into the frame. */
1176 if (MUST_SAVE_ACC_REGISTER
1177 && bit_count (save_mask) < 2)
1178 {
1179 save_mask |= (1 << 13) | (1 << 14);
1180 if (low == 0)
1181 low = 13;
bc9bb967 1182 if (high == 0 || low == high)
1183 high = low + 1;
e4d9e8e5 1184 }
1185
24833e1a 1186 /* Decide if it would be faster fill in the call-saved area of the stack
1187 frame using multiple PUSH instructions instead of a single PUSHM
1188 instruction.
1189
1190 SAVE_MASK is a bitmask of the registers that must be stored in the
1191 call-save area. PUSHED_MASK is a bitmask of the registers that would
1192 be pushed into the area if we used a PUSHM instruction. UNNEEDED_PUSHES
1193 is a bitmask of those registers in pushed_mask that are not in
1194 save_mask.
1195
1196 We use a simple heuristic that says that it is better to use
1197 multiple PUSH instructions if the number of unnecessary pushes is
1198 greater than the number of necessary pushes.
1199
1200 We also use multiple PUSH instructions if there are any fixed registers
1201 between LOW and HIGH. The only way that this can happen is if the user
1202 has specified --fixed-<reg-name> on the command line and in such
1203 circumstances we do not want to touch the fixed registers at all.
1204
1205 FIXME: Is it worth improving this heuristic ? */
1206 pushed_mask = (-1 << low) & ~(-1 << (high + 1));
1207 unneeded_pushes = (pushed_mask & (~ save_mask)) & pushed_mask;
1208
1209 if ((fixed_reg && fixed_reg <= high)
1210 || (optimize_function_for_speed_p (cfun)
1211 && bit_count (save_mask) < bit_count (unneeded_pushes)))
1212 {
1213 /* Use multiple pushes. */
1214 * lowest = 0;
1215 * highest = 0;
1216 * register_mask = save_mask;
1217 }
1218 else
1219 {
1220 /* Use one push multiple instruction. */
1221 * lowest = low;
1222 * highest = high;
1223 * register_mask = 0;
1224 }
1225
1226 * frame_size = rx_round_up
1227 (get_frame_size (), STACK_BOUNDARY / BITS_PER_UNIT);
1228
1229 if (crtl->args.size > 0)
1230 * frame_size += rx_round_up
1231 (crtl->args.size, STACK_BOUNDARY / BITS_PER_UNIT);
1232
1233 * stack_size = rx_round_up
1234 (crtl->outgoing_args_size, STACK_BOUNDARY / BITS_PER_UNIT);
1235}
1236
1237/* Generate a PUSHM instruction that matches the given operands. */
1238
1239void
1240rx_emit_stack_pushm (rtx * operands)
1241{
1242 HOST_WIDE_INT last_reg;
1243 rtx first_push;
1244
1245 gcc_assert (CONST_INT_P (operands[0]));
1246 last_reg = (INTVAL (operands[0]) / UNITS_PER_WORD) - 1;
1247
1248 gcc_assert (GET_CODE (operands[1]) == PARALLEL);
1249 first_push = XVECEXP (operands[1], 0, 1);
1250 gcc_assert (SET_P (first_push));
1251 first_push = SET_SRC (first_push);
1252 gcc_assert (REG_P (first_push));
1253
1254 asm_fprintf (asm_out_file, "\tpushm\t%s-%s\n",
67e66e16 1255 reg_names [REGNO (first_push) - last_reg],
1256 reg_names [REGNO (first_push)]);
24833e1a 1257}
1258
1259/* Generate a PARALLEL that will pass the rx_store_multiple_vector predicate. */
1260
1261static rtx
1262gen_rx_store_vector (unsigned int low, unsigned int high)
1263{
1264 unsigned int i;
1265 unsigned int count = (high - low) + 2;
1266 rtx vector;
1267
1268 vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
1269
1270 XVECEXP (vector, 0, 0) =
51e241f8 1271 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
24833e1a 1272 gen_rtx_MINUS (SImode, stack_pointer_rtx,
1273 GEN_INT ((count - 1) * UNITS_PER_WORD)));
1274
1275 for (i = 0; i < count - 1; i++)
1276 XVECEXP (vector, 0, i + 1) =
51e241f8 1277 gen_rtx_SET (VOIDmode,
24833e1a 1278 gen_rtx_MEM (SImode,
67e66e16 1279 gen_rtx_MINUS (SImode, stack_pointer_rtx,
1280 GEN_INT ((i + 1) * UNITS_PER_WORD))),
1281 gen_rtx_REG (SImode, high - i));
24833e1a 1282 return vector;
1283}
1284
67e66e16 1285/* Mark INSN as being frame related. If it is a PARALLEL
1286 then mark each element as being frame related as well. */
1287
1288static void
1289mark_frame_related (rtx insn)
1290{
1291 RTX_FRAME_RELATED_P (insn) = 1;
1292 insn = PATTERN (insn);
1293
1294 if (GET_CODE (insn) == PARALLEL)
1295 {
1296 unsigned int i;
1297
61fc50a0 1298 for (i = 0; i < (unsigned) XVECLEN (insn, 0); i++)
67e66e16 1299 RTX_FRAME_RELATED_P (XVECEXP (insn, 0, i)) = 1;
1300 }
1301}
1302
95272799 1303static bool
1304ok_for_max_constant (HOST_WIDE_INT val)
1305{
1306 if (rx_max_constant_size == 0 || rx_max_constant_size == 4)
1307 /* If there is no constraint on the size of constants
1308 used as operands, then any value is legitimate. */
1309 return true;
1310
1311 /* rx_max_constant_size specifies the maximum number
1312 of bytes that can be used to hold a signed value. */
1313 return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)),
1314 ( 1 << (rx_max_constant_size * 8)));
1315}
1316
1317/* Generate an ADD of SRC plus VAL into DEST.
1318 Handles the case where VAL is too big for max_constant_value.
1319 Sets FRAME_RELATED_P on the insn if IS_FRAME_RELATED is true. */
1320
1321static void
1322gen_safe_add (rtx dest, rtx src, rtx val, bool is_frame_related)
1323{
1324 rtx insn;
1325
1326 if (val == NULL_RTX || INTVAL (val) == 0)
1327 {
1328 gcc_assert (dest != src);
1329
1330 insn = emit_move_insn (dest, src);
1331 }
1332 else if (ok_for_max_constant (INTVAL (val)))
1333 insn = emit_insn (gen_addsi3 (dest, src, val));
1334 else
1335 {
02f06d23 1336 /* Wrap VAL in an UNSPEC so that rx_is_legitimate_constant
1337 will not reject it. */
1338 val = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, gen_rtvec (1, val), UNSPEC_CONST));
1339 insn = emit_insn (gen_addsi3 (dest, src, val));
95272799 1340
1341 if (is_frame_related)
1342 /* We have to provide our own frame related note here
1343 as the dwarf2out code cannot be expected to grok
1344 our unspec. */
1345 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
1346 gen_rtx_SET (SImode, dest,
1347 gen_rtx_PLUS (SImode, src, val)));
1348 return;
1349 }
1350
1351 if (is_frame_related)
1352 RTX_FRAME_RELATED_P (insn) = 1;
1353 return;
1354}
1355
24833e1a 1356void
1357rx_expand_prologue (void)
1358{
1359 unsigned int stack_size;
1360 unsigned int frame_size;
1361 unsigned int mask;
1362 unsigned int low;
1363 unsigned int high;
67e66e16 1364 unsigned int reg;
24833e1a 1365 rtx insn;
1366
1367 /* Naked functions use their own, programmer provided prologues. */
e4d9e8e5 1368 if (is_naked_func (NULL_TREE))
24833e1a 1369 return;
1370
1371 rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size);
1372
1373 /* If we use any of the callee-saved registers, save them now. */
1374 if (mask)
1375 {
24833e1a 1376 /* Push registers in reverse order. */
9d2f1b03 1377 for (reg = CC_REGNUM; reg --;)
24833e1a 1378 if (mask & (1 << reg))
1379 {
1380 insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, reg)));
67e66e16 1381 mark_frame_related (insn);
24833e1a 1382 }
1383 }
1384 else if (low)
1385 {
1386 if (high == low)
1387 insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, low)));
1388 else
1389 insn = emit_insn (gen_stack_pushm (GEN_INT (((high - low) + 1)
1390 * UNITS_PER_WORD),
1391 gen_rx_store_vector (low, high)));
67e66e16 1392 mark_frame_related (insn);
1393 }
1394
e4d9e8e5 1395 if (MUST_SAVE_ACC_REGISTER)
67e66e16 1396 {
1397 unsigned int acc_high, acc_low;
1398
1399 /* Interrupt handlers have to preserve the accumulator
1400 register if so requested by the user. Use the first
e4d9e8e5 1401 two pushed registers as intermediaries. */
67e66e16 1402 if (mask)
1403 {
1404 acc_low = acc_high = 0;
1405
9d2f1b03 1406 for (reg = 1; reg < CC_REGNUM; reg ++)
67e66e16 1407 if (mask & (1 << reg))
1408 {
1409 if (acc_low == 0)
1410 acc_low = reg;
1411 else
1412 {
1413 acc_high = reg;
1414 break;
1415 }
1416 }
1417
1418 /* We have assumed that there are at least two registers pushed... */
1419 gcc_assert (acc_high != 0);
1420
1421 /* Note - the bottom 16 bits of the accumulator are inaccessible.
1422 We just assume that they are zero. */
1423 emit_insn (gen_mvfacmi (gen_rtx_REG (SImode, acc_low)));
1424 emit_insn (gen_mvfachi (gen_rtx_REG (SImode, acc_high)));
1425 emit_insn (gen_stack_push (gen_rtx_REG (SImode, acc_low)));
1426 emit_insn (gen_stack_push (gen_rtx_REG (SImode, acc_high)));
1427 }
1428 else
1429 {
1430 acc_low = low;
1431 acc_high = low + 1;
1432
1433 /* We have assumed that there are at least two registers pushed... */
1434 gcc_assert (acc_high <= high);
1435
1436 emit_insn (gen_mvfacmi (gen_rtx_REG (SImode, acc_low)));
1437 emit_insn (gen_mvfachi (gen_rtx_REG (SImode, acc_high)));
1438 emit_insn (gen_stack_pushm (GEN_INT (2 * UNITS_PER_WORD),
1439 gen_rx_store_vector (acc_low, acc_high)));
1440 }
24833e1a 1441 }
1442
1443 /* If needed, set up the frame pointer. */
1444 if (frame_pointer_needed)
95272799 1445 gen_safe_add (frame_pointer_rtx, stack_pointer_rtx,
1446 GEN_INT (- (HOST_WIDE_INT) frame_size), true);
24833e1a 1447
1448 /* Allocate space for the outgoing args.
1449 If the stack frame has not already been set up then handle this as well. */
1450 if (stack_size)
1451 {
1452 if (frame_size)
1453 {
1454 if (frame_pointer_needed)
95272799 1455 gen_safe_add (stack_pointer_rtx, frame_pointer_rtx,
1456 GEN_INT (- (HOST_WIDE_INT) stack_size), true);
24833e1a 1457 else
95272799 1458 gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
1459 GEN_INT (- (HOST_WIDE_INT) (frame_size + stack_size)),
1460 true);
24833e1a 1461 }
1462 else
95272799 1463 gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
1464 GEN_INT (- (HOST_WIDE_INT) stack_size), true);
24833e1a 1465 }
1466 else if (frame_size)
1467 {
1468 if (! frame_pointer_needed)
95272799 1469 gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
1470 GEN_INT (- (HOST_WIDE_INT) frame_size), true);
24833e1a 1471 else
95272799 1472 gen_safe_add (stack_pointer_rtx, frame_pointer_rtx, NULL_RTX,
1473 true);
24833e1a 1474 }
24833e1a 1475}
1476
1477static void
1478rx_output_function_prologue (FILE * file,
1479 HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
1480{
1481 if (is_fast_interrupt_func (NULL_TREE))
1482 asm_fprintf (file, "\t; Note: Fast Interrupt Handler\n");
1483
67e66e16 1484 if (is_interrupt_func (NULL_TREE))
1485 asm_fprintf (file, "\t; Note: Interrupt Handler\n");
24833e1a 1486
1487 if (is_naked_func (NULL_TREE))
1488 asm_fprintf (file, "\t; Note: Naked Function\n");
1489
1490 if (cfun->static_chain_decl != NULL)
1491 asm_fprintf (file, "\t; Note: Nested function declared "
1492 "inside another function.\n");
1493
1494 if (crtl->calls_eh_return)
1495 asm_fprintf (file, "\t; Note: Calls __builtin_eh_return.\n");
1496}
1497
1498/* Generate a POPM or RTSD instruction that matches the given operands. */
1499
1500void
1501rx_emit_stack_popm (rtx * operands, bool is_popm)
1502{
1503 HOST_WIDE_INT stack_adjust;
1504 HOST_WIDE_INT last_reg;
1505 rtx first_push;
1506
1507 gcc_assert (CONST_INT_P (operands[0]));
1508 stack_adjust = INTVAL (operands[0]);
1509
1510 gcc_assert (GET_CODE (operands[1]) == PARALLEL);
1511 last_reg = XVECLEN (operands[1], 0) - (is_popm ? 2 : 3);
1512
1513 first_push = XVECEXP (operands[1], 0, 1);
1514 gcc_assert (SET_P (first_push));
1515 first_push = SET_DEST (first_push);
1516 gcc_assert (REG_P (first_push));
1517
1518 if (is_popm)
1519 asm_fprintf (asm_out_file, "\tpopm\t%s-%s\n",
1520 reg_names [REGNO (first_push)],
1521 reg_names [REGNO (first_push) + last_reg]);
1522 else
1523 asm_fprintf (asm_out_file, "\trtsd\t#%d, %s-%s\n",
1524 (int) stack_adjust,
1525 reg_names [REGNO (first_push)],
1526 reg_names [REGNO (first_push) + last_reg]);
1527}
1528
1529/* Generate a PARALLEL which will satisfy the rx_rtsd_vector predicate. */
1530
1531static rtx
1532gen_rx_rtsd_vector (unsigned int adjust, unsigned int low, unsigned int high)
1533{
1534 unsigned int i;
1535 unsigned int bias = 3;
1536 unsigned int count = (high - low) + bias;
1537 rtx vector;
1538
1539 vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
1540
1541 XVECEXP (vector, 0, 0) =
51e241f8 1542 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
24833e1a 1543 plus_constant (stack_pointer_rtx, adjust));
1544
1545 for (i = 0; i < count - 2; i++)
1546 XVECEXP (vector, 0, i + 1) =
51e241f8 1547 gen_rtx_SET (VOIDmode,
24833e1a 1548 gen_rtx_REG (SImode, low + i),
1549 gen_rtx_MEM (SImode,
1550 i == 0 ? stack_pointer_rtx
1551 : plus_constant (stack_pointer_rtx,
1552 i * UNITS_PER_WORD)));
1553
1554 XVECEXP (vector, 0, count - 1) = gen_rtx_RETURN (VOIDmode);
1555
1556 return vector;
1557}
1558
1559/* Generate a PARALLEL which will satisfy the rx_load_multiple_vector predicate. */
1560
1561static rtx
1562gen_rx_popm_vector (unsigned int low, unsigned int high)
1563{
1564 unsigned int i;
1565 unsigned int count = (high - low) + 2;
1566 rtx vector;
1567
1568 vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
1569
1570 XVECEXP (vector, 0, 0) =
51e241f8 1571 gen_rtx_SET (VOIDmode, stack_pointer_rtx,
24833e1a 1572 plus_constant (stack_pointer_rtx,
1573 (count - 1) * UNITS_PER_WORD));
1574
1575 for (i = 0; i < count - 1; i++)
1576 XVECEXP (vector, 0, i + 1) =
51e241f8 1577 gen_rtx_SET (VOIDmode,
24833e1a 1578 gen_rtx_REG (SImode, low + i),
1579 gen_rtx_MEM (SImode,
1580 i == 0 ? stack_pointer_rtx
1581 : plus_constant (stack_pointer_rtx,
1582 i * UNITS_PER_WORD)));
1583
1584 return vector;
1585}
1586
1587void
1588rx_expand_epilogue (bool is_sibcall)
1589{
1590 unsigned int low;
1591 unsigned int high;
1592 unsigned int frame_size;
1593 unsigned int stack_size;
1594 unsigned int register_mask;
1595 unsigned int regs_size;
67e66e16 1596 unsigned int reg;
24833e1a 1597 unsigned HOST_WIDE_INT total_size;
1598
61fc50a0 1599 /* FIXME: We do not support indirect sibcalls at the moment becaause we
1600 cannot guarantee that the register holding the function address is a
1601 call-used register. If it is a call-saved register then the stack
1602 pop instructions generated in the epilogue will corrupt the address
1603 before it is used.
1604
1605 Creating a new call-used-only register class works but then the
1606 reload pass gets stuck because it cannot always find a call-used
1607 register for spilling sibcalls.
1608
1609 The other possible solution is for this pass to scan forward for the
1610 sibcall instruction (if it has been generated) and work out if it
1611 is an indirect sibcall using a call-saved register. If it is then
1612 the address can copied into a call-used register in this epilogue
1613 code and the sibcall instruction modified to use that register. */
1614
24833e1a 1615 if (is_naked_func (NULL_TREE))
1616 {
61fc50a0 1617 gcc_assert (! is_sibcall);
1618
24833e1a 1619 /* Naked functions use their own, programmer provided epilogues.
1620 But, in order to keep gcc happy we have to generate some kind of
1621 epilogue RTL. */
1622 emit_jump_insn (gen_naked_return ());
1623 return;
1624 }
1625
1626 rx_get_stack_layout (& low, & high, & register_mask,
1627 & frame_size, & stack_size);
1628
1629 total_size = frame_size + stack_size;
1630 regs_size = ((high - low) + 1) * UNITS_PER_WORD;
1631
1632 /* See if we are unable to use the special stack frame deconstruct and
1633 return instructions. In most cases we can use them, but the exceptions
1634 are:
1635
1636 - Sibling calling functions deconstruct the frame but do not return to
1637 their caller. Instead they branch to their sibling and allow their
1638 return instruction to return to this function's parent.
1639
67e66e16 1640 - Fast and normal interrupt handling functions have to use special
24833e1a 1641 return instructions.
1642
1643 - Functions where we have pushed a fragmented set of registers into the
1644 call-save area must have the same set of registers popped. */
1645 if (is_sibcall
1646 || is_fast_interrupt_func (NULL_TREE)
67e66e16 1647 || is_interrupt_func (NULL_TREE)
24833e1a 1648 || register_mask)
1649 {
1650 /* Cannot use the special instructions - deconstruct by hand. */
1651 if (total_size)
95272799 1652 gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
1653 GEN_INT (total_size), false);
24833e1a 1654
e4d9e8e5 1655 if (MUST_SAVE_ACC_REGISTER)
24833e1a 1656 {
67e66e16 1657 unsigned int acc_low, acc_high;
1658
1659 /* Reverse the saving of the accumulator register onto the stack.
1660 Note we must adjust the saved "low" accumulator value as it
1661 is really the middle 32-bits of the accumulator. */
1662 if (register_mask)
1663 {
1664 acc_low = acc_high = 0;
9d2f1b03 1665
1666 for (reg = 1; reg < CC_REGNUM; reg ++)
67e66e16 1667 if (register_mask & (1 << reg))
1668 {
1669 if (acc_low == 0)
1670 acc_low = reg;
1671 else
1672 {
1673 acc_high = reg;
1674 break;
1675 }
1676 }
1677 emit_insn (gen_stack_pop (gen_rtx_REG (SImode, acc_high)));
1678 emit_insn (gen_stack_pop (gen_rtx_REG (SImode, acc_low)));
1679 }
1680 else
1681 {
1682 acc_low = low;
1683 acc_high = low + 1;
1684 emit_insn (gen_stack_popm (GEN_INT (2 * UNITS_PER_WORD),
1685 gen_rx_popm_vector (acc_low, acc_high)));
1686 }
1687
1688 emit_insn (gen_ashlsi3 (gen_rtx_REG (SImode, acc_low),
1689 gen_rtx_REG (SImode, acc_low),
1690 GEN_INT (16)));
1691 emit_insn (gen_mvtaclo (gen_rtx_REG (SImode, acc_low)));
1692 emit_insn (gen_mvtachi (gen_rtx_REG (SImode, acc_high)));
1693 }
24833e1a 1694
67e66e16 1695 if (register_mask)
1696 {
9d2f1b03 1697 for (reg = 0; reg < CC_REGNUM; reg ++)
24833e1a 1698 if (register_mask & (1 << reg))
1699 emit_insn (gen_stack_pop (gen_rtx_REG (SImode, reg)));
1700 }
1701 else if (low)
1702 {
1703 if (high == low)
1704 emit_insn (gen_stack_pop (gen_rtx_REG (SImode, low)));
1705 else
1706 emit_insn (gen_stack_popm (GEN_INT (regs_size),
1707 gen_rx_popm_vector (low, high)));
1708 }
1709
1710 if (is_fast_interrupt_func (NULL_TREE))
61fc50a0 1711 {
1712 gcc_assert (! is_sibcall);
1713 emit_jump_insn (gen_fast_interrupt_return ());
1714 }
67e66e16 1715 else if (is_interrupt_func (NULL_TREE))
61fc50a0 1716 {
1717 gcc_assert (! is_sibcall);
1718 emit_jump_insn (gen_exception_return ());
1719 }
24833e1a 1720 else if (! is_sibcall)
1721 emit_jump_insn (gen_simple_return ());
1722
1723 return;
1724 }
1725
1726 /* If we allocated space on the stack, free it now. */
1727 if (total_size)
1728 {
1729 unsigned HOST_WIDE_INT rtsd_size;
1730
1731 /* See if we can use the RTSD instruction. */
1732 rtsd_size = total_size + regs_size;
1733 if (rtsd_size < 1024 && (rtsd_size % 4) == 0)
1734 {
1735 if (low)
1736 emit_jump_insn (gen_pop_and_return
1737 (GEN_INT (rtsd_size),
1738 gen_rx_rtsd_vector (rtsd_size, low, high)));
1739 else
1740 emit_jump_insn (gen_deallocate_and_return (GEN_INT (total_size)));
1741
1742 return;
1743 }
1744
95272799 1745 gen_safe_add (stack_pointer_rtx, stack_pointer_rtx,
1746 GEN_INT (total_size), false);
24833e1a 1747 }
1748
1749 if (low)
1750 emit_jump_insn (gen_pop_and_return (GEN_INT (regs_size),
1751 gen_rx_rtsd_vector (regs_size,
1752 low, high)));
1753 else
1754 emit_jump_insn (gen_simple_return ());
1755}
1756
1757
1758/* Compute the offset (in words) between FROM (arg pointer
1759 or frame pointer) and TO (frame pointer or stack pointer).
1760 See ASCII art comment at the start of rx_expand_prologue
1761 for more information. */
1762
1763int
1764rx_initial_elimination_offset (int from, int to)
1765{
1766 unsigned int low;
1767 unsigned int high;
1768 unsigned int frame_size;
1769 unsigned int stack_size;
1770 unsigned int mask;
1771
1772 rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size);
1773
1774 if (from == ARG_POINTER_REGNUM)
1775 {
1776 /* Extend the computed size of the stack frame to
1777 include the registers pushed in the prologue. */
1778 if (low)
1779 frame_size += ((high - low) + 1) * UNITS_PER_WORD;
1780 else
1781 frame_size += bit_count (mask) * UNITS_PER_WORD;
1782
1783 /* Remember to include the return address. */
1784 frame_size += 1 * UNITS_PER_WORD;
1785
1786 if (to == FRAME_POINTER_REGNUM)
1787 return frame_size;
1788
1789 gcc_assert (to == STACK_POINTER_REGNUM);
1790 return frame_size + stack_size;
1791 }
1792
1793 gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM);
1794 return stack_size;
1795}
1796
24833e1a 1797/* Decide if a variable should go into one of the small data sections. */
1798
1799static bool
1800rx_in_small_data (const_tree decl)
1801{
1802 int size;
1803 const_tree section;
1804
1805 if (rx_small_data_limit == 0)
1806 return false;
1807
1808 if (TREE_CODE (decl) != VAR_DECL)
1809 return false;
1810
1811 /* We do not put read-only variables into a small data area because
1812 they would be placed with the other read-only sections, far away
1813 from the read-write data sections, and we only have one small
1814 data area pointer.
1815 Similarly commons are placed in the .bss section which might be
1816 far away (and out of alignment with respect to) the .data section. */
1817 if (TREE_READONLY (decl) || DECL_COMMON (decl))
1818 return false;
1819
1820 section = DECL_SECTION_NAME (decl);
1821 if (section)
1822 {
1823 const char * const name = TREE_STRING_POINTER (section);
1824
1825 return (strcmp (name, "D_2") == 0) || (strcmp (name, "B_2") == 0);
1826 }
1827
1828 size = int_size_in_bytes (TREE_TYPE (decl));
1829
1830 return (size > 0) && (size <= rx_small_data_limit);
1831}
1832
1833/* Return a section for X.
1834 The only special thing we do here is to honor small data. */
1835
1836static section *
1837rx_select_rtx_section (enum machine_mode mode,
1838 rtx x,
1839 unsigned HOST_WIDE_INT align)
1840{
1841 if (rx_small_data_limit > 0
1842 && GET_MODE_SIZE (mode) <= rx_small_data_limit
1843 && align <= (unsigned HOST_WIDE_INT) rx_small_data_limit * BITS_PER_UNIT)
1844 return sdata_section;
1845
1846 return default_elf_select_rtx_section (mode, x, align);
1847}
1848
1849static section *
1850rx_select_section (tree decl,
1851 int reloc,
1852 unsigned HOST_WIDE_INT align)
1853{
1854 if (rx_small_data_limit > 0)
1855 {
1856 switch (categorize_decl_for_section (decl, reloc))
1857 {
1858 case SECCAT_SDATA: return sdata_section;
1859 case SECCAT_SBSS: return sbss_section;
1860 case SECCAT_SRODATA:
1861 /* Fall through. We do not put small, read only
1862 data into the C_2 section because we are not
1863 using the C_2 section. We do not use the C_2
1864 section because it is located with the other
1865 read-only data sections, far away from the read-write
1866 data sections and we only have one small data
1867 pointer (r13). */
1868 default:
1869 break;
1870 }
1871 }
1872
1873 /* If we are supporting the Renesas assembler
1874 we cannot use mergeable sections. */
1875 if (TARGET_AS100_SYNTAX)
1876 switch (categorize_decl_for_section (decl, reloc))
1877 {
1878 case SECCAT_RODATA_MERGE_CONST:
1879 case SECCAT_RODATA_MERGE_STR_INIT:
1880 case SECCAT_RODATA_MERGE_STR:
1881 return readonly_data_section;
1882
1883 default:
1884 break;
1885 }
1886
1887 return default_elf_select_section (decl, reloc, align);
1888}
1889\f
1890enum rx_builtin
1891{
1892 RX_BUILTIN_BRK,
1893 RX_BUILTIN_CLRPSW,
1894 RX_BUILTIN_INT,
1895 RX_BUILTIN_MACHI,
1896 RX_BUILTIN_MACLO,
1897 RX_BUILTIN_MULHI,
1898 RX_BUILTIN_MULLO,
1899 RX_BUILTIN_MVFACHI,
1900 RX_BUILTIN_MVFACMI,
1901 RX_BUILTIN_MVFC,
1902 RX_BUILTIN_MVTACHI,
1903 RX_BUILTIN_MVTACLO,
1904 RX_BUILTIN_MVTC,
67e66e16 1905 RX_BUILTIN_MVTIPL,
24833e1a 1906 RX_BUILTIN_RACW,
1907 RX_BUILTIN_REVW,
1908 RX_BUILTIN_RMPA,
1909 RX_BUILTIN_ROUND,
24833e1a 1910 RX_BUILTIN_SETPSW,
1911 RX_BUILTIN_WAIT,
1912 RX_BUILTIN_max
1913};
1914
1915static void
1916rx_init_builtins (void)
1917{
1918#define ADD_RX_BUILTIN1(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE) \
1919 add_builtin_function ("__builtin_rx_" LC_NAME, \
1920 build_function_type_list (RET_TYPE##_type_node, \
1921 ARG_TYPE##_type_node, \
1922 NULL_TREE), \
1923 RX_BUILTIN_##UC_NAME, \
1924 BUILT_IN_MD, NULL, NULL_TREE)
1925
1926#define ADD_RX_BUILTIN2(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2) \
1927 add_builtin_function ("__builtin_rx_" LC_NAME, \
1928 build_function_type_list (RET_TYPE##_type_node, \
1929 ARG_TYPE1##_type_node,\
1930 ARG_TYPE2##_type_node,\
1931 NULL_TREE), \
1932 RX_BUILTIN_##UC_NAME, \
1933 BUILT_IN_MD, NULL, NULL_TREE)
1934
1935#define ADD_RX_BUILTIN3(UC_NAME,LC_NAME,RET_TYPE,ARG_TYPE1,ARG_TYPE2,ARG_TYPE3) \
1936 add_builtin_function ("__builtin_rx_" LC_NAME, \
1937 build_function_type_list (RET_TYPE##_type_node, \
1938 ARG_TYPE1##_type_node,\
1939 ARG_TYPE2##_type_node,\
1940 ARG_TYPE3##_type_node,\
1941 NULL_TREE), \
1942 RX_BUILTIN_##UC_NAME, \
1943 BUILT_IN_MD, NULL, NULL_TREE)
1944
1945 ADD_RX_BUILTIN1 (BRK, "brk", void, void);
1946 ADD_RX_BUILTIN1 (CLRPSW, "clrpsw", void, integer);
1947 ADD_RX_BUILTIN1 (SETPSW, "setpsw", void, integer);
1948 ADD_RX_BUILTIN1 (INT, "int", void, integer);
1949 ADD_RX_BUILTIN2 (MACHI, "machi", void, intSI, intSI);
1950 ADD_RX_BUILTIN2 (MACLO, "maclo", void, intSI, intSI);
1951 ADD_RX_BUILTIN2 (MULHI, "mulhi", void, intSI, intSI);
1952 ADD_RX_BUILTIN2 (MULLO, "mullo", void, intSI, intSI);
1953 ADD_RX_BUILTIN1 (MVFACHI, "mvfachi", intSI, void);
1954 ADD_RX_BUILTIN1 (MVFACMI, "mvfacmi", intSI, void);
1955 ADD_RX_BUILTIN1 (MVTACHI, "mvtachi", void, intSI);
1956 ADD_RX_BUILTIN1 (MVTACLO, "mvtaclo", void, intSI);
1957 ADD_RX_BUILTIN1 (RMPA, "rmpa", void, void);
1958 ADD_RX_BUILTIN1 (MVFC, "mvfc", intSI, integer);
1959 ADD_RX_BUILTIN2 (MVTC, "mvtc", void, integer, integer);
67e66e16 1960 ADD_RX_BUILTIN1 (MVTIPL, "mvtipl", void, integer);
24833e1a 1961 ADD_RX_BUILTIN1 (RACW, "racw", void, integer);
1962 ADD_RX_BUILTIN1 (ROUND, "round", intSI, float);
1963 ADD_RX_BUILTIN1 (REVW, "revw", intSI, intSI);
24833e1a 1964 ADD_RX_BUILTIN1 (WAIT, "wait", void, void);
1965}
1966
24833e1a 1967static rtx
1968rx_expand_void_builtin_1_arg (rtx arg, rtx (* gen_func)(rtx), bool reg)
1969{
1970 if (reg && ! REG_P (arg))
1971 arg = force_reg (SImode, arg);
1972
1973 emit_insn (gen_func (arg));
1974
1975 return NULL_RTX;
1976}
1977
1978static rtx
1979rx_expand_builtin_mvtc (tree exp)
1980{
1981 rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
1982 rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1));
1983
1984 if (! CONST_INT_P (arg1))
1985 return NULL_RTX;
1986
1987 if (! REG_P (arg2))
1988 arg2 = force_reg (SImode, arg2);
1989
1990 emit_insn (gen_mvtc (arg1, arg2));
1991
1992 return NULL_RTX;
1993}
1994
1995static rtx
1996rx_expand_builtin_mvfc (tree t_arg, rtx target)
1997{
1998 rtx arg = expand_normal (t_arg);
1999
2000 if (! CONST_INT_P (arg))
2001 return NULL_RTX;
2002
e4d9e8e5 2003 if (target == NULL_RTX)
2004 return NULL_RTX;
2005
24833e1a 2006 if (! REG_P (target))
2007 target = force_reg (SImode, target);
2008
2009 emit_insn (gen_mvfc (target, arg));
2010
2011 return target;
2012}
2013
67e66e16 2014static rtx
2015rx_expand_builtin_mvtipl (rtx arg)
2016{
2017 /* The RX610 does not support the MVTIPL instruction. */
2018 if (rx_cpu_type == RX610)
2019 return NULL_RTX;
2020
e5743482 2021 if (! CONST_INT_P (arg) || ! IN_RANGE (INTVAL (arg), 0, (1 << 4) - 1))
67e66e16 2022 return NULL_RTX;
2023
2024 emit_insn (gen_mvtipl (arg));
2025
2026 return NULL_RTX;
2027}
2028
24833e1a 2029static rtx
2030rx_expand_builtin_mac (tree exp, rtx (* gen_func)(rtx, rtx))
2031{
2032 rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0));
2033 rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1));
2034
2035 if (! REG_P (arg1))
2036 arg1 = force_reg (SImode, arg1);
2037
2038 if (! REG_P (arg2))
2039 arg2 = force_reg (SImode, arg2);
2040
2041 emit_insn (gen_func (arg1, arg2));
2042
2043 return NULL_RTX;
2044}
2045
2046static rtx
2047rx_expand_int_builtin_1_arg (rtx arg,
2048 rtx target,
2049 rtx (* gen_func)(rtx, rtx),
2050 bool mem_ok)
2051{
2052 if (! REG_P (arg))
2053 if (!mem_ok || ! MEM_P (arg))
2054 arg = force_reg (SImode, arg);
2055
2056 if (target == NULL_RTX || ! REG_P (target))
2057 target = gen_reg_rtx (SImode);
2058
2059 emit_insn (gen_func (target, arg));
2060
2061 return target;
2062}
2063
2064static rtx
2065rx_expand_int_builtin_0_arg (rtx target, rtx (* gen_func)(rtx))
2066{
2067 if (target == NULL_RTX || ! REG_P (target))
2068 target = gen_reg_rtx (SImode);
2069
2070 emit_insn (gen_func (target));
2071
2072 return target;
2073}
2074
2075static rtx
2076rx_expand_builtin_round (rtx arg, rtx target)
2077{
2078 if ((! REG_P (arg) && ! MEM_P (arg))
2079 || GET_MODE (arg) != SFmode)
2080 arg = force_reg (SFmode, arg);
2081
2082 if (target == NULL_RTX || ! REG_P (target))
2083 target = gen_reg_rtx (SImode);
2084
2085 emit_insn (gen_lrintsf2 (target, arg));
2086
2087 return target;
2088}
2089
e5743482 2090static int
0318c61a 2091valid_psw_flag (rtx op, const char *which)
e5743482 2092{
2093 static int mvtc_inform_done = 0;
2094
2095 if (GET_CODE (op) == CONST_INT)
2096 switch (INTVAL (op))
2097 {
2098 case 0: case 'c': case 'C':
2099 case 1: case 'z': case 'Z':
2100 case 2: case 's': case 'S':
2101 case 3: case 'o': case 'O':
2102 case 8: case 'i': case 'I':
2103 case 9: case 'u': case 'U':
2104 return 1;
2105 }
2106
2107 error ("__builtin_rx_%s takes 'C', 'Z', 'S', 'O', 'I', or 'U'", which);
2108 if (!mvtc_inform_done)
2109 error ("use __builtin_rx_mvtc (0, ... ) to write arbitrary values to PSW");
2110 mvtc_inform_done = 1;
2111
2112 return 0;
2113}
2114
24833e1a 2115static rtx
2116rx_expand_builtin (tree exp,
2117 rtx target,
2118 rtx subtarget ATTRIBUTE_UNUSED,
2119 enum machine_mode mode ATTRIBUTE_UNUSED,
2120 int ignore ATTRIBUTE_UNUSED)
2121{
2122 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
432093e5 2123 tree arg = call_expr_nargs (exp) >= 1 ? CALL_EXPR_ARG (exp, 0) : NULL_TREE;
24833e1a 2124 rtx op = arg ? expand_normal (arg) : NULL_RTX;
2125 unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
2126
2127 switch (fcode)
2128 {
2129 case RX_BUILTIN_BRK: emit_insn (gen_brk ()); return NULL_RTX;
e5743482 2130 case RX_BUILTIN_CLRPSW:
2131 if (!valid_psw_flag (op, "clrpsw"))
2132 return NULL_RTX;
2133 return rx_expand_void_builtin_1_arg (op, gen_clrpsw, false);
2134 case RX_BUILTIN_SETPSW:
2135 if (!valid_psw_flag (op, "setpsw"))
2136 return NULL_RTX;
2137 return rx_expand_void_builtin_1_arg (op, gen_setpsw, false);
24833e1a 2138 case RX_BUILTIN_INT: return rx_expand_void_builtin_1_arg
2139 (op, gen_int, false);
2140 case RX_BUILTIN_MACHI: return rx_expand_builtin_mac (exp, gen_machi);
2141 case RX_BUILTIN_MACLO: return rx_expand_builtin_mac (exp, gen_maclo);
2142 case RX_BUILTIN_MULHI: return rx_expand_builtin_mac (exp, gen_mulhi);
2143 case RX_BUILTIN_MULLO: return rx_expand_builtin_mac (exp, gen_mullo);
2144 case RX_BUILTIN_MVFACHI: return rx_expand_int_builtin_0_arg
2145 (target, gen_mvfachi);
2146 case RX_BUILTIN_MVFACMI: return rx_expand_int_builtin_0_arg
2147 (target, gen_mvfacmi);
2148 case RX_BUILTIN_MVTACHI: return rx_expand_void_builtin_1_arg
2149 (op, gen_mvtachi, true);
2150 case RX_BUILTIN_MVTACLO: return rx_expand_void_builtin_1_arg
2151 (op, gen_mvtaclo, true);
2152 case RX_BUILTIN_RMPA: emit_insn (gen_rmpa ()); return NULL_RTX;
2153 case RX_BUILTIN_MVFC: return rx_expand_builtin_mvfc (arg, target);
2154 case RX_BUILTIN_MVTC: return rx_expand_builtin_mvtc (exp);
67e66e16 2155 case RX_BUILTIN_MVTIPL: return rx_expand_builtin_mvtipl (op);
24833e1a 2156 case RX_BUILTIN_RACW: return rx_expand_void_builtin_1_arg
2157 (op, gen_racw, false);
2158 case RX_BUILTIN_ROUND: return rx_expand_builtin_round (op, target);
2159 case RX_BUILTIN_REVW: return rx_expand_int_builtin_1_arg
2160 (op, target, gen_revw, false);
24833e1a 2161 case RX_BUILTIN_WAIT: emit_insn (gen_wait ()); return NULL_RTX;
2162
2163 default:
2164 internal_error ("bad builtin code");
2165 break;
2166 }
2167
2168 return NULL_RTX;
2169}
2170\f
2171/* Place an element into a constructor or destructor section.
2172 Like default_ctor_section_asm_out_constructor in varasm.c
2173 except that it uses .init_array (or .fini_array) and it
2174 handles constructor priorities. */
2175
2176static void
2177rx_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor)
2178{
2179 section * s;
2180
2181 if (priority != DEFAULT_INIT_PRIORITY)
2182 {
2183 char buf[18];
2184
2185 sprintf (buf, "%s.%.5u",
2186 is_ctor ? ".init_array" : ".fini_array",
2187 priority);
2188 s = get_section (buf, SECTION_WRITE, NULL_TREE);
2189 }
2190 else if (is_ctor)
2191 s = ctors_section;
2192 else
2193 s = dtors_section;
2194
2195 switch_to_section (s);
2196 assemble_align (POINTER_SIZE);
2197 assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
2198}
2199
2200static void
2201rx_elf_asm_constructor (rtx symbol, int priority)
2202{
2203 rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */true);
2204}
2205
2206static void
2207rx_elf_asm_destructor (rtx symbol, int priority)
2208{
2209 rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */false);
2210}
2211\f
67e66e16 2212/* Check "fast_interrupt", "interrupt" and "naked" attributes. */
24833e1a 2213
2214static tree
2215rx_handle_func_attribute (tree * node,
2216 tree name,
2217 tree args,
2218 int flags ATTRIBUTE_UNUSED,
2219 bool * no_add_attrs)
2220{
2221 gcc_assert (DECL_P (* node));
2222 gcc_assert (args == NULL_TREE);
2223
2224 if (TREE_CODE (* node) != FUNCTION_DECL)
2225 {
2226 warning (OPT_Wattributes, "%qE attribute only applies to functions",
2227 name);
2228 * no_add_attrs = true;
2229 }
2230
2231 /* FIXME: We ought to check for conflicting attributes. */
2232
2233 /* FIXME: We ought to check that the interrupt and exception
2234 handler attributes have been applied to void functions. */
2235 return NULL_TREE;
2236}
2237
2238/* Table of RX specific attributes. */
2239const struct attribute_spec rx_attribute_table[] =
2240{
ac86af5d 2241 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
2242 affects_type_identity. */
2243 { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
2244 false },
2245 { "interrupt", 0, 0, true, false, false, rx_handle_func_attribute,
2246 false },
2247 { "naked", 0, 0, true, false, false, rx_handle_func_attribute,
2248 false },
2249 { NULL, 0, 0, false, false, false, NULL, false }
24833e1a 2250};
2251
98cb9b5b 2252/* Extra processing for target specific command line options. */
2253
2254static bool
fba5dd52 2255rx_handle_option (struct gcc_options *opts, struct gcc_options *opts_set,
2256 const struct cl_decoded_option *decoded,
2257 location_t loc ATTRIBUTE_UNUSED)
98cb9b5b 2258{
fba5dd52 2259 size_t code = decoded->opt_index;
2260 const char *arg = decoded->arg;
2261 int value = decoded->value;
2262
2263 gcc_assert (opts == &global_options);
2264 gcc_assert (opts_set == &global_options_set);
2265
98cb9b5b 2266 switch (code)
2267 {
2268 case OPT_mint_register_:
2269 switch (value)
2270 {
2271 case 4:
2272 fixed_regs[10] = call_used_regs [10] = 1;
2273 /* Fall through. */
2274 case 3:
2275 fixed_regs[11] = call_used_regs [11] = 1;
2276 /* Fall through. */
2277 case 2:
2278 fixed_regs[12] = call_used_regs [12] = 1;
2279 /* Fall through. */
2280 case 1:
2281 fixed_regs[13] = call_used_regs [13] = 1;
2282 /* Fall through. */
2283 case 0:
2284 return true;
2285 default:
2286 return false;
2287 }
2288 break;
2289
2290 case OPT_mmax_constant_size_:
2291 /* Make sure that the -mmax-constant_size option is in range. */
2292 return value >= 0 && value <= 4;
2293
2294 case OPT_mcpu_:
98cb9b5b 2295 if (strcasecmp (arg, "RX610") == 0)
2296 rx_cpu_type = RX610;
2297 else if (strcasecmp (arg, "RX200") == 0)
2298 {
2299 target_flags |= MASK_NO_USE_FPU;
2300 rx_cpu_type = RX200;
2301 }
2302 else if (strcasecmp (arg, "RX600") != 0)
2303 warning (0, "unrecognized argument '%s' to -mcpu= option", arg);
2304 break;
2305
2306 case OPT_fpu:
2307 if (rx_cpu_type == RX200)
bf776685 2308 error ("the RX200 cpu does not have FPU hardware");
98cb9b5b 2309 break;
2310
2311 default:
2312 break;
2313 }
2314
2315 return true;
2316}
2317
42d89991 2318/* Implement TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE. */
02e53c17 2319
2320static void
42d89991 2321rx_override_options_after_change (void)
98cb9b5b 2322{
2323 static bool first_time = TRUE;
98cb9b5b 2324
2325 if (first_time)
2326 {
2327 /* If this is the first time through and the user has not disabled
42d89991 2328 the use of RX FPU hardware then enable -ffinite-math-only,
2329 since the FPU instructions do not support NaNs and infinities. */
98cb9b5b 2330 if (TARGET_USE_FPU)
42d89991 2331 flag_finite_math_only = 1;
98cb9b5b 2332
98cb9b5b 2333 first_time = FALSE;
2334 }
2335 else
2336 {
2337 /* Alert the user if they are changing the optimization options
2338 to use IEEE compliant floating point arithmetic with RX FPU insns. */
2339 if (TARGET_USE_FPU
42d89991 2340 && !flag_finite_math_only)
2341 warning (0, "RX FPU instructions do not support NaNs and infinities");
98cb9b5b 2342 }
2343}
2344
1af17d44 2345static void
2346rx_option_override (void)
2347{
2348 /* This target defaults to strict volatile bitfields. */
2349 if (flag_strict_volatile_bitfields < 0)
2350 flag_strict_volatile_bitfields = 1;
42d89991 2351
2352 rx_override_options_after_change ();
1af17d44 2353}
2354
c17f64cc 2355/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
2356static const struct default_options rx_option_optimization_table[] =
2357 {
2358 { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
2359 { OPT_LEVELS_NONE, 0, NULL, 0 }
2360 };
2361
98cb9b5b 2362\f
24833e1a 2363static bool
2364rx_allocate_stack_slots_for_args (void)
2365{
2366 /* Naked functions should not allocate stack slots for arguments. */
2367 return ! is_naked_func (NULL_TREE);
2368}
2369
2370static bool
2371rx_func_attr_inlinable (const_tree decl)
2372{
2373 return ! is_fast_interrupt_func (decl)
67e66e16 2374 && ! is_interrupt_func (decl)
24833e1a 2375 && ! is_naked_func (decl);
2376}
2377
61fc50a0 2378/* Return nonzero if it is ok to make a tail-call to DECL,
2379 a function_decl or NULL if this is an indirect call, using EXP */
2380
2381static bool
e4d9e8e5 2382rx_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
61fc50a0 2383{
2384 /* Do not allow indirect tailcalls. The
2385 sibcall patterns do not support them. */
2386 if (decl == NULL)
2387 return false;
2388
2389 /* Never tailcall from inside interrupt handlers or naked functions. */
2390 if (is_fast_interrupt_func (NULL_TREE)
2391 || is_interrupt_func (NULL_TREE)
2392 || is_naked_func (NULL_TREE))
2393 return false;
2394
2395 return true;
2396}
2397
24833e1a 2398static void
2399rx_file_start (void)
2400{
2401 if (! TARGET_AS100_SYNTAX)
2402 default_file_start ();
2403}
2404
2405static bool
2406rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED)
2407{
c6347c7a 2408 /* The packed attribute overrides the MS behaviour. */
2409 return ! TYPE_PACKED (record_type);
24833e1a 2410}
24833e1a 2411\f
2412/* Returns true if X a legitimate constant for an immediate
2413 operand on the RX. X is already known to satisfy CONSTANT_P. */
2414
2415bool
2416rx_is_legitimate_constant (rtx x)
2417{
24833e1a 2418 switch (GET_CODE (x))
2419 {
2420 case CONST:
2421 x = XEXP (x, 0);
2422
2423 if (GET_CODE (x) == PLUS)
2424 {
2425 if (! CONST_INT_P (XEXP (x, 1)))
2426 return false;
2427
2428 /* GCC would not pass us CONST_INT + CONST_INT so we
2429 know that we have {SYMBOL|LABEL} + CONST_INT. */
2430 x = XEXP (x, 0);
2431 gcc_assert (! CONST_INT_P (x));
2432 }
2433
2434 switch (GET_CODE (x))
2435 {
2436 case LABEL_REF:
2437 case SYMBOL_REF:
2438 return true;
2439
95272799 2440 case UNSPEC:
2441 return XINT (x, 1) == UNSPEC_CONST;
2442
24833e1a 2443 default:
2444 /* FIXME: Can this ever happen ? */
2445 abort ();
2446 return false;
2447 }
2448 break;
2449
2450 case LABEL_REF:
2451 case SYMBOL_REF:
2452 return true;
2453 case CONST_DOUBLE:
09bb92cc 2454 return (rx_max_constant_size == 0 || rx_max_constant_size == 4);
24833e1a 2455 case CONST_VECTOR:
2456 return false;
2457 default:
2458 gcc_assert (CONST_INT_P (x));
2459 break;
2460 }
2461
95272799 2462 return ok_for_max_constant (INTVAL (x));
24833e1a 2463}
2464
24833e1a 2465static int
2466rx_address_cost (rtx addr, bool speed)
2467{
2468 rtx a, b;
2469
2470 if (GET_CODE (addr) != PLUS)
2471 return COSTS_N_INSNS (1);
2472
2473 a = XEXP (addr, 0);
2474 b = XEXP (addr, 1);
2475
2476 if (REG_P (a) && REG_P (b))
2477 /* Try to discourage REG+REG addressing as it keeps two registers live. */
2478 return COSTS_N_INSNS (4);
2479
2480 if (speed)
2481 /* [REG+OFF] is just as fast as [REG]. */
2482 return COSTS_N_INSNS (1);
2483
2484 if (CONST_INT_P (b)
2485 && ((INTVAL (b) > 128) || INTVAL (b) < -127))
2486 /* Try to discourage REG + <large OFF> when optimizing for size. */
2487 return COSTS_N_INSNS (2);
2488
2489 return COSTS_N_INSNS (1);
2490}
2491
2492static bool
2493rx_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
2494{
2495 /* We can always eliminate to the frame pointer.
2496 We can eliminate to the stack pointer unless a frame
2497 pointer is needed. */
2498
2499 return to == FRAME_POINTER_REGNUM
2500 || ( to == STACK_POINTER_REGNUM && ! frame_pointer_needed);
2501}
2502\f
2503
2504static void
2505rx_trampoline_template (FILE * file)
2506{
2507 /* Output assembler code for a block containing the constant
2508 part of a trampoline, leaving space for the variable parts.
2509
2510 On the RX, (where r8 is the static chain regnum) the trampoline
2511 looks like:
2512
2513 mov #<static chain value>, r8
2514 mov #<function's address>, r9
2515 jmp r9
2516
2517 In big-endian-data-mode however instructions are read into the CPU
2518 4 bytes at a time. These bytes are then swapped around before being
2519 passed to the decoder. So...we must partition our trampoline into
2520 4 byte packets and swap these packets around so that the instruction
2521 reader will reverse the process. But, in order to avoid splitting
2522 the 32-bit constants across these packet boundaries, (making inserting
2523 them into the constructed trampoline very difficult) we have to pad the
2524 instruction sequence with NOP insns. ie:
2525
2526 nop
2527 nop
2528 mov.l #<...>, r8
2529 nop
2530 nop
2531 mov.l #<...>, r9
2532 jmp r9
2533 nop
2534 nop */
2535
2536 if (! TARGET_BIG_ENDIAN_DATA)
2537 {
2538 asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", STATIC_CHAIN_REGNUM);
2539 asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", TRAMPOLINE_TEMP_REGNUM);
2540 asm_fprintf (file, "\tjmp\tr%d\n", TRAMPOLINE_TEMP_REGNUM);
2541 }
2542 else
2543 {
2544 char r8 = '0' + STATIC_CHAIN_REGNUM;
2545 char r9 = '0' + TRAMPOLINE_TEMP_REGNUM;
2546
2547 if (TARGET_AS100_SYNTAX)
2548 {
2549 asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r8);
2550 asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n");
2551 asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r9);
2552 asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n");
2553 asm_fprintf (file, "\t.BYTE 003H, 003H, 00%cH, 07fH\n", r9);
2554 }
2555 else
2556 {
2557 asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r8);
2558 asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n");
2559 asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r9);
2560 asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n");
2561 asm_fprintf (file, "\t.byte 0x03, 0x03, 0x0%c, 0x7f\n", r9);
2562 }
2563 }
2564}
2565
2566static void
2567rx_trampoline_init (rtx tramp, tree fndecl, rtx chain)
2568{
2569 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2570
2571 emit_block_move (tramp, assemble_trampoline_template (),
2572 GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
2573
2574 if (TARGET_BIG_ENDIAN_DATA)
2575 {
2576 emit_move_insn (adjust_address (tramp, SImode, 4), chain);
2577 emit_move_insn (adjust_address (tramp, SImode, 12), fnaddr);
2578 }
2579 else
2580 {
2581 emit_move_insn (adjust_address (tramp, SImode, 2), chain);
2582 emit_move_insn (adjust_address (tramp, SImode, 6 + 2), fnaddr);
2583 }
2584}
2585\f
ccfccd66 2586static int
2587rx_memory_move_cost (enum machine_mode mode, reg_class_t regclass, bool in)
9d2f1b03 2588{
ccfccd66 2589 return 2 + memory_move_secondary_cost (mode, regclass, in);
9d2f1b03 2590}
2591
ccfccd66 2592/* Convert a CC_MODE to the set of flags that it represents. */
9d2f1b03 2593
2594static unsigned int
ccfccd66 2595flags_from_mode (enum machine_mode mode)
9d2f1b03 2596{
ccfccd66 2597 switch (mode)
9d2f1b03 2598 {
ccfccd66 2599 case CC_ZSmode:
2600 return CC_FLAG_S | CC_FLAG_Z;
2601 case CC_ZSOmode:
2602 return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O;
2603 case CC_ZSCmode:
2604 return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_C;
2605 case CCmode:
2606 return CC_FLAG_S | CC_FLAG_Z | CC_FLAG_O | CC_FLAG_C;
2607 case CC_Fmode:
2608 return CC_FLAG_FP;
2609 default:
2610 gcc_unreachable ();
2611 }
2612}
9d2f1b03 2613
ccfccd66 2614/* Convert a set of flags to a CC_MODE that can implement it. */
9d2f1b03 2615
ccfccd66 2616static enum machine_mode
2617mode_from_flags (unsigned int f)
2618{
2619 if (f & CC_FLAG_FP)
2620 return CC_Fmode;
2621 if (f & CC_FLAG_O)
2622 {
2623 if (f & CC_FLAG_C)
2624 return CCmode;
2625 else
2626 return CC_ZSOmode;
9d2f1b03 2627 }
ccfccd66 2628 else if (f & CC_FLAG_C)
2629 return CC_ZSCmode;
2630 else
2631 return CC_ZSmode;
9d2f1b03 2632}
2633
ccfccd66 2634/* Convert an RTX_CODE to the set of flags needed to implement it.
2635 This assumes an integer comparison. */
2636
9d2f1b03 2637static unsigned int
ccfccd66 2638flags_from_code (enum rtx_code code)
9d2f1b03 2639{
ccfccd66 2640 switch (code)
9d2f1b03 2641 {
ccfccd66 2642 case LT:
2643 case GE:
24ad6c43 2644 return CC_FLAG_S;
ccfccd66 2645 case GT:
2646 case LE:
2647 return CC_FLAG_S | CC_FLAG_O | CC_FLAG_Z;
2648 case GEU:
2649 case LTU:
2650 return CC_FLAG_C;
2651 case GTU:
2652 case LEU:
2653 return CC_FLAG_C | CC_FLAG_Z;
2654 case EQ:
2655 case NE:
2656 return CC_FLAG_Z;
2657 default:
2658 gcc_unreachable ();
9d2f1b03 2659 }
2660}
2661
ccfccd66 2662/* Return a CC_MODE of which both M1 and M2 are subsets. */
2663
2664static enum machine_mode
2665rx_cc_modes_compatible (enum machine_mode m1, enum machine_mode m2)
9d2f1b03 2666{
ccfccd66 2667 unsigned f;
2668
2669 /* Early out for identical modes. */
2670 if (m1 == m2)
2671 return m1;
2672
2673 /* There's no valid combination for FP vs non-FP. */
2674 f = flags_from_mode (m1) | flags_from_mode (m2);
2675 if (f & CC_FLAG_FP)
2676 return VOIDmode;
2677
2678 /* Otherwise, see what mode can implement all the flags. */
2679 return mode_from_flags (f);
9d2f1b03 2680}
8b8777b9 2681
2682/* Return the minimal CC mode needed to implement (CMP_CODE X Y). */
2683
2684enum machine_mode
24ad6c43 2685rx_select_cc_mode (enum rtx_code cmp_code, rtx x, rtx y)
8b8777b9 2686{
2687 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2688 return CC_Fmode;
2689
24ad6c43 2690 if (y != const0_rtx)
2691 return CCmode;
2692
ccfccd66 2693 return mode_from_flags (flags_from_code (cmp_code));
2694}
2695
ccfccd66 2696/* Split the conditional branch. Emit (COMPARE C1 C2) into CC_REG with
2697 CC_MODE, and use that in branches based on that compare. */
2698
2699void
2700rx_split_cbranch (enum machine_mode cc_mode, enum rtx_code cmp1,
2701 rtx c1, rtx c2, rtx label)
2702{
2703 rtx flags, x;
2704
2705 flags = gen_rtx_REG (cc_mode, CC_REG);
2706 x = gen_rtx_COMPARE (cc_mode, c1, c2);
2707 x = gen_rtx_SET (VOIDmode, flags, x);
2708 emit_insn (x);
2709
2710 x = gen_rtx_fmt_ee (cmp1, VOIDmode, flags, const0_rtx);
2711 x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx);
2712 x = gen_rtx_SET (VOIDmode, pc_rtx, x);
2713 emit_jump_insn (x);
8b8777b9 2714}
2715
fc3b02a9 2716/* A helper function for matching parallels that set the flags. */
2717
2718bool
2719rx_match_ccmode (rtx insn, enum machine_mode cc_mode)
2720{
2721 rtx op1, flags;
2722 enum machine_mode flags_mode;
2723
2724 gcc_checking_assert (XVECLEN (PATTERN (insn), 0) == 2);
2725
2726 op1 = XVECEXP (PATTERN (insn), 0, 1);
2727 gcc_checking_assert (GET_CODE (SET_SRC (op1)) == COMPARE);
2728
2729 flags = SET_DEST (op1);
2730 flags_mode = GET_MODE (flags);
2731
2732 if (GET_MODE (SET_SRC (op1)) != flags_mode)
2733 return false;
2734 if (GET_MODE_CLASS (flags_mode) != MODE_CC)
2735 return false;
2736
2737 /* Ensure that the mode of FLAGS is compatible with CC_MODE. */
2738 if (flags_from_mode (flags_mode) & ~flags_from_mode (cc_mode))
2739 return false;
2740
2741 return true;
2742}
2743
9d2f1b03 2744\f
24833e1a 2745#undef TARGET_FUNCTION_VALUE
2746#define TARGET_FUNCTION_VALUE rx_function_value
2747
2748#undef TARGET_RETURN_IN_MSB
2749#define TARGET_RETURN_IN_MSB rx_return_in_msb
2750
2751#undef TARGET_IN_SMALL_DATA_P
2752#define TARGET_IN_SMALL_DATA_P rx_in_small_data
2753
2754#undef TARGET_RETURN_IN_MEMORY
2755#define TARGET_RETURN_IN_MEMORY rx_return_in_memory
2756
2757#undef TARGET_HAVE_SRODATA_SECTION
2758#define TARGET_HAVE_SRODATA_SECTION true
2759
2760#undef TARGET_ASM_SELECT_RTX_SECTION
2761#define TARGET_ASM_SELECT_RTX_SECTION rx_select_rtx_section
2762
2763#undef TARGET_ASM_SELECT_SECTION
2764#define TARGET_ASM_SELECT_SECTION rx_select_section
2765
2766#undef TARGET_INIT_BUILTINS
2767#define TARGET_INIT_BUILTINS rx_init_builtins
2768
2769#undef TARGET_EXPAND_BUILTIN
2770#define TARGET_EXPAND_BUILTIN rx_expand_builtin
2771
2772#undef TARGET_ASM_CONSTRUCTOR
2773#define TARGET_ASM_CONSTRUCTOR rx_elf_asm_constructor
2774
2775#undef TARGET_ASM_DESTRUCTOR
2776#define TARGET_ASM_DESTRUCTOR rx_elf_asm_destructor
2777
2778#undef TARGET_STRUCT_VALUE_RTX
2779#define TARGET_STRUCT_VALUE_RTX rx_struct_value_rtx
2780
2781#undef TARGET_ATTRIBUTE_TABLE
2782#define TARGET_ATTRIBUTE_TABLE rx_attribute_table
2783
2784#undef TARGET_ASM_FILE_START
2785#define TARGET_ASM_FILE_START rx_file_start
2786
2787#undef TARGET_MS_BITFIELD_LAYOUT_P
2788#define TARGET_MS_BITFIELD_LAYOUT_P rx_is_ms_bitfield_layout
2789
2790#undef TARGET_LEGITIMATE_ADDRESS_P
2791#define TARGET_LEGITIMATE_ADDRESS_P rx_is_legitimate_address
2792
5afe50d9 2793#undef TARGET_MODE_DEPENDENT_ADDRESS_P
2794#define TARGET_MODE_DEPENDENT_ADDRESS_P rx_mode_dependent_address_p
2795
24833e1a 2796#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
2797#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS rx_allocate_stack_slots_for_args
2798
2799#undef TARGET_ASM_FUNCTION_PROLOGUE
2800#define TARGET_ASM_FUNCTION_PROLOGUE rx_output_function_prologue
2801
2802#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P
2803#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P rx_func_attr_inlinable
2804
61fc50a0 2805#undef TARGET_FUNCTION_OK_FOR_SIBCALL
2806#define TARGET_FUNCTION_OK_FOR_SIBCALL rx_function_ok_for_sibcall
2807
ee4e8428 2808#undef TARGET_FUNCTION_ARG
2809#define TARGET_FUNCTION_ARG rx_function_arg
2810
2811#undef TARGET_FUNCTION_ARG_ADVANCE
2812#define TARGET_FUNCTION_ARG_ADVANCE rx_function_arg_advance
2813
bd99ba64 2814#undef TARGET_FUNCTION_ARG_BOUNDARY
2815#define TARGET_FUNCTION_ARG_BOUNDARY rx_function_arg_boundary
2816
24833e1a 2817#undef TARGET_SET_CURRENT_FUNCTION
2818#define TARGET_SET_CURRENT_FUNCTION rx_set_current_function
2819
2820#undef TARGET_HANDLE_OPTION
2821#define TARGET_HANDLE_OPTION rx_handle_option
2822
2823#undef TARGET_ASM_INTEGER
2824#define TARGET_ASM_INTEGER rx_assemble_integer
2825
2826#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
2827#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true
2828
2829#undef TARGET_MAX_ANCHOR_OFFSET
2830#define TARGET_MAX_ANCHOR_OFFSET 32
2831
2832#undef TARGET_ADDRESS_COST
2833#define TARGET_ADDRESS_COST rx_address_cost
2834
2835#undef TARGET_CAN_ELIMINATE
2836#define TARGET_CAN_ELIMINATE rx_can_eliminate
2837
b2d7ede1 2838#undef TARGET_CONDITIONAL_REGISTER_USAGE
2839#define TARGET_CONDITIONAL_REGISTER_USAGE rx_conditional_register_usage
2840
24833e1a 2841#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
2842#define TARGET_ASM_TRAMPOLINE_TEMPLATE rx_trampoline_template
2843
2844#undef TARGET_TRAMPOLINE_INIT
2845#define TARGET_TRAMPOLINE_INIT rx_trampoline_init
2846
6bb30542 2847#undef TARGET_PRINT_OPERAND
2848#define TARGET_PRINT_OPERAND rx_print_operand
2849
2850#undef TARGET_PRINT_OPERAND_ADDRESS
2851#define TARGET_PRINT_OPERAND_ADDRESS rx_print_operand_address
2852
9d2f1b03 2853#undef TARGET_CC_MODES_COMPATIBLE
2854#define TARGET_CC_MODES_COMPATIBLE rx_cc_modes_compatible
2855
2856#undef TARGET_MEMORY_MOVE_COST
2857#define TARGET_MEMORY_MOVE_COST rx_memory_move_cost
2858
1af17d44 2859#undef TARGET_OPTION_OVERRIDE
2860#define TARGET_OPTION_OVERRIDE rx_option_override
2861
c17f64cc 2862#undef TARGET_OPTION_OPTIMIZATION_TABLE
2863#define TARGET_OPTION_OPTIMIZATION_TABLE rx_option_optimization_table
2864
bd7d2835 2865#undef TARGET_PROMOTE_FUNCTION_MODE
2866#define TARGET_PROMOTE_FUNCTION_MODE rx_promote_function_mode
2867
42d89991 2868#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE
2869#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE rx_override_options_after_change
02e53c17 2870
f3274970 2871#undef TARGET_EXCEPT_UNWIND_INFO
2872#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
2873
77de4b78 2874#undef TARGET_FLAGS_REGNUM
2875#define TARGET_FLAGS_REGNUM CC_REG
2876
24833e1a 2877struct gcc_target targetm = TARGET_INITIALIZER;
2878
2879/* #include "gt-rx.h" */