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