PR c/81544 - attribute noreturn and warn_unused_result on the same function accepted
[official-gcc.git] / gcc / config / rl78 / rl78.c
blob58c8fe8ed1ca32a4fc0947246a640ee5d6b62be2
1 /* Subroutines used for code generation on Renesas RL78 processors.
2 Copyright (C) 2011-2017 Free Software Foundation, Inc.
3 Contributed by Red Hat.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "df.h"
29 #include "memmodel.h"
30 #include "tm_p.h"
31 #include "stringpool.h"
32 #include "attribs.h"
33 #include "optabs.h"
34 #include "emit-rtl.h"
35 #include "recog.h"
36 #include "diagnostic-core.h"
37 #include "varasm.h"
38 #include "stor-layout.h"
39 #include "calls.h"
40 #include "output.h"
41 #include "insn-attr.h"
42 #include "explow.h"
43 #include "expr.h"
44 #include "reload.h"
45 #include "cfgrtl.h"
46 #include "langhooks.h"
47 #include "tree-pass.h"
48 #include "context.h"
49 #include "tm-constrs.h" /* for satisfies_constraint_*(). */
50 #include "builtins.h"
52 /* This file should be included last. */
53 #include "target-def.h"
55 static inline bool is_interrupt_func (const_tree decl);
56 static inline bool is_brk_interrupt_func (const_tree decl);
57 static void rl78_reorg (void);
58 static const char *rl78_strip_name_encoding (const char *);
59 static const char *rl78_strip_nonasm_name_encoding (const char *);
60 static section * rl78_select_section (tree, int, unsigned HOST_WIDE_INT);
63 /* Debugging statements are tagged with DEBUG0 only so that they can
64 be easily enabled individually, by replacing the '0' with '1' as
65 needed. */
66 #define DEBUG0 0
67 #define DEBUG1 1
69 /* REGISTER_NAMES has the names for individual 8-bit registers, but
70 these have the names we need to use when referring to 16-bit
71 register pairs. */
72 static const char * const word_regnames[] =
74 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
75 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
76 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
77 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
78 "sp", "ap", "psw", "es", "cs"
81 /* Structure for G13 MDUC registers. */
82 struct mduc_reg_type
84 unsigned int address;
85 enum machine_mode mode;
88 struct mduc_reg_type mduc_regs[] =
90 {0xf00e8, E_QImode},
91 {0xffff0, E_HImode},
92 {0xffff2, E_HImode},
93 {0xf2224, E_HImode},
94 {0xf00e0, E_HImode},
95 {0xf00e2, E_HImode}
98 struct GTY(()) machine_function
100 /* If set, the rest of the fields have been computed. */
101 int computed;
102 /* Which register pairs need to be pushed in the prologue. */
103 int need_to_push [FIRST_PSEUDO_REGISTER / 2];
105 /* These fields describe the frame layout... */
106 /* arg pointer */
107 /* 4 bytes for saved PC */
108 int framesize_regs;
109 /* frame pointer */
110 int framesize_locals;
111 int framesize_outgoing;
112 /* stack pointer */
113 int framesize;
115 /* If set, recog is allowed to match against the "real" patterns. */
116 int real_insns_ok;
117 /* If set, recog is allowed to match against the "virtual" patterns. */
118 int virt_insns_ok;
119 /* Set if the current function needs to clean up any trampolines. */
120 int trampolines_used;
121 /* True if the ES register is used and hence
122 needs to be saved inside interrupt handlers. */
123 bool uses_es;
126 /* This is our init_machine_status, as set in
127 rl78_option_override. */
128 static struct machine_function *
129 rl78_init_machine_status (void)
131 struct machine_function *m;
133 m = ggc_cleared_alloc<machine_function> ();
134 m->virt_insns_ok = 1;
136 return m;
139 /* This pass converts virtual instructions using virtual registers, to
140 real instructions using real registers. Rather than run it as
141 reorg, we reschedule it before vartrack to help with debugging. */
142 namespace
144 const pass_data pass_data_rl78_devirt =
146 RTL_PASS, /* type */
147 "devirt", /* name */
148 OPTGROUP_NONE, /* optinfo_flags */
149 TV_MACH_DEP, /* tv_id */
150 0, /* properties_required */
151 0, /* properties_provided */
152 0, /* properties_destroyed */
153 0, /* todo_flags_start */
154 0, /* todo_flags_finish */
157 class pass_rl78_devirt : public rtl_opt_pass
159 public:
160 pass_rl78_devirt (gcc::context *ctxt)
161 : rtl_opt_pass (pass_data_rl78_devirt, ctxt)
165 /* opt_pass methods: */
166 virtual unsigned int execute (function *)
168 rl78_reorg ();
169 return 0;
172 } // anon namespace
174 rtl_opt_pass *
175 make_pass_rl78_devirt (gcc::context *ctxt)
177 return new pass_rl78_devirt (ctxt);
180 /* Redundant move elimination pass. Must be run after the basic block
181 reordering pass for the best effect. */
183 static unsigned int
184 move_elim_pass (void)
186 rtx_insn *insn, *ninsn;
187 rtx prev = NULL_RTX;
189 for (insn = get_insns (); insn; insn = ninsn)
191 rtx set;
193 ninsn = next_nonnote_nondebug_insn (insn);
195 if ((set = single_set (insn)) == NULL_RTX)
197 prev = NULL_RTX;
198 continue;
201 /* If we have two SET insns in a row (without anything
202 between them) and the source of the second one is the
203 destination of the first one, and vice versa, then we
204 can eliminate the second SET. */
205 if (prev
206 && rtx_equal_p (SET_DEST (prev), SET_SRC (set))
207 && rtx_equal_p (SET_DEST (set), SET_SRC (prev))
208 /* ... and none of the operands are volatile. */
209 && ! volatile_refs_p (SET_SRC (prev))
210 && ! volatile_refs_p (SET_DEST (prev))
211 && ! volatile_refs_p (SET_SRC (set))
212 && ! volatile_refs_p (SET_DEST (set)))
214 if (dump_file)
215 fprintf (dump_file, " Delete insn %d because it is redundant\n",
216 INSN_UID (insn));
218 delete_insn (insn);
219 prev = NULL_RTX;
221 else
222 prev = set;
225 if (dump_file)
226 print_rtl_with_bb (dump_file, get_insns (), 0);
228 return 0;
231 namespace
233 const pass_data pass_data_rl78_move_elim =
235 RTL_PASS, /* type */
236 "move_elim", /* name */
237 OPTGROUP_NONE, /* optinfo_flags */
238 TV_MACH_DEP, /* tv_id */
239 0, /* properties_required */
240 0, /* properties_provided */
241 0, /* properties_destroyed */
242 0, /* todo_flags_start */
243 0, /* todo_flags_finish */
246 class pass_rl78_move_elim : public rtl_opt_pass
248 public:
249 pass_rl78_move_elim (gcc::context *ctxt)
250 : rtl_opt_pass (pass_data_rl78_move_elim, ctxt)
254 /* opt_pass methods: */
255 virtual unsigned int execute (function *) { return move_elim_pass (); }
257 } // anon namespace
259 rtl_opt_pass *
260 make_pass_rl78_move_elim (gcc::context *ctxt)
262 return new pass_rl78_move_elim (ctxt);
265 #undef TARGET_ASM_FILE_START
266 #define TARGET_ASM_FILE_START rl78_asm_file_start
268 static void
269 rl78_asm_file_start (void)
271 int i;
273 if (TARGET_G10)
275 /* The memory used is 0xffec8 to 0xffedf; real registers are in
276 0xffee0 to 0xffee7. */
277 for (i = 8; i < 32; i++)
278 fprintf (asm_out_file, "r%d\t=\t0x%x\n", i, 0xffec0 + i);
280 else
282 for (i = 0; i < 8; i++)
284 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 8 + i, 0xffef0 + i);
285 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 16 + i, 0xffee8 + i);
286 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 24 + i, 0xffee0 + i);
290 opt_pass *rl78_devirt_pass = make_pass_rl78_devirt (g);
291 struct register_pass_info rl78_devirt_info =
293 rl78_devirt_pass,
294 "pro_and_epilogue",
296 PASS_POS_INSERT_BEFORE
299 opt_pass *rl78_move_elim_pass = make_pass_rl78_move_elim (g);
300 struct register_pass_info rl78_move_elim_info =
302 rl78_move_elim_pass,
303 "bbro",
305 PASS_POS_INSERT_AFTER
308 register_pass (& rl78_devirt_info);
309 register_pass (& rl78_move_elim_info);
312 void
313 rl78_output_symbol_ref (FILE * file, rtx sym)
315 tree type = SYMBOL_REF_DECL (sym);
316 const char *str = XSTR (sym, 0);
318 if (str[0] == '*')
320 fputs (str + 1, file);
322 else
324 str = rl78_strip_nonasm_name_encoding (str);
325 if (type && TREE_CODE (type) == FUNCTION_DECL)
327 fprintf (file, "%%code(");
328 assemble_name (file, str);
329 fprintf (file, ")");
331 else
332 assemble_name (file, str);
336 #undef TARGET_OPTION_OVERRIDE
337 #define TARGET_OPTION_OVERRIDE rl78_option_override
339 #define MUST_SAVE_MDUC_REGISTERS \
340 (TARGET_SAVE_MDUC_REGISTERS \
341 && (is_interrupt_func (NULL_TREE)) && RL78_MUL_G13)
343 static void
344 rl78_option_override (void)
346 flag_omit_frame_pointer = 1;
347 flag_no_function_cse = 1;
348 flag_split_wide_types = 0;
350 init_machine_status = rl78_init_machine_status;
352 if (TARGET_ALLREGS)
354 int i;
356 for (i = 24; i < 32; i++)
357 fixed_regs[i] = 0;
360 if (TARGET_ES0
361 && strcmp (lang_hooks.name, "GNU C")
362 && strcmp (lang_hooks.name, "GNU C11")
363 && strcmp (lang_hooks.name, "GNU C17")
364 && strcmp (lang_hooks.name, "GNU C89")
365 && strcmp (lang_hooks.name, "GNU C99")
366 /* Compiling with -flto results in a language of GNU GIMPLE being used... */
367 && strcmp (lang_hooks.name, "GNU GIMPLE"))
368 /* Address spaces are currently only supported by C. */
369 error ("-mes0 can only be used with C");
371 if (TARGET_SAVE_MDUC_REGISTERS && !(TARGET_G13 || RL78_MUL_G13))
372 warning (0, "mduc registers only saved for G13 target");
374 switch (rl78_cpu_type)
376 case CPU_UNINIT:
377 rl78_cpu_type = CPU_G14;
378 if (rl78_mul_type == MUL_UNINIT)
379 rl78_mul_type = MUL_NONE;
380 break;
382 case CPU_G10:
383 switch (rl78_mul_type)
385 case MUL_UNINIT: rl78_mul_type = MUL_NONE; break;
386 case MUL_NONE: break;
387 case MUL_G13: error ("-mmul=g13 cannot be used with -mcpu=g10"); break;
388 case MUL_G14: error ("-mmul=g14 cannot be used with -mcpu=g10"); break;
390 break;
392 case CPU_G13:
393 switch (rl78_mul_type)
395 case MUL_UNINIT: rl78_mul_type = MUL_G13; break;
396 case MUL_NONE: break;
397 case MUL_G13: break;
398 /* The S2 core does not have mul/div instructions. */
399 case MUL_G14: error ("-mmul=g14 cannot be used with -mcpu=g13"); break;
401 break;
403 case CPU_G14:
404 switch (rl78_mul_type)
406 case MUL_UNINIT: rl78_mul_type = MUL_G14; break;
407 case MUL_NONE: break;
408 case MUL_G14: break;
409 /* The G14 core does not have the hardware multiply peripheral used by the
410 G13 core, hence you cannot use G13 multipliy routines on G14 hardware. */
411 case MUL_G13: error ("-mmul=g13 cannot be used with -mcpu=g14"); break;
413 break;
417 /* Most registers are 8 bits. Some are 16 bits because, for example,
418 gcc doesn't like dealing with $FP as a register pair (the second
419 half of $fp is also 2 to keep reload happy wrt register pairs, but
420 no register class includes it). This table maps register numbers
421 to size in bytes. */
422 static const int register_sizes[] =
424 1, 1, 1, 1, 1, 1, 1, 1,
425 1, 1, 1, 1, 1, 1, 1, 1,
426 1, 1, 1, 1, 1, 1, 2, 2,
427 1, 1, 1, 1, 1, 1, 1, 1,
428 2, 2, 1, 1, 1
431 /* Predicates used in the MD patterns. This one is true when virtual
432 insns may be matched, which typically means before (or during) the
433 devirt pass. */
434 bool
435 rl78_virt_insns_ok (void)
437 if (cfun)
438 return cfun->machine->virt_insns_ok;
439 return true;
442 /* Predicates used in the MD patterns. This one is true when real
443 insns may be matched, which typically means after (or during) the
444 devirt pass. */
445 bool
446 rl78_real_insns_ok (void)
448 if (cfun)
449 return cfun->machine->real_insns_ok;
450 return false;
453 #undef TARGET_HARD_REGNO_NREGS
454 #define TARGET_HARD_REGNO_NREGS rl78_hard_regno_nregs
456 static unsigned int
457 rl78_hard_regno_nregs (unsigned int regno, machine_mode mode)
459 int rs = register_sizes[regno];
460 if (rs < 1)
461 rs = 1;
462 return ((GET_MODE_SIZE (mode) + rs - 1) / rs);
465 #undef TARGET_HARD_REGNO_MODE_OK
466 #define TARGET_HARD_REGNO_MODE_OK rl78_hard_regno_mode_ok
468 static bool
469 rl78_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
471 int s = GET_MODE_SIZE (mode);
473 if (s < 1)
474 return false;
475 /* These are not to be used by gcc. */
476 if (regno == 23 || regno == ES_REG || regno == CS_REG)
477 return false;
478 /* $fp can always be accessed as a 16-bit value. */
479 if (regno == FP_REG && s == 2)
480 return true;
481 if (regno < SP_REG)
483 /* Since a reg-reg move is really a reg-mem move, we must
484 enforce alignment. */
485 if (s > 1 && (regno % 2))
486 return false;
487 return true;
489 if (s == CC_REGNUM)
490 return (mode == BImode);
491 /* All other registers must be accessed in their natural sizes. */
492 if (s == register_sizes [regno])
493 return true;
494 return false;
497 #undef TARGET_MODES_TIEABLE_P
498 #define TARGET_MODES_TIEABLE_P rl78_modes_tieable_p
500 static bool
501 rl78_modes_tieable_p (machine_mode mode1, machine_mode mode2)
503 return ((GET_MODE_CLASS (mode1) == MODE_FLOAT
504 || GET_MODE_CLASS (mode1) == MODE_COMPLEX_FLOAT)
505 == (GET_MODE_CLASS (mode2) == MODE_FLOAT
506 || GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
509 /* Simplify_gen_subreg() doesn't handle memory references the way we
510 need it to below, so we use this function for when we must get a
511 valid subreg in a "natural" state. */
512 static rtx
513 rl78_subreg (machine_mode mode, rtx r, machine_mode omode, int byte)
515 if (GET_CODE (r) == MEM)
516 return adjust_address (r, mode, byte);
517 else
518 return simplify_gen_subreg (mode, r, omode, byte);
521 /* Used by movsi. Split SImode moves into two HImode moves, using
522 appropriate patterns for the upper and lower halves of symbols. */
523 void
524 rl78_expand_movsi (rtx *operands)
526 rtx op00, op02, op10, op12;
528 op00 = rl78_subreg (HImode, operands[0], SImode, 0);
529 op02 = rl78_subreg (HImode, operands[0], SImode, 2);
530 if (GET_CODE (operands[1]) == CONST
531 || GET_CODE (operands[1]) == SYMBOL_REF)
533 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
534 op10 = gen_rtx_CONST (HImode, op10);
535 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
536 op12 = gen_rtx_CONST (HImode, op12);
538 else
540 op10 = rl78_subreg (HImode, operands[1], SImode, 0);
541 op12 = rl78_subreg (HImode, operands[1], SImode, 2);
544 if (rtx_equal_p (operands[0], operands[1]))
546 else if (rtx_equal_p (op00, op12))
548 emit_move_insn (op02, op12);
549 emit_move_insn (op00, op10);
551 else
553 emit_move_insn (op00, op10);
554 emit_move_insn (op02, op12);
558 /* Generate code to move an SImode value. */
559 void
560 rl78_split_movsi (rtx *operands, machine_mode omode)
562 rtx op00, op02, op10, op12;
564 op00 = rl78_subreg (HImode, operands[0], omode, 0);
565 op02 = rl78_subreg (HImode, operands[0], omode, 2);
567 if (GET_CODE (operands[1]) == CONST
568 || GET_CODE (operands[1]) == SYMBOL_REF)
570 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
571 op10 = gen_rtx_CONST (HImode, op10);
572 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
573 op12 = gen_rtx_CONST (HImode, op12);
575 else
577 op10 = rl78_subreg (HImode, operands[1], omode, 0);
578 op12 = rl78_subreg (HImode, operands[1], omode, 2);
581 if (rtx_equal_p (operands[0], operands[1]))
583 else if (rtx_equal_p (op00, op12))
585 operands[2] = op02;
586 operands[4] = op12;
587 operands[3] = op00;
588 operands[5] = op10;
590 else
592 operands[2] = op00;
593 operands[4] = op10;
594 operands[3] = op02;
595 operands[5] = op12;
599 /* Used by various two-operand expanders which cannot accept all
600 operands in the "far" namespace. Force some such operands into
601 registers so that each pattern has at most one far operand. */
603 rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx))
605 int did = 0;
606 rtx temp_reg = NULL;
608 /* FIXME: in the future, be smarter about only doing this if the
609 other operand is also far, assuming the devirtualizer can also
610 handle that. */
611 if (rl78_far_p (operands[0]))
613 temp_reg = operands[0];
614 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
615 did = 1;
617 if (!did)
618 return 0;
620 emit_insn (gen (operands[0], operands[1]));
621 if (temp_reg)
622 emit_move_insn (temp_reg, operands[0]);
623 return 1;
626 /* Likewise, but for three-operand expanders. */
628 rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx))
630 int did = 0;
631 rtx temp_reg = NULL;
633 /* FIXME: Likewise. */
634 if (rl78_far_p (operands[1]))
636 rtx temp_reg = gen_reg_rtx (GET_MODE (operands[1]));
637 emit_move_insn (temp_reg, operands[1]);
638 operands[1] = temp_reg;
639 did = 1;
641 if (rl78_far_p (operands[0]))
643 temp_reg = operands[0];
644 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
645 did = 1;
647 if (!did)
648 return 0;
650 emit_insn (gen (operands[0], operands[1], operands[2]));
651 if (temp_reg)
652 emit_move_insn (temp_reg, operands[0]);
653 return 1;
657 rl78_one_far_p (rtx *operands, int n)
659 rtx which = NULL;
660 int i, c = 0;
662 for (i = 0; i < n; i ++)
663 if (rl78_far_p (operands[i]))
665 if (which == NULL)
666 which = operands[i];
667 else if (rtx_equal_p (operands[i], which))
668 continue;
669 c ++;
671 return c <= 1;
674 #undef TARGET_CAN_ELIMINATE
675 #define TARGET_CAN_ELIMINATE rl78_can_eliminate
677 static bool
678 rl78_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to ATTRIBUTE_UNUSED)
680 return true;
683 /* Returns true if the given register needs to be saved by the
684 current function. */
685 static bool
686 need_to_save (unsigned int regno)
688 if (is_interrupt_func (cfun->decl))
690 /* We don't know what devirt will need */
691 if (regno < 8)
692 return true;
694 /* We don't need to save registers that have
695 been reserved for interrupt handlers. */
696 if (regno > 23)
697 return false;
699 /* If the handler is a non-leaf function then it may call
700 non-interrupt aware routines which will happily clobber
701 any call_used registers, so we have to preserve them.
702 We do not have to worry about the frame pointer register
703 though, as that is handled below. */
704 if (!crtl->is_leaf && call_used_regs[regno] && regno < 22)
705 return true;
707 /* Otherwise we only have to save a register, call_used
708 or not, if it is used by this handler. */
709 return df_regs_ever_live_p (regno);
712 if (regno == FRAME_POINTER_REGNUM
713 && (frame_pointer_needed || df_regs_ever_live_p (regno)))
714 return true;
715 if (fixed_regs[regno])
716 return false;
717 if (crtl->calls_eh_return)
718 return true;
719 if (df_regs_ever_live_p (regno)
720 && !call_used_regs[regno])
721 return true;
722 return false;
725 /* We use this to wrap all emitted insns in the prologue. */
726 static rtx
727 F (rtx x)
729 RTX_FRAME_RELATED_P (x) = 1;
730 return x;
733 /* Compute all the frame-related fields in our machine_function
734 structure. */
735 static void
736 rl78_compute_frame_info (void)
738 int i;
740 cfun->machine->computed = 1;
741 cfun->machine->framesize_regs = 0;
742 cfun->machine->framesize_locals = get_frame_size ();
743 cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
745 for (i = 0; i < 16; i ++)
746 if (need_to_save (i * 2) || need_to_save (i * 2 + 1))
748 cfun->machine->need_to_push [i] = 1;
749 cfun->machine->framesize_regs += 2;
751 else
752 cfun->machine->need_to_push [i] = 0;
754 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
755 cfun->machine->framesize_locals ++;
757 cfun->machine->framesize = (cfun->machine->framesize_regs
758 + cfun->machine->framesize_locals
759 + cfun->machine->framesize_outgoing);
762 /* Returns true if the provided function has the specified attribute. */
763 static inline bool
764 has_func_attr (const_tree decl, const char * func_attr)
766 if (decl == NULL_TREE)
767 decl = current_function_decl;
769 return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
772 /* Returns true if the provided function has the "interrupt" attribute. */
773 static inline bool
774 is_interrupt_func (const_tree decl)
776 return has_func_attr (decl, "interrupt") || has_func_attr (decl, "brk_interrupt");
779 /* Returns true if the provided function has the "brk_interrupt" attribute. */
780 static inline bool
781 is_brk_interrupt_func (const_tree decl)
783 return has_func_attr (decl, "brk_interrupt");
786 /* Check "interrupt" attributes. */
787 static tree
788 rl78_handle_func_attribute (tree * node,
789 tree name,
790 tree args,
791 int flags ATTRIBUTE_UNUSED,
792 bool * no_add_attrs)
794 gcc_assert (DECL_P (* node));
795 gcc_assert (args == NULL_TREE);
797 if (TREE_CODE (* node) != FUNCTION_DECL)
799 warning (OPT_Wattributes, "%qE attribute only applies to functions",
800 name);
801 * no_add_attrs = true;
804 /* FIXME: We ought to check that the interrupt and exception
805 handler attributes have been applied to void functions. */
806 return NULL_TREE;
809 /* Check "naked" attributes. */
810 static tree
811 rl78_handle_naked_attribute (tree * node,
812 tree name ATTRIBUTE_UNUSED,
813 tree args,
814 int flags ATTRIBUTE_UNUSED,
815 bool * no_add_attrs)
817 gcc_assert (DECL_P (* node));
818 gcc_assert (args == NULL_TREE);
820 if (TREE_CODE (* node) != FUNCTION_DECL)
822 warning (OPT_Wattributes, "naked attribute only applies to functions");
823 * no_add_attrs = true;
826 /* Disable warnings about this function - eg reaching the end without
827 seeing a return statement - because the programmer is doing things
828 that gcc does not know about. */
829 TREE_NO_WARNING (* node) = 1;
831 return NULL_TREE;
834 /* Check "saddr" attributes. */
835 static tree
836 rl78_handle_saddr_attribute (tree * node,
837 tree name,
838 tree args ATTRIBUTE_UNUSED,
839 int flags ATTRIBUTE_UNUSED,
840 bool * no_add_attrs)
842 gcc_assert (DECL_P (* node));
844 if (TREE_CODE (* node) == FUNCTION_DECL)
846 warning (OPT_Wattributes, "%qE attribute doesn't apply to functions",
847 name);
848 * no_add_attrs = true;
851 return NULL_TREE;
854 #undef TARGET_ATTRIBUTE_TABLE
855 #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
857 /* Table of RL78-specific attributes. */
858 const struct attribute_spec rl78_attribute_table[] =
860 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
861 affects_type_identity. */
862 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
863 false, NULL },
864 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
865 false, NULL },
866 { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute,
867 false, NULL },
868 { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute,
869 false, NULL },
870 { NULL, 0, 0, false, false, false, NULL, false, NULL }
875 /* Break down an address RTX into its component base/index/addend
876 portions and return TRUE if the address is of a valid form, else
877 FALSE. */
878 static bool
879 characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
881 *base = NULL_RTX;
882 *index = NULL_RTX;
883 *addend = NULL_RTX;
885 if (GET_CODE (x) == UNSPEC
886 && XINT (x, 1) == UNS_ES_ADDR)
887 x = XVECEXP (x, 0, 1);
889 if (GET_CODE (x) == REG)
891 *base = x;
892 return true;
895 /* We sometimes get these without the CONST wrapper */
896 if (GET_CODE (x) == PLUS
897 && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
898 && GET_CODE (XEXP (x, 1)) == CONST_INT)
900 *addend = x;
901 return true;
904 if (GET_CODE (x) == PLUS)
906 *base = XEXP (x, 0);
907 x = XEXP (x, 1);
909 if (GET_CODE (*base) == SUBREG)
911 if (GET_MODE (*base) == HImode
912 && GET_MODE (XEXP (*base, 0)) == SImode
913 && GET_CODE (XEXP (*base, 0)) == REG)
915 /* This is a throw-away rtx just to tell everyone
916 else what effective register we're using. */
917 *base = gen_rtx_REG (HImode, REGNO (XEXP (*base, 0)));
921 if (GET_CODE (*base) != REG
922 && GET_CODE (x) == REG)
924 rtx tmp = *base;
925 *base = x;
926 x = tmp;
929 if (GET_CODE (*base) != REG)
930 return false;
932 if (GET_CODE (x) == ZERO_EXTEND
933 && GET_CODE (XEXP (x, 0)) == REG)
935 *index = XEXP (x, 0);
936 return false;
940 switch (GET_CODE (x))
942 case PLUS:
943 if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
944 && GET_CODE (XEXP (x, 0)) == CONST_INT)
946 *addend = x;
947 return true;
949 /* fall through */
950 case MEM:
951 case REG:
952 return false;
954 case SUBREG:
955 switch (GET_CODE (XEXP (x, 0)))
957 case CONST:
958 case SYMBOL_REF:
959 case CONST_INT:
960 *addend = x;
961 return true;
962 default:
963 return false;
966 case CONST:
967 case SYMBOL_REF:
968 case CONST_INT:
969 *addend = x;
970 return true;
972 default:
973 return false;
976 return false;
979 /* Used by the Whb constraint. Match addresses that use HL+B or HL+C
980 addressing. */
981 bool
982 rl78_hl_b_c_addr_p (rtx op)
984 rtx hl, bc;
986 if (GET_CODE (op) != PLUS)
987 return false;
988 hl = XEXP (op, 0);
989 bc = XEXP (op, 1);
990 if (GET_CODE (hl) == ZERO_EXTEND)
992 rtx tmp = hl;
993 hl = bc;
994 bc = tmp;
996 if (GET_CODE (hl) != REG)
997 return false;
998 if (GET_CODE (bc) != ZERO_EXTEND)
999 return false;
1000 bc = XEXP (bc, 0);
1001 if (GET_CODE (bc) != REG)
1002 return false;
1003 if (REGNO (hl) != HL_REG)
1004 return false;
1005 if (REGNO (bc) != B_REG && REGNO (bc) != C_REG)
1006 return false;
1008 return true;
1011 #define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
1013 /* Return the appropriate mode for a named address address. */
1015 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
1016 #define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
1018 static scalar_int_mode
1019 rl78_addr_space_address_mode (addr_space_t addrspace)
1021 switch (addrspace)
1023 case ADDR_SPACE_GENERIC:
1024 return HImode;
1025 case ADDR_SPACE_NEAR:
1026 return HImode;
1027 case ADDR_SPACE_FAR:
1028 return SImode;
1029 default:
1030 gcc_unreachable ();
1034 /* Used in various constraints and predicates to match operands in the
1035 "far" address space. */
1037 rl78_far_p (rtx x)
1039 if (! MEM_P (x))
1040 return 0;
1041 #if DEBUG0
1042 fprintf (stderr, "\033[35mrl78_far_p: "); debug_rtx (x);
1043 fprintf (stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
1044 #endif
1046 /* Not all far addresses are legitimate, because the devirtualizer
1047 can't handle them. */
1048 if (! rl78_as_legitimate_address (GET_MODE (x), XEXP (x, 0), false, ADDR_SPACE_FAR))
1049 return 0;
1051 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x))) == 32;
1054 /* Return the appropriate mode for a named address pointer. */
1055 #undef TARGET_ADDR_SPACE_POINTER_MODE
1056 #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
1058 static scalar_int_mode
1059 rl78_addr_space_pointer_mode (addr_space_t addrspace)
1061 switch (addrspace)
1063 case ADDR_SPACE_GENERIC:
1064 return HImode;
1065 case ADDR_SPACE_NEAR:
1066 return HImode;
1067 case ADDR_SPACE_FAR:
1068 return SImode;
1069 default:
1070 gcc_unreachable ();
1074 /* Returns TRUE for valid addresses. */
1075 #undef TARGET_VALID_POINTER_MODE
1076 #define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
1078 static bool
1079 rl78_valid_pointer_mode (scalar_int_mode m)
1081 return (m == HImode || m == SImode);
1084 #undef TARGET_LEGITIMATE_CONSTANT_P
1085 #define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
1087 static bool
1088 rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED)
1090 return true;
1093 #undef TARGET_LRA_P
1094 #define TARGET_LRA_P hook_bool_void_false
1096 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
1097 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
1099 bool
1100 rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
1101 bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
1103 rtx base, index, addend;
1104 bool is_far_addr = false;
1105 int as_bits;
1107 as_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (as));
1109 if (GET_CODE (x) == UNSPEC
1110 && XINT (x, 1) == UNS_ES_ADDR)
1112 x = XVECEXP (x, 0, 1);
1113 is_far_addr = true;
1116 if (as_bits == 16 && is_far_addr)
1117 return false;
1119 if (! characterize_address (x, &base, &index, &addend))
1120 return false;
1122 /* We can't extract the high/low portions of a PLUS address
1123 involving a register during devirtualization, so make sure all
1124 such __far addresses do not have addends. This forces GCC to do
1125 the sum separately. */
1126 if (addend && base && as_bits == 32 && GET_MODE (base) == SImode)
1127 return false;
1129 if (base && index)
1131 int ir = REGNO (index);
1132 int br = REGNO (base);
1134 #define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
1135 OK (REG_IS (br, HL_REG) && REG_IS (ir, B_REG), "[hl+b]");
1136 OK (REG_IS (br, HL_REG) && REG_IS (ir, C_REG), "[hl+c]");
1137 return false;
1140 if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER)
1141 return false;
1143 if (! cfun->machine->virt_insns_ok && base && GET_CODE (base) == REG
1144 && REGNO (base) >= 8 && REGNO (base) <= 31)
1145 return false;
1147 return true;
1150 /* Determine if one named address space is a subset of another. */
1151 #undef TARGET_ADDR_SPACE_SUBSET_P
1152 #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
1154 static bool
1155 rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
1157 int subset_bits;
1158 int superset_bits;
1160 subset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset));
1161 superset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset));
1163 return (subset_bits <= superset_bits);
1166 #undef TARGET_ADDR_SPACE_CONVERT
1167 #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
1169 /* Convert from one address space to another. */
1170 static rtx
1171 rl78_addr_space_convert (rtx op, tree from_type, tree to_type)
1173 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
1174 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
1175 rtx result;
1176 int to_bits;
1177 int from_bits;
1179 to_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as));
1180 from_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as));
1182 if (to_bits < from_bits)
1184 rtx tmp;
1185 /* This is unpredictable, as we're truncating off usable address
1186 bits. */
1188 warning (OPT_Waddress, "converting far pointer to near pointer");
1189 result = gen_reg_rtx (HImode);
1190 if (GET_CODE (op) == SYMBOL_REF
1191 || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER))
1192 tmp = gen_rtx_raw_SUBREG (HImode, op, 0);
1193 else
1194 tmp = simplify_subreg (HImode, op, SImode, 0);
1195 gcc_assert (tmp != NULL_RTX);
1196 emit_move_insn (result, tmp);
1197 return result;
1199 else if (to_bits > from_bits)
1201 /* This always works. */
1202 result = gen_reg_rtx (SImode);
1203 emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op);
1204 if (TREE_CODE (from_type) == POINTER_TYPE
1205 && TREE_CODE (TREE_TYPE (from_type)) == FUNCTION_TYPE)
1206 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx);
1207 else
1208 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), GEN_INT (0x0f));
1209 return result;
1211 else
1212 return op;
1213 gcc_unreachable ();
1216 /* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
1217 bool
1218 rl78_regno_mode_code_ok_for_base_p (int regno, machine_mode mode ATTRIBUTE_UNUSED,
1219 addr_space_t address_space ATTRIBUTE_UNUSED,
1220 int outer_code ATTRIBUTE_UNUSED, int index_code)
1222 if (regno <= SP_REG && regno >= 16)
1223 return true;
1224 if (index_code == REG)
1225 return (regno == HL_REG);
1226 if (regno == C_REG || regno == B_REG || regno == E_REG || regno == L_REG)
1227 return true;
1228 return false;
1231 /* Implements MODE_CODE_BASE_REG_CLASS. */
1232 enum reg_class
1233 rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED,
1234 addr_space_t address_space ATTRIBUTE_UNUSED,
1235 int outer_code ATTRIBUTE_UNUSED,
1236 int index_code ATTRIBUTE_UNUSED)
1238 return V_REGS;
1241 /* Typical stack layout should looks like this after the function's prologue:
1244 -- ^
1245 | | \ |
1246 | | arguments saved | Increasing
1247 | | on the stack | addresses
1248 PARENT arg pointer -> | | /
1249 -------------------------- ---- -------------------
1250 CHILD |ret | return address
1252 | | \
1253 | | call saved
1254 | | registers
1255 frame pointer -> | | /
1257 | | \
1258 | | local
1259 | | variables
1260 | | /
1262 | | \
1263 | | outgoing | Decreasing
1264 | | arguments | addresses
1265 current stack pointer -> | | / |
1266 -------------------------- ---- ------------------ V
1267 | | */
1269 /* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
1270 described in the machine_Function struct definition, above. */
1272 rl78_initial_elimination_offset (int from, int to)
1274 int rv = 0; /* as if arg to arg */
1276 rl78_compute_frame_info ();
1278 switch (to)
1280 case STACK_POINTER_REGNUM:
1281 rv += cfun->machine->framesize_outgoing;
1282 rv += cfun->machine->framesize_locals;
1283 /* Fall through. */
1284 case FRAME_POINTER_REGNUM:
1285 rv += cfun->machine->framesize_regs;
1286 rv += 4;
1287 break;
1288 default:
1289 gcc_unreachable ();
1292 switch (from)
1294 case FRAME_POINTER_REGNUM:
1295 rv -= 4;
1296 rv -= cfun->machine->framesize_regs;
1297 case ARG_POINTER_REGNUM:
1298 break;
1299 default:
1300 gcc_unreachable ();
1303 return rv;
1306 static bool
1307 rl78_is_naked_func (void)
1309 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE);
1312 /* Check if the block uses mul/div insns for G13 target. */
1314 static bool
1315 check_mduc_usage (void)
1317 rtx_insn * insn;
1318 basic_block bb;
1320 FOR_EACH_BB_FN (bb, cfun)
1322 FOR_BB_INSNS (bb, insn)
1324 if (INSN_P (insn)
1325 && (get_attr_is_g13_muldiv_insn (insn) == IS_G13_MULDIV_INSN_YES))
1326 return true;
1329 return false;
1332 /* Expand the function prologue (from the prologue pattern). */
1334 void
1335 rl78_expand_prologue (void)
1337 int i, fs;
1338 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
1339 rtx ax = gen_rtx_REG (HImode, AX_REG);
1340 int rb = 0;
1342 if (rl78_is_naked_func ())
1343 return;
1345 /* Always re-compute the frame info - the register usage may have changed. */
1346 rl78_compute_frame_info ();
1348 if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ()))
1349 cfun->machine->framesize += ARRAY_SIZE (mduc_regs) * 2;
1351 if (flag_stack_usage_info)
1352 current_function_static_stack_size = cfun->machine->framesize;
1354 if (is_interrupt_func (cfun->decl) && !TARGET_G10)
1355 for (i = 0; i < 4; i++)
1356 if (cfun->machine->need_to_push [i])
1358 /* Select Bank 0 if we are using any registers from Bank 0. */
1359 emit_insn (gen_sel_rb (GEN_INT (0)));
1360 break;
1363 for (i = 0; i < 16; i++)
1364 if (cfun->machine->need_to_push [i])
1366 int reg = i * 2;
1368 if (TARGET_G10)
1370 if (reg >= 8)
1372 emit_move_insn (ax, gen_rtx_REG (HImode, reg));
1373 reg = AX_REG;
1376 else
1378 int need_bank = i/4;
1380 if (need_bank != rb)
1382 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1383 rb = need_bank;
1387 F (emit_insn (gen_push (gen_rtx_REG (HImode, reg))));
1390 if (rb != 0)
1391 emit_insn (gen_sel_rb (GEN_INT (0)));
1393 /* Save ES register inside interrupt functions if it is used. */
1394 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
1396 emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode, A_REG)));
1397 F (emit_insn (gen_push (ax)));
1400 /* Save MDUC registers inside interrupt routine. */
1401 if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ()))
1403 for (unsigned i = 0; i < ARRAY_SIZE (mduc_regs); i++)
1405 mduc_reg_type *reg = mduc_regs + i;
1406 rtx mem_mduc = gen_rtx_MEM (reg->mode, GEN_INT (reg->address));
1408 MEM_VOLATILE_P (mem_mduc) = 1;
1409 if (reg->mode == QImode)
1410 emit_insn (gen_movqi (gen_rtx_REG (QImode, A_REG), mem_mduc));
1411 else
1412 emit_insn (gen_movhi (gen_rtx_REG (HImode, AX_REG), mem_mduc));
1414 emit_insn (gen_push (gen_rtx_REG (HImode, AX_REG)));
1418 if (frame_pointer_needed)
1420 F (emit_move_insn (ax, sp));
1421 F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM), ax));
1424 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1425 if (fs > 0)
1427 /* If we need to subtract more than 254*3 then it is faster and
1428 smaller to move SP into AX and perform the subtraction there. */
1429 if (fs > 254 * 3)
1431 rtx insn;
1433 emit_move_insn (ax, sp);
1434 emit_insn (gen_subhi3 (ax, ax, GEN_INT (fs)));
1435 insn = F (emit_move_insn (sp, ax));
1436 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
1437 gen_rtx_SET (sp, gen_rtx_PLUS (HImode, sp,
1438 GEN_INT (-fs))));
1440 else
1442 while (fs > 0)
1444 int fs_byte = (fs > 254) ? 254 : fs;
1446 F (emit_insn (gen_subhi3 (sp, sp, GEN_INT (fs_byte))));
1447 fs -= fs_byte;
1453 /* Expand the function epilogue (from the epilogue pattern). */
1454 void
1455 rl78_expand_epilogue (void)
1457 int i, fs;
1458 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
1459 rtx ax = gen_rtx_REG (HImode, AX_REG);
1460 int rb = 0;
1462 if (rl78_is_naked_func ())
1463 return;
1465 if (frame_pointer_needed)
1467 emit_move_insn (ax, gen_rtx_REG (HImode, FRAME_POINTER_REGNUM));
1468 emit_move_insn (sp, ax);
1470 else
1472 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1473 if (fs > 254 * 3)
1475 emit_move_insn (ax, sp);
1476 emit_insn (gen_addhi3 (ax, ax, GEN_INT (fs)));
1477 emit_move_insn (sp, ax);
1479 else
1481 while (fs > 0)
1483 int fs_byte = (fs > 254) ? 254 : fs;
1485 emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte)));
1486 fs -= fs_byte;
1491 /* Restore MDUC registers from interrupt routine. */
1492 if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ()))
1494 for (int i = ARRAY_SIZE (mduc_regs) - 1; i >= 0; i--)
1496 mduc_reg_type *reg = mduc_regs + i;
1497 rtx mem_mduc = gen_rtx_MEM (reg->mode, GEN_INT (reg->address));
1499 emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG)));
1500 MEM_VOLATILE_P (mem_mduc) = 1;
1501 if (reg->mode == QImode)
1502 emit_insn (gen_movqi (mem_mduc, gen_rtx_REG (QImode, A_REG)));
1503 else
1504 emit_insn (gen_movhi (mem_mduc, gen_rtx_REG (HImode, AX_REG)));
1508 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
1510 emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG)));
1511 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode, A_REG)));
1514 for (i = 15; i >= 0; i--)
1515 if (cfun->machine->need_to_push [i])
1517 rtx dest = gen_rtx_REG (HImode, i * 2);
1519 if (TARGET_G10)
1521 if (i < 8)
1522 emit_insn (gen_pop (dest));
1523 else
1525 emit_insn (gen_pop (ax));
1526 emit_move_insn (dest, ax);
1527 /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */
1528 emit_insn (gen_use (dest));
1531 else
1533 int need_bank = i / 4;
1535 if (need_bank != rb)
1537 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1538 rb = need_bank;
1540 emit_insn (gen_pop (dest));
1544 if (rb != 0)
1545 emit_insn (gen_sel_rb (GEN_INT (0)));
1547 if (cfun->machine->trampolines_used)
1548 emit_insn (gen_trampoline_uninit ());
1550 if (is_brk_interrupt_func (cfun->decl))
1551 emit_jump_insn (gen_brk_interrupt_return ());
1552 else if (is_interrupt_func (cfun->decl))
1553 emit_jump_insn (gen_interrupt_return ());
1554 else
1555 emit_jump_insn (gen_rl78_return ());
1558 /* Likewise, for exception handlers. */
1559 void
1560 rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED)
1562 /* FIXME - replace this with an indirect jump with stack adjust. */
1563 emit_jump_insn (gen_rl78_return ());
1566 #undef TARGET_ASM_FUNCTION_PROLOGUE
1567 #define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1569 /* We don't use this to actually emit the function prologue. We use
1570 this to insert a comment in the asm file describing the
1571 function. */
1572 static void
1573 rl78_start_function (FILE *file)
1575 int i;
1577 if (cfun->machine->framesize == 0)
1578 return;
1579 fprintf (file, "\t; start of function\n");
1581 if (cfun->machine->framesize_regs)
1583 fprintf (file, "\t; push %d:", cfun->machine->framesize_regs);
1584 for (i = 0; i < 16; i ++)
1585 if (cfun->machine->need_to_push[i])
1586 fprintf (file, " %s", word_regnames[i*2]);
1587 fprintf (file, "\n");
1590 if (frame_pointer_needed)
1591 fprintf (file, "\t; $fp points here (r22)\n");
1593 if (cfun->machine->framesize_locals)
1594 fprintf (file, "\t; locals: %d byte%s\n", cfun->machine->framesize_locals,
1595 cfun->machine->framesize_locals == 1 ? "" : "s");
1597 if (cfun->machine->framesize_outgoing)
1598 fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing,
1599 cfun->machine->framesize_outgoing == 1 ? "" : "s");
1601 if (cfun->machine->uses_es)
1602 fprintf (file, "\t; uses ES register\n");
1604 if (MUST_SAVE_MDUC_REGISTERS)
1605 fprintf (file, "\t; preserves MDUC registers\n");
1608 /* Return an RTL describing where a function return value of type RET_TYPE
1609 is held. */
1611 #undef TARGET_FUNCTION_VALUE
1612 #define TARGET_FUNCTION_VALUE rl78_function_value
1614 static rtx
1615 rl78_function_value (const_tree ret_type,
1616 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1617 bool outgoing ATTRIBUTE_UNUSED)
1619 machine_mode mode = TYPE_MODE (ret_type);
1621 return gen_rtx_REG (mode, 8);
1624 #undef TARGET_PROMOTE_FUNCTION_MODE
1625 #define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
1627 static machine_mode
1628 rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
1629 machine_mode mode,
1630 int *punsignedp ATTRIBUTE_UNUSED,
1631 const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED)
1633 return mode;
1636 /* Return an RTL expression describing the register holding a function
1637 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
1638 be passed on the stack. CUM describes the previous parameters to the
1639 function and NAMED is false if the parameter is part of a variable
1640 parameter list, or the last named parameter before the start of a
1641 variable parameter list. */
1643 #undef TARGET_FUNCTION_ARG
1644 #define TARGET_FUNCTION_ARG rl78_function_arg
1646 static rtx
1647 rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
1648 machine_mode mode ATTRIBUTE_UNUSED,
1649 const_tree type ATTRIBUTE_UNUSED,
1650 bool named ATTRIBUTE_UNUSED)
1652 return NULL_RTX;
1655 #undef TARGET_FUNCTION_ARG_ADVANCE
1656 #define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1658 static void
1659 rl78_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, const_tree type,
1660 bool named ATTRIBUTE_UNUSED)
1662 int rounded_size;
1663 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
1665 rounded_size = ((mode == BLKmode)
1666 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
1667 if (rounded_size & 1)
1668 rounded_size ++;
1669 (*cum) += rounded_size;
1672 #undef TARGET_FUNCTION_ARG_BOUNDARY
1673 #define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1675 static unsigned int
1676 rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED,
1677 const_tree type ATTRIBUTE_UNUSED)
1679 return 16;
1682 /* Supported modifier letters:
1684 A - address of a MEM
1685 S - SADDR form of a real register
1686 v - real register corresponding to a virtual register
1687 m - minus - negative of CONST_INT value.
1688 C - inverse of a conditional (NE vs EQ for example)
1689 C - complement of an integer
1690 z - collapsed conditional
1691 s - shift count mod 8
1692 S - shift count mod 16
1693 r - reverse shift count (8-(count mod 8))
1694 B - bit position
1696 h - bottom HI of an SI
1697 H - top HI of an SI
1698 q - bottom QI of an HI
1699 Q - top QI of an HI
1700 e - third QI of an SI (i.e. where the ES register gets values from)
1701 E - fourth QI of an SI (i.e. MSB)
1703 p - Add +0 to a zero-indexed HL based address.
1706 /* Implements the bulk of rl78_print_operand, below. We do it this
1707 way because we need to test for a constant at the top level and
1708 insert the '#', but not test for it anywhere else as we recurse
1709 down into the operand. */
1710 static void
1711 rl78_print_operand_1 (FILE * file, rtx op, int letter)
1713 int need_paren;
1715 switch (GET_CODE (op))
1717 case MEM:
1718 if (letter == 'A')
1719 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1720 else
1722 if (rl78_far_p (op))
1724 fprintf (file, "es:");
1725 if (GET_CODE (XEXP (op, 0)) == UNSPEC)
1726 op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1));
1728 if (letter == 'H')
1730 op = adjust_address (op, HImode, 2);
1731 letter = 0;
1733 if (letter == 'h')
1735 op = adjust_address (op, HImode, 0);
1736 letter = 0;
1738 if (letter == 'Q')
1740 op = adjust_address (op, QImode, 1);
1741 letter = 0;
1743 if (letter == 'q')
1745 op = adjust_address (op, QImode, 0);
1746 letter = 0;
1748 if (letter == 'e')
1750 op = adjust_address (op, QImode, 2);
1751 letter = 0;
1753 if (letter == 'E')
1755 op = adjust_address (op, QImode, 3);
1756 letter = 0;
1758 if (CONSTANT_P (XEXP (op, 0)))
1760 if (!rl78_saddr_p (op))
1761 fprintf (file, "!");
1762 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1764 else if (GET_CODE (XEXP (op, 0)) == PLUS
1765 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF)
1767 if (!rl78_saddr_p (op))
1768 fprintf (file, "!");
1769 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1771 else if (GET_CODE (XEXP (op, 0)) == PLUS
1772 && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
1773 && REGNO (XEXP (XEXP (op, 0), 0)) == 2)
1775 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u');
1776 fprintf (file, "[");
1777 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0);
1778 if (letter == 'p' && GET_CODE (XEXP (op, 0)) == REG)
1779 fprintf (file, "+0");
1780 fprintf (file, "]");
1782 else
1784 op = XEXP (op, 0);
1785 fprintf (file, "[");
1786 rl78_print_operand_1 (file, op, letter);
1787 if (letter == 'p' && REG_P (op) && REGNO (op) == 6)
1788 fprintf (file, "+0");
1789 fprintf (file, "]");
1792 break;
1794 case REG:
1795 if (letter == 'Q')
1796 fprintf (file, "%s", reg_names [REGNO (op) | 1]);
1797 else if (letter == 'H')
1798 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1799 else if (letter == 'q')
1800 fprintf (file, "%s", reg_names [REGNO (op) & ~1]);
1801 else if (letter == 'e')
1802 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1803 else if (letter == 'E')
1804 fprintf (file, "%s", reg_names [REGNO (op) + 3]);
1805 else if (letter == 'S')
1806 fprintf (file, "0x%x", 0xffef8 + REGNO (op));
1807 else if (GET_MODE (op) == HImode
1808 && ! (REGNO (op) & ~0xfe))
1810 if (letter == 'v')
1811 fprintf (file, "%s", word_regnames [REGNO (op) % 8]);
1812 else
1813 fprintf (file, "%s", word_regnames [REGNO (op)]);
1815 else
1816 fprintf (file, "%s", reg_names [REGNO (op)]);
1817 break;
1819 case CONST_INT:
1820 if (letter == 'Q')
1821 fprintf (file, "%ld", INTVAL (op) >> 8);
1822 else if (letter == 'H')
1823 fprintf (file, "%ld", INTVAL (op) >> 16);
1824 else if (letter == 'q')
1825 fprintf (file, "%ld", INTVAL (op) & 0xff);
1826 else if (letter == 'h')
1827 fprintf (file, "%ld", INTVAL (op) & 0xffff);
1828 else if (letter == 'e')
1829 fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff);
1830 else if (letter == 'B')
1832 int ival = INTVAL (op);
1833 if (ival == -128)
1834 ival = 0x80;
1835 if (exact_log2 (ival) >= 0)
1836 fprintf (file, "%d", exact_log2 (ival));
1837 else
1838 fprintf (file, "%d", exact_log2 (~ival & 0xff));
1840 else if (letter == 'E')
1841 fprintf (file, "%ld", (INTVAL (op) >> 24) & 0xff);
1842 else if (letter == 'm')
1843 fprintf (file, "%ld", - INTVAL (op));
1844 else if (letter == 's')
1845 fprintf (file, "%ld", INTVAL (op) % 8);
1846 else if (letter == 'S')
1847 fprintf (file, "%ld", INTVAL (op) % 16);
1848 else if (letter == 'r')
1849 fprintf (file, "%ld", 8 - (INTVAL (op) % 8));
1850 else if (letter == 'C')
1851 fprintf (file, "%ld", (INTVAL (op) ^ 0x8000) & 0xffff);
1852 else
1853 fprintf (file, "%ld", INTVAL (op));
1854 break;
1856 case CONST:
1857 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1858 break;
1860 case ZERO_EXTRACT:
1862 int bits = INTVAL (XEXP (op, 1));
1863 int ofs = INTVAL (XEXP (op, 2));
1864 if (bits == 16 && ofs == 0)
1865 fprintf (file, "%%lo16(");
1866 else if (bits == 16 && ofs == 16)
1867 fprintf (file, "%%hi16(");
1868 else if (bits == 8 && ofs == 16)
1869 fprintf (file, "%%hi8(");
1870 else
1871 gcc_unreachable ();
1872 rl78_print_operand_1 (file, XEXP (op, 0), 0);
1873 fprintf (file, ")");
1875 break;
1877 case ZERO_EXTEND:
1878 if (GET_CODE (XEXP (op, 0)) == REG)
1879 fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]);
1880 else
1881 print_rtl (file, op);
1882 break;
1884 case PLUS:
1885 need_paren = 0;
1886 if (letter == 'H')
1888 fprintf (file, "%%hi16(");
1889 need_paren = 1;
1890 letter = 0;
1892 if (letter == 'h')
1894 fprintf (file, "%%lo16(");
1895 need_paren = 1;
1896 letter = 0;
1898 if (letter == 'e')
1900 fprintf (file, "%%hi8(");
1901 need_paren = 1;
1902 letter = 0;
1904 if (letter == 'q' || letter == 'Q')
1905 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1907 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
1909 if (GET_CODE (XEXP (op, 1)) == SYMBOL_REF
1910 && SYMBOL_REF_DECL (XEXP (op, 1))
1911 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op, 1))) == FUNCTION_DECL)
1913 fprintf (file, "%%code(");
1914 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op, 1), 0)));
1915 fprintf (file, "+");
1916 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1917 fprintf (file, ")");
1919 else
1921 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1922 fprintf (file, "+");
1923 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1926 else
1928 if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1929 && SYMBOL_REF_DECL (XEXP (op, 0))
1930 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op, 0))) == FUNCTION_DECL)
1932 fprintf (file, "%%code(");
1933 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op, 0), 0)));
1934 fprintf (file, "+");
1935 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1936 fprintf (file, ")");
1938 else
1940 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1941 fprintf (file, "+");
1942 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1945 if (need_paren)
1946 fprintf (file, ")");
1947 break;
1949 case SUBREG:
1950 if (GET_MODE (op) == HImode
1951 && SUBREG_BYTE (op) == 0)
1953 fprintf (file, "%%lo16(");
1954 rl78_print_operand_1 (file, SUBREG_REG (op), 0);
1955 fprintf (file, ")");
1957 else if (GET_MODE (op) == HImode
1958 && SUBREG_BYTE (op) == 2)
1960 fprintf (file, "%%hi16(");
1961 rl78_print_operand_1 (file, SUBREG_REG (op), 0);
1962 fprintf (file, ")");
1964 else
1966 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
1968 break;
1970 case SYMBOL_REF:
1971 need_paren = 0;
1972 if (letter == 'H')
1974 fprintf (file, "%%hi16(");
1975 need_paren = 1;
1976 letter = 0;
1978 if (letter == 'h')
1980 fprintf (file, "%%lo16(");
1981 need_paren = 1;
1982 letter = 0;
1984 if (letter == 'e')
1986 fprintf (file, "%%hi8(");
1987 need_paren = 1;
1988 letter = 0;
1990 if (letter == 'q' || letter == 'Q')
1991 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1993 if (SYMBOL_REF_DECL (op) && TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL)
1995 fprintf (file, "%%code(");
1996 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0)));
1997 fprintf (file, ")");
1999 else
2000 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0)));
2001 if (need_paren)
2002 fprintf (file, ")");
2003 break;
2005 case CODE_LABEL:
2006 case LABEL_REF:
2007 output_asm_label (op);
2008 break;
2010 case LTU:
2011 if (letter == 'z')
2012 fprintf (file, "#comparison eliminated");
2013 else
2014 fprintf (file, letter == 'C' ? "nc" : "c");
2015 break;
2016 case LEU:
2017 if (letter == 'z')
2018 fprintf (file, "br");
2019 else
2020 fprintf (file, letter == 'C' ? "h" : "nh");
2021 break;
2022 case GEU:
2023 if (letter == 'z')
2024 fprintf (file, "br");
2025 else
2026 fprintf (file, letter == 'C' ? "c" : "nc");
2027 break;
2028 case GTU:
2029 if (letter == 'z')
2030 fprintf (file, "#comparison eliminated");
2031 else
2032 fprintf (file, letter == 'C' ? "nh" : "h");
2033 break;
2034 case EQ:
2035 if (letter == 'z')
2036 fprintf (file, "br");
2037 else
2038 fprintf (file, letter == 'C' ? "nz" : "z");
2039 break;
2040 case NE:
2041 if (letter == 'z')
2042 fprintf (file, "#comparison eliminated");
2043 else
2044 fprintf (file, letter == 'C' ? "z" : "nz");
2045 break;
2047 /* Note: these assume appropriate adjustments were made so that
2048 unsigned comparisons, which is all this chip has, will
2049 work. */
2050 case LT:
2051 if (letter == 'z')
2052 fprintf (file, "#comparison eliminated");
2053 else
2054 fprintf (file, letter == 'C' ? "nc" : "c");
2055 break;
2056 case LE:
2057 if (letter == 'z')
2058 fprintf (file, "br");
2059 else
2060 fprintf (file, letter == 'C' ? "h" : "nh");
2061 break;
2062 case GE:
2063 if (letter == 'z')
2064 fprintf (file, "br");
2065 else
2066 fprintf (file, letter == 'C' ? "c" : "nc");
2067 break;
2068 case GT:
2069 if (letter == 'z')
2070 fprintf (file, "#comparison eliminated");
2071 else
2072 fprintf (file, letter == 'C' ? "nh" : "h");
2073 break;
2075 default:
2076 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
2077 break;
2081 #undef TARGET_PRINT_OPERAND
2082 #define TARGET_PRINT_OPERAND rl78_print_operand
2084 static void
2085 rl78_print_operand (FILE * file, rtx op, int letter)
2087 if (CONSTANT_P (op) && letter != 'u' && letter != 's' && letter != 'r' && letter != 'S' && letter != 'B')
2088 fprintf (file, "#");
2089 rl78_print_operand_1 (file, op, letter);
2092 #undef TARGET_TRAMPOLINE_INIT
2093 #define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
2095 /* Note that the RL78's addressing makes it very difficult to do
2096 trampolines on the stack. So, libgcc has a small pool of
2097 trampolines from which one is allocated to this task. */
2098 static void
2099 rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2101 rtx mov_addr, thunk_addr;
2102 rtx function = XEXP (DECL_RTL (fndecl), 0);
2104 mov_addr = adjust_address (m_tramp, HImode, 0);
2105 thunk_addr = gen_reg_rtx (HImode);
2107 function = force_reg (HImode, function);
2108 static_chain = force_reg (HImode, static_chain);
2110 emit_insn (gen_trampoline_init (thunk_addr, function, static_chain));
2111 emit_move_insn (mov_addr, thunk_addr);
2113 cfun->machine->trampolines_used = 1;
2116 #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
2117 #define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
2119 static rtx
2120 rl78_trampoline_adjust_address (rtx m_tramp)
2122 rtx x = gen_rtx_MEM (HImode, m_tramp);
2123 return x;
2126 /* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
2127 the "normal" compares, specifically, it only has unsigned compares,
2128 so we must synthesize the missing ones. */
2129 void
2130 rl78_expand_compare (rtx *operands)
2132 if (GET_CODE (operands[2]) == MEM)
2133 operands[2] = copy_to_mode_reg (GET_MODE (operands[2]), operands[2]);
2138 /* Define this to 1 if you are debugging the peephole optimizers. */
2139 #define DEBUG_PEEP 0
2141 /* Predicate used to enable the peephole2 patterns in rl78-virt.md.
2142 The default "word" size is a byte so we can effectively use all the
2143 registers, but we want to do 16-bit moves whenever possible. This
2144 function determines when such a move is an option. */
2145 bool
2146 rl78_peep_movhi_p (rtx *operands)
2148 int i;
2149 rtx m, a;
2151 /* (set (op0) (op1))
2152 (set (op2) (op3)) */
2154 if (! rl78_virt_insns_ok ())
2155 return false;
2157 #if DEBUG_PEEP
2158 fprintf (stderr, "\033[33m");
2159 debug_rtx (operands[0]);
2160 debug_rtx (operands[1]);
2161 debug_rtx (operands[2]);
2162 debug_rtx (operands[3]);
2163 fprintf (stderr, "\033[0m");
2164 #endif
2166 /* You can move a constant to memory as QImode, but not HImode. */
2167 if (GET_CODE (operands[0]) == MEM
2168 && GET_CODE (operands[1]) != REG)
2170 #if DEBUG_PEEP
2171 fprintf (stderr, "no peep: move constant to memory\n");
2172 #endif
2173 return false;
2176 if (rtx_equal_p (operands[0], operands[3]))
2178 #if DEBUG_PEEP
2179 fprintf (stderr, "no peep: overlapping\n");
2180 #endif
2181 return false;
2184 for (i = 0; i < 2; i ++)
2186 if (GET_CODE (operands[i]) != GET_CODE (operands[i+2]))
2188 #if DEBUG_PEEP
2189 fprintf (stderr, "no peep: different codes\n");
2190 #endif
2191 return false;
2193 if (GET_MODE (operands[i]) != GET_MODE (operands[i+2]))
2195 #if DEBUG_PEEP
2196 fprintf (stderr, "no peep: different modes\n");
2197 #endif
2198 return false;
2201 switch (GET_CODE (operands[i]))
2203 case REG:
2204 /* LSB MSB */
2205 if (REGNO (operands[i]) + 1 != REGNO (operands[i+2])
2206 || GET_MODE (operands[i]) != QImode)
2208 #if DEBUG_PEEP
2209 fprintf (stderr, "no peep: wrong regnos %d %d %d\n",
2210 REGNO (operands[i]), REGNO (operands[i+2]),
2212 #endif
2213 return false;
2215 if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode))
2217 #if DEBUG_PEEP
2218 fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i]));
2219 #endif
2220 return false;
2222 break;
2224 case CONST_INT:
2225 break;
2227 case MEM:
2228 if (GET_MODE (operands[i]) != QImode)
2229 return false;
2230 if (MEM_ALIGN (operands[i]) < 16)
2231 return false;
2232 a = XEXP (operands[i], 0);
2233 if (GET_CODE (a) == CONST)
2234 a = XEXP (a, 0);
2235 if (GET_CODE (a) == PLUS)
2236 a = XEXP (a, 1);
2237 if (GET_CODE (a) == CONST_INT
2238 && INTVAL (a) & 1)
2240 #if DEBUG_PEEP
2241 fprintf (stderr, "no peep: misaligned mem %d\n", i);
2242 debug_rtx (operands[i]);
2243 #endif
2244 return false;
2246 m = adjust_address (operands[i], QImode, 1);
2247 if (! rtx_equal_p (m, operands[i+2]))
2249 #if DEBUG_PEEP
2250 fprintf (stderr, "no peep: wrong mem %d\n", i);
2251 debug_rtx (m);
2252 debug_rtx (operands[i+2]);
2253 #endif
2254 return false;
2256 break;
2258 default:
2259 #if DEBUG_PEEP
2260 fprintf (stderr, "no peep: wrong rtx %d\n", i);
2261 #endif
2262 return false;
2265 #if DEBUG_PEEP
2266 fprintf (stderr, "\033[32mpeep!\033[0m\n");
2267 #endif
2268 return true;
2271 /* Likewise, when a peephole is activated, this function helps compute
2272 the new operands. */
2273 void
2274 rl78_setup_peep_movhi (rtx *operands)
2276 int i;
2278 for (i = 0; i < 2; i ++)
2280 switch (GET_CODE (operands[i]))
2282 case REG:
2283 operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i]));
2284 break;
2286 case CONST_INT:
2287 operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char) INTVAL (operands[i+2])) * 256);
2288 break;
2290 case MEM:
2291 operands[i+4] = adjust_address (operands[i], HImode, 0);
2292 break;
2294 default:
2295 break;
2301 How Devirtualization works in the RL78 GCC port
2303 Background
2305 The RL78 is an 8-bit port with some 16-bit operations. It has 32
2306 bytes of register space, in four banks, memory-mapped. One bank is
2307 the "selected" bank and holds the registers used for primary
2308 operations. Since the registers are memory mapped, often you can
2309 still refer to the unselected banks via memory accesses.
2311 Virtual Registers
2313 The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
2314 and refers to the other banks via their memory addresses, although
2315 they're treated as regular registers internally. These "virtual"
2316 registers are R8 through R23 (bank3 is reserved for asm-based
2317 interrupt handlers).
2319 There are four machine description files:
2321 rl78.md - common register-independent patterns and definitions
2322 rl78-expand.md - expanders
2323 rl78-virt.md - patterns that match BEFORE devirtualization
2324 rl78-real.md - patterns that match AFTER devirtualization
2326 At least through register allocation and reload, gcc is told that it
2327 can do pretty much anything - but may only use the virtual registers.
2328 GCC cannot properly create the varying addressing modes that the RL78
2329 supports in an efficient way.
2331 Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
2332 uses the "valloc" attribute in rl78-virt.md for determining the rules
2333 by which it will replace virtual registers with real registers (or
2334 not) and how to make up addressing modes. For example, insns tagged
2335 with "ro1" have a single read-only parameter, which may need to be
2336 moved from memory/constant/vreg to a suitable real register. As part
2337 of devirtualization, a flag is toggled, disabling the rl78-virt.md
2338 patterns and enabling the rl78-real.md patterns. The new patterns'
2339 constraints are used to determine the real registers used. NOTE:
2340 patterns in rl78-virt.md essentially ignore the constrains and rely on
2341 predicates, where the rl78-real.md ones essentially ignore the
2342 predicates and rely on the constraints.
2344 The devirtualization pass is scheduled via the pass manager (despite
2345 being called "rl78_reorg") so it can be scheduled prior to var-track
2346 (the idea is to let gdb know about the new registers). Ideally, it
2347 would be scheduled right after pro/epilogue generation, so the
2348 post-reload optimizers could operate on the real registers, but when I
2349 tried that there were some issues building the target libraries.
2351 During devirtualization, a simple register move optimizer is run. It
2352 would be better to run a full CSE/propogation pass on it though, but
2353 that has not yet been attempted.
2356 #define DEBUG_ALLOC 0
2358 #define OP(x) (*recog_data.operand_loc[x])
2360 /* This array is used to hold knowledge about the contents of the
2361 real registers (A ... H), the memory-based registers (r8 ... r31)
2362 and the first NUM_STACK_LOCS words on the stack. We use this to
2363 avoid generating redundant move instructions.
2365 A value in the range 0 .. 31 indicates register A .. r31.
2366 A value in the range 32 .. 63 indicates stack slot (value - 32).
2367 A value of NOT_KNOWN indicates that the contents of that location
2368 are not known. */
2370 #define NUM_STACK_LOCS 32
2371 #define NOT_KNOWN 127
2373 static unsigned char content_memory [32 + NUM_STACK_LOCS];
2375 static unsigned char saved_update_index = NOT_KNOWN;
2376 static unsigned char saved_update_value;
2377 static machine_mode saved_update_mode;
2380 static inline void
2381 clear_content_memory (void)
2383 memset (content_memory, NOT_KNOWN, sizeof content_memory);
2384 if (dump_file)
2385 fprintf (dump_file, " clear content memory\n");
2386 saved_update_index = NOT_KNOWN;
2389 /* Convert LOC into an index into the content_memory array.
2390 If LOC cannot be converted, return NOT_KNOWN. */
2392 static unsigned char
2393 get_content_index (rtx loc)
2395 machine_mode mode;
2397 if (loc == NULL_RTX)
2398 return NOT_KNOWN;
2400 if (REG_P (loc))
2402 if (REGNO (loc) < 32)
2403 return REGNO (loc);
2404 return NOT_KNOWN;
2407 mode = GET_MODE (loc);
2409 if (! rl78_stack_based_mem (loc, mode))
2410 return NOT_KNOWN;
2412 loc = XEXP (loc, 0);
2414 if (REG_P (loc))
2415 /* loc = MEM (SP) */
2416 return 32;
2418 /* loc = MEM (PLUS (SP, INT)). */
2419 loc = XEXP (loc, 1);
2421 if (INTVAL (loc) < NUM_STACK_LOCS)
2422 return 32 + INTVAL (loc);
2424 return NOT_KNOWN;
2427 /* Return a string describing content INDEX in mode MODE.
2428 WARNING: Can return a pointer to a static buffer. */
2429 static const char *
2430 get_content_name (unsigned char index, machine_mode mode)
2432 static char buffer [128];
2434 if (index == NOT_KNOWN)
2435 return "Unknown";
2437 if (index > 31)
2438 sprintf (buffer, "stack slot %d", index - 32);
2439 else if (mode == HImode)
2440 sprintf (buffer, "%s%s",
2441 reg_names [index + 1], reg_names [index]);
2442 else
2443 return reg_names [index];
2445 return buffer;
2448 #if DEBUG_ALLOC
2450 static void
2451 display_content_memory (FILE * file)
2453 unsigned int i;
2455 fprintf (file, " Known memory contents:\n");
2457 for (i = 0; i < sizeof content_memory; i++)
2458 if (content_memory[i] != NOT_KNOWN)
2460 fprintf (file, " %s contains a copy of ", get_content_name (i, QImode));
2461 fprintf (file, "%s\n", get_content_name (content_memory [i], QImode));
2464 #endif
2466 static void
2467 update_content (unsigned char index, unsigned char val, machine_mode mode)
2469 unsigned int i;
2471 gcc_assert (index < sizeof content_memory);
2473 content_memory [index] = val;
2474 if (val != NOT_KNOWN)
2475 content_memory [val] = index;
2477 /* Make the entry in dump_file *before* VAL is increased below. */
2478 if (dump_file)
2480 fprintf (dump_file, " %s now contains ", get_content_name (index, mode));
2481 if (val == NOT_KNOWN)
2482 fprintf (dump_file, "Unknown\n");
2483 else
2484 fprintf (dump_file, "%s and vice versa\n", get_content_name (val, mode));
2487 if (mode == HImode)
2489 val = val == NOT_KNOWN ? val : val + 1;
2491 content_memory [index + 1] = val;
2492 if (val != NOT_KNOWN)
2494 content_memory [val] = index + 1;
2495 -- val;
2499 /* Any other places that had INDEX recorded as their contents are now invalid. */
2500 for (i = 0; i < sizeof content_memory; i++)
2502 if (i == index
2503 || (val != NOT_KNOWN && i == val))
2505 if (mode == HImode)
2506 ++ i;
2507 continue;
2510 if (content_memory[i] == index
2511 || (val != NOT_KNOWN && content_memory[i] == val))
2513 content_memory[i] = NOT_KNOWN;
2515 if (dump_file)
2516 fprintf (dump_file, " %s cleared\n", get_content_name (i, mode));
2518 if (mode == HImode)
2519 content_memory[++ i] = NOT_KNOWN;
2524 /* Record that LOC contains VALUE.
2525 For HImode locations record that LOC+1 contains VALUE+1.
2526 If LOC is not a register or stack slot, do nothing.
2527 If VALUE is not a register or stack slot, clear the recorded content. */
2529 static void
2530 record_content (rtx loc, rtx value)
2532 machine_mode mode;
2533 unsigned char index;
2534 unsigned char val;
2536 if ((index = get_content_index (loc)) == NOT_KNOWN)
2537 return;
2539 val = get_content_index (value);
2541 mode = GET_MODE (loc);
2543 if (val == index)
2545 if (! optimize)
2546 return;
2548 /* This should not happen when optimizing. */
2549 #if 1
2550 fprintf (stderr, "ASSIGNMENT of location to itself detected! [%s]\n",
2551 get_content_name (val, mode));
2552 return;
2553 #else
2554 gcc_unreachable ();
2555 #endif
2558 update_content (index, val, mode);
2561 /* Returns TRUE if LOC already contains a copy of VALUE. */
2563 static bool
2564 already_contains (rtx loc, rtx value)
2566 unsigned char index;
2567 unsigned char val;
2569 if ((index = get_content_index (loc)) == NOT_KNOWN)
2570 return false;
2572 if ((val = get_content_index (value)) == NOT_KNOWN)
2573 return false;
2575 if (content_memory [index] != val)
2576 return false;
2578 if (GET_MODE (loc) == HImode)
2579 return content_memory [index + 1] == val + 1;
2581 return true;
2584 bool
2585 rl78_es_addr (rtx addr)
2587 if (GET_CODE (addr) == MEM)
2588 addr = XEXP (addr, 0);
2589 if (GET_CODE (addr) != UNSPEC)
2590 return false;
2591 if (XINT (addr, 1) != UNS_ES_ADDR)
2592 return false;
2593 return true;
2597 rl78_es_base (rtx addr)
2599 if (GET_CODE (addr) == MEM)
2600 addr = XEXP (addr, 0);
2601 addr = XVECEXP (addr, 0, 1);
2602 if (GET_CODE (addr) == CONST
2603 && GET_CODE (XEXP (addr, 0)) == ZERO_EXTRACT)
2604 addr = XEXP (XEXP (addr, 0), 0);
2605 /* Mode doesn't matter here. */
2606 return gen_rtx_MEM (HImode, addr);
2609 /* Rescans an insn to see if it's recognized again. This is done
2610 carefully to ensure that all the constraint information is accurate
2611 for the newly matched insn. */
2612 static bool
2613 insn_ok_now (rtx_insn * insn)
2615 rtx pattern = PATTERN (insn);
2616 int i;
2618 INSN_CODE (insn) = -1;
2620 if (recog (pattern, insn, 0) > -1)
2622 extract_insn (insn);
2623 if (constrain_operands (1, get_preferred_alternatives (insn)))
2625 #if DEBUG_ALLOC
2626 fprintf (stderr, "\033[32m");
2627 debug_rtx (insn);
2628 fprintf (stderr, "\033[0m");
2629 #endif
2630 if (SET_P (pattern))
2631 record_content (SET_DEST (pattern), SET_SRC (pattern));
2633 /* We need to detect far addresses that haven't been
2634 converted to es/lo16 format. */
2635 for (i=0; i<recog_data.n_operands; i++)
2636 if (GET_CODE (OP (i)) == MEM
2637 && GET_MODE (XEXP (OP (i), 0)) == SImode
2638 && GET_CODE (XEXP (OP (i), 0)) != UNSPEC)
2639 return false;
2641 return true;
2644 else
2646 /* We need to re-recog the insn with virtual registers to get
2647 the operands. */
2648 cfun->machine->virt_insns_ok = 1;
2649 if (recog (pattern, insn, 0) > -1)
2651 extract_insn (insn);
2652 if (constrain_operands (0, get_preferred_alternatives (insn)))
2654 cfun->machine->virt_insns_ok = 0;
2655 return false;
2659 #if DEBUG_ALLOC
2660 fprintf (stderr, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
2661 debug_rtx (insn);
2662 #endif
2663 gcc_unreachable ();
2666 #if DEBUG_ALLOC
2667 fprintf (stderr, "\033[31m");
2668 debug_rtx (insn);
2669 fprintf (stderr, "\033[0m");
2670 #endif
2671 return false;
2674 #if DEBUG_ALLOC
2675 #define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
2676 #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
2677 #define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
2678 #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
2679 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
2680 #else
2681 #define FAILED gcc_unreachable ()
2682 #define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
2683 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
2684 #endif
2686 /* Registers into which we move the contents of virtual registers. */
2687 #define X gen_rtx_REG (QImode, X_REG)
2688 #define A gen_rtx_REG (QImode, A_REG)
2689 #define C gen_rtx_REG (QImode, C_REG)
2690 #define B gen_rtx_REG (QImode, B_REG)
2691 #define E gen_rtx_REG (QImode, E_REG)
2692 #define D gen_rtx_REG (QImode, D_REG)
2693 #define L gen_rtx_REG (QImode, L_REG)
2694 #define H gen_rtx_REG (QImode, H_REG)
2696 #define AX gen_rtx_REG (HImode, AX_REG)
2697 #define BC gen_rtx_REG (HImode, BC_REG)
2698 #define DE gen_rtx_REG (HImode, DE_REG)
2699 #define HL gen_rtx_REG (HImode, HL_REG)
2701 /* Returns TRUE if R is a virtual register. */
2702 static inline bool
2703 is_virtual_register (rtx r)
2705 return (GET_CODE (r) == REG
2706 && REGNO (r) >= 8
2707 && REGNO (r) < 32);
2710 /* In all these alloc routines, we expect the following: the insn
2711 pattern is unshared, the insn was previously recognized and failed
2712 due to predicates or constraints, and the operand data is in
2713 recog_data. */
2715 static int virt_insn_was_frame;
2717 /* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2718 needed. */
2719 static rtx
2720 EM2 (int line ATTRIBUTE_UNUSED, rtx r)
2722 #if DEBUG_ALLOC
2723 fprintf (stderr, "\033[36m%d: ", line);
2724 debug_rtx (r);
2725 fprintf (stderr, "\033[0m");
2726 #endif
2727 /*SCHED_GROUP_P (r) = 1;*/
2728 if (virt_insn_was_frame)
2729 RTX_FRAME_RELATED_P (r) = 1;
2730 return r;
2733 #define EM(x) EM2 (__LINE__, x)
2735 /* Return a suitable RTX for the low half of a __far address. */
2736 static rtx
2737 rl78_lo16 (rtx addr)
2739 rtx r;
2741 if (GET_CODE (addr) == SYMBOL_REF
2742 || GET_CODE (addr) == CONST)
2744 r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0));
2745 r = gen_rtx_CONST (HImode, r);
2747 else
2748 r = rl78_subreg (HImode, addr, SImode, 0);
2750 r = gen_es_addr (r);
2751 cfun->machine->uses_es = true;
2753 return r;
2756 /* Return a suitable RTX for the high half's lower byte of a __far address. */
2757 static rtx
2758 rl78_hi8 (rtx addr)
2760 if (GET_CODE (addr) == SYMBOL_REF
2761 || GET_CODE (addr) == CONST)
2763 rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16));
2764 r = gen_rtx_CONST (QImode, r);
2765 return r;
2767 return rl78_subreg (QImode, addr, SImode, 2);
2770 static void
2771 add_postponed_content_update (rtx to, rtx value)
2773 unsigned char index;
2775 if ((index = get_content_index (to)) == NOT_KNOWN)
2776 return;
2778 gcc_assert (saved_update_index == NOT_KNOWN);
2779 saved_update_index = index;
2780 saved_update_value = get_content_index (value);
2781 saved_update_mode = GET_MODE (to);
2784 static void
2785 process_postponed_content_update (void)
2787 if (saved_update_index != NOT_KNOWN)
2789 update_content (saved_update_index, saved_update_value, saved_update_mode);
2790 saved_update_index = NOT_KNOWN;
2794 /* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2795 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2796 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2797 BEFORE is true, FROM otherwise. */
2798 static rtx
2799 gen_and_emit_move (rtx to, rtx from, rtx_insn *where, bool before)
2801 machine_mode mode = GET_MODE (to);
2803 if (optimize && before && already_contains (to, from))
2805 #if DEBUG_ALLOC
2806 display_content_memory (stderr);
2807 #endif
2808 if (dump_file)
2810 fprintf (dump_file, " Omit move of %s into ",
2811 get_content_name (get_content_index (from), mode));
2812 fprintf (dump_file, "%s as it already contains this value\n",
2813 get_content_name (get_content_index (to), mode));
2816 else
2818 rtx move = mode == QImode ? gen_movqi (to, from) : gen_movhi (to, from);
2820 EM (move);
2822 if (where == NULL_RTX)
2823 emit_insn (move);
2824 else if (before)
2825 emit_insn_before (move, where);
2826 else
2828 rtx note = find_reg_note (where, REG_EH_REGION, NULL_RTX);
2830 /* If necessary move REG_EH_REGION notes forward.
2831 cf. compiling gcc.dg/pr44545.c. */
2832 if (note != NULL_RTX)
2834 add_reg_note (move, REG_EH_REGION, XEXP (note, 0));
2835 remove_note (where, note);
2838 emit_insn_after (move, where);
2841 if (before)
2842 record_content (to, from);
2843 else
2844 add_postponed_content_update (to, from);
2847 return before ? to : from;
2850 /* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2851 copy it into NEWBASE and return the updated MEM. Otherwise just
2852 return M. Any needed insns are emitted before BEFORE. */
2853 static rtx
2854 transcode_memory_rtx (rtx m, rtx newbase, rtx_insn *before)
2856 rtx base, index, addendr;
2857 int addend = 0;
2858 int need_es = 0;
2860 if (! MEM_P (m))
2861 return m;
2863 if (GET_MODE (XEXP (m, 0)) == SImode)
2865 rtx new_m;
2866 rtx seg = rl78_hi8 (XEXP (m, 0));
2868 if (!TARGET_ES0)
2870 emit_insn_before (EM (gen_movqi (A, seg)), before);
2871 emit_insn_before (EM (gen_movqi_to_es (A)), before);
2874 record_content (A, NULL_RTX);
2876 new_m = gen_rtx_MEM (GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
2877 MEM_COPY_ATTRIBUTES (new_m, m);
2878 m = new_m;
2879 need_es = 1;
2882 characterize_address (XEXP (m, 0), & base, & index, & addendr);
2883 gcc_assert (index == NULL_RTX);
2885 if (base == NULL_RTX)
2886 return m;
2888 if (addendr && GET_CODE (addendr) == CONST_INT)
2889 addend = INTVAL (addendr);
2891 gcc_assert (REG_P (base));
2892 gcc_assert (REG_P (newbase));
2894 int limit = 256 - GET_MODE_SIZE (GET_MODE (m));
2896 if (REGNO (base) == SP_REG)
2898 if (addend >= 0 && addend <= limit)
2899 return m;
2902 /* BASE should be a virtual register. We copy it to NEWBASE. If
2903 the addend is out of range for DE/HL, we use AX to compute the full
2904 address. */
2906 if (addend < 0
2907 || (addend > limit && REGNO (newbase) != BC_REG)
2908 || (addendr
2909 && (GET_CODE (addendr) != CONST_INT)
2910 && ((REGNO (newbase) != BC_REG))
2913 /* mov ax, vreg
2914 add ax, #imm
2915 mov hl, ax */
2916 EM (emit_insn_before (gen_movhi (AX, base), before));
2917 EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before));
2918 EM (emit_insn_before (gen_movhi (newbase, AX), before));
2919 record_content (AX, NULL_RTX);
2920 record_content (newbase, NULL_RTX);
2922 base = newbase;
2923 addend = 0;
2924 addendr = 0;
2926 else
2928 base = gen_and_emit_move (newbase, base, before, true);
2931 if (addend)
2933 record_content (base, NULL_RTX);
2934 base = gen_rtx_PLUS (HImode, base, GEN_INT (addend));
2936 else if (addendr)
2938 record_content (base, NULL_RTX);
2939 base = gen_rtx_PLUS (HImode, base, addendr);
2942 if (need_es)
2944 m = change_address (m, GET_MODE (m), gen_es_addr (base));
2945 cfun->machine->uses_es = true;
2947 else
2948 m = change_address (m, GET_MODE (m), base);
2949 return m;
2952 /* Copy SRC to accumulator (A or AX), placing any generated insns
2953 before BEFORE. Returns accumulator RTX. */
2954 static rtx
2955 move_to_acc (int opno, rtx_insn *before)
2957 rtx src = OP (opno);
2958 machine_mode mode = GET_MODE (src);
2960 if (REG_P (src) && REGNO (src) < 2)
2961 return src;
2963 if (mode == VOIDmode)
2964 mode = recog_data.operand_mode[opno];
2966 return gen_and_emit_move (mode == QImode ? A : AX, src, before, true);
2969 static void
2970 force_into_acc (rtx src, rtx_insn *before)
2972 machine_mode mode = GET_MODE (src);
2973 rtx move;
2975 if (REG_P (src) && REGNO (src) < 2)
2976 return;
2978 move = mode == QImode ? gen_movqi (A, src) : gen_movhi (AX, src);
2980 EM (move);
2982 emit_insn_before (move, before);
2983 record_content (AX, NULL_RTX);
2986 /* Copy accumulator (A or AX) to DEST, placing any generated insns
2987 after AFTER. Returns accumulator RTX. */
2988 static rtx
2989 move_from_acc (unsigned int opno, rtx_insn *after)
2991 rtx dest = OP (opno);
2992 machine_mode mode = GET_MODE (dest);
2994 if (REG_P (dest) && REGNO (dest) < 2)
2995 return dest;
2997 return gen_and_emit_move (dest, mode == QImode ? A : AX, after, false);
3000 /* Copy accumulator (A or AX) to REGNO, placing any generated insns
3001 before BEFORE. Returns reg RTX. */
3002 static rtx
3003 move_acc_to_reg (rtx acc, int regno, rtx_insn *before)
3005 machine_mode mode = GET_MODE (acc);
3006 rtx reg;
3008 reg = gen_rtx_REG (mode, regno);
3010 return gen_and_emit_move (reg, acc, before, true);
3013 /* Copy SRC to X, placing any generated insns before BEFORE.
3014 Returns X RTX. */
3015 static rtx
3016 move_to_x (int opno, rtx_insn *before)
3018 rtx src = OP (opno);
3019 machine_mode mode = GET_MODE (src);
3020 rtx reg;
3022 if (mode == VOIDmode)
3023 mode = recog_data.operand_mode[opno];
3024 reg = (mode == QImode) ? X : AX;
3026 if (mode == QImode || ! is_virtual_register (OP (opno)))
3028 OP (opno) = move_to_acc (opno, before);
3029 OP (opno) = move_acc_to_reg (OP (opno), X_REG, before);
3030 return reg;
3033 return gen_and_emit_move (reg, src, before, true);
3036 /* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
3037 Returns H/HL RTX. */
3038 static rtx
3039 move_to_hl (int opno, rtx_insn *before)
3041 rtx src = OP (opno);
3042 machine_mode mode = GET_MODE (src);
3043 rtx reg;
3045 if (mode == VOIDmode)
3046 mode = recog_data.operand_mode[opno];
3047 reg = (mode == QImode) ? L : HL;
3049 if (mode == QImode || ! is_virtual_register (OP (opno)))
3051 OP (opno) = move_to_acc (opno, before);
3052 OP (opno) = move_acc_to_reg (OP (opno), L_REG, before);
3053 return reg;
3056 return gen_and_emit_move (reg, src, before, true);
3059 /* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
3060 Returns E/DE RTX. */
3061 static rtx
3062 move_to_de (int opno, rtx_insn *before)
3064 rtx src = OP (opno);
3065 machine_mode mode = GET_MODE (src);
3066 rtx reg;
3068 if (mode == VOIDmode)
3069 mode = recog_data.operand_mode[opno];
3071 reg = (mode == QImode) ? E : DE;
3073 if (mode == QImode || ! is_virtual_register (OP (opno)))
3075 OP (opno) = move_to_acc (opno, before);
3076 OP (opno) = move_acc_to_reg (OP (opno), E_REG, before);
3078 else
3080 gen_and_emit_move (reg, src, before, true);
3083 return reg;
3086 /* Devirtualize an insn of the form (SET (op) (unop (op))). */
3087 static void
3088 rl78_alloc_physical_registers_op1 (rtx_insn * insn)
3090 /* op[0] = func op[1] */
3092 /* We first try using A as the destination, then copying it
3093 back. */
3094 if (rtx_equal_p (OP (0), OP (1)))
3096 OP (0) =
3097 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3099 else
3101 /* If necessary, load the operands into BC and HL.
3102 Check to see if we already have OP (0) in HL
3103 and if so, swap the order.
3105 It is tempting to perform this optimization when OP(0) does
3106 not hold a MEM, but this leads to bigger code in general.
3107 The problem is that if OP(1) holds a MEM then swapping it
3108 into BC means a BC-relative load is used and these are 3
3109 bytes long vs 1 byte for an HL load. */
3110 if (MEM_P (OP (0))
3111 && already_contains (HL, XEXP (OP (0), 0)))
3113 OP (0) = transcode_memory_rtx (OP (0), HL, insn);
3114 OP (1) = transcode_memory_rtx (OP (1), BC, insn);
3116 else
3118 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3119 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
3123 MAYBE_OK (insn);
3125 OP (0) = move_from_acc (0, insn);
3127 MAYBE_OK (insn);
3129 /* Try copying the src to acc first, then. This is for, for
3130 example, ZERO_EXTEND or NOT. */
3131 OP (1) = move_to_acc (1, insn);
3133 MUST_BE_OK (insn);
3136 /* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
3137 Assumes that the current insn has already been recognised and hence the
3138 constraint data has been filled in. */
3139 static bool
3140 has_constraint (unsigned int opnum, enum constraint_num constraint)
3142 const char * p = recog_data.constraints[opnum];
3144 /* No constraints means anything is accepted. */
3145 if (p == NULL || *p == 0 || *p == ',')
3146 return true;
3150 char c;
3151 unsigned int len;
3153 c = *p;
3154 len = CONSTRAINT_LEN (c, p);
3155 gcc_assert (len > 0);
3157 switch (c)
3159 case 0:
3160 case ',':
3161 return false;
3162 default:
3163 if (lookup_constraint (p) == constraint)
3164 return true;
3166 p += len;
3168 while (1);
3171 /* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
3172 static void
3173 rl78_alloc_physical_registers_op2 (rtx_insn * insn)
3175 rtx_insn *prev;
3176 rtx_insn *first;
3177 bool hl_used;
3178 int tmp_id;
3179 rtx saved_op1;
3181 if (rtx_equal_p (OP (0), OP (1)))
3183 if (MEM_P (OP (2)))
3185 OP (0) =
3186 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3187 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3189 else
3191 OP (0) =
3192 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
3193 OP (2) = transcode_memory_rtx (OP (2), DE, insn);
3196 else if (rtx_equal_p (OP (0), OP (2)))
3198 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3199 OP (0) =
3200 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3202 else
3204 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3205 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3206 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3209 MAYBE_OK (insn);
3211 prev = prev_nonnote_nondebug_insn (insn);
3212 if (recog_data.constraints[1][0] == '%'
3213 && is_virtual_register (OP (1))
3214 && ! is_virtual_register (OP (2))
3215 && ! CONSTANT_P (OP (2)))
3217 rtx tmp = OP (1);
3218 OP (1) = OP (2);
3219 OP (2) = tmp;
3222 /* Make a note of whether (H)L is being used. It matters
3223 because if OP (2) also needs reloading, then we must take
3224 care not to corrupt HL. */
3225 hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1));
3227 /* If HL is not currently being used and dest == op1 then there are
3228 some possible optimizations available by reloading one of the
3229 operands into HL, before trying to use the accumulator. */
3230 if (optimize
3231 && ! hl_used
3232 && rtx_equal_p (OP (0), OP (1)))
3234 /* If op0 is a Ws1 type memory address then switching the base
3235 address register to HL might allow us to perform an in-memory
3236 operation. (eg for the INCW instruction).
3238 FIXME: Adding the move into HL is costly if this optimization is not
3239 going to work, so for now, make sure that we know that the new insn will
3240 match the requirements of the addhi3_real pattern. Really we ought to
3241 generate a candidate sequence, test that, and then install it if the
3242 results are good. */
3243 if (satisfies_constraint_Ws1 (OP (0))
3244 && has_constraint (0, CONSTRAINT_Wh1)
3245 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
3247 rtx base, index, addend, newbase;
3249 characterize_address (XEXP (OP (0), 0), & base, & index, & addend);
3250 gcc_assert (index == NULL_RTX);
3251 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
3253 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3254 if (addend != NULL_RTX)
3256 newbase = gen_and_emit_move (HL, base, insn, true);
3257 record_content (newbase, NULL_RTX);
3258 newbase = gen_rtx_PLUS (HImode, newbase, addend);
3260 OP (0) = OP (1) = change_address (OP (0), VOIDmode, newbase);
3262 /* We do not want to fail here as this means that
3263 we have inserted useless insns into the stream. */
3264 MUST_BE_OK (insn);
3267 else if (REG_P (OP (0))
3268 && satisfies_constraint_Ws1 (OP (2))
3269 && has_constraint (2, CONSTRAINT_Wh1))
3271 rtx base, index, addend, newbase;
3273 characterize_address (XEXP (OP (2), 0), & base, & index, & addend);
3274 gcc_assert (index == NULL_RTX);
3275 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
3277 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3278 if (addend != NULL_RTX)
3280 gen_and_emit_move (HL, base, insn, true);
3282 if (REGNO (OP (0)) != X_REG)
3284 OP (1) = move_to_acc (1, insn);
3285 OP (0) = move_from_acc (0, insn);
3288 record_content (HL, NULL_RTX);
3289 newbase = gen_rtx_PLUS (HImode, HL, addend);
3291 OP (2) = change_address (OP (2), VOIDmode, newbase);
3293 /* We do not want to fail here as this means that
3294 we have inserted useless insns into the stream. */
3295 MUST_BE_OK (insn);
3300 OP (0) = move_from_acc (0, insn);
3302 tmp_id = get_max_insn_count ();
3303 saved_op1 = OP (1);
3305 if (rtx_equal_p (OP (1), OP (2)))
3306 OP (2) = OP (1) = move_to_acc (1, insn);
3307 else
3308 OP (1) = move_to_acc (1, insn);
3310 MAYBE_OK (insn);
3312 /* If we omitted the move of OP1 into the accumulator (because
3313 it was already there from a previous insn), then force the
3314 generation of the move instruction now. We know that we
3315 are about to emit a move into HL (or DE) via AX, and hence
3316 our optimization to remove the load of OP1 is no longer valid. */
3317 if (tmp_id == get_max_insn_count ())
3318 force_into_acc (saved_op1, insn);
3320 /* We have to copy op2 to HL (or DE), but that involves AX, which
3321 already has a live value. Emit it before those insns. */
3323 if (prev)
3324 first = next_nonnote_nondebug_insn (prev);
3325 else
3326 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3329 OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first);
3331 MUST_BE_OK (insn);
3334 /* Devirtualize an insn of the form SET (PC) (MEM/REG). */
3335 static void
3336 rl78_alloc_physical_registers_ro1 (rtx_insn * insn)
3338 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3340 MAYBE_OK (insn);
3342 OP (0) = move_to_acc (0, insn);
3344 MUST_BE_OK (insn);
3347 /* Devirtualize a compare insn. */
3348 static void
3349 rl78_alloc_physical_registers_cmp (rtx_insn * insn)
3351 int tmp_id;
3352 rtx saved_op1;
3353 rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
3354 rtx_insn *first;
3356 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3357 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3359 /* HI compares have to have OP (1) in AX, but QI
3360 compares do not, so it is worth checking here. */
3361 MAYBE_OK (insn);
3363 /* For an HImode compare, OP (1) must always be in AX.
3364 But if OP (1) is a REG (and not AX), then we can avoid
3365 a reload of OP (1) if we reload OP (2) into AX and invert
3366 the comparison. */
3367 if (REG_P (OP (1))
3368 && REGNO (OP (1)) != AX_REG
3369 && GET_MODE (OP (1)) == HImode
3370 && MEM_P (OP (2)))
3372 rtx cmp = XEXP (SET_SRC (PATTERN (insn)), 0);
3374 OP (2) = move_to_acc (2, insn);
3376 switch (GET_CODE (cmp))
3378 case EQ:
3379 case NE:
3380 break;
3381 case LTU: cmp = gen_rtx_GTU (HImode, OP (2), OP (1)); break;
3382 case GTU: cmp = gen_rtx_LTU (HImode, OP (2), OP (1)); break;
3383 case LEU: cmp = gen_rtx_GEU (HImode, OP (2), OP (1)); break;
3384 case GEU: cmp = gen_rtx_LEU (HImode, OP (2), OP (1)); break;
3386 case LT:
3387 case GT:
3388 case LE:
3389 case GE:
3390 #if DEBUG_ALLOC
3391 debug_rtx (insn);
3392 #endif
3393 default:
3394 gcc_unreachable ();
3397 if (GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE)
3398 PATTERN (insn) = gen_cbranchhi4_real (cmp, OP (2), OP (1), OP (3));
3399 else
3400 PATTERN (insn) = gen_cbranchhi4_real_inverted (cmp, OP (2), OP (1), OP (3));
3402 MUST_BE_OK (insn);
3405 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
3406 should be handled by the second alternative of the cbranchhi_real pattern. */
3407 if (rtx_equal_p (OP (1), OP (2)))
3409 OP (1) = OP (2) = BC;
3410 MUST_BE_OK (insn);
3413 tmp_id = get_max_insn_count ();
3414 saved_op1 = OP (1);
3416 OP (1) = move_to_acc (1, insn);
3418 MAYBE_OK (insn);
3420 /* If we omitted the move of OP1 into the accumulator (because
3421 it was already there from a previous insn), then force the
3422 generation of the move instruction now. We know that we
3423 are about to emit a move into HL via AX, and hence our
3424 optimization to remove the load of OP1 is no longer valid. */
3425 if (tmp_id == get_max_insn_count ())
3426 force_into_acc (saved_op1, insn);
3428 /* We have to copy op2 to HL, but that involves the acc, which
3429 already has a live value. Emit it before those insns. */
3430 if (prev)
3431 first = next_nonnote_nondebug_insn (prev);
3432 else
3433 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3435 OP (2) = move_to_hl (2, first);
3437 MUST_BE_OK (insn);
3440 /* Like op2, but AX = A * X. */
3441 static void
3442 rl78_alloc_physical_registers_umul (rtx_insn * insn)
3444 rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
3445 rtx_insn *first;
3446 int tmp_id;
3447 rtx saved_op1;
3449 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3450 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3451 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3453 MAYBE_OK (insn);
3455 if (recog_data.constraints[1][0] == '%'
3456 && is_virtual_register (OP (1))
3457 && !is_virtual_register (OP (2))
3458 && !CONSTANT_P (OP (2)))
3460 rtx tmp = OP (1);
3461 OP (1) = OP (2);
3462 OP (2) = tmp;
3465 OP (0) = move_from_acc (0, insn);
3467 tmp_id = get_max_insn_count ();
3468 saved_op1 = OP (1);
3470 if (rtx_equal_p (OP (1), OP (2)))
3472 gcc_assert (GET_MODE (OP (2)) == QImode);
3473 /* The MULU instruction does not support duplicate arguments
3474 but we know that if we copy OP (2) to X it will do so via
3475 A and thus OP (1) will already be loaded into A. */
3476 OP (2) = move_to_x (2, insn);
3477 OP (1) = A;
3479 else
3480 OP (1) = move_to_acc (1, insn);
3482 MAYBE_OK (insn);
3484 /* If we omitted the move of OP1 into the accumulator (because
3485 it was already there from a previous insn), then force the
3486 generation of the move instruction now. We know that we
3487 are about to emit a move into HL (or DE) via AX, and hence
3488 our optimization to remove the load of OP1 is no longer valid. */
3489 if (tmp_id == get_max_insn_count ())
3490 force_into_acc (saved_op1, insn);
3492 /* We have to copy op2 to X, but that involves the acc, which
3493 already has a live value. Emit it before those insns. */
3495 if (prev)
3496 first = next_nonnote_nondebug_insn (prev);
3497 else
3498 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3500 OP (2) = move_to_x (2, first);
3502 MUST_BE_OK (insn);
3505 static void
3506 rl78_alloc_address_registers_macax (rtx_insn * insn)
3508 int which, op;
3509 bool replace_in_op0 = false;
3510 bool replace_in_op1 = false;
3512 MAYBE_OK (insn);
3514 /* Two different MEMs are not allowed. */
3515 which = 0;
3516 for (op = 2; op >= 0; op --)
3518 if (MEM_P (OP (op)))
3520 if (op == 0 && replace_in_op0)
3521 continue;
3522 if (op == 1 && replace_in_op1)
3523 continue;
3525 switch (which)
3527 case 0:
3528 /* If we replace a MEM, make sure that we replace it for all
3529 occurrences of the same MEM in the insn. */
3530 replace_in_op0 = (op > 0 && rtx_equal_p (OP (op), OP (0)));
3531 replace_in_op1 = (op > 1 && rtx_equal_p (OP (op), OP (1)));
3533 OP (op) = transcode_memory_rtx (OP (op), HL, insn);
3534 if (op == 2
3535 && MEM_P (OP (op))
3536 && ((GET_CODE (XEXP (OP (op), 0)) == REG
3537 && REGNO (XEXP (OP (op), 0)) == SP_REG)
3538 || (GET_CODE (XEXP (OP (op), 0)) == PLUS
3539 && REGNO (XEXP (XEXP (OP (op), 0), 0)) == SP_REG)))
3541 emit_insn_before (gen_movhi (HL, gen_rtx_REG (HImode, SP_REG)), insn);
3542 OP (op) = replace_rtx (OP (op), gen_rtx_REG (HImode, SP_REG), HL);
3544 if (replace_in_op0)
3545 OP (0) = OP (op);
3546 if (replace_in_op1)
3547 OP (1) = OP (op);
3548 break;
3549 case 1:
3550 OP (op) = transcode_memory_rtx (OP (op), DE, insn);
3551 break;
3552 case 2:
3553 OP (op) = transcode_memory_rtx (OP (op), BC, insn);
3554 break;
3556 which ++;
3560 MUST_BE_OK (insn);
3563 static void
3564 rl78_alloc_address_registers_div (rtx_insn * insn)
3566 MUST_BE_OK (insn);
3569 /* Scan all insns and devirtualize them. */
3570 static void
3571 rl78_alloc_physical_registers (void)
3573 /* During most of the compile, gcc is dealing with virtual
3574 registers. At this point, we need to assign physical registers
3575 to the vitual ones, and copy in/out as needed. */
3577 rtx_insn *insn, *curr;
3578 enum attr_valloc valloc_method;
3580 for (insn = get_insns (); insn; insn = curr)
3582 int i;
3584 curr = next_nonnote_nondebug_insn (insn);
3586 if (INSN_P (insn)
3587 && (GET_CODE (PATTERN (insn)) == SET
3588 || GET_CODE (PATTERN (insn)) == CALL)
3589 && INSN_CODE (insn) == -1)
3591 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
3592 continue;
3593 i = recog (PATTERN (insn), insn, 0);
3594 if (i == -1)
3596 debug_rtx (insn);
3597 gcc_unreachable ();
3599 INSN_CODE (insn) = i;
3603 cfun->machine->virt_insns_ok = 0;
3604 cfun->machine->real_insns_ok = 1;
3606 clear_content_memory ();
3608 for (insn = get_insns (); insn; insn = curr)
3610 rtx pattern;
3612 curr = insn ? next_nonnote_nondebug_insn (insn) : NULL;
3614 if (!INSN_P (insn))
3616 if (LABEL_P (insn))
3617 clear_content_memory ();
3619 continue;
3622 if (dump_file)
3623 fprintf (dump_file, "Converting insn %d\n", INSN_UID (insn));
3625 pattern = PATTERN (insn);
3626 if (GET_CODE (pattern) == PARALLEL)
3627 pattern = XVECEXP (pattern, 0, 0);
3628 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3629 clear_content_memory ();
3630 if (GET_CODE (pattern) != SET
3631 && GET_CODE (pattern) != CALL)
3632 continue;
3633 if (GET_CODE (pattern) == SET
3634 && GET_CODE (SET_SRC (pattern)) == ASM_OPERANDS)
3635 continue;
3637 valloc_method = get_attr_valloc (insn);
3639 PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
3641 if (valloc_method == VALLOC_MACAX)
3643 record_content (AX, NULL_RTX);
3644 record_content (BC, NULL_RTX);
3645 record_content (DE, NULL_RTX);
3647 else if (valloc_method == VALLOC_DIVHI)
3649 record_content (AX, NULL_RTX);
3650 record_content (BC, NULL_RTX);
3652 else if (valloc_method == VALLOC_DIVSI)
3654 record_content (AX, NULL_RTX);
3655 record_content (BC, NULL_RTX);
3656 record_content (DE, NULL_RTX);
3657 record_content (HL, NULL_RTX);
3660 if (insn_ok_now (insn))
3661 continue;
3663 INSN_CODE (insn) = -1;
3665 if (RTX_FRAME_RELATED_P (insn))
3666 virt_insn_was_frame = 1;
3667 else
3668 virt_insn_was_frame = 0;
3670 switch (valloc_method)
3672 case VALLOC_OP1:
3673 rl78_alloc_physical_registers_op1 (insn);
3674 break;
3675 case VALLOC_OP2:
3676 rl78_alloc_physical_registers_op2 (insn);
3677 break;
3678 case VALLOC_RO1:
3679 rl78_alloc_physical_registers_ro1 (insn);
3680 break;
3681 case VALLOC_CMP:
3682 rl78_alloc_physical_registers_cmp (insn);
3683 break;
3684 case VALLOC_UMUL:
3685 rl78_alloc_physical_registers_umul (insn);
3686 record_content (AX, NULL_RTX);
3687 break;
3688 case VALLOC_MACAX:
3689 /* Macro that clobbers AX. */
3690 rl78_alloc_address_registers_macax (insn);
3691 record_content (AX, NULL_RTX);
3692 record_content (BC, NULL_RTX);
3693 record_content (DE, NULL_RTX);
3694 break;
3695 case VALLOC_DIVSI:
3696 rl78_alloc_address_registers_div (insn);
3697 record_content (AX, NULL_RTX);
3698 record_content (BC, NULL_RTX);
3699 record_content (DE, NULL_RTX);
3700 record_content (HL, NULL_RTX);
3701 break;
3702 case VALLOC_DIVHI:
3703 rl78_alloc_address_registers_div (insn);
3704 record_content (AX, NULL_RTX);
3705 record_content (BC, NULL_RTX);
3706 break;
3707 default:
3708 gcc_unreachable ();
3711 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3712 clear_content_memory ();
3713 else
3714 process_postponed_content_update ();
3717 #if DEBUG_ALLOC
3718 fprintf (stderr, "\033[0m");
3719 #endif
3722 /* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3723 This function scans for uses of registers; the last use (i.e. first
3724 encounter when scanning backwards) triggers a REG_DEAD note if the
3725 reg was previously in DEAD[]. */
3726 static void
3727 rl78_note_reg_uses (char *dead, rtx s, rtx insn)
3729 const char *fmt;
3730 int i, r;
3731 enum rtx_code code;
3733 if (!s)
3734 return;
3736 code = GET_CODE (s);
3738 switch (code)
3740 /* Compare registers by number. */
3741 case REG:
3742 r = REGNO (s);
3743 if (dump_file)
3745 fprintf (dump_file, "note use reg %d size %d on insn %d\n",
3746 r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn));
3747 print_rtl_single (dump_file, s);
3749 if (dead [r])
3750 add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r));
3751 for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++)
3752 dead [r + i] = 0;
3753 return;
3755 /* These codes have no constituent expressions
3756 and are unique. */
3757 case SCRATCH:
3758 case CC0:
3759 case PC:
3760 return;
3762 case CONST_INT:
3763 case CONST_VECTOR:
3764 case CONST_DOUBLE:
3765 case CONST_FIXED:
3766 /* These are kept unique for a given value. */
3767 return;
3769 default:
3770 break;
3773 fmt = GET_RTX_FORMAT (code);
3775 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
3777 if (fmt[i] == 'E')
3779 int j;
3780 for (j = XVECLEN (s, i) - 1; j >= 0; j--)
3781 rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn);
3783 else if (fmt[i] == 'e')
3784 rl78_note_reg_uses (dead, XEXP (s, i), insn);
3788 /* Like the previous function, but scan for SETs instead. */
3789 static void
3790 rl78_note_reg_set (char *dead, rtx d, rtx insn)
3792 int r, i;
3794 if (GET_CODE (d) == MEM)
3795 rl78_note_reg_uses (dead, XEXP (d, 0), insn);
3797 if (GET_CODE (d) != REG)
3798 return;
3800 r = REGNO (d);
3801 if (dead [r])
3802 add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r));
3803 if (dump_file)
3804 fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d)));
3805 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
3806 dead [r + i] = 1;
3809 /* This is a rather crude register death pass. Death status is reset
3810 at every jump or call insn. */
3811 static void
3812 rl78_calculate_death_notes (void)
3814 char dead[FIRST_PSEUDO_REGISTER];
3815 rtx p, s, d;
3816 rtx_insn *insn;
3817 int i;
3819 memset (dead, 0, sizeof (dead));
3821 for (insn = get_last_insn ();
3822 insn;
3823 insn = prev_nonnote_nondebug_insn (insn))
3825 if (dump_file)
3827 fprintf (dump_file, "\n--------------------------------------------------");
3828 fprintf (dump_file, "\nDead:");
3829 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
3830 if (dead[i])
3831 fprintf (dump_file, " %s", reg_names[i]);
3832 fprintf (dump_file, "\n");
3833 print_rtl_single (dump_file, insn);
3836 switch (GET_CODE (insn))
3838 case INSN:
3839 p = PATTERN (insn);
3840 if (GET_CODE (p) == PARALLEL)
3842 rtx q = XVECEXP (p, 0 ,1);
3844 /* This happens with the DIV patterns. */
3845 if (GET_CODE (q) == SET)
3847 s = SET_SRC (q);
3848 d = SET_DEST (q);
3849 rl78_note_reg_set (dead, d, insn);
3850 rl78_note_reg_uses (dead, s, insn);
3853 p = XVECEXP (p, 0, 0);
3856 switch (GET_CODE (p))
3858 case SET:
3859 s = SET_SRC (p);
3860 d = SET_DEST (p);
3861 rl78_note_reg_set (dead, d, insn);
3862 rl78_note_reg_uses (dead, s, insn);
3863 break;
3865 case USE:
3866 rl78_note_reg_uses (dead, p, insn);
3867 break;
3869 default:
3870 break;
3872 break;
3874 case JUMP_INSN:
3875 if (INSN_CODE (insn) == CODE_FOR_rl78_return)
3877 memset (dead, 1, sizeof (dead));
3878 /* We expect a USE just prior to this, which will mark
3879 the actual return registers. The USE will have a
3880 death note, but we aren't going to be modifying it
3881 after this pass. */
3882 break;
3884 /* FALLTHRU */
3885 case CALL_INSN:
3886 memset (dead, 0, sizeof (dead));
3887 break;
3889 default:
3890 break;
3892 if (dump_file)
3893 print_rtl_single (dump_file, insn);
3897 /* Helper function to reset the origins in RP and the age in AGE for
3898 all registers. */
3899 static void
3900 reset_origins (int *rp, int *age)
3902 int i;
3903 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3905 rp[i] = i;
3906 age[i] = 0;
3910 static void
3911 set_origin (rtx pat, rtx_insn * insn, int * origins, int * age)
3913 rtx src = SET_SRC (pat);
3914 rtx dest = SET_DEST (pat);
3915 int mb = GET_MODE_SIZE (GET_MODE (dest));
3916 int i;
3918 if (GET_CODE (dest) == REG)
3920 int dr = REGNO (dest);
3922 if (GET_CODE (src) == REG)
3924 int sr = REGNO (src);
3925 bool same = true;
3926 int best_age, best_reg;
3928 /* See if the copy is not needed. */
3929 for (i = 0; i < mb; i ++)
3930 if (origins[dr + i] != origins[sr + i])
3931 same = false;
3933 if (same)
3935 if (dump_file)
3936 fprintf (dump_file, "deleting because dest already has correct value\n");
3937 delete_insn (insn);
3938 return;
3941 if (dr < 8 || sr >= 8)
3943 int ar;
3945 best_age = -1;
3946 best_reg = -1;
3948 /* See if the copy can be made from another
3949 bank 0 register instead, instead of the
3950 virtual src register. */
3951 for (ar = 0; ar < 8; ar += mb)
3953 same = true;
3955 for (i = 0; i < mb; i ++)
3956 if (origins[ar + i] != origins[sr + i])
3957 same = false;
3959 /* The chip has some reg-reg move limitations. */
3960 if (mb == 1 && dr > 3)
3961 same = false;
3963 if (same)
3965 if (best_age == -1 || best_age > age[sr + i])
3967 best_age = age[sr + i];
3968 best_reg = sr;
3973 if (best_reg != -1)
3975 /* FIXME: copy debug info too. */
3976 SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg);
3977 sr = best_reg;
3981 for (i = 0; i < mb; i++)
3983 origins[dr + i] = origins[sr + i];
3984 age[dr + i] = age[sr + i] + 1;
3987 else
3989 /* The destination is computed, its origin is itself. */
3990 if (dump_file)
3991 fprintf (dump_file, "resetting origin of r%d for %d byte%s\n",
3992 dr, mb, mb == 1 ? "" : "s");
3994 for (i = 0; i < mb; i ++)
3996 origins[dr + i] = dr + i;
3997 age[dr + i] = 0;
4001 /* Any registers marked with that reg as an origin are reset. */
4002 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4003 if (origins[i] >= dr && origins[i] < dr + mb)
4005 origins[i] = i;
4006 age[i] = 0;
4010 /* Special case - our MUL patterns uses AX and sometimes BC. */
4011 if (get_attr_valloc (insn) == VALLOC_MACAX)
4013 if (dump_file)
4014 fprintf (dump_file, "Resetting origin of AX/BC for MUL pattern.\n");
4016 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4017 if (i <= 3 || origins[i] <= 3)
4019 origins[i] = i;
4020 age[i] = 0;
4023 else if (get_attr_valloc (insn) == VALLOC_DIVHI)
4025 if (dump_file)
4026 fprintf (dump_file, "Resetting origin of AX/DE for DIVHI pattern.\n");
4028 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4029 if (i == A_REG
4030 || i == X_REG
4031 || i == D_REG
4032 || i == E_REG
4033 || origins[i] == A_REG
4034 || origins[i] == X_REG
4035 || origins[i] == D_REG
4036 || origins[i] == E_REG)
4038 origins[i] = i;
4039 age[i] = 0;
4042 else if (get_attr_valloc (insn) == VALLOC_DIVSI)
4044 if (dump_file)
4045 fprintf (dump_file, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n");
4047 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4048 if (i <= 7 || origins[i] <= 7)
4050 origins[i] = i;
4051 age[i] = 0;
4055 if (GET_CODE (src) == ASHIFT
4056 || GET_CODE (src) == ASHIFTRT
4057 || GET_CODE (src) == LSHIFTRT)
4059 rtx count = XEXP (src, 1);
4061 if (GET_CODE (count) == REG)
4063 /* Special case - our pattern clobbers the count register. */
4064 int r = REGNO (count);
4066 if (dump_file)
4067 fprintf (dump_file, "Resetting origin of r%d for shift.\n", r);
4069 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4070 if (i == r || origins[i] == r)
4072 origins[i] = i;
4073 age[i] = 0;
4079 /* The idea behind this optimization is to look for cases where we
4080 move data from A to B to C, and instead move from A to B, and A to
4081 C. If B is a virtual register or memory, this is a big win on its
4082 own. If B turns out to be unneeded after this, it's a bigger win.
4083 For each register, we try to determine where it's value originally
4084 came from, if it's propogated purely through moves (and not
4085 computes). The ORIGINS[] array has the regno for the "origin" of
4086 the value in the [regno] it's indexed by. */
4087 static void
4088 rl78_propogate_register_origins (void)
4090 int origins[FIRST_PSEUDO_REGISTER];
4091 int age[FIRST_PSEUDO_REGISTER];
4092 int i;
4093 rtx_insn *insn, *ninsn = NULL;
4094 rtx pat;
4096 reset_origins (origins, age);
4098 for (insn = get_insns (); insn; insn = ninsn)
4100 ninsn = next_nonnote_nondebug_insn (insn);
4102 if (dump_file)
4104 fprintf (dump_file, "\n");
4105 fprintf (dump_file, "Origins:");
4106 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
4107 if (origins[i] != i)
4108 fprintf (dump_file, " r%d=r%d", i, origins[i]);
4109 fprintf (dump_file, "\n");
4110 print_rtl_single (dump_file, insn);
4113 switch (GET_CODE (insn))
4115 case CODE_LABEL:
4116 case BARRIER:
4117 case CALL_INSN:
4118 case JUMP_INSN:
4119 reset_origins (origins, age);
4120 break;
4122 default:
4123 break;
4125 case INSN:
4126 pat = PATTERN (insn);
4128 if (GET_CODE (pat) == PARALLEL)
4130 rtx clobber = XVECEXP (pat, 0, 1);
4131 pat = XVECEXP (pat, 0, 0);
4132 if (GET_CODE (clobber) == CLOBBER
4133 && GET_CODE (XEXP (clobber, 0)) == REG)
4135 int cr = REGNO (XEXP (clobber, 0));
4136 int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0)));
4137 if (dump_file)
4138 fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr);
4139 for (i = 0; i < mb; i++)
4141 origins[cr + i] = cr + i;
4142 age[cr + i] = 0;
4145 /* This happens with the DIV patterns. */
4146 else if (GET_CODE (clobber) == SET)
4148 set_origin (clobber, insn, origins, age);
4150 else
4151 break;
4154 if (GET_CODE (pat) == SET)
4156 set_origin (pat, insn, origins, age);
4158 else if (GET_CODE (pat) == CLOBBER
4159 && GET_CODE (XEXP (pat, 0)) == REG)
4161 if (REG_P (XEXP (pat, 0)))
4163 unsigned int reg = REGNO (XEXP (pat, 0));
4165 origins[reg] = reg;
4166 age[reg] = 0;
4173 /* Remove any SETs where the destination is unneeded. */
4174 static void
4175 rl78_remove_unused_sets (void)
4177 rtx_insn *insn, *ninsn = NULL;
4178 rtx dest;
4180 for (insn = get_insns (); insn; insn = ninsn)
4182 ninsn = next_nonnote_nondebug_insn (insn);
4184 rtx set = single_set (insn);
4185 if (set == NULL)
4186 continue;
4188 dest = SET_DEST (set);
4190 if (GET_CODE (dest) != REG || REGNO (dest) > 23)
4191 continue;
4193 if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
4195 if (dump_file)
4196 fprintf (dump_file, "deleting because the set register is never used.\n");
4197 delete_insn (insn);
4202 /* This is the top of the devritualization pass. */
4203 static void
4204 rl78_reorg (void)
4206 /* split2 only happens when optimizing, but we need all movSIs to be
4207 split now. */
4208 if (optimize <= 0)
4209 split_all_insns ();
4211 rl78_alloc_physical_registers ();
4213 if (dump_file)
4215 fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
4216 print_rtl_with_bb (dump_file, get_insns (), 0);
4219 rl78_propogate_register_origins ();
4220 rl78_calculate_death_notes ();
4222 if (dump_file)
4224 fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
4225 print_rtl_with_bb (dump_file, get_insns (), 0);
4226 fprintf (dump_file, "\n======================================================================\n");
4229 rl78_remove_unused_sets ();
4231 /* The code after devirtualizing has changed so much that at this point
4232 we might as well just rescan everything. Note that
4233 df_rescan_all_insns is not going to help here because it does not
4234 touch the artificial uses and defs. */
4235 df_finish_pass (true);
4236 if (optimize > 1)
4237 df_live_add_problem ();
4238 df_scan_alloc (NULL);
4239 df_scan_blocks ();
4241 if (optimize)
4242 df_analyze ();
4245 #undef TARGET_RETURN_IN_MEMORY
4246 #define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
4248 static bool
4249 rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
4251 const HOST_WIDE_INT size = int_size_in_bytes (type);
4252 return (size == -1 || size > 8);
4256 #undef TARGET_RTX_COSTS
4257 #define TARGET_RTX_COSTS rl78_rtx_costs
4259 static bool
4260 rl78_rtx_costs (rtx x,
4261 machine_mode mode,
4262 int outer_code ATTRIBUTE_UNUSED,
4263 int opno ATTRIBUTE_UNUSED,
4264 int * total,
4265 bool speed ATTRIBUTE_UNUSED)
4267 int code = GET_CODE (x);
4269 if (code == IF_THEN_ELSE)
4271 *total = COSTS_N_INSNS (10);
4272 return true;
4275 if (mode == HImode)
4277 if (code == MULT && ! speed)
4279 * total = COSTS_N_INSNS (8);
4280 return true;
4282 return false;
4285 if (mode == SImode)
4287 switch (code)
4289 case MULT:
4290 if (! speed)
4291 /* If we are compiling for space then we do not want to use the
4292 inline SImode multiplication patterns or shift sequences.
4293 The cost is not set to 1 or 5 however as we have to allow for
4294 the possibility that we might be converting a leaf function
4295 into a non-leaf function. (There is no way to tell here).
4296 A value of 13 seems to be a reasonable compromise for the
4297 moment. */
4298 * total = COSTS_N_INSNS (13);
4299 else if (RL78_MUL_G14)
4300 *total = COSTS_N_INSNS (14);
4301 else if (RL78_MUL_G13)
4302 *total = COSTS_N_INSNS (29);
4303 else
4304 *total = COSTS_N_INSNS (500);
4305 return true;
4307 case PLUS:
4308 *total = COSTS_N_INSNS (8);
4309 return true;
4311 case ASHIFT:
4312 case ASHIFTRT:
4313 case LSHIFTRT:
4314 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4316 switch (INTVAL (XEXP (x, 1)))
4318 case 0: *total = COSTS_N_INSNS (0); break;
4319 case 1: *total = COSTS_N_INSNS (6); break;
4320 case 2: case 3: case 4: case 5: case 6: case 7:
4321 *total = COSTS_N_INSNS (10); break;
4322 case 8: *total = COSTS_N_INSNS (6); break;
4323 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
4324 *total = COSTS_N_INSNS (10); break;
4325 case 16: *total = COSTS_N_INSNS (3); break;
4326 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
4327 *total = COSTS_N_INSNS (4); break;
4328 case 24: *total = COSTS_N_INSNS (4); break;
4329 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
4330 *total = COSTS_N_INSNS (5); break;
4333 else
4334 *total = COSTS_N_INSNS (10+4*16);
4335 return true;
4337 default:
4338 break;
4341 return false;
4345 static GTY(()) section * saddr_section;
4346 static GTY(()) section * frodata_section;
4349 rl78_saddr_p (rtx x)
4351 const char * c;
4353 if (MEM_P (x))
4354 x = XEXP (x, 0);
4355 if (GET_CODE (x) == PLUS)
4356 x = XEXP (x, 0);
4357 if (GET_CODE (x) != SYMBOL_REF)
4358 return 0;
4360 c = XSTR (x, 0);
4361 if (memcmp (c, "@s.", 3) == 0)
4362 return 1;
4364 return 0;
4368 rl78_sfr_p (rtx x)
4370 if (MEM_P (x))
4371 x = XEXP (x, 0);
4372 if (GET_CODE (x) != CONST_INT)
4373 return 0;
4375 if ((INTVAL (x) & 0xFF00) != 0xFF00)
4376 return 0;
4378 return 1;
4381 #undef TARGET_STRIP_NAME_ENCODING
4382 #define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding
4384 static const char *
4385 rl78_strip_name_encoding (const char * sym)
4387 while (1)
4389 if (*sym == '*')
4390 sym++;
4391 else if (*sym == '@' && sym[2] == '.')
4392 sym += 3;
4393 else
4394 return sym;
4398 /* Like rl78_strip_name_encoding, but does not strip leading asterisks. This
4399 is important if the stripped name is going to be passed to assemble_name()
4400 as that handles asterisk prefixed names in a special manner. */
4402 static const char *
4403 rl78_strip_nonasm_name_encoding (const char * sym)
4405 while (1)
4407 if (*sym == '@' && sym[2] == '.')
4408 sym += 3;
4409 else
4410 return sym;
4415 static int
4416 rl78_attrlist_to_encoding (tree list, tree decl ATTRIBUTE_UNUSED)
4418 while (list)
4420 if (is_attribute_p ("saddr", TREE_PURPOSE (list)))
4421 return 's';
4422 list = TREE_CHAIN (list);
4425 return 0;
4428 #define RL78_ATTRIBUTES(decl) \
4429 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
4430 : DECL_ATTRIBUTES (decl) \
4431 ? (DECL_ATTRIBUTES (decl)) \
4432 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
4434 #undef TARGET_ENCODE_SECTION_INFO
4435 #define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info
4437 static void
4438 rl78_encode_section_info (tree decl, rtx rtl, int first)
4440 rtx rtlname;
4441 const char * oldname;
4442 char encoding;
4443 char * newname;
4444 tree idp;
4445 tree type;
4446 tree rl78_attributes;
4448 if (!first)
4449 return;
4451 rtlname = XEXP (rtl, 0);
4453 if (GET_CODE (rtlname) == SYMBOL_REF)
4454 oldname = XSTR (rtlname, 0);
4455 else if (GET_CODE (rtlname) == MEM
4456 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
4457 oldname = XSTR (XEXP (rtlname, 0), 0);
4458 else
4459 gcc_unreachable ();
4461 type = TREE_TYPE (decl);
4462 if (type == error_mark_node)
4463 return;
4464 if (! DECL_P (decl))
4465 return;
4466 rl78_attributes = RL78_ATTRIBUTES (decl);
4468 encoding = rl78_attrlist_to_encoding (rl78_attributes, decl);
4470 if (encoding)
4472 newname = (char *) alloca (strlen (oldname) + 4);
4473 sprintf (newname, "@%c.%s", encoding, oldname);
4474 idp = get_identifier (newname);
4475 XEXP (rtl, 0) =
4476 gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
4477 SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl);
4478 SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl);
4482 #undef TARGET_ASM_INIT_SECTIONS
4483 #define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections
4485 static void
4486 rl78_asm_init_sections (void)
4488 saddr_section
4489 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
4490 "\t.section .saddr,\"aw\",@progbits");
4491 frodata_section
4492 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
4493 "\t.section .frodata,\"aw\",@progbits");
4496 #undef TARGET_ASM_SELECT_SECTION
4497 #define TARGET_ASM_SELECT_SECTION rl78_select_section
4499 static section *
4500 rl78_select_section (tree decl,
4501 int reloc,
4502 unsigned HOST_WIDE_INT align)
4504 int readonly = 1;
4506 switch (TREE_CODE (decl))
4508 case VAR_DECL:
4509 if (!TREE_READONLY (decl)
4510 || TREE_SIDE_EFFECTS (decl)
4511 || !DECL_INITIAL (decl)
4512 || (DECL_INITIAL (decl) != error_mark_node
4513 && !TREE_CONSTANT (DECL_INITIAL (decl))))
4514 readonly = 0;
4515 break;
4516 case CONSTRUCTOR:
4517 if (! TREE_CONSTANT (decl))
4518 readonly = 0;
4519 break;
4521 default:
4522 break;
4525 if (TREE_CODE (decl) == VAR_DECL)
4527 const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4529 if (name[0] == '@' && name[2] == '.')
4530 switch (name[1])
4532 case 's':
4533 return saddr_section;
4536 if (TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_FAR
4537 && readonly)
4539 return frodata_section;
4543 if (readonly)
4544 return TARGET_ES0 ? frodata_section : readonly_data_section;
4546 switch (categorize_decl_for_section (decl, reloc))
4548 case SECCAT_TEXT: return text_section;
4549 case SECCAT_DATA: return data_section;
4550 case SECCAT_BSS: return bss_section;
4551 case SECCAT_RODATA: return TARGET_ES0 ? frodata_section : readonly_data_section;
4552 default:
4553 return default_select_section (decl, reloc, align);
4557 void
4558 rl78_output_labelref (FILE *file, const char *str)
4560 const char *str2;
4562 str2 = targetm.strip_name_encoding (str);
4563 if (str2[0] != '.')
4564 fputs (user_label_prefix, file);
4565 fputs (str2, file);
4568 void
4569 rl78_output_aligned_common (FILE *stream,
4570 tree decl ATTRIBUTE_UNUSED,
4571 const char *name,
4572 int size, int align, int global)
4574 /* We intentionally don't use rl78_section_tag() here. */
4575 if (name[0] == '@' && name[2] == '.')
4577 const char *sec = 0;
4578 switch (name[1])
4580 case 's':
4581 switch_to_section (saddr_section);
4582 sec = ".saddr";
4583 break;
4585 if (sec)
4587 const char *name2;
4588 int p2align = 0;
4590 while (align > BITS_PER_UNIT)
4592 align /= 2;
4593 p2align ++;
4595 name2 = targetm.strip_name_encoding (name);
4596 if (global)
4597 fprintf (stream, "\t.global\t_%s\n", name2);
4598 fprintf (stream, "\t.p2align %d\n", p2align);
4599 fprintf (stream, "\t.type\t_%s,@object\n", name2);
4600 fprintf (stream, "\t.size\t_%s,%d\n", name2, size);
4601 fprintf (stream, "_%s:\n\t.zero\t%d\n", name2, size);
4602 return;
4606 if (!global)
4608 fprintf (stream, "\t.local\t");
4609 assemble_name (stream, name);
4610 fprintf (stream, "\n");
4612 fprintf (stream, "\t.comm\t");
4613 assemble_name (stream, name);
4614 fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);
4617 #undef TARGET_INSERT_ATTRIBUTES
4618 #define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes
4620 static void
4621 rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED)
4623 if (TARGET_ES0
4624 && TREE_CODE (decl) == VAR_DECL
4625 && TREE_READONLY (decl)
4626 && TREE_ADDRESSABLE (decl)
4627 && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_GENERIC)
4629 tree type = TREE_TYPE (decl);
4630 tree attr = TYPE_ATTRIBUTES (type);
4631 int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR);
4633 TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q);
4637 #undef TARGET_ASM_INTEGER
4638 #define TARGET_ASM_INTEGER rl78_asm_out_integer
4640 static bool
4641 rl78_asm_out_integer (rtx x, unsigned int size, int aligned_p)
4643 if (default_assemble_integer (x, size, aligned_p))
4644 return true;
4646 if (size == 4)
4648 assemble_integer_with_op (".long\t", x);
4649 return true;
4652 return false;
4655 #undef TARGET_UNWIND_WORD_MODE
4656 #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
4658 static scalar_int_mode
4659 rl78_unwind_word_mode (void)
4661 return HImode;
4664 #ifndef USE_COLLECT2
4665 #undef TARGET_ASM_CONSTRUCTOR
4666 #define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor
4667 #undef TARGET_ASM_DESTRUCTOR
4668 #define TARGET_ASM_DESTRUCTOR rl78_asm_destructor
4670 static void
4671 rl78_asm_ctor_dtor (rtx symbol, int priority, bool is_ctor)
4673 section *sec;
4675 if (priority != DEFAULT_INIT_PRIORITY)
4677 /* This section of the function is based upon code copied
4678 from: gcc/varasm.c:get_cdtor_priority_section(). */
4679 char buf[18];
4681 sprintf (buf, "%s.%.5u", is_ctor ? ".ctors" : ".dtors",
4682 MAX_INIT_PRIORITY - priority);
4683 sec = get_section (buf, 0, NULL);
4685 else
4686 sec = is_ctor ? ctors_section : dtors_section;
4688 assemble_addr_to_section (symbol, sec);
4691 static void
4692 rl78_asm_constructor (rtx symbol, int priority)
4694 rl78_asm_ctor_dtor (symbol, priority, true);
4697 static void
4698 rl78_asm_destructor (rtx symbol, int priority)
4700 rl78_asm_ctor_dtor (symbol, priority, false);
4702 #endif /* ! USE_COLLECT2 */
4704 /* Scan backwards through the insn chain looking to see if the flags
4705 have been set for a comparison of OP against OPERAND. Start with
4706 the insn *before* the current insn. */
4708 bool
4709 rl78_flags_already_set (rtx op, rtx operand)
4711 /* We only track the Z flag. */
4712 if (GET_CODE (op) != EQ && GET_CODE (op) != NE)
4713 return false;
4715 /* This should not happen, but let's be paranoid. */
4716 if (current_output_insn == NULL_RTX)
4717 return false;
4719 rtx_insn *insn;
4720 bool res = false;
4722 for (insn = prev_nonnote_nondebug_insn (current_output_insn);
4723 insn != NULL_RTX;
4724 insn = prev_nonnote_nondebug_insn (insn))
4726 if (LABEL_P (insn))
4727 break;
4729 if (! INSN_P (insn))
4730 continue;
4732 /* Make sure that the insn can be recognized. */
4733 if (recog_memoized (insn) == -1)
4734 continue;
4736 enum attr_update_Z updated = get_attr_update_Z (insn);
4738 rtx set = single_set (insn);
4739 bool must_break = (set != NULL_RTX && rtx_equal_p (operand, SET_DEST (set)));
4741 switch (updated)
4743 case UPDATE_Z_NO:
4744 break;
4745 case UPDATE_Z_CLOBBER:
4746 must_break = true;
4747 break;
4748 case UPDATE_Z_UPDATE_Z:
4749 res = must_break;
4750 must_break = true;
4751 break;
4752 default:
4753 gcc_unreachable ();
4756 if (must_break)
4757 break;
4760 /* We have to re-recognize the current insn as the call(s) to
4761 get_attr_update_Z() above will have overwritten the recog_data cache. */
4762 recog_memoized (current_output_insn);
4763 cleanup_subreg_operands (current_output_insn);
4764 constrain_operands_cached (current_output_insn, 1);
4766 return res;
4769 const char *
4770 rl78_addsi3_internal (rtx * operands, unsigned int alternative)
4772 /* If we are adding in a constant symbolic address when -mes0
4773 is active then we know that the address must be <64K and
4774 that it is invalid to access anything above 64K relative to
4775 this address. So we can skip adding in the high bytes. */
4776 if (TARGET_ES0
4777 && GET_CODE (operands[2]) == SYMBOL_REF
4778 && TREE_CODE (SYMBOL_REF_DECL (operands[2])) == VAR_DECL
4779 && TREE_READONLY (SYMBOL_REF_DECL (operands[2]))
4780 && ! TREE_SIDE_EFFECTS (SYMBOL_REF_DECL (operands[2])))
4781 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax";
4783 switch (alternative)
4785 case 0:
4786 case 1:
4787 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax\n\tmovw ax, %H1\n\tsknc\n\tincw ax\n\taddw ax, %H2\n\tmovw %H0, ax";
4788 case 2:
4789 return "movw ax, %h1\n\taddw ax,%h2\n\tmovw bc, ax\n\tmovw ax, %H1\n\tsknc\n\tincw ax\n\taddw ax, %H2\n\tmovw %H0, ax\n\tmovw ax, bc\n\tmovw %h0, ax";
4790 default:
4791 gcc_unreachable ();
4796 rl78_emit_libcall (const char *name, enum rtx_code code,
4797 enum machine_mode dmode, enum machine_mode smode,
4798 int noperands, rtx *operands)
4800 rtx ret;
4801 rtx_insn *insns;
4802 rtx libcall;
4803 rtx equiv;
4805 start_sequence ();
4806 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
4808 switch (noperands)
4810 case 2:
4811 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
4812 dmode, operands[1], smode);
4813 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
4814 break;
4816 case 3:
4817 ret = emit_library_call_value (libcall, NULL_RTX,
4818 LCT_CONST, dmode,
4819 operands[1], smode, operands[2],
4820 smode);
4821 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
4822 break;
4824 default:
4825 gcc_unreachable ();
4828 insns = get_insns ();
4829 end_sequence ();
4830 emit_libcall_block (insns, operands[0], ret, equiv);
4831 return ret;
4835 #undef TARGET_PREFERRED_RELOAD_CLASS
4836 #define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
4838 static reg_class_t
4839 rl78_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t rclass)
4841 if (rclass == NO_REGS)
4842 rclass = V_REGS;
4844 return rclass;
4848 struct gcc_target targetm = TARGET_INITIALIZER;
4850 #include "gt-rl78.h"