]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/rl78/rl78.c
PR middle-end/54146
[thirdparty/gcc.git] / gcc / config / rl78 / rl78.c
CommitLineData
78e515f7 1/* Subroutines used for code generation on Renesas RL78 processors.
2 Copyright (C) 2011 Free Software Foundation, Inc.
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#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "tree.h"
26#include "rtl.h"
27#include "regs.h"
28#include "hard-reg-set.h"
29#include "insn-config.h"
30#include "conditions.h"
31#include "output.h"
32#include "insn-attr.h"
33#include "flags.h"
34#include "function.h"
35#include "expr.h"
36#include "optabs.h"
37#include "libfuncs.h"
38#include "recog.h"
39#include "diagnostic-core.h"
40#include "toplev.h"
41#include "reload.h"
42#include "df.h"
43#include "ggc.h"
44#include "tm_p.h"
45#include "debug.h"
46#include "target.h"
47#include "target-def.h"
48#include "langhooks.h"
49#include "rl78-protos.h"
b9ed1410 50#include "dumpfile.h"
78e515f7 51\f
52static inline bool is_interrupt_func (const_tree decl);
53static inline bool is_brk_interrupt_func (const_tree decl);
54static void rl78_reorg (void);
55\f
56
57/* Debugging statements are tagged with DEBUG0 only so that they can
58 be easily enabled individually, by replacing the '0' with '1' as
59 needed. */
60#define DEBUG0 0
61#define DEBUG1 1
62
63/* REGISTER_NAMES has the names for individual 8-bit registers, but
64 these have the names we need to use when referring to 16-bit
65 register pairs. */
66static const char * const word_regnames[] =
67{
68 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
69 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
70 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
71 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
72 "sp", "ap", "psw", "es", "cs"
73};
74
75struct GTY(()) machine_function
76{
77 /* If set, the rest of the fields have been computed. */
78 int computed;
79 /* Which register pairs need to be pushed in the prologue. */
80 int need_to_push [FIRST_PSEUDO_REGISTER / 2];
81
82 /* These fields describe the frame layout... */
83 /* arg pointer */
84 /* 4 bytes for saved PC */
85 int framesize_regs;
86 /* frame pointer */
87 int framesize_locals;
88 int framesize_outgoing;
89 /* stack pointer */
90 int framesize;
91
92 /* If set, recog is allowed to match against the "real" patterns. */
93 int real_insns_ok;
94 /* If set, recog is allowed to match against the "virtual" patterns. */
95 int virt_insns_ok;
96 /* Set if the current function needs to clean up any trampolines. */
97 int trampolines_used;
98};
99
100/* This is our init_machine_status, as set in
101 rl78_option_override. */
102static struct machine_function *
103rl78_init_machine_status (void)
104{
105 struct machine_function *m;
106
107 m = ggc_alloc_cleared_machine_function ();
108 m->virt_insns_ok = 1;
109
110 return m;
111}
112
113/* Returns whether to run the devirtualization pass. */
114static bool
115devirt_gate (void)
116{
117 return true;
118}
119
120/* Runs the devirtualization pass. */
121static unsigned int
122devirt_pass (void)
123{
124 rl78_reorg ();
125 return 0;
126}
127
128/* This pass converts virtual instructions using virtual registers, to
129 real instructions using real registers. Rather than run it as
130 reorg, we reschedule it before vartrack to help with debugging. */
131static struct opt_pass rl78_devirt_pass =
132{
133 RTL_PASS,
134 "devirt",
135 devirt_gate,
136 devirt_pass,
137 NULL,
138 NULL,
139 212,
140 TV_MACH_DEP,
141 0, 0, 0,
142 0,
4f08bfe3 143 0
78e515f7 144};
145
146static struct register_pass_info rl78_devirt_info =
147{
148 & rl78_devirt_pass,
149 "vartrack",
150 1,
151 PASS_POS_INSERT_BEFORE
152};
153
154#undef TARGET_ASM_FILE_START
155#define TARGET_ASM_FILE_START rl78_asm_file_start
156
157static void
158rl78_asm_file_start (void)
159{
160 int i;
161
162 for (i = 0; i < 8; i++)
163 {
164 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 8 + i, 0xffef0 + i);
165 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 16 + i, 0xffee8 + i);
166 }
167
168 register_pass (& rl78_devirt_info);
169}
170
171\f
172#undef TARGET_OPTION_OVERRIDE
173#define TARGET_OPTION_OVERRIDE rl78_option_override
174
175static void
176rl78_option_override (void)
177{
178 flag_omit_frame_pointer = 1;
179 flag_no_function_cse = 1;
180 flag_split_wide_types = 0;
181
182 init_machine_status = rl78_init_machine_status;
183}
184
185/* Most registers are 8 bits. Some are 16 bits because, for example,
186 gcc doesn't like dealing with $FP as a register pair. This table
187 maps register numbers to size in bytes. */
188static const int register_sizes[] =
189{
190 1, 1, 1, 1, 1, 1, 1, 1,
191 1, 1, 1, 1, 1, 1, 1, 1,
192 1, 1, 1, 1, 1, 1, 2, 1,
193 1, 1, 1, 1, 1, 1, 1, 1,
194 2, 2, 1, 1, 1
195};
196
197/* Predicates used in the MD patterns. This one is true when virtual
198 insns may be matched, which typically means before (or during) the
199 devirt pass. */
200bool
201rl78_virt_insns_ok (void)
202{
203 if (cfun)
204 return cfun->machine->virt_insns_ok;
205 return true;
206}
207
208/* Predicates used in the MD patterns. This one is true when real
209 insns may be matched, which typically means after (or during) the
210 devirt pass. */
211bool
212rl78_real_insns_ok (void)
213{
214 if (cfun)
215 return cfun->machine->real_insns_ok;
216 return false;
217}
218
219/* Implements HARD_REGNO_NREGS. */
220int
221rl78_hard_regno_nregs (int regno, enum machine_mode mode)
222{
223 int rs = register_sizes[regno];
224 if (rs < 1)
225 rs = 1;
226 return ((GET_MODE_SIZE (mode) + rs - 1) / rs);
227}
228
229/* Implements HARD_REGNO_MODE_OK. */
230int
231rl78_hard_regno_mode_ok (int regno, enum machine_mode mode)
232{
233 int s = GET_MODE_SIZE (mode);
234
235 if (s < 1)
236 return 0;
237 /* These are not to be used by gcc. */
238 if (regno == 23 || regno == ES_REG || regno == CS_REG)
239 return 0;
240 /* $fp can alway sbe accessed as a 16-bit value. */
241 if (regno == FP_REG && s == 2)
242 return 1;
243 if (regno < SP_REG)
244 {
245 /* Since a reg-reg move is really a reg-mem move, we must
246 enforce alignment. */
247 if (s > 1 && (regno % 2))
248 return 0;
249 return 1;
250 }
251 if (s == CC_REGNUM)
252 return (mode == BImode);
253 /* All other registers must be accessed in their natural sizes. */
254 if (s == register_sizes [regno])
255 return 1;
256 return 0;
257}
258
259/* Simplify_gen_subreg() doesn't handle memory references the way we
260 need it to below, so we use this function for when we must get a
261 valid subreg in a "natural" state. */
262static rtx
263rl78_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte)
264{
265 if (GET_CODE (r) == MEM)
266 return adjust_address (r, mode, byte);
267 else
268 return simplify_gen_subreg (mode, r, omode, byte);
269}
270
271/* Used by movsi. Split SImode moves into two HImode moves, using
272 appropriate patterns for the upper and lower halves of symbols. */
273void
274rl78_expand_movsi (rtx *operands)
275{
276 rtx op00, op02, op10, op12;
277
278 op00 = rl78_subreg (HImode, operands[0], SImode, 0);
279 op02 = rl78_subreg (HImode, operands[0], SImode, 2);
280 if (GET_CODE (operands[1]) == CONST
281 || GET_CODE (operands[1]) == SYMBOL_REF)
282 {
283 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
284 op10 = gen_rtx_CONST (HImode, op10);
285 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
286 op12 = gen_rtx_CONST (HImode, op12);
287 }
288 else
289 {
290 op10 = rl78_subreg (HImode, operands[1], SImode, 0);
291 op12 = rl78_subreg (HImode, operands[1], SImode, 2);
292 }
293
294 if (rtx_equal_p (operands[0], operands[1]))
295 ;
296 else if (rtx_equal_p (op00, op12))
297 {
298 emit_move_insn (op02, op12);
299 emit_move_insn (op00, op10);
300 }
301 else
302 {
303 emit_move_insn (op00, op10);
304 emit_move_insn (op02, op12);
305 }
306}
307
308/* Used by various two-operand expanders which cannot accept all
309 operands in the "far" namespace. Force some such operands into
310 registers so that each pattern has at most one far operand. */
311int
312rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx))
313{
314 int did = 0;
315 rtx temp_reg = NULL;
316
317 /* FIXME: in the future, be smarter about only doing this if the
318 other operand is also far, assuming the devirtualizer can also
319 handle that. */
320 if (rl78_far_p (operands[0]))
321 {
322 temp_reg = operands[0];
323 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
324 did = 1;
325 }
326 if (!did)
327 return 0;
328
329 emit_insn (gen (operands[0], operands[1]));
330 if (temp_reg)
331 emit_move_insn (temp_reg, operands[0]);
332 return 1;
333}
334
335/* Likewise, but for three-operand expanders. */
336int
337rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx))
338{
339 int did = 0;
340 rtx temp_reg = NULL;
341
342 /* FIXME: Likewise. */
343 if (rl78_far_p (operands[1]))
344 {
345 rtx temp_reg = gen_reg_rtx (GET_MODE (operands[1]));
346 emit_move_insn (temp_reg, operands[1]);
347 operands[1] = temp_reg;
348 did = 1;
349 }
350 if (rl78_far_p (operands[0]))
351 {
352 temp_reg = operands[0];
353 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
354 did = 1;
355 }
356 if (!did)
357 return 0;
358
359 emit_insn (gen (operands[0], operands[1], operands[2]));
360 if (temp_reg)
361 emit_move_insn (temp_reg, operands[0]);
362 return 1;
363}
364
365#undef TARGET_CAN_ELIMINATE
366#define TARGET_CAN_ELIMINATE rl78_can_eliminate
367
368static bool
369rl78_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to ATTRIBUTE_UNUSED)
370{
371 return true;
372}
373
374/* Returns nonzero if the given register needs to be saved by the
375 current function. */
376static int
377need_to_save (int regno)
378{
379 if (is_interrupt_func (cfun->decl))
380 {
381 if (regno < 8)
382 return 1; /* don't know what devirt will need */
383 if (regno > 23)
384 return 0; /* don't need to save interrupt registers */
d5bf7b64 385 if (crtl->is_leaf)
78e515f7 386 {
387 return df_regs_ever_live_p (regno);
388 }
389 else
390 return 1;
391 }
392 if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
393 return 1;
394 if (fixed_regs[regno])
395 return 0;
396 if (crtl->calls_eh_return)
397 return 1;
398 if (df_regs_ever_live_p (regno)
399 && !call_used_regs[regno])
400 return 1;
401 return 0;
402}
403
404/* We use this to wrap all emitted insns in the prologue. */
405static rtx
406F (rtx x)
407{
408 RTX_FRAME_RELATED_P (x) = 1;
409 return x;
410}
411
412/* Compute all the frame-related fields in our machine_function
413 structure. */
414static void
415rl78_compute_frame_info (void)
416{
417 int i;
418
419 cfun->machine->computed = 1;
420 cfun->machine->framesize_regs = 0;
421 cfun->machine->framesize_locals = get_frame_size ();
422 cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
423
424 for (i = 0; i < 16; i ++)
425 if (need_to_save (i * 2) || need_to_save (i * 2 + 1))
426 {
427 cfun->machine->need_to_push [i] = 1;
428 cfun->machine->framesize_regs += 2;
429 }
430 else
431 cfun->machine->need_to_push [i] = 0;
432
433 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
434 cfun->machine->framesize_locals ++;
435
436 cfun->machine->framesize = (cfun->machine->framesize_regs
437 + cfun->machine->framesize_locals
438 + cfun->machine->framesize_outgoing);
439}
440\f
441/* Returns true if the provided function has the specified attribute. */
442static inline bool
443has_func_attr (const_tree decl, const char * func_attr)
444{
445 if (decl == NULL_TREE)
446 decl = current_function_decl;
447
448 return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
449}
450
451/* Returns true if the provided function has the "interrupt" attribute. */
452static inline bool
453is_interrupt_func (const_tree decl)
454{
455 return has_func_attr (decl, "interrupt") || has_func_attr (decl, "brk_interrupt");
456}
457
458/* Returns true if the provided function has the "brk_interrupt" attribute. */
459static inline bool
460is_brk_interrupt_func (const_tree decl)
461{
462 return has_func_attr (decl, "brk_interrupt");
463}
464
465/* Check "interrupt" attributes. */
466static tree
467rl78_handle_func_attribute (tree * node,
468 tree name,
469 tree args,
470 int flags ATTRIBUTE_UNUSED,
471 bool * no_add_attrs)
472{
473 gcc_assert (DECL_P (* node));
474 gcc_assert (args == NULL_TREE);
475
476 if (TREE_CODE (* node) != FUNCTION_DECL)
477 {
478 warning (OPT_Wattributes, "%qE attribute only applies to functions",
479 name);
480 * no_add_attrs = true;
481 }
482
483 /* FIXME: We ought to check that the interrupt and exception
484 handler attributes have been applied to void functions. */
485 return NULL_TREE;
486}
487
488#undef TARGET_ATTRIBUTE_TABLE
489#define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
490
491/* Table of RL78-specific attributes. */
492const struct attribute_spec rl78_attribute_table[] =
493{
494 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
495 affects_type_identity. */
496 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
497 false },
498 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
499 false },
500 { NULL, 0, 0, false, false, false, NULL, false }
501};
502
503
504\f
505/* Break down an address RTX into its component base/index/addend
506 portions and return TRUE if the address is of a valid form, else
507 FALSE. */
508static bool
509characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
510{
511 *base = NULL_RTX;
512 *index = NULL_RTX;
513 *addend = NULL_RTX;
514
515 if (GET_CODE (x) == REG)
516 {
517 *base = x;
518 return true;
519 }
520
521 /* We sometimes get these without the CONST wrapper */
522 if (GET_CODE (x) == PLUS
523 && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
524 && GET_CODE (XEXP (x, 1)) == CONST_INT)
525 {
526 *addend = x;
527 return true;
528 }
529
530 if (GET_CODE (x) == PLUS)
531 {
532 *base = XEXP (x, 0);
533 x = XEXP (x, 1);
534
535 if (GET_CODE (*base) != REG
536 && GET_CODE (x) == REG)
537 {
538 rtx tmp = *base;
539 *base = x;
540 x = tmp;
541 }
542
543 if (GET_CODE (*base) != REG)
544 return false;
545
546 if (GET_CODE (x) == ZERO_EXTEND
547 && GET_CODE (XEXP (x, 0)) == REG)
548 {
549 *index = XEXP (x, 0);
550 return false;
551 }
552 }
553
554 switch (GET_CODE (x))
555 {
556 case PLUS:
557 if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
558 && GET_CODE (XEXP (x, 0)) == CONST_INT)
559 {
560 *addend = x;
561 return true;
562 }
563 /* fall through */
564 case MEM:
565 case REG:
566 return false;
567
568 case CONST:
569 case SYMBOL_REF:
570 case CONST_INT:
571 *addend = x;
572 return true;
573
574 default:
575 return false;
576 }
577
578 return false;
579}
580
581/* Used by the Whb constraint. Match addresses that use HL+B or HL+C
582 addressing. */
583bool
584rl78_hl_b_c_addr_p (rtx op)
585{
586 rtx hl, bc;
587
588 if (GET_CODE (op) != PLUS)
589 return false;
590 hl = XEXP (op, 0);
591 bc = XEXP (op, 1);
592 if (GET_CODE (hl) == ZERO_EXTEND)
593 {
594 rtx tmp = hl;
595 hl = bc;
596 bc = tmp;
597 }
598 if (GET_CODE (hl) != REG)
599 return false;
600 if (GET_CODE (bc) != ZERO_EXTEND)
601 return false;
602 bc = XEXP (bc, 0);
603 if (GET_CODE (bc) != REG)
604 return false;
605 if (REGNO (hl) != HL_REG)
606 return false;
607 if (REGNO (bc) != B_REG && REGNO (bc) != C_REG)
608 return false;
609
610 return true;
611}
612
613#define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
614
615/* Used in various constraints and predicates to match operands in the
616 "far" address space. */
617int
618rl78_far_p (rtx x)
619{
620 if (GET_CODE (x) != MEM)
621 return 0;
622#if DEBUG0
623 fprintf(stderr, "\033[35mrl78_far_p: "); debug_rtx(x);
624 fprintf(stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
625#endif
626 return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR;
627}
628
629/* Return the appropriate mode for a named address pointer. */
630#undef TARGET_ADDR_SPACE_POINTER_MODE
631#define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
632static enum machine_mode
633rl78_addr_space_pointer_mode (addr_space_t addrspace)
634{
635 switch (addrspace)
636 {
637 case ADDR_SPACE_GENERIC:
638 return HImode;
639 case ADDR_SPACE_FAR:
640 return SImode;
641 default:
642 gcc_unreachable ();
643 }
644}
645
646/* Return the appropriate mode for a named address address. */
647#undef TARGET_ADDR_SPACE_ADDRESS_MODE
648#define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
649static enum machine_mode
650rl78_addr_space_address_mode (addr_space_t addrspace)
651{
652 switch (addrspace)
653 {
654 case ADDR_SPACE_GENERIC:
655 return HImode;
656 case ADDR_SPACE_FAR:
657 return SImode;
658 default:
659 gcc_unreachable ();
660 }
661}
662
663#undef TARGET_LEGITIMATE_CONSTANT_P
664#define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
665
666static bool
667rl78_is_legitimate_constant (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED)
668{
669 return true;
670}
671
672#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
673#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
674
675bool
676rl78_as_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x,
677 bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
678{
679 rtx base, index, addend;
680
681 if (as == ADDR_SPACE_GENERIC
682 && GET_MODE (x) == SImode)
683 return false;
684
685 if (! characterize_address (x, &base, &index, &addend))
686 return false;
687
688 if (base && index)
689 {
690 int ir = REGNO (index);
691 int br = REGNO (base);
692
693#define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
694 OK (REG_IS (br, HL_REG) && REG_IS (ir, B_REG), "[hl+b]");
695 OK (REG_IS (br, HL_REG) && REG_IS (ir, C_REG), "[hl+c]");
696 return false;
697 }
698
699 if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER)
700 return false;
701
702 return true;
703}
704
705/* Determine if one named address space is a subset of another. */
706#undef TARGET_ADDR_SPACE_SUBSET_P
707#define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
708static bool
709rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
710{
711 gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR);
712 gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR);
713
714 if (subset == superset)
715 return true;
716
717 else
718 return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR);
719}
720
721#undef TARGET_ADDR_SPACE_CONVERT
722#define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
723/* Convert from one address space to another. */
724static rtx
725rl78_addr_space_convert (rtx op, tree from_type, tree to_type)
726{
727 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
728 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
729 rtx result;
730
731 gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR);
732 gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR);
733
734 if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR)
735 {
736 /* This is unpredictable, as we're truncating off usable address
737 bits. */
738
739 result = gen_reg_rtx (HImode);
740 emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0));
741 return result;
742 }
743 else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC)
744 {
745 /* This always works. */
746 result = gen_reg_rtx (SImode);
747 debug_rtx(result);
748 debug_rtx(op);
749 emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op);
750 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx);
751 return result;
752 }
753 else
754 gcc_unreachable ();
755}
756
757/* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
758bool
759rl78_regno_mode_code_ok_for_base_p (int regno, enum machine_mode mode ATTRIBUTE_UNUSED,
760 addr_space_t address_space ATTRIBUTE_UNUSED,
761 int outer_code ATTRIBUTE_UNUSED, int index_code)
762{
763 if (regno < 24 && regno >= 16)
764 return true;
765 if (index_code == REG)
766 return (regno == HL_REG);
767 if (regno == C_REG || regno == B_REG || regno == E_REG || regno == L_REG)
768 return true;
769 return false;
770}
771
772/* Implements MODE_CODE_BASE_REG_CLASS. */
773enum reg_class
774rl78_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
775 addr_space_t address_space ATTRIBUTE_UNUSED,
776 int outer_code ATTRIBUTE_UNUSED,
777 int index_code ATTRIBUTE_UNUSED)
778{
779 return V_REGS;
780}
781
782/* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
783 described in the machine_Function struct definition, above. */
784int
785rl78_initial_elimination_offset (int from, int to)
786{
787 int rv = 0; /* as if arg to arg */
788
789 rl78_compute_frame_info ();
790
791 switch (to)
792 {
793 case STACK_POINTER_REGNUM:
794 rv += cfun->machine->framesize_outgoing;
795 rv += cfun->machine->framesize_locals;
796 /* Fall through. */
797 case FRAME_POINTER_REGNUM:
798 rv += cfun->machine->framesize_regs;
799 rv += 4;
800 break;
801 default:
802 gcc_unreachable ();
803 }
804
805 switch (from)
806 {
807 case FRAME_POINTER_REGNUM:
808 rv -= 4;
809 rv -= cfun->machine->framesize_regs;
810 case ARG_POINTER_REGNUM:
811 break;
812 default:
813 gcc_unreachable ();
814 }
815
816 return rv;
817}
818
819/* Expand the function prologue (from the prologue pattern). */
820void
821rl78_expand_prologue (void)
822{
823 int i, fs;
824 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
825 int rb = 0;
826
827 if (!cfun->machine->computed)
828 rl78_compute_frame_info ();
829
e4858e6a 830 if (flag_stack_usage_info)
831 current_function_static_stack_size = cfun->machine->framesize;
832
78e515f7 833 for (i = 0; i < 16; i++)
834 if (cfun->machine->need_to_push [i])
835 {
836 int need_bank = i/4;
837 if (need_bank != rb)
838 {
839 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
840 rb = need_bank;
841 }
842 F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2))));
843 }
844 if (rb != 0)
845 emit_insn (gen_sel_rb (GEN_INT (0)));
846
847 if (frame_pointer_needed)
848 F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM),
849 gen_rtx_REG (HImode, STACK_POINTER_REGNUM)));
850
851 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
852 while (fs > 0)
853 {
854 int fs_byte = (fs > 254) ? 254 : fs;
855 F (emit_insn (gen_subhi3 (sp, sp, GEN_INT (fs_byte))));
856 fs -= fs_byte;
857 }
858}
859
860/* Expand the function epilogue (from the epilogue pattern). */
861void
862rl78_expand_epilogue (void)
863{
864 int i, fs;
865 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
866 int rb = 0;
867
868 if (frame_pointer_needed)
869 {
870 emit_move_insn (gen_rtx_REG (HImode, STACK_POINTER_REGNUM),
871 gen_rtx_REG (HImode, FRAME_POINTER_REGNUM));
872 }
873 else
874 {
875 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
876 while (fs > 0)
877 {
878 int fs_byte = (fs > 254) ? 254 : fs;
879
880 emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte)));
881 fs -= fs_byte;
882 }
883 }
884
885 for (i = 15; i >= 0; i--)
886 if (cfun->machine->need_to_push [i])
887 {
888 int need_bank = i / 4;
889
890 if (need_bank != rb)
891 {
892 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
893 rb = need_bank;
894 }
895 emit_insn (gen_pop (gen_rtx_REG (HImode, i * 2)));
896 }
897
898 if (rb != 0)
899 emit_insn (gen_sel_rb (GEN_INT (0)));
900
901 if (cfun->machine->trampolines_used)
902 emit_insn (gen_trampoline_uninit ());
903
904 if (is_brk_interrupt_func (cfun->decl))
905 emit_jump_insn (gen_brk_interrupt_return ());
906 else if (is_interrupt_func (cfun->decl))
907 emit_jump_insn (gen_interrupt_return ());
908 else
edf1f7ba 909 emit_jump_insn (gen_rl78_return ());
78e515f7 910}
911
912/* Likewise, for exception handlers. */
913void
914rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED)
915{
916 /* FIXME - replace this with an indirect jump with stack adjust. */
edf1f7ba 917 emit_jump_insn (gen_rl78_return ());
78e515f7 918}
919
920#undef TARGET_ASM_FUNCTION_PROLOGUE
921#define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
922
923/* We don't use this to actually emit the function prologue. We use
924 this to insert a comment in the asm file describing the
925 function. */
926static void
927rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
928{
929 int i;
930
931 if (cfun->machine->framesize == 0)
932 return;
933 fprintf (file, "\t; start of function\n");
934
935 if (cfun->machine->framesize_regs)
936 {
937 fprintf (file, "\t; push %d:", cfun->machine->framesize_regs);
938 for (i = 0; i < 16; i ++)
939 if (cfun->machine->need_to_push[i])
940 fprintf (file, " %s", word_regnames[i*2]);
941 fprintf(file, "\n");
942 }
943
944 if (frame_pointer_needed)
945 fprintf (file, "\t; $fp points here (r22)\n");
946
947 if (cfun->machine->framesize_locals)
948 fprintf (file, "\t; locals: %d byte%s\n", cfun->machine->framesize_locals,
949 cfun->machine->framesize_locals == 1 ? "" : "s");
950
951 if (cfun->machine->framesize_outgoing)
952 fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing,
953 cfun->machine->framesize_outgoing == 1 ? "" : "s");
954}
955
956/* Return an RTL describing where a function return value of type RET_TYPE
957 is held. */
958
959#undef TARGET_FUNCTION_VALUE
960#define TARGET_FUNCTION_VALUE rl78_function_value
961
962static rtx
963rl78_function_value (const_tree ret_type,
964 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
965 bool outgoing ATTRIBUTE_UNUSED)
966{
967 enum machine_mode mode = TYPE_MODE (ret_type);
968
969 return gen_rtx_REG (mode, 8);
970}
971
972#undef TARGET_PROMOTE_FUNCTION_MODE
973#define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
974
975static enum machine_mode
976rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
977 enum machine_mode mode,
978 int *punsignedp ATTRIBUTE_UNUSED,
979 const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED)
980{
981 return mode;
982}
983
984/* Return an RTL expression describing the register holding a function
985 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
986 be passed on the stack. CUM describes the previous parameters to the
987 function and NAMED is false if the parameter is part of a variable
988 parameter list, or the last named parameter before the start of a
989 variable parameter list. */
990
991#undef TARGET_FUNCTION_ARG
992#define TARGET_FUNCTION_ARG rl78_function_arg
993
994static rtx
995rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
996 enum machine_mode mode ATTRIBUTE_UNUSED,
997 const_tree type ATTRIBUTE_UNUSED,
998 bool named ATTRIBUTE_UNUSED)
999{
1000 return NULL_RTX;
1001}
1002
1003#undef TARGET_FUNCTION_ARG_ADVANCE
1004#define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1005
1006static void
1007rl78_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode, const_tree type,
1008 bool named ATTRIBUTE_UNUSED)
1009{
1010 int rounded_size;
1011 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
1012
1013 rounded_size = ((mode == BLKmode)
1014 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
1015 if (rounded_size & 1)
1016 rounded_size ++;
1017 (*cum) += rounded_size;
1018}
1019
1020#undef TARGET_FUNCTION_ARG_BOUNDARY
1021#define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1022
1023static unsigned int
1024rl78_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
1025 const_tree type ATTRIBUTE_UNUSED)
1026{
1027 return 16;
1028}
1029
1030/* Supported modifier letters:
1031
1032 A - address of a MEM
1033 S - SADDR form of a real register
1034 v - real register corresponding to a virtual register
1035 m - minus - negative of CONST_INT value.
1036 c - inverse of a conditional (NE vs EQ for example)
1037
1038 h - bottom HI of an SI
1039 H - top HI of an SI
1040 q - bottom QI of an HI
1041 Q - top QI of an HI
1042 e - third QI of an SI (i.e. where the ES register gets values from)
1043
1044*/
1045
1046/* Implements the bulk of rl78_print_operand, below. We do it this
1047 way because we need to test for a constant at the top level and
1048 insert the '#', but not test for it anywhere else as we recurse
1049 down into the operand. */
1050static void
1051rl78_print_operand_1 (FILE * file, rtx op, int letter)
1052{
1053 int need_paren;
1054
1055 switch (GET_CODE (op))
1056 {
1057 case MEM:
1058 if (letter == 'A')
1059 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1060 else
1061 {
1062 if (rl78_far_p (op))
1063 fprintf(file, "es:");
1064 if (letter == 'H')
1065 {
1066 op = adjust_address (op, HImode, 2);
1067 letter = 0;
1068 }
1069 if (letter == 'h')
1070 {
1071 op = adjust_address (op, HImode, 0);
1072 letter = 0;
1073 }
1074 if (letter == 'Q')
1075 {
1076 op = adjust_address (op, QImode, 1);
1077 letter = 0;
1078 }
1079 if (letter == 'q')
1080 {
1081 op = adjust_address (op, QImode, 0);
1082 letter = 0;
1083 }
1084 if (letter == 'e')
1085 {
1086 op = adjust_address (op, QImode, 2);
1087 letter = 0;
1088 }
1089 if (CONSTANT_P (XEXP (op, 0)))
1090 {
1091 fprintf(file, "!");
1092 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1093 }
1094 else if (GET_CODE (XEXP (op, 0)) == PLUS
1095 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF)
1096 {
1097 fprintf(file, "!");
1098 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1099 }
1100 else if (GET_CODE (XEXP (op, 0)) == PLUS
1101 && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
1102 && REGNO (XEXP (XEXP (op, 0), 0)) == 2)
1103 {
1104 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u');
1105 fprintf(file, "[");
1106 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0);
1107 fprintf(file, "]");
1108 }
1109 else
1110 {
1111 fprintf(file, "[");
1112 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1113 fprintf(file, "]");
1114 }
1115 }
1116 break;
1117
1118 case REG:
1119 if (letter == 'Q')
1120 fprintf (file, "%s", reg_names [REGNO (op) | 1]);
1121 else if (letter == 'H')
1122 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1123 else if (letter == 'q')
1124 fprintf (file, "%s", reg_names [REGNO (op) & ~1]);
1125 else if (letter == 'e')
1126 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1127 else if (letter == 'S')
1128 fprintf (file, "0x%x", 0xffef8 + REGNO (op));
1129 else if (GET_MODE (op) == HImode
1130 && ! (REGNO (op) & ~0xfe))
1131 {
1132 if (letter == 'v')
1133 fprintf (file, "%s", word_regnames [REGNO (op) % 8]);
1134 else
1135 fprintf (file, "%s", word_regnames [REGNO (op)]);
1136 }
1137 else
1138 fprintf (file, "%s", reg_names [REGNO (op)]);
1139 break;
1140
1141 case CONST_INT:
1142 if (letter == 'Q')
1143 fprintf (file, "%ld", INTVAL (op) >> 8);
1144 else if (letter == 'H')
1145 fprintf (file, "%ld", INTVAL (op) >> 16);
1146 else if (letter == 'q')
1147 fprintf (file, "%ld", INTVAL (op) & 0xff);
1148 else if (letter == 'h')
1149 fprintf (file, "%ld", INTVAL (op) & 0xffff);
1150 else if (letter == 'e')
1151 fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff);
1152 else if (letter == 'm')
1153 fprintf (file, "%ld", - INTVAL (op));
1154 else
1155 fprintf(file, "%ld", INTVAL (op));
1156 break;
1157
1158 case CONST:
1159 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1160 break;
1161
1162 case ZERO_EXTRACT:
1163 {
1164 int bits = INTVAL (XEXP (op, 1));
1165 int ofs = INTVAL (XEXP (op, 2));
1166 if (bits == 16 && ofs == 0)
1167 fprintf (file, "%%lo16(");
1168 else if (bits == 16 && ofs == 16)
1169 fprintf (file, "%%hi16(");
1170 else if (bits == 8 && ofs == 16)
1171 fprintf (file, "%%hi8(");
1172 else
1173 gcc_unreachable ();
1174 rl78_print_operand_1 (file, XEXP (op, 0), 0);
1175 fprintf (file, ")");
1176 }
1177 break;
1178
1179 case ZERO_EXTEND:
1180 if (GET_CODE (XEXP (op, 0)) == REG)
1181 fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]);
1182 else
1183 print_rtl (file, op);
1184 break;
1185
1186 case PLUS:
1187 need_paren = 0;
1188 if (letter == 'H')
1189 {
1190 fprintf (file, "%%hi16(");
1191 need_paren = 1;
1192 letter = 0;
1193 }
1194 if (letter == 'h')
1195 {
1196 fprintf (file, "%%lo16(");
1197 need_paren = 1;
1198 letter = 0;
1199 }
1200 if (letter == 'e')
1201 {
1202 fprintf (file, "%%hi8(");
1203 need_paren = 1;
1204 letter = 0;
1205 }
1206 if (letter == 'q' || letter == 'Q')
1207 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1208
1209 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
1210 {
1211 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1212 fprintf (file, "+");
1213 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1214 }
1215 else
1216 {
1217 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1218 fprintf (file, "+");
1219 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1220 }
1221 if (need_paren)
1222 fprintf (file, ")");
1223 break;
1224
1225 case SYMBOL_REF:
1226 need_paren = 0;
1227 if (letter == 'H')
1228 {
1229 fprintf (file, "%%hi16(");
1230 need_paren = 1;
1231 letter = 0;
1232 }
1233 if (letter == 'h')
1234 {
1235 fprintf (file, "%%lo16(");
1236 need_paren = 1;
1237 letter = 0;
1238 }
1239 if (letter == 'e')
1240 {
1241 fprintf (file, "%%hi8(");
1242 need_paren = 1;
1243 letter = 0;
1244 }
1245 if (letter == 'q' || letter == 'Q')
1246 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1247
1248 output_addr_const (file, op);
1249 if (need_paren)
1250 fprintf (file, ")");
1251 break;
1252
1253 case CODE_LABEL:
1254 case LABEL_REF:
1255 output_asm_label (op);
1256 break;
1257
1258 case LTU:
1259 fprintf (file, letter == 'c' ? "nc" : "c");
1260 break;
1261 case LEU:
1262 fprintf (file, letter == 'c' ? "h" : "nh");
1263 break;
1264 case GEU:
1265 fprintf (file, letter == 'c' ? "c" : "nc");
1266 break;
1267 case GTU:
1268 fprintf (file, letter == 'c' ? "nh" : "h");
1269 break;
1270 case EQ:
1271 fprintf (file, letter == 'c' ? "nz" : "z");
1272 break;
1273 case NE:
1274 fprintf (file, letter == 'c' ? "z" : "nz");
1275 break;
1276
1277 default:
1278 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
1279 break;
1280 }
1281}
1282
1283#undef TARGET_PRINT_OPERAND
1284#define TARGET_PRINT_OPERAND rl78_print_operand
1285
1286static void
1287rl78_print_operand (FILE * file, rtx op, int letter)
1288{
1289 if (CONSTANT_P (op) && letter != 'u')
1290 fprintf (file, "#");
1291 rl78_print_operand_1 (file, op, letter);
1292}
1293
1294#undef TARGET_TRAMPOLINE_INIT
1295#define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
1296
1297/* Note that the RL78's addressing makes it very difficult to do
1298 trampolines on the stack. So, libgcc has a small pool of
1299 trampolines from which one is allocated to this task. */
1300static void
1301rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
1302{
1303 rtx mov_addr, thunk_addr;
1304 rtx function = XEXP (DECL_RTL (fndecl), 0);
1305
1306 mov_addr = adjust_address (m_tramp, HImode, 0);
1307 thunk_addr = gen_reg_rtx (HImode);
1308
1309 function = force_reg (HImode, function);
1310 static_chain = force_reg (HImode, static_chain);
1311
1312 emit_insn (gen_trampoline_init (thunk_addr, function, static_chain));
1313 emit_move_insn (mov_addr, thunk_addr);
1314
1315 cfun->machine->trampolines_used = 1;
1316}
1317
1318#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
1319#define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
1320
1321static rtx
1322rl78_trampoline_adjust_address (rtx m_tramp)
1323{
1324 rtx x = gen_rtx_MEM (HImode, m_tramp);
1325 return x;
1326}
1327\f
1328/* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
1329 the "normal" compares, specifically, it only has unsigned compares,
1330 so we must synthesize the missing ones. */
1331void
1332rl78_expand_compare (rtx *operands)
1333{
1334 /* RL78 does not have signed comparisons. We must modify the
1335 operands to be in the unsigned range, and emit an unsigned
1336 comparison. */
1337
1338 enum machine_mode mode;
1339 rtx high_bit;
1340 int i;
1341 RTX_CODE new_cond;
1342
1343 switch (GET_CODE (operands[0]))
1344 {
1345 case GE:
1346 new_cond = GEU;
1347 break;
1348 case LE:
1349 new_cond = LEU;
1350 break;
1351 case GT:
1352 new_cond = GTU;
1353 break;
1354 case LT:
1355 new_cond = LTU;
1356 break;
1357 default:
1358 return;
1359 }
1360
1361#if DEBUG0
1362 fprintf (stderr, "\033[38;5;129mrl78_expand_compare\n");
1363 debug_rtx (operands[0]);
1364 fprintf (stderr, "\033[0m");
1365#endif
1366
1367 mode = GET_MODE (operands[1]);
1368 if (mode == VOIDmode)
1369 mode = GET_MODE (operands[2]);
1370 high_bit = GEN_INT (~0 << (GET_MODE_BITSIZE (mode) - 1));
1371
1372 /* 0: conditional 1,2: operands */
1373 for (i = 1; i <= 2; i ++)
1374 {
1375 rtx r = operands[i];
1376
1377 if (GET_CODE (r) == CONST_INT)
1378 r = GEN_INT (INTVAL (r) ^ INTVAL (high_bit));
1379 else
1380 {
1381 r = gen_rtx_PLUS (mode, operands[i], high_bit);
1382 r = copy_to_mode_reg (mode, r);
1383 }
1384 operands[i] = r;
1385 }
1386
1387 operands[0] = gen_rtx_fmt_ee (new_cond, GET_MODE (operands[0]), operands[1], operands[2]);
1388
1389#if DEBUG0
1390 fprintf (stderr, "\033[38;5;142mrl78_expand_compare\n");
1391 debug_rtx (operands[0]);
1392 fprintf (stderr, "\033[0m");
1393#endif
1394}
1395
1396\f
1397
1398/* Define this to 1 if you are debugging the peephole optimizers. */
1399#define DEBUG_PEEP 0
1400
1401/* Predicate used to enable the peephole2 patterns in rl78-virt.md.
1402 The default "word" size is a byte so we can effectively use all the
1403 registers, but we want to do 16-bit moves whenever possible. This
1404 function determines when such a move is an option. */
1405bool
1406rl78_peep_movhi_p (rtx *operands)
1407{
1408 int i;
1409 rtx m, a;
1410
1411 /* (set (op0) (op1))
1412 (set (op2) (op3)) */
1413
1414#if DEBUG_PEEP
1415 fprintf (stderr, "\033[33m");
1416 debug_rtx(operands[0]);
1417 debug_rtx(operands[1]);
1418 debug_rtx(operands[2]);
1419 debug_rtx(operands[3]);
1420 fprintf (stderr, "\033[0m");
1421#endif
1422
1423 if (rtx_equal_p (operands[0], operands[3]))
1424 {
1425#if DEBUG_PEEP
1426 fprintf (stderr, "no peep: overlapping\n");
1427#endif
1428 return false;
1429 }
1430
1431 for (i = 0; i < 2; i ++)
1432 {
1433 if (GET_CODE (operands[i]) != GET_CODE (operands[i+2]))
1434 {
1435#if DEBUG_PEEP
1436 fprintf (stderr, "no peep: different codes\n");
1437#endif
1438 return false;
1439 }
1440 if (GET_MODE (operands[i]) != GET_MODE (operands[i+2]))
1441 {
1442#if DEBUG_PEEP
1443 fprintf (stderr, "no peep: different modes\n");
1444#endif
1445 return false;
1446 }
1447
1448 switch (GET_CODE (operands[i]))
1449 {
1450 case REG:
1451 /* LSB MSB */
1452 if (REGNO (operands[i]) + 1 != REGNO (operands[i+2])
1453 || GET_MODE (operands[i]) != QImode)
1454 {
1455#if DEBUG_PEEP
1456 fprintf (stderr, "no peep: wrong regnos %d %d %d\n",
1457 REGNO (operands[i]), REGNO (operands[i+2]),
1458 i);
1459#endif
1460 return false;
1461 }
1462 if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode))
1463 {
1464#if DEBUG_PEEP
1465 fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i]));
1466#endif
1467 return false;
1468 }
1469 break;
1470
1471 case CONST_INT:
1472 break;
1473
1474 case MEM:
1475 if (GET_MODE (operands[i]) != QImode)
1476 return false;
1477 if (MEM_ALIGN (operands[i]) < 16)
1478 return false;
1479 a = XEXP (operands[i], 0);
1480 if (GET_CODE (a) == CONST)
1481 a = XEXP (a, 0);
1482 if (GET_CODE (a) == PLUS)
1483 a = XEXP (a, 1);
1484 if (GET_CODE (a) == CONST_INT
1485 && INTVAL (a) & 1)
1486 {
1487#if DEBUG_PEEP
1488 fprintf (stderr, "no peep: misaligned mem %d\n", i);
1489 debug_rtx (operands[i]);
1490#endif
1491 return false;
1492 }
1493 m = adjust_address (operands[i], QImode, 1);
1494 if (! rtx_equal_p (m, operands[i+2]))
1495 {
1496#if DEBUG_PEEP
1497 fprintf (stderr, "no peep: wrong mem %d\n", i);
1498 debug_rtx(m);
1499 debug_rtx (operands[i+2]);
1500#endif
1501 return false;
1502 }
1503 break;
1504
1505 default:
1506#if DEBUG_PEEP
1507 fprintf (stderr, "no peep: wrong rtx %d\n", i);
1508#endif
1509 return false;
1510 }
1511 }
1512#if DEBUG_PEEP
1513 fprintf (stderr, "\033[32mpeep!\033[0m\n");
1514#endif
1515 return true;
1516}
1517
1518/* Likewise, when a peephole is activated, this function helps compute
1519 the new operands. */
1520void
1521rl78_setup_peep_movhi (rtx *operands)
1522{
1523 int i;
1524
1525 for (i = 0; i < 2; i ++)
1526 {
1527 switch (GET_CODE (operands[i]))
1528 {
1529 case REG:
1530 operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i]));
1531 break;
1532
1533 case CONST_INT:
1534 operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char)INTVAL (operands[i+2])) * 256);
1535 break;
1536
1537 case MEM:
1538 operands[i+4] = adjust_address (operands[i], HImode, 0);
1539 break;
1540
1541 default:
1542 break;
1543 }
1544 }
1545}
1546\f
1547/*
1548 How Devirtualization works in the RL78 GCC port
1549
1550Background
1551
1552The RL78 is an 8-bit port with some 16-bit operations. It has 32
1553bytes of register space, in four banks, memory-mapped. One bank is
1554the "selected" bank and holds the registers used for primary
1555operations. Since the registers are memory mapped, often you can
1556still refer to the unselected banks via memory accesses.
1557
1558Virtual Registers
1559
1560The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
1561and refers to the other banks via their memory addresses, although
1562they're treated as regular registers internally. These "virtual"
1563registers are R8 through R23 (bank3 is reserved for asm-based
1564interrupt handlers).
1565
1566There are four machine description files:
1567
1568rl78.md - common register-independent patterns and definitions
1569rl78-expand.md - expanders
1570rl78-virt.md - patterns that match BEFORE devirtualization
1571rl78-real.md - patterns that match AFTER devirtualization
1572
1573At least through register allocation and reload, gcc is told that it
1574can do pretty much anything - but may only use the virtual registers.
1575GCC cannot properly create the varying addressing modes that the RL78
1576supports in an efficient way.
1577
1578Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
1579uses the "valloc" attribute in rl78-virt.md for determining the rules
1580by which it will replace virtual registers with real registers (or
1581not) and how to make up addressing modes. For example, insns tagged
1582with "ro1" have a single read-only parameter, which may need to be
1583moved from memory/constant/vreg to a suitable real register. As part
1584of devirtualization, a flag is toggled, disabling the rl78-virt.md
1585patterns and enabling the rl78-real.md patterns. The new patterns'
1586constraints are used to determine the real registers used. NOTE:
1587patterns in rl78-virt.md essentially ignore the constrains and rely on
1588predicates, where the rl78-real.md ones essentially ignore the
1589predicates and rely on the constraints.
1590
1591The devirtualization pass is scheduled via the pass manager (despite
1592being called "rl78_reorg") so it can be scheduled prior to var-track
1593(the idea is to let gdb know about the new registers). Ideally, it
1594would be scheduled right after pro/epilogue generation, so the
1595post-reload optimizers could operate on the real registers, but when I
1596tried that there were some issues building the target libraries.
1597
1598During devirtualization, a simple register move optimizer is run. It
1599would be better to run a full CSE/propogation pass on it through, or
1600re-run regmove, but that has not yet been attempted.
1601
1602 */
1603#define DEBUG_ALLOC 0
1604
1605/* Rescans an insn to see if it's recognized again. This is done
1606 carefully to ensure that all the constraint information is accurate
1607 for the newly matched insn. */
1608static bool
1609insn_ok_now (rtx insn)
1610{
1611 INSN_CODE (insn) = -1;
1612 if (recog (PATTERN (insn), insn, 0) > -1)
1613 {
1614 extract_insn (insn);
1615 if (constrain_operands (1))
1616 {
1617#if DEBUG_ALLOC
1618 fprintf (stderr, "\033[32m");
1619 debug_rtx (insn);
1620 fprintf (stderr, "\033[0m");
1621#endif
1622 return true;
1623 }
1624 }
1625 else
1626 {
1627 fprintf (stderr, "\033[41;30m Unrecognized insn \033[0m\n");
1628 debug_rtx (insn);
1629 gcc_unreachable ();
1630 }
1631#if DEBUG_ALLOC
1632 fprintf (stderr, "\033[31m");
1633 debug_rtx (insn);
1634 fprintf (stderr, "\033[0m");
1635#endif
1636 return false;
1637}
1638
1639#if DEBUG_ALLOC
1640#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
1641#define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
1642#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable()
1643#define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
1644#else
1645#define WORKED
1646#define FAILEDSOFAR
1647#define FAILED gcc_unreachable ()
1648#define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
1649#endif
1650
1651/* Registers into which we move the contents of virtual registers. */
1652#define X gen_rtx_REG (QImode, 0)
1653#define A gen_rtx_REG (QImode, 1)
1654#define C gen_rtx_REG (QImode, 2)
1655#define B gen_rtx_REG (QImode, 3)
1656#define E gen_rtx_REG (QImode, 4)
1657#define D gen_rtx_REG (QImode, 5)
1658#define L gen_rtx_REG (QImode, 6)
1659#define H gen_rtx_REG (QImode, 7)
1660
1661#define AX gen_rtx_REG (HImode, 0)
1662#define BC gen_rtx_REG (HImode, 2)
1663#define DE gen_rtx_REG (HImode, 4)
1664#define HL gen_rtx_REG (HImode, 6)
1665
1666#define OP(x) (*recog_data.operand_loc[x])
1667
1668/* Returns TRUE if R is a virtual register. */
1669static bool
1670is_virtual_register (rtx r)
1671{
1672 return (GET_CODE (r) == REG
1673 && REGNO (r) >= 8
1674 && REGNO (r) < 24);
1675}
1676
1677/* In all these alloc routines, we expect the following: the insn
1678 pattern is unshared, the insn was previously recognized and failed
1679 due to predicates or constraints, and the operand data is in
1680 recog_data. */
1681
1682static int virt_insn_was_frame;
1683
1684/* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
1685 needed. */
1686static rtx
1687EM2 (int line ATTRIBUTE_UNUSED, rtx r)
1688{
1689#if DEBUG_ALLOC
1690 fprintf (stderr, "\033[36m%d: ", line);
1691 debug_rtx(r);
1692 fprintf (stderr, "\033[0m");
1693#endif
1694 /*SCHED_GROUP_P (r) = 1;*/
1695 if (virt_insn_was_frame)
1696 RTX_FRAME_RELATED_P (r) = 1;
1697 return r;
1698}
1699
1700#define EM(x) EM2 (__LINE__, x)
1701
1702/* Return a suitable RTX for the low half of a __far address. */
1703static rtx
1704rl78_lo16 (rtx addr)
1705{
1706 if (GET_CODE (addr) == SYMBOL_REF
1707 || GET_CODE (addr) == CONST)
1708 {
1709 rtx r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0));
1710 r = gen_rtx_CONST (HImode, r);
1711 return r;
1712 }
1713 return rl78_subreg (HImode, addr, SImode, 0);
1714}
1715
1716/* Return a suitable RTX for the high half's lower byte of a __far address. */
1717static rtx
1718rl78_hi8 (rtx addr)
1719{
1720 if (GET_CODE (addr) == SYMBOL_REF
1721 || GET_CODE (addr) == CONST)
1722 {
1723 rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16));
1724 r = gen_rtx_CONST (QImode, r);
1725 return r;
1726 }
1727 return rl78_subreg (QImode, addr, SImode, 2);
1728}
1729
1730/* Copy any register values into real registers and return an RTX for
1731 the same memory, now addressed by real registers. Any needed insns
1732 are emitted before BEFORE. */
1733static rtx
1734transcode_memory_rtx (rtx m, rtx newbase, rtx before)
1735{
1736 rtx base, index, addendr;
1737 int addend = 0;
1738
1739 if (GET_CODE (m) != MEM)
1740 return m;
1741
1742 if (GET_MODE (XEXP (m, 0)) == SImode)
1743 {
1744 rtx seg = rl78_hi8 (XEXP (m, 0));
1745#if DEBUG_ALLOC
1746 fprintf (stderr, "setting ES:\n");
1747 debug_rtx(seg);
1748#endif
1749 emit_insn_before (EM(gen_movqi (A, seg)), before);
1750 emit_insn_before (EM(gen_movqi_es (A)), before);
1751 m = change_address (m, GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
1752 }
1753
1754 characterize_address (XEXP (m, 0), &base, &index, &addendr);
1755 gcc_assert (index == NULL_RTX);
1756
1757#if DEBUG_ALLOC
1758 fprintf (stderr, "\033[33m"); debug_rtx(m); fprintf (stderr, "\033[0m");
1759 debug_rtx (base);
1760#endif
1761 if (base == NULL_RTX)
1762 return m;
1763
1764 if (addendr && GET_CODE (addendr) == CONST_INT)
1765 addend = INTVAL (addendr);
1766
1767 if (REGNO (base) == SP_REG)
1768 {
1769 if (addend >= 0 && addend <= 255)
1770 return m;
1771 }
1772
1773 /* BASE should be a virtual register. We copy it to NEWBASE. If
1774 the addend is out of range for DE/HL, we use AX to compute the full
1775 address. */
1776
1777 if (addend < 0
1778 || (addend > 255 && REGNO (newbase) != 2)
1779 || (addendr && GET_CODE (addendr) != CONST_INT))
1780 {
1781 /* mov ax, vreg
1782 add ax, #imm
1783 mov hl, ax */
1784 EM (emit_insn_before (gen_movhi (AX, base), before));
1785 EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before));
1786 EM (emit_insn_before (gen_movhi (newbase, AX), before));
1787 base = newbase;
1788 addend = 0;
1789 }
1790 else
1791 {
1792 EM (emit_insn_before (gen_movhi (newbase, base), before));
1793 base = newbase;
1794 }
1795
1796 if (addend)
1797 base = gen_rtx_PLUS (HImode, base, GEN_INT (addend));
1798
1799#if DEBUG_ALLOC
1800 fprintf (stderr, "\033[33m");
1801 debug_rtx (m);
1802#endif
1803 m = change_address (m, GET_MODE (m), base);
1804#if DEBUG_ALLOC
1805 debug_rtx (m);
1806 fprintf (stderr, "\033[0m");
1807#endif
1808 return m;
1809}
1810
1811/* Copy SRC to accumulator (A or AX), placing any generated insns
1812 before BEFORE. Returns accumulator RTX. */
1813
1814static rtx
1815move_to_acc (int opno, rtx before)
1816{
1817 rtx src = OP(opno);
1818 enum machine_mode mode = GET_MODE (src);
1819
1820 if (GET_CODE (src) == REG
1821 && REGNO (src) < 2)
1822 return src;
1823
1824 if (mode == VOIDmode)
1825 mode = recog_data.operand_mode[opno];
1826
1827 if (mode == QImode)
1828 {
1829 EM (emit_insn_before (gen_movqi (A, src), before));
1830 return A;
1831 }
1832 else
1833 {
1834 EM (emit_insn_before (gen_movhi (AX, src), before));
1835 return AX;
1836 }
1837}
1838
1839/* Copy accumulator (A or AX) to DEST, placing any generated insns
1840 after AFTER. Returns accumulator RTX. */
1841
1842static rtx
1843move_from_acc (rtx dest, rtx after)
1844{
1845 enum machine_mode mode = GET_MODE (dest);
1846
1847 if (REG_P (dest) && REGNO (dest) < 2)
1848 return dest;
1849
1850 if (mode == QImode)
1851 {
1852 EM (emit_insn_after (gen_movqi (dest, A), after));
1853 return A;
1854 }
1855 else
1856 {
1857 EM (emit_insn_after (gen_movhi (dest, AX), after));
1858 return AX;
1859 }
1860}
1861
1862/* Copy accumulator (A or AX) to REGNO, placing any generated insns
1863 before BEFORE. Returns reg RTX. */
1864
1865static rtx
1866move_acc_to_reg (rtx acc, int regno, rtx before)
1867{
1868 enum machine_mode mode = GET_MODE (acc);
1869 rtx reg;
1870
1871 reg = gen_rtx_REG (mode, regno);
1872
1873 if (mode == QImode)
1874 {
1875 EM (emit_insn_before (gen_movqi (reg, A), before));
1876 return reg;
1877 }
1878 else
1879 {
1880 EM (emit_insn_before (gen_movhi (reg, AX), before));
1881 return reg;
1882 }
1883}
1884
1885/* Copy SRC to X, placing any generated insns before BEFORE.
1886 Returns X RTX. */
1887
1888static rtx
1889move_to_x (int opno, rtx before)
1890{
1891 rtx src = OP(opno);
1892 enum machine_mode mode = GET_MODE (src);
1893 rtx reg;
1894
1895 if (mode == VOIDmode)
1896 mode = recog_data.operand_mode[opno];
1897 reg = (mode == QImode) ? X : AX;
1898
1899 if (mode == QImode || ! is_virtual_register (OP (opno)))
1900 {
1901 OP(opno) = move_to_acc (opno, before);
1902 OP(opno) = move_acc_to_reg (OP(opno), X_REG, before);
1903 return reg;
1904 }
1905
1906 if (mode == QImode)
1907 EM (emit_insn_before (gen_movqi (reg, src), before));
1908 else
1909 EM (emit_insn_before (gen_movhi (reg, src), before));
1910
1911 return reg;
1912}
1913
1914/* Copy OP(opno) to H or HL, placing any generated insns before BEFORE.
1915 Returns H/HL RTX. */
1916
1917static rtx
1918move_to_hl (int opno, rtx before)
1919{
1920 rtx src = OP (opno);
1921 enum machine_mode mode = GET_MODE (src);
1922 rtx reg;
1923
1924 if (mode == VOIDmode)
1925 mode = recog_data.operand_mode[opno];
1926 reg = (mode == QImode) ? L : HL;
1927
1928 if (mode == QImode || ! is_virtual_register (OP (opno)))
1929 {
1930 OP (opno) = move_to_acc (opno, before);
1931 OP (opno) = move_acc_to_reg (OP (opno), L_REG, before);
1932 return reg;
1933 }
1934
1935 if (mode == QImode)
1936 EM (emit_insn_before (gen_movqi (reg, src), before));
1937 else
1938 EM (emit_insn_before (gen_movhi (reg, src), before));
1939
1940 return reg;
1941}
1942
1943/* Copy OP(opno) to E or DE, placing any generated insns before BEFORE.
1944 Returns E/DE RTX. */
1945
1946static rtx
1947move_to_de (int opno, rtx before)
1948{
1949 rtx src = OP (opno);
1950 enum machine_mode mode = GET_MODE (src);
1951 rtx reg;
1952
1953 if (mode == VOIDmode)
1954 mode = recog_data.operand_mode[opno];
1955
1956 reg = (mode == QImode) ? E : DE;
1957
1958 if (mode == QImode || ! is_virtual_register (OP (opno)))
1959 {
1960 OP (opno) = move_to_acc (opno, before);
1961 OP (opno) = move_acc_to_reg (OP (opno), E_REG, before);
1962 }
1963 else
1964 {
1965 rtx move = mode == QImode ? gen_movqi (reg, src) : gen_movhi (reg, src);
1966
1967 EM (emit_insn_before (move, before));
1968 }
1969
1970 return reg;
1971}
1972
1973/* Devirtualize an insn of the form (SET (op) (unop (op))). */
1974static void
1975rl78_alloc_physical_registers_op1 (rtx insn)
1976{
1977 /* op[0] = func op[1] */
1978
1979 /* We first try using A as the destination, then copying it
1980 back. */
1981 if (rtx_equal_p (OP(0), OP(1)))
1982 {
1983 OP(0) =
1984 OP(1) = transcode_memory_rtx (OP(1), DE, insn);
1985 }
1986 else
1987 {
1988 OP(0) = transcode_memory_rtx (OP(0), BC, insn);
1989 OP(1) = transcode_memory_rtx (OP(1), HL, insn);
1990 }
1991
1992 MAYBE_OK (insn);
1993
1994 OP(0) = move_from_acc (OP(0), insn);
1995
1996 MAYBE_OK (insn);
1997
1998 /* Try copying the src to acc first, then. This is for, for
1999 example, ZERO_EXTEND or NOT. */
2000 OP(1) = move_to_acc (1, insn);
2001
2002 MAYBE_OK (insn);
2003
2004 FAILED;
2005}
2006
2007/* Devirtualize an insn of the form (SET (op) (unop (op) (op))). */
2008static void
2009rl78_alloc_physical_registers_op2 (rtx insn)
2010{
2011 /* op[0] = op[1] func op[2] */
2012 rtx prev = prev_nonnote_nondebug_insn (insn);
2013 rtx first;
2014 bool hl_used;
2015
2016 if (rtx_equal_p (OP(0), OP(1)))
2017 {
2018 OP(0) =
2019 OP(1) = transcode_memory_rtx (OP(1), DE, insn);
2020 prev = next_nonnote_nondebug_insn (prev);
2021 OP(2) = transcode_memory_rtx (OP(2), HL, insn);
2022 prev = prev_nonnote_nondebug_insn (prev);
2023 }
2024 else if (rtx_equal_p (OP(0), OP(2)))
2025 {
2026 OP(1) = transcode_memory_rtx (OP(1), DE, insn);
2027 prev = next_nonnote_nondebug_insn (prev);
2028 OP(0) =
2029 OP(2) = transcode_memory_rtx (OP(2), HL, insn);
2030 prev = prev_nonnote_nondebug_insn (prev);
2031 }
2032 else
2033 {
2034 OP(0) = transcode_memory_rtx (OP(0), BC, insn);
2035 OP(1) = transcode_memory_rtx (OP(1), DE, insn);
2036 prev = next_nonnote_nondebug_insn (prev);
2037 OP(2) = transcode_memory_rtx (OP(2), HL, insn);
2038 }
2039
2040 MAYBE_OK (insn);
2041
2042 prev = prev_nonnote_nondebug_insn (insn);
2043 if (recog_data.constraints[1][0] == '%'
2044 && is_virtual_register (OP (1))
2045 && ! is_virtual_register (OP (2))
2046 && ! CONSTANT_P (OP (2)))
2047 {
2048 rtx tmp = OP (1);
2049 OP (1) = OP (2);
2050 OP (2) = tmp;
2051 }
2052
2053 /* Make a note of wether (H)L is being used. It matters
2054 because if OP(2) alsoneeds reloading, then we must take
2055 care not to corrupt HL. */
2056 hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1));
2057
2058 OP(0) = move_from_acc (OP (0), insn);
2059 OP(1) = move_to_acc (1, insn);
2060
2061 MAYBE_OK (insn);
2062
2063 /* We have to copy op2 to HL, but that involves AX, which
2064 already has a live value. Emit it before those insns. */
2065
2066 if (prev)
2067 first = next_nonnote_nondebug_insn (prev);
2068 else
2069 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
2070 ;
2071
2072 OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first);
2073
2074 MAYBE_OK (insn);
2075
2076 FAILED;
2077}
2078
2079/* Devirtualize an insn of the form (SET () (unop (op))). */
2080
2081static void
2082rl78_alloc_physical_registers_ro1 (rtx insn)
2083{
2084 /* (void) op[0] */
2085 OP(0) = transcode_memory_rtx (OP(0), BC, insn);
2086
2087 MAYBE_OK (insn);
2088
2089 OP(0) = move_to_acc (0, insn);
2090
2091 MAYBE_OK (insn);
2092
2093 FAILED;
2094}
2095
2096/* Devirtualize a compare insn. */
2097static void
2098rl78_alloc_physical_registers_cmp (rtx insn)
2099{
2100 /* op[1] cmp_op[0] op[2] */
2101 rtx prev = prev_nonnote_nondebug_insn (insn);
2102 rtx first;
2103
2104 OP(1) = transcode_memory_rtx (OP(1), DE, insn);
2105 OP(2) = transcode_memory_rtx (OP(2), HL, insn);
2106
2107 MAYBE_OK (insn);
2108
2109 OP(1) = move_to_acc (1, insn);
2110
2111 MAYBE_OK (insn);
2112
2113 /* We have to copy op2 to HL, but that involves the acc, which
2114 already has a live value. Emit it before those insns. */
2115
2116 if (prev)
2117 first = next_nonnote_nondebug_insn (prev);
2118 else
2119 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
2120 ;
2121 OP(2) = move_to_hl (2, first);
2122
2123 MAYBE_OK (insn);
2124
2125 FAILED;
2126}
2127
2128/* Like op2, but AX = A op X. */
2129static void
2130rl78_alloc_physical_registers_umul (rtx insn)
2131{
2132 /* op[0] = op[1] func op[2] */
2133 rtx prev = prev_nonnote_nondebug_insn (insn);
2134 rtx first;
2135
2136 OP(0) = transcode_memory_rtx (OP(0), BC, insn);
2137 OP(1) = transcode_memory_rtx (OP(1), DE, insn);
2138 OP(2) = transcode_memory_rtx (OP(2), HL, insn);
2139
2140 MAYBE_OK (insn);
2141
2142 if (recog_data.constraints[1][0] == '%'
2143 && is_virtual_register (OP(1))
2144 && !is_virtual_register (OP(2))
2145 && !CONSTANT_P (OP(2)))
2146 {
2147 rtx tmp = OP(1);
2148 OP(1) = OP(2);
2149 OP(2) = tmp;
2150 }
2151
2152 OP(0) = move_from_acc (OP(0), insn);
2153 OP(1) = move_to_acc (1, insn);
2154
2155 MAYBE_OK (insn);
2156
2157 /* We have to copy op2 to X, but that involves the acc, which
2158 already has a live value. Emit it before those insns. */
2159
2160 if (prev)
2161 first = next_nonnote_nondebug_insn (prev);
2162 else
2163 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
2164 ;
2165 OP(2) = move_to_x (2, first);
2166
2167 MAYBE_OK (insn);
2168
2169 FAILED;
2170}
2171
2172/* Scan all insns and devirtualize them. */
2173static void
2174rl78_alloc_physical_registers (void)
2175{
2176 /* During most of the compile, gcc is dealing with virtual
2177 registers. At this point, we need to assign physical registers
2178 to the vitual ones, and copy in/out as needed. */
2179
2180 rtx insn, curr;
2181 enum attr_valloc valloc_method;
2182
2183 for (insn = get_insns (); insn; insn = curr)
2184 {
2185 int i;
2186
2187 curr = next_nonnote_nondebug_insn (insn);
2188
2189 if (INSN_P (insn)
2190 && (GET_CODE (PATTERN (insn)) == SET
2191 || GET_CODE (PATTERN (insn)) == CALL)
2192 && INSN_CODE (insn) == -1)
2193 {
2194 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
2195 continue;
2196 i = recog (PATTERN (insn), insn, 0);
2197 if (i == -1)
2198 {
2199 debug_rtx (insn);
2200 gcc_unreachable ();
2201 }
2202 INSN_CODE (insn) = i;
2203 }
2204 }
2205
2206 cfun->machine->virt_insns_ok = 0;
2207 cfun->machine->real_insns_ok = 1;
2208
2209 for (insn = get_insns (); insn; insn = curr)
2210 {
2211 curr = insn ? next_nonnote_nondebug_insn (insn) : NULL;
2212
2213 if (!INSN_P (insn))
2214 continue;
2215 if (GET_CODE (PATTERN (insn)) != SET
2216 && GET_CODE (PATTERN (insn)) != CALL)
2217 continue;
2218
2219 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
2220 continue;
2221
2222 valloc_method = get_attr_valloc (insn);
2223
2224 PATTERN (insn)= copy_rtx_if_shared (PATTERN (insn));
2225
2226 if (insn_ok_now (insn))
2227 continue;
2228
2229 INSN_CODE (insn) = -1;
2230
2231 if (RTX_FRAME_RELATED_P (insn))
2232 virt_insn_was_frame = 1;
2233 else
2234 virt_insn_was_frame = 0;
2235
2236 switch (valloc_method)
2237 {
2238 case VALLOC_OP1:
2239 rl78_alloc_physical_registers_op1 (insn);
2240 break;
2241 case VALLOC_OP2:
2242 rl78_alloc_physical_registers_op2 (insn);
2243 break;
2244 case VALLOC_RO1:
2245 rl78_alloc_physical_registers_ro1 (insn);
2246 break;
2247 case VALLOC_CMP:
2248 rl78_alloc_physical_registers_cmp (insn);
2249 break;
2250 case VALLOC_UMUL:
2251 rl78_alloc_physical_registers_umul (insn);
2252 break;
2253 case VALLOC_MACAX:
2254 /* Macro that clobbers AX */
2255 break;
2256 }
2257 }
2258#if DEBUG_ALLOC
2259 fprintf (stderr, "\033[0m");
2260#endif
2261}
2262
2263/* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
2264 This function scans for uses of registers; the last use (i.e. first
2265 encounter when scanning backwards) triggers a REG_DEAD note if the
2266 reg was previously in DEAD[]. */
2267static void
2268rl78_note_reg_uses (char *dead, rtx s, rtx insn)
2269{
2270 const char *fmt;
2271 int i, r;
2272 enum rtx_code code;
2273
2274 if (!s)
2275 return;
2276
2277 code = GET_CODE (s);
2278
2279 switch (code)
2280 {
2281 /* Compare registers by number. */
2282 case REG:
2283 r = REGNO (s);
2284 if (dump_file)
2285 {
2286 fprintf (dump_file, "note use reg %d size %d on insn %d\n",
2287 r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn));
2288 print_rtl_single (dump_file, s);
2289 }
2290 if (dead [r])
2291 add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r));
2292 for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++)
2293 dead [r + i] = 0;
2294 return;
2295
2296 /* These codes have no constituent expressions
2297 and are unique. */
2298 case SCRATCH:
2299 case CC0:
2300 case PC:
2301 return;
2302
2303 case CONST_INT:
2304 case CONST_VECTOR:
2305 case CONST_DOUBLE:
2306 case CONST_FIXED:
2307 /* These are kept unique for a given value. */
2308 return;
2309
2310 default:
2311 break;
2312 }
2313
2314 fmt = GET_RTX_FORMAT (code);
2315
2316 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
2317 {
2318 if (fmt[i] == 'E')
2319 {
2320 int j;
2321 for (j = XVECLEN (s, i) - 1; j >= 0; j--)
2322 rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn);
2323 }
2324 else if (fmt[i] == 'e')
2325 rl78_note_reg_uses (dead, XEXP (s, i), insn);
2326 }
2327}
2328
2329/* Like the previous function, but scan for SETs instead. */
2330static void
2331rl78_note_reg_set (char *dead, rtx d, rtx insn)
2332{
2333 int r, i;
2334
2335 if (GET_CODE (d) != REG)
2336 return;
2337
2338 r = REGNO (d);
2339 if (dead [r])
2340 add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r));
2341 if (dump_file)
2342 fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d)));
2343 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
2344 dead [r + i] = 1;
2345}
2346
2347/* This is a rather crude register death pass. Death status is reset
2348 at every jump or call insn. */
2349static void
2350rl78_calculate_death_notes (void)
2351{
2352 char dead[FIRST_PSEUDO_REGISTER];
2353 rtx insn, p, s, d;
2354 int i;
2355
2356 memset (dead, 0, sizeof (dead));
2357
2358 for (insn = get_last_insn ();
2359 insn;
2360 insn = prev_nonnote_nondebug_insn (insn))
2361 {
2362 if (dump_file)
2363 {
2364 fprintf (dump_file, "\n--------------------------------------------------");
2365 fprintf (dump_file, "\nDead:");
2366 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
2367 if (dead[i])
2368 fprintf(dump_file, " %s", reg_names[i]);
2369 fprintf (dump_file, "\n");
2370 print_rtl_single (dump_file, insn);
2371 }
2372
2373 switch (GET_CODE (insn))
2374 {
2375 case INSN:
2376 p = PATTERN (insn);
2377 switch (GET_CODE (p))
2378 {
2379 case SET:
2380 s = SET_SRC (p);
2381 d = SET_DEST (p);
2382 rl78_note_reg_set (dead, d, insn);
2383 rl78_note_reg_uses (dead, s, insn);
2384 break;
2385
2386 case USE:
2387 rl78_note_reg_uses (dead, p, insn);
2388 break;
2389
2390 default:
2391 break;
2392 }
2393 break;
2394
2395 case JUMP_INSN:
edf1f7ba 2396 if (INSN_CODE (insn) == CODE_FOR_rl78_return)
78e515f7 2397 {
2398 memset (dead, 1, sizeof (dead));
2399 /* We expect a USE just prior to this, which will mark
2400 the actual return registers. The USE will have a
2401 death note, but we aren't going to be modifying it
2402 after this pass. */
2403 break;
2404 }
2405 case CALL_INSN:
2406 memset (dead, 0, sizeof (dead));
2407 break;
2408
2409 default:
2410 break;
2411 }
2412 if (dump_file)
2413 print_rtl_single (dump_file, insn);
2414 }
2415}
2416
2417/* Helper function to reset the origins in RP and the age in AGE for
2418 all registers. */
2419static void
2420reset_origins (int *rp, int *age)
2421{
2422 int i;
2423 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2424 {
2425 rp[i] = i;
2426 age[i] = 0;
2427 }
2428}
2429
2430/* The idea behind this optimization is to look for cases where we
2431 move data from A to B to C, and instead move from A to B, and A to
2432 C. If B is a virtual register or memory, this is a big win on its
2433 own. If B turns out to be unneeded after this, it's a bigger win.
2434 For each register, we try to determine where it's value originally
2435 came from, if it's propogated purely through moves (and not
2436 computes). The ORIGINS[] array has the regno for the "origin" of
2437 the value in the [regno] it's indexed by. */
2438static void
2439rl78_propogate_register_origins (void)
2440{
2441 int origins[FIRST_PSEUDO_REGISTER];
2442 int age[FIRST_PSEUDO_REGISTER];
2443 int i;
2444 rtx insn, ninsn = NULL_RTX;
2445 rtx pat;
2446
2447 reset_origins (origins, age);
2448
2449 for (insn = get_insns (); insn; insn = ninsn)
2450 {
2451 ninsn = next_nonnote_nondebug_insn (insn);
2452
2453 if (dump_file)
2454 {
2455 fprintf (dump_file, "\n");
2456 fprintf (dump_file, "Origins:");
2457 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
2458 if (origins[i] != i)
2459 fprintf (dump_file, " r%d=r%d", i, origins[i]);
2460 fprintf (dump_file, "\n");
2461 print_rtl_single (dump_file, insn);
2462 }
2463
2464 switch (GET_CODE (insn))
2465 {
2466 case CODE_LABEL:
2467 case BARRIER:
2468 case CALL_INSN:
2469 case JUMP_INSN:
2470 reset_origins (origins, age);
2471 break;
2472
2473 default:
2474 break;
2475
2476 case INSN:
2477 pat = PATTERN (insn);
2478
2479 if (GET_CODE (pat) == PARALLEL)
2480 {
2481 rtx clobber = XVECEXP (pat, 0, 1);
2482 pat = XVECEXP (pat, 0, 0);
2483 if (GET_CODE (clobber) == CLOBBER)
2484 {
2485 int cr = REGNO (XEXP (clobber, 0));
2486 int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0)));
2487 if (dump_file)
2488 fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr);
2489 for (i = 0; i < mb; i++)
2490 {
2491 origins[cr + i] = cr + i;
2492 age[cr + i] = 0;
2493 }
2494 }
2495 else
2496 break;
2497 }
2498
2499 if (GET_CODE (pat) == SET)
2500 {
2501 rtx src = SET_SRC (pat);
2502 rtx dest = SET_DEST (pat);
2503 int mb = GET_MODE_SIZE (GET_MODE (dest));
2504
2505 if (GET_CODE (dest) == REG)
2506 {
2507 int dr = REGNO (dest);
2508
2509 if (GET_CODE (src) == REG)
2510 {
2511 int sr = REGNO (src);
2512 int same = 1;
2513 int best_age, best_reg;
2514
2515 /* See if the copy is not needed. */
2516 for (i = 0; i < mb; i ++)
2517 if (origins[dr + i] != origins[sr + i])
2518 same = 0;
2519 if (same)
2520 {
2521 if (dump_file)
2522 fprintf (dump_file, "deleting because dest already has correct value\n");
2523 delete_insn (insn);
2524 break;
2525 }
2526
2527 if (dr < 8 || sr >= 8)
2528 {
2529 int ar;
2530
2531 best_age = -1;
2532 best_reg = -1;
2533 /* See if the copy can be made from another
2534 bank 0 register instead, instead of the
2535 virtual src register. */
2536 for (ar = 0; ar < 8; ar += mb)
2537 {
2538 same = 1;
2539 for (i = 0; i < mb; i ++)
2540 if (origins[ar + i] != origins[sr + i])
2541 same = 0;
2542
2543 /* The chip has some reg-reg move limitations. */
2544 if (mb == 1 && dr > 3)
2545 same = 0;
2546
2547 if (same)
2548 {
2549 if (best_age == -1 || best_age > age[sr + i])
2550 {
2551 best_age = age[sr + i];
2552 best_reg = sr;
2553 }
2554 }
2555 }
2556
2557 if (best_reg != -1)
2558 {
2559 /* FIXME: copy debug info too. */
2560 SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg);
2561 sr = best_reg;
2562 }
2563 }
2564
2565 for (i = 0; i < mb; i++)
2566 {
2567 origins[dr + i] = origins[sr + i];
2568 age[dr + i] = age[sr + i] + 1;
2569 }
2570 }
2571 else
2572 {
2573 /* The destination is computed, its origin is itself. */
2574 if (dump_file)
2575 fprintf (dump_file, "resetting origin of r%d for %d byte%s\n",
2576 dr, mb, mb == 1 ? "" : "s");
2577 for (i = 0; i < mb; i ++)
2578 {
2579 origins[dr + i] = dr + i;
2580 age[dr + i] = 0;
2581 }
2582 }
2583
2584 /* Any registers marked with that reg as an origin are reset. */
2585 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2586 if (origins[i] >= dr && origins[i] < dr + mb)
2587 {
2588 origins[i] = i;
2589 age[i] = 0;
2590 }
2591 }
2592
2593 /* Special case - our ADDSI3 macro uses AX */
2594 if (get_attr_valloc (insn) == VALLOC_MACAX)
2595 {
2596 if (dump_file)
2597 fprintf (dump_file, "Resetting origin of AX for macro.\n");
2598 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2599 if (i <= 1 || origins[i] <= 1)
2600 {
2601 origins[i] = i;
2602 age[i] = 0;
2603 }
2604 }
2605
2606 if (GET_CODE (src) == ASHIFT
2607 || GET_CODE (src) == ASHIFTRT
2608 || GET_CODE (src) == LSHIFTRT)
2609 {
2610 rtx count = XEXP (src, 1);
2611 if (GET_CODE (count) == REG)
2612 {
2613 /* Special case - our pattern clobbers the count register. */
2614 int r = REGNO (count);
2615 if (dump_file)
2616 fprintf (dump_file, "Resetting origin of r%d for shift.\n", r);
2617 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2618 if (i == r || origins[i] == r)
2619 {
2620 origins[i] = i;
2621 age[i] = 0;
2622 }
2623 }
2624 }
2625 }
2626 }
2627 }
2628}
2629
2630/* Remove any SETs where the destination is unneeded. */
2631static void
2632rl78_remove_unused_sets (void)
2633{
2634 rtx insn, ninsn = NULL_RTX;
2635 rtx dest;
2636
2637 for (insn = get_insns (); insn; insn = ninsn)
2638 {
2639 ninsn = next_nonnote_nondebug_insn (insn);
2640
2641 if ((insn = single_set (insn)) == NULL_RTX)
2642 continue;
2643
2644 dest = SET_DEST (insn);
2645
2646 if (REGNO (dest) > 23)
2647 continue;
2648
2649 if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
2650 delete_insn (insn);
2651 }
2652}
2653
2654#undef xTARGET_MACHINE_DEPENDENT_REORG
2655#define xTARGET_MACHINE_DEPENDENT_REORG rl78_reorg
2656
2657/* This is the top of the devritualization pass. */
2658static void
2659rl78_reorg (void)
2660{
2661 rl78_alloc_physical_registers ();
2662
2663 if (dump_file)
2664 {
2665 fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
5147ec07 2666 print_rtl_with_bb (dump_file, get_insns (), 0);
78e515f7 2667 }
2668
2669 rl78_propogate_register_origins ();
2670 rl78_calculate_death_notes ();
2671
2672 if (dump_file)
2673 {
2674 fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
5147ec07 2675 print_rtl_with_bb (dump_file, get_insns (), 0);
78e515f7 2676 fprintf (dump_file, "\n======================================================================\n");
2677 }
2678
2679 rl78_remove_unused_sets ();
2680
2681 /* The code after devirtualizing has changed so much that at this point
2682 we might as well just rescan everything. Note that
2683 df_rescan_all_insns is not going to help here because it does not
2684 touch the artificial uses and defs. */
2685 df_finish_pass (true);
2686 if (optimize > 1)
2687 df_live_add_problem ();
2688 df_scan_alloc (NULL);
2689 df_scan_blocks ();
2690
2691 if (optimize)
2692 df_analyze ();
2693}
2694
2695#undef TARGET_RETURN_IN_MEMORY
2696#define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
2697
2698static bool
2699rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
2700{
2701 const HOST_WIDE_INT size = int_size_in_bytes (type);
2702 return (size == -1 || size > 8);
2703}
2704
2705\f
2706struct gcc_target targetm = TARGET_INITIALIZER;
2707
2708#include "gt-rl78.h"