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