]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/rl78/rl78.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / config / rl78 / rl78.c
CommitLineData
78e515f7 1/* Subroutines used for code generation on Renesas RL78 processors.
fbd26352 2 Copyright (C) 2011-2019 Free Software Foundation, Inc.
78e515f7 3 Contributed by Red Hat.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
785790dc 21#define IN_TARGET_CODE 1
22
78e515f7 23#include "config.h"
24#include "system.h"
25#include "coretypes.h"
9ef16211 26#include "backend.h"
c1eb80de 27#include "target.h"
9ef16211 28#include "rtl.h"
c1eb80de 29#include "tree.h"
9ef16211 30#include "df.h"
ad7b10a2 31#include "memmodel.h"
c1eb80de 32#include "tm_p.h"
33#include "stringpool.h"
0b3bf55c 34#include "attribs.h"
c1eb80de 35#include "optabs.h"
36#include "emit-rtl.h"
37#include "recog.h"
38#include "diagnostic-core.h"
9ed99284 39#include "varasm.h"
40#include "stor-layout.h"
41#include "calls.h"
78e515f7 42#include "output.h"
43#include "insn-attr.h"
d53441c8 44#include "explow.h"
78e515f7 45#include "expr.h"
78e515f7 46#include "reload.h"
94ea8568 47#include "cfgrtl.h"
78e515f7 48#include "langhooks.h"
f4d26dae 49#include "tree-pass.h"
4abac0f0 50#include "context.h"
3f3556f1 51#include "tm-constrs.h" /* for satisfies_constraint_*(). */
f7715905 52#include "builtins.h"
4b498588 53
0c71fb4f 54/* This file should be included last. */
4b498588 55#include "target-def.h"
78e515f7 56\f
57static inline bool is_interrupt_func (const_tree decl);
58static inline bool is_brk_interrupt_func (const_tree decl);
59static void rl78_reorg (void);
0c5d0bfa 60static const char *rl78_strip_name_encoding (const char *);
61static const char *rl78_strip_nonasm_name_encoding (const char *);
62static section * rl78_select_section (tree, int, unsigned HOST_WIDE_INT);
78e515f7 63\f
64
65/* Debugging statements are tagged with DEBUG0 only so that they can
66 be easily enabled individually, by replacing the '0' with '1' as
67 needed. */
68#define DEBUG0 0
69#define DEBUG1 1
70
71/* REGISTER_NAMES has the names for individual 8-bit registers, but
72 these have the names we need to use when referring to 16-bit
73 register pairs. */
74static const char * const word_regnames[] =
75{
76 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
77 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
78 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
79 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
80 "sp", "ap", "psw", "es", "cs"
81};
82
61bafda6 83/* used by rl78_addsi3_internal for formatting insns output */
84static char fmt_buffer[1024];
85
dce5e16b 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{
1e0295b9 95 {0xf00e8, E_QImode},
96 {0xffff0, E_HImode},
97 {0xffff2, E_HImode},
98 {0xf2224, E_HImode},
99 {0xf00e0, E_HImode},
100 {0xf00e2, E_HImode}
dce5e16b 101};
102
78e515f7 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;
93e93552 126 /* True if the ES register is used and hence
127 needs to be saved inside interrupt handlers. */
128 bool uses_es;
78e515f7 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
25a27413 138 m = ggc_cleared_alloc<machine_function> ();
78e515f7 139 m->virt_insns_ok = 1;
140
141 return m;
142}
143
78e515f7 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. */
93e93552 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 };
78e515f7 161
93e93552 162 class pass_rl78_devirt : public rtl_opt_pass
4abac0f0 163 {
93e93552 164 public:
165 pass_rl78_devirt (gcc::context *ctxt)
166 : rtl_opt_pass (pass_data_rl78_devirt, ctxt)
167 {
168 }
4abac0f0 169
93e93552 170 /* opt_pass methods: */
171 virtual unsigned int execute (function *)
65b0537f 172 {
173 rl78_reorg ();
174 return 0;
175 }
93e93552 176 };
4abac0f0 177} // anon namespace
178
179rtl_opt_pass *
180make_pass_rl78_devirt (gcc::context *ctxt)
181{
182 return new pass_rl78_devirt (ctxt);
183}
184
1d701d79 185/* Redundant move elimination pass. Must be run after the basic block
186 reordering pass for the best effect. */
187
3f3556f1 188static unsigned int
189move_elim_pass (void)
190{
50fc2d35 191 rtx_insn *insn, *ninsn;
192 rtx prev = NULL_RTX;
3f3556f1 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))
f648448d 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)))
3f3556f1 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 }
93e93552 229
3f3556f1 230 if (dump_file)
2cf07b8b 231 print_rtl_with_bb (dump_file, get_insns (), TDF_NONE);
3f3556f1 232
233 return 0;
234}
235
93e93552 236namespace
3f3556f1 237{
93e93552 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 };
3f3556f1 250
93e93552 251 class pass_rl78_move_elim : public rtl_opt_pass
3f3556f1 252 {
93e93552 253 public:
254 pass_rl78_move_elim (gcc::context *ctxt)
255 : rtl_opt_pass (pass_data_rl78_move_elim, ctxt)
256 {
257 }
3f3556f1 258
93e93552 259 /* opt_pass methods: */
260 virtual unsigned int execute (function *) { return move_elim_pass (); }
261 };
3f3556f1 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}
4abac0f0 269
78e515f7 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
c5a0ae5e 278 if (TARGET_G10)
78e515f7 279 {
c5a0ae5e 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);
55ea1438 291 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 24 + i, 0xffee0 + i);
c5a0ae5e 292 }
78e515f7 293 }
294
4abac0f0 295 opt_pass *rl78_devirt_pass = make_pass_rl78_devirt (g);
33c6d8ad 296 struct register_pass_info rl78_devirt_info =
4abac0f0 297 {
298 rl78_devirt_pass,
3f3556f1 299 "pro_and_epilogue",
4abac0f0 300 1,
301 PASS_POS_INSERT_BEFORE
302 };
303
3f3556f1 304 opt_pass *rl78_move_elim_pass = make_pass_rl78_move_elim (g);
33c6d8ad 305 struct register_pass_info rl78_move_elim_info =
3f3556f1 306 {
307 rl78_move_elim_pass,
308 "bbro",
309 1,
310 PASS_POS_INSERT_AFTER
311 };
312
78e515f7 313 register_pass (& rl78_devirt_info);
3f3556f1 314 register_pass (& rl78_move_elim_info);
78e515f7 315}
316
0c5d0bfa 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}
78e515f7 340\f
341#undef TARGET_OPTION_OVERRIDE
342#define TARGET_OPTION_OVERRIDE rl78_option_override
343
dce5e16b 344#define MUST_SAVE_MDUC_REGISTERS \
345 (TARGET_SAVE_MDUC_REGISTERS \
346 && (is_interrupt_func (NULL_TREE)) && RL78_MUL_G13)
347
78e515f7 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;
55ea1438 356
357 if (TARGET_ALLREGS)
358 {
359 int i;
1d701d79 360
361 for (i = 24; i < 32; i++)
55ea1438 362 fixed_regs[i] = 0;
363 }
0c5d0bfa 364
365 if (TARGET_ES0
366 && strcmp (lang_hooks.name, "GNU C")
95328f38 367 && strcmp (lang_hooks.name, "GNU C11")
a0f44249 368 && strcmp (lang_hooks.name, "GNU C17")
fcbe1d64 369 && strcmp (lang_hooks.name, "GNU C2X")
95328f38 370 && strcmp (lang_hooks.name, "GNU C89")
371 && strcmp (lang_hooks.name, "GNU C99")
0c5d0bfa 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. */
2f6d557f 375 error ("%<-mes0%> can only be used with C");
e98e1692 376
dce5e16b 377 if (TARGET_SAVE_MDUC_REGISTERS && !(TARGET_G13 || RL78_MUL_G13))
378 warning (0, "mduc registers only saved for G13 target");
379
e98e1692 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;
2f6d557f 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;
e98e1692 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. */
2f6d557f 407 case MUL_G14: error ("%<-mmul=g14%> cannot be used with "
408 "%<-mcpu=g13%>"); break;
e98e1692 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. */
2f6d557f 420 case MUL_G13: error ("%<-mmul=g13%> cannot be used with "
421 "%<-mcpu=g14%>"); break;
e98e1692 422 }
423 break;
424 }
78e515f7 425}
426
427/* Most registers are 8 bits. Some are 16 bits because, for example,
8a6bcd4e 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. */
78e515f7 432static const int register_sizes[] =
433{
434 1, 1, 1, 1, 1, 1, 1, 1,
435 1, 1, 1, 1, 1, 1, 1, 1,
8a6bcd4e 436 1, 1, 1, 1, 1, 1, 2, 2,
78e515f7 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
74f68e49 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)
78e515f7 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
b395382f 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)
78e515f7 480{
481 int s = GET_MODE_SIZE (mode);
482
483 if (s < 1)
b395382f 484 return false;
78e515f7 485 /* These are not to be used by gcc. */
486 if (regno == 23 || regno == ES_REG || regno == CS_REG)
b395382f 487 return false;
8a6bcd4e 488 /* $fp can always be accessed as a 16-bit value. */
78e515f7 489 if (regno == FP_REG && s == 2)
b395382f 490 return true;
78e515f7 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))
b395382f 496 return false;
497 return true;
78e515f7 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])
b395382f 503 return true;
504 return false;
78e515f7 505}
506
5f6dcf1a 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
78e515f7 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
3754d046 523rl78_subreg (machine_mode mode, rtx r, machine_mode omode, int byte)
78e515f7 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
1d701d79 568/* Generate code to move an SImode value. */
3f3556f1 569void
582adad1 570rl78_split_movsi (rtx *operands, machine_mode omode)
3f3556f1 571{
572 rtx op00, op02, op10, op12;
573
29236229 574 op00 = rl78_subreg (HImode, operands[0], omode, 0);
575 op02 = rl78_subreg (HImode, operands[0], omode, 2);
1d701d79 576
3f3556f1 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 {
29236229 587 op10 = rl78_subreg (HImode, operands[1], omode, 0);
588 op12 = rl78_subreg (HImode, operands[1], omode, 2);
3f3556f1 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
ce8becce 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
78e515f7 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
c17507c2 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
78e515f7 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
69b00414 705/* Returns true if the given register needs to be saved by the
78e515f7 706 current function. */
69b00414 707static bool
708need_to_save (unsigned int regno)
78e515f7 709{
710 if (is_interrupt_func (cfun->decl))
711 {
1d701d79 712 /* We don't know what devirt will need */
713 if (regno < 8)
714 return true;
715
69b00414 716 /* We don't need to save registers that have
717 been reserved for interrupt handlers. */
78e515f7 718 if (regno > 23)
69b00414 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
70f723f8 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. */
726 if (!crtl->is_leaf && call_used_regs[regno] && regno < 22)
69b00414 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);
78e515f7 732 }
69b00414 733
52337e94 734 if (regno == FRAME_POINTER_REGNUM
735 && (frame_pointer_needed || df_regs_ever_live_p (regno)))
69b00414 736 return true;
78e515f7 737 if (fixed_regs[regno])
69b00414 738 return false;
78e515f7 739 if (crtl->calls_eh_return)
69b00414 740 return true;
78e515f7 741 if (df_regs_ever_live_p (regno)
742 && !call_used_regs[regno])
69b00414 743 return true;
744 return false;
78e515f7 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,
8a6bcd4e 811 tree name,
5c38c127 812 tree args ATTRIBUTE_UNUSED,
8a6bcd4e 813 int flags ATTRIBUTE_UNUSED,
814 bool * no_add_attrs)
78e515f7 815{
816 gcc_assert (DECL_P (* node));
78e515f7 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
0c5d0bfa 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 {
867 warning (OPT_Wattributes, "%qE attribute doesn't apply to functions",
868 name);
869 * no_add_attrs = true;
870 }
871
872 return NULL_TREE;
873}
874
76205d3a 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
78e515f7 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{
672bc44d 903 /* Name, min_len, max_len, decl_req, type_req, fn_type_req,
904 affects_type_identity, handler, exclude. */
76205d3a 905 { "interrupt", 0, -1, true, false, false, false,
672bc44d 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 },
446afaa9 913 { "vector", 1, -1, true, false, false, false,
914 rl78_handle_vector_attribute, NULL },
672bc44d 915 { NULL, 0, 0, false, false, false, false, NULL, NULL }
78e515f7 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
1d701d79 930 if (GET_CODE (x) == UNSPEC
931 && XINT (x, 1) == UNS_ES_ADDR)
932 x = XVECEXP (x, 0, 1);
933
78e515f7 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
0c5d0bfa 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
78e515f7 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
0c5d0bfa 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
78e515f7 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
0c5d0bfa 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
f77c4496 1063static scalar_int_mode
0c5d0bfa 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
78e515f7 1079/* Used in various constraints and predicates to match operands in the
1080 "far" address space. */
1081int
1082rl78_far_p (rtx x)
1083{
3f3556f1 1084 if (! MEM_P (x))
78e515f7 1085 return 0;
1086#if DEBUG0
8a6bcd4e 1087 fprintf (stderr, "\033[35mrl78_far_p: "); debug_rtx (x);
3f3556f1 1088 fprintf (stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
78e515f7 1089#endif
750dcfc5 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
0c5d0bfa 1096 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x))) == 32;
78e515f7 1097}
1098
1099/* Return the appropriate mode for a named address pointer. */
8a6bcd4e 1100#undef TARGET_ADDR_SPACE_POINTER_MODE
78e515f7 1101#define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
93e93552 1102
f77c4496 1103static scalar_int_mode
78e515f7 1104rl78_addr_space_pointer_mode (addr_space_t addrspace)
1105{
1106 switch (addrspace)
1107 {
1108 case ADDR_SPACE_GENERIC:
1109 return HImode;
0c5d0bfa 1110 case ADDR_SPACE_NEAR:
1111 return HImode;
78e515f7 1112 case ADDR_SPACE_FAR:
1113 return SImode;
1114 default:
1115 gcc_unreachable ();
1116 }
1117}
1118
556726e1 1119/* Returns TRUE for valid addresses. */
8a6bcd4e 1120#undef TARGET_VALID_POINTER_MODE
556726e1 1121#define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
93e93552 1122
556726e1 1123static bool
f77c4496 1124rl78_valid_pointer_mode (scalar_int_mode m)
556726e1 1125{
1126 return (m == HImode || m == SImode);
1127}
1128
78e515f7 1129#undef TARGET_LEGITIMATE_CONSTANT_P
1130#define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
1131
1132static bool
3754d046 1133rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED)
78e515f7 1134{
1135 return true;
1136}
1137
e46fbef5 1138#undef TARGET_LRA_P
1139#define TARGET_LRA_P hook_bool_void_false
1140
78e515f7 1141#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
1142#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
1143
1144bool
3754d046 1145rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED, rtx x,
78e515f7 1146 bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
1147{
1148 rtx base, index, addend;
1d701d79 1149 bool is_far_addr = false;
0c5d0bfa 1150 int as_bits;
1151
1152 as_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (as));
78e515f7 1153
563dc27b 1154 if (GET_CODE (x) == UNSPEC
1155 && XINT (x, 1) == UNS_ES_ADDR)
1d701d79 1156 {
1157 x = XVECEXP (x, 0, 1);
1158 is_far_addr = true;
1159 }
563dc27b 1160
0c5d0bfa 1161 if (as_bits == 16 && is_far_addr)
78e515f7 1162 return false;
1163
1164 if (! characterize_address (x, &base, &index, &addend))
1165 return false;
1166
03e08569 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. */
0c5d0bfa 1171 if (addend && base && as_bits == 32 && GET_MODE (base) == SImode)
03e08569 1172 return false;
1173
78e515f7 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
3f3556f1 1188 if (! cfun->machine->virt_insns_ok && base && GET_CODE (base) == REG
1189 && REGNO (base) >= 8 && REGNO (base) <= 31)
1190 return false;
1191
78e515f7 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
93e93552 1198
78e515f7 1199static bool
1200rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
1201{
0c5d0bfa 1202 int subset_bits;
1203 int superset_bits;
78e515f7 1204
0c5d0bfa 1205 subset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset));
1206 superset_bits = GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset));
78e515f7 1207
0c5d0bfa 1208 return (subset_bits <= superset_bits);
78e515f7 1209}
1210
1211#undef TARGET_ADDR_SPACE_CONVERT
1212#define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
93e93552 1213
78e515f7 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;
0c5d0bfa 1221 int to_bits;
1222 int from_bits;
78e515f7 1223
0c5d0bfa 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));
78e515f7 1226
0c5d0bfa 1227 if (to_bits < from_bits)
78e515f7 1228 {
0c5d0bfa 1229 rtx tmp;
78e515f7 1230 /* This is unpredictable, as we're truncating off usable address
1231 bits. */
1232
0c5d0bfa 1233 warning (OPT_Waddress, "converting far pointer to near pointer");
78e515f7 1234 result = gen_reg_rtx (HImode);
0c5d0bfa 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);
78e515f7 1242 return result;
1243 }
0c5d0bfa 1244 else if (to_bits > from_bits)
78e515f7 1245 {
1246 /* This always works. */
1247 result = gen_reg_rtx (SImode);
78e515f7 1248 emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op);
0c5d0bfa 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));
78e515f7 1254 return result;
1255 }
1256 else
0c5d0bfa 1257 return op;
1258 gcc_unreachable ();
78e515f7 1259}
1260
1261/* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
1262bool
3754d046 1263rl78_regno_mode_code_ok_for_base_p (int regno, machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1264 addr_space_t address_space ATTRIBUTE_UNUSED,
1265 int outer_code ATTRIBUTE_UNUSED, int index_code)
1266{
f716766f 1267 if (regno <= SP_REG && regno >= 16)
78e515f7 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
3754d046 1278rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 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
93e93552 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
78e515f7 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
dce5e16b 1351static bool
fbac2992 1352rl78_is_naked_func (void)
1353{
1354 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE);
1355}
1356
dce5e16b 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
78e515f7 1377/* Expand the function prologue (from the prologue pattern). */
dce5e16b 1378
78e515f7 1379void
1380rl78_expand_prologue (void)
1381{
1382 int i, fs;
1383 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
90f06e32 1384 rtx ax = gen_rtx_REG (HImode, AX_REG);
78e515f7 1385 int rb = 0;
1386
fbac2992 1387 if (rl78_is_naked_func ())
1388 return;
1389
69b00414 1390 /* Always re-compute the frame info - the register usage may have changed. */
1391 rl78_compute_frame_info ();
78e515f7 1392
dce5e16b 1393 if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ()))
1394 cfun->machine->framesize += ARRAY_SIZE (mduc_regs) * 2;
1395
e4858e6a 1396 if (flag_stack_usage_info)
1397 current_function_static_stack_size = cfun->machine->framesize;
1398
c5a0ae5e 1399 if (is_interrupt_func (cfun->decl) && !TARGET_G10)
69b00414 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 }
8d5f09ff 1407
78e515f7 1408 for (i = 0; i < 16; i++)
1409 if (cfun->machine->need_to_push [i])
1410 {
90f06e32 1411 int reg = i * 2;
1412
c5a0ae5e 1413 if (TARGET_G10)
78e515f7 1414 {
90f06e32 1415 if (reg >= 8)
1416 {
1417 emit_move_insn (ax, gen_rtx_REG (HImode, reg));
1418 reg = AX_REG;
1419 }
78e515f7 1420 }
1d701d79 1421 else
1422 {
90f06e32 1423 int need_bank = i/4;
1d701d79 1424
1425 if (need_bank != rb)
1426 {
1427 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1428 rb = need_bank;
1429 }
1d701d79 1430 }
90f06e32 1431
1432 F (emit_insn (gen_push (gen_rtx_REG (HImode, reg))));
78e515f7 1433 }
1d701d79 1434
78e515f7 1435 if (rb != 0)
1436 emit_insn (gen_sel_rb (GEN_INT (0)));
1437
93e93552 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)));
90f06e32 1442 F (emit_insn (gen_push (ax)));
93e93552 1443 }
1444
dce5e16b 1445 /* Save MDUC registers inside interrupt routine. */
1446 if (MUST_SAVE_MDUC_REGISTERS && (!crtl->is_leaf || check_mduc_usage ()))
1447 {
936f302c 1448 for (unsigned i = 0; i < ARRAY_SIZE (mduc_regs); i++)
dce5e16b 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
78e515f7 1463 if (frame_pointer_needed)
ed2d7e5b 1464 {
90f06e32 1465 F (emit_move_insn (ax, sp));
1466 F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM), ax));
ed2d7e5b 1467 }
78e515f7 1468
1469 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
90f06e32 1470 if (fs > 0)
78e515f7 1471 {
90f06e32 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)));
d1dc25ff 1480 insn = F (emit_move_insn (sp, ax));
90f06e32 1481 add_reg_note (insn, REG_FRAME_RELATED_EXPR,
d1f9b275 1482 gen_rtx_SET (sp, gen_rtx_PLUS (HImode, sp,
1483 GEN_INT (-fs))));
90f06e32 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 }
78e515f7 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);
90f06e32 1504 rtx ax = gen_rtx_REG (HImode, AX_REG);
78e515f7 1505 int rb = 0;
1506
fbac2992 1507 if (rl78_is_naked_func ())
1508 return;
1509
78e515f7 1510 if (frame_pointer_needed)
1511 {
90f06e32 1512 emit_move_insn (ax, gen_rtx_REG (HImode, FRAME_POINTER_REGNUM));
1513 emit_move_insn (sp, ax);
78e515f7 1514 }
1515 else
1516 {
1517 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
90f06e32 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
78e515f7 1525 {
90f06e32 1526 while (fs > 0)
1527 {
1528 int fs_byte = (fs > 254) ? 254 : fs;
78e515f7 1529
90f06e32 1530 emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte)));
1531 fs -= fs_byte;
1532 }
78e515f7 1533 }
1534 }
1535
dce5e16b 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
93e93552 1553 if (is_interrupt_func (cfun->decl) && cfun->machine->uses_es)
1554 {
1555 emit_insn (gen_pop (gen_rtx_REG (HImode, AX_REG)));
0c5d0bfa 1556 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode, A_REG)));
93e93552 1557 }
1558
78e515f7 1559 for (i = 15; i >= 0; i--)
1560 if (cfun->machine->need_to_push [i])
1561 {
85b515c9 1562 rtx dest = gen_rtx_REG (HImode, i * 2);
1563
c5a0ae5e 1564 if (TARGET_G10)
78e515f7 1565 {
90f06e32 1566 if (i < 8)
1567 emit_insn (gen_pop (dest));
1568 else
85b515c9 1569 {
90f06e32 1570 emit_insn (gen_pop (ax));
85b515c9 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 }
c5a0ae5e 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 }
85b515c9 1585 emit_insn (gen_pop (dest));
78e515f7 1586 }
78e515f7 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
edf1f7ba 1600 emit_jump_insn (gen_rl78_return ());
78e515f7 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. */
edf1f7ba 1608 emit_jump_insn (gen_rl78_return ());
78e515f7 1609}
1610
1611#undef TARGET_ASM_FUNCTION_PROLOGUE
1612#define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1613
76205d3a 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
78e515f7 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
718e6d56 1674rl78_start_function (FILE *file)
78e515f7 1675{
1676 int i;
76205d3a 1677
1678 add_vector_labels (file, "interrupt");
1679 add_vector_labels (file, "vector");
78e515f7 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]);
3f3556f1 1691 fprintf (file, "\n");
78e515f7 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");
93e93552 1704
1705 if (cfun->machine->uses_es)
1706 fprintf (file, "\t; uses ES register\n");
dce5e16b 1707
1708 if (MUST_SAVE_MDUC_REGISTERS)
1709 fprintf (file, "\t; preserves MDUC registers\n");
78e515f7 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{
3754d046 1723 machine_mode mode = TYPE_MODE (ret_type);
78e515f7 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
3754d046 1731static machine_mode
78e515f7 1732rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
3754d046 1733 machine_mode mode,
78e515f7 1734 int *punsignedp ATTRIBUTE_UNUSED,
1735 const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED)
1736{
1737 return mode;
1738}
1739
1740/* Return an RTL expression describing the register holding a function
1741 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
1742 be passed on the stack. CUM describes the previous parameters to the
1743 function and NAMED is false if the parameter is part of a variable
1744 parameter list, or the last named parameter before the start of a
1745 variable parameter list. */
1746
1747#undef TARGET_FUNCTION_ARG
1748#define TARGET_FUNCTION_ARG rl78_function_arg
1749
1750static rtx
1751rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
3754d046 1752 machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1753 const_tree type ATTRIBUTE_UNUSED,
1754 bool named ATTRIBUTE_UNUSED)
1755{
1756 return NULL_RTX;
1757}
1758
1759#undef TARGET_FUNCTION_ARG_ADVANCE
1760#define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1761
1762static void
3754d046 1763rl78_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, const_tree type,
78e515f7 1764 bool named ATTRIBUTE_UNUSED)
1765{
1766 int rounded_size;
1767 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
1768
1769 rounded_size = ((mode == BLKmode)
1770 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
1771 if (rounded_size & 1)
1772 rounded_size ++;
1773 (*cum) += rounded_size;
1774}
1775
1776#undef TARGET_FUNCTION_ARG_BOUNDARY
1777#define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1778
1779static unsigned int
3754d046 1780rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED,
78e515f7 1781 const_tree type ATTRIBUTE_UNUSED)
1782{
1783 return 16;
1784}
1785
1786/* Supported modifier letters:
1787
1788 A - address of a MEM
1789 S - SADDR form of a real register
1790 v - real register corresponding to a virtual register
1791 m - minus - negative of CONST_INT value.
2ced756b 1792 C - inverse of a conditional (NE vs EQ for example)
1793 C - complement of an integer
3f3556f1 1794 z - collapsed conditional
1795 s - shift count mod 8
1796 S - shift count mod 16
1797 r - reverse shift count (8-(count mod 8))
56df4a64 1798 B - bit position
78e515f7 1799
1800 h - bottom HI of an SI
1801 H - top HI of an SI
1802 q - bottom QI of an HI
1803 Q - top QI of an HI
1804 e - third QI of an SI (i.e. where the ES register gets values from)
3f3556f1 1805 E - fourth QI of an SI (i.e. MSB)
78e515f7 1806
d1dc25ff 1807 p - Add +0 to a zero-indexed HL based address.
78e515f7 1808*/
1809
1810/* Implements the bulk of rl78_print_operand, below. We do it this
1811 way because we need to test for a constant at the top level and
1812 insert the '#', but not test for it anywhere else as we recurse
1813 down into the operand. */
1814static void
1815rl78_print_operand_1 (FILE * file, rtx op, int letter)
1816{
1817 int need_paren;
1818
1819 switch (GET_CODE (op))
1820 {
1821 case MEM:
1822 if (letter == 'A')
1823 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1824 else
1825 {
1826 if (rl78_far_p (op))
563dc27b 1827 {
1828 fprintf (file, "es:");
0c5d0bfa 1829 if (GET_CODE (XEXP (op, 0)) == UNSPEC)
1830 op = gen_rtx_MEM (GET_MODE (op), XVECEXP (XEXP (op, 0), 0, 1));
563dc27b 1831 }
78e515f7 1832 if (letter == 'H')
1833 {
1834 op = adjust_address (op, HImode, 2);
1835 letter = 0;
1836 }
1837 if (letter == 'h')
1838 {
1839 op = adjust_address (op, HImode, 0);
1840 letter = 0;
1841 }
1842 if (letter == 'Q')
1843 {
1844 op = adjust_address (op, QImode, 1);
1845 letter = 0;
1846 }
1847 if (letter == 'q')
1848 {
1849 op = adjust_address (op, QImode, 0);
1850 letter = 0;
1851 }
1852 if (letter == 'e')
1853 {
1854 op = adjust_address (op, QImode, 2);
1855 letter = 0;
1856 }
3f3556f1 1857 if (letter == 'E')
1858 {
1859 op = adjust_address (op, QImode, 3);
1860 letter = 0;
1861 }
78e515f7 1862 if (CONSTANT_P (XEXP (op, 0)))
1863 {
0c5d0bfa 1864 if (!rl78_saddr_p (op))
1865 fprintf (file, "!");
78e515f7 1866 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1867 }
1868 else if (GET_CODE (XEXP (op, 0)) == PLUS
1869 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF)
1870 {
0c5d0bfa 1871 if (!rl78_saddr_p (op))
1872 fprintf (file, "!");
78e515f7 1873 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1874 }
1875 else if (GET_CODE (XEXP (op, 0)) == PLUS
1876 && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
1877 && REGNO (XEXP (XEXP (op, 0), 0)) == 2)
1878 {
1879 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u');
3f3556f1 1880 fprintf (file, "[");
78e515f7 1881 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0);
d1dc25ff 1882 if (letter == 'p' && GET_CODE (XEXP (op, 0)) == REG)
1883 fprintf (file, "+0");
3f3556f1 1884 fprintf (file, "]");
78e515f7 1885 }
1886 else
1887 {
d1dc25ff 1888 op = XEXP (op, 0);
3f3556f1 1889 fprintf (file, "[");
d1dc25ff 1890 rl78_print_operand_1 (file, op, letter);
1891 if (letter == 'p' && REG_P (op) && REGNO (op) == 6)
40d1c891 1892 fprintf (file, "+0");
3f3556f1 1893 fprintf (file, "]");
78e515f7 1894 }
1895 }
1896 break;
1897
1898 case REG:
1899 if (letter == 'Q')
1900 fprintf (file, "%s", reg_names [REGNO (op) | 1]);
1901 else if (letter == 'H')
1902 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1903 else if (letter == 'q')
1904 fprintf (file, "%s", reg_names [REGNO (op) & ~1]);
1905 else if (letter == 'e')
1906 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
3f3556f1 1907 else if (letter == 'E')
1908 fprintf (file, "%s", reg_names [REGNO (op) + 3]);
78e515f7 1909 else if (letter == 'S')
1910 fprintf (file, "0x%x", 0xffef8 + REGNO (op));
1911 else if (GET_MODE (op) == HImode
1912 && ! (REGNO (op) & ~0xfe))
1913 {
1914 if (letter == 'v')
1915 fprintf (file, "%s", word_regnames [REGNO (op) % 8]);
1916 else
1917 fprintf (file, "%s", word_regnames [REGNO (op)]);
1918 }
1919 else
1920 fprintf (file, "%s", reg_names [REGNO (op)]);
1921 break;
1922
1923 case CONST_INT:
1924 if (letter == 'Q')
1925 fprintf (file, "%ld", INTVAL (op) >> 8);
1926 else if (letter == 'H')
1927 fprintf (file, "%ld", INTVAL (op) >> 16);
1928 else if (letter == 'q')
1929 fprintf (file, "%ld", INTVAL (op) & 0xff);
1930 else if (letter == 'h')
1931 fprintf (file, "%ld", INTVAL (op) & 0xffff);
1932 else if (letter == 'e')
1933 fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff);
56df4a64 1934 else if (letter == 'B')
0c5d0bfa 1935 {
1936 int ival = INTVAL (op);
1937 if (ival == -128)
1938 ival = 0x80;
1939 if (exact_log2 (ival) >= 0)
1940 fprintf (file, "%d", exact_log2 (ival));
1941 else
1942 fprintf (file, "%d", exact_log2 (~ival & 0xff));
1943 }
3f3556f1 1944 else if (letter == 'E')
1945 fprintf (file, "%ld", (INTVAL (op) >> 24) & 0xff);
78e515f7 1946 else if (letter == 'm')
1947 fprintf (file, "%ld", - INTVAL (op));
3f3556f1 1948 else if (letter == 's')
1949 fprintf (file, "%ld", INTVAL (op) % 8);
1950 else if (letter == 'S')
1951 fprintf (file, "%ld", INTVAL (op) % 16);
1952 else if (letter == 'r')
1953 fprintf (file, "%ld", 8 - (INTVAL (op) % 8));
1954 else if (letter == 'C')
1955 fprintf (file, "%ld", (INTVAL (op) ^ 0x8000) & 0xffff);
78e515f7 1956 else
3f3556f1 1957 fprintf (file, "%ld", INTVAL (op));
78e515f7 1958 break;
1959
1960 case CONST:
1961 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1962 break;
1963
1964 case ZERO_EXTRACT:
1965 {
1966 int bits = INTVAL (XEXP (op, 1));
1967 int ofs = INTVAL (XEXP (op, 2));
1968 if (bits == 16 && ofs == 0)
1969 fprintf (file, "%%lo16(");
1970 else if (bits == 16 && ofs == 16)
1971 fprintf (file, "%%hi16(");
1972 else if (bits == 8 && ofs == 16)
1973 fprintf (file, "%%hi8(");
1974 else
1975 gcc_unreachable ();
1976 rl78_print_operand_1 (file, XEXP (op, 0), 0);
1977 fprintf (file, ")");
1978 }
1979 break;
1980
1981 case ZERO_EXTEND:
1982 if (GET_CODE (XEXP (op, 0)) == REG)
1983 fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]);
1984 else
1985 print_rtl (file, op);
1986 break;
1987
1988 case PLUS:
1989 need_paren = 0;
1990 if (letter == 'H')
1991 {
1992 fprintf (file, "%%hi16(");
1993 need_paren = 1;
1994 letter = 0;
1995 }
1996 if (letter == 'h')
1997 {
1998 fprintf (file, "%%lo16(");
1999 need_paren = 1;
2000 letter = 0;
2001 }
2002 if (letter == 'e')
2003 {
2004 fprintf (file, "%%hi8(");
2005 need_paren = 1;
2006 letter = 0;
2007 }
2008 if (letter == 'q' || letter == 'Q')
2009 output_operand_lossage ("q/Q modifiers invalid for symbol references");
2010
2011 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
2012 {
d1dc25ff 2013 if (GET_CODE (XEXP (op, 1)) == SYMBOL_REF
2014 && SYMBOL_REF_DECL (XEXP (op, 1))
2015 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op, 1))) == FUNCTION_DECL)
2016 {
2017 fprintf (file, "%%code(");
2018 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op, 1), 0)));
2019 fprintf (file, "+");
2020 rl78_print_operand_1 (file, XEXP (op, 0), letter);
2021 fprintf (file, ")");
2022 }
2023 else
2024 {
2025 rl78_print_operand_1 (file, XEXP (op, 1), letter);
2026 fprintf (file, "+");
2027 rl78_print_operand_1 (file, XEXP (op, 0), letter);
2028 }
78e515f7 2029 }
2030 else
2031 {
d1dc25ff 2032 if (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
2033 && SYMBOL_REF_DECL (XEXP (op, 0))
2034 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op, 0))) == FUNCTION_DECL)
2035 {
2036 fprintf (file, "%%code(");
2037 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op, 0), 0)));
2038 fprintf (file, "+");
2039 rl78_print_operand_1 (file, XEXP (op, 1), letter);
2040 fprintf (file, ")");
2041 }
2042 else
2043 {
2044 rl78_print_operand_1 (file, XEXP (op, 0), letter);
2045 fprintf (file, "+");
2046 rl78_print_operand_1 (file, XEXP (op, 1), letter);
2047 }
78e515f7 2048 }
2049 if (need_paren)
2050 fprintf (file, ")");
2051 break;
2052
0c5d0bfa 2053 case SUBREG:
2054 if (GET_MODE (op) == HImode
2055 && SUBREG_BYTE (op) == 0)
2056 {
2057 fprintf (file, "%%lo16(");
2058 rl78_print_operand_1 (file, SUBREG_REG (op), 0);
2059 fprintf (file, ")");
2060 }
2061 else if (GET_MODE (op) == HImode
2062 && SUBREG_BYTE (op) == 2)
2063 {
2064 fprintf (file, "%%hi16(");
2065 rl78_print_operand_1 (file, SUBREG_REG (op), 0);
2066 fprintf (file, ")");
2067 }
2068 else
2069 {
2070 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
2071 }
2072 break;
2073
78e515f7 2074 case SYMBOL_REF:
2075 need_paren = 0;
2076 if (letter == 'H')
2077 {
2078 fprintf (file, "%%hi16(");
2079 need_paren = 1;
2080 letter = 0;
2081 }
2082 if (letter == 'h')
2083 {
2084 fprintf (file, "%%lo16(");
2085 need_paren = 1;
2086 letter = 0;
2087 }
2088 if (letter == 'e')
2089 {
2090 fprintf (file, "%%hi8(");
2091 need_paren = 1;
2092 letter = 0;
2093 }
2094 if (letter == 'q' || letter == 'Q')
2095 output_operand_lossage ("q/Q modifiers invalid for symbol references");
2096
0c5d0bfa 2097 if (SYMBOL_REF_DECL (op) && TREE_CODE (SYMBOL_REF_DECL (op)) == FUNCTION_DECL)
2098 {
2099 fprintf (file, "%%code(");
2100 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0)));
2101 fprintf (file, ")");
2102 }
2103 else
2104 assemble_name (file, rl78_strip_nonasm_name_encoding (XSTR (op, 0)));
78e515f7 2105 if (need_paren)
2106 fprintf (file, ")");
2107 break;
2108
2109 case CODE_LABEL:
2110 case LABEL_REF:
2111 output_asm_label (op);
2112 break;
2113
2114 case LTU:
3f3556f1 2115 if (letter == 'z')
2116 fprintf (file, "#comparison eliminated");
2117 else
2ced756b 2118 fprintf (file, letter == 'C' ? "nc" : "c");
78e515f7 2119 break;
2120 case LEU:
3f3556f1 2121 if (letter == 'z')
2122 fprintf (file, "br");
2123 else
2ced756b 2124 fprintf (file, letter == 'C' ? "h" : "nh");
78e515f7 2125 break;
2126 case GEU:
3f3556f1 2127 if (letter == 'z')
2128 fprintf (file, "br");
2129 else
2ced756b 2130 fprintf (file, letter == 'C' ? "c" : "nc");
78e515f7 2131 break;
2132 case GTU:
3f3556f1 2133 if (letter == 'z')
2134 fprintf (file, "#comparison eliminated");
2135 else
2ced756b 2136 fprintf (file, letter == 'C' ? "nh" : "h");
78e515f7 2137 break;
2138 case EQ:
3f3556f1 2139 if (letter == 'z')
2140 fprintf (file, "br");
2141 else
2ced756b 2142 fprintf (file, letter == 'C' ? "nz" : "z");
78e515f7 2143 break;
2144 case NE:
3f3556f1 2145 if (letter == 'z')
2146 fprintf (file, "#comparison eliminated");
2147 else
2ced756b 2148 fprintf (file, letter == 'C' ? "z" : "nz");
3f3556f1 2149 break;
2150
2151 /* Note: these assume appropriate adjustments were made so that
2152 unsigned comparisons, which is all this chip has, will
2153 work. */
2154 case LT:
2155 if (letter == 'z')
2156 fprintf (file, "#comparison eliminated");
2157 else
2ced756b 2158 fprintf (file, letter == 'C' ? "nc" : "c");
3f3556f1 2159 break;
2160 case LE:
2161 if (letter == 'z')
2162 fprintf (file, "br");
2163 else
2ced756b 2164 fprintf (file, letter == 'C' ? "h" : "nh");
3f3556f1 2165 break;
2166 case GE:
2167 if (letter == 'z')
2168 fprintf (file, "br");
2169 else
2ced756b 2170 fprintf (file, letter == 'C' ? "c" : "nc");
3f3556f1 2171 break;
2172 case GT:
2173 if (letter == 'z')
2174 fprintf (file, "#comparison eliminated");
2175 else
2ced756b 2176 fprintf (file, letter == 'C' ? "nh" : "h");
78e515f7 2177 break;
2178
2179 default:
2180 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
2181 break;
2182 }
2183}
2184
2185#undef TARGET_PRINT_OPERAND
2186#define TARGET_PRINT_OPERAND rl78_print_operand
2187
2188static void
2189rl78_print_operand (FILE * file, rtx op, int letter)
2190{
56df4a64 2191 if (CONSTANT_P (op) && letter != 'u' && letter != 's' && letter != 'r' && letter != 'S' && letter != 'B')
78e515f7 2192 fprintf (file, "#");
2193 rl78_print_operand_1 (file, op, letter);
2194}
2195
2196#undef TARGET_TRAMPOLINE_INIT
2197#define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
2198
2199/* Note that the RL78's addressing makes it very difficult to do
2200 trampolines on the stack. So, libgcc has a small pool of
2201 trampolines from which one is allocated to this task. */
2202static void
2203rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
2204{
2205 rtx mov_addr, thunk_addr;
2206 rtx function = XEXP (DECL_RTL (fndecl), 0);
2207
2208 mov_addr = adjust_address (m_tramp, HImode, 0);
2209 thunk_addr = gen_reg_rtx (HImode);
2210
2211 function = force_reg (HImode, function);
2212 static_chain = force_reg (HImode, static_chain);
2213
2214 emit_insn (gen_trampoline_init (thunk_addr, function, static_chain));
2215 emit_move_insn (mov_addr, thunk_addr);
2216
2217 cfun->machine->trampolines_used = 1;
2218}
2219
2220#undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
2221#define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
2222
2223static rtx
2224rl78_trampoline_adjust_address (rtx m_tramp)
2225{
2226 rtx x = gen_rtx_MEM (HImode, m_tramp);
2227 return x;
2228}
2229\f
2230/* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
2231 the "normal" compares, specifically, it only has unsigned compares,
2232 so we must synthesize the missing ones. */
2233void
2234rl78_expand_compare (rtx *operands)
2235{
3f3556f1 2236 if (GET_CODE (operands[2]) == MEM)
2237 operands[2] = copy_to_mode_reg (GET_MODE (operands[2]), operands[2]);
78e515f7 2238}
2239
2240\f
2241
2242/* Define this to 1 if you are debugging the peephole optimizers. */
2243#define DEBUG_PEEP 0
2244
2245/* Predicate used to enable the peephole2 patterns in rl78-virt.md.
2246 The default "word" size is a byte so we can effectively use all the
2247 registers, but we want to do 16-bit moves whenever possible. This
2248 function determines when such a move is an option. */
2249bool
2250rl78_peep_movhi_p (rtx *operands)
2251{
2252 int i;
2253 rtx m, a;
2254
2255 /* (set (op0) (op1))
2256 (set (op2) (op3)) */
2257
1d701d79 2258 if (! rl78_virt_insns_ok ())
2259 return false;
2260
78e515f7 2261#if DEBUG_PEEP
2262 fprintf (stderr, "\033[33m");
3f3556f1 2263 debug_rtx (operands[0]);
2264 debug_rtx (operands[1]);
2265 debug_rtx (operands[2]);
2266 debug_rtx (operands[3]);
78e515f7 2267 fprintf (stderr, "\033[0m");
2268#endif
2269
c5a0ae5e 2270 /* You can move a constant to memory as QImode, but not HImode. */
2271 if (GET_CODE (operands[0]) == MEM
2272 && GET_CODE (operands[1]) != REG)
2273 {
2274#if DEBUG_PEEP
2275 fprintf (stderr, "no peep: move constant to memory\n");
2276#endif
2277 return false;
2278 }
2279
78e515f7 2280 if (rtx_equal_p (operands[0], operands[3]))
2281 {
2282#if DEBUG_PEEP
2283 fprintf (stderr, "no peep: overlapping\n");
2284#endif
2285 return false;
2286 }
2287
2288 for (i = 0; i < 2; i ++)
2289 {
2290 if (GET_CODE (operands[i]) != GET_CODE (operands[i+2]))
2291 {
2292#if DEBUG_PEEP
2293 fprintf (stderr, "no peep: different codes\n");
2294#endif
2295 return false;
2296 }
2297 if (GET_MODE (operands[i]) != GET_MODE (operands[i+2]))
2298 {
2299#if DEBUG_PEEP
2300 fprintf (stderr, "no peep: different modes\n");
2301#endif
2302 return false;
2303 }
2304
2305 switch (GET_CODE (operands[i]))
2306 {
2307 case REG:
2308 /* LSB MSB */
2309 if (REGNO (operands[i]) + 1 != REGNO (operands[i+2])
2310 || GET_MODE (operands[i]) != QImode)
2311 {
2312#if DEBUG_PEEP
2313 fprintf (stderr, "no peep: wrong regnos %d %d %d\n",
2314 REGNO (operands[i]), REGNO (operands[i+2]),
2315 i);
2316#endif
2317 return false;
2318 }
2319 if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode))
2320 {
2321#if DEBUG_PEEP
2322 fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i]));
2323#endif
2324 return false;
2325 }
2326 break;
2327
2328 case CONST_INT:
2329 break;
2330
2331 case MEM:
2332 if (GET_MODE (operands[i]) != QImode)
2333 return false;
2334 if (MEM_ALIGN (operands[i]) < 16)
2335 return false;
2336 a = XEXP (operands[i], 0);
2337 if (GET_CODE (a) == CONST)
2338 a = XEXP (a, 0);
2339 if (GET_CODE (a) == PLUS)
2340 a = XEXP (a, 1);
2341 if (GET_CODE (a) == CONST_INT
2342 && INTVAL (a) & 1)
2343 {
2344#if DEBUG_PEEP
2345 fprintf (stderr, "no peep: misaligned mem %d\n", i);
2346 debug_rtx (operands[i]);
2347#endif
2348 return false;
2349 }
2350 m = adjust_address (operands[i], QImode, 1);
2351 if (! rtx_equal_p (m, operands[i+2]))
2352 {
2353#if DEBUG_PEEP
2354 fprintf (stderr, "no peep: wrong mem %d\n", i);
8a6bcd4e 2355 debug_rtx (m);
78e515f7 2356 debug_rtx (operands[i+2]);
2357#endif
2358 return false;
2359 }
2360 break;
2361
2362 default:
2363#if DEBUG_PEEP
2364 fprintf (stderr, "no peep: wrong rtx %d\n", i);
2365#endif
2366 return false;
2367 }
2368 }
2369#if DEBUG_PEEP
2370 fprintf (stderr, "\033[32mpeep!\033[0m\n");
2371#endif
2372 return true;
2373}
2374
2375/* Likewise, when a peephole is activated, this function helps compute
2376 the new operands. */
2377void
2378rl78_setup_peep_movhi (rtx *operands)
2379{
2380 int i;
2381
2382 for (i = 0; i < 2; i ++)
2383 {
2384 switch (GET_CODE (operands[i]))
2385 {
2386 case REG:
2387 operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i]));
2388 break;
2389
2390 case CONST_INT:
8a6bcd4e 2391 operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char) INTVAL (operands[i+2])) * 256);
78e515f7 2392 break;
2393
2394 case MEM:
2395 operands[i+4] = adjust_address (operands[i], HImode, 0);
2396 break;
2397
2398 default:
2399 break;
2400 }
2401 }
2402}
2403\f
2404/*
2405 How Devirtualization works in the RL78 GCC port
2406
2407Background
2408
2409The RL78 is an 8-bit port with some 16-bit operations. It has 32
2410bytes of register space, in four banks, memory-mapped. One bank is
2411the "selected" bank and holds the registers used for primary
2412operations. Since the registers are memory mapped, often you can
2413still refer to the unselected banks via memory accesses.
2414
2415Virtual Registers
2416
2417The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
2418and refers to the other banks via their memory addresses, although
2419they're treated as regular registers internally. These "virtual"
2420registers are R8 through R23 (bank3 is reserved for asm-based
2421interrupt handlers).
2422
2423There are four machine description files:
2424
2425rl78.md - common register-independent patterns and definitions
2426rl78-expand.md - expanders
2427rl78-virt.md - patterns that match BEFORE devirtualization
2428rl78-real.md - patterns that match AFTER devirtualization
2429
2430At least through register allocation and reload, gcc is told that it
2431can do pretty much anything - but may only use the virtual registers.
2432GCC cannot properly create the varying addressing modes that the RL78
2433supports in an efficient way.
2434
2435Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
2436uses the "valloc" attribute in rl78-virt.md for determining the rules
2437by which it will replace virtual registers with real registers (or
2438not) and how to make up addressing modes. For example, insns tagged
2439with "ro1" have a single read-only parameter, which may need to be
2440moved from memory/constant/vreg to a suitable real register. As part
2441of devirtualization, a flag is toggled, disabling the rl78-virt.md
2442patterns and enabling the rl78-real.md patterns. The new patterns'
2443constraints are used to determine the real registers used. NOTE:
2444patterns in rl78-virt.md essentially ignore the constrains and rely on
2445predicates, where the rl78-real.md ones essentially ignore the
2446predicates and rely on the constraints.
2447
2448The devirtualization pass is scheduled via the pass manager (despite
2449being called "rl78_reorg") so it can be scheduled prior to var-track
2450(the idea is to let gdb know about the new registers). Ideally, it
2451would be scheduled right after pro/epilogue generation, so the
2452post-reload optimizers could operate on the real registers, but when I
2453tried that there were some issues building the target libraries.
2454
2455During devirtualization, a simple register move optimizer is run. It
67d57e27 2456would be better to run a full CSE/propogation pass on it though, but
2457that has not yet been attempted.
78e515f7 2458
2459 */
2460#define DEBUG_ALLOC 0
2461
563dc27b 2462#define OP(x) (*recog_data.operand_loc[x])
2463
3f3556f1 2464/* This array is used to hold knowledge about the contents of the
2465 real registers (A ... H), the memory-based registers (r8 ... r31)
2466 and the first NUM_STACK_LOCS words on the stack. We use this to
2467 avoid generating redundant move instructions.
2468
2469 A value in the range 0 .. 31 indicates register A .. r31.
2470 A value in the range 32 .. 63 indicates stack slot (value - 32).
2471 A value of NOT_KNOWN indicates that the contents of that location
2472 are not known. */
2473
2474#define NUM_STACK_LOCS 32
2475#define NOT_KNOWN 127
2476
2477static unsigned char content_memory [32 + NUM_STACK_LOCS];
2478
2479static unsigned char saved_update_index = NOT_KNOWN;
2480static unsigned char saved_update_value;
3754d046 2481static machine_mode saved_update_mode;
3f3556f1 2482
2483
2484static inline void
2485clear_content_memory (void)
2486{
2487 memset (content_memory, NOT_KNOWN, sizeof content_memory);
2488 if (dump_file)
2489 fprintf (dump_file, " clear content memory\n");
2490 saved_update_index = NOT_KNOWN;
2491}
2492
2493/* Convert LOC into an index into the content_memory array.
2494 If LOC cannot be converted, return NOT_KNOWN. */
2495
2496static unsigned char
2497get_content_index (rtx loc)
2498{
3754d046 2499 machine_mode mode;
3f3556f1 2500
2501 if (loc == NULL_RTX)
2502 return NOT_KNOWN;
2503
2504 if (REG_P (loc))
2505 {
2506 if (REGNO (loc) < 32)
2507 return REGNO (loc);
2508 return NOT_KNOWN;
2509 }
2510
2511 mode = GET_MODE (loc);
2512
2513 if (! rl78_stack_based_mem (loc, mode))
2514 return NOT_KNOWN;
2515
2516 loc = XEXP (loc, 0);
2517
2518 if (REG_P (loc))
2519 /* loc = MEM (SP) */
2520 return 32;
2521
2522 /* loc = MEM (PLUS (SP, INT)). */
2523 loc = XEXP (loc, 1);
2524
2525 if (INTVAL (loc) < NUM_STACK_LOCS)
2526 return 32 + INTVAL (loc);
2527
2528 return NOT_KNOWN;
2529}
2530
2531/* Return a string describing content INDEX in mode MODE.
2532 WARNING: Can return a pointer to a static buffer. */
3f3556f1 2533static const char *
3754d046 2534get_content_name (unsigned char index, machine_mode mode)
3f3556f1 2535{
2536 static char buffer [128];
2537
2538 if (index == NOT_KNOWN)
2539 return "Unknown";
2540
2541 if (index > 31)
2542 sprintf (buffer, "stack slot %d", index - 32);
2543 else if (mode == HImode)
2544 sprintf (buffer, "%s%s",
2545 reg_names [index + 1], reg_names [index]);
2546 else
2547 return reg_names [index];
2548
2549 return buffer;
2550}
2551
2552#if DEBUG_ALLOC
2553
2554static void
2555display_content_memory (FILE * file)
2556{
2557 unsigned int i;
2558
2559 fprintf (file, " Known memory contents:\n");
2560
2561 for (i = 0; i < sizeof content_memory; i++)
2562 if (content_memory[i] != NOT_KNOWN)
2563 {
2564 fprintf (file, " %s contains a copy of ", get_content_name (i, QImode));
2565 fprintf (file, "%s\n", get_content_name (content_memory [i], QImode));
2566 }
2567}
2568#endif
2569
2570static void
3754d046 2571update_content (unsigned char index, unsigned char val, machine_mode mode)
3f3556f1 2572{
2573 unsigned int i;
2574
2575 gcc_assert (index < sizeof content_memory);
2576
2577 content_memory [index] = val;
2578 if (val != NOT_KNOWN)
2579 content_memory [val] = index;
2580
2581 /* Make the entry in dump_file *before* VAL is increased below. */
2582 if (dump_file)
2583 {
2584 fprintf (dump_file, " %s now contains ", get_content_name (index, mode));
2585 if (val == NOT_KNOWN)
2586 fprintf (dump_file, "Unknown\n");
2587 else
2588 fprintf (dump_file, "%s and vice versa\n", get_content_name (val, mode));
2589 }
8a6bcd4e 2590
3f3556f1 2591 if (mode == HImode)
2592 {
2593 val = val == NOT_KNOWN ? val : val + 1;
2594
2595 content_memory [index + 1] = val;
2596 if (val != NOT_KNOWN)
2597 {
2598 content_memory [val] = index + 1;
2599 -- val;
2600 }
2601 }
2602
2603 /* Any other places that had INDEX recorded as their contents are now invalid. */
2604 for (i = 0; i < sizeof content_memory; i++)
2605 {
2606 if (i == index
2607 || (val != NOT_KNOWN && i == val))
2608 {
2609 if (mode == HImode)
2610 ++ i;
2611 continue;
2612 }
8a6bcd4e 2613
3f3556f1 2614 if (content_memory[i] == index
2615 || (val != NOT_KNOWN && content_memory[i] == val))
2616 {
2617 content_memory[i] = NOT_KNOWN;
2618
2619 if (dump_file)
2620 fprintf (dump_file, " %s cleared\n", get_content_name (i, mode));
2621
2622 if (mode == HImode)
2623 content_memory[++ i] = NOT_KNOWN;
2624 }
2625 }
2626}
2627
2628/* Record that LOC contains VALUE.
2629 For HImode locations record that LOC+1 contains VALUE+1.
2630 If LOC is not a register or stack slot, do nothing.
2631 If VALUE is not a register or stack slot, clear the recorded content. */
2632
2633static void
2634record_content (rtx loc, rtx value)
2635{
3754d046 2636 machine_mode mode;
3f3556f1 2637 unsigned char index;
2638 unsigned char val;
2639
2640 if ((index = get_content_index (loc)) == NOT_KNOWN)
2641 return;
2642
2643 val = get_content_index (value);
2644
2645 mode = GET_MODE (loc);
2646
2647 if (val == index)
2648 {
2649 if (! optimize)
2650 return;
2651
2652 /* This should not happen when optimizing. */
2653#if 1
2654 fprintf (stderr, "ASSIGNMENT of location to itself detected! [%s]\n",
2655 get_content_name (val, mode));
2656 return;
2657#else
2658 gcc_unreachable ();
2659#endif
2660 }
2661
2662 update_content (index, val, mode);
2663}
2664
2665/* Returns TRUE if LOC already contains a copy of VALUE. */
2666
2667static bool
2668already_contains (rtx loc, rtx value)
2669{
2670 unsigned char index;
2671 unsigned char val;
2672
2673 if ((index = get_content_index (loc)) == NOT_KNOWN)
2674 return false;
2675
2676 if ((val = get_content_index (value)) == NOT_KNOWN)
2677 return false;
2678
2679 if (content_memory [index] != val)
2680 return false;
2681
2682 if (GET_MODE (loc) == HImode)
2683 return content_memory [index + 1] == val + 1;
2684
2685 return true;
2686}
2687
563dc27b 2688bool
2689rl78_es_addr (rtx addr)
2690{
2691 if (GET_CODE (addr) == MEM)
2692 addr = XEXP (addr, 0);
2693 if (GET_CODE (addr) != UNSPEC)
2694 return false;
2695 if (XINT (addr, 1) != UNS_ES_ADDR)
2696 return false;
2697 return true;
2698}
2699
2700rtx
2701rl78_es_base (rtx addr)
2702{
2703 if (GET_CODE (addr) == MEM)
2704 addr = XEXP (addr, 0);
2705 addr = XVECEXP (addr, 0, 1);
2706 if (GET_CODE (addr) == CONST
2707 && GET_CODE (XEXP (addr, 0)) == ZERO_EXTRACT)
2708 addr = XEXP (XEXP (addr, 0), 0);
2709 /* Mode doesn't matter here. */
2710 return gen_rtx_MEM (HImode, addr);
2711}
2712
78e515f7 2713/* Rescans an insn to see if it's recognized again. This is done
2714 carefully to ensure that all the constraint information is accurate
2715 for the newly matched insn. */
2716static bool
93e93552 2717insn_ok_now (rtx_insn * insn)
78e515f7 2718{
3f3556f1 2719 rtx pattern = PATTERN (insn);
563dc27b 2720 int i;
3f3556f1 2721
78e515f7 2722 INSN_CODE (insn) = -1;
3f3556f1 2723
2724 if (recog (pattern, insn, 0) > -1)
78e515f7 2725 {
2726 extract_insn (insn);
e2f730a9 2727 if (constrain_operands (1, get_preferred_alternatives (insn)))
78e515f7 2728 {
2729#if DEBUG_ALLOC
2730 fprintf (stderr, "\033[32m");
2731 debug_rtx (insn);
2732 fprintf (stderr, "\033[0m");
2733#endif
3f3556f1 2734 if (SET_P (pattern))
2735 record_content (SET_DEST (pattern), SET_SRC (pattern));
2736
563dc27b 2737 /* We need to detect far addresses that haven't been
2738 converted to es/lo16 format. */
2739 for (i=0; i<recog_data.n_operands; i++)
1d701d79 2740 if (GET_CODE (OP (i)) == MEM
2741 && GET_MODE (XEXP (OP (i), 0)) == SImode
2742 && GET_CODE (XEXP (OP (i), 0)) != UNSPEC)
783c08c7 2743 goto not_ok;
563dc27b 2744
78e515f7 2745 return true;
2746 }
2747 }
3f3556f1 2748
783c08c7 2749 /* INSN is not OK as-is. It may not be recognized in real mode or
2750 it might not have satisfied its constraints in real mode. Either
2751 way it will require fixups.
2752
2753 It is vital we always re-recognize at this point as some insns
2754 have fewer operands in real mode than virtual mode. If we do
2755 not re-recognize, then the recog_data will refer to real mode
2756 operands and we may read invalid data. Usually this isn't a
2757 problem, but once in a while the data we read is bogus enough
2758 to cause a segfault or other undesirable behavior. */
2759 not_ok:
2760
2761 /* We need to re-recog the insn with virtual registers to get
2762 the operands. */
2763 INSN_CODE (insn) = -1;
2764 cfun->machine->virt_insns_ok = 1;
2765 if (recog (pattern, insn, 0) > -1)
2766 {
2767 extract_insn (insn);
2768 /* In theory this should always be true. */
2769 if (constrain_operands (0, get_preferred_alternatives (insn)))
2770 {
2771 cfun->machine->virt_insns_ok = 0;
2772 return false;
2773 }
2774 }
3f3556f1 2775
78e515f7 2776#if DEBUG_ALLOC
783c08c7 2777 fprintf (stderr, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
78e515f7 2778 debug_rtx (insn);
78e515f7 2779#endif
783c08c7 2780 gcc_unreachable ();
78e515f7 2781 return false;
2782}
2783
2784#if DEBUG_ALLOC
3f3556f1 2785#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
78e515f7 2786#define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
93e93552 2787#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
78e515f7 2788#define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
3f3556f1 2789#define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
78e515f7 2790#else
78e515f7 2791#define FAILED gcc_unreachable ()
2792#define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
3f3556f1 2793#define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
78e515f7 2794#endif
2795
2796/* Registers into which we move the contents of virtual registers. */
1d701d79 2797#define X gen_rtx_REG (QImode, X_REG)
2798#define A gen_rtx_REG (QImode, A_REG)
2799#define C gen_rtx_REG (QImode, C_REG)
2800#define B gen_rtx_REG (QImode, B_REG)
2801#define E gen_rtx_REG (QImode, E_REG)
2802#define D gen_rtx_REG (QImode, D_REG)
2803#define L gen_rtx_REG (QImode, L_REG)
2804#define H gen_rtx_REG (QImode, H_REG)
2805
2806#define AX gen_rtx_REG (HImode, AX_REG)
2807#define BC gen_rtx_REG (HImode, BC_REG)
2808#define DE gen_rtx_REG (HImode, DE_REG)
2809#define HL gen_rtx_REG (HImode, HL_REG)
78e515f7 2810
78e515f7 2811/* Returns TRUE if R is a virtual register. */
1d701d79 2812static inline bool
78e515f7 2813is_virtual_register (rtx r)
2814{
2815 return (GET_CODE (r) == REG
2816 && REGNO (r) >= 8
55ea1438 2817 && REGNO (r) < 32);
78e515f7 2818}
2819
2820/* In all these alloc routines, we expect the following: the insn
2821 pattern is unshared, the insn was previously recognized and failed
2822 due to predicates or constraints, and the operand data is in
2823 recog_data. */
2824
2825static int virt_insn_was_frame;
2826
2827/* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2828 needed. */
2829static rtx
2830EM2 (int line ATTRIBUTE_UNUSED, rtx r)
2831{
2832#if DEBUG_ALLOC
2833 fprintf (stderr, "\033[36m%d: ", line);
8a6bcd4e 2834 debug_rtx (r);
78e515f7 2835 fprintf (stderr, "\033[0m");
2836#endif
2837 /*SCHED_GROUP_P (r) = 1;*/
2838 if (virt_insn_was_frame)
2839 RTX_FRAME_RELATED_P (r) = 1;
2840 return r;
2841}
2842
2843#define EM(x) EM2 (__LINE__, x)
2844
2845/* Return a suitable RTX for the low half of a __far address. */
2846static rtx
2847rl78_lo16 (rtx addr)
2848{
563dc27b 2849 rtx r;
2850
78e515f7 2851 if (GET_CODE (addr) == SYMBOL_REF
2852 || GET_CODE (addr) == CONST)
2853 {
563dc27b 2854 r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0));
78e515f7 2855 r = gen_rtx_CONST (HImode, r);
78e515f7 2856 }
563dc27b 2857 else
2858 r = rl78_subreg (HImode, addr, SImode, 0);
2859
2860 r = gen_es_addr (r);
93e93552 2861 cfun->machine->uses_es = true;
563dc27b 2862
2863 return r;
78e515f7 2864}
2865
2866/* Return a suitable RTX for the high half's lower byte of a __far address. */
2867static rtx
2868rl78_hi8 (rtx addr)
2869{
2870 if (GET_CODE (addr) == SYMBOL_REF
2871 || GET_CODE (addr) == CONST)
2872 {
2873 rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16));
2874 r = gen_rtx_CONST (QImode, r);
2875 return r;
2876 }
2877 return rl78_subreg (QImode, addr, SImode, 2);
2878}
2879
3f3556f1 2880static void
2881add_postponed_content_update (rtx to, rtx value)
2882{
2883 unsigned char index;
2884
2885 if ((index = get_content_index (to)) == NOT_KNOWN)
2886 return;
2887
2888 gcc_assert (saved_update_index == NOT_KNOWN);
2889 saved_update_index = index;
2890 saved_update_value = get_content_index (value);
2891 saved_update_mode = GET_MODE (to);
2892}
2893
2894static void
2895process_postponed_content_update (void)
2896{
2897 if (saved_update_index != NOT_KNOWN)
2898 {
2899 update_content (saved_update_index, saved_update_value, saved_update_mode);
2900 saved_update_index = NOT_KNOWN;
2901 }
2902}
2903
2904/* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2905 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2906 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2907 BEFORE is true, FROM otherwise. */
2908static rtx
b977a85a 2909gen_and_emit_move (rtx to, rtx from, rtx_insn *where, bool before)
3f3556f1 2910{
3754d046 2911 machine_mode mode = GET_MODE (to);
3f3556f1 2912
2913 if (optimize && before && already_contains (to, from))
2914 {
2915#if DEBUG_ALLOC
2916 display_content_memory (stderr);
2917#endif
2918 if (dump_file)
2919 {
2920 fprintf (dump_file, " Omit move of %s into ",
2921 get_content_name (get_content_index (from), mode));
2922 fprintf (dump_file, "%s as it already contains this value\n",
2923 get_content_name (get_content_index (to), mode));
2924 }
2925 }
2926 else
2927 {
2928 rtx move = mode == QImode ? gen_movqi (to, from) : gen_movhi (to, from);
8a6bcd4e 2929
3f3556f1 2930 EM (move);
2931
2932 if (where == NULL_RTX)
2933 emit_insn (move);
2934 else if (before)
2935 emit_insn_before (move, where);
2936 else
2937 {
2938 rtx note = find_reg_note (where, REG_EH_REGION, NULL_RTX);
2939
2940 /* If necessary move REG_EH_REGION notes forward.
2941 cf. compiling gcc.dg/pr44545.c. */
2942 if (note != NULL_RTX)
2943 {
2944 add_reg_note (move, REG_EH_REGION, XEXP (note, 0));
2945 remove_note (where, note);
2946 }
2947
2948 emit_insn_after (move, where);
2949 }
2950
2951 if (before)
2952 record_content (to, from);
2953 else
2954 add_postponed_content_update (to, from);
2955 }
1d701d79 2956
3f3556f1 2957 return before ? to : from;
2958}
2959
2960/* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2961 copy it into NEWBASE and return the updated MEM. Otherwise just
2962 return M. Any needed insns are emitted before BEFORE. */
78e515f7 2963static rtx
b977a85a 2964transcode_memory_rtx (rtx m, rtx newbase, rtx_insn *before)
78e515f7 2965{
2966 rtx base, index, addendr;
2967 int addend = 0;
563dc27b 2968 int need_es = 0;
78e515f7 2969
3f3556f1 2970 if (! MEM_P (m))
78e515f7 2971 return m;
2972
2973 if (GET_MODE (XEXP (m, 0)) == SImode)
2974 {
1d701d79 2975 rtx new_m;
78e515f7 2976 rtx seg = rl78_hi8 (XEXP (m, 0));
1d701d79 2977
0c5d0bfa 2978 if (!TARGET_ES0)
2979 {
2980 emit_insn_before (EM (gen_movqi (A, seg)), before);
2981 emit_insn_before (EM (gen_movqi_to_es (A)), before);
2982 }
2983
3f3556f1 2984 record_content (A, NULL_RTX);
2985
1d701d79 2986 new_m = gen_rtx_MEM (GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
2987 MEM_COPY_ATTRIBUTES (new_m, m);
2988 m = new_m;
563dc27b 2989 need_es = 1;
78e515f7 2990 }
2991
3f3556f1 2992 characterize_address (XEXP (m, 0), & base, & index, & addendr);
78e515f7 2993 gcc_assert (index == NULL_RTX);
2994
78e515f7 2995 if (base == NULL_RTX)
2996 return m;
2997
2998 if (addendr && GET_CODE (addendr) == CONST_INT)
2999 addend = INTVAL (addendr);
3000
3f3556f1 3001 gcc_assert (REG_P (base));
3002 gcc_assert (REG_P (newbase));
3003
0c5d0bfa 3004 int limit = 256 - GET_MODE_SIZE (GET_MODE (m));
3005
78e515f7 3006 if (REGNO (base) == SP_REG)
3007 {
889a65e7 3008 if (addend >= 0 && addend <= limit)
78e515f7 3009 return m;
3010 }
3011
3012 /* BASE should be a virtual register. We copy it to NEWBASE. If
3013 the addend is out of range for DE/HL, we use AX to compute the full
3014 address. */
3015
3016 if (addend < 0
0c5d0bfa 3017 || (addend > limit && REGNO (newbase) != BC_REG)
3018 || (addendr
3019 && (GET_CODE (addendr) != CONST_INT)
3020 && ((REGNO (newbase) != BC_REG))
3021 ))
78e515f7 3022 {
3023 /* mov ax, vreg
3024 add ax, #imm
3025 mov hl, ax */
3026 EM (emit_insn_before (gen_movhi (AX, base), before));
3027 EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before));
3028 EM (emit_insn_before (gen_movhi (newbase, AX), before));
3f3556f1 3029 record_content (AX, NULL_RTX);
3030 record_content (newbase, NULL_RTX);
3031
78e515f7 3032 base = newbase;
3033 addend = 0;
0c5d0bfa 3034 addendr = 0;
78e515f7 3035 }
3036 else
3037 {
3f3556f1 3038 base = gen_and_emit_move (newbase, base, before, true);
78e515f7 3039 }
3040
3041 if (addend)
3f3556f1 3042 {
3043 record_content (base, NULL_RTX);
3044 base = gen_rtx_PLUS (HImode, base, GEN_INT (addend));
3045 }
0c5d0bfa 3046 else if (addendr)
3047 {
3048 record_content (base, NULL_RTX);
3049 base = gen_rtx_PLUS (HImode, base, addendr);
3050 }
78e515f7 3051
563dc27b 3052 if (need_es)
93e93552 3053 {
3054 m = change_address (m, GET_MODE (m), gen_es_addr (base));
3055 cfun->machine->uses_es = true;
3056 }
563dc27b 3057 else
3058 m = change_address (m, GET_MODE (m), base);
78e515f7 3059 return m;
3060}
3061
3062/* Copy SRC to accumulator (A or AX), placing any generated insns
3063 before BEFORE. Returns accumulator RTX. */
78e515f7 3064static rtx
b977a85a 3065move_to_acc (int opno, rtx_insn *before)
78e515f7 3066{
3f3556f1 3067 rtx src = OP (opno);
3754d046 3068 machine_mode mode = GET_MODE (src);
78e515f7 3069
3f3556f1 3070 if (REG_P (src) && REGNO (src) < 2)
78e515f7 3071 return src;
3072
3073 if (mode == VOIDmode)
3074 mode = recog_data.operand_mode[opno];
3075
3f3556f1 3076 return gen_and_emit_move (mode == QImode ? A : AX, src, before, true);
3077}
3078
3079static void
db7dd023 3080force_into_acc (rtx src, rtx_insn *before)
3f3556f1 3081{
3754d046 3082 machine_mode mode = GET_MODE (src);
3f3556f1 3083 rtx move;
3084
3085 if (REG_P (src) && REGNO (src) < 2)
3086 return;
3087
3088 move = mode == QImode ? gen_movqi (A, src) : gen_movhi (AX, src);
8a6bcd4e 3089
3f3556f1 3090 EM (move);
3091
3092 emit_insn_before (move, before);
3093 record_content (AX, NULL_RTX);
78e515f7 3094}
3095
3096/* Copy accumulator (A or AX) to DEST, placing any generated insns
3097 after AFTER. Returns accumulator RTX. */
78e515f7 3098static rtx
b977a85a 3099move_from_acc (unsigned int opno, rtx_insn *after)
78e515f7 3100{
3f3556f1 3101 rtx dest = OP (opno);
3754d046 3102 machine_mode mode = GET_MODE (dest);
78e515f7 3103
3104 if (REG_P (dest) && REGNO (dest) < 2)
3105 return dest;
3106
3f3556f1 3107 return gen_and_emit_move (dest, mode == QImode ? A : AX, after, false);
78e515f7 3108}
3109
3110/* Copy accumulator (A or AX) to REGNO, placing any generated insns
3111 before BEFORE. Returns reg RTX. */
78e515f7 3112static rtx
b977a85a 3113move_acc_to_reg (rtx acc, int regno, rtx_insn *before)
78e515f7 3114{
3754d046 3115 machine_mode mode = GET_MODE (acc);
78e515f7 3116 rtx reg;
3117
3118 reg = gen_rtx_REG (mode, regno);
3119
3f3556f1 3120 return gen_and_emit_move (reg, acc, before, true);
78e515f7 3121}
3122
3123/* Copy SRC to X, placing any generated insns before BEFORE.
3124 Returns X RTX. */
78e515f7 3125static rtx
b977a85a 3126move_to_x (int opno, rtx_insn *before)
78e515f7 3127{
3f3556f1 3128 rtx src = OP (opno);
3754d046 3129 machine_mode mode = GET_MODE (src);
78e515f7 3130 rtx reg;
3131
3132 if (mode == VOIDmode)
3133 mode = recog_data.operand_mode[opno];
3134 reg = (mode == QImode) ? X : AX;
3135
3136 if (mode == QImode || ! is_virtual_register (OP (opno)))
3137 {
3f3556f1 3138 OP (opno) = move_to_acc (opno, before);
1d701d79 3139 OP (opno) = move_acc_to_reg (OP (opno), X_REG, before);
78e515f7 3140 return reg;
3141 }
3142
3f3556f1 3143 return gen_and_emit_move (reg, src, before, true);
78e515f7 3144}
3145
1d701d79 3146/* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
78e515f7 3147 Returns H/HL RTX. */
78e515f7 3148static rtx
b977a85a 3149move_to_hl (int opno, rtx_insn *before)
78e515f7 3150{
3151 rtx src = OP (opno);
3754d046 3152 machine_mode mode = GET_MODE (src);
78e515f7 3153 rtx reg;
3154
3155 if (mode == VOIDmode)
3156 mode = recog_data.operand_mode[opno];
3157 reg = (mode == QImode) ? L : HL;
3158
3159 if (mode == QImode || ! is_virtual_register (OP (opno)))
3160 {
3161 OP (opno) = move_to_acc (opno, before);
3162 OP (opno) = move_acc_to_reg (OP (opno), L_REG, before);
3163 return reg;
3164 }
3165
3f3556f1 3166 return gen_and_emit_move (reg, src, before, true);
78e515f7 3167}
3168
1d701d79 3169/* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
78e515f7 3170 Returns E/DE RTX. */
78e515f7 3171static rtx
b977a85a 3172move_to_de (int opno, rtx_insn *before)
78e515f7 3173{
3174 rtx src = OP (opno);
3754d046 3175 machine_mode mode = GET_MODE (src);
78e515f7 3176 rtx reg;
3177
3178 if (mode == VOIDmode)
3179 mode = recog_data.operand_mode[opno];
3180
3181 reg = (mode == QImode) ? E : DE;
3182
3183 if (mode == QImode || ! is_virtual_register (OP (opno)))
3184 {
3185 OP (opno) = move_to_acc (opno, before);
3186 OP (opno) = move_acc_to_reg (OP (opno), E_REG, before);
3187 }
3188 else
3189 {
3f3556f1 3190 gen_and_emit_move (reg, src, before, true);
78e515f7 3191 }
3192
3193 return reg;
3194}
3195
3196/* Devirtualize an insn of the form (SET (op) (unop (op))). */
3197static void
93e93552 3198rl78_alloc_physical_registers_op1 (rtx_insn * insn)
78e515f7 3199{
3200 /* op[0] = func op[1] */
3201
3202 /* We first try using A as the destination, then copying it
3203 back. */
3f3556f1 3204 if (rtx_equal_p (OP (0), OP (1)))
78e515f7 3205 {
3f3556f1 3206 OP (0) =
3207 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
78e515f7 3208 }
3209 else
3210 {
3f3556f1 3211 /* If necessary, load the operands into BC and HL.
3212 Check to see if we already have OP (0) in HL
0c5d0bfa 3213 and if so, swap the order.
3214
3215 It is tempting to perform this optimization when OP(0) does
3216 not hold a MEM, but this leads to bigger code in general.
3217 The problem is that if OP(1) holds a MEM then swapping it
889a65e7 3218 into BC means a BC-relative load is used and these are 3
3219 bytes long vs 1 byte for an HL load. */
3f3556f1 3220 if (MEM_P (OP (0))
3221 && already_contains (HL, XEXP (OP (0), 0)))
3222 {
3223 OP (0) = transcode_memory_rtx (OP (0), HL, insn);
3224 OP (1) = transcode_memory_rtx (OP (1), BC, insn);
3225 }
3226 else
3227 {
3228 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3229 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
3230 }
78e515f7 3231 }
3232
3233 MAYBE_OK (insn);
3234
3f3556f1 3235 OP (0) = move_from_acc (0, insn);
78e515f7 3236
3237 MAYBE_OK (insn);
3238
3239 /* Try copying the src to acc first, then. This is for, for
3240 example, ZERO_EXTEND or NOT. */
3f3556f1 3241 OP (1) = move_to_acc (1, insn);
78e515f7 3242
3f3556f1 3243 MUST_BE_OK (insn);
3244}
3245
3246/* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
3247 Assumes that the current insn has already been recognised and hence the
3248 constraint data has been filled in. */
3249static bool
3250has_constraint (unsigned int opnum, enum constraint_num constraint)
3251{
3252 const char * p = recog_data.constraints[opnum];
3253
3254 /* No constraints means anything is accepted. */
3255 if (p == NULL || *p == 0 || *p == ',')
3256 return true;
8a6bcd4e 3257
3f3556f1 3258 do
3259 {
3260 char c;
3261 unsigned int len;
78e515f7 3262
3f3556f1 3263 c = *p;
3264 len = CONSTRAINT_LEN (c, p);
3265 gcc_assert (len > 0);
3266
3267 switch (c)
3268 {
3269 case 0:
3270 case ',':
3271 return false;
3272 default:
3273 if (lookup_constraint (p) == constraint)
3274 return true;
3275 }
3276 p += len;
3277 }
3278 while (1);
78e515f7 3279}
3280
3f3556f1 3281/* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
78e515f7 3282static void
93e93552 3283rl78_alloc_physical_registers_op2 (rtx_insn * insn)
78e515f7 3284{
56d95ea5 3285 rtx_insn *prev;
3286 rtx_insn *first;
78e515f7 3287 bool hl_used;
3f3556f1 3288 int tmp_id;
3289 rtx saved_op1;
78e515f7 3290
3f3556f1 3291 if (rtx_equal_p (OP (0), OP (1)))
78e515f7 3292 {
750dcfc5 3293 if (MEM_P (OP (2)))
3294 {
3295 OP (0) =
3296 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3297 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
3298 }
3299 else
3300 {
3301 OP (0) =
3302 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
3303 OP (2) = transcode_memory_rtx (OP (2), DE, insn);
3304 }
78e515f7 3305 }
3f3556f1 3306 else if (rtx_equal_p (OP (0), OP (2)))
78e515f7 3307 {
3f3556f1 3308 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3309 OP (0) =
3310 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3311 }
3312 else
3313 {
3f3556f1 3314 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3315 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3316 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3317 }
3318
3319 MAYBE_OK (insn);
3320
3321 prev = prev_nonnote_nondebug_insn (insn);
3322 if (recog_data.constraints[1][0] == '%'
3323 && is_virtual_register (OP (1))
3324 && ! is_virtual_register (OP (2))
3325 && ! CONSTANT_P (OP (2)))
3326 {
3327 rtx tmp = OP (1);
3328 OP (1) = OP (2);
3329 OP (2) = tmp;
3330 }
3331
3f3556f1 3332 /* Make a note of whether (H)L is being used. It matters
8a6bcd4e 3333 because if OP (2) also needs reloading, then we must take
78e515f7 3334 care not to corrupt HL. */
3335 hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1));
3336
3f3556f1 3337 /* If HL is not currently being used and dest == op1 then there are
3338 some possible optimizations available by reloading one of the
3339 operands into HL, before trying to use the accumulator. */
3340 if (optimize
3341 && ! hl_used
3342 && rtx_equal_p (OP (0), OP (1)))
3343 {
3344 /* If op0 is a Ws1 type memory address then switching the base
3345 address register to HL might allow us to perform an in-memory
3346 operation. (eg for the INCW instruction).
8a6bcd4e 3347
3f3556f1 3348 FIXME: Adding the move into HL is costly if this optimization is not
3349 going to work, so for now, make sure that we know that the new insn will
3350 match the requirements of the addhi3_real pattern. Really we ought to
3351 generate a candidate sequence, test that, and then install it if the
3352 results are good. */
3353 if (satisfies_constraint_Ws1 (OP (0))
3354 && has_constraint (0, CONSTRAINT_Wh1)
3355 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
3356 {
3357 rtx base, index, addend, newbase;
3358
3359 characterize_address (XEXP (OP (0), 0), & base, & index, & addend);
3360 gcc_assert (index == NULL_RTX);
3361 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
3362
3363 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3364 if (addend != NULL_RTX)
3365 {
3366 newbase = gen_and_emit_move (HL, base, insn, true);
3367 record_content (newbase, NULL_RTX);
3368 newbase = gen_rtx_PLUS (HImode, newbase, addend);
8a6bcd4e 3369
3f3556f1 3370 OP (0) = OP (1) = change_address (OP (0), VOIDmode, newbase);
3371
3372 /* We do not want to fail here as this means that
3373 we have inserted useless insns into the stream. */
3374 MUST_BE_OK (insn);
3375 }
3376 }
3377 else if (REG_P (OP (0))
3378 && satisfies_constraint_Ws1 (OP (2))
3379 && has_constraint (2, CONSTRAINT_Wh1))
3380 {
3381 rtx base, index, addend, newbase;
3382
3383 characterize_address (XEXP (OP (2), 0), & base, & index, & addend);
3384 gcc_assert (index == NULL_RTX);
3385 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
3386
3387 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3388 if (addend != NULL_RTX)
3389 {
3390 gen_and_emit_move (HL, base, insn, true);
3391
3392 if (REGNO (OP (0)) != X_REG)
3393 {
3394 OP (1) = move_to_acc (1, insn);
3395 OP (0) = move_from_acc (0, insn);
3396 }
3397
3398 record_content (HL, NULL_RTX);
3399 newbase = gen_rtx_PLUS (HImode, HL, addend);
8a6bcd4e 3400
3f3556f1 3401 OP (2) = change_address (OP (2), VOIDmode, newbase);
3402
3403 /* We do not want to fail here as this means that
3404 we have inserted useless insns into the stream. */
3405 MUST_BE_OK (insn);
3406 }
3407 }
3408 }
3409
3f3556f1 3410 OP (0) = move_from_acc (0, insn);
3411
3412 tmp_id = get_max_insn_count ();
3413 saved_op1 = OP (1);
3414
3415 if (rtx_equal_p (OP (1), OP (2)))
3416 OP (2) = OP (1) = move_to_acc (1, insn);
3417 else
3418 OP (1) = move_to_acc (1, insn);
78e515f7 3419
3420 MAYBE_OK (insn);
3421
3f3556f1 3422 /* If we omitted the move of OP1 into the accumulator (because
3423 it was already there from a previous insn), then force the
3424 generation of the move instruction now. We know that we
3425 are about to emit a move into HL (or DE) via AX, and hence
3426 our optimization to remove the load of OP1 is no longer valid. */
3427 if (tmp_id == get_max_insn_count ())
3428 force_into_acc (saved_op1, insn);
3429
3430 /* We have to copy op2 to HL (or DE), but that involves AX, which
78e515f7 3431 already has a live value. Emit it before those insns. */
3432
3433 if (prev)
3434 first = next_nonnote_nondebug_insn (prev);
3435 else
3436 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3437 ;
3438
3439 OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first);
8a6bcd4e 3440
3f3556f1 3441 MUST_BE_OK (insn);
78e515f7 3442}
3443
3f3556f1 3444/* Devirtualize an insn of the form SET (PC) (MEM/REG). */
78e515f7 3445static void
93e93552 3446rl78_alloc_physical_registers_ro1 (rtx_insn * insn)
78e515f7 3447{
3f3556f1 3448 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
78e515f7 3449
3450 MAYBE_OK (insn);
3451
3f3556f1 3452 OP (0) = move_to_acc (0, insn);
78e515f7 3453
3f3556f1 3454 MUST_BE_OK (insn);
78e515f7 3455}
3456
3457/* Devirtualize a compare insn. */
3458static void
93e93552 3459rl78_alloc_physical_registers_cmp (rtx_insn * insn)
78e515f7 3460{
3f3556f1 3461 int tmp_id;
3462 rtx saved_op1;
bf79ca12 3463 rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
56d95ea5 3464 rtx_insn *first;
78e515f7 3465
3f3556f1 3466 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3467 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3468
1d701d79 3469 /* HI compares have to have OP (1) in AX, but QI
3f3556f1 3470 compares do not, so it is worth checking here. */
78e515f7 3471 MAYBE_OK (insn);
3472
1d701d79 3473 /* For an HImode compare, OP (1) must always be in AX.
3474 But if OP (1) is a REG (and not AX), then we can avoid
3475 a reload of OP (1) if we reload OP (2) into AX and invert
3f3556f1 3476 the comparison. */
3477 if (REG_P (OP (1))
3478 && REGNO (OP (1)) != AX_REG
3479 && GET_MODE (OP (1)) == HImode
3480 && MEM_P (OP (2)))
3481 {
3482 rtx cmp = XEXP (SET_SRC (PATTERN (insn)), 0);
3483
3484 OP (2) = move_to_acc (2, insn);
3485
3486 switch (GET_CODE (cmp))
3487 {
3488 case EQ:
3489 case NE:
3490 break;
3491 case LTU: cmp = gen_rtx_GTU (HImode, OP (2), OP (1)); break;
3492 case GTU: cmp = gen_rtx_LTU (HImode, OP (2), OP (1)); break;
3493 case LEU: cmp = gen_rtx_GEU (HImode, OP (2), OP (1)); break;
3494 case GEU: cmp = gen_rtx_LEU (HImode, OP (2), OP (1)); break;
3495
3496 case LT:
3497 case GT:
3498 case LE:
3499 case GE:
3500#if DEBUG_ALLOC
3501 debug_rtx (insn);
3502#endif
3503 default:
3504 gcc_unreachable ();
3505 }
8a6bcd4e 3506
3f3556f1 3507 if (GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE)
3508 PATTERN (insn) = gen_cbranchhi4_real (cmp, OP (2), OP (1), OP (3));
3509 else
3510 PATTERN (insn) = gen_cbranchhi4_real_inverted (cmp, OP (2), OP (1), OP (3));
3511
3512 MUST_BE_OK (insn);
3513 }
3514
3515 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
3516 should be handled by the second alternative of the cbranchhi_real pattern. */
3517 if (rtx_equal_p (OP (1), OP (2)))
3518 {
3519 OP (1) = OP (2) = BC;
3520 MUST_BE_OK (insn);
3521 }
8a6bcd4e 3522
3f3556f1 3523 tmp_id = get_max_insn_count ();
3524 saved_op1 = OP (1);
3525
3526 OP (1) = move_to_acc (1, insn);
78e515f7 3527
3528 MAYBE_OK (insn);
3529
3f3556f1 3530 /* If we omitted the move of OP1 into the accumulator (because
3531 it was already there from a previous insn), then force the
3532 generation of the move instruction now. We know that we
3533 are about to emit a move into HL via AX, and hence our
3534 optimization to remove the load of OP1 is no longer valid. */
3535 if (tmp_id == get_max_insn_count ())
3536 force_into_acc (saved_op1, insn);
3537
78e515f7 3538 /* We have to copy op2 to HL, but that involves the acc, which
3539 already has a live value. Emit it before those insns. */
78e515f7 3540 if (prev)
3541 first = next_nonnote_nondebug_insn (prev);
3542 else
3543 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3544 ;
3f3556f1 3545 OP (2) = move_to_hl (2, first);
78e515f7 3546
3f3556f1 3547 MUST_BE_OK (insn);
78e515f7 3548}
3549
8a6bcd4e 3550/* Like op2, but AX = A * X. */
78e515f7 3551static void
93e93552 3552rl78_alloc_physical_registers_umul (rtx_insn * insn)
78e515f7 3553{
bf79ca12 3554 rtx_insn *prev = prev_nonnote_nondebug_insn (insn);
56d95ea5 3555 rtx_insn *first;
3f3556f1 3556 int tmp_id;
3557 rtx saved_op1;
78e515f7 3558
3f3556f1 3559 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
3560 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
3561 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
78e515f7 3562
3563 MAYBE_OK (insn);
3564
3565 if (recog_data.constraints[1][0] == '%'
3f3556f1 3566 && is_virtual_register (OP (1))
3567 && !is_virtual_register (OP (2))
3568 && !CONSTANT_P (OP (2)))
78e515f7 3569 {
3f3556f1 3570 rtx tmp = OP (1);
3571 OP (1) = OP (2);
3572 OP (2) = tmp;
78e515f7 3573 }
3574
3f3556f1 3575 OP (0) = move_from_acc (0, insn);
3576
3577 tmp_id = get_max_insn_count ();
3578 saved_op1 = OP (1);
8a6bcd4e 3579
3580 if (rtx_equal_p (OP (1), OP (2)))
3581 {
3582 gcc_assert (GET_MODE (OP (2)) == QImode);
3583 /* The MULU instruction does not support duplicate arguments
3584 but we know that if we copy OP (2) to X it will do so via
3585 A and thus OP (1) will already be loaded into A. */
3586 OP (2) = move_to_x (2, insn);
3587 OP (1) = A;
3588 }
3589 else
3590 OP (1) = move_to_acc (1, insn);
78e515f7 3591
3592 MAYBE_OK (insn);
3593
3f3556f1 3594 /* If we omitted the move of OP1 into the accumulator (because
3595 it was already there from a previous insn), then force the
3596 generation of the move instruction now. We know that we
3597 are about to emit a move into HL (or DE) via AX, and hence
3598 our optimization to remove the load of OP1 is no longer valid. */
3599 if (tmp_id == get_max_insn_count ())
3600 force_into_acc (saved_op1, insn);
3601
78e515f7 3602 /* We have to copy op2 to X, but that involves the acc, which
3603 already has a live value. Emit it before those insns. */
3604
3605 if (prev)
3606 first = next_nonnote_nondebug_insn (prev);
3607 else
3608 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
3609 ;
3f3556f1 3610 OP (2) = move_to_x (2, first);
3611
3612 MUST_BE_OK (insn);
3613}
3614
3615static void
93e93552 3616rl78_alloc_address_registers_macax (rtx_insn * insn)
3f3556f1 3617{
3618 int which, op;
3619 bool replace_in_op0 = false;
3620 bool replace_in_op1 = false;
78e515f7 3621
3622 MAYBE_OK (insn);
3623
3f3556f1 3624 /* Two different MEMs are not allowed. */
3625 which = 0;
3626 for (op = 2; op >= 0; op --)
3627 {
3628 if (MEM_P (OP (op)))
3629 {
3630 if (op == 0 && replace_in_op0)
3631 continue;
3632 if (op == 1 && replace_in_op1)
3633 continue;
3634
3635 switch (which)
3636 {
3637 case 0:
3638 /* If we replace a MEM, make sure that we replace it for all
3639 occurrences of the same MEM in the insn. */
3640 replace_in_op0 = (op > 0 && rtx_equal_p (OP (op), OP (0)));
3641 replace_in_op1 = (op > 1 && rtx_equal_p (OP (op), OP (1)));
3642
3643 OP (op) = transcode_memory_rtx (OP (op), HL, insn);
3644 if (op == 2
3645 && MEM_P (OP (op))
7f210f10 3646 && ((GET_CODE (XEXP (OP (op), 0)) == REG
3647 && REGNO (XEXP (OP (op), 0)) == SP_REG)
3f3556f1 3648 || (GET_CODE (XEXP (OP (op), 0)) == PLUS
3649 && REGNO (XEXP (XEXP (OP (op), 0), 0)) == SP_REG)))
3650 {
3651 emit_insn_before (gen_movhi (HL, gen_rtx_REG (HImode, SP_REG)), insn);
3652 OP (op) = replace_rtx (OP (op), gen_rtx_REG (HImode, SP_REG), HL);
3653 }
3654 if (replace_in_op0)
3655 OP (0) = OP (op);
3656 if (replace_in_op1)
3657 OP (1) = OP (op);
3658 break;
3659 case 1:
3660 OP (op) = transcode_memory_rtx (OP (op), DE, insn);
3661 break;
3662 case 2:
3663 OP (op) = transcode_memory_rtx (OP (op), BC, insn);
3664 break;
3665 }
3666 which ++;
3667 }
3668 }
1d701d79 3669
3f3556f1 3670 MUST_BE_OK (insn);
78e515f7 3671}
3672
889a65e7 3673static void
3674rl78_alloc_address_registers_div (rtx_insn * insn)
3675{
3676 MUST_BE_OK (insn);
3677}
3678
78e515f7 3679/* Scan all insns and devirtualize them. */
3680static void
3681rl78_alloc_physical_registers (void)
3682{
3683 /* During most of the compile, gcc is dealing with virtual
3684 registers. At this point, we need to assign physical registers
3685 to the vitual ones, and copy in/out as needed. */
3686
ed3e6e5d 3687 rtx_insn *insn, *curr;
78e515f7 3688 enum attr_valloc valloc_method;
3689
3690 for (insn = get_insns (); insn; insn = curr)
3691 {
3692 int i;
3693
3694 curr = next_nonnote_nondebug_insn (insn);
3695
3696 if (INSN_P (insn)
3697 && (GET_CODE (PATTERN (insn)) == SET
3698 || GET_CODE (PATTERN (insn)) == CALL)
3699 && INSN_CODE (insn) == -1)
3700 {
3701 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
3702 continue;
3703 i = recog (PATTERN (insn), insn, 0);
3704 if (i == -1)
3705 {
3706 debug_rtx (insn);
3707 gcc_unreachable ();
3708 }
3709 INSN_CODE (insn) = i;
3710 }
3711 }
3712
3713 cfun->machine->virt_insns_ok = 0;
3714 cfun->machine->real_insns_ok = 1;
3715
3f3556f1 3716 clear_content_memory ();
3717
78e515f7 3718 for (insn = get_insns (); insn; insn = curr)
3719 {
3f3556f1 3720 rtx pattern;
3721
78e515f7 3722 curr = insn ? next_nonnote_nondebug_insn (insn) : NULL;
3723
3724 if (!INSN_P (insn))
3f3556f1 3725 {
3726 if (LABEL_P (insn))
3727 clear_content_memory ();
8a6bcd4e 3728
3f3556f1 3729 continue;
3730 }
78e515f7 3731
3f3556f1 3732 if (dump_file)
3733 fprintf (dump_file, "Converting insn %d\n", INSN_UID (insn));
3734
3735 pattern = PATTERN (insn);
3736 if (GET_CODE (pattern) == PARALLEL)
3737 pattern = XVECEXP (pattern, 0, 0);
3738 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3739 clear_content_memory ();
3740 if (GET_CODE (pattern) != SET
3741 && GET_CODE (pattern) != CALL)
3742 continue;
7f210f10 3743 if (GET_CODE (pattern) == SET
3744 && GET_CODE (SET_SRC (pattern)) == ASM_OPERANDS)
78e515f7 3745 continue;
3746
3747 valloc_method = get_attr_valloc (insn);
3748
3f3556f1 3749 PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
3750
3751 if (valloc_method == VALLOC_MACAX)
3752 {
3753 record_content (AX, NULL_RTX);
3754 record_content (BC, NULL_RTX);
3755 record_content (DE, NULL_RTX);
3756 }
e98e1692 3757 else if (valloc_method == VALLOC_DIVHI)
3758 {
3759 record_content (AX, NULL_RTX);
3760 record_content (BC, NULL_RTX);
3761 }
3762 else if (valloc_method == VALLOC_DIVSI)
3763 {
3764 record_content (AX, NULL_RTX);
3765 record_content (BC, NULL_RTX);
3766 record_content (DE, NULL_RTX);
3767 record_content (HL, NULL_RTX);
3768 }
78e515f7 3769
3770 if (insn_ok_now (insn))
3771 continue;
3772
3773 INSN_CODE (insn) = -1;
3774
3775 if (RTX_FRAME_RELATED_P (insn))
3776 virt_insn_was_frame = 1;
3777 else
3778 virt_insn_was_frame = 0;
3779
3780 switch (valloc_method)
3781 {
3782 case VALLOC_OP1:
3783 rl78_alloc_physical_registers_op1 (insn);
3784 break;
3785 case VALLOC_OP2:
3786 rl78_alloc_physical_registers_op2 (insn);
3787 break;
3788 case VALLOC_RO1:
3789 rl78_alloc_physical_registers_ro1 (insn);
3790 break;
3791 case VALLOC_CMP:
3792 rl78_alloc_physical_registers_cmp (insn);
3793 break;
3794 case VALLOC_UMUL:
3795 rl78_alloc_physical_registers_umul (insn);
e98e1692 3796 record_content (AX, NULL_RTX);
78e515f7 3797 break;
3798 case VALLOC_MACAX:
3f3556f1 3799 /* Macro that clobbers AX. */
3800 rl78_alloc_address_registers_macax (insn);
3801 record_content (AX, NULL_RTX);
3802 record_content (BC, NULL_RTX);
3803 record_content (DE, NULL_RTX);
78e515f7 3804 break;
e98e1692 3805 case VALLOC_DIVSI:
3806 rl78_alloc_address_registers_div (insn);
3807 record_content (AX, NULL_RTX);
3808 record_content (BC, NULL_RTX);
3809 record_content (DE, NULL_RTX);
3810 record_content (HL, NULL_RTX);
3811 break;
3812 case VALLOC_DIVHI:
3813 rl78_alloc_address_registers_div (insn);
3814 record_content (AX, NULL_RTX);
3815 record_content (BC, NULL_RTX);
3816 break;
889a65e7 3817 default:
3818 gcc_unreachable ();
78e515f7 3819 }
3f3556f1 3820
3821 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3822 clear_content_memory ();
3823 else
3824 process_postponed_content_update ();
78e515f7 3825 }
1d701d79 3826
78e515f7 3827#if DEBUG_ALLOC
3828 fprintf (stderr, "\033[0m");
3829#endif
3830}
3831
3832/* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3833 This function scans for uses of registers; the last use (i.e. first
3834 encounter when scanning backwards) triggers a REG_DEAD note if the
3835 reg was previously in DEAD[]. */
3836static void
3837rl78_note_reg_uses (char *dead, rtx s, rtx insn)
3838{
3839 const char *fmt;
3840 int i, r;
3841 enum rtx_code code;
3842
3843 if (!s)
3844 return;
3845
3846 code = GET_CODE (s);
3847
3848 switch (code)
3849 {
3850 /* Compare registers by number. */
3851 case REG:
3852 r = REGNO (s);
3853 if (dump_file)
3854 {
3855 fprintf (dump_file, "note use reg %d size %d on insn %d\n",
3856 r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn));
3857 print_rtl_single (dump_file, s);
3858 }
3859 if (dead [r])
3860 add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r));
3861 for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++)
3862 dead [r + i] = 0;
3863 return;
3864
3865 /* These codes have no constituent expressions
3866 and are unique. */
3867 case SCRATCH:
3868 case CC0:
3869 case PC:
3870 return;
3871
3872 case CONST_INT:
3873 case CONST_VECTOR:
3874 case CONST_DOUBLE:
3875 case CONST_FIXED:
3876 /* These are kept unique for a given value. */
3877 return;
3878
3879 default:
3880 break;
3881 }
3882
3883 fmt = GET_RTX_FORMAT (code);
3884
3885 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
3886 {
3887 if (fmt[i] == 'E')
3888 {
3889 int j;
3890 for (j = XVECLEN (s, i) - 1; j >= 0; j--)
3891 rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn);
3892 }
3893 else if (fmt[i] == 'e')
3894 rl78_note_reg_uses (dead, XEXP (s, i), insn);
3895 }
3896}
3897
3898/* Like the previous function, but scan for SETs instead. */
3899static void
3900rl78_note_reg_set (char *dead, rtx d, rtx insn)
3901{
3902 int r, i;
77d72b07 3903 bool is_dead;
889a65e7 3904 if (GET_CODE (d) == MEM)
3905 rl78_note_reg_uses (dead, XEXP (d, 0), insn);
3906
78e515f7 3907 if (GET_CODE (d) != REG)
3908 return;
3909
77d72b07 3910 /* Do not mark the reg unused unless all QImode parts of it are dead. */
78e515f7 3911 r = REGNO (d);
77d72b07 3912 is_dead = true;
3913 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
3914 if (!dead [r + i])
3915 is_dead = false;
3916 if(is_dead)
3917 add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r));
78e515f7 3918 if (dump_file)
3919 fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d)));
3920 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
3921 dead [r + i] = 1;
3922}
3923
3924/* This is a rather crude register death pass. Death status is reset
3925 at every jump or call insn. */
3926static void
3927rl78_calculate_death_notes (void)
3928{
3929 char dead[FIRST_PSEUDO_REGISTER];
56d95ea5 3930 rtx p, s, d;
3931rtx_insn *insn;
78e515f7 3932 int i;
3933
3934 memset (dead, 0, sizeof (dead));
3935
3936 for (insn = get_last_insn ();
3937 insn;
3938 insn = prev_nonnote_nondebug_insn (insn))
3939 {
3940 if (dump_file)
3941 {
3942 fprintf (dump_file, "\n--------------------------------------------------");
3943 fprintf (dump_file, "\nDead:");
3944 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
3945 if (dead[i])
3f3556f1 3946 fprintf (dump_file, " %s", reg_names[i]);
78e515f7 3947 fprintf (dump_file, "\n");
3948 print_rtl_single (dump_file, insn);
3949 }
3950
3951 switch (GET_CODE (insn))
3952 {
3953 case INSN:
3954 p = PATTERN (insn);
315b808d 3955 if (GET_CODE (p) == PARALLEL)
889a65e7 3956 {
3957 rtx q = XVECEXP (p, 0 ,1);
3958
3959 /* This happens with the DIV patterns. */
3960 if (GET_CODE (q) == SET)
3961 {
3962 s = SET_SRC (q);
3963 d = SET_DEST (q);
3964 rl78_note_reg_set (dead, d, insn);
3965 rl78_note_reg_uses (dead, s, insn);
3966
3967 }
3968 p = XVECEXP (p, 0, 0);
3969 }
3970
78e515f7 3971 switch (GET_CODE (p))
3972 {
3973 case SET:
3974 s = SET_SRC (p);
3975 d = SET_DEST (p);
3976 rl78_note_reg_set (dead, d, insn);
3977 rl78_note_reg_uses (dead, s, insn);
3978 break;
3979
3980 case USE:
3981 rl78_note_reg_uses (dead, p, insn);
3982 break;
3983
3984 default:
3985 break;
3986 }
3987 break;
3988
3989 case JUMP_INSN:
edf1f7ba 3990 if (INSN_CODE (insn) == CODE_FOR_rl78_return)
78e515f7 3991 {
3992 memset (dead, 1, sizeof (dead));
3993 /* We expect a USE just prior to this, which will mark
3994 the actual return registers. The USE will have a
3995 death note, but we aren't going to be modifying it
3996 after this pass. */
3997 break;
3998 }
511d3173 3999 /* FALLTHRU */
78e515f7 4000 case CALL_INSN:
4001 memset (dead, 0, sizeof (dead));
4002 break;
4003
4004 default:
4005 break;
4006 }
4007 if (dump_file)
4008 print_rtl_single (dump_file, insn);
4009 }
4010}
4011
4012/* Helper function to reset the origins in RP and the age in AGE for
4013 all registers. */
4014static void
4015reset_origins (int *rp, int *age)
4016{
4017 int i;
4018 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4019 {
4020 rp[i] = i;
4021 age[i] = 0;
4022 }
4023}
4024
889a65e7 4025static void
4026set_origin (rtx pat, rtx_insn * insn, int * origins, int * age)
4027{
4028 rtx src = SET_SRC (pat);
4029 rtx dest = SET_DEST (pat);
4030 int mb = GET_MODE_SIZE (GET_MODE (dest));
4031 int i;
4032
4033 if (GET_CODE (dest) == REG)
4034 {
4035 int dr = REGNO (dest);
4036
4037 if (GET_CODE (src) == REG)
4038 {
4039 int sr = REGNO (src);
4040 bool same = true;
4041 int best_age, best_reg;
4042
4043 /* See if the copy is not needed. */
4044 for (i = 0; i < mb; i ++)
4045 if (origins[dr + i] != origins[sr + i])
4046 same = false;
4047
4048 if (same)
4049 {
4050 if (dump_file)
4051 fprintf (dump_file, "deleting because dest already has correct value\n");
4052 delete_insn (insn);
4053 return;
4054 }
4055
4056 if (dr < 8 || sr >= 8)
4057 {
4058 int ar;
4059
4060 best_age = -1;
4061 best_reg = -1;
4062
4063 /* See if the copy can be made from another
4064 bank 0 register instead, instead of the
4065 virtual src register. */
4066 for (ar = 0; ar < 8; ar += mb)
4067 {
4068 same = true;
4069
4070 for (i = 0; i < mb; i ++)
4071 if (origins[ar + i] != origins[sr + i])
4072 same = false;
4073
4074 /* The chip has some reg-reg move limitations. */
4075 if (mb == 1 && dr > 3)
4076 same = false;
4077
4078 if (same)
4079 {
4080 if (best_age == -1 || best_age > age[sr + i])
4081 {
4082 best_age = age[sr + i];
4083 best_reg = sr;
4084 }
4085 }
4086 }
4087
4088 if (best_reg != -1)
4089 {
4090 /* FIXME: copy debug info too. */
4091 SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg);
4092 sr = best_reg;
4093 }
4094 }
4095
4096 for (i = 0; i < mb; i++)
4097 {
4098 origins[dr + i] = origins[sr + i];
4099 age[dr + i] = age[sr + i] + 1;
4100 }
4101 }
4102 else
4103 {
4104 /* The destination is computed, its origin is itself. */
4105 if (dump_file)
4106 fprintf (dump_file, "resetting origin of r%d for %d byte%s\n",
4107 dr, mb, mb == 1 ? "" : "s");
4108
4109 for (i = 0; i < mb; i ++)
4110 {
4111 origins[dr + i] = dr + i;
4112 age[dr + i] = 0;
4113 }
4114 }
4115
4116 /* Any registers marked with that reg as an origin are reset. */
4117 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4118 if (origins[i] >= dr && origins[i] < dr + mb)
4119 {
4120 origins[i] = i;
4121 age[i] = 0;
4122 }
4123 }
4124
4125 /* Special case - our MUL patterns uses AX and sometimes BC. */
4126 if (get_attr_valloc (insn) == VALLOC_MACAX)
4127 {
4128 if (dump_file)
4129 fprintf (dump_file, "Resetting origin of AX/BC for MUL pattern.\n");
4130
4131 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4132 if (i <= 3 || origins[i] <= 3)
4133 {
4134 origins[i] = i;
4135 age[i] = 0;
4136 }
4137 }
e98e1692 4138 else if (get_attr_valloc (insn) == VALLOC_DIVHI)
4139 {
4140 if (dump_file)
4141 fprintf (dump_file, "Resetting origin of AX/DE for DIVHI pattern.\n");
4142
4143 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4144 if (i == A_REG
4145 || i == X_REG
4146 || i == D_REG
4147 || i == E_REG
4148 || origins[i] == A_REG
4149 || origins[i] == X_REG
4150 || origins[i] == D_REG
4151 || origins[i] == E_REG)
4152 {
4153 origins[i] = i;
4154 age[i] = 0;
4155 }
4156 }
4157 else if (get_attr_valloc (insn) == VALLOC_DIVSI)
4158 {
4159 if (dump_file)
4160 fprintf (dump_file, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n");
4161
4162 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4163 if (i <= 7 || origins[i] <= 7)
4164 {
4165 origins[i] = i;
4166 age[i] = 0;
4167 }
4168 }
889a65e7 4169
4170 if (GET_CODE (src) == ASHIFT
4171 || GET_CODE (src) == ASHIFTRT
4172 || GET_CODE (src) == LSHIFTRT)
4173 {
4174 rtx count = XEXP (src, 1);
4175
4176 if (GET_CODE (count) == REG)
4177 {
4178 /* Special case - our pattern clobbers the count register. */
4179 int r = REGNO (count);
4180
4181 if (dump_file)
4182 fprintf (dump_file, "Resetting origin of r%d for shift.\n", r);
4183
4184 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
4185 if (i == r || origins[i] == r)
4186 {
4187 origins[i] = i;
4188 age[i] = 0;
4189 }
4190 }
4191 }
4192}
4193
78e515f7 4194/* The idea behind this optimization is to look for cases where we
4195 move data from A to B to C, and instead move from A to B, and A to
4196 C. If B is a virtual register or memory, this is a big win on its
4197 own. If B turns out to be unneeded after this, it's a bigger win.
4198 For each register, we try to determine where it's value originally
4199 came from, if it's propogated purely through moves (and not
4200 computes). The ORIGINS[] array has the regno for the "origin" of
4201 the value in the [regno] it's indexed by. */
4202static void
4203rl78_propogate_register_origins (void)
4204{
4205 int origins[FIRST_PSEUDO_REGISTER];
4206 int age[FIRST_PSEUDO_REGISTER];
4207 int i;
d3ffa7b4 4208 rtx_insn *insn, *ninsn = NULL;
78e515f7 4209 rtx pat;
4210
4211 reset_origins (origins, age);
4212
4213 for (insn = get_insns (); insn; insn = ninsn)
4214 {
4215 ninsn = next_nonnote_nondebug_insn (insn);
4216
4217 if (dump_file)
4218 {
4219 fprintf (dump_file, "\n");
4220 fprintf (dump_file, "Origins:");
4221 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
4222 if (origins[i] != i)
4223 fprintf (dump_file, " r%d=r%d", i, origins[i]);
4224 fprintf (dump_file, "\n");
4225 print_rtl_single (dump_file, insn);
4226 }
4227
4228 switch (GET_CODE (insn))
4229 {
4230 case CODE_LABEL:
4231 case BARRIER:
4232 case CALL_INSN:
4233 case JUMP_INSN:
4234 reset_origins (origins, age);
4235 break;
4236
4237 default:
4238 break;
4239
4240 case INSN:
4241 pat = PATTERN (insn);
4242
4243 if (GET_CODE (pat) == PARALLEL)
4244 {
4245 rtx clobber = XVECEXP (pat, 0, 1);
4246 pat = XVECEXP (pat, 0, 0);
9aea9676 4247 if (GET_CODE (clobber) == CLOBBER
4248 && GET_CODE (XEXP (clobber, 0)) == REG)
78e515f7 4249 {
4250 int cr = REGNO (XEXP (clobber, 0));
4251 int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0)));
4252 if (dump_file)
4253 fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr);
4254 for (i = 0; i < mb; i++)
4255 {
4256 origins[cr + i] = cr + i;
4257 age[cr + i] = 0;
4258 }
4259 }
889a65e7 4260 /* This happens with the DIV patterns. */
4261 else if (GET_CODE (clobber) == SET)
4262 {
4263 set_origin (clobber, insn, origins, age);
4264 }
78e515f7 4265 else
4266 break;
4267 }
4268
4269 if (GET_CODE (pat) == SET)
4270 {
889a65e7 4271 set_origin (pat, insn, origins, age);
78e515f7 4272 }
9aea9676 4273 else if (GET_CODE (pat) == CLOBBER
4274 && GET_CODE (XEXP (pat, 0)) == REG)
1d701d79 4275 {
4276 if (REG_P (XEXP (pat, 0)))
4277 {
4278 unsigned int reg = REGNO (XEXP (pat, 0));
4279
4280 origins[reg] = reg;
4281 age[reg] = 0;
4282 }
4283 }
78e515f7 4284 }
4285 }
4286}
4287
4288/* Remove any SETs where the destination is unneeded. */
4289static void
4290rl78_remove_unused_sets (void)
4291{
50fc2d35 4292 rtx_insn *insn, *ninsn = NULL;
78e515f7 4293 rtx dest;
4294
4295 for (insn = get_insns (); insn; insn = ninsn)
4296 {
4297 ninsn = next_nonnote_nondebug_insn (insn);
4298
50fc2d35 4299 rtx set = single_set (insn);
4300 if (set == NULL)
78e515f7 4301 continue;
4302
50fc2d35 4303 dest = SET_DEST (set);
78e515f7 4304
8bcf96c6 4305 if (GET_CODE (dest) != REG || REGNO (dest) > 23)
78e515f7 4306 continue;
4307
4308 if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
889a65e7 4309 {
4310 if (dump_file)
4311 fprintf (dump_file, "deleting because the set register is never used.\n");
4312 delete_insn (insn);
4313 }
78e515f7 4314 }
4315}
4316
78e515f7 4317/* This is the top of the devritualization pass. */
4318static void
4319rl78_reorg (void)
4320{
3f3556f1 4321 /* split2 only happens when optimizing, but we need all movSIs to be
4322 split now. */
4323 if (optimize <= 0)
4324 split_all_insns ();
4325
78e515f7 4326 rl78_alloc_physical_registers ();
4327
4328 if (dump_file)
4329 {
4330 fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
2cf07b8b 4331 print_rtl_with_bb (dump_file, get_insns (), TDF_NONE);
78e515f7 4332 }
4333
4334 rl78_propogate_register_origins ();
4335 rl78_calculate_death_notes ();
4336
4337 if (dump_file)
4338 {
4339 fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
2cf07b8b 4340 print_rtl_with_bb (dump_file, get_insns (), TDF_NONE);
78e515f7 4341 fprintf (dump_file, "\n======================================================================\n");
4342 }
4343
4344 rl78_remove_unused_sets ();
4345
4346 /* The code after devirtualizing has changed so much that at this point
4347 we might as well just rescan everything. Note that
4348 df_rescan_all_insns is not going to help here because it does not
4349 touch the artificial uses and defs. */
4350 df_finish_pass (true);
4351 if (optimize > 1)
4352 df_live_add_problem ();
4353 df_scan_alloc (NULL);
4354 df_scan_blocks ();
4355
4356 if (optimize)
4357 df_analyze ();
4358}
4359
3f3556f1 4360#undef TARGET_RETURN_IN_MEMORY
78e515f7 4361#define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
4362
4363static bool
4364rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
4365{
4366 const HOST_WIDE_INT size = int_size_in_bytes (type);
4367 return (size == -1 || size > 8);
4368}
4369
3f3556f1 4370\f
4371#undef TARGET_RTX_COSTS
4372#define TARGET_RTX_COSTS rl78_rtx_costs
4373
d1dc25ff 4374static bool
5ae4887d 4375rl78_rtx_costs (rtx x,
4376 machine_mode mode,
4377 int outer_code ATTRIBUTE_UNUSED,
4378 int opno ATTRIBUTE_UNUSED,
4379 int * total,
4380 bool speed ATTRIBUTE_UNUSED)
3f3556f1 4381{
5ae4887d 4382 int code = GET_CODE (x);
4383
3f3556f1 4384 if (code == IF_THEN_ELSE)
d1dc25ff 4385 {
4386 *total = COSTS_N_INSNS (10);
4387 return true;
4388 }
4389
76a1865a 4390 if (mode == HImode)
4391 {
4392 if (code == MULT && ! speed)
4393 {
4394 * total = COSTS_N_INSNS (8);
4395 return true;
4396 }
4397 return false;
4398 }
4399
5ae4887d 4400 if (mode == SImode)
3f3556f1 4401 {
4402 switch (code)
4403 {
4404 case MULT:
76a1865a 4405 if (! speed)
4406 /* If we are compiling for space then we do not want to use the
4407 inline SImode multiplication patterns or shift sequences.
4408 The cost is not set to 1 or 5 however as we have to allow for
4409 the possibility that we might be converting a leaf function
4410 into a non-leaf function. (There is no way to tell here).
4411 A value of 13 seems to be a reasonable compromise for the
4412 moment. */
4413 * total = COSTS_N_INSNS (13);
4414 else if (RL78_MUL_G14)
3f3556f1 4415 *total = COSTS_N_INSNS (14);
4416 else if (RL78_MUL_G13)
4417 *total = COSTS_N_INSNS (29);
4418 else
4419 *total = COSTS_N_INSNS (500);
4420 return true;
76a1865a 4421
3f3556f1 4422 case PLUS:
4423 *total = COSTS_N_INSNS (8);
4424 return true;
76a1865a 4425
3f3556f1 4426 case ASHIFT:
4427 case ASHIFTRT:
4428 case LSHIFTRT:
4429 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4430 {
4431 switch (INTVAL (XEXP (x, 1)))
4432 {
4433 case 0: *total = COSTS_N_INSNS (0); break;
4434 case 1: *total = COSTS_N_INSNS (6); break;
4435 case 2: case 3: case 4: case 5: case 6: case 7:
4436 *total = COSTS_N_INSNS (10); break;
4437 case 8: *total = COSTS_N_INSNS (6); break;
4438 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
4439 *total = COSTS_N_INSNS (10); break;
4440 case 16: *total = COSTS_N_INSNS (3); break;
4441 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
4442 *total = COSTS_N_INSNS (4); break;
4443 case 24: *total = COSTS_N_INSNS (4); break;
4444 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
4445 *total = COSTS_N_INSNS (5); break;
4446 }
4447 }
4448 else
4449 *total = COSTS_N_INSNS (10+4*16);
4450 return true;
76a1865a 4451
4452 default:
4453 break;
3f3556f1 4454 }
4455 }
4456 return false;
4457}
78e515f7 4458\f
99bdcd9d 4459
0c5d0bfa 4460static GTY(()) section * saddr_section;
4461static GTY(()) section * frodata_section;
4462
4463int
4464rl78_saddr_p (rtx x)
4465{
4466 const char * c;
4467
4468 if (MEM_P (x))
4469 x = XEXP (x, 0);
4470 if (GET_CODE (x) == PLUS)
4471 x = XEXP (x, 0);
4472 if (GET_CODE (x) != SYMBOL_REF)
4473 return 0;
4474
4475 c = XSTR (x, 0);
4476 if (memcmp (c, "@s.", 3) == 0)
4477 return 1;
4478
4479 return 0;
4480}
4481
4482int
4483rl78_sfr_p (rtx x)
4484{
4485 if (MEM_P (x))
4486 x = XEXP (x, 0);
4487 if (GET_CODE (x) != CONST_INT)
4488 return 0;
4489
4490 if ((INTVAL (x) & 0xFF00) != 0xFF00)
4491 return 0;
4492
4493 return 1;
4494}
4495
4496#undef TARGET_STRIP_NAME_ENCODING
4497#define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding
4498
4499static const char *
4500rl78_strip_name_encoding (const char * sym)
4501{
4502 while (1)
4503 {
4504 if (*sym == '*')
4505 sym++;
4506 else if (*sym == '@' && sym[2] == '.')
4507 sym += 3;
4508 else
4509 return sym;
4510 }
4511}
4512
4513/* Like rl78_strip_name_encoding, but does not strip leading asterisks. This
4514 is important if the stripped name is going to be passed to assemble_name()
4515 as that handles asterisk prefixed names in a special manner. */
4516
4517static const char *
4518rl78_strip_nonasm_name_encoding (const char * sym)
4519{
4520 while (1)
4521 {
4522 if (*sym == '@' && sym[2] == '.')
4523 sym += 3;
4524 else
4525 return sym;
4526 }
4527}
4528
4529
4530static int
4531rl78_attrlist_to_encoding (tree list, tree decl ATTRIBUTE_UNUSED)
4532{
4533 while (list)
4534 {
4535 if (is_attribute_p ("saddr", TREE_PURPOSE (list)))
4536 return 's';
4537 list = TREE_CHAIN (list);
4538 }
4539
4540 return 0;
4541}
4542
4543#define RL78_ATTRIBUTES(decl) \
4544 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
4545 : DECL_ATTRIBUTES (decl) \
4546 ? (DECL_ATTRIBUTES (decl)) \
4547 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
4548
4549#undef TARGET_ENCODE_SECTION_INFO
4550#define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info
4551
4552static void
4553rl78_encode_section_info (tree decl, rtx rtl, int first)
4554{
4555 rtx rtlname;
4556 const char * oldname;
4557 char encoding;
4558 char * newname;
4559 tree idp;
4560 tree type;
4561 tree rl78_attributes;
4562
4563 if (!first)
4564 return;
4565
4566 rtlname = XEXP (rtl, 0);
4567
4568 if (GET_CODE (rtlname) == SYMBOL_REF)
4569 oldname = XSTR (rtlname, 0);
4570 else if (GET_CODE (rtlname) == MEM
4571 && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
4572 oldname = XSTR (XEXP (rtlname, 0), 0);
4573 else
4574 gcc_unreachable ();
4575
4576 type = TREE_TYPE (decl);
4577 if (type == error_mark_node)
4578 return;
4579 if (! DECL_P (decl))
4580 return;
4581 rl78_attributes = RL78_ATTRIBUTES (decl);
4582
4583 encoding = rl78_attrlist_to_encoding (rl78_attributes, decl);
4584
4585 if (encoding)
4586 {
4587 newname = (char *) alloca (strlen (oldname) + 4);
4588 sprintf (newname, "@%c.%s", encoding, oldname);
4589 idp = get_identifier (newname);
4590 XEXP (rtl, 0) =
4591 gen_rtx_SYMBOL_REF (Pmode, IDENTIFIER_POINTER (idp));
4592 SYMBOL_REF_WEAK (XEXP (rtl, 0)) = DECL_WEAK (decl);
4593 SET_SYMBOL_REF_DECL (XEXP (rtl, 0), decl);
4594 }
4595}
4596
4597#undef TARGET_ASM_INIT_SECTIONS
4598#define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections
4599
4600static void
4601rl78_asm_init_sections (void)
4602{
4603 saddr_section
4604 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
4605 "\t.section .saddr,\"aw\",@progbits");
4606 frodata_section
4607 = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
4608 "\t.section .frodata,\"aw\",@progbits");
4609}
4610
4611#undef TARGET_ASM_SELECT_SECTION
4612#define TARGET_ASM_SELECT_SECTION rl78_select_section
4613
4614static section *
4615rl78_select_section (tree decl,
8d2e95d3 4616 int reloc,
4617 unsigned HOST_WIDE_INT align)
0c5d0bfa 4618{
4619 int readonly = 1;
4620
4621 switch (TREE_CODE (decl))
4622 {
4623 case VAR_DECL:
4624 if (!TREE_READONLY (decl)
4625 || TREE_SIDE_EFFECTS (decl)
4626 || !DECL_INITIAL (decl)
4627 || (DECL_INITIAL (decl) != error_mark_node
4628 && !TREE_CONSTANT (DECL_INITIAL (decl))))
4629 readonly = 0;
4630 break;
4631 case CONSTRUCTOR:
4632 if (! TREE_CONSTANT (decl))
4633 readonly = 0;
4634 break;
4635
4636 default:
4637 break;
4638 }
4639
4640 if (TREE_CODE (decl) == VAR_DECL)
4641 {
4642 const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
4643
4644 if (name[0] == '@' && name[2] == '.')
4645 switch (name[1])
4646 {
4647 case 's':
4648 return saddr_section;
4649 }
4650
4651 if (TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_FAR
4652 && readonly)
4653 {
4654 return frodata_section;
4655 }
4656 }
4657
4658 if (readonly)
5c14cb1d 4659 return TARGET_ES0 ? frodata_section : readonly_data_section;
0c5d0bfa 4660
8d2e95d3 4661 switch (categorize_decl_for_section (decl, reloc))
4662 {
4663 case SECCAT_TEXT: return text_section;
4664 case SECCAT_DATA: return data_section;
4665 case SECCAT_BSS: return bss_section;
5c14cb1d 4666 case SECCAT_RODATA: return TARGET_ES0 ? frodata_section : readonly_data_section;
8d2e95d3 4667 default:
4668 return default_select_section (decl, reloc, align);
4669 }
0c5d0bfa 4670}
4671
4672void
4673rl78_output_labelref (FILE *file, const char *str)
4674{
4675 const char *str2;
4676
4677 str2 = targetm.strip_name_encoding (str);
4678 if (str2[0] != '.')
4679 fputs (user_label_prefix, file);
4680 fputs (str2, file);
4681}
4682
4683void
4684rl78_output_aligned_common (FILE *stream,
4685 tree decl ATTRIBUTE_UNUSED,
4686 const char *name,
4687 int size, int align, int global)
4688{
4689 /* We intentionally don't use rl78_section_tag() here. */
4690 if (name[0] == '@' && name[2] == '.')
4691 {
4692 const char *sec = 0;
4693 switch (name[1])
4694 {
4695 case 's':
4696 switch_to_section (saddr_section);
4697 sec = ".saddr";
4698 break;
4699 }
4700 if (sec)
4701 {
4702 const char *name2;
4703 int p2align = 0;
4704
4705 while (align > BITS_PER_UNIT)
4706 {
4707 align /= 2;
4708 p2align ++;
4709 }
4710 name2 = targetm.strip_name_encoding (name);
4711 if (global)
4712 fprintf (stream, "\t.global\t_%s\n", name2);
4713 fprintf (stream, "\t.p2align %d\n", p2align);
4714 fprintf (stream, "\t.type\t_%s,@object\n", name2);
4715 fprintf (stream, "\t.size\t_%s,%d\n", name2, size);
4716 fprintf (stream, "_%s:\n\t.zero\t%d\n", name2, size);
4717 return;
4718 }
4719 }
4720
4721 if (!global)
4722 {
4723 fprintf (stream, "\t.local\t");
4724 assemble_name (stream, name);
4725 fprintf (stream, "\n");
4726 }
4727 fprintf (stream, "\t.comm\t");
4728 assemble_name (stream, name);
4729 fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);
4730}
4731
4732#undef TARGET_INSERT_ATTRIBUTES
4733#define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes
4734
4735static void
4736rl78_insert_attributes (tree decl, tree *attributes ATTRIBUTE_UNUSED)
4737{
4738 if (TARGET_ES0
4739 && TREE_CODE (decl) == VAR_DECL
4740 && TREE_READONLY (decl)
4741 && TREE_ADDRESSABLE (decl)
4742 && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_GENERIC)
4743 {
4744 tree type = TREE_TYPE (decl);
4745 tree attr = TYPE_ATTRIBUTES (type);
4746 int q = TYPE_QUALS_NO_ADDR_SPACE (type) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR);
e98e1692 4747
0c5d0bfa 4748 TREE_TYPE (decl) = build_type_attribute_qual_variant (type, attr, q);
4749 }
4750}
4751
4752#undef TARGET_ASM_INTEGER
4753#define TARGET_ASM_INTEGER rl78_asm_out_integer
4754
4755static bool
4756rl78_asm_out_integer (rtx x, unsigned int size, int aligned_p)
4757{
4758 if (default_assemble_integer (x, size, aligned_p))
4759 return true;
4760
4761 if (size == 4)
4762 {
4763 assemble_integer_with_op (".long\t", x);
4764 return true;
4765 }
4766
4767 return false;
4768}
0c5d0bfa 4769\f
99bdcd9d 4770#undef TARGET_UNWIND_WORD_MODE
4771#define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
4772
f77c4496 4773static scalar_int_mode
99bdcd9d 4774rl78_unwind_word_mode (void)
4775{
4776 return HImode;
4777}
4778
0c5d0bfa 4779#ifndef USE_COLLECT2
4780#undef TARGET_ASM_CONSTRUCTOR
4781#define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor
4782#undef TARGET_ASM_DESTRUCTOR
4783#define TARGET_ASM_DESTRUCTOR rl78_asm_destructor
4784
4785static void
4786rl78_asm_ctor_dtor (rtx symbol, int priority, bool is_ctor)
4787{
4788 section *sec;
4789
4790 if (priority != DEFAULT_INIT_PRIORITY)
4791 {
4792 /* This section of the function is based upon code copied
4793 from: gcc/varasm.c:get_cdtor_priority_section(). */
511d3173 4794 char buf[18];
0c5d0bfa 4795
4796 sprintf (buf, "%s.%.5u", is_ctor ? ".ctors" : ".dtors",
4797 MAX_INIT_PRIORITY - priority);
4798 sec = get_section (buf, 0, NULL);
4799 }
4800 else
4801 sec = is_ctor ? ctors_section : dtors_section;
4802
4803 assemble_addr_to_section (symbol, sec);
4804}
4805
4806static void
4807rl78_asm_constructor (rtx symbol, int priority)
4808{
4809 rl78_asm_ctor_dtor (symbol, priority, true);
4810}
4811
4812static void
4813rl78_asm_destructor (rtx symbol, int priority)
4814{
4815 rl78_asm_ctor_dtor (symbol, priority, false);
4816}
4817#endif /* ! USE_COLLECT2 */
4818
4819/* Scan backwards through the insn chain looking to see if the flags
4820 have been set for a comparison of OP against OPERAND. Start with
4821 the insn *before* the current insn. */
4822
4823bool
4824rl78_flags_already_set (rtx op, rtx operand)
4825{
4826 /* We only track the Z flag. */
4827 if (GET_CODE (op) != EQ && GET_CODE (op) != NE)
4828 return false;
4829
4830 /* This should not happen, but let's be paranoid. */
4831 if (current_output_insn == NULL_RTX)
4832 return false;
4833
4834 rtx_insn *insn;
4835 bool res = false;
4836
4837 for (insn = prev_nonnote_nondebug_insn (current_output_insn);
4838 insn != NULL_RTX;
4839 insn = prev_nonnote_nondebug_insn (insn))
4840 {
4841 if (LABEL_P (insn))
4842 break;
e98e1692 4843
0c5d0bfa 4844 if (! INSN_P (insn))
4845 continue;
4846
4847 /* Make sure that the insn can be recognized. */
4848 if (recog_memoized (insn) == -1)
4849 continue;
4850
4851 enum attr_update_Z updated = get_attr_update_Z (insn);
4852
4853 rtx set = single_set (insn);
4854 bool must_break = (set != NULL_RTX && rtx_equal_p (operand, SET_DEST (set)));
4855
4856 switch (updated)
4857 {
4858 case UPDATE_Z_NO:
4859 break;
4860 case UPDATE_Z_CLOBBER:
4861 must_break = true;
4862 break;
4863 case UPDATE_Z_UPDATE_Z:
4864 res = must_break;
4865 must_break = true;
4866 break;
4867 default:
4868 gcc_unreachable ();
4869 }
4870
4871 if (must_break)
4872 break;
4873 }
4874
4875 /* We have to re-recognize the current insn as the call(s) to
4876 get_attr_update_Z() above will have overwritten the recog_data cache. */
4877 recog_memoized (current_output_insn);
4878 cleanup_subreg_operands (current_output_insn);
4879 constrain_operands_cached (current_output_insn, 1);
4880
4881 return res;
4882}
95328f38 4883
4884const char *
4885rl78_addsi3_internal (rtx * operands, unsigned int alternative)
4886{
61bafda6 4887 const char *addH2 = "addw ax, %H2\n\t";
4888
95328f38 4889 /* If we are adding in a constant symbolic address when -mes0
4890 is active then we know that the address must be <64K and
4891 that it is invalid to access anything above 64K relative to
4892 this address. So we can skip adding in the high bytes. */
4893 if (TARGET_ES0
4894 && GET_CODE (operands[2]) == SYMBOL_REF
4895 && TREE_CODE (SYMBOL_REF_DECL (operands[2])) == VAR_DECL
4896 && TREE_READONLY (SYMBOL_REF_DECL (operands[2]))
4897 && ! TREE_SIDE_EFFECTS (SYMBOL_REF_DECL (operands[2])))
4898 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax";
4899
61bafda6 4900 if(CONST_INT_P(operands[2]))
4901 {
4902 if((INTVAL(operands[2]) & 0xFFFF0000) == 0)
4903 {
4904 addH2 = "";
4905 }
4906 else if((INTVAL(operands[2]) & 0xFFFF0000) == 0x00010000)
4907 {
4908 addH2 = "incw ax\n\t";
4909 }
4910 else if((INTVAL(operands[2]) & 0xFFFF0000) == 0xFFFF0000)
4911 {
4912 addH2 = "decw ax\n\t";
4913 }
4914 }
4915
95328f38 4916 switch (alternative)
4917 {
4918 case 0:
4919 case 1:
61bafda6 4920 snprintf(fmt_buffer, sizeof(fmt_buffer),
4921 "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);
4922 break;
95328f38 4923 case 2:
61bafda6 4924 snprintf(fmt_buffer, sizeof(fmt_buffer),
4925 "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);
4926 break;
95328f38 4927 default:
4928 gcc_unreachable ();
4929 }
61bafda6 4930
4931 return fmt_buffer;
95328f38 4932}
4933
99efc84b 4934rtx
4935rl78_emit_libcall (const char *name, enum rtx_code code,
4936 enum machine_mode dmode, enum machine_mode smode,
4937 int noperands, rtx *operands)
4938{
4939 rtx ret;
4940 rtx_insn *insns;
4941 rtx libcall;
4942 rtx equiv;
4943
4944 start_sequence ();
4945 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
4946
4947 switch (noperands)
4948 {
4949 case 2:
4950 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
4951 dmode, operands[1], smode);
4952 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
4953 break;
4954
4955 case 3:
4956 ret = emit_library_call_value (libcall, NULL_RTX,
4957 LCT_CONST, dmode,
4958 operands[1], smode, operands[2],
4959 smode);
4960 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
4961 break;
4962
4963 default:
4964 gcc_unreachable ();
4965 }
4966
4967 insns = get_insns ();
4968 end_sequence ();
4969 emit_libcall_block (insns, operands[0], ret, equiv);
4970 return ret;
4971}
4972
d1dc25ff 4973\f
4974#undef TARGET_PREFERRED_RELOAD_CLASS
4975#define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
4976
4977static reg_class_t
d1f90de5 4978rl78_preferred_reload_class (rtx x ATTRIBUTE_UNUSED, reg_class_t rclass)
d1dc25ff 4979{
4980 if (rclass == NO_REGS)
4981 rclass = V_REGS;
4982
4983 return rclass;
4984}
4985
889a65e7 4986\f
78e515f7 4987struct gcc_target targetm = TARGET_INITIALIZER;
4988
4989#include "gt-rl78.h"