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