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