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