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