]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/rl78/rl78.c
rl78.c (rl78_asm_file_start): Specify alternate vregs location for RL78/G10.
[thirdparty/gcc.git] / gcc / config / rl78 / rl78.c
1 /* Subroutines used for code generation on Renesas RL78 processors.
2 Copyright (C) 2011-2013 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 "tm.h"
25 #include "tree.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "insn-config.h"
30 #include "conditions.h"
31 #include "output.h"
32 #include "insn-attr.h"
33 #include "flags.h"
34 #include "function.h"
35 #include "expr.h"
36 #include "optabs.h"
37 #include "libfuncs.h"
38 #include "recog.h"
39 #include "diagnostic-core.h"
40 #include "toplev.h"
41 #include "reload.h"
42 #include "df.h"
43 #include "ggc.h"
44 #include "tm_p.h"
45 #include "debug.h"
46 #include "target.h"
47 #include "target-def.h"
48 #include "langhooks.h"
49 #include "rl78-protos.h"
50 #include "dumpfile.h"
51 #include "tree-pass.h"
52 #include "context.h"
53 #include "tm-constrs.h" /* for satisfies_constraint_*(). */
54 #include "insn-flags.h" /* for gen_*(). */
55 \f
56 static inline bool is_interrupt_func (const_tree decl);
57 static inline bool is_brk_interrupt_func (const_tree decl);
58 static void rl78_reorg (void);
59 \f
60
61 /* Debugging statements are tagged with DEBUG0 only so that they can
62 be easily enabled individually, by replacing the '0' with '1' as
63 needed. */
64 #define DEBUG0 0
65 #define DEBUG1 1
66
67 /* REGISTER_NAMES has the names for individual 8-bit registers, but
68 these have the names we need to use when referring to 16-bit
69 register pairs. */
70 static const char * const word_regnames[] =
71 {
72 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
73 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
74 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
75 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
76 "sp", "ap", "psw", "es", "cs"
77 };
78
79 struct GTY(()) machine_function
80 {
81 /* If set, the rest of the fields have been computed. */
82 int computed;
83 /* Which register pairs need to be pushed in the prologue. */
84 int need_to_push [FIRST_PSEUDO_REGISTER / 2];
85
86 /* These fields describe the frame layout... */
87 /* arg pointer */
88 /* 4 bytes for saved PC */
89 int framesize_regs;
90 /* frame pointer */
91 int framesize_locals;
92 int framesize_outgoing;
93 /* stack pointer */
94 int framesize;
95
96 /* If set, recog is allowed to match against the "real" patterns. */
97 int real_insns_ok;
98 /* If set, recog is allowed to match against the "virtual" patterns. */
99 int virt_insns_ok;
100 /* Set if the current function needs to clean up any trampolines. */
101 int trampolines_used;
102 };
103
104 /* This is our init_machine_status, as set in
105 rl78_option_override. */
106 static struct machine_function *
107 rl78_init_machine_status (void)
108 {
109 struct machine_function *m;
110
111 m = ggc_alloc_cleared_machine_function ();
112 m->virt_insns_ok = 1;
113
114 return m;
115 }
116
117 /* Returns whether to run the devirtualization pass. */
118 static bool
119 devirt_gate (void)
120 {
121 return true;
122 }
123
124 /* Runs the devirtualization pass. */
125 static unsigned int
126 devirt_pass (void)
127 {
128 rl78_reorg ();
129 return 0;
130 }
131
132 /* This pass converts virtual instructions using virtual registers, to
133 real instructions using real registers. Rather than run it as
134 reorg, we reschedule it before vartrack to help with debugging. */
135 namespace {
136
137 const pass_data pass_data_rl78_devirt =
138 {
139 RTL_PASS, /* type */
140 "devirt", /* name */
141 OPTGROUP_NONE, /* optinfo_flags */
142 true, /* has_gate */
143 true, /* has_execute */
144 TV_MACH_DEP, /* tv_id */
145 0, /* properties_required */
146 0, /* properties_provided */
147 0, /* properties_destroyed */
148 0, /* todo_flags_start */
149 0, /* todo_flags_finish */
150 };
151
152 class pass_rl78_devirt : public rtl_opt_pass
153 {
154 public:
155 pass_rl78_devirt(gcc::context *ctxt)
156 : rtl_opt_pass(pass_data_rl78_devirt, ctxt)
157 {
158 }
159
160 /* opt_pass methods: */
161 bool gate () { return devirt_gate (); }
162 unsigned int execute () { return devirt_pass (); }
163 };
164
165 } // anon namespace
166
167 rtl_opt_pass *
168 make_pass_rl78_devirt (gcc::context *ctxt)
169 {
170 return new pass_rl78_devirt (ctxt);
171 }
172
173 static unsigned int
174 move_elim_pass (void)
175 {
176 rtx insn, ninsn, prev = NULL_RTX;
177
178 for (insn = get_insns (); insn; insn = ninsn)
179 {
180 rtx set;
181
182 ninsn = next_nonnote_nondebug_insn (insn);
183
184 if ((set = single_set (insn)) == NULL_RTX)
185 {
186 prev = NULL_RTX;
187 continue;
188 }
189
190 /* If we have two SET insns in a row (without anything
191 between them) and the source of the second one is the
192 destination of the first one, and vice versa, then we
193 can eliminate the second SET. */
194 if (prev
195 && rtx_equal_p (SET_DEST (prev), SET_SRC (set))
196 && rtx_equal_p (SET_DEST (set), SET_SRC (prev))
197 )
198 {
199 if (dump_file)
200 fprintf (dump_file, " Delete insn %d because it is redundant\n",
201 INSN_UID (insn));
202
203 delete_insn (insn);
204 prev = NULL_RTX;
205 }
206 else
207 prev = set;
208 }
209
210 if (dump_file)
211 print_rtl_with_bb (dump_file, get_insns (), 0);
212
213 return 0;
214 }
215
216 namespace {
217
218 const pass_data pass_data_rl78_move_elim =
219 {
220 RTL_PASS, /* type */
221 "move_elim", /* name */
222 OPTGROUP_NONE, /* optinfo_flags */
223 true, /* has_gate */
224 true, /* has_execute */
225 TV_MACH_DEP, /* tv_id */
226 0, /* properties_required */
227 0, /* properties_provided */
228 0, /* properties_destroyed */
229 0, /* todo_flags_start */
230 0, /* todo_flags_finish */
231 };
232
233 class pass_rl78_move_elim : public rtl_opt_pass
234 {
235 public:
236 pass_rl78_move_elim(gcc::context *ctxt)
237 : rtl_opt_pass(pass_data_rl78_move_elim, ctxt)
238 {
239 }
240
241 /* opt_pass methods: */
242 bool gate () { return devirt_gate (); }
243 unsigned int execute () { return move_elim_pass (); }
244 };
245
246 } // anon namespace
247
248 rtl_opt_pass *
249 make_pass_rl78_move_elim (gcc::context *ctxt)
250 {
251 return new pass_rl78_move_elim (ctxt);
252 }
253
254 #undef TARGET_ASM_FILE_START
255 #define TARGET_ASM_FILE_START rl78_asm_file_start
256
257 static void
258 rl78_asm_file_start (void)
259 {
260 int i;
261
262 if (TARGET_G10)
263 {
264 /* The memory used is 0xffec8 to 0xffedf; real registers are in
265 0xffee0 to 0xffee7. */
266 for (i = 8; i < 32; i++)
267 fprintf (asm_out_file, "r%d\t=\t0x%x\n", i, 0xffec0 + i);
268 }
269 else
270 {
271 for (i = 0; i < 8; i++)
272 {
273 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 8 + i, 0xffef0 + i);
274 fprintf (asm_out_file, "r%d\t=\t0x%x\n", 16 + i, 0xffee8 + i);
275 }
276 }
277
278 opt_pass *rl78_devirt_pass = make_pass_rl78_devirt (g);
279 static struct register_pass_info rl78_devirt_info =
280 {
281 rl78_devirt_pass,
282 "pro_and_epilogue",
283 1,
284 PASS_POS_INSERT_BEFORE
285 };
286
287 opt_pass *rl78_move_elim_pass = make_pass_rl78_move_elim (g);
288 static struct register_pass_info rl78_move_elim_info =
289 {
290 rl78_move_elim_pass,
291 "bbro",
292 1,
293 PASS_POS_INSERT_AFTER
294 };
295
296 register_pass (& rl78_devirt_info);
297 register_pass (& rl78_move_elim_info);
298 }
299
300 \f
301 #undef TARGET_OPTION_OVERRIDE
302 #define TARGET_OPTION_OVERRIDE rl78_option_override
303
304 static void
305 rl78_option_override (void)
306 {
307 flag_omit_frame_pointer = 1;
308 flag_no_function_cse = 1;
309 flag_split_wide_types = 0;
310
311 init_machine_status = rl78_init_machine_status;
312 }
313
314 /* Most registers are 8 bits. Some are 16 bits because, for example,
315 gcc doesn't like dealing with $FP as a register pair. This table
316 maps register numbers to size in bytes. */
317 static const int register_sizes[] =
318 {
319 1, 1, 1, 1, 1, 1, 1, 1,
320 1, 1, 1, 1, 1, 1, 1, 1,
321 1, 1, 1, 1, 1, 1, 2, 1,
322 1, 1, 1, 1, 1, 1, 1, 1,
323 2, 2, 1, 1, 1
324 };
325
326 /* Predicates used in the MD patterns. This one is true when virtual
327 insns may be matched, which typically means before (or during) the
328 devirt pass. */
329 bool
330 rl78_virt_insns_ok (void)
331 {
332 if (cfun)
333 return cfun->machine->virt_insns_ok;
334 return true;
335 }
336
337 /* Predicates used in the MD patterns. This one is true when real
338 insns may be matched, which typically means after (or during) the
339 devirt pass. */
340 bool
341 rl78_real_insns_ok (void)
342 {
343 if (cfun)
344 return cfun->machine->real_insns_ok;
345 return false;
346 }
347
348 /* Implements HARD_REGNO_NREGS. */
349 int
350 rl78_hard_regno_nregs (int regno, enum machine_mode mode)
351 {
352 int rs = register_sizes[regno];
353 if (rs < 1)
354 rs = 1;
355 return ((GET_MODE_SIZE (mode) + rs - 1) / rs);
356 }
357
358 /* Implements HARD_REGNO_MODE_OK. */
359 int
360 rl78_hard_regno_mode_ok (int regno, enum machine_mode mode)
361 {
362 int s = GET_MODE_SIZE (mode);
363
364 if (s < 1)
365 return 0;
366 /* These are not to be used by gcc. */
367 if (regno == 23 || regno == ES_REG || regno == CS_REG)
368 return 0;
369 /* $fp can alway sbe accessed as a 16-bit value. */
370 if (regno == FP_REG && s == 2)
371 return 1;
372 if (regno < SP_REG)
373 {
374 /* Since a reg-reg move is really a reg-mem move, we must
375 enforce alignment. */
376 if (s > 1 && (regno % 2))
377 return 0;
378 return 1;
379 }
380 if (s == CC_REGNUM)
381 return (mode == BImode);
382 /* All other registers must be accessed in their natural sizes. */
383 if (s == register_sizes [regno])
384 return 1;
385 return 0;
386 }
387
388 /* Simplify_gen_subreg() doesn't handle memory references the way we
389 need it to below, so we use this function for when we must get a
390 valid subreg in a "natural" state. */
391 static rtx
392 rl78_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte)
393 {
394 if (GET_CODE (r) == MEM)
395 return adjust_address (r, mode, byte);
396 else
397 return simplify_gen_subreg (mode, r, omode, byte);
398 }
399
400 /* Used by movsi. Split SImode moves into two HImode moves, using
401 appropriate patterns for the upper and lower halves of symbols. */
402 void
403 rl78_expand_movsi (rtx *operands)
404 {
405 rtx op00, op02, op10, op12;
406
407 op00 = rl78_subreg (HImode, operands[0], SImode, 0);
408 op02 = rl78_subreg (HImode, operands[0], SImode, 2);
409 if (GET_CODE (operands[1]) == CONST
410 || GET_CODE (operands[1]) == SYMBOL_REF)
411 {
412 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
413 op10 = gen_rtx_CONST (HImode, op10);
414 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
415 op12 = gen_rtx_CONST (HImode, op12);
416 }
417 else
418 {
419 op10 = rl78_subreg (HImode, operands[1], SImode, 0);
420 op12 = rl78_subreg (HImode, operands[1], SImode, 2);
421 }
422
423 if (rtx_equal_p (operands[0], operands[1]))
424 ;
425 else if (rtx_equal_p (op00, op12))
426 {
427 emit_move_insn (op02, op12);
428 emit_move_insn (op00, op10);
429 }
430 else
431 {
432 emit_move_insn (op00, op10);
433 emit_move_insn (op02, op12);
434 }
435 }
436
437 void
438 rl78_split_movsi (rtx *operands)
439 {
440 rtx op00, op02, op10, op12;
441
442 op00 = rl78_subreg (HImode, operands[0], SImode, 0);
443 op02 = rl78_subreg (HImode, operands[0], SImode, 2);
444 if (GET_CODE (operands[1]) == CONST
445 || GET_CODE (operands[1]) == SYMBOL_REF)
446 {
447 op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
448 op10 = gen_rtx_CONST (HImode, op10);
449 op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
450 op12 = gen_rtx_CONST (HImode, op12);
451 }
452 else
453 {
454 op10 = rl78_subreg (HImode, operands[1], SImode, 0);
455 op12 = rl78_subreg (HImode, operands[1], SImode, 2);
456 }
457
458 if (rtx_equal_p (operands[0], operands[1]))
459 ;
460 else if (rtx_equal_p (op00, op12))
461 {
462 operands[2] = op02;
463 operands[4] = op12;
464 operands[3] = op00;
465 operands[5] = op10;
466 }
467 else
468 {
469 operands[2] = op00;
470 operands[4] = op10;
471 operands[3] = op02;
472 operands[5] = op12;
473 }
474 }
475
476
477 /* Used by various two-operand expanders which cannot accept all
478 operands in the "far" namespace. Force some such operands into
479 registers so that each pattern has at most one far operand. */
480 int
481 rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx))
482 {
483 int did = 0;
484 rtx temp_reg = NULL;
485
486 /* FIXME: in the future, be smarter about only doing this if the
487 other operand is also far, assuming the devirtualizer can also
488 handle that. */
489 if (rl78_far_p (operands[0]))
490 {
491 temp_reg = operands[0];
492 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
493 did = 1;
494 }
495 if (!did)
496 return 0;
497
498 emit_insn (gen (operands[0], operands[1]));
499 if (temp_reg)
500 emit_move_insn (temp_reg, operands[0]);
501 return 1;
502 }
503
504 /* Likewise, but for three-operand expanders. */
505 int
506 rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx))
507 {
508 int did = 0;
509 rtx temp_reg = NULL;
510
511 /* FIXME: Likewise. */
512 if (rl78_far_p (operands[1]))
513 {
514 rtx temp_reg = gen_reg_rtx (GET_MODE (operands[1]));
515 emit_move_insn (temp_reg, operands[1]);
516 operands[1] = temp_reg;
517 did = 1;
518 }
519 if (rl78_far_p (operands[0]))
520 {
521 temp_reg = operands[0];
522 operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
523 did = 1;
524 }
525 if (!did)
526 return 0;
527
528 emit_insn (gen (operands[0], operands[1], operands[2]));
529 if (temp_reg)
530 emit_move_insn (temp_reg, operands[0]);
531 return 1;
532 }
533
534 #undef TARGET_CAN_ELIMINATE
535 #define TARGET_CAN_ELIMINATE rl78_can_eliminate
536
537 static bool
538 rl78_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to ATTRIBUTE_UNUSED)
539 {
540 return true;
541 }
542
543 /* Returns nonzero if the given register needs to be saved by the
544 current function. */
545 static int
546 need_to_save (int regno)
547 {
548 if (is_interrupt_func (cfun->decl))
549 {
550 if (regno < 8)
551 return 1; /* don't know what devirt will need */
552 if (regno > 23)
553 return 0; /* don't need to save interrupt registers */
554 if (crtl->is_leaf)
555 {
556 return df_regs_ever_live_p (regno);
557 }
558 else
559 return 1;
560 }
561 if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
562 return 1;
563 if (fixed_regs[regno])
564 return 0;
565 if (crtl->calls_eh_return)
566 return 1;
567 if (df_regs_ever_live_p (regno)
568 && !call_used_regs[regno])
569 return 1;
570 return 0;
571 }
572
573 /* We use this to wrap all emitted insns in the prologue. */
574 static rtx
575 F (rtx x)
576 {
577 RTX_FRAME_RELATED_P (x) = 1;
578 return x;
579 }
580
581 /* Compute all the frame-related fields in our machine_function
582 structure. */
583 static void
584 rl78_compute_frame_info (void)
585 {
586 int i;
587
588 cfun->machine->computed = 1;
589 cfun->machine->framesize_regs = 0;
590 cfun->machine->framesize_locals = get_frame_size ();
591 cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
592
593 for (i = 0; i < 16; i ++)
594 if (need_to_save (i * 2) || need_to_save (i * 2 + 1))
595 {
596 cfun->machine->need_to_push [i] = 1;
597 cfun->machine->framesize_regs += 2;
598 }
599 else
600 cfun->machine->need_to_push [i] = 0;
601
602 if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
603 cfun->machine->framesize_locals ++;
604
605 cfun->machine->framesize = (cfun->machine->framesize_regs
606 + cfun->machine->framesize_locals
607 + cfun->machine->framesize_outgoing);
608 }
609 \f
610 /* Returns true if the provided function has the specified attribute. */
611 static inline bool
612 has_func_attr (const_tree decl, const char * func_attr)
613 {
614 if (decl == NULL_TREE)
615 decl = current_function_decl;
616
617 return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
618 }
619
620 /* Returns true if the provided function has the "interrupt" attribute. */
621 static inline bool
622 is_interrupt_func (const_tree decl)
623 {
624 return has_func_attr (decl, "interrupt") || has_func_attr (decl, "brk_interrupt");
625 }
626
627 /* Returns true if the provided function has the "brk_interrupt" attribute. */
628 static inline bool
629 is_brk_interrupt_func (const_tree decl)
630 {
631 return has_func_attr (decl, "brk_interrupt");
632 }
633
634 /* Check "interrupt" attributes. */
635 static tree
636 rl78_handle_func_attribute (tree * node,
637 tree name,
638 tree args,
639 int flags ATTRIBUTE_UNUSED,
640 bool * no_add_attrs)
641 {
642 gcc_assert (DECL_P (* node));
643 gcc_assert (args == NULL_TREE);
644
645 if (TREE_CODE (* node) != FUNCTION_DECL)
646 {
647 warning (OPT_Wattributes, "%qE attribute only applies to functions",
648 name);
649 * no_add_attrs = true;
650 }
651
652 /* FIXME: We ought to check that the interrupt and exception
653 handler attributes have been applied to void functions. */
654 return NULL_TREE;
655 }
656
657 #undef TARGET_ATTRIBUTE_TABLE
658 #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
659
660 /* Table of RL78-specific attributes. */
661 const struct attribute_spec rl78_attribute_table[] =
662 {
663 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
664 affects_type_identity. */
665 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
666 false },
667 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute,
668 false },
669 { "naked", 0, 0, true, false, false, rl78_handle_func_attribute,
670 false },
671 { NULL, 0, 0, false, false, false, NULL, false }
672 };
673
674
675 \f
676 /* Break down an address RTX into its component base/index/addend
677 portions and return TRUE if the address is of a valid form, else
678 FALSE. */
679 static bool
680 characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
681 {
682 *base = NULL_RTX;
683 *index = NULL_RTX;
684 *addend = NULL_RTX;
685
686 if (GET_CODE (x) == REG)
687 {
688 *base = x;
689 return true;
690 }
691
692 /* We sometimes get these without the CONST wrapper */
693 if (GET_CODE (x) == PLUS
694 && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
695 && GET_CODE (XEXP (x, 1)) == CONST_INT)
696 {
697 *addend = x;
698 return true;
699 }
700
701 if (GET_CODE (x) == PLUS)
702 {
703 *base = XEXP (x, 0);
704 x = XEXP (x, 1);
705
706 if (GET_CODE (*base) != REG
707 && GET_CODE (x) == REG)
708 {
709 rtx tmp = *base;
710 *base = x;
711 x = tmp;
712 }
713
714 if (GET_CODE (*base) != REG)
715 return false;
716
717 if (GET_CODE (x) == ZERO_EXTEND
718 && GET_CODE (XEXP (x, 0)) == REG)
719 {
720 *index = XEXP (x, 0);
721 return false;
722 }
723 }
724
725 switch (GET_CODE (x))
726 {
727 case PLUS:
728 if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
729 && GET_CODE (XEXP (x, 0)) == CONST_INT)
730 {
731 *addend = x;
732 return true;
733 }
734 /* fall through */
735 case MEM:
736 case REG:
737 return false;
738
739 case CONST:
740 case SYMBOL_REF:
741 case CONST_INT:
742 *addend = x;
743 return true;
744
745 default:
746 return false;
747 }
748
749 return false;
750 }
751
752 /* Used by the Whb constraint. Match addresses that use HL+B or HL+C
753 addressing. */
754 bool
755 rl78_hl_b_c_addr_p (rtx op)
756 {
757 rtx hl, bc;
758
759 if (GET_CODE (op) != PLUS)
760 return false;
761 hl = XEXP (op, 0);
762 bc = XEXP (op, 1);
763 if (GET_CODE (hl) == ZERO_EXTEND)
764 {
765 rtx tmp = hl;
766 hl = bc;
767 bc = tmp;
768 }
769 if (GET_CODE (hl) != REG)
770 return false;
771 if (GET_CODE (bc) != ZERO_EXTEND)
772 return false;
773 bc = XEXP (bc, 0);
774 if (GET_CODE (bc) != REG)
775 return false;
776 if (REGNO (hl) != HL_REG)
777 return false;
778 if (REGNO (bc) != B_REG && REGNO (bc) != C_REG)
779 return false;
780
781 return true;
782 }
783
784 #define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
785
786 /* Used in various constraints and predicates to match operands in the
787 "far" address space. */
788 int
789 rl78_far_p (rtx x)
790 {
791 if (! MEM_P (x))
792 return 0;
793 #if DEBUG0
794 fprintf (stderr, "\033[35mrl78_far_p: "); debug_rtx(x);
795 fprintf (stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
796 #endif
797 return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR;
798 }
799
800 /* Return the appropriate mode for a named address pointer. */
801 #undef TARGET_ADDR_SPACE_POINTER_MODE
802 #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
803 static enum machine_mode
804 rl78_addr_space_pointer_mode (addr_space_t addrspace)
805 {
806 switch (addrspace)
807 {
808 case ADDR_SPACE_GENERIC:
809 return HImode;
810 case ADDR_SPACE_FAR:
811 return SImode;
812 default:
813 gcc_unreachable ();
814 }
815 }
816
817 /* Returns TRUE for valid addresses. */
818 #undef TARGET_VALID_POINTER_MODE
819 #define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
820 static bool
821 rl78_valid_pointer_mode (enum machine_mode m)
822 {
823 return (m == HImode || m == SImode);
824 }
825
826 /* Return the appropriate mode for a named address address. */
827 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
828 #define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
829 static enum machine_mode
830 rl78_addr_space_address_mode (addr_space_t addrspace)
831 {
832 switch (addrspace)
833 {
834 case ADDR_SPACE_GENERIC:
835 return HImode;
836 case ADDR_SPACE_FAR:
837 return SImode;
838 default:
839 gcc_unreachable ();
840 }
841 }
842
843 #undef TARGET_LEGITIMATE_CONSTANT_P
844 #define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
845
846 static bool
847 rl78_is_legitimate_constant (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED)
848 {
849 return true;
850 }
851
852 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
853 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
854
855 bool
856 rl78_as_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x,
857 bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
858 {
859 rtx base, index, addend;
860
861 if (as == ADDR_SPACE_GENERIC
862 && GET_MODE (x) == SImode)
863 return false;
864
865 if (! characterize_address (x, &base, &index, &addend))
866 return false;
867
868 /* We can't extract the high/low portions of a PLUS address
869 involving a register during devirtualization, so make sure all
870 such __far addresses do not have addends. This forces GCC to do
871 the sum separately. */
872 if (addend && base && as == ADDR_SPACE_FAR)
873 return false;
874
875 if (base && index)
876 {
877 int ir = REGNO (index);
878 int br = REGNO (base);
879
880 #define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
881 OK (REG_IS (br, HL_REG) && REG_IS (ir, B_REG), "[hl+b]");
882 OK (REG_IS (br, HL_REG) && REG_IS (ir, C_REG), "[hl+c]");
883 return false;
884 }
885
886 if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER)
887 return false;
888
889 if (! cfun->machine->virt_insns_ok && base && GET_CODE (base) == REG
890 && REGNO (base) >= 8 && REGNO (base) <= 31)
891 return false;
892
893 return true;
894 }
895
896 /* Determine if one named address space is a subset of another. */
897 #undef TARGET_ADDR_SPACE_SUBSET_P
898 #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
899 static bool
900 rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
901 {
902 gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR);
903 gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR);
904
905 if (subset == superset)
906 return true;
907
908 else
909 return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR);
910 }
911
912 #undef TARGET_ADDR_SPACE_CONVERT
913 #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
914 /* Convert from one address space to another. */
915 static rtx
916 rl78_addr_space_convert (rtx op, tree from_type, tree to_type)
917 {
918 addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
919 addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
920 rtx result;
921
922 gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR);
923 gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR);
924
925 if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR)
926 {
927 /* This is unpredictable, as we're truncating off usable address
928 bits. */
929
930 result = gen_reg_rtx (HImode);
931 emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0));
932 return result;
933 }
934 else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC)
935 {
936 /* This always works. */
937 result = gen_reg_rtx (SImode);
938 emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op);
939 emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx);
940 return result;
941 }
942 else
943 gcc_unreachable ();
944 }
945
946 /* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
947 bool
948 rl78_regno_mode_code_ok_for_base_p (int regno, enum machine_mode mode ATTRIBUTE_UNUSED,
949 addr_space_t address_space ATTRIBUTE_UNUSED,
950 int outer_code ATTRIBUTE_UNUSED, int index_code)
951 {
952 if (regno <= SP_REG && regno >= 16)
953 return true;
954 if (index_code == REG)
955 return (regno == HL_REG);
956 if (regno == C_REG || regno == B_REG || regno == E_REG || regno == L_REG)
957 return true;
958 return false;
959 }
960
961 /* Implements MODE_CODE_BASE_REG_CLASS. */
962 enum reg_class
963 rl78_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
964 addr_space_t address_space ATTRIBUTE_UNUSED,
965 int outer_code ATTRIBUTE_UNUSED,
966 int index_code ATTRIBUTE_UNUSED)
967 {
968 return V_REGS;
969 }
970
971 /* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
972 described in the machine_Function struct definition, above. */
973 int
974 rl78_initial_elimination_offset (int from, int to)
975 {
976 int rv = 0; /* as if arg to arg */
977
978 rl78_compute_frame_info ();
979
980 switch (to)
981 {
982 case STACK_POINTER_REGNUM:
983 rv += cfun->machine->framesize_outgoing;
984 rv += cfun->machine->framesize_locals;
985 /* Fall through. */
986 case FRAME_POINTER_REGNUM:
987 rv += cfun->machine->framesize_regs;
988 rv += 4;
989 break;
990 default:
991 gcc_unreachable ();
992 }
993
994 switch (from)
995 {
996 case FRAME_POINTER_REGNUM:
997 rv -= 4;
998 rv -= cfun->machine->framesize_regs;
999 case ARG_POINTER_REGNUM:
1000 break;
1001 default:
1002 gcc_unreachable ();
1003 }
1004
1005 return rv;
1006 }
1007
1008 static int
1009 rl78_is_naked_func (void)
1010 {
1011 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE);
1012 }
1013
1014 /* Expand the function prologue (from the prologue pattern). */
1015 void
1016 rl78_expand_prologue (void)
1017 {
1018 int i, fs;
1019 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
1020 int rb = 0;
1021
1022 if (rl78_is_naked_func ())
1023 return;
1024
1025 if (!cfun->machine->computed)
1026 rl78_compute_frame_info ();
1027
1028 if (flag_stack_usage_info)
1029 current_function_static_stack_size = cfun->machine->framesize;
1030
1031 if (is_interrupt_func (cfun->decl) && !TARGET_G10)
1032 emit_insn (gen_sel_rb (GEN_INT (0)));
1033
1034 for (i = 0; i < 16; i++)
1035 if (cfun->machine->need_to_push [i])
1036 {
1037 if (TARGET_G10)
1038 {
1039 emit_move_insn (gen_rtx_REG (HImode, 0), gen_rtx_REG (HImode, i*2));
1040 F (emit_insn (gen_push (gen_rtx_REG (HImode, 0))));
1041 }
1042 else {
1043 int need_bank = i/4;
1044 if (need_bank != rb)
1045 {
1046 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1047 rb = need_bank;
1048 }
1049 F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2))));
1050 }
1051 }
1052 if (rb != 0)
1053 emit_insn (gen_sel_rb (GEN_INT (0)));
1054
1055 if (frame_pointer_needed)
1056 {
1057 F (emit_move_insn (gen_rtx_REG (HImode, AX_REG),
1058 gen_rtx_REG (HImode, STACK_POINTER_REGNUM)));
1059 F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM),
1060 gen_rtx_REG (HImode, AX_REG)));
1061 }
1062
1063 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1064 while (fs > 0)
1065 {
1066 int fs_byte = (fs > 254) ? 254 : fs;
1067 F (emit_insn (gen_subhi3 (sp, sp, GEN_INT (fs_byte))));
1068 fs -= fs_byte;
1069 }
1070 }
1071
1072 /* Expand the function epilogue (from the epilogue pattern). */
1073 void
1074 rl78_expand_epilogue (void)
1075 {
1076 int i, fs;
1077 rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
1078 int rb = 0;
1079
1080 if (rl78_is_naked_func ())
1081 return;
1082
1083 if (frame_pointer_needed)
1084 {
1085 emit_move_insn (gen_rtx_REG (HImode, AX_REG),
1086 gen_rtx_REG (HImode, FRAME_POINTER_REGNUM));
1087 emit_move_insn (gen_rtx_REG (HImode, STACK_POINTER_REGNUM),
1088 gen_rtx_REG (HImode, AX_REG));
1089 }
1090 else
1091 {
1092 fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
1093 while (fs > 0)
1094 {
1095 int fs_byte = (fs > 254) ? 254 : fs;
1096
1097 emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte)));
1098 fs -= fs_byte;
1099 }
1100 }
1101
1102 for (i = 15; i >= 0; i--)
1103 if (cfun->machine->need_to_push [i])
1104 {
1105 if (TARGET_G10)
1106 {
1107 emit_insn (gen_pop (gen_rtx_REG (HImode, 0)));
1108 emit_move_insn (gen_rtx_REG (HImode, i*2), gen_rtx_REG (HImode, 0));
1109 }
1110 else
1111 {
1112 int need_bank = i / 4;
1113
1114 if (need_bank != rb)
1115 {
1116 emit_insn (gen_sel_rb (GEN_INT (need_bank)));
1117 rb = need_bank;
1118 }
1119 emit_insn (gen_pop (gen_rtx_REG (HImode, i * 2)));
1120 }
1121 }
1122
1123 if (rb != 0)
1124 emit_insn (gen_sel_rb (GEN_INT (0)));
1125
1126 if (cfun->machine->trampolines_used)
1127 emit_insn (gen_trampoline_uninit ());
1128
1129 if (is_brk_interrupt_func (cfun->decl))
1130 emit_jump_insn (gen_brk_interrupt_return ());
1131 else if (is_interrupt_func (cfun->decl))
1132 emit_jump_insn (gen_interrupt_return ());
1133 else
1134 emit_jump_insn (gen_rl78_return ());
1135 }
1136
1137 /* Likewise, for exception handlers. */
1138 void
1139 rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED)
1140 {
1141 /* FIXME - replace this with an indirect jump with stack adjust. */
1142 emit_jump_insn (gen_rl78_return ());
1143 }
1144
1145 #undef TARGET_ASM_FUNCTION_PROLOGUE
1146 #define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1147
1148 /* We don't use this to actually emit the function prologue. We use
1149 this to insert a comment in the asm file describing the
1150 function. */
1151 static void
1152 rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
1153 {
1154 int i;
1155
1156 if (cfun->machine->framesize == 0)
1157 return;
1158 fprintf (file, "\t; start of function\n");
1159
1160 if (cfun->machine->framesize_regs)
1161 {
1162 fprintf (file, "\t; push %d:", cfun->machine->framesize_regs);
1163 for (i = 0; i < 16; i ++)
1164 if (cfun->machine->need_to_push[i])
1165 fprintf (file, " %s", word_regnames[i*2]);
1166 fprintf (file, "\n");
1167 }
1168
1169 if (frame_pointer_needed)
1170 fprintf (file, "\t; $fp points here (r22)\n");
1171
1172 if (cfun->machine->framesize_locals)
1173 fprintf (file, "\t; locals: %d byte%s\n", cfun->machine->framesize_locals,
1174 cfun->machine->framesize_locals == 1 ? "" : "s");
1175
1176 if (cfun->machine->framesize_outgoing)
1177 fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing,
1178 cfun->machine->framesize_outgoing == 1 ? "" : "s");
1179 }
1180
1181 /* Return an RTL describing where a function return value of type RET_TYPE
1182 is held. */
1183
1184 #undef TARGET_FUNCTION_VALUE
1185 #define TARGET_FUNCTION_VALUE rl78_function_value
1186
1187 static rtx
1188 rl78_function_value (const_tree ret_type,
1189 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1190 bool outgoing ATTRIBUTE_UNUSED)
1191 {
1192 enum machine_mode mode = TYPE_MODE (ret_type);
1193
1194 return gen_rtx_REG (mode, 8);
1195 }
1196
1197 #undef TARGET_PROMOTE_FUNCTION_MODE
1198 #define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
1199
1200 static enum machine_mode
1201 rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
1202 enum machine_mode mode,
1203 int *punsignedp ATTRIBUTE_UNUSED,
1204 const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED)
1205 {
1206 return mode;
1207 }
1208
1209 /* Return an RTL expression describing the register holding a function
1210 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
1211 be passed on the stack. CUM describes the previous parameters to the
1212 function and NAMED is false if the parameter is part of a variable
1213 parameter list, or the last named parameter before the start of a
1214 variable parameter list. */
1215
1216 #undef TARGET_FUNCTION_ARG
1217 #define TARGET_FUNCTION_ARG rl78_function_arg
1218
1219 static rtx
1220 rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
1221 enum machine_mode mode ATTRIBUTE_UNUSED,
1222 const_tree type ATTRIBUTE_UNUSED,
1223 bool named ATTRIBUTE_UNUSED)
1224 {
1225 return NULL_RTX;
1226 }
1227
1228 #undef TARGET_FUNCTION_ARG_ADVANCE
1229 #define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1230
1231 static void
1232 rl78_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode, const_tree type,
1233 bool named ATTRIBUTE_UNUSED)
1234 {
1235 int rounded_size;
1236 CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
1237
1238 rounded_size = ((mode == BLKmode)
1239 ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
1240 if (rounded_size & 1)
1241 rounded_size ++;
1242 (*cum) += rounded_size;
1243 }
1244
1245 #undef TARGET_FUNCTION_ARG_BOUNDARY
1246 #define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1247
1248 static unsigned int
1249 rl78_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
1250 const_tree type ATTRIBUTE_UNUSED)
1251 {
1252 return 16;
1253 }
1254
1255 /* Supported modifier letters:
1256
1257 A - address of a MEM
1258 S - SADDR form of a real register
1259 v - real register corresponding to a virtual register
1260 m - minus - negative of CONST_INT value.
1261 c - inverse of a conditional (NE vs EQ for example)
1262 z - collapsed conditional
1263 s - shift count mod 8
1264 S - shift count mod 16
1265 r - reverse shift count (8-(count mod 8))
1266
1267 h - bottom HI of an SI
1268 H - top HI of an SI
1269 q - bottom QI of an HI
1270 Q - top QI of an HI
1271 e - third QI of an SI (i.e. where the ES register gets values from)
1272 E - fourth QI of an SI (i.e. MSB)
1273
1274 */
1275
1276 /* Implements the bulk of rl78_print_operand, below. We do it this
1277 way because we need to test for a constant at the top level and
1278 insert the '#', but not test for it anywhere else as we recurse
1279 down into the operand. */
1280 static void
1281 rl78_print_operand_1 (FILE * file, rtx op, int letter)
1282 {
1283 int need_paren;
1284
1285 switch (GET_CODE (op))
1286 {
1287 case MEM:
1288 if (letter == 'A')
1289 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1290 else
1291 {
1292 if (rl78_far_p (op))
1293 fprintf (file, "es:");
1294 if (letter == 'H')
1295 {
1296 op = adjust_address (op, HImode, 2);
1297 letter = 0;
1298 }
1299 if (letter == 'h')
1300 {
1301 op = adjust_address (op, HImode, 0);
1302 letter = 0;
1303 }
1304 if (letter == 'Q')
1305 {
1306 op = adjust_address (op, QImode, 1);
1307 letter = 0;
1308 }
1309 if (letter == 'q')
1310 {
1311 op = adjust_address (op, QImode, 0);
1312 letter = 0;
1313 }
1314 if (letter == 'e')
1315 {
1316 op = adjust_address (op, QImode, 2);
1317 letter = 0;
1318 }
1319 if (letter == 'E')
1320 {
1321 op = adjust_address (op, QImode, 3);
1322 letter = 0;
1323 }
1324 if (CONSTANT_P (XEXP (op, 0)))
1325 {
1326 fprintf (file, "!");
1327 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1328 }
1329 else if (GET_CODE (XEXP (op, 0)) == PLUS
1330 && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF)
1331 {
1332 fprintf (file, "!");
1333 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1334 }
1335 else if (GET_CODE (XEXP (op, 0)) == PLUS
1336 && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
1337 && REGNO (XEXP (XEXP (op, 0), 0)) == 2)
1338 {
1339 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u');
1340 fprintf (file, "[");
1341 rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0);
1342 fprintf (file, "]");
1343 }
1344 else
1345 {
1346 fprintf (file, "[");
1347 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1348 fprintf (file, "]");
1349 }
1350 }
1351 break;
1352
1353 case REG:
1354 if (letter == 'Q')
1355 fprintf (file, "%s", reg_names [REGNO (op) | 1]);
1356 else if (letter == 'H')
1357 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1358 else if (letter == 'q')
1359 fprintf (file, "%s", reg_names [REGNO (op) & ~1]);
1360 else if (letter == 'e')
1361 fprintf (file, "%s", reg_names [REGNO (op) + 2]);
1362 else if (letter == 'E')
1363 fprintf (file, "%s", reg_names [REGNO (op) + 3]);
1364 else if (letter == 'S')
1365 fprintf (file, "0x%x", 0xffef8 + REGNO (op));
1366 else if (GET_MODE (op) == HImode
1367 && ! (REGNO (op) & ~0xfe))
1368 {
1369 if (letter == 'v')
1370 fprintf (file, "%s", word_regnames [REGNO (op) % 8]);
1371 else
1372 fprintf (file, "%s", word_regnames [REGNO (op)]);
1373 }
1374 else
1375 fprintf (file, "%s", reg_names [REGNO (op)]);
1376 break;
1377
1378 case CONST_INT:
1379 if (letter == 'Q')
1380 fprintf (file, "%ld", INTVAL (op) >> 8);
1381 else if (letter == 'H')
1382 fprintf (file, "%ld", INTVAL (op) >> 16);
1383 else if (letter == 'q')
1384 fprintf (file, "%ld", INTVAL (op) & 0xff);
1385 else if (letter == 'h')
1386 fprintf (file, "%ld", INTVAL (op) & 0xffff);
1387 else if (letter == 'e')
1388 fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff);
1389 else if (letter == 'E')
1390 fprintf (file, "%ld", (INTVAL (op) >> 24) & 0xff);
1391 else if (letter == 'm')
1392 fprintf (file, "%ld", - INTVAL (op));
1393 else if (letter == 's')
1394 fprintf (file, "%ld", INTVAL (op) % 8);
1395 else if (letter == 'S')
1396 fprintf (file, "%ld", INTVAL (op) % 16);
1397 else if (letter == 'r')
1398 fprintf (file, "%ld", 8 - (INTVAL (op) % 8));
1399 else if (letter == 'C')
1400 fprintf (file, "%ld", (INTVAL (op) ^ 0x8000) & 0xffff);
1401 else
1402 fprintf (file, "%ld", INTVAL (op));
1403 break;
1404
1405 case CONST:
1406 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1407 break;
1408
1409 case ZERO_EXTRACT:
1410 {
1411 int bits = INTVAL (XEXP (op, 1));
1412 int ofs = INTVAL (XEXP (op, 2));
1413 if (bits == 16 && ofs == 0)
1414 fprintf (file, "%%lo16(");
1415 else if (bits == 16 && ofs == 16)
1416 fprintf (file, "%%hi16(");
1417 else if (bits == 8 && ofs == 16)
1418 fprintf (file, "%%hi8(");
1419 else
1420 gcc_unreachable ();
1421 rl78_print_operand_1 (file, XEXP (op, 0), 0);
1422 fprintf (file, ")");
1423 }
1424 break;
1425
1426 case ZERO_EXTEND:
1427 if (GET_CODE (XEXP (op, 0)) == REG)
1428 fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]);
1429 else
1430 print_rtl (file, op);
1431 break;
1432
1433 case PLUS:
1434 need_paren = 0;
1435 if (letter == 'H')
1436 {
1437 fprintf (file, "%%hi16(");
1438 need_paren = 1;
1439 letter = 0;
1440 }
1441 if (letter == 'h')
1442 {
1443 fprintf (file, "%%lo16(");
1444 need_paren = 1;
1445 letter = 0;
1446 }
1447 if (letter == 'e')
1448 {
1449 fprintf (file, "%%hi8(");
1450 need_paren = 1;
1451 letter = 0;
1452 }
1453 if (letter == 'q' || letter == 'Q')
1454 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1455
1456 if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
1457 {
1458 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1459 fprintf (file, "+");
1460 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1461 }
1462 else
1463 {
1464 rl78_print_operand_1 (file, XEXP (op, 0), letter);
1465 fprintf (file, "+");
1466 rl78_print_operand_1 (file, XEXP (op, 1), letter);
1467 }
1468 if (need_paren)
1469 fprintf (file, ")");
1470 break;
1471
1472 case SYMBOL_REF:
1473 need_paren = 0;
1474 if (letter == 'H')
1475 {
1476 fprintf (file, "%%hi16(");
1477 need_paren = 1;
1478 letter = 0;
1479 }
1480 if (letter == 'h')
1481 {
1482 fprintf (file, "%%lo16(");
1483 need_paren = 1;
1484 letter = 0;
1485 }
1486 if (letter == 'e')
1487 {
1488 fprintf (file, "%%hi8(");
1489 need_paren = 1;
1490 letter = 0;
1491 }
1492 if (letter == 'q' || letter == 'Q')
1493 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1494
1495 output_addr_const (file, op);
1496 if (need_paren)
1497 fprintf (file, ")");
1498 break;
1499
1500 case CODE_LABEL:
1501 case LABEL_REF:
1502 output_asm_label (op);
1503 break;
1504
1505 case LTU:
1506 if (letter == 'z')
1507 fprintf (file, "#comparison eliminated");
1508 else
1509 fprintf (file, letter == 'c' ? "nc" : "c");
1510 break;
1511 case LEU:
1512 if (letter == 'z')
1513 fprintf (file, "br");
1514 else
1515 fprintf (file, letter == 'c' ? "h" : "nh");
1516 break;
1517 case GEU:
1518 if (letter == 'z')
1519 fprintf (file, "br");
1520 else
1521 fprintf (file, letter == 'c' ? "c" : "nc");
1522 break;
1523 case GTU:
1524 if (letter == 'z')
1525 fprintf (file, "#comparison eliminated");
1526 else
1527 fprintf (file, letter == 'c' ? "nh" : "h");
1528 break;
1529 case EQ:
1530 if (letter == 'z')
1531 fprintf (file, "br");
1532 else
1533 fprintf (file, letter == 'c' ? "nz" : "z");
1534 break;
1535 case NE:
1536 if (letter == 'z')
1537 fprintf (file, "#comparison eliminated");
1538 else
1539 fprintf (file, letter == 'c' ? "z" : "nz");
1540 break;
1541
1542 /* Note: these assume appropriate adjustments were made so that
1543 unsigned comparisons, which is all this chip has, will
1544 work. */
1545 case LT:
1546 if (letter == 'z')
1547 fprintf (file, "#comparison eliminated");
1548 else
1549 fprintf (file, letter == 'c' ? "nc" : "c");
1550 break;
1551 case LE:
1552 if (letter == 'z')
1553 fprintf (file, "br");
1554 else
1555 fprintf (file, letter == 'c' ? "h" : "nh");
1556 break;
1557 case GE:
1558 if (letter == 'z')
1559 fprintf (file, "br");
1560 else
1561 fprintf (file, letter == 'c' ? "c" : "nc");
1562 break;
1563 case GT:
1564 if (letter == 'z')
1565 fprintf (file, "#comparison eliminated");
1566 else
1567 fprintf (file, letter == 'c' ? "nh" : "h");
1568 break;
1569
1570 default:
1571 fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
1572 break;
1573 }
1574 }
1575
1576 #undef TARGET_PRINT_OPERAND
1577 #define TARGET_PRINT_OPERAND rl78_print_operand
1578
1579 static void
1580 rl78_print_operand (FILE * file, rtx op, int letter)
1581 {
1582 if (CONSTANT_P (op) && letter != 'u' && letter != 's' && letter != 'r' && letter != 'S')
1583 fprintf (file, "#");
1584 rl78_print_operand_1 (file, op, letter);
1585 }
1586
1587 #undef TARGET_TRAMPOLINE_INIT
1588 #define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
1589
1590 /* Note that the RL78's addressing makes it very difficult to do
1591 trampolines on the stack. So, libgcc has a small pool of
1592 trampolines from which one is allocated to this task. */
1593 static void
1594 rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
1595 {
1596 rtx mov_addr, thunk_addr;
1597 rtx function = XEXP (DECL_RTL (fndecl), 0);
1598
1599 mov_addr = adjust_address (m_tramp, HImode, 0);
1600 thunk_addr = gen_reg_rtx (HImode);
1601
1602 function = force_reg (HImode, function);
1603 static_chain = force_reg (HImode, static_chain);
1604
1605 emit_insn (gen_trampoline_init (thunk_addr, function, static_chain));
1606 emit_move_insn (mov_addr, thunk_addr);
1607
1608 cfun->machine->trampolines_used = 1;
1609 }
1610
1611 #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
1612 #define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
1613
1614 static rtx
1615 rl78_trampoline_adjust_address (rtx m_tramp)
1616 {
1617 rtx x = gen_rtx_MEM (HImode, m_tramp);
1618 return x;
1619 }
1620 \f
1621 /* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
1622 the "normal" compares, specifically, it only has unsigned compares,
1623 so we must synthesize the missing ones. */
1624 void
1625 rl78_expand_compare (rtx *operands)
1626 {
1627 if (GET_CODE (operands[2]) == MEM)
1628 operands[2] = copy_to_mode_reg (GET_MODE (operands[2]), operands[2]);
1629 }
1630
1631 \f
1632
1633 /* Define this to 1 if you are debugging the peephole optimizers. */
1634 #define DEBUG_PEEP 0
1635
1636 /* Predicate used to enable the peephole2 patterns in rl78-virt.md.
1637 The default "word" size is a byte so we can effectively use all the
1638 registers, but we want to do 16-bit moves whenever possible. This
1639 function determines when such a move is an option. */
1640 bool
1641 rl78_peep_movhi_p (rtx *operands)
1642 {
1643 int i;
1644 rtx m, a;
1645
1646 /* (set (op0) (op1))
1647 (set (op2) (op3)) */
1648
1649 #if DEBUG_PEEP
1650 fprintf (stderr, "\033[33m");
1651 debug_rtx (operands[0]);
1652 debug_rtx (operands[1]);
1653 debug_rtx (operands[2]);
1654 debug_rtx (operands[3]);
1655 fprintf (stderr, "\033[0m");
1656 #endif
1657
1658 /* You can move a constant to memory as QImode, but not HImode. */
1659 if (GET_CODE (operands[0]) == MEM
1660 && GET_CODE (operands[1]) != REG)
1661 {
1662 #if DEBUG_PEEP
1663 fprintf (stderr, "no peep: move constant to memory\n");
1664 #endif
1665 return false;
1666 }
1667
1668 if (rtx_equal_p (operands[0], operands[3]))
1669 {
1670 #if DEBUG_PEEP
1671 fprintf (stderr, "no peep: overlapping\n");
1672 #endif
1673 return false;
1674 }
1675
1676 for (i = 0; i < 2; i ++)
1677 {
1678 if (GET_CODE (operands[i]) != GET_CODE (operands[i+2]))
1679 {
1680 #if DEBUG_PEEP
1681 fprintf (stderr, "no peep: different codes\n");
1682 #endif
1683 return false;
1684 }
1685 if (GET_MODE (operands[i]) != GET_MODE (operands[i+2]))
1686 {
1687 #if DEBUG_PEEP
1688 fprintf (stderr, "no peep: different modes\n");
1689 #endif
1690 return false;
1691 }
1692
1693 switch (GET_CODE (operands[i]))
1694 {
1695 case REG:
1696 /* LSB MSB */
1697 if (REGNO (operands[i]) + 1 != REGNO (operands[i+2])
1698 || GET_MODE (operands[i]) != QImode)
1699 {
1700 #if DEBUG_PEEP
1701 fprintf (stderr, "no peep: wrong regnos %d %d %d\n",
1702 REGNO (operands[i]), REGNO (operands[i+2]),
1703 i);
1704 #endif
1705 return false;
1706 }
1707 if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode))
1708 {
1709 #if DEBUG_PEEP
1710 fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i]));
1711 #endif
1712 return false;
1713 }
1714 break;
1715
1716 case CONST_INT:
1717 break;
1718
1719 case MEM:
1720 if (GET_MODE (operands[i]) != QImode)
1721 return false;
1722 if (MEM_ALIGN (operands[i]) < 16)
1723 return false;
1724 a = XEXP (operands[i], 0);
1725 if (GET_CODE (a) == CONST)
1726 a = XEXP (a, 0);
1727 if (GET_CODE (a) == PLUS)
1728 a = XEXP (a, 1);
1729 if (GET_CODE (a) == CONST_INT
1730 && INTVAL (a) & 1)
1731 {
1732 #if DEBUG_PEEP
1733 fprintf (stderr, "no peep: misaligned mem %d\n", i);
1734 debug_rtx (operands[i]);
1735 #endif
1736 return false;
1737 }
1738 m = adjust_address (operands[i], QImode, 1);
1739 if (! rtx_equal_p (m, operands[i+2]))
1740 {
1741 #if DEBUG_PEEP
1742 fprintf (stderr, "no peep: wrong mem %d\n", i);
1743 debug_rtx(m);
1744 debug_rtx (operands[i+2]);
1745 #endif
1746 return false;
1747 }
1748 break;
1749
1750 default:
1751 #if DEBUG_PEEP
1752 fprintf (stderr, "no peep: wrong rtx %d\n", i);
1753 #endif
1754 return false;
1755 }
1756 }
1757 #if DEBUG_PEEP
1758 fprintf (stderr, "\033[32mpeep!\033[0m\n");
1759 #endif
1760 return true;
1761 }
1762
1763 /* Likewise, when a peephole is activated, this function helps compute
1764 the new operands. */
1765 void
1766 rl78_setup_peep_movhi (rtx *operands)
1767 {
1768 int i;
1769
1770 for (i = 0; i < 2; i ++)
1771 {
1772 switch (GET_CODE (operands[i]))
1773 {
1774 case REG:
1775 operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i]));
1776 break;
1777
1778 case CONST_INT:
1779 operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char)INTVAL (operands[i+2])) * 256);
1780 break;
1781
1782 case MEM:
1783 operands[i+4] = adjust_address (operands[i], HImode, 0);
1784 break;
1785
1786 default:
1787 break;
1788 }
1789 }
1790 }
1791 \f
1792 /*
1793 How Devirtualization works in the RL78 GCC port
1794
1795 Background
1796
1797 The RL78 is an 8-bit port with some 16-bit operations. It has 32
1798 bytes of register space, in four banks, memory-mapped. One bank is
1799 the "selected" bank and holds the registers used for primary
1800 operations. Since the registers are memory mapped, often you can
1801 still refer to the unselected banks via memory accesses.
1802
1803 Virtual Registers
1804
1805 The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
1806 and refers to the other banks via their memory addresses, although
1807 they're treated as regular registers internally. These "virtual"
1808 registers are R8 through R23 (bank3 is reserved for asm-based
1809 interrupt handlers).
1810
1811 There are four machine description files:
1812
1813 rl78.md - common register-independent patterns and definitions
1814 rl78-expand.md - expanders
1815 rl78-virt.md - patterns that match BEFORE devirtualization
1816 rl78-real.md - patterns that match AFTER devirtualization
1817
1818 At least through register allocation and reload, gcc is told that it
1819 can do pretty much anything - but may only use the virtual registers.
1820 GCC cannot properly create the varying addressing modes that the RL78
1821 supports in an efficient way.
1822
1823 Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
1824 uses the "valloc" attribute in rl78-virt.md for determining the rules
1825 by which it will replace virtual registers with real registers (or
1826 not) and how to make up addressing modes. For example, insns tagged
1827 with "ro1" have a single read-only parameter, which may need to be
1828 moved from memory/constant/vreg to a suitable real register. As part
1829 of devirtualization, a flag is toggled, disabling the rl78-virt.md
1830 patterns and enabling the rl78-real.md patterns. The new patterns'
1831 constraints are used to determine the real registers used. NOTE:
1832 patterns in rl78-virt.md essentially ignore the constrains and rely on
1833 predicates, where the rl78-real.md ones essentially ignore the
1834 predicates and rely on the constraints.
1835
1836 The devirtualization pass is scheduled via the pass manager (despite
1837 being called "rl78_reorg") so it can be scheduled prior to var-track
1838 (the idea is to let gdb know about the new registers). Ideally, it
1839 would be scheduled right after pro/epilogue generation, so the
1840 post-reload optimizers could operate on the real registers, but when I
1841 tried that there were some issues building the target libraries.
1842
1843 During devirtualization, a simple register move optimizer is run. It
1844 would be better to run a full CSE/propogation pass on it through, or
1845 re-run regmove, but that has not yet been attempted.
1846
1847 */
1848 #define DEBUG_ALLOC 0
1849
1850 /* This array is used to hold knowledge about the contents of the
1851 real registers (A ... H), the memory-based registers (r8 ... r31)
1852 and the first NUM_STACK_LOCS words on the stack. We use this to
1853 avoid generating redundant move instructions.
1854
1855 A value in the range 0 .. 31 indicates register A .. r31.
1856 A value in the range 32 .. 63 indicates stack slot (value - 32).
1857 A value of NOT_KNOWN indicates that the contents of that location
1858 are not known. */
1859
1860 #define NUM_STACK_LOCS 32
1861 #define NOT_KNOWN 127
1862
1863 static unsigned char content_memory [32 + NUM_STACK_LOCS];
1864
1865 static unsigned char saved_update_index = NOT_KNOWN;
1866 static unsigned char saved_update_value;
1867 static enum machine_mode saved_update_mode;
1868
1869
1870 static inline void
1871 clear_content_memory (void)
1872 {
1873 memset (content_memory, NOT_KNOWN, sizeof content_memory);
1874 if (dump_file)
1875 fprintf (dump_file, " clear content memory\n");
1876 saved_update_index = NOT_KNOWN;
1877 }
1878
1879 /* Convert LOC into an index into the content_memory array.
1880 If LOC cannot be converted, return NOT_KNOWN. */
1881
1882 static unsigned char
1883 get_content_index (rtx loc)
1884 {
1885 enum machine_mode mode;
1886
1887 if (loc == NULL_RTX)
1888 return NOT_KNOWN;
1889
1890 if (REG_P (loc))
1891 {
1892 if (REGNO (loc) < 32)
1893 return REGNO (loc);
1894 return NOT_KNOWN;
1895 }
1896
1897 mode = GET_MODE (loc);
1898
1899 if (! rl78_stack_based_mem (loc, mode))
1900 return NOT_KNOWN;
1901
1902 loc = XEXP (loc, 0);
1903
1904 if (REG_P (loc))
1905 /* loc = MEM (SP) */
1906 return 32;
1907
1908 /* loc = MEM (PLUS (SP, INT)). */
1909 loc = XEXP (loc, 1);
1910
1911 if (INTVAL (loc) < NUM_STACK_LOCS)
1912 return 32 + INTVAL (loc);
1913
1914 return NOT_KNOWN;
1915 }
1916
1917 /* Return a string describing content INDEX in mode MODE.
1918 WARNING: Can return a pointer to a static buffer. */
1919
1920 static const char *
1921 get_content_name (unsigned char index, enum machine_mode mode)
1922 {
1923 static char buffer [128];
1924
1925 if (index == NOT_KNOWN)
1926 return "Unknown";
1927
1928 if (index > 31)
1929 sprintf (buffer, "stack slot %d", index - 32);
1930 else if (mode == HImode)
1931 sprintf (buffer, "%s%s",
1932 reg_names [index + 1], reg_names [index]);
1933 else
1934 return reg_names [index];
1935
1936 return buffer;
1937 }
1938
1939 #if DEBUG_ALLOC
1940
1941 static void
1942 display_content_memory (FILE * file)
1943 {
1944 unsigned int i;
1945
1946 fprintf (file, " Known memory contents:\n");
1947
1948 for (i = 0; i < sizeof content_memory; i++)
1949 if (content_memory[i] != NOT_KNOWN)
1950 {
1951 fprintf (file, " %s contains a copy of ", get_content_name (i, QImode));
1952 fprintf (file, "%s\n", get_content_name (content_memory [i], QImode));
1953 }
1954 }
1955 #endif
1956
1957 static void
1958 update_content (unsigned char index, unsigned char val, enum machine_mode mode)
1959 {
1960 unsigned int i;
1961
1962 gcc_assert (index < sizeof content_memory);
1963
1964 content_memory [index] = val;
1965 if (val != NOT_KNOWN)
1966 content_memory [val] = index;
1967
1968 /* Make the entry in dump_file *before* VAL is increased below. */
1969 if (dump_file)
1970 {
1971 fprintf (dump_file, " %s now contains ", get_content_name (index, mode));
1972 if (val == NOT_KNOWN)
1973 fprintf (dump_file, "Unknown\n");
1974 else
1975 fprintf (dump_file, "%s and vice versa\n", get_content_name (val, mode));
1976 }
1977
1978 if (mode == HImode)
1979 {
1980 val = val == NOT_KNOWN ? val : val + 1;
1981
1982 content_memory [index + 1] = val;
1983 if (val != NOT_KNOWN)
1984 {
1985 content_memory [val] = index + 1;
1986 -- val;
1987 }
1988 }
1989
1990 /* Any other places that had INDEX recorded as their contents are now invalid. */
1991 for (i = 0; i < sizeof content_memory; i++)
1992 {
1993 if (i == index
1994 || (val != NOT_KNOWN && i == val))
1995 {
1996 if (mode == HImode)
1997 ++ i;
1998 continue;
1999 }
2000
2001 if (content_memory[i] == index
2002 || (val != NOT_KNOWN && content_memory[i] == val))
2003 {
2004 content_memory[i] = NOT_KNOWN;
2005
2006 if (dump_file)
2007 fprintf (dump_file, " %s cleared\n", get_content_name (i, mode));
2008
2009 if (mode == HImode)
2010 content_memory[++ i] = NOT_KNOWN;
2011 }
2012 }
2013 }
2014
2015 /* Record that LOC contains VALUE.
2016 For HImode locations record that LOC+1 contains VALUE+1.
2017 If LOC is not a register or stack slot, do nothing.
2018 If VALUE is not a register or stack slot, clear the recorded content. */
2019
2020 static void
2021 record_content (rtx loc, rtx value)
2022 {
2023 enum machine_mode mode;
2024 unsigned char index;
2025 unsigned char val;
2026
2027 if ((index = get_content_index (loc)) == NOT_KNOWN)
2028 return;
2029
2030 val = get_content_index (value);
2031
2032 mode = GET_MODE (loc);
2033
2034 if (val == index)
2035 {
2036 if (! optimize)
2037 return;
2038
2039 /* This should not happen when optimizing. */
2040 #if 1
2041 fprintf (stderr, "ASSIGNMENT of location to itself detected! [%s]\n",
2042 get_content_name (val, mode));
2043 return;
2044 #else
2045 gcc_unreachable ();
2046 #endif
2047 }
2048
2049 update_content (index, val, mode);
2050 }
2051
2052 /* Returns TRUE if LOC already contains a copy of VALUE. */
2053
2054 static bool
2055 already_contains (rtx loc, rtx value)
2056 {
2057 unsigned char index;
2058 unsigned char val;
2059
2060 if ((index = get_content_index (loc)) == NOT_KNOWN)
2061 return false;
2062
2063 if ((val = get_content_index (value)) == NOT_KNOWN)
2064 return false;
2065
2066 if (content_memory [index] != val)
2067 return false;
2068
2069 if (GET_MODE (loc) == HImode)
2070 return content_memory [index + 1] == val + 1;
2071
2072 return true;
2073 }
2074
2075 /* Rescans an insn to see if it's recognized again. This is done
2076 carefully to ensure that all the constraint information is accurate
2077 for the newly matched insn. */
2078 static bool
2079 insn_ok_now (rtx insn)
2080 {
2081 rtx pattern = PATTERN (insn);
2082
2083 INSN_CODE (insn) = -1;
2084
2085 if (recog (pattern, insn, 0) > -1)
2086 {
2087 extract_insn (insn);
2088 if (constrain_operands (1))
2089 {
2090 #if DEBUG_ALLOC
2091 fprintf (stderr, "\033[32m");
2092 debug_rtx (insn);
2093 fprintf (stderr, "\033[0m");
2094 #endif
2095 if (SET_P (pattern))
2096 record_content (SET_DEST (pattern), SET_SRC (pattern));
2097
2098 return true;
2099 }
2100 }
2101 else
2102 {
2103 /* We need to re-recog the insn with virtual registers to get
2104 the operands */
2105 cfun->machine->virt_insns_ok = 1;
2106 if (recog (pattern, insn, 0) > -1)
2107 {
2108 extract_insn (insn);
2109 if (constrain_operands (0))
2110 {
2111 cfun->machine->virt_insns_ok = 0;
2112 return false;
2113 }
2114 }
2115
2116 #if DEBUG_ALLOC
2117 fprintf (stderr, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
2118 debug_rtx (insn);
2119 #endif
2120 gcc_unreachable ();
2121 }
2122
2123 #if DEBUG_ALLOC
2124 fprintf (stderr, "\033[31m");
2125 debug_rtx (insn);
2126 fprintf (stderr, "\033[0m");
2127 #endif
2128 return false;
2129 }
2130
2131 #if DEBUG_ALLOC
2132 #define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
2133 #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
2134 #define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable()
2135 #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
2136 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
2137 #else
2138 #define FAILED gcc_unreachable ()
2139 #define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
2140 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
2141 #endif
2142
2143 /* Registers into which we move the contents of virtual registers. */
2144 #define X gen_rtx_REG (QImode, 0)
2145 #define A gen_rtx_REG (QImode, 1)
2146 #define C gen_rtx_REG (QImode, 2)
2147 #define B gen_rtx_REG (QImode, 3)
2148 #define E gen_rtx_REG (QImode, 4)
2149 #define D gen_rtx_REG (QImode, 5)
2150 #define L gen_rtx_REG (QImode, 6)
2151 #define H gen_rtx_REG (QImode, 7)
2152
2153 #define AX gen_rtx_REG (HImode, 0)
2154 #define BC gen_rtx_REG (HImode, 2)
2155 #define DE gen_rtx_REG (HImode, 4)
2156 #define HL gen_rtx_REG (HImode, 6)
2157
2158 #define OP(x) (*recog_data.operand_loc[x])
2159
2160 /* Returns TRUE if R is a virtual register. */
2161 static bool
2162 is_virtual_register (rtx r)
2163 {
2164 return (GET_CODE (r) == REG
2165 && REGNO (r) >= 8
2166 && REGNO (r) < 24);
2167 }
2168
2169 /* In all these alloc routines, we expect the following: the insn
2170 pattern is unshared, the insn was previously recognized and failed
2171 due to predicates or constraints, and the operand data is in
2172 recog_data. */
2173
2174 static int virt_insn_was_frame;
2175
2176 /* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2177 needed. */
2178 static rtx
2179 EM2 (int line ATTRIBUTE_UNUSED, rtx r)
2180 {
2181 #if DEBUG_ALLOC
2182 fprintf (stderr, "\033[36m%d: ", line);
2183 debug_rtx(r);
2184 fprintf (stderr, "\033[0m");
2185 #endif
2186 /*SCHED_GROUP_P (r) = 1;*/
2187 if (virt_insn_was_frame)
2188 RTX_FRAME_RELATED_P (r) = 1;
2189 return r;
2190 }
2191
2192 #define EM(x) EM2 (__LINE__, x)
2193
2194 /* Return a suitable RTX for the low half of a __far address. */
2195 static rtx
2196 rl78_lo16 (rtx addr)
2197 {
2198 if (GET_CODE (addr) == SYMBOL_REF
2199 || GET_CODE (addr) == CONST)
2200 {
2201 rtx r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0));
2202 r = gen_rtx_CONST (HImode, r);
2203 return r;
2204 }
2205 return rl78_subreg (HImode, addr, SImode, 0);
2206 }
2207
2208 /* Return a suitable RTX for the high half's lower byte of a __far address. */
2209 static rtx
2210 rl78_hi8 (rtx addr)
2211 {
2212 if (GET_CODE (addr) == SYMBOL_REF
2213 || GET_CODE (addr) == CONST)
2214 {
2215 rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16));
2216 r = gen_rtx_CONST (QImode, r);
2217 return r;
2218 }
2219 return rl78_subreg (QImode, addr, SImode, 2);
2220 }
2221
2222 static void
2223 add_postponed_content_update (rtx to, rtx value)
2224 {
2225 unsigned char index;
2226
2227 if ((index = get_content_index (to)) == NOT_KNOWN)
2228 return;
2229
2230 gcc_assert (saved_update_index == NOT_KNOWN);
2231 saved_update_index = index;
2232 saved_update_value = get_content_index (value);
2233 saved_update_mode = GET_MODE (to);
2234 }
2235
2236 static void
2237 process_postponed_content_update (void)
2238 {
2239 if (saved_update_index != NOT_KNOWN)
2240 {
2241 update_content (saved_update_index, saved_update_value, saved_update_mode);
2242 saved_update_index = NOT_KNOWN;
2243 }
2244 }
2245
2246 /* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2247 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2248 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2249 BEFORE is true, FROM otherwise. */
2250 static rtx
2251 gen_and_emit_move (rtx to, rtx from, rtx where, bool before)
2252 {
2253 enum machine_mode mode = GET_MODE (to);
2254
2255 if (optimize && before && already_contains (to, from))
2256 {
2257 #if DEBUG_ALLOC
2258 display_content_memory (stderr);
2259 #endif
2260 if (dump_file)
2261 {
2262 fprintf (dump_file, " Omit move of %s into ",
2263 get_content_name (get_content_index (from), mode));
2264 fprintf (dump_file, "%s as it already contains this value\n",
2265 get_content_name (get_content_index (to), mode));
2266 }
2267 }
2268 else
2269 {
2270 rtx move = mode == QImode ? gen_movqi (to, from) : gen_movhi (to, from);
2271
2272 EM (move);
2273
2274 if (where == NULL_RTX)
2275 emit_insn (move);
2276 else if (before)
2277 emit_insn_before (move, where);
2278 else
2279 {
2280 rtx note = find_reg_note (where, REG_EH_REGION, NULL_RTX);
2281
2282 /* If necessary move REG_EH_REGION notes forward.
2283 cf. compiling gcc.dg/pr44545.c. */
2284 if (note != NULL_RTX)
2285 {
2286 add_reg_note (move, REG_EH_REGION, XEXP (note, 0));
2287 remove_note (where, note);
2288 }
2289
2290 emit_insn_after (move, where);
2291 }
2292
2293 if (before)
2294 record_content (to, from);
2295 else
2296 add_postponed_content_update (to, from);
2297 }
2298 return before ? to : from;
2299 }
2300
2301 /* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2302 copy it into NEWBASE and return the updated MEM. Otherwise just
2303 return M. Any needed insns are emitted before BEFORE. */
2304 static rtx
2305 transcode_memory_rtx (rtx m, rtx newbase, rtx before)
2306 {
2307 rtx base, index, addendr;
2308 int addend = 0;
2309
2310 if (! MEM_P (m))
2311 return m;
2312
2313 if (GET_MODE (XEXP (m, 0)) == SImode)
2314 {
2315 rtx seg = rl78_hi8 (XEXP (m, 0));
2316 #if DEBUG_ALLOC
2317 fprintf (stderr, "setting ES:\n");
2318 debug_rtx(seg);
2319 #endif
2320 emit_insn_before (EM (gen_movqi (A, seg)), before);
2321 emit_insn_before (EM (gen_movqi_es (A)), before);
2322 record_content (A, NULL_RTX);
2323
2324 m = change_address (m, GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
2325 }
2326
2327 characterize_address (XEXP (m, 0), & base, & index, & addendr);
2328 gcc_assert (index == NULL_RTX);
2329
2330 #if DEBUG_ALLOC
2331 fprintf (stderr, "\033[33m"); debug_rtx (m); fprintf (stderr, "\033[0m");
2332 debug_rtx (base);
2333 #endif
2334 if (base == NULL_RTX)
2335 return m;
2336
2337 if (addendr && GET_CODE (addendr) == CONST_INT)
2338 addend = INTVAL (addendr);
2339
2340 gcc_assert (REG_P (base));
2341 gcc_assert (REG_P (newbase));
2342
2343 if (REGNO (base) == SP_REG)
2344 {
2345 if (addend >= 0 && addend <= 255)
2346 return m;
2347 }
2348
2349 /* BASE should be a virtual register. We copy it to NEWBASE. If
2350 the addend is out of range for DE/HL, we use AX to compute the full
2351 address. */
2352
2353 if (addend < 0
2354 || (addend > 255 && REGNO (newbase) != 2)
2355 || (addendr && GET_CODE (addendr) != CONST_INT))
2356 {
2357 /* mov ax, vreg
2358 add ax, #imm
2359 mov hl, ax */
2360 EM (emit_insn_before (gen_movhi (AX, base), before));
2361 EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before));
2362 EM (emit_insn_before (gen_movhi (newbase, AX), before));
2363 record_content (AX, NULL_RTX);
2364 record_content (newbase, NULL_RTX);
2365
2366 base = newbase;
2367 addend = 0;
2368 }
2369 else
2370 {
2371 base = gen_and_emit_move (newbase, base, before, true);
2372 }
2373
2374 if (addend)
2375 {
2376 record_content (base, NULL_RTX);
2377 base = gen_rtx_PLUS (HImode, base, GEN_INT (addend));
2378 }
2379
2380 #if DEBUG_ALLOC
2381 fprintf (stderr, "\033[33m");
2382 debug_rtx (m);
2383 #endif
2384 m = change_address (m, GET_MODE (m), base);
2385 #if DEBUG_ALLOC
2386 debug_rtx (m);
2387 fprintf (stderr, "\033[0m");
2388 #endif
2389 return m;
2390 }
2391
2392 /* Copy SRC to accumulator (A or AX), placing any generated insns
2393 before BEFORE. Returns accumulator RTX. */
2394
2395 static rtx
2396 move_to_acc (int opno, rtx before)
2397 {
2398 rtx src = OP (opno);
2399 enum machine_mode mode = GET_MODE (src);
2400
2401 if (REG_P (src) && REGNO (src) < 2)
2402 return src;
2403
2404 if (mode == VOIDmode)
2405 mode = recog_data.operand_mode[opno];
2406
2407 return gen_and_emit_move (mode == QImode ? A : AX, src, before, true);
2408 }
2409
2410 static void
2411 force_into_acc (rtx src, rtx before)
2412 {
2413 enum machine_mode mode = GET_MODE (src);
2414 rtx move;
2415
2416 if (REG_P (src) && REGNO (src) < 2)
2417 return;
2418
2419 move = mode == QImode ? gen_movqi (A, src) : gen_movhi (AX, src);
2420
2421 EM (move);
2422
2423 emit_insn_before (move, before);
2424 record_content (AX, NULL_RTX);
2425 }
2426
2427 /* Copy accumulator (A or AX) to DEST, placing any generated insns
2428 after AFTER. Returns accumulator RTX. */
2429
2430 static rtx
2431 move_from_acc (unsigned int opno, rtx after)
2432 {
2433 rtx dest = OP (opno);
2434 enum machine_mode mode = GET_MODE (dest);
2435
2436 if (REG_P (dest) && REGNO (dest) < 2)
2437 return dest;
2438
2439 return gen_and_emit_move (dest, mode == QImode ? A : AX, after, false);
2440 }
2441
2442 /* Copy accumulator (A or AX) to REGNO, placing any generated insns
2443 before BEFORE. Returns reg RTX. */
2444
2445 static rtx
2446 move_acc_to_reg (rtx acc, int regno, rtx before)
2447 {
2448 enum machine_mode mode = GET_MODE (acc);
2449 rtx reg;
2450
2451 reg = gen_rtx_REG (mode, regno);
2452
2453 return gen_and_emit_move (reg, acc, before, true);
2454 }
2455
2456 /* Copy SRC to X, placing any generated insns before BEFORE.
2457 Returns X RTX. */
2458
2459 static rtx
2460 move_to_x (int opno, rtx before)
2461 {
2462 rtx src = OP (opno);
2463 enum machine_mode mode = GET_MODE (src);
2464 rtx reg;
2465
2466 if (mode == VOIDmode)
2467 mode = recog_data.operand_mode[opno];
2468 reg = (mode == QImode) ? X : AX;
2469
2470 if (mode == QImode || ! is_virtual_register (OP (opno)))
2471 {
2472 OP (opno) = move_to_acc (opno, before);
2473 OP (opno) = move_acc_to_reg (OP(opno), X_REG, before);
2474 return reg;
2475 }
2476
2477 return gen_and_emit_move (reg, src, before, true);
2478 }
2479
2480 /* Copy OP(opno) to H or HL, placing any generated insns before BEFORE.
2481 Returns H/HL RTX. */
2482
2483 static rtx
2484 move_to_hl (int opno, rtx before)
2485 {
2486 rtx src = OP (opno);
2487 enum machine_mode mode = GET_MODE (src);
2488 rtx reg;
2489
2490 if (mode == VOIDmode)
2491 mode = recog_data.operand_mode[opno];
2492 reg = (mode == QImode) ? L : HL;
2493
2494 if (mode == QImode || ! is_virtual_register (OP (opno)))
2495 {
2496 OP (opno) = move_to_acc (opno, before);
2497 OP (opno) = move_acc_to_reg (OP (opno), L_REG, before);
2498 return reg;
2499 }
2500
2501 return gen_and_emit_move (reg, src, before, true);
2502 }
2503
2504 /* Copy OP(opno) to E or DE, placing any generated insns before BEFORE.
2505 Returns E/DE RTX. */
2506
2507 static rtx
2508 move_to_de (int opno, rtx before)
2509 {
2510 rtx src = OP (opno);
2511 enum machine_mode mode = GET_MODE (src);
2512 rtx reg;
2513
2514 if (mode == VOIDmode)
2515 mode = recog_data.operand_mode[opno];
2516
2517 reg = (mode == QImode) ? E : DE;
2518
2519 if (mode == QImode || ! is_virtual_register (OP (opno)))
2520 {
2521 OP (opno) = move_to_acc (opno, before);
2522 OP (opno) = move_acc_to_reg (OP (opno), E_REG, before);
2523 }
2524 else
2525 {
2526 gen_and_emit_move (reg, src, before, true);
2527 }
2528
2529 return reg;
2530 }
2531
2532 /* Devirtualize an insn of the form (SET (op) (unop (op))). */
2533 static void
2534 rl78_alloc_physical_registers_op1 (rtx insn)
2535 {
2536 /* op[0] = func op[1] */
2537
2538 /* We first try using A as the destination, then copying it
2539 back. */
2540 if (rtx_equal_p (OP (0), OP (1)))
2541 {
2542 OP (0) =
2543 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
2544 }
2545 else
2546 {
2547 /* If necessary, load the operands into BC and HL.
2548 Check to see if we already have OP (0) in HL
2549 and if so, swap the order. */
2550 if (MEM_P (OP (0))
2551 && already_contains (HL, XEXP (OP (0), 0)))
2552 {
2553 OP (0) = transcode_memory_rtx (OP (0), HL, insn);
2554 OP (1) = transcode_memory_rtx (OP (1), BC, insn);
2555 }
2556 else
2557 {
2558 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
2559 OP (1) = transcode_memory_rtx (OP (1), HL, insn);
2560 }
2561 }
2562
2563 MAYBE_OK (insn);
2564
2565 OP (0) = move_from_acc (0, insn);
2566
2567 MAYBE_OK (insn);
2568
2569 /* Try copying the src to acc first, then. This is for, for
2570 example, ZERO_EXTEND or NOT. */
2571 OP (1) = move_to_acc (1, insn);
2572
2573 MUST_BE_OK (insn);
2574 }
2575
2576 /* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
2577 Assumes that the current insn has already been recognised and hence the
2578 constraint data has been filled in. */
2579 static bool
2580 has_constraint (unsigned int opnum, enum constraint_num constraint)
2581 {
2582 const char * p = recog_data.constraints[opnum];
2583
2584 /* No constraints means anything is accepted. */
2585 if (p == NULL || *p == 0 || *p == ',')
2586 return true;
2587
2588 do
2589 {
2590 char c;
2591 unsigned int len;
2592
2593 c = *p;
2594 len = CONSTRAINT_LEN (c, p);
2595 gcc_assert (len > 0);
2596
2597 switch (c)
2598 {
2599 case 0:
2600 case ',':
2601 return false;
2602 default:
2603 if (lookup_constraint (p) == constraint)
2604 return true;
2605 }
2606 p += len;
2607 }
2608 while (1);
2609 }
2610
2611 /* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
2612 static void
2613 rl78_alloc_physical_registers_op2 (rtx insn)
2614 {
2615 rtx prev;
2616 rtx first;
2617 bool hl_used;
2618 int tmp_id;
2619 rtx saved_op1;
2620
2621 if (rtx_equal_p (OP (0), OP (1)))
2622 {
2623 OP (0) =
2624 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
2625 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
2626 }
2627 else if (rtx_equal_p (OP (0), OP (2)))
2628 {
2629 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
2630 OP (0) =
2631 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
2632 }
2633 else
2634 {
2635 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
2636 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
2637 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
2638 }
2639
2640 MAYBE_OK (insn);
2641
2642 prev = prev_nonnote_nondebug_insn (insn);
2643 if (recog_data.constraints[1][0] == '%'
2644 && is_virtual_register (OP (1))
2645 && ! is_virtual_register (OP (2))
2646 && ! CONSTANT_P (OP (2)))
2647 {
2648 rtx tmp = OP (1);
2649 OP (1) = OP (2);
2650 OP (2) = tmp;
2651 }
2652
2653 /* Make a note of whether (H)L is being used. It matters
2654 because if OP (2) alsoneeds reloading, then we must take
2655 care not to corrupt HL. */
2656 hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1));
2657
2658 /* If HL is not currently being used and dest == op1 then there are
2659 some possible optimizations available by reloading one of the
2660 operands into HL, before trying to use the accumulator. */
2661 if (optimize
2662 && ! hl_used
2663 && rtx_equal_p (OP (0), OP (1)))
2664 {
2665 /* If op0 is a Ws1 type memory address then switching the base
2666 address register to HL might allow us to perform an in-memory
2667 operation. (eg for the INCW instruction).
2668
2669 FIXME: Adding the move into HL is costly if this optimization is not
2670 going to work, so for now, make sure that we know that the new insn will
2671 match the requirements of the addhi3_real pattern. Really we ought to
2672 generate a candidate sequence, test that, and then install it if the
2673 results are good. */
2674 if (satisfies_constraint_Ws1 (OP (0))
2675 && has_constraint (0, CONSTRAINT_Wh1)
2676 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
2677 {
2678 rtx base, index, addend, newbase;
2679
2680 characterize_address (XEXP (OP (0), 0), & base, & index, & addend);
2681 gcc_assert (index == NULL_RTX);
2682 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
2683
2684 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
2685 if (addend != NULL_RTX)
2686 {
2687 newbase = gen_and_emit_move (HL, base, insn, true);
2688 record_content (newbase, NULL_RTX);
2689 newbase = gen_rtx_PLUS (HImode, newbase, addend);
2690
2691 OP (0) = OP (1) = change_address (OP (0), VOIDmode, newbase);
2692
2693 /* We do not want to fail here as this means that
2694 we have inserted useless insns into the stream. */
2695 MUST_BE_OK (insn);
2696 }
2697 }
2698 else if (REG_P (OP (0))
2699 && satisfies_constraint_Ws1 (OP (2))
2700 && has_constraint (2, CONSTRAINT_Wh1))
2701 {
2702 rtx base, index, addend, newbase;
2703
2704 characterize_address (XEXP (OP (2), 0), & base, & index, & addend);
2705 gcc_assert (index == NULL_RTX);
2706 gcc_assert (REG_P (base) && REGNO (base) == SP_REG);
2707
2708 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
2709 if (addend != NULL_RTX)
2710 {
2711 gen_and_emit_move (HL, base, insn, true);
2712
2713 if (REGNO (OP (0)) != X_REG)
2714 {
2715 OP (1) = move_to_acc (1, insn);
2716 OP (0) = move_from_acc (0, insn);
2717 }
2718
2719 record_content (HL, NULL_RTX);
2720 newbase = gen_rtx_PLUS (HImode, HL, addend);
2721
2722 OP (2) = change_address (OP (2), VOIDmode, newbase);
2723
2724 /* We do not want to fail here as this means that
2725 we have inserted useless insns into the stream. */
2726 MUST_BE_OK (insn);
2727 }
2728 }
2729 }
2730
2731
2732 OP (0) = move_from_acc (0, insn);
2733
2734 tmp_id = get_max_insn_count ();
2735 saved_op1 = OP (1);
2736
2737 if (rtx_equal_p (OP (1), OP (2)))
2738 OP (2) = OP (1) = move_to_acc (1, insn);
2739 else
2740 OP (1) = move_to_acc (1, insn);
2741
2742 MAYBE_OK (insn);
2743
2744 /* If we omitted the move of OP1 into the accumulator (because
2745 it was already there from a previous insn), then force the
2746 generation of the move instruction now. We know that we
2747 are about to emit a move into HL (or DE) via AX, and hence
2748 our optimization to remove the load of OP1 is no longer valid. */
2749 if (tmp_id == get_max_insn_count ())
2750 force_into_acc (saved_op1, insn);
2751
2752 /* We have to copy op2 to HL (or DE), but that involves AX, which
2753 already has a live value. Emit it before those insns. */
2754
2755 if (prev)
2756 first = next_nonnote_nondebug_insn (prev);
2757 else
2758 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
2759 ;
2760
2761 OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first);
2762
2763 MUST_BE_OK (insn);
2764 }
2765
2766 /* Devirtualize an insn of the form SET (PC) (MEM/REG). */
2767
2768 static void
2769 rl78_alloc_physical_registers_ro1 (rtx insn)
2770 {
2771 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
2772
2773 MAYBE_OK (insn);
2774
2775 OP (0) = move_to_acc (0, insn);
2776
2777 MUST_BE_OK (insn);
2778 }
2779
2780 /* Devirtualize a compare insn. */
2781
2782 static void
2783 rl78_alloc_physical_registers_cmp (rtx insn)
2784 {
2785 int tmp_id;
2786 rtx saved_op1;
2787 rtx prev = prev_nonnote_nondebug_insn (insn);
2788 rtx first;
2789
2790 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
2791 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
2792
2793 /* HI compares have to have OP(1) in AX, but QI
2794 compares do not, so it is worth checking here. */
2795 MAYBE_OK (insn);
2796
2797 /* For an HImode compare, OP(1) must always be in AX.
2798 But if OP(1) is a REG (and not AX), then we can avoid
2799 a reload of OP(1) if we reload OP(2) into AX and invert
2800 the comparison. */
2801 if (REG_P (OP (1))
2802 && REGNO (OP (1)) != AX_REG
2803 && GET_MODE (OP (1)) == HImode
2804 && MEM_P (OP (2)))
2805 {
2806 rtx cmp = XEXP (SET_SRC (PATTERN (insn)), 0);
2807
2808 OP (2) = move_to_acc (2, insn);
2809
2810 switch (GET_CODE (cmp))
2811 {
2812 case EQ:
2813 case NE:
2814 break;
2815 case LTU: cmp = gen_rtx_GTU (HImode, OP (2), OP (1)); break;
2816 case GTU: cmp = gen_rtx_LTU (HImode, OP (2), OP (1)); break;
2817 case LEU: cmp = gen_rtx_GEU (HImode, OP (2), OP (1)); break;
2818 case GEU: cmp = gen_rtx_LEU (HImode, OP (2), OP (1)); break;
2819
2820 case LT:
2821 case GT:
2822 case LE:
2823 case GE:
2824 #if DEBUG_ALLOC
2825 debug_rtx (insn);
2826 #endif
2827 default:
2828 gcc_unreachable ();
2829 }
2830
2831 if (GET_CODE (cmp) == EQ || GET_CODE (cmp) == NE)
2832 PATTERN (insn) = gen_cbranchhi4_real (cmp, OP (2), OP (1), OP (3));
2833 else
2834 PATTERN (insn) = gen_cbranchhi4_real_inverted (cmp, OP (2), OP (1), OP (3));
2835
2836 MUST_BE_OK (insn);
2837 }
2838
2839 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
2840 should be handled by the second alternative of the cbranchhi_real pattern. */
2841 if (rtx_equal_p (OP (1), OP (2)))
2842 {
2843 OP (1) = OP (2) = BC;
2844 MUST_BE_OK (insn);
2845 }
2846
2847 tmp_id = get_max_insn_count ();
2848 saved_op1 = OP (1);
2849
2850 OP (1) = move_to_acc (1, insn);
2851
2852 MAYBE_OK (insn);
2853
2854 /* If we omitted the move of OP1 into the accumulator (because
2855 it was already there from a previous insn), then force the
2856 generation of the move instruction now. We know that we
2857 are about to emit a move into HL via AX, and hence our
2858 optimization to remove the load of OP1 is no longer valid. */
2859 if (tmp_id == get_max_insn_count ())
2860 force_into_acc (saved_op1, insn);
2861
2862 /* We have to copy op2 to HL, but that involves the acc, which
2863 already has a live value. Emit it before those insns. */
2864 if (prev)
2865 first = next_nonnote_nondebug_insn (prev);
2866 else
2867 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
2868 ;
2869 OP (2) = move_to_hl (2, first);
2870
2871 MUST_BE_OK (insn);
2872 }
2873
2874 /* Like op2, but AX = A op X. */
2875
2876 static void
2877 rl78_alloc_physical_registers_umul (rtx insn)
2878 {
2879 rtx prev = prev_nonnote_nondebug_insn (insn);
2880 rtx first;
2881 int tmp_id;
2882 rtx saved_op1;
2883
2884 OP (0) = transcode_memory_rtx (OP (0), BC, insn);
2885 OP (1) = transcode_memory_rtx (OP (1), DE, insn);
2886 OP (2) = transcode_memory_rtx (OP (2), HL, insn);
2887
2888 MAYBE_OK (insn);
2889
2890 if (recog_data.constraints[1][0] == '%'
2891 && is_virtual_register (OP (1))
2892 && !is_virtual_register (OP (2))
2893 && !CONSTANT_P (OP (2)))
2894 {
2895 rtx tmp = OP (1);
2896 OP (1) = OP (2);
2897 OP (2) = tmp;
2898 }
2899
2900 OP (0) = move_from_acc (0, insn);
2901
2902 tmp_id = get_max_insn_count ();
2903 saved_op1 = OP (1);
2904
2905 OP (1) = move_to_acc (1, insn);
2906
2907 MAYBE_OK (insn);
2908
2909 /* If we omitted the move of OP1 into the accumulator (because
2910 it was already there from a previous insn), then force the
2911 generation of the move instruction now. We know that we
2912 are about to emit a move into HL (or DE) via AX, and hence
2913 our optimization to remove the load of OP1 is no longer valid. */
2914 if (tmp_id == get_max_insn_count ())
2915 force_into_acc (saved_op1, insn);
2916
2917 /* We have to copy op2 to X, but that involves the acc, which
2918 already has a live value. Emit it before those insns. */
2919
2920 if (prev)
2921 first = next_nonnote_nondebug_insn (prev);
2922 else
2923 for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
2924 ;
2925 OP (2) = move_to_x (2, first);
2926
2927 MUST_BE_OK (insn);
2928 }
2929
2930 static void
2931 rl78_alloc_address_registers_macax (rtx insn)
2932 {
2933 int which, op;
2934 bool replace_in_op0 = false;
2935 bool replace_in_op1 = false;
2936
2937 MAYBE_OK (insn);
2938
2939 /* Two different MEMs are not allowed. */
2940 which = 0;
2941 for (op = 2; op >= 0; op --)
2942 {
2943 if (MEM_P (OP (op)))
2944 {
2945 if (op == 0 && replace_in_op0)
2946 continue;
2947 if (op == 1 && replace_in_op1)
2948 continue;
2949
2950 switch (which)
2951 {
2952 case 0:
2953 /* If we replace a MEM, make sure that we replace it for all
2954 occurrences of the same MEM in the insn. */
2955 replace_in_op0 = (op > 0 && rtx_equal_p (OP (op), OP (0)));
2956 replace_in_op1 = (op > 1 && rtx_equal_p (OP (op), OP (1)));
2957
2958 OP (op) = transcode_memory_rtx (OP (op), HL, insn);
2959 if (op == 2
2960 && MEM_P (OP (op))
2961 && (REGNO (XEXP (OP (op), 0)) == SP_REG
2962 || (GET_CODE (XEXP (OP (op), 0)) == PLUS
2963 && REGNO (XEXP (XEXP (OP (op), 0), 0)) == SP_REG)))
2964 {
2965 emit_insn_before (gen_movhi (HL, gen_rtx_REG (HImode, SP_REG)), insn);
2966 OP (op) = replace_rtx (OP (op), gen_rtx_REG (HImode, SP_REG), HL);
2967 }
2968 if (replace_in_op0)
2969 OP (0) = OP (op);
2970 if (replace_in_op1)
2971 OP (1) = OP (op);
2972 break;
2973 case 1:
2974 OP (op) = transcode_memory_rtx (OP (op), DE, insn);
2975 break;
2976 case 2:
2977 OP (op) = transcode_memory_rtx (OP (op), BC, insn);
2978 break;
2979 }
2980 which ++;
2981 }
2982 }
2983 MUST_BE_OK (insn);
2984 }
2985
2986 /* Scan all insns and devirtualize them. */
2987 static void
2988 rl78_alloc_physical_registers (void)
2989 {
2990 /* During most of the compile, gcc is dealing with virtual
2991 registers. At this point, we need to assign physical registers
2992 to the vitual ones, and copy in/out as needed. */
2993
2994 rtx insn, curr;
2995 enum attr_valloc valloc_method;
2996
2997 for (insn = get_insns (); insn; insn = curr)
2998 {
2999 int i;
3000
3001 curr = next_nonnote_nondebug_insn (insn);
3002
3003 if (INSN_P (insn)
3004 && (GET_CODE (PATTERN (insn)) == SET
3005 || GET_CODE (PATTERN (insn)) == CALL)
3006 && INSN_CODE (insn) == -1)
3007 {
3008 if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
3009 continue;
3010 i = recog (PATTERN (insn), insn, 0);
3011 if (i == -1)
3012 {
3013 debug_rtx (insn);
3014 gcc_unreachable ();
3015 }
3016 INSN_CODE (insn) = i;
3017 }
3018 }
3019
3020 cfun->machine->virt_insns_ok = 0;
3021 cfun->machine->real_insns_ok = 1;
3022
3023 clear_content_memory ();
3024
3025 for (insn = get_insns (); insn; insn = curr)
3026 {
3027 rtx pattern;
3028
3029 curr = insn ? next_nonnote_nondebug_insn (insn) : NULL;
3030
3031 if (!INSN_P (insn))
3032 {
3033 if (LABEL_P (insn))
3034 clear_content_memory ();
3035
3036 continue;
3037 }
3038
3039 if (dump_file)
3040 fprintf (dump_file, "Converting insn %d\n", INSN_UID (insn));
3041
3042 pattern = PATTERN (insn);
3043 if (GET_CODE (pattern) == PARALLEL)
3044 pattern = XVECEXP (pattern, 0, 0);
3045 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3046 clear_content_memory ();
3047 if (GET_CODE (pattern) != SET
3048 && GET_CODE (pattern) != CALL)
3049 continue;
3050 if (GET_CODE (SET_SRC (pattern)) == ASM_OPERANDS)
3051 continue;
3052
3053 valloc_method = get_attr_valloc (insn);
3054
3055 PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
3056
3057 if (valloc_method == VALLOC_MACAX)
3058 {
3059 record_content (AX, NULL_RTX);
3060 record_content (BC, NULL_RTX);
3061 record_content (DE, NULL_RTX);
3062 }
3063
3064 if (insn_ok_now (insn))
3065 continue;
3066
3067 INSN_CODE (insn) = -1;
3068
3069 if (RTX_FRAME_RELATED_P (insn))
3070 virt_insn_was_frame = 1;
3071 else
3072 virt_insn_was_frame = 0;
3073
3074 switch (valloc_method)
3075 {
3076 case VALLOC_OP1:
3077 rl78_alloc_physical_registers_op1 (insn);
3078 break;
3079 case VALLOC_OP2:
3080 rl78_alloc_physical_registers_op2 (insn);
3081 break;
3082 case VALLOC_RO1:
3083 rl78_alloc_physical_registers_ro1 (insn);
3084 break;
3085 case VALLOC_CMP:
3086 rl78_alloc_physical_registers_cmp (insn);
3087 break;
3088 case VALLOC_UMUL:
3089 rl78_alloc_physical_registers_umul (insn);
3090 break;
3091 case VALLOC_MACAX:
3092 /* Macro that clobbers AX. */
3093 rl78_alloc_address_registers_macax (insn);
3094 record_content (AX, NULL_RTX);
3095 record_content (BC, NULL_RTX);
3096 record_content (DE, NULL_RTX);
3097 break;
3098 }
3099
3100 if (JUMP_P (insn) || CALL_P (insn) || GET_CODE (pattern) == CALL)
3101 clear_content_memory ();
3102 else
3103 process_postponed_content_update ();
3104 }
3105 #if DEBUG_ALLOC
3106 fprintf (stderr, "\033[0m");
3107 #endif
3108 }
3109
3110 /* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3111 This function scans for uses of registers; the last use (i.e. first
3112 encounter when scanning backwards) triggers a REG_DEAD note if the
3113 reg was previously in DEAD[]. */
3114 static void
3115 rl78_note_reg_uses (char *dead, rtx s, rtx insn)
3116 {
3117 const char *fmt;
3118 int i, r;
3119 enum rtx_code code;
3120
3121 if (!s)
3122 return;
3123
3124 code = GET_CODE (s);
3125
3126 switch (code)
3127 {
3128 /* Compare registers by number. */
3129 case REG:
3130 r = REGNO (s);
3131 if (dump_file)
3132 {
3133 fprintf (dump_file, "note use reg %d size %d on insn %d\n",
3134 r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn));
3135 print_rtl_single (dump_file, s);
3136 }
3137 if (dead [r])
3138 add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r));
3139 for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++)
3140 dead [r + i] = 0;
3141 return;
3142
3143 /* These codes have no constituent expressions
3144 and are unique. */
3145 case SCRATCH:
3146 case CC0:
3147 case PC:
3148 return;
3149
3150 case CONST_INT:
3151 case CONST_VECTOR:
3152 case CONST_DOUBLE:
3153 case CONST_FIXED:
3154 /* These are kept unique for a given value. */
3155 return;
3156
3157 default:
3158 break;
3159 }
3160
3161 fmt = GET_RTX_FORMAT (code);
3162
3163 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
3164 {
3165 if (fmt[i] == 'E')
3166 {
3167 int j;
3168 for (j = XVECLEN (s, i) - 1; j >= 0; j--)
3169 rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn);
3170 }
3171 else if (fmt[i] == 'e')
3172 rl78_note_reg_uses (dead, XEXP (s, i), insn);
3173 }
3174 }
3175
3176 /* Like the previous function, but scan for SETs instead. */
3177 static void
3178 rl78_note_reg_set (char *dead, rtx d, rtx insn)
3179 {
3180 int r, i;
3181
3182 if (GET_CODE (d) != REG)
3183 return;
3184
3185 r = REGNO (d);
3186 if (dead [r])
3187 add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r));
3188 if (dump_file)
3189 fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d)));
3190 for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
3191 dead [r + i] = 1;
3192 }
3193
3194 /* This is a rather crude register death pass. Death status is reset
3195 at every jump or call insn. */
3196 static void
3197 rl78_calculate_death_notes (void)
3198 {
3199 char dead[FIRST_PSEUDO_REGISTER];
3200 rtx insn, p, s, d;
3201 int i;
3202
3203 memset (dead, 0, sizeof (dead));
3204
3205 for (insn = get_last_insn ();
3206 insn;
3207 insn = prev_nonnote_nondebug_insn (insn))
3208 {
3209 if (dump_file)
3210 {
3211 fprintf (dump_file, "\n--------------------------------------------------");
3212 fprintf (dump_file, "\nDead:");
3213 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
3214 if (dead[i])
3215 fprintf (dump_file, " %s", reg_names[i]);
3216 fprintf (dump_file, "\n");
3217 print_rtl_single (dump_file, insn);
3218 }
3219
3220 switch (GET_CODE (insn))
3221 {
3222 case INSN:
3223 p = PATTERN (insn);
3224 switch (GET_CODE (p))
3225 {
3226 case SET:
3227 s = SET_SRC (p);
3228 d = SET_DEST (p);
3229 rl78_note_reg_set (dead, d, insn);
3230 rl78_note_reg_uses (dead, s, insn);
3231 break;
3232
3233 case USE:
3234 rl78_note_reg_uses (dead, p, insn);
3235 break;
3236
3237 default:
3238 break;
3239 }
3240 break;
3241
3242 case JUMP_INSN:
3243 if (INSN_CODE (insn) == CODE_FOR_rl78_return)
3244 {
3245 memset (dead, 1, sizeof (dead));
3246 /* We expect a USE just prior to this, which will mark
3247 the actual return registers. The USE will have a
3248 death note, but we aren't going to be modifying it
3249 after this pass. */
3250 break;
3251 }
3252 case CALL_INSN:
3253 memset (dead, 0, sizeof (dead));
3254 break;
3255
3256 default:
3257 break;
3258 }
3259 if (dump_file)
3260 print_rtl_single (dump_file, insn);
3261 }
3262 }
3263
3264 /* Helper function to reset the origins in RP and the age in AGE for
3265 all registers. */
3266 static void
3267 reset_origins (int *rp, int *age)
3268 {
3269 int i;
3270 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3271 {
3272 rp[i] = i;
3273 age[i] = 0;
3274 }
3275 }
3276
3277 /* The idea behind this optimization is to look for cases where we
3278 move data from A to B to C, and instead move from A to B, and A to
3279 C. If B is a virtual register or memory, this is a big win on its
3280 own. If B turns out to be unneeded after this, it's a bigger win.
3281 For each register, we try to determine where it's value originally
3282 came from, if it's propogated purely through moves (and not
3283 computes). The ORIGINS[] array has the regno for the "origin" of
3284 the value in the [regno] it's indexed by. */
3285 static void
3286 rl78_propogate_register_origins (void)
3287 {
3288 int origins[FIRST_PSEUDO_REGISTER];
3289 int age[FIRST_PSEUDO_REGISTER];
3290 int i;
3291 rtx insn, ninsn = NULL_RTX;
3292 rtx pat;
3293
3294 reset_origins (origins, age);
3295
3296 for (insn = get_insns (); insn; insn = ninsn)
3297 {
3298 ninsn = next_nonnote_nondebug_insn (insn);
3299
3300 if (dump_file)
3301 {
3302 fprintf (dump_file, "\n");
3303 fprintf (dump_file, "Origins:");
3304 for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
3305 if (origins[i] != i)
3306 fprintf (dump_file, " r%d=r%d", i, origins[i]);
3307 fprintf (dump_file, "\n");
3308 print_rtl_single (dump_file, insn);
3309 }
3310
3311 switch (GET_CODE (insn))
3312 {
3313 case CODE_LABEL:
3314 case BARRIER:
3315 case CALL_INSN:
3316 case JUMP_INSN:
3317 reset_origins (origins, age);
3318 break;
3319
3320 default:
3321 break;
3322
3323 case INSN:
3324 pat = PATTERN (insn);
3325
3326 if (GET_CODE (pat) == PARALLEL)
3327 {
3328 rtx clobber = XVECEXP (pat, 0, 1);
3329 pat = XVECEXP (pat, 0, 0);
3330 if (GET_CODE (clobber) == CLOBBER)
3331 {
3332 int cr = REGNO (XEXP (clobber, 0));
3333 int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0)));
3334 if (dump_file)
3335 fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr);
3336 for (i = 0; i < mb; i++)
3337 {
3338 origins[cr + i] = cr + i;
3339 age[cr + i] = 0;
3340 }
3341 }
3342 else
3343 break;
3344 }
3345
3346 if (GET_CODE (pat) == SET)
3347 {
3348 rtx src = SET_SRC (pat);
3349 rtx dest = SET_DEST (pat);
3350 int mb = GET_MODE_SIZE (GET_MODE (dest));
3351
3352 if (GET_CODE (dest) == REG)
3353 {
3354 int dr = REGNO (dest);
3355
3356 if (GET_CODE (src) == REG)
3357 {
3358 int sr = REGNO (src);
3359 int same = 1;
3360 int best_age, best_reg;
3361
3362 /* See if the copy is not needed. */
3363 for (i = 0; i < mb; i ++)
3364 if (origins[dr + i] != origins[sr + i])
3365 same = 0;
3366 if (same)
3367 {
3368 if (dump_file)
3369 fprintf (dump_file, "deleting because dest already has correct value\n");
3370 delete_insn (insn);
3371 break;
3372 }
3373
3374 if (dr < 8 || sr >= 8)
3375 {
3376 int ar;
3377
3378 best_age = -1;
3379 best_reg = -1;
3380 /* See if the copy can be made from another
3381 bank 0 register instead, instead of the
3382 virtual src register. */
3383 for (ar = 0; ar < 8; ar += mb)
3384 {
3385 same = 1;
3386 for (i = 0; i < mb; i ++)
3387 if (origins[ar + i] != origins[sr + i])
3388 same = 0;
3389
3390 /* The chip has some reg-reg move limitations. */
3391 if (mb == 1 && dr > 3)
3392 same = 0;
3393
3394 if (same)
3395 {
3396 if (best_age == -1 || best_age > age[sr + i])
3397 {
3398 best_age = age[sr + i];
3399 best_reg = sr;
3400 }
3401 }
3402 }
3403
3404 if (best_reg != -1)
3405 {
3406 /* FIXME: copy debug info too. */
3407 SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg);
3408 sr = best_reg;
3409 }
3410 }
3411
3412 for (i = 0; i < mb; i++)
3413 {
3414 origins[dr + i] = origins[sr + i];
3415 age[dr + i] = age[sr + i] + 1;
3416 }
3417 }
3418 else
3419 {
3420 /* The destination is computed, its origin is itself. */
3421 if (dump_file)
3422 fprintf (dump_file, "resetting origin of r%d for %d byte%s\n",
3423 dr, mb, mb == 1 ? "" : "s");
3424 for (i = 0; i < mb; i ++)
3425 {
3426 origins[dr + i] = dr + i;
3427 age[dr + i] = 0;
3428 }
3429 }
3430
3431 /* Any registers marked with that reg as an origin are reset. */
3432 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3433 if (origins[i] >= dr && origins[i] < dr + mb)
3434 {
3435 origins[i] = i;
3436 age[i] = 0;
3437 }
3438 }
3439
3440 /* Special case - our ADDSI3 macro uses AX and sometimes BC. */
3441 if (get_attr_valloc (insn) == VALLOC_MACAX)
3442 {
3443 if (dump_file)
3444 fprintf (dump_file, "Resetting origin of AX/BC for macro.\n");
3445 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3446 if (i <= 3 || origins[i] <= 3)
3447 {
3448 origins[i] = i;
3449 age[i] = 0;
3450 }
3451 }
3452
3453 if (GET_CODE (src) == ASHIFT
3454 || GET_CODE (src) == ASHIFTRT
3455 || GET_CODE (src) == LSHIFTRT)
3456 {
3457 rtx count = XEXP (src, 1);
3458 if (GET_CODE (count) == REG)
3459 {
3460 /* Special case - our pattern clobbers the count register. */
3461 int r = REGNO (count);
3462 if (dump_file)
3463 fprintf (dump_file, "Resetting origin of r%d for shift.\n", r);
3464 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
3465 if (i == r || origins[i] == r)
3466 {
3467 origins[i] = i;
3468 age[i] = 0;
3469 }
3470 }
3471 }
3472 }
3473 }
3474 }
3475 }
3476
3477 /* Remove any SETs where the destination is unneeded. */
3478 static void
3479 rl78_remove_unused_sets (void)
3480 {
3481 rtx insn, ninsn = NULL_RTX;
3482 rtx dest;
3483
3484 for (insn = get_insns (); insn; insn = ninsn)
3485 {
3486 ninsn = next_nonnote_nondebug_insn (insn);
3487
3488 if ((insn = single_set (insn)) == NULL_RTX)
3489 continue;
3490
3491 dest = SET_DEST (insn);
3492
3493 if (GET_CODE (dest) != REG || REGNO (dest) > 23)
3494 continue;
3495
3496 if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
3497 delete_insn (insn);
3498 }
3499 }
3500
3501 /* This is the top of the devritualization pass. */
3502 static void
3503 rl78_reorg (void)
3504 {
3505 /* split2 only happens when optimizing, but we need all movSIs to be
3506 split now. */
3507 if (optimize <= 0)
3508 split_all_insns ();
3509
3510 rl78_alloc_physical_registers ();
3511
3512 if (dump_file)
3513 {
3514 fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
3515 print_rtl_with_bb (dump_file, get_insns (), 0);
3516 }
3517
3518 rl78_propogate_register_origins ();
3519 rl78_calculate_death_notes ();
3520
3521 if (dump_file)
3522 {
3523 fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
3524 print_rtl_with_bb (dump_file, get_insns (), 0);
3525 fprintf (dump_file, "\n======================================================================\n");
3526 }
3527
3528 rl78_remove_unused_sets ();
3529
3530 /* The code after devirtualizing has changed so much that at this point
3531 we might as well just rescan everything. Note that
3532 df_rescan_all_insns is not going to help here because it does not
3533 touch the artificial uses and defs. */
3534 df_finish_pass (true);
3535 if (optimize > 1)
3536 df_live_add_problem ();
3537 df_scan_alloc (NULL);
3538 df_scan_blocks ();
3539
3540 if (optimize)
3541 df_analyze ();
3542 }
3543
3544 #undef TARGET_RETURN_IN_MEMORY
3545 #define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
3546
3547 static bool
3548 rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
3549 {
3550 const HOST_WIDE_INT size = int_size_in_bytes (type);
3551 return (size == -1 || size > 8);
3552 }
3553
3554 \f
3555 #undef TARGET_RTX_COSTS
3556 #define TARGET_RTX_COSTS rl78_rtx_costs
3557
3558 static bool rl78_rtx_costs (rtx x,
3559 int code,
3560 int outer_code ATTRIBUTE_UNUSED,
3561 int opno ATTRIBUTE_UNUSED,
3562 int * total,
3563 bool speed ATTRIBUTE_UNUSED)
3564 {
3565 if (code == IF_THEN_ELSE)
3566 return COSTS_N_INSNS (10);
3567 if (GET_MODE (x) == SImode)
3568 {
3569 switch (code)
3570 {
3571 case MULT:
3572 if (RL78_MUL_RL78)
3573 *total = COSTS_N_INSNS (14);
3574 else if (RL78_MUL_G13)
3575 *total = COSTS_N_INSNS (29);
3576 else
3577 *total = COSTS_N_INSNS (500);
3578 return true;
3579 case PLUS:
3580 *total = COSTS_N_INSNS (8);
3581 return true;
3582 case ASHIFT:
3583 case ASHIFTRT:
3584 case LSHIFTRT:
3585 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
3586 {
3587 switch (INTVAL (XEXP (x, 1)))
3588 {
3589 case 0: *total = COSTS_N_INSNS (0); break;
3590 case 1: *total = COSTS_N_INSNS (6); break;
3591 case 2: case 3: case 4: case 5: case 6: case 7:
3592 *total = COSTS_N_INSNS (10); break;
3593 case 8: *total = COSTS_N_INSNS (6); break;
3594 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
3595 *total = COSTS_N_INSNS (10); break;
3596 case 16: *total = COSTS_N_INSNS (3); break;
3597 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
3598 *total = COSTS_N_INSNS (4); break;
3599 case 24: *total = COSTS_N_INSNS (4); break;
3600 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
3601 *total = COSTS_N_INSNS (5); break;
3602 }
3603 }
3604 else
3605 *total = COSTS_N_INSNS (10+4*16);
3606 return true;
3607 }
3608 }
3609 return false;
3610 }
3611 \f
3612
3613 #undef TARGET_UNWIND_WORD_MODE
3614 #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
3615
3616 static enum machine_mode
3617 rl78_unwind_word_mode (void)
3618 {
3619 return HImode;
3620 }
3621
3622 struct gcc_target targetm = TARGET_INITIALIZER;
3623
3624 #include "gt-rl78.h"