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