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