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