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