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