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