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