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