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