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