]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/rl78/rl78.c
gcc/
[thirdparty/gcc.git] / gcc / config / rl78 / rl78.c
CommitLineData
78e515f7 1/* Subroutines used for code generation on Renesas RL78 processors.
d353bf18 2 Copyright (C) 2011-2015 Free Software Foundation, Inc.
78e515f7 3 Contributed by Red Hat.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
b20a8bb4 25#include "alias.h"
26#include "symtab.h"
78e515f7 27#include "tree.h"
b20a8bb4 28#include "fold-const.h"
9ed99284 29#include "varasm.h"
30#include "stor-layout.h"
31#include "calls.h"
78e515f7 32#include "rtl.h"
33#include "regs.h"
34#include "hard-reg-set.h"
35#include "insn-config.h"
36#include "conditions.h"
37#include "output.h"
38#include "insn-attr.h"
39#include "flags.h"
40#include "function.h"
d53441c8 41#include "expmed.h"
42#include "dojump.h"
43#include "explow.h"
44#include "emit-rtl.h"
45#include "stmt.h"
78e515f7 46#include "expr.h"
34517c64 47#include "insn-codes.h"
78e515f7 48#include "optabs.h"
49#include "libfuncs.h"
50#include "recog.h"
51#include "diagnostic-core.h"
52#include "toplev.h"
53#include "reload.h"
94ea8568 54#include "dominance.h"
55#include "cfg.h"
56#include "cfgrtl.h"
57#include "cfganal.h"
58#include "lcm.h"
59#include "cfgbuild.h"
60#include "cfgcleanup.h"
61#include "predict.h"
62#include "basic-block.h"
78e515f7 63#include "df.h"
78e515f7 64#include "tm_p.h"
65#include "debug.h"
66#include "target.h"
67#include "target-def.h"
68#include "langhooks.h"
69#include "rl78-protos.h"
b9ed1410 70#include "dumpfile.h"
f4d26dae 71#include "tree-pass.h"
4abac0f0 72#include "context.h"
3f3556f1 73#include "tm-constrs.h" /* for satisfies_constraint_*(). */
74#include "insn-flags.h" /* for gen_*(). */
f7715905 75#include "builtins.h"
0c5d0bfa 76#include "stringpool.h"
78e515f7 77\f
78static inline bool is_interrupt_func (const_tree decl);
79static inline bool is_brk_interrupt_func (const_tree decl);
80static void rl78_reorg (void);
0c5d0bfa 81static const char *rl78_strip_name_encoding (const char *);
82static const char *rl78_strip_nonasm_name_encoding (const char *);
83static section * rl78_select_section (tree, int, unsigned HOST_WIDE_INT);
78e515f7 84\f
85
86/* Debugging statements are tagged with DEBUG0 only so that they can
87 be easily enabled individually, by replacing the '0' with '1' as
88 needed. */
89#define DEBUG0 0
90#define DEBUG1 1
91
92/* REGISTER_NAMES has the names for individual 8-bit registers, but
93 these have the names we need to use when referring to 16-bit
94 register pairs. */
95static const char * const word_regnames[] =
96{
97 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
98 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
99 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
100 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
101 "sp", "ap", "psw", "es", "cs"
102};
103
104struct GTY(()) machine_function
105{
106 /* If set, the rest of the fields have been computed. */
107 int computed;
108 /* Which register pairs need to be pushed in the prologue. */
109 int need_to_push [FIRST_PSEUDO_REGISTER / 2];
110
111 /* These fields describe the frame layout... */
112 /* arg pointer */
113 /* 4 bytes for saved PC */
114 int framesize_regs;
115 /* frame pointer */
116 int framesize_locals;
117 int framesize_outgoing;
118 /* stack pointer */
119 int framesize;
120
121 /* If set, recog is allowed to match against the "real" patterns. */
122 int real_insns_ok;
123 /* If set, recog is allowed to match against the "virtual" patterns. */
124 int virt_insns_ok;
125 /* Set if the current function needs to clean up any trampolines. */
126 int trampolines_used;
93e93552 127 /* True if the ES register is used and hence
128 needs to be saved inside interrupt handlers. */
129 bool uses_es;
78e515f7 130};
131
132/* This is our init_machine_status, as set in
133 rl78_option_override. */
134static struct machine_function *
135rl78_init_machine_status (void)
136{
137 struct machine_function *m;
138
25a27413 139 m = ggc_cleared_alloc<machine_function> ();
78e515f7 140 m->virt_insns_ok = 1;
141
142 return m;
143}
144
78e515f7 145/* This pass converts virtual instructions using virtual registers, to
146 real instructions using real registers. Rather than run it as
147 reorg, we reschedule it before vartrack to help with debugging. */
93e93552 148namespace
149{
150 const pass_data pass_data_rl78_devirt =
151 {
152 RTL_PASS, /* type */
153 "devirt", /* name */
154 OPTGROUP_NONE, /* optinfo_flags */
155 TV_MACH_DEP, /* tv_id */
156 0, /* properties_required */
157 0, /* properties_provided */
158 0, /* properties_destroyed */
159 0, /* todo_flags_start */
160 0, /* todo_flags_finish */
161 };
78e515f7 162
93e93552 163 class pass_rl78_devirt : public rtl_opt_pass
4abac0f0 164 {
93e93552 165 public:
166 pass_rl78_devirt (gcc::context *ctxt)
167 : rtl_opt_pass (pass_data_rl78_devirt, ctxt)
168 {
169 }
4abac0f0 170
93e93552 171 /* opt_pass methods: */
172 virtual unsigned int execute (function *)
65b0537f 173 {
174 rl78_reorg ();
175 return 0;
176 }
93e93552 177 };
4abac0f0 178} // anon namespace
179
180rtl_opt_pass *
181make_pass_rl78_devirt (gcc::context *ctxt)
182{
183 return new pass_rl78_devirt (ctxt);
184}
185
1d701d79 186/* Redundant move elimination pass. Must be run after the basic block
187 reordering pass for the best effect. */
188
3f3556f1 189static unsigned int
190move_elim_pass (void)
191{
50fc2d35 192 rtx_insn *insn, *ninsn;
193 rtx prev = NULL_RTX;
3f3556f1 194
195 for (insn = get_insns (); insn; insn = ninsn)
196 {
197 rtx set;
198
199 ninsn = next_nonnote_nondebug_insn (insn);
200
201 if ((set = single_set (insn)) == NULL_RTX)
202 {
203 prev = NULL_RTX;
204 continue;
205 }
206
207 /* If we have two SET insns in a row (without anything
208 between them) and the source of the second one is the
209 destination of the first one, and vice versa, then we
210 can eliminate the second SET. */
211 if (prev
212 && rtx_equal_p (SET_DEST (prev), SET_SRC (set))
f648448d 213 && rtx_equal_p (SET_DEST (set), SET_SRC (prev))
214 /* ... and none of the operands are volatile. */
215 && ! volatile_refs_p (SET_SRC (prev))
216 && ! volatile_refs_p (SET_DEST (prev))
217 && ! volatile_refs_p (SET_SRC (set))
218 && ! volatile_refs_p (SET_DEST (set)))
3f3556f1 219 {
220 if (dump_file)
221 fprintf (dump_file, " Delete insn %d because it is redundant\n",
222 INSN_UID (insn));
223
224 delete_insn (insn);
225 prev = NULL_RTX;
226 }
227 else
228 prev = set;
229 }
93e93552 230
3f3556f1 231 if (dump_file)
232 print_rtl_with_bb (dump_file, get_insns (), 0);
233
234 return 0;
235}
236
93e93552 237namespace
3f3556f1 238{
93e93552 239 const pass_data pass_data_rl78_move_elim =
240 {
241 RTL_PASS, /* type */
242 "move_elim", /* name */
243 OPTGROUP_NONE, /* optinfo_flags */
244 TV_MACH_DEP, /* tv_id */
245 0, /* properties_required */
246 0, /* properties_provided */
247 0, /* properties_destroyed */
248 0, /* todo_flags_start */
249 0, /* todo_flags_finish */
250 };
3f3556f1 251
93e93552 252 class pass_rl78_move_elim : public rtl_opt_pass
3f3556f1 253 {
93e93552 254 public:
255 pass_rl78_move_elim (gcc::context *ctxt)
256 : rtl_opt_pass (pass_data_rl78_move_elim, ctxt)
257 {
258 }
3f3556f1 259
93e93552 260 /* opt_pass methods: */
261 virtual unsigned int execute (function *) { return move_elim_pass (); }
262 };
3f3556f1 263} // anon namespace
264
265rtl_opt_pass *
266make_pass_rl78_move_elim (gcc::context *ctxt)
267{
268 return new pass_rl78_move_elim (ctxt);
269}
4abac0f0 270
78e515f7 271#undef TARGET_ASM_FILE_START
272#define TARGET_ASM_FILE_START rl78_asm_file_start
273
274static void
275rl78_asm_file_start (void)
276{
277 int i;
278
c5a0ae5e 279 if (TARGET_G10)
78e515f7 280 {
c5a0ae5e 281 /* The memory used is 0xffec8 to 0xffedf; real registers are in
282 0xffee0 to 0xffee7. */
283 for (i = 8; i < 32; i++)
284 fprintf (asm_out_file, "r%d\t=\t0x%x\n", i, 0xffec0 + i);
285 }
286 else
287 {
288 for (i = 0; i < 8; i++)
289 {
290 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 8 + i, 0xffef0 + i);
291 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 16 + i, 0xffee8 + i);
55ea1438 292 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 24 + i, 0xffee0 + i);
c5a0ae5e 293 }
78e515f7 294 }
295
4abac0f0 296 opt_pass *rl78_devirt_pass = make_pass_rl78_devirt (g);
33c6d8ad 297 struct register_pass_info rl78_devirt_info =
4abac0f0 298 {
299 rl78_devirt_pass,
3f3556f1 300 "pro_and_epilogue",
4abac0f0 301 1,
302 PASS_POS_INSERT_BEFORE
303 };
304
3f3556f1 305 opt_pass *rl78_move_elim_pass = make_pass_rl78_move_elim (g);
33c6d8ad 306 struct register_pass_info rl78_move_elim_info =
3f3556f1 307 {
308 rl78_move_elim_pass,
309 "bbro",
310 1,
311 PASS_POS_INSERT_AFTER
312 };
313
78e515f7 314 register_pass (& rl78_devirt_info);
3f3556f1 315 register_pass (& rl78_move_elim_info);
78e515f7 316}
317
0c5d0bfa 318void
319rl78_output_symbol_ref (FILE * file, rtx sym)
320{
321 tree type = SYMBOL_REF_DECL (sym);
322 const char *str = XSTR (sym, 0);
323
324 if (str[0] == '*')
325 {
326 fputs (str + 1, file);
327 }
328 else
329 {
330 str = rl78_strip_nonasm_name_encoding (str);
331 if (type && TREE_CODE (type) == FUNCTION_DECL)
332 {
333 fprintf (file, "%%code(");
334 assemble_name (file, str);
335 fprintf (file, ")");
336 }
337 else
338 assemble_name (file, str);
339 }
340}
78e515f7 341\f
342#undef TARGET_OPTION_OVERRIDE
343#define TARGET_OPTION_OVERRIDE rl78_option_override
344
345static void
346rl78_option_override (void)
347{
348 flag_omit_frame_pointer = 1;
349 flag_no_function_cse = 1;
350 flag_split_wide_types = 0;
351
352 init_machine_status = rl78_init_machine_status;
55ea1438 353
354 if (TARGET_ALLREGS)
355 {
356 int i;
1d701d79 357
358 for (i = 24; i < 32; i++)
55ea1438 359 fixed_regs[i] = 0;
360 }
0c5d0bfa 361
362 if (TARGET_ES0
363 && strcmp (lang_hooks.name, "GNU C")
364 /* Compiling with -flto results in a language of GNU GIMPLE being used... */
365 && strcmp (lang_hooks.name, "GNU GIMPLE"))
366 /* Address spaces are currently only supported by C. */
367 error ("-mes0 can only be used with C");
e98e1692 368
369 switch (rl78_cpu_type)
370 {
371 case CPU_UNINIT:
372 rl78_cpu_type = CPU_G14;
373 if (rl78_mul_type == MUL_UNINIT)
374 rl78_mul_type = MUL_NONE;
375 break;
376
377 case CPU_G10:
378 switch (rl78_mul_type)
379 {
380 case MUL_UNINIT: rl78_mul_type = MUL_NONE; break;
381 case MUL_NONE: break;
382 case MUL_G13: error ("-mmul=g13 cannot be used with -mcpu=g10"); break;
383 case MUL_G14: error ("-mmul=g14 cannot be used with -mcpu=g10"); break;
384 }
385 break;
386
387 case CPU_G13:
388 switch (rl78_mul_type)
389 {
390 case MUL_UNINIT: rl78_mul_type = MUL_G13; break;
391 case MUL_NONE: break;
392 case MUL_G13: break;
393 /* The S2 core does not have mul/div instructions. */
394 case MUL_G14: error ("-mmul=g14 cannot be used with -mcpu=g13"); break;
395 }
396 break;
397
398 case CPU_G14:
399 switch (rl78_mul_type)
400 {
401 case MUL_UNINIT: rl78_mul_type = MUL_G14; break;
402 case MUL_NONE: break;
403 case MUL_G14: break;
404 /* The G14 core does not have the hardware multiply peripheral used by the
405 G13 core, hence you cannot use G13 multipliy routines on G14 hardware. */
406 case MUL_G13: error ("-mmul=g13 cannot be used with -mcpu=g14"); break;
407 }
408 break;
409 }
78e515f7 410}
411
412/* Most registers are 8 bits. Some are 16 bits because, for example,
8a6bcd4e 413 gcc doesn't like dealing with $FP as a register pair (the second
414 half of $fp is also 2 to keep reload happy wrt register pairs, but
415 no register class includes it). This table maps register numbers
416 to size in bytes. */
78e515f7 417static const int register_sizes[] =
418{
419 1, 1, 1, 1, 1, 1, 1, 1,
420 1, 1, 1, 1, 1, 1, 1, 1,
8a6bcd4e 421 1, 1, 1, 1, 1, 1, 2, 2,
78e515f7 422 1, 1, 1, 1, 1, 1, 1, 1,
423 2, 2, 1, 1, 1
424};
425
426/* Predicates used in the MD patterns. This one is true when virtual
427 insns may be matched, which typically means before (or during) the
428 devirt pass. */
429bool
430rl78_virt_insns_ok (void)
431{
432 if (cfun)
433 return cfun->machine->virt_insns_ok;
434 return true;
435}
436
437/* Predicates used in the MD patterns. This one is true when real
438 insns may be matched, which typically means after (or during) the
439 devirt pass. */
440bool
441rl78_real_insns_ok (void)
442{
443 if (cfun)
444 return cfun->machine->real_insns_ok;
445 return false;
446}
447
448/* Implements HARD_REGNO_NREGS. */
449int
3754d046 450rl78_hard_regno_nregs (int regno, machine_mode mode)
78e515f7 451{
452 int rs = register_sizes[regno];
453 if (rs < 1)
454 rs = 1;
455 return ((GET_MODE_SIZE (mode) + rs - 1) / rs);
456}
457
458/* Implements HARD_REGNO_MODE_OK. */
459int
3754d046 460rl78_hard_regno_mode_ok (int regno, machine_mode mode)
78e515f7 461{
462 int s = GET_MODE_SIZE (mode);
463
464 if (s < 1)
465 return 0;
466 /* These are not to be used by gcc. */
467 if (regno == 23 || regno == ES_REG || regno == CS_REG)
468 return 0;
8a6bcd4e 469 /* $fp can always be accessed as a 16-bit value. */
78e515f7 470 if (regno == FP_REG && s == 2)
471 return 1;
472 if (regno < SP_REG)
473 {
474 /* Since a reg-reg move is really a reg-mem move, we must
475 enforce alignment. */
476 if (s > 1 && (regno % 2))
477 return 0;
478 return 1;
479 }
480 if (s == CC_REGNUM)
481 return (mode == BImode);
482 /* All other registers must be accessed in their natural sizes. */
483 if (s == register_sizes [regno])
484 return 1;
485 return 0;
486}
487
488/* Simplify_gen_subreg() doesn't handle memory references the way we
489 need it to below, so we use this function for when we must get a
490 valid subreg in a "natural" state. */
491static rtx
3754d046 492rl78_subreg (machine_mode mode, rtx r, machine_mode omode, int byte)
78e515f7 493{
494 if (GET_CODE (r) == MEM)
495 return adjust_address (r, mode, byte);
496 else
497 return simplify_gen_subreg (mode, r, omode, byte);
498}
499
500/* Used by movsi. Split SImode moves into two HImode moves, using
501 appropriate patterns for the upper and lower halves of symbols. */
502void
503rl78_expand_movsi (rtx *operands)
504{
505 rtx op00, op02, op10, op12;
506
507 op00 = rl78_subreg (HImode, operands[0], SImode, 0);
508 op02 = rl78_subreg (HImode, operands[0], SImode, 2);
509 if (GET_CODE (operands[1]) == CONST
510 || GET_CODE (operands[1]) == SYMBOL_REF)
511 {
512 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
513 op10 = gen_rtx_CONST (HImode, op10);
514 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
515 op12 = gen_rtx_CONST (HImode, op12);
516 }
517 else
518 {
519 op10 = rl78_subreg (HImode, operands[1], SImode, 0);
520 op12 = rl78_subreg (HImode, operands[1], SImode, 2);
521 }
522
523 if (rtx_equal_p (operands[0], operands[1]))
524 ;
525 else if (rtx_equal_p (op00, op12))
526 {
527 emit_move_insn (op02, op12);
528 emit_move_insn (op00, op10);
529 }
530 else
531 {
532 emit_move_insn (op00, op10);
533 emit_move_insn (op02, op12);
534 }
535}
536
1d701d79 537/* Generate code to move an SImode value. */
3f3556f1 538void
29236229 539rl78_split_movsi (rtx *operands, enum machine_mode omode)
3f3556f1 540{
541 rtx op00, op02, op10, op12;
542
29236229 543 op00 = rl78_subreg (HImode, operands[0], omode, 0);
544 op02 = rl78_subreg (HImode, operands[0], omode, 2);
1d701d79 545
3f3556f1 546 if (GET_CODE (operands[1]) == CONST
547 || GET_CODE (operands[1]) == SYMBOL_REF)
548 {
549 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
550 op10 = gen_rtx_CONST (HImode, op10);
551 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
552 op12 = gen_rtx_CONST (HImode, op12);
553 }
554 else
555 {
29236229 556 op10 = rl78_subreg (HImode, operands[1], omode, 0);
557 op12 = rl78_subreg (HImode, operands[1], omode, 2);
3f3556f1 558 }
559
560 if (rtx_equal_p (operands[0], operands[1]))
561 ;
562 else if (rtx_equal_p (op00, op12))
563 {
564 operands[2] = op02;
565 operands[4] = op12;
566 operands[3] = op00;
567 operands[5] = op10;
568 }
569 else
570 {
571 operands[2] = op00;
572 operands[4] = op10;
573 operands[3] = op02;
574 operands[5] = op12;
575 }
576}
577
78e515f7 578/* Used by various two-operand expanders which cannot accept all
579 operands in the "far" namespace. Force some such operands into
580 registers so that each pattern has at most one far operand. */
581int
582rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx))
583{
584 int did = 0;
585 rtx temp_reg = NULL;
586
587 /* FIXME: in the future, be smarter about only doing this if the
588 other operand is also far, assuming the devirtualizer can also
589 handle that. */
590 if (rl78_far_p (operands[0]))
591 {
592 temp_reg = operands[0];
593 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
594 did = 1;
595 }
596 if (!did)
597 return 0;
598
599 emit_insn (gen (operands[0], operands[1]));
600 if (temp_reg)
601 emit_move_insn (temp_reg, operands[0]);
602 return 1;
603}
604
605/* Likewise, but for three-operand expanders. */
606int
607rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx))
608{
609 int did = 0;
610 rtx temp_reg = NULL;
611
750dcfc5 612 /* As an exception, we allow two far operands if they're identical
613 and the third operand is not a MEM. This allows global variables
614 to be incremented, for example. */
615 if (rtx_equal_p (operands[0], operands[1])
616 && ! MEM_P (operands[2]))
617 return 0;
618
78e515f7 619 /* FIXME: Likewise. */
620 if (rl78_far_p (operands[1]))
621 {
622 rtx temp_reg = gen_reg_rtx (GET_MODE (operands[1]));
623 emit_move_insn (temp_reg, operands[1]);
624 operands[1] = temp_reg;
625 did = 1;
626 }
627 if (rl78_far_p (operands[0]))
628 {
629 temp_reg = operands[0];
630 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
631 did = 1;
632 }
633 if (!did)
634 return 0;
635
636 emit_insn (gen (operands[0], operands[1], operands[2]));
637 if (temp_reg)
638 emit_move_insn (temp_reg, operands[0]);
639 return 1;
640}
641
642#undef TARGET_CAN_ELIMINATE
643#define TARGET_CAN_ELIMINATE rl78_can_eliminate
644
645static bool
646rl78_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to ATTRIBUTE_UNUSED)
647{
648 return true;
649}
650
69b00414 651/* Returns true if the given register needs to be saved by the
78e515f7 652 current function. */
69b00414 653static bool
654need_to_save (unsigned int regno)
78e515f7 655{
656 if (is_interrupt_func (cfun->decl))
657 {
1d701d79 658 /* We don't know what devirt will need */
659 if (regno < 8)
660 return true;
661
69b00414 662 /* We don't need to save registers that have
663 been reserved for interrupt handlers. */
78e515f7 664 if (regno > 23)
69b00414 665 return false;
666
667 /* If the handler is a non-leaf function then it may call
668 non-interrupt aware routines which will happily clobber
70f723f8 669 any call_used registers, so we have to preserve them.
670 We do not have to worry about the frame pointer register
671 though, as that is handled below. */
672 if (!crtl->is_leaf && call_used_regs[regno] && regno < 22)
69b00414 673 return true;
674
675 /* Otherwise we only have to save a register, call_used
676 or not, if it is used by this handler. */
677 return df_regs_ever_live_p (regno);
78e515f7 678 }
69b00414 679
52337e94 680 if (regno == FRAME_POINTER_REGNUM
681 && (frame_pointer_needed || df_regs_ever_live_p (regno)))
69b00414 682 return true;
78e515f7 683 if (fixed_regs[regno])
69b00414 684 return false;
78e515f7 685 if (crtl->calls_eh_return)
69b00414 686 return true;
78e515f7 687 if (df_regs_ever_live_p (regno)
688 && !call_used_regs[regno])
69b00414 689 return true;
690 return false;
78e515f7 691}
692
693/* We use this to wrap all emitted insns in the prologue. */
694static rtx
695F (rtx x)
696{
697 RTX_FRAME_RELATED_P (x) = 1;
698 return x;
699}
700
701/* Compute all the frame-related fields in our machine_function
702 structure. */
703static void
704rl78_compute_frame_info (void)
705{
706 int i;
707
708 cfun->machine->computed = 1;
709 cfun->machine->framesize_regs = 0;
710 cfun->machine->framesize_locals = get_frame_size ();
711 cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
712
713 for (i = 0; i < 16; i ++)
714 if (need_to_save (i * 2) || need_to_save (i * 2 + 1))
715 {
716 cfun->machine->need_to_push [i] = 1;
717 cfun->machine->framesize_regs += 2;
718 }
719 else
720 cfun->machine->need_to_push [i] = 0;
721
722 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
723 cfun->machine->framesize_locals ++;
724
725 cfun->machine->framesize = (cfun->machine->framesize_regs
726 + cfun->machine->framesize_locals
727 + cfun->machine->framesize_outgoing);
728}
729\f
730/* Returns true if the provided function has the specified attribute. */
731static inline bool
732has_func_attr (const_tree decl, const char * func_attr)
733{
734 if (decl == NULL_TREE)
735 decl = current_function_decl;
736
737 return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
738}
739
740/* Returns true if the provided function has the "interrupt" attribute. */
741static inline bool
742is_interrupt_func (const_tree decl)
743{
744 return has_func_attr (decl, "interrupt") || has_func_attr (decl, "brk_interrupt");
745}
746
747/* Returns true if the provided function has the "brk_interrupt" attribute. */
748static inline bool
749is_brk_interrupt_func (const_tree decl)
750{
751 return has_func_attr (decl, "brk_interrupt");
752}
753
754/* Check "interrupt" attributes. */
755static tree
756rl78_handle_func_attribute (tree * node,
8a6bcd4e 757 tree name,
758 tree args,
759 int flags ATTRIBUTE_UNUSED,
760 bool * no_add_attrs)
78e515f7 761{
762 gcc_assert (DECL_P (* node));
763 gcc_assert (args == NULL_TREE);
764
765 if (TREE_CODE (* node) != FUNCTION_DECL)
766 {
767 warning (OPT_Wattributes, "%qE attribute only applies to functions",
768 name);
769 * no_add_attrs = true;
770 }
771
772 /* FIXME: We ought to check that the interrupt and exception
773 handler attributes have been applied to void functions. */
774 return NULL_TREE;
775}
776
0c5d0bfa 777/* Check "naked" attributes. */
778static tree
779rl78_handle_naked_attribute (tree * node,
780 tree name ATTRIBUTE_UNUSED,
781 tree args,
782 int flags ATTRIBUTE_UNUSED,
783 bool * no_add_attrs)
784{
785 gcc_assert (DECL_P (* node));
786 gcc_assert (args == NULL_TREE);
787
788 if (TREE_CODE (* node) != FUNCTION_DECL)
789 {
790 warning (OPT_Wattributes, "naked attribute only applies to functions");
791 * no_add_attrs = true;
792 }
793
794 /* Disable warnings about this function - eg reaching the end without
795 seeing a return statement - because the programmer is doing things
796 that gcc does not know about. */
797 TREE_NO_WARNING (* node) = 1;
798
799 return NULL_TREE;
800}
801
802/* Check "saddr" attributes. */
803static tree
804rl78_handle_saddr_attribute (tree * node,
805 tree name,
806 tree args ATTRIBUTE_UNUSED,
807 int flags ATTRIBUTE_UNUSED,
808 bool * no_add_attrs)
809{
810 gcc_assert (DECL_P (* node));
811
812 if (TREE_CODE (* node) == FUNCTION_DECL)
813 {
814 warning (OPT_Wattributes, "%qE attribute doesn't apply to functions",
815 name);
816 * no_add_attrs = true;
817 }
818
819 return NULL_TREE;
820}
821
78e515f7 822#undef TARGET_ATTRIBUTE_TABLE
823#define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
824
825/* Table of RL78-specific attributes. */
826const struct attribute_spec rl78_attribute_table[] =
827{
828 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
829 affects_type_identity. */
830 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
831 false },
832 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
833 false },
0c5d0bfa 834 { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute,
835 false },
836 { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute,
fbac2992 837 false },
78e515f7 838 { NULL, 0, 0, false, false, false, NULL, false }
839};
840
841
842\f
843/* Break down an address RTX into its component base/index/addend
844 portions and return TRUE if the address is of a valid form, else
845 FALSE. */
846static bool
847characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
848{
849 *base = NULL_RTX;
850 *index = NULL_RTX;
851 *addend = NULL_RTX;
852
1d701d79 853 if (GET_CODE (x) == UNSPEC
854 && XINT (x, 1) == UNS_ES_ADDR)
855 x = XVECEXP (x, 0, 1);
856
78e515f7 857 if (GET_CODE (x) == REG)
858 {
859 *base = x;
860 return true;
861 }
862
863 /* We sometimes get these without the CONST wrapper */
864 if (GET_CODE (x) == PLUS
865 && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
866 && GET_CODE (XEXP (x, 1)) == CONST_INT)
867 {
868 *addend = x;
869 return true;
870 }
871
872 if (GET_CODE (x) == PLUS)
873 {
874 *base = XEXP (x, 0);
875 x = XEXP (x, 1);
876
0c5d0bfa 877 if (GET_CODE (*base) == SUBREG)
878 {
879 if (GET_MODE (*base) == HImode
880 && GET_MODE (XEXP (*base, 0)) == SImode
881 && GET_CODE (XEXP (*base, 0)) == REG)
882 {
883 /* This is a throw-away rtx just to tell everyone
884 else what effective register we're using. */
885 *base = gen_rtx_REG (HImode, REGNO (XEXP (*base, 0)));
886 }
887 }
888
78e515f7 889 if (GET_CODE (*base) != REG
890 && GET_CODE (x) == REG)
891 {
892 rtx tmp = *base;
893 *base = x;
894 x = tmp;
895 }
896
897 if (GET_CODE (*base) != REG)
898 return false;
899
900 if (GET_CODE (x) == ZERO_EXTEND
901 && GET_CODE (XEXP (x, 0)) == REG)
902 {
903 *index = XEXP (x, 0);
904 return false;
905 }
906 }
907
908 switch (GET_CODE (x))
909 {
910 case PLUS:
911 if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
912 && GET_CODE (XEXP (x, 0)) == CONST_INT)
913 {
914 *addend = x;
915 return true;
916 }
917 /* fall through */
918 case MEM:
919 case REG:
920 return false;
921
0c5d0bfa 922 case SUBREG:
923 switch (GET_CODE (XEXP (x, 0)))
924 {
925 case CONST:
926 case SYMBOL_REF:
927 case CONST_INT:
928 *addend = x;
929 return true;
930 default:
931 return false;
932 }
933
78e515f7 934 case CONST:
935 case SYMBOL_REF:
936 case CONST_INT:
937 *addend = x;
938 return true;
939
940 default:
941 return false;
942 }
943
944 return false;
945}
946
947/* Used by the Whb constraint. Match addresses that use HL+B or HL+C
948 addressing. */
949bool
950rl78_hl_b_c_addr_p (rtx op)
951{
952 rtx hl, bc;
953
954 if (GET_CODE (op) != PLUS)
955 return false;
956 hl = XEXP (op, 0);
957 bc = XEXP (op, 1);
958 if (GET_CODE (hl) == ZERO_EXTEND)
959 {
960 rtx tmp = hl;
961 hl = bc;
962 bc = tmp;
963 }
964 if (GET_CODE (hl) != REG)
965 return false;
966 if (GET_CODE (bc) != ZERO_EXTEND)
967 return false;
968 bc = XEXP (bc, 0);
969 if (GET_CODE (bc) != REG)
970 return false;
971 if (REGNO (hl) != HL_REG)
972 return false;
973 if (REGNO (bc) != B_REG && REGNO (bc) != C_REG)
974 return false;
975
976 return true;
977}
978
979#define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
980
0c5d0bfa 981/* Return the appropriate mode for a named address address. */
982
983#undef TARGET_ADDR_SPACE_ADDRESS_MODE
984#define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
985
986static enum machine_mode
987rl78_addr_space_address_mode (addr_space_t addrspace)
988{
989 switch (addrspace)
990 {
991 case ADDR_SPACE_GENERIC:
992 return HImode;
993 case ADDR_SPACE_NEAR:
994 return HImode;
995 case ADDR_SPACE_FAR:
996 return SImode;
997 default:
998 gcc_unreachable ();
999 }
1000}
1001
78e515f7 1002/* Used in various constraints and predicates to match operands in the
1003 "far" address space. */
1004int
1005rl78_far_p (rtx x)
1006{
3f3556f1 1007 if (! MEM_P (x))
78e515f7 1008 return 0;
1009#if DEBUG0
8a6bcd4e 1010 fprintf (stderr, "\033[35mrl78_far_p: "); debug_rtx (x);
3f3556f1 1011 fprintf (stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
78e515f7 1012#endif
750dcfc5 1013
1014 /* Not all far addresses are legitimate, because the devirtualizer
1015 can't handle them. */
1016 if (! rl78_as_legitimate_address (GET_MODE (x), XEXP (x, 0), false, ADDR_SPACE_FAR))
1017 return 0;
1018
0c5d0bfa 1019 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x))) == 32;
78e515f7 1020}
1021
1022/* Return the appropriate mode for a named address pointer. */
8a6bcd4e 1023#undef TARGET_ADDR_SPACE_POINTER_MODE
78e515f7 1024#define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
93e93552 1025
3754d046 1026static machine_mode
78e515f7 1027rl78_addr_space_pointer_mode (addr_space_t addrspace)
1028{
1029 switch (addrspace)
1030 {
1031 case ADDR_SPACE_GENERIC:
1032 return HImode;
0c5d0bfa 1033 case ADDR_SPACE_NEAR:
1034 return HImode;
78e515f7 1035 case ADDR_SPACE_FAR:
1036 return SImode;
1037 default:
1038 gcc_unreachable ();
1039 }
1040}
1041
556726e1 1042/* Returns TRUE for valid addresses. */
8a6bcd4e 1043#undef TARGET_VALID_POINTER_MODE
556726e1 1044#define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
93e93552 1045
556726e1 1046static bool
3754d046 1047rl78_valid_pointer_mode (machine_mode m)
556726e1 1048{
1049 return (m == HImode || m == SImode);
1050}
1051
78e515f7 1052#undef TARGET_LEGITIMATE_CONSTANT_P
1053#define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
1054
1055static bool
3754d046 1056rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED)
78e515f7 1057{
1058 return true;
1059}
1060
1061#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
1062#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
1063
1064bool
3754d046 1065rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
78e515f7 1066 bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
1067{
1068 rtx base, index, addend;
1d701d79 1069 bool is_far_addr = false;
0c5d0bfa 1070 int as_bits;
1071
1072 as_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (as));
78e515f7 1073
563dc27b 1074 if (GET_CODE (x) == UNSPEC
1075 && XINT (x, 1) == UNS_ES_ADDR)
1d701d79 1076 {
1077 x = XVECEXP (x, 0, 1);
1078 is_far_addr = true;
1079 }
563dc27b 1080
0c5d0bfa 1081 if (as_bits == 16 && is_far_addr)
78e515f7 1082 return false;
1083
1084 if (! characterize_address (x, &base, &index, &addend))
1085 return false;
1086
03e08569 1087 /* We can't extract the high/low portions of a PLUS address
1088 involving a register during devirtualization, so make sure all
1089 such __far addresses do not have addends. This forces GCC to do
1090 the sum separately. */
0c5d0bfa 1091 if (addend && base && as_bits == 32 && GET_MODE (base) == SImode)
03e08569 1092 return false;
1093
78e515f7 1094 if (base && index)
1095 {
1096 int ir = REGNO (index);
1097 int br = REGNO (base);
1098
1099#define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
1100 OK (REG_IS (br, HL_REG) && REG_IS (ir, B_REG), "[hl+b]");
1101 OK (REG_IS (br, HL_REG) && REG_IS (ir, C_REG), "[hl+c]");
1102 return false;
1103 }
1104
1105 if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER)
1106 return false;
1107
3f3556f1 1108 if (! cfun->machine->virt_insns_ok && base && GET_CODE (base) == REG
1109 && REGNO (base) >= 8 && REGNO (base) <= 31)
1110 return false;
1111
78e515f7 1112 return true;
1113}
1114
1115/* Determine if one named address space is a subset of another. */
1116#undef TARGET_ADDR_SPACE_SUBSET_P
1117#define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
93e93552 1118
78e515f7 1119static bool
1120rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
1121{
0c5d0bfa 1122 int subset_bits;
1123 int superset_bits;
78e515f7 1124
0c5d0bfa 1125 subset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset));
1126 superset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset));
78e515f7 1127
0c5d0bfa 1128 return (subset_bits <= superset_bits);
78e515f7 1129}
1130
1131#undef TARGET_ADDR_SPACE_CONVERT
1132#define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
93e93552 1133
78e515f7 1134/* Convert from one address space to another. */
1135static rtx
1136rl78_addr_space_convert (rtx op, tree from_type, tree to_type)
1137{
1138 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
1139 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
1140 rtx result;
0c5d0bfa 1141 int to_bits;
1142 int from_bits;
78e515f7 1143
0c5d0bfa 1144 to_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as));
1145 from_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as));
78e515f7 1146
0c5d0bfa 1147 if (to_bits < from_bits)
78e515f7 1148 {
0c5d0bfa 1149 rtx tmp;
78e515f7 1150 /* This is unpredictable, as we're truncating off usable address
1151 bits. */
1152
0c5d0bfa 1153 warning (OPT_Waddress, "converting far pointer to near pointer");
78e515f7 1154 result = gen_reg_rtx (HImode);
0c5d0bfa 1155 if (GET_CODE (op) == SYMBOL_REF
1156 || (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER))
1157 tmp = gen_rtx_raw_SUBREG (HImode, op, 0);
1158 else
1159 tmp = simplify_subreg (HImode, op, SImode, 0);
1160 gcc_assert (tmp != NULL_RTX);
1161 emit_move_insn (result, tmp);
78e515f7 1162 return result;
1163 }
0c5d0bfa 1164 else if (to_bits > from_bits)
78e515f7 1165 {
1166 /* This always works. */
1167 result = gen_reg_rtx (SImode);
78e515f7 1168 emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op);
0c5d0bfa 1169 if (TREE_CODE (from_type) == POINTER_TYPE
1170 && TREE_CODE (TREE_TYPE (from_type)) == FUNCTION_TYPE)
1171 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx);
1172 else
1173 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), GEN_INT (0x0f));
78e515f7 1174 return result;
1175 }
1176 else
0c5d0bfa 1177 return op;
1178 gcc_unreachable ();
78e515f7 1179}
1180
1181/* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
1182bool
3754d046 1183rl78_regno_mode_code_ok_for_base_p (int regno, machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1184 addr_space_t address_space ATTRIBUTE_UNUSED,
1185 int outer_code ATTRIBUTE_UNUSED, int index_code)
1186{
f716766f 1187 if (regno <= SP_REG && regno >= 16)
78e515f7 1188 return true;
1189 if (index_code == REG)
1190 return (regno == HL_REG);
1191 if (regno == C_REG || regno == B_REG || regno == E_REG || regno == L_REG)
1192 return true;
1193 return false;
1194}
1195
1196/* Implements MODE_CODE_BASE_REG_CLASS. */
1197enum reg_class
3754d046 1198rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1199 addr_space_t address_space ATTRIBUTE_UNUSED,
1200 int outer_code ATTRIBUTE_UNUSED,
1201 int index_code ATTRIBUTE_UNUSED)
1202{
1203 return V_REGS;
1204}
1205
93e93552 1206/* Typical stack layout should looks like this after the function's prologue:
1207
1208 | |
1209 -- ^
1210 | | \ |
1211 | | arguments saved | Increasing
1212 | | on the stack | addresses
1213 PARENT arg pointer -> | | /
1214 -------------------------- ---- -------------------
1215 CHILD |ret | return address
1216 --
1217 | | \
1218 | | call saved
1219 | | registers
1220 frame pointer -> | | /
1221 --
1222 | | \
1223 | | local
1224 | | variables
1225 | | /
1226 --
1227 | | \
1228 | | outgoing | Decreasing
1229 | | arguments | addresses
1230 current stack pointer -> | | / |
1231 -------------------------- ---- ------------------ V
1232 | | */
1233
78e515f7 1234/* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
1235 described in the machine_Function struct definition, above. */
1236int
1237rl78_initial_elimination_offset (int from, int to)
1238{
1239 int rv = 0; /* as if arg to arg */
1240
1241 rl78_compute_frame_info ();
1242
1243 switch (to)
1244 {
1245 case STACK_POINTER_REGNUM:
1246 rv += cfun->machine->framesize_outgoing;
1247 rv += cfun->machine->framesize_locals;
1248 /* Fall through. */
1249 case FRAME_POINTER_REGNUM:
1250 rv += cfun->machine->framesize_regs;
1251 rv += 4;
1252 break;
1253 default:
1254 gcc_unreachable ();
1255 }
1256
1257 switch (from)
1258 {
1259 case FRAME_POINTER_REGNUM:
1260 rv -= 4;
1261 rv -= cfun->machine->framesize_regs;
1262 case ARG_POINTER_REGNUM:
1263 break;
1264 default:
1265 gcc_unreachable ();
1266 }
1267
1268 return rv;
1269}
1270
fbac2992 1271static int
1272rl78_is_naked_func (void)
1273{
1274 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE);
1275}
1276
78e515f7 1277/* Expand the function prologue (from the prologue pattern). */
1278void
1279rl78_expand_prologue (void)
1280{
1281 int i, fs;
1282 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
90f06e32 1283 rtx ax = gen_rtx_REG (HImode, AX_REG);
78e515f7 1284 int rb = 0;
1285
fbac2992 1286 if (rl78_is_naked_func ())
1287 return;
1288
69b00414 1289 /* Always re-compute the frame info - the register usage may have changed. */
1290 rl78_compute_frame_info ();
78e515f7 1291
e4858e6a 1292 if (flag_stack_usage_info)
1293 current_function_static_stack_size = cfun->machine->framesize;
1294
c5a0ae5e 1295 if (is_interrupt_func (cfun->decl) && !TARGET_G10)
69b00414 1296 for (i = 0; i < 4; i++)
1297 if (cfun->machine->need_to_push [i])
1298 {
1299 /* Select Bank 0 if we are using any registers from Bank 0. */
1300 emit_insn (gen_sel_rb (GEN_INT (0)));
1301 break;
1302 }
8d5f09ff 1303
78e515f7 1304 for (i = 0; i < 16; i++)
1305 if (cfun->machine->need_to_push [i])
1306 {
90f06e32 1307 int reg = i * 2;
1308
c5a0ae5e 1309 if (TARGET_G10)
78e515f7 1310 {
90f06e32 1311 if (reg >= 8)
1312 {
1313 emit_move_insn (ax, gen_rtx_REG (HImode, reg));
1314 reg = AX_REG;
1315 }
78e515f7 1316 }
1d701d79 1317 else
1318 {
90f06e32 1319 int need_bank = i/4;
1d701d79 1320
1321 if (need_bank != rb)
1322 {
1323 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1324 rb = need_bank;
1325 }
1d701d79 1326 }
90f06e32 1327
1328 F (emit_insn (gen_push (gen_rtx_REG (HImode, reg))));
78e515f7 1329 }
1d701d79 1330
78e515f7 1331 if (rb != 0)
1332 emit_insn (gen_sel_rb (GEN_INT (0)));
1333
93e93552 1334 /* Save ES register inside interrupt functions if it is used. */
1335 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
1336 {
1337 emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode, A_REG)));
90f06e32 1338 F (emit_insn (gen_push (ax)));
93e93552 1339 }
1340
78e515f7 1341 if (frame_pointer_needed)
ed2d7e5b 1342 {
90f06e32 1343 F (emit_move_insn (ax, sp));
1344 F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM), ax));
ed2d7e5b 1345 }
78e515f7 1346
1347 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
90f06e32 1348 if (fs > 0)
78e515f7 1349 {
90f06e32 1350 /* If we need to subtract more than 254*3 then it is faster and
1351 smaller to move SP into AX and perform the subtraction there. */
1352 if (fs > 254 * 3)
1353 {
1354 rtx insn;
1355
1356 emit_move_insn (ax, sp);
1357 emit_insn (gen_subhi3 (ax, ax, GEN_INT (fs)));
d1dc25ff 1358 insn = F (emit_move_insn (sp, ax));
90f06e32 1359 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
d1f9b275 1360 gen_rtx_SET (sp, gen_rtx_PLUS (HImode, sp,
1361 GEN_INT (-fs))));
90f06e32 1362 }
1363 else
1364 {
1365 while (fs > 0)
1366 {
1367 int fs_byte = (fs > 254) ? 254 : fs;
1368
1369 F (emit_insn (gen_subhi3 (sp, sp, GEN_INT (fs_byte))));
1370 fs -= fs_byte;
1371 }
1372 }
78e515f7 1373 }
1374}
1375
1376/* Expand the function epilogue (from the epilogue pattern). */
1377void
1378rl78_expand_epilogue (void)
1379{
1380 int i, fs;
1381 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
90f06e32 1382 rtx ax = gen_rtx_REG (HImode, AX_REG);
78e515f7 1383 int rb = 0;
1384
fbac2992 1385 if (rl78_is_naked_func ())
1386 return;
1387
78e515f7 1388 if (frame_pointer_needed)
1389 {
90f06e32 1390 emit_move_insn (ax, gen_rtx_REG (HImode, FRAME_POINTER_REGNUM));
1391 emit_move_insn (sp, ax);
78e515f7 1392 }
1393 else
1394 {
1395 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
90f06e32 1396 if (fs > 254 * 3)
1397 {
1398 emit_move_insn (ax, sp);
1399 emit_insn (gen_addhi3 (ax, ax, GEN_INT (fs)));
1400 emit_move_insn (sp, ax);
1401 }
1402 else
78e515f7 1403 {
90f06e32 1404 while (fs > 0)
1405 {
1406 int fs_byte = (fs > 254) ? 254 : fs;
78e515f7 1407
90f06e32 1408 emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte)));
1409 fs -= fs_byte;
1410 }
78e515f7 1411 }
1412 }
1413
93e93552 1414 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
1415 {
1416 emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG)));
0c5d0bfa 1417 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode, A_REG)));
93e93552 1418 }
1419
78e515f7 1420 for (i = 15; i >= 0; i--)
1421 if (cfun->machine->need_to_push [i])
1422 {
85b515c9 1423 rtx dest = gen_rtx_REG (HImode, i * 2);
1424
c5a0ae5e 1425 if (TARGET_G10)
78e515f7 1426 {
90f06e32 1427 if (i < 8)
1428 emit_insn (gen_pop (dest));
1429 else
85b515c9 1430 {
90f06e32 1431 emit_insn (gen_pop (ax));
85b515c9 1432 emit_move_insn (dest, ax);
1433 /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */
1434 emit_insn (gen_use (dest));
1435 }
c5a0ae5e 1436 }
1437 else
1438 {
1439 int need_bank = i / 4;
1440
1441 if (need_bank != rb)
1442 {
1443 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1444 rb = need_bank;
1445 }
85b515c9 1446 emit_insn (gen_pop (dest));
78e515f7 1447 }
78e515f7 1448 }
1449
1450 if (rb != 0)
1451 emit_insn (gen_sel_rb (GEN_INT (0)));
1452
1453 if (cfun->machine->trampolines_used)
1454 emit_insn (gen_trampoline_uninit ());
1455
1456 if (is_brk_interrupt_func (cfun->decl))
1457 emit_jump_insn (gen_brk_interrupt_return ());
1458 else if (is_interrupt_func (cfun->decl))
1459 emit_jump_insn (gen_interrupt_return ());
1460 else
edf1f7ba 1461 emit_jump_insn (gen_rl78_return ());
78e515f7 1462}
1463
1464/* Likewise, for exception handlers. */
1465void
1466rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED)
1467{
1468 /* FIXME - replace this with an indirect jump with stack adjust. */
edf1f7ba 1469 emit_jump_insn (gen_rl78_return ());
78e515f7 1470}
1471
1472#undef TARGET_ASM_FUNCTION_PROLOGUE
1473#define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1474
1475/* We don't use this to actually emit the function prologue. We use
1476 this to insert a comment in the asm file describing the
1477 function. */
1478static void
1479rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
1480{
1481 int i;
1482
1483 if (cfun->machine->framesize == 0)
1484 return;
1485 fprintf (file, "\t; start of function\n");
1486
1487 if (cfun->machine->framesize_regs)
1488 {
1489 fprintf (file, "\t; push %d:", cfun->machine->framesize_regs);
1490 for (i = 0; i < 16; i ++)
1491 if (cfun->machine->need_to_push[i])
1492 fprintf (file, " %s", word_regnames[i*2]);
3f3556f1 1493 fprintf (file, "\n");
78e515f7 1494 }
1495
1496 if (frame_pointer_needed)
1497 fprintf (file, "\t; $fp points here (r22)\n");
1498
1499 if (cfun->machine->framesize_locals)
1500 fprintf (file, "\t; locals: %d byte%s\n", cfun->machine->framesize_locals,
1501 cfun->machine->framesize_locals == 1 ? "" : "s");
1502
1503 if (cfun->machine->framesize_outgoing)
1504 fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing,
1505 cfun->machine->framesize_outgoing == 1 ? "" : "s");
93e93552 1506
1507 if (cfun->machine->uses_es)
1508 fprintf (file, "\t; uses ES register\n");
78e515f7 1509}
1510
1511/* Return an RTL describing where a function return value of type RET_TYPE
1512 is held. */
1513
1514#undef TARGET_FUNCTION_VALUE
1515#define TARGET_FUNCTION_VALUE rl78_function_value
1516
1517static rtx
1518rl78_function_value (const_tree ret_type,
1519 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1520 bool outgoing ATTRIBUTE_UNUSED)
1521{
3754d046 1522 machine_mode mode = TYPE_MODE (ret_type);
78e515f7 1523
1524 return gen_rtx_REG (mode, 8);
1525}
1526
1527#undef TARGET_PROMOTE_FUNCTION_MODE
1528#define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
1529
3754d046 1530static machine_mode
78e515f7 1531rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
3754d046 1532 machine_mode mode,
78e515f7 1533 int *punsignedp ATTRIBUTE_UNUSED,
1534 const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED)
1535{
1536 return mode;
1537}
1538
1539/* Return an RTL expression describing the register holding a function
1540 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
1541 be passed on the stack. CUM describes the previous parameters to the
1542 function and NAMED is false if the parameter is part of a variable
1543 parameter list, or the last named parameter before the start of a
1544 variable parameter list. */
1545
1546#undef TARGET_FUNCTION_ARG
1547#define TARGET_FUNCTION_ARG rl78_function_arg
1548
1549static rtx
1550rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
3754d046 1551 machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1552 const_tree type ATTRIBUTE_UNUSED,
1553 bool named ATTRIBUTE_UNUSED)
1554{
1555 return NULL_RTX;
1556}
1557
1558#undef TARGET_FUNCTION_ARG_ADVANCE
1559#define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1560
1561static void
3754d046 1562rl78_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, const_tree type,
78e515f7 1563 bool named ATTRIBUTE_UNUSED)
1564{
1565 int rounded_size;
1566 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
1567
1568 rounded_size = ((mode == BLKmode)
1569 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
1570 if (rounded_size & 1)
1571 rounded_size ++;
1572 (*cum) += rounded_size;
1573}
1574
1575#undef TARGET_FUNCTION_ARG_BOUNDARY
1576#define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1577
1578static unsigned int
3754d046 1579rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1580 const_tree type ATTRIBUTE_UNUSED)
1581{
1582 return 16;
1583}
1584
1585/* Supported modifier letters:
1586
1587 A - address of a MEM
1588 S - SADDR form of a real register
1589 v - real register corresponding to a virtual register
1590 m - minus - negative of CONST_INT value.
2ced756b 1591 C - inverse of a conditional (NE vs EQ for example)
1592 C - complement of an integer
3f3556f1 1593 z - collapsed conditional
1594 s - shift count mod 8
1595 S - shift count mod 16
1596 r - reverse shift count (8-(count mod 8))
56df4a64 1597 B - bit position
78e515f7 1598
1599 h - bottom HI of an SI
1600 H - top HI of an SI
1601 q - bottom QI of an HI
1602 Q - top QI of an HI
1603 e - third QI of an SI (i.e. where the ES register gets values from)
3f3556f1 1604 E - fourth QI of an SI (i.e. MSB)
78e515f7 1605
d1dc25ff 1606 p - Add +0 to a zero-indexed HL based address.
78e515f7 1607*/
1608
1609/* Implements the bulk of rl78_print_operand, below. We do it this
1610 way because we need to test for a constant at the top level and
1611 insert the '#', but not test for it anywhere else as we recurse
1612 down into the operand. */
1613static void
1614rl78_print_operand_1 (FILE * file, rtx op, int letter)
1615{
1616 int need_paren;
1617
1618 switch (GET_CODE (op))
1619 {
1620 case MEM:
1621 if (letter == 'A')
1622 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1623 else
1624 {
1625 if (rl78_far_p (op))
563dc27b 1626 {
1627 fprintf (file, "es:");
0c5d0bfa 1628 if (GET_CODE (XEXP (op, 0)) == UNSPEC)
1629 op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1));
563dc27b 1630 }
78e515f7 1631 if (letter == 'H')
1632 {
1633 op = adjust_address (op, HImode, 2);
1634 letter = 0;
1635 }
1636 if (letter == 'h')
1637 {
1638 op = adjust_address (op, HImode, 0);
1639 letter = 0;
1640 }
1641 if (letter == 'Q')
1642 {
1643 op = adjust_address (op, QImode, 1);
1644 letter = 0;
1645 }
1646 if (letter == 'q')
1647 {
1648 op = adjust_address (op, QImode, 0);
1649 letter = 0;
1650 }
1651 if (letter == 'e')
1652 {
1653 op = adjust_address (op, QImode, 2);
1654 letter = 0;
1655 }
3f3556f1 1656 if (letter == 'E')
1657 {
1658 op = adjust_address (op, QImode, 3);
1659 letter = 0;
1660 }
78e515f7 1661 if (CONSTANT_P (XEXP (op, 0)))
1662 {
0c5d0bfa 1663 if (!rl78_saddr_p (op))
1664 fprintf (file, "!");
78e515f7 1665 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1666 }
1667 else if (GET_CODE (XEXP (op, 0)) == PLUS
1668 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF)
1669 {
0c5d0bfa 1670 if (!rl78_saddr_p (op))
1671 fprintf (file, "!");
78e515f7 1672 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1673 }
1674 else if (GET_CODE (XEXP (op, 0)) == PLUS
1675 && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
1676 && REGNO (XEXP (XEXP (op, 0), 0)) == 2)
1677 {
1678 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u');
3f3556f1 1679 fprintf (file, "[");
78e515f7 1680 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0);
d1dc25ff 1681 if (letter == 'p' && GET_CODE (XEXP (op, 0)) == REG)
1682 fprintf (file, "+0");
3f3556f1 1683 fprintf (file, "]");
78e515f7 1684 }
1685 else
1686 {
d1dc25ff 1687 op = XEXP (op, 0);
3f3556f1 1688 fprintf (file, "[");
d1dc25ff 1689 rl78_print_operand_1 (file, op, letter);
1690 if (letter == 'p' && REG_P (op) && REGNO (op) == 6)
40d1c891 1691 fprintf (file, "+0");
3f3556f1 1692 fprintf (file, "]");
78e515f7 1693 }
1694 }
1695 break;
1696
1697 case REG:
1698 if (letter == 'Q')
1699 fprintf (file, "%s", reg_names [REGNO (op) | 1]);
1700 else if (letter == 'H')
1701 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1702 else if (letter == 'q')
1703 fprintf (file, "%s", reg_names [REGNO (op) & ~1]);
1704 else if (letter == 'e')
1705 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
3f3556f1 1706 else if (letter == 'E')
1707 fprintf (file, "%s", reg_names [REGNO (op) + 3]);
78e515f7 1708 else if (letter == 'S')
1709 fprintf (file, "0x%x", 0xffef8 + REGNO (op));
1710 else if (GET_MODE (op) == HImode
1711 && ! (REGNO (op) & ~0xfe))
1712 {
1713 if (letter == 'v')
1714 fprintf (file, "%s", word_regnames [REGNO (op) % 8]);
1715 else
1716 fprintf (file, "%s", word_regnames [REGNO (op)]);
1717 }
1718 else
1719 fprintf (file, "%s", reg_names [REGNO (op)]);
1720 break;
1721
1722 case CONST_INT:
1723 if (letter == 'Q')
1724 fprintf (file, "%ld", INTVAL (op) >> 8);
1725 else if (letter == 'H')
1726 fprintf (file, "%ld", INTVAL (op) >> 16);
1727 else if (letter == 'q')
1728 fprintf (file, "%ld", INTVAL (op) & 0xff);
1729 else if (letter == 'h')
1730 fprintf (file, "%ld", INTVAL (op) & 0xffff);
1731 else if (letter == 'e')
1732 fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff);
56df4a64 1733 else if (letter == 'B')
0c5d0bfa 1734 {
1735 int ival = INTVAL (op);
1736 if (ival == -128)
1737 ival = 0x80;
1738 if (exact_log2 (ival) >= 0)
1739 fprintf (file, "%d", exact_log2 (ival));
1740 else
1741 fprintf (file, "%d", exact_log2 (~ival & 0xff));
1742 }
3f3556f1 1743 else if (letter == 'E')
1744 fprintf (file, "%ld", (INTVAL (op) >> 24) & 0xff);
78e515f7 1745 else if (letter == 'm')
1746 fprintf (file, "%ld", - INTVAL (op));
3f3556f1 1747 else if (letter == 's')
1748 fprintf (file, "%ld", INTVAL (op) % 8);
1749 else if (letter == 'S')
1750 fprintf (file, "%ld", INTVAL (op) % 16);
1751 else if (letter == 'r')
1752 fprintf (file, "%ld", 8 - (INTVAL (op) % 8));
1753 else if (letter == 'C')
1754 fprintf (file, "%ld", (INTVAL (op) ^ 0x8000) & 0xffff);
78e515f7 1755 else
3f3556f1 1756 fprintf (file, "%ld", INTVAL (op));
78e515f7 1757 break;
1758
1759 case CONST:
1760 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1761 break;
1762
1763 case ZERO_EXTRACT:
1764 {
1765 int bits = INTVAL (XEXP (op, 1));
1766 int ofs = INTVAL (XEXP (op, 2));
1767 if (bits == 16 && ofs == 0)
1768 fprintf (file, "%%lo16(");
1769 else if (bits == 16 && ofs == 16)
1770 fprintf (file, "%%hi16(");
1771 else if (bits == 8 && ofs == 16)
1772 fprintf (file, "%%hi8(");
1773 else
1774 gcc_unreachable ();
1775 rl78_print_operand_1 (file, XEXP (op, 0), 0);
1776 fprintf (file, ")");
1777 }
1778 break;
1779
1780 case ZERO_EXTEND:
1781 if (GET_CODE (XEXP (op, 0)) == REG)
1782 fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]);
1783 else
1784 print_rtl (file, op);
1785 break;
1786
1787 case PLUS:
1788 need_paren = 0;
1789 if (letter == 'H')
1790 {
1791 fprintf (file, "%%hi16(");
1792 need_paren = 1;
1793 letter = 0;
1794 }
1795 if (letter == 'h')
1796 {
1797 fprintf (file, "%%lo16(");
1798 need_paren = 1;
1799 letter = 0;
1800 }
1801 if (letter == 'e')
1802 {
1803 fprintf (file, "%%hi8(");
1804 need_paren = 1;
1805 letter = 0;
1806 }
1807 if (letter == 'q' || letter == 'Q')
1808 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1809
1810 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
1811 {
d1dc25ff 1812 if (GET_CODE (XEXP (op, 1)) == SYMBOL_REF
1813 && SYMBOL_REF_DECL (XEXP (op, 1))
1814 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op, 1))) == FUNCTION_DECL)
1815 {
1816 fprintf (file, "%%code(");
1817 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op, 1), 0)));
1818 fprintf (file, "+");
1819 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1820 fprintf (file, ")");
1821 }
1822 else
1823 {
1824 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1825 fprintf (file, "+");
1826 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1827 }
78e515f7 1828 }
1829 else
1830 {
d1dc25ff 1831 if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1832 && SYMBOL_REF_DECL (XEXP (op, 0))
1833 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op, 0))) == FUNCTION_DECL)
1834 {
1835 fprintf (file, "%%code(");
1836 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op, 0), 0)));
1837 fprintf (file, "+");
1838 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1839 fprintf (file, ")");
1840 }
1841 else
1842 {
1843 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1844 fprintf (file, "+");
1845 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1846 }
78e515f7 1847 }
1848 if (need_paren)
1849 fprintf (file, ")");
1850 break;
1851
0c5d0bfa 1852 case SUBREG:
1853 if (GET_MODE (op) == HImode
1854 && SUBREG_BYTE (op) == 0)
1855 {
1856 fprintf (file, "%%lo16(");
1857 rl78_print_operand_1 (file, SUBREG_REG (op), 0);
1858 fprintf (file, ")");
1859 }
1860 else if (GET_MODE (op) == HImode
1861 && SUBREG_BYTE (op) == 2)
1862 {
1863 fprintf (file, "%%hi16(");
1864 rl78_print_operand_1 (file, SUBREG_REG (op), 0);
1865 fprintf (file, ")");
1866 }
1867 else
1868 {
1869 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
1870 }
1871 break;
1872
78e515f7 1873 case SYMBOL_REF:
1874 need_paren = 0;
1875 if (letter == 'H')
1876 {
1877 fprintf (file, "%%hi16(");
1878 need_paren = 1;
1879 letter = 0;
1880 }
1881 if (letter == 'h')
1882 {
1883 fprintf (file, "%%lo16(");
1884 need_paren = 1;
1885 letter = 0;
1886 }
1887 if (letter == 'e')
1888 {
1889 fprintf (file, "%%hi8(");
1890 need_paren = 1;
1891 letter = 0;
1892 }
1893 if (letter == 'q' || letter == 'Q')
1894 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1895
0c5d0bfa 1896 if (SYMBOL_REF_DECL (op) && TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL)
1897 {
1898 fprintf (file, "%%code(");
1899 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0)));
1900 fprintf (file, ")");
1901 }
1902 else
1903 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0)));
78e515f7 1904 if (need_paren)
1905 fprintf (file, ")");
1906 break;
1907
1908 case CODE_LABEL:
1909 case LABEL_REF:
1910 output_asm_label (op);
1911 break;
1912
1913 case LTU:
3f3556f1 1914 if (letter == 'z')
1915 fprintf (file, "#comparison eliminated");
1916 else
2ced756b 1917 fprintf (file, letter == 'C' ? "nc" : "c");
78e515f7 1918 break;
1919 case LEU:
3f3556f1 1920 if (letter == 'z')
1921 fprintf (file, "br");
1922 else
2ced756b 1923 fprintf (file, letter == 'C' ? "h" : "nh");
78e515f7 1924 break;
1925 case GEU:
3f3556f1 1926 if (letter == 'z')
1927 fprintf (file, "br");
1928 else
2ced756b 1929 fprintf (file, letter == 'C' ? "c" : "nc");
78e515f7 1930 break;
1931 case GTU:
3f3556f1 1932 if (letter == 'z')
1933 fprintf (file, "#comparison eliminated");
1934 else
2ced756b 1935 fprintf (file, letter == 'C' ? "nh" : "h");
78e515f7 1936 break;
1937 case EQ:
3f3556f1 1938 if (letter == 'z')
1939 fprintf (file, "br");
1940 else
2ced756b 1941 fprintf (file, letter == 'C' ? "nz" : "z");
78e515f7 1942 break;
1943 case NE:
3f3556f1 1944 if (letter == 'z')
1945 fprintf (file, "#comparison eliminated");
1946 else
2ced756b 1947 fprintf (file, letter == 'C' ? "z" : "nz");
3f3556f1 1948 break;
1949
1950 /* Note: these assume appropriate adjustments were made so that
1951 unsigned comparisons, which is all this chip has, will
1952 work. */
1953 case LT:
1954 if (letter == 'z')
1955 fprintf (file, "#comparison eliminated");
1956 else
2ced756b 1957 fprintf (file, letter == 'C' ? "nc" : "c");
3f3556f1 1958 break;
1959 case LE:
1960 if (letter == 'z')
1961 fprintf (file, "br");
1962 else
2ced756b 1963 fprintf (file, letter == 'C' ? "h" : "nh");
3f3556f1 1964 break;
1965 case GE:
1966 if (letter == 'z')
1967 fprintf (file, "br");
1968 else
2ced756b 1969 fprintf (file, letter == 'C' ? "c" : "nc");
3f3556f1 1970 break;
1971 case GT:
1972 if (letter == 'z')
1973 fprintf (file, "#comparison eliminated");
1974 else
2ced756b 1975 fprintf (file, letter == 'C' ? "nh" : "h");
78e515f7 1976 break;
1977
1978 default:
1979 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
1980 break;
1981 }
1982}
1983
1984#undef TARGET_PRINT_OPERAND
1985#define TARGET_PRINT_OPERAND rl78_print_operand
1986
1987static void
1988rl78_print_operand (FILE * file, rtx op, int letter)
1989{
56df4a64 1990 if (CONSTANT_P (op) && letter != 'u' && letter != 's' && letter != 'r' && letter != 'S' && letter != 'B')
78e515f7 1991 fprintf (file, "#");
1992 rl78_print_operand_1 (file, op, letter);
1993}
1994
1995#undef TARGET_TRAMPOLINE_INIT
1996#define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
1997
1998/* Note that the RL78's addressing makes it very difficult to do
1999 trampolines on the stack. So, libgcc has a small pool of
2000 trampolines from which one is allocated to this task. */
2001static void
2002rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2003{
2004 rtx mov_addr, thunk_addr;
2005 rtx function = XEXP (DECL_RTL (fndecl), 0);
2006
2007 mov_addr = adjust_address (m_tramp, HImode, 0);
2008 thunk_addr = gen_reg_rtx (HImode);
2009
2010 function = force_reg (HImode, function);
2011 static_chain = force_reg (HImode, static_chain);
2012
2013 emit_insn (gen_trampoline_init (thunk_addr, function, static_chain));
2014 emit_move_insn (mov_addr, thunk_addr);
2015
2016 cfun->machine->trampolines_used = 1;
2017}
2018
2019#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
2020#define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
2021
2022static rtx
2023rl78_trampoline_adjust_address (rtx m_tramp)
2024{
2025 rtx x = gen_rtx_MEM (HImode, m_tramp);
2026 return x;
2027}
2028\f
2029/* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
2030 the "normal" compares, specifically, it only has unsigned compares,
2031 so we must synthesize the missing ones. */
2032void
2033rl78_expand_compare (rtx *operands)
2034{
3f3556f1 2035 if (GET_CODE (operands[2]) == MEM)
2036 operands[2] = copy_to_mode_reg (GET_MODE (operands[2]), operands[2]);
78e515f7 2037}
2038
2039\f
2040
2041/* Define this to 1 if you are debugging the peephole optimizers. */
2042#define DEBUG_PEEP 0
2043
2044/* Predicate used to enable the peephole2 patterns in rl78-virt.md.
2045 The default "word" size is a byte so we can effectively use all the
2046 registers, but we want to do 16-bit moves whenever possible. This
2047 function determines when such a move is an option. */
2048bool
2049rl78_peep_movhi_p (rtx *operands)
2050{
2051 int i;
2052 rtx m, a;
2053
2054 /* (set (op0) (op1))
2055 (set (op2) (op3)) */
2056
1d701d79 2057 if (! rl78_virt_insns_ok ())
2058 return false;
2059
78e515f7 2060#if DEBUG_PEEP
2061 fprintf (stderr, "\033[33m");
3f3556f1 2062 debug_rtx (operands[0]);
2063 debug_rtx (operands[1]);
2064 debug_rtx (operands[2]);
2065 debug_rtx (operands[3]);
78e515f7 2066 fprintf (stderr, "\033[0m");
2067#endif
2068
c5a0ae5e 2069 /* You can move a constant to memory as QImode, but not HImode. */
2070 if (GET_CODE (operands[0]) == MEM
2071 && GET_CODE (operands[1]) != REG)
2072 {
2073#if DEBUG_PEEP
2074 fprintf (stderr, "no peep: move constant to memory\n");
2075#endif
2076 return false;
2077 }
2078
78e515f7 2079 if (rtx_equal_p (operands[0], operands[3]))
2080 {
2081#if DEBUG_PEEP
2082 fprintf (stderr, "no peep: overlapping\n");
2083#endif
2084 return false;
2085 }
2086
2087 for (i = 0; i < 2; i ++)
2088 {
2089 if (GET_CODE (operands[i]) != GET_CODE (operands[i+2]))
2090 {
2091#if DEBUG_PEEP
2092 fprintf (stderr, "no peep: different codes\n");
2093#endif
2094 return false;
2095 }
2096 if (GET_MODE (operands[i]) != GET_MODE (operands[i+2]))
2097 {
2098#if DEBUG_PEEP
2099 fprintf (stderr, "no peep: different modes\n");
2100#endif
2101 return false;
2102 }
2103
2104 switch (GET_CODE (operands[i]))
2105 {
2106 case REG:
2107 /* LSB MSB */
2108 if (REGNO (operands[i]) + 1 != REGNO (operands[i+2])
2109 || GET_MODE (operands[i]) != QImode)
2110 {
2111#if DEBUG_PEEP
2112 fprintf (stderr, "no peep: wrong regnos %d %d %d\n",
2113 REGNO (operands[i]), REGNO (operands[i+2]),
2114 i);
2115#endif
2116 return false;
2117 }
2118 if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode))
2119 {
2120#if DEBUG_PEEP
2121 fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i]));
2122#endif
2123 return false;
2124 }
2125 break;
2126
2127 case CONST_INT:
2128 break;
2129
2130 case MEM:
2131 if (GET_MODE (operands[i]) != QImode)
2132 return false;
2133 if (MEM_ALIGN (operands[i]) < 16)
2134 return false;
2135 a = XEXP (operands[i], 0);
2136 if (GET_CODE (a) == CONST)
2137 a = XEXP (a, 0);
2138 if (GET_CODE (a) == PLUS)
2139 a = XEXP (a, 1);
2140 if (GET_CODE (a) == CONST_INT
2141 && INTVAL (a) & 1)
2142 {
2143#if DEBUG_PEEP
2144 fprintf (stderr, "no peep: misaligned mem %d\n", i);
2145 debug_rtx (operands[i]);
2146#endif
2147 return false;
2148 }
2149 m = adjust_address (operands[i], QImode, 1);
2150 if (! rtx_equal_p (m, operands[i+2]))
2151 {
2152#if DEBUG_PEEP
2153 fprintf (stderr, "no peep: wrong mem %d\n", i);
8a6bcd4e 2154 debug_rtx (m);
78e515f7 2155 debug_rtx (operands[i+2]);
2156#endif
2157 return false;
2158 }
2159 break;
2160
2161 default:
2162#if DEBUG_PEEP
2163 fprintf (stderr, "no peep: wrong rtx %d\n", i);
2164#endif
2165 return false;
2166 }
2167 }
2168#if DEBUG_PEEP
2169 fprintf (stderr, "\033[32mpeep!\033[0m\n");
2170#endif
2171 return true;
2172}
2173
2174/* Likewise, when a peephole is activated, this function helps compute
2175 the new operands. */
2176void
2177rl78_setup_peep_movhi (rtx *operands)
2178{
2179 int i;
2180
2181 for (i = 0; i < 2; i ++)
2182 {
2183 switch (GET_CODE (operands[i]))
2184 {
2185 case REG:
2186 operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i]));
2187 break;
2188
2189 case CONST_INT:
8a6bcd4e 2190 operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char) INTVAL (operands[i+2])) * 256);
78e515f7 2191 break;
2192
2193 case MEM:
2194 operands[i+4] = adjust_address (operands[i], HImode, 0);
2195 break;
2196
2197 default:
2198 break;
2199 }
2200 }
2201}
2202\f
2203/*
2204 How Devirtualization works in the RL78 GCC port
2205
2206Background
2207
2208The RL78 is an 8-bit port with some 16-bit operations. It has 32
2209bytes of register space, in four banks, memory-mapped. One bank is
2210the "selected" bank and holds the registers used for primary
2211operations. Since the registers are memory mapped, often you can
2212still refer to the unselected banks via memory accesses.
2213
2214Virtual Registers
2215
2216The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
2217and refers to the other banks via their memory addresses, although
2218they're treated as regular registers internally. These "virtual"
2219registers are R8 through R23 (bank3 is reserved for asm-based
2220interrupt handlers).
2221
2222There are four machine description files:
2223
2224rl78.md - common register-independent patterns and definitions
2225rl78-expand.md - expanders
2226rl78-virt.md - patterns that match BEFORE devirtualization
2227rl78-real.md - patterns that match AFTER devirtualization
2228
2229At least through register allocation and reload, gcc is told that it
2230can do pretty much anything - but may only use the virtual registers.
2231GCC cannot properly create the varying addressing modes that the RL78
2232supports in an efficient way.
2233
2234Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
2235uses the "valloc" attribute in rl78-virt.md for determining the rules
2236by which it will replace virtual registers with real registers (or
2237not) and how to make up addressing modes. For example, insns tagged
2238with "ro1" have a single read-only parameter, which may need to be
2239moved from memory/constant/vreg to a suitable real register. As part
2240of devirtualization, a flag is toggled, disabling the rl78-virt.md
2241patterns and enabling the rl78-real.md patterns. The new patterns'
2242constraints are used to determine the real registers used. NOTE:
2243patterns in rl78-virt.md essentially ignore the constrains and rely on
2244predicates, where the rl78-real.md ones essentially ignore the
2245predicates and rely on the constraints.
2246
2247The devirtualization pass is scheduled via the pass manager (despite
2248being called "rl78_reorg") so it can be scheduled prior to var-track
2249(the idea is to let gdb know about the new registers). Ideally, it
2250would be scheduled right after pro/epilogue generation, so the
2251post-reload optimizers could operate on the real registers, but when I
2252tried that there were some issues building the target libraries.
2253
2254During devirtualization, a simple register move optimizer is run. It
67d57e27 2255would be better to run a full CSE/propogation pass on it though, but
2256that has not yet been attempted.
78e515f7 2257
2258 */
2259#define DEBUG_ALLOC 0
2260
563dc27b 2261#define OP(x) (*recog_data.operand_loc[x])
2262
3f3556f1 2263/* This array is used to hold knowledge about the contents of the
2264 real registers (A ... H), the memory-based registers (r8 ... r31)
2265 and the first NUM_STACK_LOCS words on the stack. We use this to
2266 avoid generating redundant move instructions.
2267
2268 A value in the range 0 .. 31 indicates register A .. r31.
2269 A value in the range 32 .. 63 indicates stack slot (value - 32).
2270 A value of NOT_KNOWN indicates that the contents of that location
2271 are not known. */
2272
2273#define NUM_STACK_LOCS 32
2274#define NOT_KNOWN 127
2275
2276static unsigned char content_memory [32 + NUM_STACK_LOCS];
2277
2278static unsigned char saved_update_index = NOT_KNOWN;
2279static unsigned char saved_update_value;
3754d046 2280static machine_mode saved_update_mode;
3f3556f1 2281
2282
2283static inline void
2284clear_content_memory (void)
2285{
2286 memset (content_memory, NOT_KNOWN, sizeof content_memory);
2287 if (dump_file)
2288 fprintf (dump_file, " clear content memory\n");
2289 saved_update_index = NOT_KNOWN;
2290}
2291
2292/* Convert LOC into an index into the content_memory array.
2293 If LOC cannot be converted, return NOT_KNOWN. */
2294
2295static unsigned char
2296get_content_index (rtx loc)
2297{
3754d046 2298 machine_mode mode;
3f3556f1 2299
2300 if (loc == NULL_RTX)
2301 return NOT_KNOWN;
2302
2303 if (REG_P (loc))
2304 {
2305 if (REGNO (loc) < 32)
2306 return REGNO (loc);
2307 return NOT_KNOWN;
2308 }
2309
2310 mode = GET_MODE (loc);
2311
2312 if (! rl78_stack_based_mem (loc, mode))
2313 return NOT_KNOWN;
2314
2315 loc = XEXP (loc, 0);
2316
2317 if (REG_P (loc))
2318 /* loc = MEM (SP) */
2319 return 32;
2320
2321 /* loc = MEM (PLUS (SP, INT)). */
2322 loc = XEXP (loc, 1);
2323
2324 if (INTVAL (loc) < NUM_STACK_LOCS)
2325 return 32 + INTVAL (loc);
2326
2327 return NOT_KNOWN;
2328}
2329
2330/* Return a string describing content INDEX in mode MODE.
2331 WARNING: Can return a pointer to a static buffer. */
3f3556f1 2332static const char *
3754d046 2333get_content_name (unsigned char index, machine_mode mode)
3f3556f1 2334{
2335 static char buffer [128];
2336
2337 if (index == NOT_KNOWN)
2338 return "Unknown";
2339
2340 if (index > 31)
2341 sprintf (buffer, "stack slot %d", index - 32);
2342 else if (mode == HImode)
2343 sprintf (buffer, "%s%s",
2344 reg_names [index + 1], reg_names [index]);
2345 else
2346 return reg_names [index];
2347
2348 return buffer;
2349}
2350
2351#if DEBUG_ALLOC
2352
2353static void
2354display_content_memory (FILE * file)
2355{
2356 unsigned int i;
2357
2358 fprintf (file, " Known memory contents:\n");
2359
2360 for (i = 0; i < sizeof content_memory; i++)
2361 if (content_memory[i] != NOT_KNOWN)
2362 {
2363 fprintf (file, " %s contains a copy of ", get_content_name (i, QImode));
2364 fprintf (file, "%s\n", get_content_name (content_memory [i], QImode));
2365 }
2366}
2367#endif
2368
2369static void
3754d046 2370update_content (unsigned char index, unsigned char val, machine_mode mode)
3f3556f1 2371{
2372 unsigned int i;
2373
2374 gcc_assert (index < sizeof content_memory);
2375
2376 content_memory [index] = val;
2377 if (val != NOT_KNOWN)
2378 content_memory [val] = index;
2379
2380 /* Make the entry in dump_file *before* VAL is increased below. */
2381 if (dump_file)
2382 {
2383 fprintf (dump_file, " %s now contains ", get_content_name (index, mode));
2384 if (val == NOT_KNOWN)
2385 fprintf (dump_file, "Unknown\n");
2386 else
2387 fprintf (dump_file, "%s and vice versa\n", get_content_name (val, mode));
2388 }
8a6bcd4e 2389
3f3556f1 2390 if (mode == HImode)
2391 {
2392 val = val == NOT_KNOWN ? val : val + 1;
2393
2394 content_memory [index + 1] = val;
2395 if (val != NOT_KNOWN)
2396 {
2397 content_memory [val] = index + 1;
2398 -- val;
2399 }
2400 }
2401
2402 /* Any other places that had INDEX recorded as their contents are now invalid. */
2403 for (i = 0; i < sizeof content_memory; i++)
2404 {
2405 if (i == index
2406 || (val != NOT_KNOWN && i == val))
2407 {
2408 if (mode == HImode)
2409 ++ i;
2410 continue;
2411 }
8a6bcd4e 2412
3f3556f1 2413 if (content_memory[i] == index
2414 || (val != NOT_KNOWN && content_memory[i] == val))
2415 {
2416 content_memory[i] = NOT_KNOWN;
2417
2418 if (dump_file)
2419 fprintf (dump_file, " %s cleared\n", get_content_name (i, mode));
2420
2421 if (mode == HImode)
2422 content_memory[++ i] = NOT_KNOWN;
2423 }
2424 }
2425}
2426
2427/* Record that LOC contains VALUE.
2428 For HImode locations record that LOC+1 contains VALUE+1.
2429 If LOC is not a register or stack slot, do nothing.
2430 If VALUE is not a register or stack slot, clear the recorded content. */
2431
2432static void
2433record_content (rtx loc, rtx value)
2434{
3754d046 2435 machine_mode mode;
3f3556f1 2436 unsigned char index;
2437 unsigned char val;
2438
2439 if ((index = get_content_index (loc)) == NOT_KNOWN)
2440 return;
2441
2442 val = get_content_index (value);
2443
2444 mode = GET_MODE (loc);
2445
2446 if (val == index)
2447 {
2448 if (! optimize)
2449 return;
2450
2451 /* This should not happen when optimizing. */
2452#if 1
2453 fprintf (stderr, "ASSIGNMENT of location to itself detected! [%s]\n",
2454 get_content_name (val, mode));
2455 return;
2456#else
2457 gcc_unreachable ();
2458#endif
2459 }
2460
2461 update_content (index, val, mode);
2462}
2463
2464/* Returns TRUE if LOC already contains a copy of VALUE. */
2465
2466static bool
2467already_contains (rtx loc, rtx value)
2468{
2469 unsigned char index;
2470 unsigned char val;
2471
2472 if ((index = get_content_index (loc)) == NOT_KNOWN)
2473 return false;
2474
2475 if ((val = get_content_index (value)) == NOT_KNOWN)
2476 return false;
2477
2478 if (content_memory [index] != val)
2479 return false;
2480
2481 if (GET_MODE (loc) == HImode)
2482 return content_memory [index + 1] == val + 1;
2483
2484 return true;
2485}
2486
563dc27b 2487bool
2488rl78_es_addr (rtx addr)
2489{
2490 if (GET_CODE (addr) == MEM)
2491 addr = XEXP (addr, 0);
2492 if (GET_CODE (addr) != UNSPEC)
2493 return false;
2494 if (XINT (addr, 1) != UNS_ES_ADDR)
2495 return false;
2496 return true;
2497}
2498
2499rtx
2500rl78_es_base (rtx addr)
2501{
2502 if (GET_CODE (addr) == MEM)
2503 addr = XEXP (addr, 0);
2504 addr = XVECEXP (addr, 0, 1);
2505 if (GET_CODE (addr) == CONST
2506 && GET_CODE (XEXP (addr, 0)) == ZERO_EXTRACT)
2507 addr = XEXP (XEXP (addr, 0), 0);
2508 /* Mode doesn't matter here. */
2509 return gen_rtx_MEM (HImode, addr);
2510}
2511
78e515f7 2512/* Rescans an insn to see if it's recognized again. This is done
2513 carefully to ensure that all the constraint information is accurate
2514 for the newly matched insn. */
2515static bool
93e93552 2516insn_ok_now (rtx_insn * insn)
78e515f7 2517{
3f3556f1 2518 rtx pattern = PATTERN (insn);
563dc27b 2519 int i;
3f3556f1 2520
78e515f7 2521 INSN_CODE (insn) = -1;
3f3556f1 2522
2523 if (recog (pattern, insn, 0) > -1)
78e515f7 2524 {
2525 extract_insn (insn);
e2f730a9 2526 if (constrain_operands (1, get_preferred_alternatives (insn)))
78e515f7 2527 {
2528#if DEBUG_ALLOC
2529 fprintf (stderr, "\033[32m");
2530 debug_rtx (insn);
2531 fprintf (stderr, "\033[0m");
2532#endif
3f3556f1 2533 if (SET_P (pattern))
2534 record_content (SET_DEST (pattern), SET_SRC (pattern));
2535
563dc27b 2536 /* We need to detect far addresses that haven't been
2537 converted to es/lo16 format. */
2538 for (i=0; i<recog_data.n_operands; i++)
1d701d79 2539 if (GET_CODE (OP (i)) == MEM
2540 && GET_MODE (XEXP (OP (i), 0)) == SImode
2541 && GET_CODE (XEXP (OP (i), 0)) != UNSPEC)
563dc27b 2542 return false;
2543
78e515f7 2544 return true;
2545 }
2546 }
2547 else
2548 {
3f3556f1 2549 /* We need to re-recog the insn with virtual registers to get
1d701d79 2550 the operands. */
3f3556f1 2551 cfun->machine->virt_insns_ok = 1;
2552 if (recog (pattern, insn, 0) > -1)
2553 {
2554 extract_insn (insn);
e2f730a9 2555 if (constrain_operands (0, get_preferred_alternatives (insn)))
3f3556f1 2556 {
2557 cfun->machine->virt_insns_ok = 0;
2558 return false;
2559 }
2560 }
2561
2562#if DEBUG_ALLOC
2563 fprintf (stderr, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
78e515f7 2564 debug_rtx (insn);
3f3556f1 2565#endif
78e515f7 2566 gcc_unreachable ();
2567 }
3f3556f1 2568
78e515f7 2569#if DEBUG_ALLOC
2570 fprintf (stderr, "\033[31m");
2571 debug_rtx (insn);
2572 fprintf (stderr, "\033[0m");
2573#endif
2574 return false;
2575}
2576
2577#if DEBUG_ALLOC
3f3556f1 2578#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
78e515f7 2579#define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
93e93552 2580#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
78e515f7 2581#define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
3f3556f1 2582#define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
78e515f7 2583#else
78e515f7 2584#define FAILED gcc_unreachable ()
2585#define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
3f3556f1 2586#define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
78e515f7 2587#endif
2588
2589/* Registers into which we move the contents of virtual registers. */
1d701d79 2590#define X gen_rtx_REG (QImode, X_REG)
2591#define A gen_rtx_REG (QImode, A_REG)
2592#define C gen_rtx_REG (QImode, C_REG)
2593#define B gen_rtx_REG (QImode, B_REG)
2594#define E gen_rtx_REG (QImode, E_REG)
2595#define D gen_rtx_REG (QImode, D_REG)
2596#define L gen_rtx_REG (QImode, L_REG)
2597#define H gen_rtx_REG (QImode, H_REG)
2598
2599#define AX gen_rtx_REG (HImode, AX_REG)
2600#define BC gen_rtx_REG (HImode, BC_REG)
2601#define DE gen_rtx_REG (HImode, DE_REG)
2602#define HL gen_rtx_REG (HImode, HL_REG)
78e515f7 2603
78e515f7 2604/* Returns TRUE if R is a virtual register. */
1d701d79 2605static inline bool
78e515f7 2606is_virtual_register (rtx r)
2607{
2608 return (GET_CODE (r) == REG
2609 && REGNO (r) >= 8
55ea1438 2610 && REGNO (r) < 32);
78e515f7 2611}
2612
2613/* In all these alloc routines, we expect the following: the insn
2614 pattern is unshared, the insn was previously recognized and failed
2615 due to predicates or constraints, and the operand data is in
2616 recog_data. */
2617
2618static int virt_insn_was_frame;
2619
2620/* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2621 needed. */
2622static rtx
2623EM2 (int line ATTRIBUTE_UNUSED, rtx r)
2624{
2625#if DEBUG_ALLOC
2626 fprintf (stderr, "\033[36m%d: ", line);
8a6bcd4e 2627 debug_rtx (r);
78e515f7 2628 fprintf (stderr, "\033[0m");
2629#endif
2630 /*SCHED_GROUP_P (r) = 1;*/
2631 if (virt_insn_was_frame)
2632 RTX_FRAME_RELATED_P (r) = 1;
2633 return r;
2634}
2635
2636#define EM(x) EM2 (__LINE__, x)
2637
2638/* Return a suitable RTX for the low half of a __far address. */
2639static rtx
2640rl78_lo16 (rtx addr)
2641{
563dc27b 2642 rtx r;
2643
78e515f7 2644 if (GET_CODE (addr) == SYMBOL_REF
2645 || GET_CODE (addr) == CONST)
2646 {
563dc27b 2647 r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0));
78e515f7 2648 r = gen_rtx_CONST (HImode, r);
78e515f7 2649 }
563dc27b 2650 else
2651 r = rl78_subreg (HImode, addr, SImode, 0);
2652
2653 r = gen_es_addr (r);
93e93552 2654 cfun->machine->uses_es = true;
563dc27b 2655
2656 return r;
78e515f7 2657}
2658
2659/* Return a suitable RTX for the high half's lower byte of a __far address. */
2660static rtx
2661rl78_hi8 (rtx addr)
2662{
2663 if (GET_CODE (addr) == SYMBOL_REF
2664 || GET_CODE (addr) == CONST)
2665 {
2666 rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16));
2667 r = gen_rtx_CONST (QImode, r);
2668 return r;
2669 }
2670 return rl78_subreg (QImode, addr, SImode, 2);
2671}
2672
3f3556f1 2673static void
2674add_postponed_content_update (rtx to, rtx value)
2675{
2676 unsigned char index;
2677
2678 if ((index = get_content_index (to)) == NOT_KNOWN)
2679 return;
2680
2681 gcc_assert (saved_update_index == NOT_KNOWN);
2682 saved_update_index = index;
2683 saved_update_value = get_content_index (value);
2684 saved_update_mode = GET_MODE (to);
2685}
2686
2687static void
2688process_postponed_content_update (void)
2689{
2690 if (saved_update_index != NOT_KNOWN)
2691 {
2692 update_content (saved_update_index, saved_update_value, saved_update_mode);
2693 saved_update_index = NOT_KNOWN;
2694 }
2695}
2696
2697/* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2698 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2699 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2700 BEFORE is true, FROM otherwise. */
2701static rtx
2702gen_and_emit_move (rtx to, rtx from, rtx where, bool before)
2703{
3754d046 2704 machine_mode mode = GET_MODE (to);
3f3556f1 2705
2706 if (optimize && before && already_contains (to, from))
2707 {
2708#if DEBUG_ALLOC
2709 display_content_memory (stderr);
2710#endif
2711 if (dump_file)
2712 {
2713 fprintf (dump_file, " Omit move of %s into ",
2714 get_content_name (get_content_index (from), mode));
2715 fprintf (dump_file, "%s as it already contains this value\n",
2716 get_content_name (get_content_index (to), mode));
2717 }
2718 }
2719 else
2720 {
2721 rtx move = mode == QImode ? gen_movqi (to, from) : gen_movhi (to, from);
8a6bcd4e 2722
3f3556f1 2723 EM (move);
2724
2725 if (where == NULL_RTX)
2726 emit_insn (move);
2727 else if (before)
2728 emit_insn_before (move, where);
2729 else
2730 {
2731 rtx note = find_reg_note (where, REG_EH_REGION, NULL_RTX);
2732
2733 /* If necessary move REG_EH_REGION notes forward.
2734 cf. compiling gcc.dg/pr44545.c. */
2735 if (note != NULL_RTX)
2736 {
2737 add_reg_note (move, REG_EH_REGION, XEXP (note, 0));
2738 remove_note (where, note);
2739 }
2740
2741 emit_insn_after (move, where);
2742 }
2743
2744 if (before)
2745 record_content (to, from);
2746 else
2747 add_postponed_content_update (to, from);
2748 }
1d701d79 2749
3f3556f1 2750 return before ? to : from;
2751}
2752
2753/* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2754 copy it into NEWBASE and return the updated MEM. Otherwise just
2755 return M. Any needed insns are emitted before BEFORE. */
78e515f7 2756static rtx
2757transcode_memory_rtx (rtx m, rtx newbase, rtx before)
2758{
2759 rtx base, index, addendr;
2760 int addend = 0;
563dc27b 2761 int need_es = 0;
78e515f7 2762
3f3556f1 2763 if (! MEM_P (m))
78e515f7 2764 return m;
2765
2766 if (GET_MODE (XEXP (m, 0)) == SImode)
2767 {
1d701d79 2768 rtx new_m;
78e515f7 2769 rtx seg = rl78_hi8 (XEXP (m, 0));
1d701d79 2770
0c5d0bfa 2771 if (!TARGET_ES0)
2772 {
2773 emit_insn_before (EM (gen_movqi (A, seg)), before);
2774 emit_insn_before (EM (gen_movqi_to_es (A)), before);
2775 }
2776
3f3556f1 2777 record_content (A, NULL_RTX);
2778
1d701d79 2779 new_m = gen_rtx_MEM (GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
2780 MEM_COPY_ATTRIBUTES (new_m, m);
2781 m = new_m;
563dc27b 2782 need_es = 1;
78e515f7 2783 }
2784
3f3556f1 2785 characterize_address (XEXP (m, 0), & base, & index, & addendr);
78e515f7 2786 gcc_assert (index == NULL_RTX);
2787
78e515f7 2788 if (base == NULL_RTX)
2789 return m;
2790
2791 if (addendr && GET_CODE (addendr) == CONST_INT)
2792 addend = INTVAL (addendr);
2793
3f3556f1 2794 gcc_assert (REG_P (base));
2795 gcc_assert (REG_P (newbase));
2796
0c5d0bfa 2797 int limit = 256 - GET_MODE_SIZE (GET_MODE (m));
2798
78e515f7 2799 if (REGNO (base) == SP_REG)
2800 {
889a65e7 2801 if (addend >= 0 && addend <= limit)
78e515f7 2802 return m;
2803 }
2804
2805 /* BASE should be a virtual register. We copy it to NEWBASE. If
2806 the addend is out of range for DE/HL, we use AX to compute the full
2807 address. */
2808
2809 if (addend < 0
0c5d0bfa 2810 || (addend > limit && REGNO (newbase) != BC_REG)
2811 || (addendr
2812 && (GET_CODE (addendr) != CONST_INT)
2813 && ((REGNO (newbase) != BC_REG))
2814 ))
78e515f7 2815 {
2816 /* mov ax, vreg
2817 add ax, #imm
2818 mov hl, ax */
2819 EM (emit_insn_before (gen_movhi (AX, base), before));
2820 EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before));
2821 EM (emit_insn_before (gen_movhi (newbase, AX), before));
3f3556f1 2822 record_content (AX, NULL_RTX);
2823 record_content (newbase, NULL_RTX);
2824
78e515f7 2825 base = newbase;
2826 addend = 0;
0c5d0bfa 2827 addendr = 0;
78e515f7 2828 }
2829 else
2830 {
3f3556f1 2831 base = gen_and_emit_move (newbase, base, before, true);
78e515f7 2832 }
2833
2834 if (addend)
3f3556f1 2835 {
2836 record_content (base, NULL_RTX);
2837 base = gen_rtx_PLUS (HImode, base, GEN_INT (addend));
2838 }
0c5d0bfa 2839 else if (addendr)
2840 {
2841 record_content (base, NULL_RTX);
2842 base = gen_rtx_PLUS (HImode, base, addendr);
2843 }
78e515f7 2844
563dc27b 2845 if (need_es)
93e93552 2846 {
2847 m = change_address (m, GET_MODE (m), gen_es_addr (base));
2848 cfun->machine->uses_es = true;
2849 }
563dc27b 2850 else
2851 m = change_address (m, GET_MODE (m), base);
78e515f7 2852 return m;
2853}
2854
2855/* Copy SRC to accumulator (A or AX), placing any generated insns
2856 before BEFORE. Returns accumulator RTX. */
78e515f7 2857static rtx
2858move_to_acc (int opno, rtx before)
2859{
3f3556f1 2860 rtx src = OP (opno);
3754d046 2861 machine_mode mode = GET_MODE (src);
78e515f7 2862
3f3556f1 2863 if (REG_P (src) && REGNO (src) < 2)
78e515f7 2864 return src;
2865
2866 if (mode == VOIDmode)
2867 mode = recog_data.operand_mode[opno];
2868
3f3556f1 2869 return gen_and_emit_move (mode == QImode ? A : AX, src, before, true);
2870}
2871
2872static void
2873force_into_acc (rtx src, rtx before)
2874{
3754d046 2875 machine_mode mode = GET_MODE (src);
3f3556f1 2876 rtx move;
2877
2878 if (REG_P (src) && REGNO (src) < 2)
2879 return;
2880
2881 move = mode == QImode ? gen_movqi (A, src) : gen_movhi (AX, src);
8a6bcd4e 2882
3f3556f1 2883 EM (move);
2884
2885 emit_insn_before (move, before);
2886 record_content (AX, NULL_RTX);
78e515f7 2887}
2888
2889/* Copy accumulator (A or AX) to DEST, placing any generated insns
2890 after AFTER. Returns accumulator RTX. */
78e515f7 2891static rtx
3f3556f1 2892move_from_acc (unsigned int opno, rtx after)
78e515f7 2893{
3f3556f1 2894 rtx dest = OP (opno);
3754d046 2895 machine_mode mode = GET_MODE (dest);
78e515f7 2896
2897 if (REG_P (dest) && REGNO (dest) < 2)
2898 return dest;
2899
3f3556f1 2900 return gen_and_emit_move (dest, mode == QImode ? A : AX, after, false);
78e515f7 2901}
2902
2903/* Copy accumulator (A or AX) to REGNO, placing any generated insns
2904 before BEFORE. Returns reg RTX. */
78e515f7 2905static rtx
2906move_acc_to_reg (rtx acc, int regno, rtx before)
2907{
3754d046 2908 machine_mode mode = GET_MODE (acc);
78e515f7 2909 rtx reg;
2910
2911 reg = gen_rtx_REG (mode, regno);
2912
3f3556f1 2913 return gen_and_emit_move (reg, acc, before, true);
78e515f7 2914}
2915
2916/* Copy SRC to X, placing any generated insns before BEFORE.
2917 Returns X RTX. */
78e515f7 2918static rtx
2919move_to_x (int opno, rtx before)
2920{
3f3556f1 2921 rtx src = OP (opno);
3754d046 2922 machine_mode mode = GET_MODE (src);
78e515f7 2923 rtx reg;
2924
2925 if (mode == VOIDmode)
2926 mode = recog_data.operand_mode[opno];
2927 reg = (mode == QImode) ? X : AX;
2928
2929 if (mode == QImode || ! is_virtual_register (OP (opno)))
2930 {
3f3556f1 2931 OP (opno) = move_to_acc (opno, before);
1d701d79 2932 OP (opno) = move_acc_to_reg (OP (opno), X_REG, before);
78e515f7 2933 return reg;
2934 }
2935
3f3556f1 2936 return gen_and_emit_move (reg, src, before, true);
78e515f7 2937}
2938
1d701d79 2939/* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
78e515f7 2940 Returns H/HL RTX. */
78e515f7 2941static rtx
2942move_to_hl (int opno, rtx before)
2943{
2944 rtx src = OP (opno);
3754d046 2945 machine_mode mode = GET_MODE (src);
78e515f7 2946 rtx reg;
2947
2948 if (mode == VOIDmode)
2949 mode = recog_data.operand_mode[opno];
2950 reg = (mode == QImode) ? L : HL;
2951
2952 if (mode == QImode || ! is_virtual_register (OP (opno)))
2953 {
2954 OP (opno) = move_to_acc (opno, before);
2955 OP (opno) = move_acc_to_reg (OP (opno), L_REG, before);
2956 return reg;
2957 }
2958
3f3556f1 2959 return gen_and_emit_move (reg, src, before, true);
78e515f7 2960}
2961
1d701d79 2962/* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
78e515f7 2963 Returns E/DE RTX. */
78e515f7 2964static rtx
2965move_to_de (int opno, rtx before)
2966{
2967 rtx src = OP (opno);
3754d046 2968 machine_mode mode = GET_MODE (src);
78e515f7 2969 rtx reg;
2970
2971 if (mode == VOIDmode)
2972 mode = recog_data.operand_mode[opno];
2973
2974 reg = (mode == QImode) ? E : DE;
2975
2976 if (mode == QImode || ! is_virtual_register (OP (opno)))
2977 {
2978 OP (opno) = move_to_acc (opno, before);
2979 OP (opno) = move_acc_to_reg (OP (opno), E_REG, before);
2980 }
2981 else
2982 {
3f3556f1 2983 gen_and_emit_move (reg, src, before, true);
78e515f7 2984 }
2985
2986 return reg;
2987}
2988
2989/* Devirtualize an insn of the form (SET (op) (unop (op))). */
2990static void
93e93552 2991rl78_alloc_physical_registers_op1 (rtx_insn * insn)
78e515f7 2992{
2993 /* op[0] = func op[1] */
2994
2995 /* We first try using A as the destination, then copying it
2996 back. */
3f3556f1 2997 if (rtx_equal_p (OP (0), OP (1)))
78e515f7 2998 {
3f3556f1 2999 OP (0) =
3000 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
78e515f7 3001 }
3002 else
3003 {
3f3556f1 3004 /* If necessary, load the operands into BC and HL.
3005 Check to see if we already have OP (0) in HL
0c5d0bfa 3006 and if so, swap the order.
3007
3008 It is tempting to perform this optimization when OP(0) does
3009 not hold a MEM, but this leads to bigger code in general.
3010 The problem is that if OP(1) holds a MEM then swapping it
889a65e7 3011 into BC means a BC-relative load is used and these are 3
3012 bytes long vs 1 byte for an HL load. */
3f3556f1 3013 if (MEM_P (OP (0))
3014 && already_contains (HL, XEXP (OP (0), 0)))
3015 {
3016 OP (0) = transcode_memory_rtx (OP (0), HL, insn);
3017 OP (1) = transcode_memory_rtx (OP (1), BC, insn);
3018 }
3019 else
3020 {
3021 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3022 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
3023 }
78e515f7 3024 }
3025
3026 MAYBE_OK (insn);
3027
3f3556f1 3028 OP (0) = move_from_acc (0, insn);
78e515f7 3029
3030 MAYBE_OK (insn);
3031
3032 /* Try copying the src to acc first, then. This is for, for
3033 example, ZERO_EXTEND or NOT. */
3f3556f1 3034 OP (1) = move_to_acc (1, insn);
78e515f7 3035
3f3556f1 3036 MUST_BE_OK (insn);
3037}
3038
3039/* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
3040 Assumes that the current insn has already been recognised and hence the
3041 constraint data has been filled in. */
3042static bool
3043has_constraint (unsigned int opnum, enum constraint_num constraint)
3044{
3045 const char * p = recog_data.constraints[opnum];
3046
3047 /* No constraints means anything is accepted. */
3048 if (p == NULL || *p == 0 || *p == ',')
3049 return true;
8a6bcd4e 3050
3f3556f1 3051 do
3052 {
3053 char c;
3054 unsigned int len;
78e515f7 3055
3f3556f1 3056 c = *p;
3057 len = CONSTRAINT_LEN (c, p);
3058 gcc_assert (len > 0);
3059
3060 switch (c)
3061 {
3062 case 0:
3063 case ',':
3064 return false;
3065 default:
3066 if (lookup_constraint (p) == constraint)
3067 return true;
3068 }
3069 p += len;
3070 }
3071 while (1);
78e515f7 3072}
3073
3f3556f1 3074/* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
78e515f7 3075static void
93e93552 3076rl78_alloc_physical_registers_op2 (rtx_insn * insn)
78e515f7 3077{
3f3556f1 3078 rtx prev;
78e515f7 3079 rtx first;
3080 bool hl_used;
3f3556f1 3081 int tmp_id;
3082 rtx saved_op1;
78e515f7 3083
3f3556f1 3084 if (rtx_equal_p (OP (0), OP (1)))
78e515f7 3085 {
750dcfc5 3086 if (MEM_P (OP (2)))
3087 {
3088 OP (0) =
3089 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3090 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3091 }
3092 else
3093 {
3094 OP (0) =
3095 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
3096 OP (2) = transcode_memory_rtx (OP (2), DE, insn);
3097 }
78e515f7 3098 }
3f3556f1 3099 else if (rtx_equal_p (OP (0), OP (2)))
78e515f7 3100 {
3f3556f1 3101 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3102 OP (0) =
3103 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3104 }
3105 else
3106 {
3f3556f1 3107 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3108 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3109 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3110 }
3111
3112 MAYBE_OK (insn);
3113
3114 prev = prev_nonnote_nondebug_insn (insn);
3115 if (recog_data.constraints[1][0] == '%'
3116 && is_virtual_register (OP (1))
3117 && ! is_virtual_register (OP (2))
3118 && ! CONSTANT_P (OP (2)))
3119 {
3120 rtx tmp = OP (1);
3121 OP (1) = OP (2);
3122 OP (2) = tmp;
3123 }
3124
3f3556f1 3125 /* Make a note of whether (H)L is being used. It matters
8a6bcd4e 3126 because if OP (2) also needs reloading, then we must take
78e515f7 3127 care not to corrupt HL. */
3128 hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1));
3129
3f3556f1 3130 /* If HL is not currently being used and dest == op1 then there are
3131 some possible optimizations available by reloading one of the
3132 operands into HL, before trying to use the accumulator. */
3133 if (optimize
3134 && ! hl_used
3135 && rtx_equal_p (OP (0), OP (1)))
3136 {
3137 /* If op0 is a Ws1 type memory address then switching the base
3138 address register to HL might allow us to perform an in-memory
3139 operation. (eg for the INCW instruction).
8a6bcd4e 3140
3f3556f1 3141 FIXME: Adding the move into HL is costly if this optimization is not
3142 going to work, so for now, make sure that we know that the new insn will
3143 match the requirements of the addhi3_real pattern. Really we ought to
3144 generate a candidate sequence, test that, and then install it if the
3145 results are good. */
3146 if (satisfies_constraint_Ws1 (OP (0))
3147 && has_constraint (0, CONSTRAINT_Wh1)
3148 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
3149 {
3150 rtx base, index, addend, newbase;
3151
3152 characterize_address (XEXP (OP (0), 0), & base, & index, & addend);
3153 gcc_assert (index == NULL_RTX);
3154 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
3155
3156 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3157 if (addend != NULL_RTX)
3158 {
3159 newbase = gen_and_emit_move (HL, base, insn, true);
3160 record_content (newbase, NULL_RTX);
3161 newbase = gen_rtx_PLUS (HImode, newbase, addend);
8a6bcd4e 3162
3f3556f1 3163 OP (0) = OP (1) = change_address (OP (0), VOIDmode, newbase);
3164
3165 /* We do not want to fail here as this means that
3166 we have inserted useless insns into the stream. */
3167 MUST_BE_OK (insn);
3168 }
3169 }
3170 else if (REG_P (OP (0))
3171 && satisfies_constraint_Ws1 (OP (2))
3172 && has_constraint (2, CONSTRAINT_Wh1))
3173 {
3174 rtx base, index, addend, newbase;
3175
3176 characterize_address (XEXP (OP (2), 0), & base, & index, & addend);
3177 gcc_assert (index == NULL_RTX);
3178 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
3179
3180 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3181 if (addend != NULL_RTX)
3182 {
3183 gen_and_emit_move (HL, base, insn, true);
3184
3185 if (REGNO (OP (0)) != X_REG)
3186 {
3187 OP (1) = move_to_acc (1, insn);
3188 OP (0) = move_from_acc (0, insn);
3189 }
3190
3191 record_content (HL, NULL_RTX);
3192 newbase = gen_rtx_PLUS (HImode, HL, addend);
8a6bcd4e 3193
3f3556f1 3194 OP (2) = change_address (OP (2), VOIDmode, newbase);
3195
3196 /* We do not want to fail here as this means that
3197 we have inserted useless insns into the stream. */
3198 MUST_BE_OK (insn);
3199 }
3200 }
3201 }
3202
3f3556f1 3203 OP (0) = move_from_acc (0, insn);
3204
3205 tmp_id = get_max_insn_count ();
3206 saved_op1 = OP (1);
3207
3208 if (rtx_equal_p (OP (1), OP (2)))
3209 OP (2) = OP (1) = move_to_acc (1, insn);
3210 else
3211 OP (1) = move_to_acc (1, insn);
78e515f7 3212
3213 MAYBE_OK (insn);
3214
3f3556f1 3215 /* If we omitted the move of OP1 into the accumulator (because
3216 it was already there from a previous insn), then force the
3217 generation of the move instruction now. We know that we
3218 are about to emit a move into HL (or DE) via AX, and hence
3219 our optimization to remove the load of OP1 is no longer valid. */
3220 if (tmp_id == get_max_insn_count ())
3221 force_into_acc (saved_op1, insn);
3222
3223 /* We have to copy op2 to HL (or DE), but that involves AX, which
78e515f7 3224 already has a live value. Emit it before those insns. */
3225
3226 if (prev)
3227 first = next_nonnote_nondebug_insn (prev);
3228 else
3229 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3230 ;
3231
3232 OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first);
8a6bcd4e 3233
3f3556f1 3234 MUST_BE_OK (insn);
78e515f7 3235}
3236
3f3556f1 3237/* Devirtualize an insn of the form SET (PC) (MEM/REG). */
78e515f7 3238static void
93e93552 3239rl78_alloc_physical_registers_ro1 (rtx_insn * insn)
78e515f7 3240{
3f3556f1 3241 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
78e515f7 3242
3243 MAYBE_OK (insn);
3244
3f3556f1 3245 OP (0) = move_to_acc (0, insn);
78e515f7 3246
3f3556f1 3247 MUST_BE_OK (insn);
78e515f7 3248}
3249
3250/* Devirtualize a compare insn. */
3251static void
93e93552 3252rl78_alloc_physical_registers_cmp (rtx_insn * insn)
78e515f7 3253{
3f3556f1 3254 int tmp_id;
3255 rtx saved_op1;
bf79ca12 3256 rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
78e515f7 3257 rtx first;
3258
3f3556f1 3259 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3260 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3261
1d701d79 3262 /* HI compares have to have OP (1) in AX, but QI
3f3556f1 3263 compares do not, so it is worth checking here. */
78e515f7 3264 MAYBE_OK (insn);
3265
1d701d79 3266 /* For an HImode compare, OP (1) must always be in AX.
3267 But if OP (1) is a REG (and not AX), then we can avoid
3268 a reload of OP (1) if we reload OP (2) into AX and invert
3f3556f1 3269 the comparison. */
3270 if (REG_P (OP (1))
3271 && REGNO (OP (1)) != AX_REG
3272 && GET_MODE (OP (1)) == HImode
3273 && MEM_P (OP (2)))
3274 {
3275 rtx cmp = XEXP (SET_SRC (PATTERN (insn)), 0);
3276
3277 OP (2) = move_to_acc (2, insn);
3278
3279 switch (GET_CODE (cmp))
3280 {
3281 case EQ:
3282 case NE:
3283 break;
3284 case LTU: cmp = gen_rtx_GTU (HImode, OP (2), OP (1)); break;
3285 case GTU: cmp = gen_rtx_LTU (HImode, OP (2), OP (1)); break;
3286 case LEU: cmp = gen_rtx_GEU (HImode, OP (2), OP (1)); break;
3287 case GEU: cmp = gen_rtx_LEU (HImode, OP (2), OP (1)); break;
3288
3289 case LT:
3290 case GT:
3291 case LE:
3292 case GE:
3293#if DEBUG_ALLOC
3294 debug_rtx (insn);
3295#endif
3296 default:
3297 gcc_unreachable ();
3298 }
8a6bcd4e 3299
3f3556f1 3300 if (GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE)
3301 PATTERN (insn) = gen_cbranchhi4_real (cmp, OP (2), OP (1), OP (3));
3302 else
3303 PATTERN (insn) = gen_cbranchhi4_real_inverted (cmp, OP (2), OP (1), OP (3));
3304
3305 MUST_BE_OK (insn);
3306 }
3307
3308 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
3309 should be handled by the second alternative of the cbranchhi_real pattern. */
3310 if (rtx_equal_p (OP (1), OP (2)))
3311 {
3312 OP (1) = OP (2) = BC;
3313 MUST_BE_OK (insn);
3314 }
8a6bcd4e 3315
3f3556f1 3316 tmp_id = get_max_insn_count ();
3317 saved_op1 = OP (1);
3318
3319 OP (1) = move_to_acc (1, insn);
78e515f7 3320
3321 MAYBE_OK (insn);
3322
3f3556f1 3323 /* If we omitted the move of OP1 into the accumulator (because
3324 it was already there from a previous insn), then force the
3325 generation of the move instruction now. We know that we
3326 are about to emit a move into HL via AX, and hence our
3327 optimization to remove the load of OP1 is no longer valid. */
3328 if (tmp_id == get_max_insn_count ())
3329 force_into_acc (saved_op1, insn);
3330
78e515f7 3331 /* We have to copy op2 to HL, but that involves the acc, which
3332 already has a live value. Emit it before those insns. */
78e515f7 3333 if (prev)
3334 first = next_nonnote_nondebug_insn (prev);
3335 else
3336 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3337 ;
3f3556f1 3338 OP (2) = move_to_hl (2, first);
78e515f7 3339
3f3556f1 3340 MUST_BE_OK (insn);
78e515f7 3341}
3342
8a6bcd4e 3343/* Like op2, but AX = A * X. */
78e515f7 3344static void
93e93552 3345rl78_alloc_physical_registers_umul (rtx_insn * insn)
78e515f7 3346{
bf79ca12 3347 rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
78e515f7 3348 rtx first;
3f3556f1 3349 int tmp_id;
3350 rtx saved_op1;
78e515f7 3351
3f3556f1 3352 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3353 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3354 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3355
3356 MAYBE_OK (insn);
3357
3358 if (recog_data.constraints[1][0] == '%'
3f3556f1 3359 && is_virtual_register (OP (1))
3360 && !is_virtual_register (OP (2))
3361 && !CONSTANT_P (OP (2)))
78e515f7 3362 {
3f3556f1 3363 rtx tmp = OP (1);
3364 OP (1) = OP (2);
3365 OP (2) = tmp;
78e515f7 3366 }
3367
3f3556f1 3368 OP (0) = move_from_acc (0, insn);
3369
3370 tmp_id = get_max_insn_count ();
3371 saved_op1 = OP (1);
8a6bcd4e 3372
3373 if (rtx_equal_p (OP (1), OP (2)))
3374 {
3375 gcc_assert (GET_MODE (OP (2)) == QImode);
3376 /* The MULU instruction does not support duplicate arguments
3377 but we know that if we copy OP (2) to X it will do so via
3378 A and thus OP (1) will already be loaded into A. */
3379 OP (2) = move_to_x (2, insn);
3380 OP (1) = A;
3381 }
3382 else
3383 OP (1) = move_to_acc (1, insn);
78e515f7 3384
3385 MAYBE_OK (insn);
3386
3f3556f1 3387 /* If we omitted the move of OP1 into the accumulator (because
3388 it was already there from a previous insn), then force the
3389 generation of the move instruction now. We know that we
3390 are about to emit a move into HL (or DE) via AX, and hence
3391 our optimization to remove the load of OP1 is no longer valid. */
3392 if (tmp_id == get_max_insn_count ())
3393 force_into_acc (saved_op1, insn);
3394
78e515f7 3395 /* We have to copy op2 to X, but that involves the acc, which
3396 already has a live value. Emit it before those insns. */
3397
3398 if (prev)
3399 first = next_nonnote_nondebug_insn (prev);
3400 else
3401 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3402 ;
3f3556f1 3403 OP (2) = move_to_x (2, first);
3404
3405 MUST_BE_OK (insn);
3406}
3407
3408static void
93e93552 3409rl78_alloc_address_registers_macax (rtx_insn * insn)
3f3556f1 3410{
3411 int which, op;
3412 bool replace_in_op0 = false;
3413 bool replace_in_op1 = false;
78e515f7 3414
3415 MAYBE_OK (insn);
3416
3f3556f1 3417 /* Two different MEMs are not allowed. */
3418 which = 0;
3419 for (op = 2; op >= 0; op --)
3420 {
3421 if (MEM_P (OP (op)))
3422 {
3423 if (op == 0 && replace_in_op0)
3424 continue;
3425 if (op == 1 && replace_in_op1)
3426 continue;
3427
3428 switch (which)
3429 {
3430 case 0:
3431 /* If we replace a MEM, make sure that we replace it for all
3432 occurrences of the same MEM in the insn. */
3433 replace_in_op0 = (op > 0 && rtx_equal_p (OP (op), OP (0)));
3434 replace_in_op1 = (op > 1 && rtx_equal_p (OP (op), OP (1)));
3435
3436 OP (op) = transcode_memory_rtx (OP (op), HL, insn);
3437 if (op == 2
3438 && MEM_P (OP (op))
7f210f10 3439 && ((GET_CODE (XEXP (OP (op), 0)) == REG
3440 && REGNO (XEXP (OP (op), 0)) == SP_REG)
3f3556f1 3441 || (GET_CODE (XEXP (OP (op), 0)) == PLUS
3442 && REGNO (XEXP (XEXP (OP (op), 0), 0)) == SP_REG)))
3443 {
3444 emit_insn_before (gen_movhi (HL, gen_rtx_REG (HImode, SP_REG)), insn);
3445 OP (op) = replace_rtx (OP (op), gen_rtx_REG (HImode, SP_REG), HL);
3446 }
3447 if (replace_in_op0)
3448 OP (0) = OP (op);
3449 if (replace_in_op1)
3450 OP (1) = OP (op);
3451 break;
3452 case 1:
3453 OP (op) = transcode_memory_rtx (OP (op), DE, insn);
3454 break;
3455 case 2:
3456 OP (op) = transcode_memory_rtx (OP (op), BC, insn);
3457 break;
3458 }
3459 which ++;
3460 }
3461 }
1d701d79 3462
3f3556f1 3463 MUST_BE_OK (insn);
78e515f7 3464}
3465
889a65e7 3466static void
3467rl78_alloc_address_registers_div (rtx_insn * insn)
3468{
3469 MUST_BE_OK (insn);
3470}
3471
78e515f7 3472/* Scan all insns and devirtualize them. */
3473static void
3474rl78_alloc_physical_registers (void)
3475{
3476 /* During most of the compile, gcc is dealing with virtual
3477 registers. At this point, we need to assign physical registers
3478 to the vitual ones, and copy in/out as needed. */
3479
ed3e6e5d 3480 rtx_insn *insn, *curr;
78e515f7 3481 enum attr_valloc valloc_method;
3482
3483 for (insn = get_insns (); insn; insn = curr)
3484 {
3485 int i;
3486
3487 curr = next_nonnote_nondebug_insn (insn);
3488
3489 if (INSN_P (insn)
3490 && (GET_CODE (PATTERN (insn)) == SET
3491 || GET_CODE (PATTERN (insn)) == CALL)
3492 && INSN_CODE (insn) == -1)
3493 {
3494 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
3495 continue;
3496 i = recog (PATTERN (insn), insn, 0);
3497 if (i == -1)
3498 {
3499 debug_rtx (insn);
3500 gcc_unreachable ();
3501 }
3502 INSN_CODE (insn) = i;
3503 }
3504 }
3505
3506 cfun->machine->virt_insns_ok = 0;
3507 cfun->machine->real_insns_ok = 1;
3508
3f3556f1 3509 clear_content_memory ();
3510
78e515f7 3511 for (insn = get_insns (); insn; insn = curr)
3512 {
3f3556f1 3513 rtx pattern;
3514
78e515f7 3515 curr = insn ? next_nonnote_nondebug_insn (insn) : NULL;
3516
3517 if (!INSN_P (insn))
3f3556f1 3518 {
3519 if (LABEL_P (insn))
3520 clear_content_memory ();
8a6bcd4e 3521
3f3556f1 3522 continue;
3523 }
78e515f7 3524
3f3556f1 3525 if (dump_file)
3526 fprintf (dump_file, "Converting insn %d\n", INSN_UID (insn));
3527
3528 pattern = PATTERN (insn);
3529 if (GET_CODE (pattern) == PARALLEL)
3530 pattern = XVECEXP (pattern, 0, 0);
3531 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3532 clear_content_memory ();
3533 if (GET_CODE (pattern) != SET
3534 && GET_CODE (pattern) != CALL)
3535 continue;
7f210f10 3536 if (GET_CODE (pattern) == SET
3537 && GET_CODE (SET_SRC (pattern)) == ASM_OPERANDS)
78e515f7 3538 continue;
3539
3540 valloc_method = get_attr_valloc (insn);
3541
3f3556f1 3542 PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
3543
3544 if (valloc_method == VALLOC_MACAX)
3545 {
3546 record_content (AX, NULL_RTX);
3547 record_content (BC, NULL_RTX);
3548 record_content (DE, NULL_RTX);
3549 }
e98e1692 3550 else if (valloc_method == VALLOC_DIVHI)
3551 {
3552 record_content (AX, NULL_RTX);
3553 record_content (BC, NULL_RTX);
3554 }
3555 else if (valloc_method == VALLOC_DIVSI)
3556 {
3557 record_content (AX, NULL_RTX);
3558 record_content (BC, NULL_RTX);
3559 record_content (DE, NULL_RTX);
3560 record_content (HL, NULL_RTX);
3561 }
78e515f7 3562
3563 if (insn_ok_now (insn))
3564 continue;
3565
3566 INSN_CODE (insn) = -1;
3567
3568 if (RTX_FRAME_RELATED_P (insn))
3569 virt_insn_was_frame = 1;
3570 else
3571 virt_insn_was_frame = 0;
3572
3573 switch (valloc_method)
3574 {
3575 case VALLOC_OP1:
3576 rl78_alloc_physical_registers_op1 (insn);
3577 break;
3578 case VALLOC_OP2:
3579 rl78_alloc_physical_registers_op2 (insn);
3580 break;
3581 case VALLOC_RO1:
3582 rl78_alloc_physical_registers_ro1 (insn);
3583 break;
3584 case VALLOC_CMP:
3585 rl78_alloc_physical_registers_cmp (insn);
3586 break;
3587 case VALLOC_UMUL:
3588 rl78_alloc_physical_registers_umul (insn);
e98e1692 3589 record_content (AX, NULL_RTX);
78e515f7 3590 break;
3591 case VALLOC_MACAX:
3f3556f1 3592 /* Macro that clobbers AX. */
3593 rl78_alloc_address_registers_macax (insn);
3594 record_content (AX, NULL_RTX);
3595 record_content (BC, NULL_RTX);
3596 record_content (DE, NULL_RTX);
78e515f7 3597 break;
e98e1692 3598 case VALLOC_DIVSI:
3599 rl78_alloc_address_registers_div (insn);
3600 record_content (AX, NULL_RTX);
3601 record_content (BC, NULL_RTX);
3602 record_content (DE, NULL_RTX);
3603 record_content (HL, NULL_RTX);
3604 break;
3605 case VALLOC_DIVHI:
3606 rl78_alloc_address_registers_div (insn);
3607 record_content (AX, NULL_RTX);
3608 record_content (BC, NULL_RTX);
3609 break;
889a65e7 3610 default:
3611 gcc_unreachable ();
78e515f7 3612 }
3f3556f1 3613
3614 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3615 clear_content_memory ();
3616 else
3617 process_postponed_content_update ();
78e515f7 3618 }
1d701d79 3619
78e515f7 3620#if DEBUG_ALLOC
3621 fprintf (stderr, "\033[0m");
3622#endif
3623}
3624
3625/* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3626 This function scans for uses of registers; the last use (i.e. first
3627 encounter when scanning backwards) triggers a REG_DEAD note if the
3628 reg was previously in DEAD[]. */
3629static void
3630rl78_note_reg_uses (char *dead, rtx s, rtx insn)
3631{
3632 const char *fmt;
3633 int i, r;
3634 enum rtx_code code;
3635
3636 if (!s)
3637 return;
3638
3639 code = GET_CODE (s);
3640
3641 switch (code)
3642 {
3643 /* Compare registers by number. */
3644 case REG:
3645 r = REGNO (s);
3646 if (dump_file)
3647 {
3648 fprintf (dump_file, "note use reg %d size %d on insn %d\n",
3649 r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn));
3650 print_rtl_single (dump_file, s);
3651 }
3652 if (dead [r])
3653 add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r));
3654 for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++)
3655 dead [r + i] = 0;
3656 return;
3657
3658 /* These codes have no constituent expressions
3659 and are unique. */
3660 case SCRATCH:
3661 case CC0:
3662 case PC:
3663 return;
3664
3665 case CONST_INT:
3666 case CONST_VECTOR:
3667 case CONST_DOUBLE:
3668 case CONST_FIXED:
3669 /* These are kept unique for a given value. */
3670 return;
3671
3672 default:
3673 break;
3674 }
3675
3676 fmt = GET_RTX_FORMAT (code);
3677
3678 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
3679 {
3680 if (fmt[i] == 'E')
3681 {
3682 int j;
3683 for (j = XVECLEN (s, i) - 1; j >= 0; j--)
3684 rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn);
3685 }
3686 else if (fmt[i] == 'e')
3687 rl78_note_reg_uses (dead, XEXP (s, i), insn);
3688 }
3689}
3690
3691/* Like the previous function, but scan for SETs instead. */
3692static void
3693rl78_note_reg_set (char *dead, rtx d, rtx insn)
3694{
3695 int r, i;
3696
889a65e7 3697 if (GET_CODE (d) == MEM)
3698 rl78_note_reg_uses (dead, XEXP (d, 0), insn);
3699
78e515f7 3700 if (GET_CODE (d) != REG)
3701 return;
3702
3703 r = REGNO (d);
3704 if (dead [r])
3705 add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r));
3706 if (dump_file)
3707 fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d)));
3708 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
3709 dead [r + i] = 1;
3710}
3711
3712/* This is a rather crude register death pass. Death status is reset
3713 at every jump or call insn. */
3714static void
3715rl78_calculate_death_notes (void)
3716{
3717 char dead[FIRST_PSEUDO_REGISTER];
3718 rtx insn, p, s, d;
3719 int i;
3720
3721 memset (dead, 0, sizeof (dead));
3722
3723 for (insn = get_last_insn ();
3724 insn;
3725 insn = prev_nonnote_nondebug_insn (insn))
3726 {
3727 if (dump_file)
3728 {
3729 fprintf (dump_file, "\n--------------------------------------------------");
3730 fprintf (dump_file, "\nDead:");
3731 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
3732 if (dead[i])
3f3556f1 3733 fprintf (dump_file, " %s", reg_names[i]);
78e515f7 3734 fprintf (dump_file, "\n");
3735 print_rtl_single (dump_file, insn);
3736 }
3737
3738 switch (GET_CODE (insn))
3739 {
3740 case INSN:
3741 p = PATTERN (insn);
315b808d 3742 if (GET_CODE (p) == PARALLEL)
889a65e7 3743 {
3744 rtx q = XVECEXP (p, 0 ,1);
3745
3746 /* This happens with the DIV patterns. */
3747 if (GET_CODE (q) == SET)
3748 {
3749 s = SET_SRC (q);
3750 d = SET_DEST (q);
3751 rl78_note_reg_set (dead, d, insn);
3752 rl78_note_reg_uses (dead, s, insn);
3753
3754 }
3755 p = XVECEXP (p, 0, 0);
3756 }
3757
78e515f7 3758 switch (GET_CODE (p))
3759 {
3760 case SET:
3761 s = SET_SRC (p);
3762 d = SET_DEST (p);
3763 rl78_note_reg_set (dead, d, insn);
3764 rl78_note_reg_uses (dead, s, insn);
3765 break;
3766
3767 case USE:
3768 rl78_note_reg_uses (dead, p, insn);
3769 break;
3770
3771 default:
3772 break;
3773 }
3774 break;
3775
3776 case JUMP_INSN:
edf1f7ba 3777 if (INSN_CODE (insn) == CODE_FOR_rl78_return)
78e515f7 3778 {
3779 memset (dead, 1, sizeof (dead));
3780 /* We expect a USE just prior to this, which will mark
3781 the actual return registers. The USE will have a
3782 death note, but we aren't going to be modifying it
3783 after this pass. */
3784 break;
3785 }
3786 case CALL_INSN:
3787 memset (dead, 0, sizeof (dead));
3788 break;
3789
3790 default:
3791 break;
3792 }
3793 if (dump_file)
3794 print_rtl_single (dump_file, insn);
3795 }
3796}
3797
3798/* Helper function to reset the origins in RP and the age in AGE for
3799 all registers. */
3800static void
3801reset_origins (int *rp, int *age)
3802{
3803 int i;
3804 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3805 {
3806 rp[i] = i;
3807 age[i] = 0;
3808 }
3809}
3810
889a65e7 3811static void
3812set_origin (rtx pat, rtx_insn * insn, int * origins, int * age)
3813{
3814 rtx src = SET_SRC (pat);
3815 rtx dest = SET_DEST (pat);
3816 int mb = GET_MODE_SIZE (GET_MODE (dest));
3817 int i;
3818
3819 if (GET_CODE (dest) == REG)
3820 {
3821 int dr = REGNO (dest);
3822
3823 if (GET_CODE (src) == REG)
3824 {
3825 int sr = REGNO (src);
3826 bool same = true;
3827 int best_age, best_reg;
3828
3829 /* See if the copy is not needed. */
3830 for (i = 0; i < mb; i ++)
3831 if (origins[dr + i] != origins[sr + i])
3832 same = false;
3833
3834 if (same)
3835 {
3836 if (dump_file)
3837 fprintf (dump_file, "deleting because dest already has correct value\n");
3838 delete_insn (insn);
3839 return;
3840 }
3841
3842 if (dr < 8 || sr >= 8)
3843 {
3844 int ar;
3845
3846 best_age = -1;
3847 best_reg = -1;
3848
3849 /* See if the copy can be made from another
3850 bank 0 register instead, instead of the
3851 virtual src register. */
3852 for (ar = 0; ar < 8; ar += mb)
3853 {
3854 same = true;
3855
3856 for (i = 0; i < mb; i ++)
3857 if (origins[ar + i] != origins[sr + i])
3858 same = false;
3859
3860 /* The chip has some reg-reg move limitations. */
3861 if (mb == 1 && dr > 3)
3862 same = false;
3863
3864 if (same)
3865 {
3866 if (best_age == -1 || best_age > age[sr + i])
3867 {
3868 best_age = age[sr + i];
3869 best_reg = sr;
3870 }
3871 }
3872 }
3873
3874 if (best_reg != -1)
3875 {
3876 /* FIXME: copy debug info too. */
3877 SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg);
3878 sr = best_reg;
3879 }
3880 }
3881
3882 for (i = 0; i < mb; i++)
3883 {
3884 origins[dr + i] = origins[sr + i];
3885 age[dr + i] = age[sr + i] + 1;
3886 }
3887 }
3888 else
3889 {
3890 /* The destination is computed, its origin is itself. */
3891 if (dump_file)
3892 fprintf (dump_file, "resetting origin of r%d for %d byte%s\n",
3893 dr, mb, mb == 1 ? "" : "s");
3894
3895 for (i = 0; i < mb; i ++)
3896 {
3897 origins[dr + i] = dr + i;
3898 age[dr + i] = 0;
3899 }
3900 }
3901
3902 /* Any registers marked with that reg as an origin are reset. */
3903 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3904 if (origins[i] >= dr && origins[i] < dr + mb)
3905 {
3906 origins[i] = i;
3907 age[i] = 0;
3908 }
3909 }
3910
3911 /* Special case - our MUL patterns uses AX and sometimes BC. */
3912 if (get_attr_valloc (insn) == VALLOC_MACAX)
3913 {
3914 if (dump_file)
3915 fprintf (dump_file, "Resetting origin of AX/BC for MUL pattern.\n");
3916
3917 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3918 if (i <= 3 || origins[i] <= 3)
3919 {
3920 origins[i] = i;
3921 age[i] = 0;
3922 }
3923 }
e98e1692 3924 else if (get_attr_valloc (insn) == VALLOC_DIVHI)
3925 {
3926 if (dump_file)
3927 fprintf (dump_file, "Resetting origin of AX/DE for DIVHI pattern.\n");
3928
3929 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3930 if (i == A_REG
3931 || i == X_REG
3932 || i == D_REG
3933 || i == E_REG
3934 || origins[i] == A_REG
3935 || origins[i] == X_REG
3936 || origins[i] == D_REG
3937 || origins[i] == E_REG)
3938 {
3939 origins[i] = i;
3940 age[i] = 0;
3941 }
3942 }
3943 else if (get_attr_valloc (insn) == VALLOC_DIVSI)
3944 {
3945 if (dump_file)
3946 fprintf (dump_file, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n");
3947
3948 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3949 if (i <= 7 || origins[i] <= 7)
3950 {
3951 origins[i] = i;
3952 age[i] = 0;
3953 }
3954 }
889a65e7 3955
3956 if (GET_CODE (src) == ASHIFT
3957 || GET_CODE (src) == ASHIFTRT
3958 || GET_CODE (src) == LSHIFTRT)
3959 {
3960 rtx count = XEXP (src, 1);
3961
3962 if (GET_CODE (count) == REG)
3963 {
3964 /* Special case - our pattern clobbers the count register. */
3965 int r = REGNO (count);
3966
3967 if (dump_file)
3968 fprintf (dump_file, "Resetting origin of r%d for shift.\n", r);
3969
3970 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3971 if (i == r || origins[i] == r)
3972 {
3973 origins[i] = i;
3974 age[i] = 0;
3975 }
3976 }
3977 }
3978}
3979
78e515f7 3980/* The idea behind this optimization is to look for cases where we
3981 move data from A to B to C, and instead move from A to B, and A to
3982 C. If B is a virtual register or memory, this is a big win on its
3983 own. If B turns out to be unneeded after this, it's a bigger win.
3984 For each register, we try to determine where it's value originally
3985 came from, if it's propogated purely through moves (and not
3986 computes). The ORIGINS[] array has the regno for the "origin" of
3987 the value in the [regno] it's indexed by. */
3988static void
3989rl78_propogate_register_origins (void)
3990{
3991 int origins[FIRST_PSEUDO_REGISTER];
3992 int age[FIRST_PSEUDO_REGISTER];
3993 int i;
d3ffa7b4 3994 rtx_insn *insn, *ninsn = NULL;
78e515f7 3995 rtx pat;
3996
3997 reset_origins (origins, age);
3998
3999 for (insn = get_insns (); insn; insn = ninsn)
4000 {
4001 ninsn = next_nonnote_nondebug_insn (insn);
4002
4003 if (dump_file)
4004 {
4005 fprintf (dump_file, "\n");
4006 fprintf (dump_file, "Origins:");
4007 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
4008 if (origins[i] != i)
4009 fprintf (dump_file, " r%d=r%d", i, origins[i]);
4010 fprintf (dump_file, "\n");
4011 print_rtl_single (dump_file, insn);
4012 }
4013
4014 switch (GET_CODE (insn))
4015 {
4016 case CODE_LABEL:
4017 case BARRIER:
4018 case CALL_INSN:
4019 case JUMP_INSN:
4020 reset_origins (origins, age);
4021 break;
4022
4023 default:
4024 break;
4025
4026 case INSN:
4027 pat = PATTERN (insn);
4028
4029 if (GET_CODE (pat) == PARALLEL)
4030 {
4031 rtx clobber = XVECEXP (pat, 0, 1);
4032 pat = XVECEXP (pat, 0, 0);
9aea9676 4033 if (GET_CODE (clobber) == CLOBBER
4034 && GET_CODE (XEXP (clobber, 0)) == REG)
78e515f7 4035 {
4036 int cr = REGNO (XEXP (clobber, 0));
4037 int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0)));
4038 if (dump_file)
4039 fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr);
4040 for (i = 0; i < mb; i++)
4041 {
4042 origins[cr + i] = cr + i;
4043 age[cr + i] = 0;
4044 }
4045 }
889a65e7 4046 /* This happens with the DIV patterns. */
4047 else if (GET_CODE (clobber) == SET)
4048 {
4049 set_origin (clobber, insn, origins, age);
4050 }
78e515f7 4051 else
4052 break;
4053 }
4054
4055 if (GET_CODE (pat) == SET)
4056 {
889a65e7 4057 set_origin (pat, insn, origins, age);
78e515f7 4058 }
9aea9676 4059 else if (GET_CODE (pat) == CLOBBER
4060 && GET_CODE (XEXP (pat, 0)) == REG)
1d701d79 4061 {
4062 if (REG_P (XEXP (pat, 0)))
4063 {
4064 unsigned int reg = REGNO (XEXP (pat, 0));
4065
4066 origins[reg] = reg;
4067 age[reg] = 0;
4068 }
4069 }
78e515f7 4070 }
4071 }
4072}
4073
4074/* Remove any SETs where the destination is unneeded. */
4075static void
4076rl78_remove_unused_sets (void)
4077{
50fc2d35 4078 rtx_insn *insn, *ninsn = NULL;
78e515f7 4079 rtx dest;
4080
4081 for (insn = get_insns (); insn; insn = ninsn)
4082 {
4083 ninsn = next_nonnote_nondebug_insn (insn);
4084
50fc2d35 4085 rtx set = single_set (insn);
4086 if (set == NULL)
78e515f7 4087 continue;
4088
50fc2d35 4089 dest = SET_DEST (set);
78e515f7 4090
8bcf96c6 4091 if (GET_CODE (dest) != REG || REGNO (dest) > 23)
78e515f7 4092 continue;
4093
4094 if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
889a65e7 4095 {
4096 if (dump_file)
4097 fprintf (dump_file, "deleting because the set register is never used.\n");
4098 delete_insn (insn);
4099 }
78e515f7 4100 }
4101}
4102
78e515f7 4103/* This is the top of the devritualization pass. */
4104static void
4105rl78_reorg (void)
4106{
3f3556f1 4107 /* split2 only happens when optimizing, but we need all movSIs to be
4108 split now. */
4109 if (optimize <= 0)
4110 split_all_insns ();
4111
78e515f7 4112 rl78_alloc_physical_registers ();
4113
4114 if (dump_file)
4115 {
4116 fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
5147ec07 4117 print_rtl_with_bb (dump_file, get_insns (), 0);
78e515f7 4118 }
4119
4120 rl78_propogate_register_origins ();
4121 rl78_calculate_death_notes ();
4122
4123 if (dump_file)
4124 {
4125 fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
5147ec07 4126 print_rtl_with_bb (dump_file, get_insns (), 0);
78e515f7 4127 fprintf (dump_file, "\n======================================================================\n");
4128 }
4129
4130 rl78_remove_unused_sets ();
4131
4132 /* The code after devirtualizing has changed so much that at this point
4133 we might as well just rescan everything. Note that
4134 df_rescan_all_insns is not going to help here because it does not
4135 touch the artificial uses and defs. */
4136 df_finish_pass (true);
4137 if (optimize > 1)
4138 df_live_add_problem ();
4139 df_scan_alloc (NULL);
4140 df_scan_blocks ();
4141
4142 if (optimize)
4143 df_analyze ();
4144}
4145
3f3556f1 4146#undef TARGET_RETURN_IN_MEMORY
78e515f7 4147#define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
4148
4149static bool
4150rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
4151{
4152 const HOST_WIDE_INT size = int_size_in_bytes (type);
4153 return (size == -1 || size > 8);
4154}
4155
3f3556f1 4156\f
4157#undef TARGET_RTX_COSTS
4158#define TARGET_RTX_COSTS rl78_rtx_costs
4159
d1dc25ff 4160static bool
4161rl78_rtx_costs (rtx x,
4162 int code,
4163 int outer_code ATTRIBUTE_UNUSED,
4164 int opno ATTRIBUTE_UNUSED,
4165 int * total,
4166 bool speed ATTRIBUTE_UNUSED)
3f3556f1 4167{
4168 if (code == IF_THEN_ELSE)
d1dc25ff 4169 {
4170 *total = COSTS_N_INSNS (10);
4171 return true;
4172 }
4173
3f3556f1 4174 if (GET_MODE (x) == SImode)
4175 {
4176 switch (code)
4177 {
4178 case MULT:
e98e1692 4179 if (RL78_MUL_G14)
3f3556f1 4180 *total = COSTS_N_INSNS (14);
4181 else if (RL78_MUL_G13)
4182 *total = COSTS_N_INSNS (29);
4183 else
4184 *total = COSTS_N_INSNS (500);
4185 return true;
4186 case PLUS:
4187 *total = COSTS_N_INSNS (8);
4188 return true;
4189 case ASHIFT:
4190 case ASHIFTRT:
4191 case LSHIFTRT:
4192 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4193 {
4194 switch (INTVAL (XEXP (x, 1)))
4195 {
4196 case 0: *total = COSTS_N_INSNS (0); break;
4197 case 1: *total = COSTS_N_INSNS (6); break;
4198 case 2: case 3: case 4: case 5: case 6: case 7:
4199 *total = COSTS_N_INSNS (10); break;
4200 case 8: *total = COSTS_N_INSNS (6); break;
4201 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
4202 *total = COSTS_N_INSNS (10); break;
4203 case 16: *total = COSTS_N_INSNS (3); break;
4204 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
4205 *total = COSTS_N_INSNS (4); break;
4206 case 24: *total = COSTS_N_INSNS (4); break;
4207 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
4208 *total = COSTS_N_INSNS (5); break;
4209 }
4210 }
4211 else
4212 *total = COSTS_N_INSNS (10+4*16);
4213 return true;
4214 }
4215 }
4216 return false;
4217}
78e515f7 4218\f
99bdcd9d 4219
0c5d0bfa 4220static GTY(()) section * saddr_section;
4221static GTY(()) section * frodata_section;
4222
4223int
4224rl78_saddr_p (rtx x)
4225{
4226 const char * c;
4227
4228 if (MEM_P (x))
4229 x = XEXP (x, 0);
4230 if (GET_CODE (x) == PLUS)
4231 x = XEXP (x, 0);
4232 if (GET_CODE (x) != SYMBOL_REF)
4233 return 0;
4234
4235 c = XSTR (x, 0);
4236 if (memcmp (c, "@s.", 3) == 0)
4237 return 1;
4238
4239 return 0;
4240}
4241
4242int
4243rl78_sfr_p (rtx x)
4244{
4245 if (MEM_P (x))
4246 x = XEXP (x, 0);
4247 if (GET_CODE (x) != CONST_INT)
4248 return 0;
4249
4250 if ((INTVAL (x) & 0xFF00) != 0xFF00)
4251 return 0;
4252
4253 return 1;
4254}
4255
4256#undef TARGET_STRIP_NAME_ENCODING
4257#define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding
4258
4259static const char *
4260rl78_strip_name_encoding (const char * sym)
4261{
4262 while (1)
4263 {
4264 if (*sym == '*')
4265 sym++;
4266 else if (*sym == '@' && sym[2] == '.')
4267 sym += 3;
4268 else
4269 return sym;
4270 }
4271}
4272
4273/* Like rl78_strip_name_encoding, but does not strip leading asterisks. This
4274 is important if the stripped name is going to be passed to assemble_name()
4275 as that handles asterisk prefixed names in a special manner. */
4276
4277static const char *
4278rl78_strip_nonasm_name_encoding (const char * sym)
4279{
4280 while (1)
4281 {
4282 if (*sym == '@' && sym[2] == '.')
4283 sym += 3;
4284 else
4285 return sym;
4286 }
4287}
4288
4289
4290static int
4291rl78_attrlist_to_encoding (tree list, tree decl ATTRIBUTE_UNUSED)
4292{
4293 while (list)
4294 {
4295 if (is_attribute_p ("saddr", TREE_PURPOSE (list)))
4296 return 's';
4297 list = TREE_CHAIN (list);
4298 }
4299
4300 return 0;
4301}
4302
4303#define RL78_ATTRIBUTES(decl) \
4304 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
4305 : DECL_ATTRIBUTES (decl) \
4306 ? (DECL_ATTRIBUTES (decl)) \
4307 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
4308
4309#undef TARGET_ENCODE_SECTION_INFO
4310#define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info
4311
4312static void
4313rl78_encode_section_info (tree decl, rtx rtl, int first)
4314{
4315 rtx rtlname;
4316 const char * oldname;
4317 char encoding;
4318 char * newname;
4319 tree idp;
4320 tree type;
4321 tree rl78_attributes;
4322
4323 if (!first)
4324 return;
4325
4326 rtlname = XEXP (rtl, 0);
4327
4328 if (GET_CODE (rtlname) == SYMBOL_REF)
4329 oldname = XSTR (rtlname, 0);
4330 else if (GET_CODE (rtlname) == MEM
4331 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
4332 oldname = XSTR (XEXP (rtlname, 0), 0);
4333 else
4334 gcc_unreachable ();
4335
4336 type = TREE_TYPE (decl);
4337 if (type == error_mark_node)
4338 return;
4339 if (! DECL_P (decl))
4340 return;
4341 rl78_attributes = RL78_ATTRIBUTES (decl);
4342
4343 encoding = rl78_attrlist_to_encoding (rl78_attributes, decl);
4344
4345 if (encoding)
4346 {
4347 newname = (char *) alloca (strlen (oldname) + 4);
4348 sprintf (newname, "@%c.%s", encoding, oldname);
4349 idp = get_identifier (newname);
4350 XEXP (rtl, 0) =
4351 gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
4352 SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl);
4353 SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl);
4354 }
4355}
4356
4357#undef TARGET_ASM_INIT_SECTIONS
4358#define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections
4359
4360static void
4361rl78_asm_init_sections (void)
4362{
4363 saddr_section
4364 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
4365 "\t.section .saddr,\"aw\",@progbits");
4366 frodata_section
4367 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
4368 "\t.section .frodata,\"aw\",@progbits");
4369}
4370
4371#undef TARGET_ASM_SELECT_SECTION
4372#define TARGET_ASM_SELECT_SECTION rl78_select_section
4373
4374static section *
4375rl78_select_section (tree decl,
8d2e95d3 4376 int reloc,
4377 unsigned HOST_WIDE_INT align)
0c5d0bfa 4378{
4379 int readonly = 1;
4380
4381 switch (TREE_CODE (decl))
4382 {
4383 case VAR_DECL:
4384 if (!TREE_READONLY (decl)
4385 || TREE_SIDE_EFFECTS (decl)
4386 || !DECL_INITIAL (decl)
4387 || (DECL_INITIAL (decl) != error_mark_node
4388 && !TREE_CONSTANT (DECL_INITIAL (decl))))
4389 readonly = 0;
4390 break;
4391 case CONSTRUCTOR:
4392 if (! TREE_CONSTANT (decl))
4393 readonly = 0;
4394 break;
4395
4396 default:
4397 break;
4398 }
4399
4400 if (TREE_CODE (decl) == VAR_DECL)
4401 {
4402 const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4403
4404 if (name[0] == '@' && name[2] == '.')
4405 switch (name[1])
4406 {
4407 case 's':
4408 return saddr_section;
4409 }
4410
4411 if (TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_FAR
4412 && readonly)
4413 {
4414 return frodata_section;
4415 }
4416 }
4417
4418 if (readonly)
5c14cb1d 4419 return TARGET_ES0 ? frodata_section : readonly_data_section;
0c5d0bfa 4420
8d2e95d3 4421 switch (categorize_decl_for_section (decl, reloc))
4422 {
4423 case SECCAT_TEXT: return text_section;
4424 case SECCAT_DATA: return data_section;
4425 case SECCAT_BSS: return bss_section;
5c14cb1d 4426 case SECCAT_RODATA: return TARGET_ES0 ? frodata_section : readonly_data_section;
8d2e95d3 4427 default:
4428 return default_select_section (decl, reloc, align);
4429 }
0c5d0bfa 4430}
4431
4432void
4433rl78_output_labelref (FILE *file, const char *str)
4434{
4435 const char *str2;
4436
4437 str2 = targetm.strip_name_encoding (str);
4438 if (str2[0] != '.')
4439 fputs (user_label_prefix, file);
4440 fputs (str2, file);
4441}
4442
4443void
4444rl78_output_aligned_common (FILE *stream,
4445 tree decl ATTRIBUTE_UNUSED,
4446 const char *name,
4447 int size, int align, int global)
4448{
4449 /* We intentionally don't use rl78_section_tag() here. */
4450 if (name[0] == '@' && name[2] == '.')
4451 {
4452 const char *sec = 0;
4453 switch (name[1])
4454 {
4455 case 's':
4456 switch_to_section (saddr_section);
4457 sec = ".saddr";
4458 break;
4459 }
4460 if (sec)
4461 {
4462 const char *name2;
4463 int p2align = 0;
4464
4465 while (align > BITS_PER_UNIT)
4466 {
4467 align /= 2;
4468 p2align ++;
4469 }
4470 name2 = targetm.strip_name_encoding (name);
4471 if (global)
4472 fprintf (stream, "\t.global\t_%s\n", name2);
4473 fprintf (stream, "\t.p2align %d\n", p2align);
4474 fprintf (stream, "\t.type\t_%s,@object\n", name2);
4475 fprintf (stream, "\t.size\t_%s,%d\n", name2, size);
4476 fprintf (stream, "_%s:\n\t.zero\t%d\n", name2, size);
4477 return;
4478 }
4479 }
4480
4481 if (!global)
4482 {
4483 fprintf (stream, "\t.local\t");
4484 assemble_name (stream, name);
4485 fprintf (stream, "\n");
4486 }
4487 fprintf (stream, "\t.comm\t");
4488 assemble_name (stream, name);
4489 fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);
4490}
4491
4492#undef TARGET_INSERT_ATTRIBUTES
4493#define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes
4494
4495static void
4496rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED)
4497{
4498 if (TARGET_ES0
4499 && TREE_CODE (decl) == VAR_DECL
4500 && TREE_READONLY (decl)
4501 && TREE_ADDRESSABLE (decl)
4502 && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_GENERIC)
4503 {
4504 tree type = TREE_TYPE (decl);
4505 tree attr = TYPE_ATTRIBUTES (type);
4506 int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR);
e98e1692 4507
0c5d0bfa 4508 TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q);
4509 }
4510}
4511
4512#undef TARGET_ASM_INTEGER
4513#define TARGET_ASM_INTEGER rl78_asm_out_integer
4514
4515static bool
4516rl78_asm_out_integer (rtx x, unsigned int size, int aligned_p)
4517{
4518 if (default_assemble_integer (x, size, aligned_p))
4519 return true;
4520
4521 if (size == 4)
4522 {
4523 assemble_integer_with_op (".long\t", x);
4524 return true;
4525 }
4526
4527 return false;
4528}
0c5d0bfa 4529\f
99bdcd9d 4530#undef TARGET_UNWIND_WORD_MODE
4531#define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
4532
3754d046 4533static machine_mode
99bdcd9d 4534rl78_unwind_word_mode (void)
4535{
4536 return HImode;
4537}
4538
0c5d0bfa 4539#ifndef USE_COLLECT2
4540#undef TARGET_ASM_CONSTRUCTOR
4541#define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor
4542#undef TARGET_ASM_DESTRUCTOR
4543#define TARGET_ASM_DESTRUCTOR rl78_asm_destructor
4544
4545static void
4546rl78_asm_ctor_dtor (rtx symbol, int priority, bool is_ctor)
4547{
4548 section *sec;
4549
4550 if (priority != DEFAULT_INIT_PRIORITY)
4551 {
4552 /* This section of the function is based upon code copied
4553 from: gcc/varasm.c:get_cdtor_priority_section(). */
4554 char buf[16];
4555
4556 sprintf (buf, "%s.%.5u", is_ctor ? ".ctors" : ".dtors",
4557 MAX_INIT_PRIORITY - priority);
4558 sec = get_section (buf, 0, NULL);
4559 }
4560 else
4561 sec = is_ctor ? ctors_section : dtors_section;
4562
4563 assemble_addr_to_section (symbol, sec);
4564}
4565
4566static void
4567rl78_asm_constructor (rtx symbol, int priority)
4568{
4569 rl78_asm_ctor_dtor (symbol, priority, true);
4570}
4571
4572static void
4573rl78_asm_destructor (rtx symbol, int priority)
4574{
4575 rl78_asm_ctor_dtor (symbol, priority, false);
4576}
4577#endif /* ! USE_COLLECT2 */
4578
4579/* Scan backwards through the insn chain looking to see if the flags
4580 have been set for a comparison of OP against OPERAND. Start with
4581 the insn *before* the current insn. */
4582
4583bool
4584rl78_flags_already_set (rtx op, rtx operand)
4585{
4586 /* We only track the Z flag. */
4587 if (GET_CODE (op) != EQ && GET_CODE (op) != NE)
4588 return false;
4589
4590 /* This should not happen, but let's be paranoid. */
4591 if (current_output_insn == NULL_RTX)
4592 return false;
4593
4594 rtx_insn *insn;
4595 bool res = false;
4596
4597 for (insn = prev_nonnote_nondebug_insn (current_output_insn);
4598 insn != NULL_RTX;
4599 insn = prev_nonnote_nondebug_insn (insn))
4600 {
4601 if (LABEL_P (insn))
4602 break;
e98e1692 4603
0c5d0bfa 4604 if (! INSN_P (insn))
4605 continue;
4606
4607 /* Make sure that the insn can be recognized. */
4608 if (recog_memoized (insn) == -1)
4609 continue;
4610
4611 enum attr_update_Z updated = get_attr_update_Z (insn);
4612
4613 rtx set = single_set (insn);
4614 bool must_break = (set != NULL_RTX && rtx_equal_p (operand, SET_DEST (set)));
4615
4616 switch (updated)
4617 {
4618 case UPDATE_Z_NO:
4619 break;
4620 case UPDATE_Z_CLOBBER:
4621 must_break = true;
4622 break;
4623 case UPDATE_Z_UPDATE_Z:
4624 res = must_break;
4625 must_break = true;
4626 break;
4627 default:
4628 gcc_unreachable ();
4629 }
4630
4631 if (must_break)
4632 break;
4633 }
4634
4635 /* We have to re-recognize the current insn as the call(s) to
4636 get_attr_update_Z() above will have overwritten the recog_data cache. */
4637 recog_memoized (current_output_insn);
4638 cleanup_subreg_operands (current_output_insn);
4639 constrain_operands_cached (current_output_insn, 1);
4640
4641 return res;
4642}
d1dc25ff 4643\f
4644#undef TARGET_PREFERRED_RELOAD_CLASS
4645#define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
4646
4647static reg_class_t
d1f90de5 4648rl78_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t rclass)
d1dc25ff 4649{
4650 if (rclass == NO_REGS)
4651 rclass = V_REGS;
4652
4653 return rclass;
4654}
4655
889a65e7 4656\f
78e515f7 4657struct gcc_target targetm = TARGET_INITIALIZER;
4658
4659#include "gt-rl78.h"