1 /* Subroutines used for code generation on Renesas RL78 processors.
2 Copyright (C) 2011-2021 Free Software Foundation, Inc.
3 Contributed by Red Hat.
5 This file is part of GCC.
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)
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.
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/>. */
21 #define IN_TARGET_CODE 1
25 #include "coretypes.h"
33 #include "stringpool.h"
38 #include "diagnostic-core.h"
40 #include "stor-layout.h"
43 #include "insn-attr.h"
48 #include "langhooks.h"
49 #include "tree-pass.h"
51 #include "tm-constrs.h" /* for satisfies_constraint_*(). */
54 /* This file should be included last. */
55 #include "target-def.h"
57 static inline bool is_interrupt_func (const_tree decl
);
58 static inline bool is_brk_interrupt_func (const_tree decl
);
59 static void rl78_reorg (void);
60 static const char *rl78_strip_name_encoding (const char *);
61 static const char *rl78_strip_nonasm_name_encoding (const char *);
62 static section
* rl78_select_section (tree
, int, unsigned HOST_WIDE_INT
);
65 /* Debugging statements are tagged with DEBUG0 only so that they can
66 be easily enabled individually, by replacing the '0' with '1' as
71 /* REGISTER_NAMES has the names for individual 8-bit registers, but
72 these have the names we need to use when referring to 16-bit
74 static const char * const word_regnames
[] =
76 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
77 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
78 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
79 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
80 "sp", "ap", "psw", "es", "cs"
83 /* used by rl78_addsi3_internal for formatting insns output */
84 static char fmt_buffer
[1024];
86 /* Structure for G13 MDUC registers. */
90 enum machine_mode mode
;
93 struct mduc_reg_type mduc_regs
[] =
103 struct GTY(()) machine_function
105 /* If set, the rest of the fields have been computed. */
107 /* Which register pairs need to be pushed in the prologue. */
108 int need_to_push
[FIRST_PSEUDO_REGISTER
/ 2];
110 /* These fields describe the frame layout... */
112 /* 4 bytes for saved PC */
115 int framesize_locals
;
116 int framesize_outgoing
;
120 /* If set, recog is allowed to match against the "real" patterns. */
122 /* If set, recog is allowed to match against the "virtual" patterns. */
124 /* Set if the current function needs to clean up any trampolines. */
125 int trampolines_used
;
126 /* True if the ES register is used and hence
127 needs to be saved inside interrupt handlers. */
131 /* This is our init_machine_status, as set in
132 rl78_option_override. */
133 static struct machine_function
*
134 rl78_init_machine_status (void)
136 struct machine_function
*m
;
138 m
= ggc_cleared_alloc
<machine_function
> ();
139 m
->virt_insns_ok
= 1;
144 /* This pass converts virtual instructions using virtual registers, to
145 real instructions using real registers. Rather than run it as
146 reorg, we reschedule it before vartrack to help with debugging. */
149 const pass_data pass_data_rl78_devirt
=
153 OPTGROUP_NONE
, /* optinfo_flags */
154 TV_MACH_DEP
, /* tv_id */
155 0, /* properties_required */
156 0, /* properties_provided */
157 0, /* properties_destroyed */
158 0, /* todo_flags_start */
159 0, /* todo_flags_finish */
162 class pass_rl78_devirt
: public rtl_opt_pass
165 pass_rl78_devirt (gcc::context
*ctxt
)
166 : rtl_opt_pass (pass_data_rl78_devirt
, ctxt
)
170 /* opt_pass methods: */
171 virtual unsigned int execute (function
*)
180 make_pass_rl78_devirt (gcc::context
*ctxt
)
182 return new pass_rl78_devirt (ctxt
);
185 /* Redundant move elimination pass. Must be run after the basic block
186 reordering pass for the best effect. */
189 move_elim_pass (void)
191 rtx_insn
*insn
, *ninsn
;
194 for (insn
= get_insns (); insn
; insn
= ninsn
)
198 ninsn
= next_nonnote_nondebug_insn (insn
);
200 if ((set
= single_set (insn
)) == NULL_RTX
)
206 /* If we have two SET insns in a row (without anything
207 between them) and the source of the second one is the
208 destination of the first one, and vice versa, then we
209 can eliminate the second SET. */
211 && rtx_equal_p (SET_DEST (prev
), SET_SRC (set
))
212 && rtx_equal_p (SET_DEST (set
), SET_SRC (prev
))
213 /* ... and none of the operands are volatile. */
214 && ! volatile_refs_p (SET_SRC (prev
))
215 && ! volatile_refs_p (SET_DEST (prev
))
216 && ! volatile_refs_p (SET_SRC (set
))
217 && ! volatile_refs_p (SET_DEST (set
)))
220 fprintf (dump_file
, " Delete insn %d because it is redundant\n",
231 print_rtl_with_bb (dump_file
, get_insns (), TDF_NONE
);
238 const pass_data pass_data_rl78_move_elim
=
241 "move_elim", /* name */
242 OPTGROUP_NONE
, /* optinfo_flags */
243 TV_MACH_DEP
, /* tv_id */
244 0, /* properties_required */
245 0, /* properties_provided */
246 0, /* properties_destroyed */
247 0, /* todo_flags_start */
248 0, /* todo_flags_finish */
251 class pass_rl78_move_elim
: public rtl_opt_pass
254 pass_rl78_move_elim (gcc::context
*ctxt
)
255 : rtl_opt_pass (pass_data_rl78_move_elim
, ctxt
)
259 /* opt_pass methods: */
260 virtual unsigned int execute (function
*) { return move_elim_pass (); }
265 make_pass_rl78_move_elim (gcc::context
*ctxt
)
267 return new pass_rl78_move_elim (ctxt
);
270 #undef TARGET_ASM_FILE_START
271 #define TARGET_ASM_FILE_START rl78_asm_file_start
274 rl78_asm_file_start (void)
280 /* The memory used is 0xffec8 to 0xffedf; real registers are in
281 0xffee0 to 0xffee7. */
282 for (i
= 8; i
< 32; i
++)
283 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", i
, 0xffec0 + i
);
287 for (i
= 0; i
< 8; i
++)
289 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 8 + i
, 0xffef0 + i
);
290 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 16 + i
, 0xffee8 + i
);
291 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 24 + i
, 0xffee0 + i
);
295 opt_pass
*rl78_devirt_pass
= make_pass_rl78_devirt (g
);
296 struct register_pass_info rl78_devirt_info
=
301 PASS_POS_INSERT_BEFORE
304 opt_pass
*rl78_move_elim_pass
= make_pass_rl78_move_elim (g
);
305 struct register_pass_info rl78_move_elim_info
=
310 PASS_POS_INSERT_AFTER
313 register_pass (& rl78_devirt_info
);
314 register_pass (& rl78_move_elim_info
);
318 rl78_output_symbol_ref (FILE * file
, rtx sym
)
320 tree type
= SYMBOL_REF_DECL (sym
);
321 const char *str
= XSTR (sym
, 0);
325 fputs (str
+ 1, file
);
329 str
= rl78_strip_nonasm_name_encoding (str
);
330 if (type
&& TREE_CODE (type
) == FUNCTION_DECL
)
332 fprintf (file
, "%%code(");
333 assemble_name (file
, str
);
337 assemble_name (file
, str
);
341 #undef TARGET_OPTION_OVERRIDE
342 #define TARGET_OPTION_OVERRIDE rl78_option_override
344 #define MUST_SAVE_MDUC_REGISTERS \
345 (TARGET_SAVE_MDUC_REGISTERS \
346 && (is_interrupt_func (NULL_TREE)) && RL78_MUL_G13)
349 rl78_option_override (void)
351 flag_omit_frame_pointer
= 1;
352 flag_no_function_cse
= 1;
353 flag_split_wide_types
= 0;
355 init_machine_status
= rl78_init_machine_status
;
361 for (i
= 24; i
< 32; i
++)
366 && strcmp (lang_hooks
.name
, "GNU C")
367 && strcmp (lang_hooks
.name
, "GNU C11")
368 && strcmp (lang_hooks
.name
, "GNU C17")
369 && strcmp (lang_hooks
.name
, "GNU C2X")
370 && strcmp (lang_hooks
.name
, "GNU C89")
371 && strcmp (lang_hooks
.name
, "GNU C99")
372 /* Compiling with -flto results in a language of GNU GIMPLE being used... */
373 && strcmp (lang_hooks
.name
, "GNU GIMPLE"))
374 /* Address spaces are currently only supported by C. */
375 error ("%<-mes0%> can only be used with C");
377 if (TARGET_SAVE_MDUC_REGISTERS
&& !(TARGET_G13
|| RL78_MUL_G13
))
378 warning (0, "mduc registers only saved for G13 target");
380 switch (rl78_cpu_type
)
383 rl78_cpu_type
= CPU_G14
;
384 if (rl78_mul_type
== MUL_UNINIT
)
385 rl78_mul_type
= MUL_NONE
;
389 switch (rl78_mul_type
)
391 case MUL_UNINIT
: rl78_mul_type
= MUL_NONE
; break;
392 case MUL_NONE
: break;
393 case MUL_G13
: error ("%<-mmul=g13%> cannot be used with "
394 "%<-mcpu=g10%>"); break;
395 case MUL_G14
: error ("%<-mmul=g14%> cannot be used with "
396 "%<-mcpu=g10%>"); break;
401 switch (rl78_mul_type
)
403 case MUL_UNINIT
: rl78_mul_type
= MUL_G13
; break;
404 case MUL_NONE
: break;
406 /* The S2 core does not have mul/div instructions. */
407 case MUL_G14
: error ("%<-mmul=g14%> cannot be used with "
408 "%<-mcpu=g13%>"); break;
413 switch (rl78_mul_type
)
415 case MUL_UNINIT
: rl78_mul_type
= MUL_G14
; break;
416 case MUL_NONE
: break;
418 /* The G14 core does not have the hardware multiply peripheral used by the
419 G13 core, hence you cannot use G13 multipliy routines on G14 hardware. */
420 case MUL_G13
: error ("%<-mmul=g13%> cannot be used with "
421 "%<-mcpu=g14%>"); break;
427 /* Most registers are 8 bits. Some are 16 bits because, for example,
428 gcc doesn't like dealing with $FP as a register pair (the second
429 half of $fp is also 2 to keep reload happy wrt register pairs, but
430 no register class includes it). This table maps register numbers
432 static const int register_sizes
[] =
434 1, 1, 1, 1, 1, 1, 1, 1,
435 1, 1, 1, 1, 1, 1, 1, 1,
436 1, 1, 1, 1, 1, 1, 2, 2,
437 1, 1, 1, 1, 1, 1, 1, 1,
441 /* Predicates used in the MD patterns. This one is true when virtual
442 insns may be matched, which typically means before (or during) the
445 rl78_virt_insns_ok (void)
448 return cfun
->machine
->virt_insns_ok
;
452 /* Predicates used in the MD patterns. This one is true when real
453 insns may be matched, which typically means after (or during) the
456 rl78_real_insns_ok (void)
459 return cfun
->machine
->real_insns_ok
;
463 #undef TARGET_HARD_REGNO_NREGS
464 #define TARGET_HARD_REGNO_NREGS rl78_hard_regno_nregs
467 rl78_hard_regno_nregs (unsigned int regno
, machine_mode mode
)
469 int rs
= register_sizes
[regno
];
472 return ((GET_MODE_SIZE (mode
) + rs
- 1) / rs
);
475 #undef TARGET_HARD_REGNO_MODE_OK
476 #define TARGET_HARD_REGNO_MODE_OK rl78_hard_regno_mode_ok
479 rl78_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
481 int s
= GET_MODE_SIZE (mode
);
485 /* These are not to be used by gcc. */
486 if (regno
== 23 || regno
== ES_REG
|| regno
== CS_REG
)
488 /* $fp can always be accessed as a 16-bit value. */
489 if (regno
== FP_REG
&& s
== 2)
493 /* Since a reg-reg move is really a reg-mem move, we must
494 enforce alignment. */
495 if (s
> 1 && (regno
% 2))
500 return (mode
== BImode
);
501 /* All other registers must be accessed in their natural sizes. */
502 if (s
== register_sizes
[regno
])
507 #undef TARGET_MODES_TIEABLE_P
508 #define TARGET_MODES_TIEABLE_P rl78_modes_tieable_p
511 rl78_modes_tieable_p (machine_mode mode1
, machine_mode mode2
)
513 return ((GET_MODE_CLASS (mode1
) == MODE_FLOAT
514 || GET_MODE_CLASS (mode1
) == MODE_COMPLEX_FLOAT
)
515 == (GET_MODE_CLASS (mode2
) == MODE_FLOAT
516 || GET_MODE_CLASS (mode2
) == MODE_COMPLEX_FLOAT
));
519 /* Simplify_gen_subreg() doesn't handle memory references the way we
520 need it to below, so we use this function for when we must get a
521 valid subreg in a "natural" state. */
523 rl78_subreg (machine_mode mode
, rtx r
, machine_mode omode
, int byte
)
525 if (GET_CODE (r
) == MEM
)
526 return adjust_address (r
, mode
, byte
);
528 return simplify_gen_subreg (mode
, r
, omode
, byte
);
531 /* Used by movsi. Split SImode moves into two HImode moves, using
532 appropriate patterns for the upper and lower halves of symbols. */
534 rl78_expand_movsi (rtx
*operands
)
536 rtx op00
, op02
, op10
, op12
;
538 op00
= rl78_subreg (HImode
, operands
[0], SImode
, 0);
539 op02
= rl78_subreg (HImode
, operands
[0], SImode
, 2);
540 if (GET_CODE (operands
[1]) == CONST
541 || GET_CODE (operands
[1]) == SYMBOL_REF
)
543 op10
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (0));
544 op10
= gen_rtx_CONST (HImode
, op10
);
545 op12
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (16));
546 op12
= gen_rtx_CONST (HImode
, op12
);
550 op10
= rl78_subreg (HImode
, operands
[1], SImode
, 0);
551 op12
= rl78_subreg (HImode
, operands
[1], SImode
, 2);
554 if (rtx_equal_p (operands
[0], operands
[1]))
556 else if (rtx_equal_p (op00
, op12
))
558 emit_move_insn (op02
, op12
);
559 emit_move_insn (op00
, op10
);
563 emit_move_insn (op00
, op10
);
564 emit_move_insn (op02
, op12
);
568 /* Generate code to move an SImode value. */
570 rl78_split_movsi (rtx
*operands
, machine_mode omode
)
572 rtx op00
, op02
, op10
, op12
;
574 op00
= rl78_subreg (HImode
, operands
[0], omode
, 0);
575 op02
= rl78_subreg (HImode
, operands
[0], omode
, 2);
577 if (GET_CODE (operands
[1]) == CONST
578 || GET_CODE (operands
[1]) == SYMBOL_REF
)
580 op10
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (0));
581 op10
= gen_rtx_CONST (HImode
, op10
);
582 op12
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (16));
583 op12
= gen_rtx_CONST (HImode
, op12
);
587 op10
= rl78_subreg (HImode
, operands
[1], omode
, 0);
588 op12
= rl78_subreg (HImode
, operands
[1], omode
, 2);
591 if (rtx_equal_p (operands
[0], operands
[1]))
593 else if (rtx_equal_p (op00
, op12
))
610 rl78_split_movdi (rtx
*operands
, enum machine_mode omode
)
612 rtx op00
, op04
, op10
, op14
;
613 op00
= rl78_subreg (SImode
, operands
[0], omode
, 0);
614 op04
= rl78_subreg (SImode
, operands
[0], omode
, 4);
615 op10
= rl78_subreg (SImode
, operands
[1], omode
, 0);
616 op14
= rl78_subreg (SImode
, operands
[1], omode
, 4);
617 emit_insn (gen_movsi (op00
, op10
));
618 emit_insn (gen_movsi (op04
, op14
));
621 /* Used by various two-operand expanders which cannot accept all
622 operands in the "far" namespace. Force some such operands into
623 registers so that each pattern has at most one far operand. */
625 rl78_force_nonfar_2 (rtx
*operands
, rtx (*gen
)(rtx
,rtx
))
630 /* FIXME: in the future, be smarter about only doing this if the
631 other operand is also far, assuming the devirtualizer can also
633 if (rl78_far_p (operands
[0]))
635 temp_reg
= operands
[0];
636 operands
[0] = gen_reg_rtx (GET_MODE (operands
[0]));
642 emit_insn (gen (operands
[0], operands
[1]));
644 emit_move_insn (temp_reg
, operands
[0]);
648 /* Likewise, but for three-operand expanders. */
650 rl78_force_nonfar_3 (rtx
*operands
, rtx (*gen
)(rtx
,rtx
,rtx
))
655 /* FIXME: Likewise. */
656 if (rl78_far_p (operands
[1]))
658 rtx temp_reg
= gen_reg_rtx (GET_MODE (operands
[1]));
659 emit_move_insn (temp_reg
, operands
[1]);
660 operands
[1] = temp_reg
;
663 if (rl78_far_p (operands
[0]))
665 temp_reg
= operands
[0];
666 operands
[0] = gen_reg_rtx (GET_MODE (operands
[0]));
672 emit_insn (gen (operands
[0], operands
[1], operands
[2]));
674 emit_move_insn (temp_reg
, operands
[0]);
679 rl78_one_far_p (rtx
*operands
, int n
)
684 for (i
= 0; i
< n
; i
++)
685 if (rl78_far_p (operands
[i
]))
689 else if (rtx_equal_p (operands
[i
], which
))
696 #undef TARGET_CAN_ELIMINATE
697 #define TARGET_CAN_ELIMINATE rl78_can_eliminate
700 rl78_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to ATTRIBUTE_UNUSED
)
705 /* Returns true if the given register needs to be saved by the
708 need_to_save (unsigned int regno
)
710 if (is_interrupt_func (cfun
->decl
))
712 /* We don't know what devirt will need */
716 /* We don't need to save registers that have
717 been reserved for interrupt handlers. */
721 /* If the handler is a non-leaf function then it may call
722 non-interrupt aware routines which will happily clobber
723 any call_used registers, so we have to preserve them.
724 We do not have to worry about the frame pointer register
725 though, as that is handled below. */
726 if (!crtl
->is_leaf
&& call_used_or_fixed_reg_p (regno
) && regno
< 22)
729 /* Otherwise we only have to save a register, call_used
730 or not, if it is used by this handler. */
731 return df_regs_ever_live_p (regno
);
734 if (regno
== FRAME_POINTER_REGNUM
735 && (frame_pointer_needed
|| df_regs_ever_live_p (regno
)))
737 if (fixed_regs
[regno
])
739 if (crtl
->calls_eh_return
)
741 if (df_regs_ever_live_p (regno
)
742 && !call_used_or_fixed_reg_p (regno
))
747 /* We use this to wrap all emitted insns in the prologue. */
751 RTX_FRAME_RELATED_P (x
) = 1;
755 /* Compute all the frame-related fields in our machine_function
758 rl78_compute_frame_info (void)
762 cfun
->machine
->computed
= 1;
763 cfun
->machine
->framesize_regs
= 0;
764 cfun
->machine
->framesize_locals
= get_frame_size ();
765 cfun
->machine
->framesize_outgoing
= crtl
->outgoing_args_size
;
767 for (i
= 0; i
< 16; i
++)
768 if (need_to_save (i
* 2) || need_to_save (i
* 2 + 1))
770 cfun
->machine
->need_to_push
[i
] = 1;
771 cfun
->machine
->framesize_regs
+= 2;
774 cfun
->machine
->need_to_push
[i
] = 0;
776 if ((cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
) & 1)
777 cfun
->machine
->framesize_locals
++;
779 cfun
->machine
->framesize
= (cfun
->machine
->framesize_regs
780 + cfun
->machine
->framesize_locals
781 + cfun
->machine
->framesize_outgoing
);
784 /* Returns true if the provided function has the specified attribute. */
786 has_func_attr (const_tree decl
, const char * func_attr
)
788 if (decl
== NULL_TREE
)
789 decl
= current_function_decl
;
791 return lookup_attribute (func_attr
, DECL_ATTRIBUTES (decl
)) != NULL_TREE
;
794 /* Returns true if the provided function has the "interrupt" attribute. */
796 is_interrupt_func (const_tree decl
)
798 return has_func_attr (decl
, "interrupt") || has_func_attr (decl
, "brk_interrupt");
801 /* Returns true if the provided function has the "brk_interrupt" attribute. */
803 is_brk_interrupt_func (const_tree decl
)
805 return has_func_attr (decl
, "brk_interrupt");
808 /* Check "interrupt" attributes. */
810 rl78_handle_func_attribute (tree
* node
,
812 tree args ATTRIBUTE_UNUSED
,
813 int flags ATTRIBUTE_UNUSED
,
816 gcc_assert (DECL_P (* node
));
818 if (TREE_CODE (* node
) != FUNCTION_DECL
)
820 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
822 * no_add_attrs
= true;
825 /* FIXME: We ought to check that the interrupt and exception
826 handler attributes have been applied to void functions. */
830 /* Check "naked" attributes. */
832 rl78_handle_naked_attribute (tree
* node
,
833 tree name ATTRIBUTE_UNUSED
,
835 int flags ATTRIBUTE_UNUSED
,
838 gcc_assert (DECL_P (* node
));
839 gcc_assert (args
== NULL_TREE
);
841 if (TREE_CODE (* node
) != FUNCTION_DECL
)
843 warning (OPT_Wattributes
, "naked attribute only applies to functions");
844 * no_add_attrs
= true;
847 /* Disable warnings about this function - eg reaching the end without
848 seeing a return statement - because the programmer is doing things
849 that gcc does not know about. */
850 TREE_NO_WARNING (* node
) = 1;
855 /* Check "saddr" attributes. */
857 rl78_handle_saddr_attribute (tree
* node
,
859 tree args ATTRIBUTE_UNUSED
,
860 int flags ATTRIBUTE_UNUSED
,
863 gcc_assert (DECL_P (* node
));
865 if (TREE_CODE (* node
) == FUNCTION_DECL
)
867 warning (OPT_Wattributes
, "%qE attribute doesn%'t apply to functions",
869 * no_add_attrs
= true;
875 /* Check "vector" attribute. */
878 rl78_handle_vector_attribute (tree
* node
,
881 int flags ATTRIBUTE_UNUSED
,
884 gcc_assert (DECL_P (* node
));
885 gcc_assert (args
!= NULL_TREE
);
887 if (TREE_CODE (* node
) != FUNCTION_DECL
)
889 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
891 * no_add_attrs
= true;
897 #undef TARGET_ATTRIBUTE_TABLE
898 #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
900 /* Table of RL78-specific attributes. */
901 const struct attribute_spec rl78_attribute_table
[] =
903 /* Name, min_len, max_len, decl_req, type_req, fn_type_req,
904 affects_type_identity, handler, exclude. */
905 { "interrupt", 0, -1, true, false, false, false,
906 rl78_handle_func_attribute
, NULL
},
907 { "brk_interrupt", 0, 0, true, false, false, false,
908 rl78_handle_func_attribute
, NULL
},
909 { "naked", 0, 0, true, false, false, false,
910 rl78_handle_naked_attribute
, NULL
},
911 { "saddr", 0, 0, true, false, false, false,
912 rl78_handle_saddr_attribute
, NULL
},
913 { "vector", 1, -1, true, false, false, false,
914 rl78_handle_vector_attribute
, NULL
},
915 { NULL
, 0, 0, false, false, false, false, NULL
, NULL
}
920 /* Break down an address RTX into its component base/index/addend
921 portions and return TRUE if the address is of a valid form, else
924 characterize_address (rtx x
, rtx
*base
, rtx
*index
, rtx
*addend
)
930 if (GET_CODE (x
) == UNSPEC
931 && XINT (x
, 1) == UNS_ES_ADDR
)
932 x
= XVECEXP (x
, 0, 1);
934 if (GET_CODE (x
) == REG
)
940 /* We sometimes get these without the CONST wrapper */
941 if (GET_CODE (x
) == PLUS
942 && GET_CODE (XEXP (x
, 0)) == SYMBOL_REF
943 && GET_CODE (XEXP (x
, 1)) == CONST_INT
)
949 if (GET_CODE (x
) == PLUS
)
954 if (GET_CODE (*base
) == SUBREG
)
956 if (GET_MODE (*base
) == HImode
957 && GET_MODE (XEXP (*base
, 0)) == SImode
958 && GET_CODE (XEXP (*base
, 0)) == REG
)
960 /* This is a throw-away rtx just to tell everyone
961 else what effective register we're using. */
962 *base
= gen_rtx_REG (HImode
, REGNO (XEXP (*base
, 0)));
966 if (GET_CODE (*base
) != REG
967 && GET_CODE (x
) == REG
)
974 if (GET_CODE (*base
) != REG
)
977 if (GET_CODE (x
) == ZERO_EXTEND
978 && GET_CODE (XEXP (x
, 0)) == REG
)
980 *index
= XEXP (x
, 0);
985 switch (GET_CODE (x
))
988 if (GET_CODE (XEXP (x
, 0)) == SYMBOL_REF
989 && GET_CODE (XEXP (x
, 0)) == CONST_INT
)
1000 switch (GET_CODE (XEXP (x
, 0)))
1024 /* Used by the Whb constraint. Match addresses that use HL+B or HL+C
1027 rl78_hl_b_c_addr_p (rtx op
)
1031 if (GET_CODE (op
) != PLUS
)
1035 if (GET_CODE (hl
) == ZERO_EXTEND
)
1041 if (GET_CODE (hl
) != REG
)
1043 if (GET_CODE (bc
) != ZERO_EXTEND
)
1046 if (GET_CODE (bc
) != REG
)
1048 if (REGNO (hl
) != HL_REG
)
1050 if (REGNO (bc
) != B_REG
&& REGNO (bc
) != C_REG
)
1056 #define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
1058 /* Return the appropriate mode for a named address address. */
1060 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
1061 #define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
1063 static scalar_int_mode
1064 rl78_addr_space_address_mode (addr_space_t addrspace
)
1068 case ADDR_SPACE_GENERIC
:
1070 case ADDR_SPACE_NEAR
:
1072 case ADDR_SPACE_FAR
:
1079 /* Used in various constraints and predicates to match operands in the
1080 "far" address space. */
1087 fprintf (stderr
, "\033[35mrl78_far_p: "); debug_rtx (x
);
1088 fprintf (stderr
, " = %d\033[0m\n", MEM_ADDR_SPACE (x
) == ADDR_SPACE_FAR
);
1091 /* Not all far addresses are legitimate, because the devirtualizer
1092 can't handle them. */
1093 if (! rl78_as_legitimate_address (GET_MODE (x
), XEXP (x
, 0), false, ADDR_SPACE_FAR
))
1096 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x
))) == 32;
1099 /* Return the appropriate mode for a named address pointer. */
1100 #undef TARGET_ADDR_SPACE_POINTER_MODE
1101 #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
1103 static scalar_int_mode
1104 rl78_addr_space_pointer_mode (addr_space_t addrspace
)
1108 case ADDR_SPACE_GENERIC
:
1110 case ADDR_SPACE_NEAR
:
1112 case ADDR_SPACE_FAR
:
1119 /* Returns TRUE for valid addresses. */
1120 #undef TARGET_VALID_POINTER_MODE
1121 #define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
1124 rl78_valid_pointer_mode (scalar_int_mode m
)
1126 return (m
== HImode
|| m
== SImode
);
1129 #undef TARGET_LEGITIMATE_CONSTANT_P
1130 #define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
1133 rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
)
1139 #define TARGET_LRA_P hook_bool_void_false
1141 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
1142 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
1145 rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
,
1146 bool strict ATTRIBUTE_UNUSED
, addr_space_t as ATTRIBUTE_UNUSED
)
1148 rtx base
, index
, addend
;
1149 bool is_far_addr
= false;
1152 as_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (as
));
1154 if (GET_CODE (x
) == UNSPEC
1155 && XINT (x
, 1) == UNS_ES_ADDR
)
1157 x
= XVECEXP (x
, 0, 1);
1161 if (as_bits
== 16 && is_far_addr
)
1164 if (! characterize_address (x
, &base
, &index
, &addend
))
1167 /* We can't extract the high/low portions of a PLUS address
1168 involving a register during devirtualization, so make sure all
1169 such __far addresses do not have addends. This forces GCC to do
1170 the sum separately. */
1171 if (addend
&& base
&& as_bits
== 32 && GET_MODE (base
) == SImode
)
1176 int ir
= REGNO (index
);
1177 int br
= REGNO (base
);
1179 #define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
1180 OK (REG_IS (br
, HL_REG
) && REG_IS (ir
, B_REG
), "[hl+b]");
1181 OK (REG_IS (br
, HL_REG
) && REG_IS (ir
, C_REG
), "[hl+c]");
1185 if (strict
&& base
&& GET_CODE (base
) == REG
&& REGNO (base
) >= FIRST_PSEUDO_REGISTER
)
1188 if (! cfun
->machine
->virt_insns_ok
&& base
&& GET_CODE (base
) == REG
1189 && REGNO (base
) >= 8 && REGNO (base
) <= 31)
1195 /* Determine if one named address space is a subset of another. */
1196 #undef TARGET_ADDR_SPACE_SUBSET_P
1197 #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
1200 rl78_addr_space_subset_p (addr_space_t subset
, addr_space_t superset
)
1205 subset_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset
));
1206 superset_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset
));
1208 return (subset_bits
<= superset_bits
);
1211 #undef TARGET_ADDR_SPACE_CONVERT
1212 #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
1214 /* Convert from one address space to another. */
1216 rl78_addr_space_convert (rtx op
, tree from_type
, tree to_type
)
1218 addr_space_t from_as
= TYPE_ADDR_SPACE (TREE_TYPE (from_type
));
1219 addr_space_t to_as
= TYPE_ADDR_SPACE (TREE_TYPE (to_type
));
1224 to_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as
));
1225 from_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as
));
1227 if (to_bits
< from_bits
)
1230 /* This is unpredictable, as we're truncating off usable address
1233 warning (OPT_Waddress
, "converting far pointer to near pointer");
1234 result
= gen_reg_rtx (HImode
);
1235 if (GET_CODE (op
) == SYMBOL_REF
1236 || (GET_CODE (op
) == REG
&& REGNO (op
) >= FIRST_PSEUDO_REGISTER
))
1237 tmp
= gen_rtx_raw_SUBREG (HImode
, op
, 0);
1239 tmp
= simplify_subreg (HImode
, op
, SImode
, 0);
1240 gcc_assert (tmp
!= NULL_RTX
);
1241 emit_move_insn (result
, tmp
);
1244 else if (to_bits
> from_bits
)
1246 /* This always works. */
1247 result
= gen_reg_rtx (SImode
);
1248 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 0), op
);
1249 if (TREE_CODE (from_type
) == POINTER_TYPE
1250 && TREE_CODE (TREE_TYPE (from_type
)) == FUNCTION_TYPE
)
1251 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 2), const0_rtx
);
1253 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 2), GEN_INT (0x0f));
1261 /* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
1263 rl78_regno_mode_code_ok_for_base_p (int regno
, machine_mode mode ATTRIBUTE_UNUSED
,
1264 addr_space_t address_space ATTRIBUTE_UNUSED
,
1265 int outer_code ATTRIBUTE_UNUSED
, int index_code
)
1267 if (regno
<= SP_REG
&& regno
>= 16)
1269 if (index_code
== REG
)
1270 return (regno
== HL_REG
);
1271 if (regno
== C_REG
|| regno
== B_REG
|| regno
== E_REG
|| regno
== L_REG
)
1276 /* Implements MODE_CODE_BASE_REG_CLASS. */
1278 rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED
,
1279 addr_space_t address_space ATTRIBUTE_UNUSED
,
1280 int outer_code ATTRIBUTE_UNUSED
,
1281 int index_code ATTRIBUTE_UNUSED
)
1286 /* Typical stack layout should looks like this after the function's prologue:
1291 | | arguments saved | Increasing
1292 | | on the stack | addresses
1293 PARENT arg pointer -> | | /
1294 -------------------------- ---- -------------------
1295 CHILD |ret | return address
1300 frame pointer -> | | /
1308 | | outgoing | Decreasing
1309 | | arguments | addresses
1310 current stack pointer -> | | / |
1311 -------------------------- ---- ------------------ V
1314 /* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
1315 described in the machine_Function struct definition, above. */
1317 rl78_initial_elimination_offset (int from
, int to
)
1319 int rv
= 0; /* as if arg to arg */
1321 rl78_compute_frame_info ();
1325 case STACK_POINTER_REGNUM
:
1326 rv
+= cfun
->machine
->framesize_outgoing
;
1327 rv
+= cfun
->machine
->framesize_locals
;
1329 case FRAME_POINTER_REGNUM
:
1330 rv
+= cfun
->machine
->framesize_regs
;
1339 case FRAME_POINTER_REGNUM
:
1341 rv
-= cfun
->machine
->framesize_regs
;
1342 case ARG_POINTER_REGNUM
:
1352 rl78_is_naked_func (void)
1354 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl
)) != NULL_TREE
);
1357 /* Check if the block uses mul/div insns for G13 target. */
1360 check_mduc_usage (void)
1365 FOR_EACH_BB_FN (bb
, cfun
)
1367 FOR_BB_INSNS (bb
, insn
)
1370 && (get_attr_is_g13_muldiv_insn (insn
) == IS_G13_MULDIV_INSN_YES
))
1377 /* Expand the function prologue (from the prologue pattern). */
1380 rl78_expand_prologue (void)
1383 rtx sp
= gen_rtx_REG (HImode
, STACK_POINTER_REGNUM
);
1384 rtx ax
= gen_rtx_REG (HImode
, AX_REG
);
1387 if (rl78_is_naked_func ())
1390 /* Always re-compute the frame info - the register usage may have changed. */
1391 rl78_compute_frame_info ();
1393 if (MUST_SAVE_MDUC_REGISTERS
&& (!crtl
->is_leaf
|| check_mduc_usage ()))
1394 cfun
->machine
->framesize
+= ARRAY_SIZE (mduc_regs
) * 2;
1396 if (flag_stack_usage_info
)
1397 current_function_static_stack_size
= cfun
->machine
->framesize
;
1399 if (is_interrupt_func (cfun
->decl
) && !TARGET_G10
)
1400 for (i
= 0; i
< 4; i
++)
1401 if (cfun
->machine
->need_to_push
[i
])
1403 /* Select Bank 0 if we are using any registers from Bank 0. */
1404 emit_insn (gen_sel_rb (GEN_INT (0)));
1408 for (i
= 0; i
< 16; i
++)
1409 if (cfun
->machine
->need_to_push
[i
])
1417 emit_move_insn (ax
, gen_rtx_REG (HImode
, reg
));
1423 int need_bank
= i
/4;
1425 if (need_bank
!= rb
)
1427 emit_insn (gen_sel_rb (GEN_INT (need_bank
)));
1432 F (emit_insn (gen_push (gen_rtx_REG (HImode
, reg
))));
1436 emit_insn (gen_sel_rb (GEN_INT (0)));
1438 /* Save ES register inside interrupt functions if it is used. */
1439 if (is_interrupt_func (cfun
->decl
) && cfun
->machine
->uses_es
)
1441 emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode
, A_REG
)));
1442 F (emit_insn (gen_push (ax
)));
1445 /* Save MDUC registers inside interrupt routine. */
1446 if (MUST_SAVE_MDUC_REGISTERS
&& (!crtl
->is_leaf
|| check_mduc_usage ()))
1448 for (unsigned i
= 0; i
< ARRAY_SIZE (mduc_regs
); i
++)
1450 mduc_reg_type
*reg
= mduc_regs
+ i
;
1451 rtx mem_mduc
= gen_rtx_MEM (reg
->mode
, GEN_INT (reg
->address
));
1453 MEM_VOLATILE_P (mem_mduc
) = 1;
1454 if (reg
->mode
== QImode
)
1455 emit_insn (gen_movqi (gen_rtx_REG (QImode
, A_REG
), mem_mduc
));
1457 emit_insn (gen_movhi (gen_rtx_REG (HImode
, AX_REG
), mem_mduc
));
1459 emit_insn (gen_push (gen_rtx_REG (HImode
, AX_REG
)));
1463 if (frame_pointer_needed
)
1465 F (emit_move_insn (ax
, sp
));
1466 F (emit_move_insn (gen_rtx_REG (HImode
, FRAME_POINTER_REGNUM
), ax
));
1469 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1472 /* If we need to subtract more than 254*3 then it is faster and
1473 smaller to move SP into AX and perform the subtraction there. */
1478 emit_move_insn (ax
, sp
);
1479 emit_insn (gen_subhi3 (ax
, ax
, GEN_INT (fs
)));
1480 insn
= F (emit_move_insn (sp
, ax
));
1481 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
1482 gen_rtx_SET (sp
, gen_rtx_PLUS (HImode
, sp
,
1489 int fs_byte
= (fs
> 254) ? 254 : fs
;
1491 F (emit_insn (gen_subhi3 (sp
, sp
, GEN_INT (fs_byte
))));
1498 /* Expand the function epilogue (from the epilogue pattern). */
1500 rl78_expand_epilogue (void)
1503 rtx sp
= gen_rtx_REG (HImode
, STACK_POINTER_REGNUM
);
1504 rtx ax
= gen_rtx_REG (HImode
, AX_REG
);
1507 if (rl78_is_naked_func ())
1510 if (frame_pointer_needed
)
1512 emit_move_insn (ax
, gen_rtx_REG (HImode
, FRAME_POINTER_REGNUM
));
1513 emit_move_insn (sp
, ax
);
1517 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1520 emit_move_insn (ax
, sp
);
1521 emit_insn (gen_addhi3 (ax
, ax
, GEN_INT (fs
)));
1522 emit_move_insn (sp
, ax
);
1528 int fs_byte
= (fs
> 254) ? 254 : fs
;
1530 emit_insn (gen_addhi3 (sp
, sp
, GEN_INT (fs_byte
)));
1536 /* Restore MDUC registers from interrupt routine. */
1537 if (MUST_SAVE_MDUC_REGISTERS
&& (!crtl
->is_leaf
|| check_mduc_usage ()))
1539 for (int i
= ARRAY_SIZE (mduc_regs
) - 1; i
>= 0; i
--)
1541 mduc_reg_type
*reg
= mduc_regs
+ i
;
1542 rtx mem_mduc
= gen_rtx_MEM (reg
->mode
, GEN_INT (reg
->address
));
1544 emit_insn (gen_pop (gen_rtx_REG (HImode
, AX_REG
)));
1545 MEM_VOLATILE_P (mem_mduc
) = 1;
1546 if (reg
->mode
== QImode
)
1547 emit_insn (gen_movqi (mem_mduc
, gen_rtx_REG (QImode
, A_REG
)));
1549 emit_insn (gen_movhi (mem_mduc
, gen_rtx_REG (HImode
, AX_REG
)));
1553 if (is_interrupt_func (cfun
->decl
) && cfun
->machine
->uses_es
)
1555 emit_insn (gen_pop (gen_rtx_REG (HImode
, AX_REG
)));
1556 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode
, A_REG
)));
1559 for (i
= 15; i
>= 0; i
--)
1560 if (cfun
->machine
->need_to_push
[i
])
1562 rtx dest
= gen_rtx_REG (HImode
, i
* 2);
1567 emit_insn (gen_pop (dest
));
1570 emit_insn (gen_pop (ax
));
1571 emit_move_insn (dest
, ax
);
1572 /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */
1573 emit_insn (gen_use (dest
));
1578 int need_bank
= i
/ 4;
1580 if (need_bank
!= rb
)
1582 emit_insn (gen_sel_rb (GEN_INT (need_bank
)));
1585 emit_insn (gen_pop (dest
));
1590 emit_insn (gen_sel_rb (GEN_INT (0)));
1592 if (cfun
->machine
->trampolines_used
)
1593 emit_insn (gen_trampoline_uninit ());
1595 if (is_brk_interrupt_func (cfun
->decl
))
1596 emit_jump_insn (gen_brk_interrupt_return ());
1597 else if (is_interrupt_func (cfun
->decl
))
1598 emit_jump_insn (gen_interrupt_return ());
1600 emit_jump_insn (gen_rl78_return ());
1603 /* Likewise, for exception handlers. */
1605 rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED
)
1607 /* FIXME - replace this with an indirect jump with stack adjust. */
1608 emit_jump_insn (gen_rl78_return ());
1611 #undef TARGET_ASM_FUNCTION_PROLOGUE
1612 #define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1615 add_vector_labels (FILE *file
, const char *aname
)
1619 const char *vname
= "vect";
1623 /* This node is for the vector/interrupt tag itself */
1624 vec_attr
= lookup_attribute (aname
, DECL_ATTRIBUTES (current_function_decl
));
1628 /* Now point it at the first argument */
1629 vec_attr
= TREE_VALUE (vec_attr
);
1631 /* Iterate through the arguments. */
1634 val_attr
= TREE_VALUE (vec_attr
);
1635 switch (TREE_CODE (val_attr
))
1638 s
= TREE_STRING_POINTER (val_attr
);
1639 goto string_id_common
;
1641 case IDENTIFIER_NODE
:
1642 s
= IDENTIFIER_POINTER (val_attr
);
1645 if (strcmp (s
, "$default") == 0)
1647 fprintf (file
, "\t.global\t$tableentry$default$%s\n", vname
);
1648 fprintf (file
, "$tableentry$default$%s:\n", vname
);
1655 vnum
= TREE_INT_CST_LOW (val_attr
);
1657 fprintf (file
, "\t.global\t$tableentry$%d$%s\n", vnum
, vname
);
1658 fprintf (file
, "$tableentry$%d$%s:\n", vnum
, vname
);
1665 vec_attr
= TREE_CHAIN (vec_attr
);
1670 /* We don't use this to actually emit the function prologue. We use
1671 this to insert a comment in the asm file describing the
1674 rl78_start_function (FILE *file
)
1678 add_vector_labels (file
, "interrupt");
1679 add_vector_labels (file
, "vector");
1681 if (cfun
->machine
->framesize
== 0)
1683 fprintf (file
, "\t; start of function\n");
1685 if (cfun
->machine
->framesize_regs
)
1687 fprintf (file
, "\t; push %d:", cfun
->machine
->framesize_regs
);
1688 for (i
= 0; i
< 16; i
++)
1689 if (cfun
->machine
->need_to_push
[i
])
1690 fprintf (file
, " %s", word_regnames
[i
*2]);
1691 fprintf (file
, "\n");
1694 if (frame_pointer_needed
)
1695 fprintf (file
, "\t; $fp points here (r22)\n");
1697 if (cfun
->machine
->framesize_locals
)
1698 fprintf (file
, "\t; locals: %d byte%s\n", cfun
->machine
->framesize_locals
,
1699 cfun
->machine
->framesize_locals
== 1 ? "" : "s");
1701 if (cfun
->machine
->framesize_outgoing
)
1702 fprintf (file
, "\t; outgoing: %d byte%s\n", cfun
->machine
->framesize_outgoing
,
1703 cfun
->machine
->framesize_outgoing
== 1 ? "" : "s");
1705 if (cfun
->machine
->uses_es
)
1706 fprintf (file
, "\t; uses ES register\n");
1708 if (MUST_SAVE_MDUC_REGISTERS
)
1709 fprintf (file
, "\t; preserves MDUC registers\n");
1712 /* Return an RTL describing where a function return value of type RET_TYPE
1715 #undef TARGET_FUNCTION_VALUE
1716 #define TARGET_FUNCTION_VALUE rl78_function_value
1719 rl78_function_value (const_tree ret_type
,
1720 const_tree fn_decl_or_type ATTRIBUTE_UNUSED
,
1721 bool outgoing ATTRIBUTE_UNUSED
)
1723 machine_mode mode
= TYPE_MODE (ret_type
);
1725 return gen_rtx_REG (mode
, 8);
1728 #undef TARGET_PROMOTE_FUNCTION_MODE
1729 #define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
1732 rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED
,
1734 int *punsignedp ATTRIBUTE_UNUSED
,
1735 const_tree funtype ATTRIBUTE_UNUSED
, int for_return ATTRIBUTE_UNUSED
)
1740 #undef TARGET_FUNCTION_ARG
1741 #define TARGET_FUNCTION_ARG rl78_function_arg
1744 rl78_function_arg (cumulative_args_t
, const function_arg_info
&)
1749 #undef TARGET_FUNCTION_ARG_ADVANCE
1750 #define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1753 rl78_function_arg_advance (cumulative_args_t cum_v
,
1754 const function_arg_info
&arg
)
1757 CUMULATIVE_ARGS
* cum
= get_cumulative_args (cum_v
);
1759 rounded_size
= arg
.promoted_size_in_bytes ();
1760 if (rounded_size
& 1)
1762 (*cum
) += rounded_size
;
1765 #undef TARGET_FUNCTION_ARG_BOUNDARY
1766 #define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1769 rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED
,
1770 const_tree type ATTRIBUTE_UNUSED
)
1775 /* Supported modifier letters:
1777 A - address of a MEM
1778 S - SADDR form of a real register
1779 v - real register corresponding to a virtual register
1780 m - minus - negative of CONST_INT value.
1781 C - inverse of a conditional (NE vs EQ for example)
1782 C - complement of an integer
1783 z - collapsed conditional
1784 s - shift count mod 8
1785 S - shift count mod 16
1786 r - reverse shift count (8-(count mod 8))
1789 h - bottom HI of an SI
1791 q - bottom QI of an HI
1793 e - third QI of an SI (i.e. where the ES register gets values from)
1794 E - fourth QI of an SI (i.e. MSB)
1796 p - Add +0 to a zero-indexed HL based address.
1799 /* Implements the bulk of rl78_print_operand, below. We do it this
1800 way because we need to test for a constant at the top level and
1801 insert the '#', but not test for it anywhere else as we recurse
1802 down into the operand. */
1804 rl78_print_operand_1 (FILE * file
, rtx op
, int letter
)
1808 switch (GET_CODE (op
))
1812 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1815 if (rl78_far_p (op
))
1817 fprintf (file
, "es:");
1818 if (GET_CODE (XEXP (op
, 0)) == UNSPEC
)
1819 op
= gen_rtx_MEM (GET_MODE (op
), XVECEXP (XEXP (op
, 0), 0, 1));
1823 op
= adjust_address (op
, HImode
, 2);
1828 op
= adjust_address (op
, HImode
, 0);
1833 op
= adjust_address (op
, QImode
, 1);
1838 op
= adjust_address (op
, QImode
, 0);
1843 op
= adjust_address (op
, QImode
, 2);
1848 op
= adjust_address (op
, QImode
, 3);
1851 if (CONSTANT_P (XEXP (op
, 0)))
1853 if (!rl78_saddr_p (op
))
1854 fprintf (file
, "!");
1855 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1857 else if (GET_CODE (XEXP (op
, 0)) == PLUS
1858 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
)
1860 if (!rl78_saddr_p (op
))
1861 fprintf (file
, "!");
1862 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1864 else if (GET_CODE (XEXP (op
, 0)) == PLUS
1865 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
1866 && REGNO (XEXP (XEXP (op
, 0), 0)) == 2)
1868 rl78_print_operand_1 (file
, XEXP (XEXP (op
, 0), 1), 'u');
1869 fprintf (file
, "[");
1870 rl78_print_operand_1 (file
, XEXP (XEXP (op
, 0), 0), 0);
1871 if (letter
== 'p' && GET_CODE (XEXP (op
, 0)) == REG
)
1872 fprintf (file
, "+0");
1873 fprintf (file
, "]");
1878 fprintf (file
, "[");
1879 rl78_print_operand_1 (file
, op
, letter
);
1880 if (letter
== 'p' && REG_P (op
) && REGNO (op
) == 6)
1881 fprintf (file
, "+0");
1882 fprintf (file
, "]");
1889 fprintf (file
, "%s", reg_names
[REGNO (op
) | 1]);
1890 else if (letter
== 'H')
1891 fprintf (file
, "%s", reg_names
[REGNO (op
) + 2]);
1892 else if (letter
== 'q')
1893 fprintf (file
, "%s", reg_names
[REGNO (op
) & ~1]);
1894 else if (letter
== 'e')
1895 fprintf (file
, "%s", reg_names
[REGNO (op
) + 2]);
1896 else if (letter
== 'E')
1897 fprintf (file
, "%s", reg_names
[REGNO (op
) + 3]);
1898 else if (letter
== 'S')
1899 fprintf (file
, "0x%x", 0xffef8 + REGNO (op
));
1900 else if (GET_MODE (op
) == HImode
1901 && ! (REGNO (op
) & ~0xfe))
1904 fprintf (file
, "%s", word_regnames
[REGNO (op
) % 8]);
1906 fprintf (file
, "%s", word_regnames
[REGNO (op
)]);
1909 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
1914 fprintf (file
, "%ld", INTVAL (op
) >> 8);
1915 else if (letter
== 'H')
1916 fprintf (file
, "%ld", INTVAL (op
) >> 16);
1917 else if (letter
== 'q')
1918 fprintf (file
, "%ld", INTVAL (op
) & 0xff);
1919 else if (letter
== 'h')
1920 fprintf (file
, "%ld", INTVAL (op
) & 0xffff);
1921 else if (letter
== 'e')
1922 fprintf (file
, "%ld", (INTVAL (op
) >> 16) & 0xff);
1923 else if (letter
== 'B')
1925 int ival
= INTVAL (op
);
1928 if (exact_log2 (ival
) >= 0)
1929 fprintf (file
, "%d", exact_log2 (ival
));
1931 fprintf (file
, "%d", exact_log2 (~ival
& 0xff));
1933 else if (letter
== 'E')
1934 fprintf (file
, "%ld", (INTVAL (op
) >> 24) & 0xff);
1935 else if (letter
== 'm')
1936 fprintf (file
, "%ld", - INTVAL (op
));
1937 else if (letter
== 's')
1938 fprintf (file
, "%ld", INTVAL (op
) % 8);
1939 else if (letter
== 'S')
1940 fprintf (file
, "%ld", INTVAL (op
) % 16);
1941 else if (letter
== 'r')
1942 fprintf (file
, "%ld", 8 - (INTVAL (op
) % 8));
1943 else if (letter
== 'C')
1944 fprintf (file
, "%ld", (INTVAL (op
) ^ 0x8000) & 0xffff);
1946 fprintf (file
, "%ld", INTVAL (op
));
1950 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1955 int bits
= INTVAL (XEXP (op
, 1));
1956 int ofs
= INTVAL (XEXP (op
, 2));
1957 if (bits
== 16 && ofs
== 0)
1958 fprintf (file
, "%%lo16(");
1959 else if (bits
== 16 && ofs
== 16)
1960 fprintf (file
, "%%hi16(");
1961 else if (bits
== 8 && ofs
== 16)
1962 fprintf (file
, "%%hi8(");
1965 rl78_print_operand_1 (file
, XEXP (op
, 0), 0);
1966 fprintf (file
, ")");
1971 if (GET_CODE (XEXP (op
, 0)) == REG
)
1972 fprintf (file
, "%s", reg_names
[REGNO (XEXP (op
, 0))]);
1974 print_rtl (file
, op
);
1981 fprintf (file
, "%%hi16(");
1987 fprintf (file
, "%%lo16(");
1993 fprintf (file
, "%%hi8(");
1997 if (letter
== 'q' || letter
== 'Q')
1998 output_operand_lossage ("q/Q modifiers invalid for symbol references");
2000 if (GET_CODE (XEXP (op
, 0)) == ZERO_EXTEND
)
2002 if (GET_CODE (XEXP (op
, 1)) == SYMBOL_REF
2003 && SYMBOL_REF_DECL (XEXP (op
, 1))
2004 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op
, 1))) == FUNCTION_DECL
)
2006 fprintf (file
, "%%code(");
2007 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op
, 1), 0)));
2008 fprintf (file
, "+");
2009 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
2010 fprintf (file
, ")");
2014 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
2015 fprintf (file
, "+");
2016 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
2021 if (GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
2022 && SYMBOL_REF_DECL (XEXP (op
, 0))
2023 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op
, 0))) == FUNCTION_DECL
)
2025 fprintf (file
, "%%code(");
2026 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op
, 0), 0)));
2027 fprintf (file
, "+");
2028 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
2029 fprintf (file
, ")");
2033 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
2034 fprintf (file
, "+");
2035 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
2039 fprintf (file
, ")");
2043 if (GET_MODE (op
) == HImode
2044 && SUBREG_BYTE (op
) == 0)
2046 fprintf (file
, "%%lo16(");
2047 rl78_print_operand_1 (file
, SUBREG_REG (op
), 0);
2048 fprintf (file
, ")");
2050 else if (GET_MODE (op
) == HImode
2051 && SUBREG_BYTE (op
) == 2)
2053 fprintf (file
, "%%hi16(");
2054 rl78_print_operand_1 (file
, SUBREG_REG (op
), 0);
2055 fprintf (file
, ")");
2059 fprintf (file
, "(%s)", GET_RTX_NAME (GET_CODE (op
)));
2067 fprintf (file
, "%%hi16(");
2073 fprintf (file
, "%%lo16(");
2079 fprintf (file
, "%%hi8(");
2083 if (letter
== 'q' || letter
== 'Q')
2084 output_operand_lossage ("q/Q modifiers invalid for symbol references");
2086 if (SYMBOL_REF_DECL (op
) && TREE_CODE (SYMBOL_REF_DECL (op
)) == FUNCTION_DECL
)
2088 fprintf (file
, "%%code(");
2089 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (op
, 0)));
2090 fprintf (file
, ")");
2093 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (op
, 0)));
2095 fprintf (file
, ")");
2100 output_asm_label (op
);
2105 fprintf (file
, "#comparison eliminated");
2107 fprintf (file
, letter
== 'C' ? "nc" : "c");
2111 fprintf (file
, "br");
2113 fprintf (file
, letter
== 'C' ? "h" : "nh");
2117 fprintf (file
, "br");
2119 fprintf (file
, letter
== 'C' ? "c" : "nc");
2123 fprintf (file
, "#comparison eliminated");
2125 fprintf (file
, letter
== 'C' ? "nh" : "h");
2129 fprintf (file
, "br");
2131 fprintf (file
, letter
== 'C' ? "nz" : "z");
2135 fprintf (file
, "#comparison eliminated");
2137 fprintf (file
, letter
== 'C' ? "z" : "nz");
2140 /* Note: these assume appropriate adjustments were made so that
2141 unsigned comparisons, which is all this chip has, will
2145 fprintf (file
, "#comparison eliminated");
2147 fprintf (file
, letter
== 'C' ? "nc" : "c");
2151 fprintf (file
, "br");
2153 fprintf (file
, letter
== 'C' ? "h" : "nh");
2157 fprintf (file
, "br");
2159 fprintf (file
, letter
== 'C' ? "c" : "nc");
2163 fprintf (file
, "#comparison eliminated");
2165 fprintf (file
, letter
== 'C' ? "nh" : "h");
2169 fprintf (file
, "(%s)", GET_RTX_NAME (GET_CODE (op
)));
2174 #undef TARGET_PRINT_OPERAND
2175 #define TARGET_PRINT_OPERAND rl78_print_operand
2178 rl78_print_operand (FILE * file
, rtx op
, int letter
)
2180 if (CONSTANT_P (op
) && letter
!= 'u' && letter
!= 's' && letter
!= 'r' && letter
!= 'S' && letter
!= 'B')
2181 fprintf (file
, "#");
2182 rl78_print_operand_1 (file
, op
, letter
);
2185 #undef TARGET_TRAMPOLINE_INIT
2186 #define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
2188 /* Note that the RL78's addressing makes it very difficult to do
2189 trampolines on the stack. So, libgcc has a small pool of
2190 trampolines from which one is allocated to this task. */
2192 rl78_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
2194 rtx mov_addr
, thunk_addr
;
2195 rtx function
= XEXP (DECL_RTL (fndecl
), 0);
2197 mov_addr
= adjust_address (m_tramp
, HImode
, 0);
2198 thunk_addr
= gen_reg_rtx (HImode
);
2200 function
= force_reg (HImode
, function
);
2201 static_chain
= force_reg (HImode
, static_chain
);
2203 emit_insn (gen_trampoline_init (thunk_addr
, function
, static_chain
));
2204 emit_move_insn (mov_addr
, thunk_addr
);
2206 cfun
->machine
->trampolines_used
= 1;
2209 #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
2210 #define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
2213 rl78_trampoline_adjust_address (rtx m_tramp
)
2215 rtx x
= gen_rtx_MEM (HImode
, m_tramp
);
2219 /* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
2220 the "normal" compares, specifically, it only has unsigned compares,
2221 so we must synthesize the missing ones. */
2223 rl78_expand_compare (rtx
*operands
)
2225 if (GET_CODE (operands
[2]) == MEM
)
2226 operands
[2] = copy_to_mode_reg (GET_MODE (operands
[2]), operands
[2]);
2231 /* Define this to 1 if you are debugging the peephole optimizers. */
2232 #define DEBUG_PEEP 0
2234 /* Predicate used to enable the peephole2 patterns in rl78-virt.md.
2235 The default "word" size is a byte so we can effectively use all the
2236 registers, but we want to do 16-bit moves whenever possible. This
2237 function determines when such a move is an option. */
2239 rl78_peep_movhi_p (rtx
*operands
)
2244 /* (set (op0) (op1))
2245 (set (op2) (op3)) */
2247 if (! rl78_virt_insns_ok ())
2251 fprintf (stderr
, "\033[33m");
2252 debug_rtx (operands
[0]);
2253 debug_rtx (operands
[1]);
2254 debug_rtx (operands
[2]);
2255 debug_rtx (operands
[3]);
2256 fprintf (stderr
, "\033[0m");
2259 /* You can move a constant to memory as QImode, but not HImode. */
2260 if (GET_CODE (operands
[0]) == MEM
2261 && GET_CODE (operands
[1]) != REG
)
2264 fprintf (stderr
, "no peep: move constant to memory\n");
2269 if (rtx_equal_p (operands
[0], operands
[3]))
2272 fprintf (stderr
, "no peep: overlapping\n");
2277 for (i
= 0; i
< 2; i
++)
2279 if (GET_CODE (operands
[i
]) != GET_CODE (operands
[i
+2]))
2282 fprintf (stderr
, "no peep: different codes\n");
2286 if (GET_MODE (operands
[i
]) != GET_MODE (operands
[i
+2]))
2289 fprintf (stderr
, "no peep: different modes\n");
2294 switch (GET_CODE (operands
[i
]))
2298 if (REGNO (operands
[i
]) + 1 != REGNO (operands
[i
+2])
2299 || GET_MODE (operands
[i
]) != QImode
)
2302 fprintf (stderr
, "no peep: wrong regnos %d %d %d\n",
2303 REGNO (operands
[i
]), REGNO (operands
[i
+2]),
2308 if (! rl78_hard_regno_mode_ok (REGNO (operands
[i
]), HImode
))
2311 fprintf (stderr
, "no peep: reg %d not HI\n", REGNO (operands
[i
]));
2321 if (GET_MODE (operands
[i
]) != QImode
)
2323 if (MEM_ALIGN (operands
[i
]) < 16)
2325 a
= XEXP (operands
[i
], 0);
2326 if (GET_CODE (a
) == CONST
)
2328 if (GET_CODE (a
) == PLUS
)
2330 if (GET_CODE (a
) == CONST_INT
2334 fprintf (stderr
, "no peep: misaligned mem %d\n", i
);
2335 debug_rtx (operands
[i
]);
2339 m
= adjust_address (operands
[i
], QImode
, 1);
2340 if (! rtx_equal_p (m
, operands
[i
+2]))
2343 fprintf (stderr
, "no peep: wrong mem %d\n", i
);
2345 debug_rtx (operands
[i
+2]);
2353 fprintf (stderr
, "no peep: wrong rtx %d\n", i
);
2359 fprintf (stderr
, "\033[32mpeep!\033[0m\n");
2364 /* Likewise, when a peephole is activated, this function helps compute
2365 the new operands. */
2367 rl78_setup_peep_movhi (rtx
*operands
)
2371 for (i
= 0; i
< 2; i
++)
2373 switch (GET_CODE (operands
[i
]))
2376 operands
[i
+4] = gen_rtx_REG (HImode
, REGNO (operands
[i
]));
2380 operands
[i
+4] = GEN_INT ((INTVAL (operands
[i
]) & 0xff) + ((char) INTVAL (operands
[i
+2])) * 256);
2384 operands
[i
+4] = adjust_address (operands
[i
], HImode
, 0);
2394 How Devirtualization works in the RL78 GCC port
2398 The RL78 is an 8-bit port with some 16-bit operations. It has 32
2399 bytes of register space, in four banks, memory-mapped. One bank is
2400 the "selected" bank and holds the registers used for primary
2401 operations. Since the registers are memory mapped, often you can
2402 still refer to the unselected banks via memory accesses.
2406 The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
2407 and refers to the other banks via their memory addresses, although
2408 they're treated as regular registers internally. These "virtual"
2409 registers are R8 through R23 (bank3 is reserved for asm-based
2410 interrupt handlers).
2412 There are four machine description files:
2414 rl78.md - common register-independent patterns and definitions
2415 rl78-expand.md - expanders
2416 rl78-virt.md - patterns that match BEFORE devirtualization
2417 rl78-real.md - patterns that match AFTER devirtualization
2419 At least through register allocation and reload, gcc is told that it
2420 can do pretty much anything - but may only use the virtual registers.
2421 GCC cannot properly create the varying addressing modes that the RL78
2422 supports in an efficient way.
2424 Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
2425 uses the "valloc" attribute in rl78-virt.md for determining the rules
2426 by which it will replace virtual registers with real registers (or
2427 not) and how to make up addressing modes. For example, insns tagged
2428 with "ro1" have a single read-only parameter, which may need to be
2429 moved from memory/constant/vreg to a suitable real register. As part
2430 of devirtualization, a flag is toggled, disabling the rl78-virt.md
2431 patterns and enabling the rl78-real.md patterns. The new patterns'
2432 constraints are used to determine the real registers used. NOTE:
2433 patterns in rl78-virt.md essentially ignore the constrains and rely on
2434 predicates, where the rl78-real.md ones essentially ignore the
2435 predicates and rely on the constraints.
2437 The devirtualization pass is scheduled via the pass manager (despite
2438 being called "rl78_reorg") so it can be scheduled prior to var-track
2439 (the idea is to let gdb know about the new registers). Ideally, it
2440 would be scheduled right after pro/epilogue generation, so the
2441 post-reload optimizers could operate on the real registers, but when I
2442 tried that there were some issues building the target libraries.
2444 During devirtualization, a simple register move optimizer is run. It
2445 would be better to run a full CSE/propogation pass on it though, but
2446 that has not yet been attempted.
2449 #define DEBUG_ALLOC 0
2451 #define OP(x) (*recog_data.operand_loc[x])
2453 /* This array is used to hold knowledge about the contents of the
2454 real registers (A ... H), the memory-based registers (r8 ... r31)
2455 and the first NUM_STACK_LOCS words on the stack. We use this to
2456 avoid generating redundant move instructions.
2458 A value in the range 0 .. 31 indicates register A .. r31.
2459 A value in the range 32 .. 63 indicates stack slot (value - 32).
2460 A value of NOT_KNOWN indicates that the contents of that location
2463 #define NUM_STACK_LOCS 32
2464 #define NOT_KNOWN 127
2466 static unsigned char content_memory
[32 + NUM_STACK_LOCS
];
2468 static unsigned char saved_update_index
= NOT_KNOWN
;
2469 static unsigned char saved_update_value
;
2470 static machine_mode saved_update_mode
;
2474 clear_content_memory (void)
2476 memset (content_memory
, NOT_KNOWN
, sizeof content_memory
);
2478 fprintf (dump_file
, " clear content memory\n");
2479 saved_update_index
= NOT_KNOWN
;
2482 /* Convert LOC into an index into the content_memory array.
2483 If LOC cannot be converted, return NOT_KNOWN. */
2485 static unsigned char
2486 get_content_index (rtx loc
)
2490 if (loc
== NULL_RTX
)
2495 if (REGNO (loc
) < 32)
2500 mode
= GET_MODE (loc
);
2502 if (! rl78_stack_based_mem (loc
, mode
))
2505 loc
= XEXP (loc
, 0);
2508 /* loc = MEM (SP) */
2511 /* loc = MEM (PLUS (SP, INT)). */
2512 loc
= XEXP (loc
, 1);
2514 if (INTVAL (loc
) < NUM_STACK_LOCS
)
2515 return 32 + INTVAL (loc
);
2520 /* Return a string describing content INDEX in mode MODE.
2521 WARNING: Can return a pointer to a static buffer. */
2523 get_content_name (unsigned char index
, machine_mode mode
)
2525 static char buffer
[128];
2527 if (index
== NOT_KNOWN
)
2531 sprintf (buffer
, "stack slot %d", index
- 32);
2532 else if (mode
== HImode
)
2533 sprintf (buffer
, "%s%s",
2534 reg_names
[index
+ 1], reg_names
[index
]);
2536 return reg_names
[index
];
2544 display_content_memory (FILE * file
)
2548 fprintf (file
, " Known memory contents:\n");
2550 for (i
= 0; i
< sizeof content_memory
; i
++)
2551 if (content_memory
[i
] != NOT_KNOWN
)
2553 fprintf (file
, " %s contains a copy of ", get_content_name (i
, QImode
));
2554 fprintf (file
, "%s\n", get_content_name (content_memory
[i
], QImode
));
2560 update_content (unsigned char index
, unsigned char val
, machine_mode mode
)
2564 gcc_assert (index
< sizeof content_memory
);
2566 content_memory
[index
] = val
;
2567 if (val
!= NOT_KNOWN
)
2568 content_memory
[val
] = index
;
2570 /* Make the entry in dump_file *before* VAL is increased below. */
2573 fprintf (dump_file
, " %s now contains ", get_content_name (index
, mode
));
2574 if (val
== NOT_KNOWN
)
2575 fprintf (dump_file
, "Unknown\n");
2577 fprintf (dump_file
, "%s and vice versa\n", get_content_name (val
, mode
));
2582 val
= val
== NOT_KNOWN
? val
: val
+ 1;
2584 content_memory
[index
+ 1] = val
;
2585 if (val
!= NOT_KNOWN
)
2587 content_memory
[val
] = index
+ 1;
2592 /* Any other places that had INDEX recorded as their contents are now invalid. */
2593 for (i
= 0; i
< sizeof content_memory
; i
++)
2596 || (val
!= NOT_KNOWN
&& i
== val
))
2603 if (content_memory
[i
] == index
2604 || (val
!= NOT_KNOWN
&& content_memory
[i
] == val
))
2606 content_memory
[i
] = NOT_KNOWN
;
2609 fprintf (dump_file
, " %s cleared\n", get_content_name (i
, mode
));
2612 content_memory
[++ i
] = NOT_KNOWN
;
2617 /* Record that LOC contains VALUE.
2618 For HImode locations record that LOC+1 contains VALUE+1.
2619 If LOC is not a register or stack slot, do nothing.
2620 If VALUE is not a register or stack slot, clear the recorded content. */
2623 record_content (rtx loc
, rtx value
)
2626 unsigned char index
;
2629 if ((index
= get_content_index (loc
)) == NOT_KNOWN
)
2632 val
= get_content_index (value
);
2634 mode
= GET_MODE (loc
);
2641 /* This should not happen when optimizing. */
2643 fprintf (stderr
, "ASSIGNMENT of location to itself detected! [%s]\n",
2644 get_content_name (val
, mode
));
2651 update_content (index
, val
, mode
);
2654 /* Returns TRUE if LOC already contains a copy of VALUE. */
2657 already_contains (rtx loc
, rtx value
)
2659 unsigned char index
;
2662 if ((index
= get_content_index (loc
)) == NOT_KNOWN
)
2665 if ((val
= get_content_index (value
)) == NOT_KNOWN
)
2668 if (content_memory
[index
] != val
)
2671 if (GET_MODE (loc
) == HImode
)
2672 return content_memory
[index
+ 1] == val
+ 1;
2678 rl78_es_addr (rtx addr
)
2680 if (GET_CODE (addr
) == MEM
)
2681 addr
= XEXP (addr
, 0);
2682 if (GET_CODE (addr
) != UNSPEC
)
2684 if (XINT (addr
, 1) != UNS_ES_ADDR
)
2690 rl78_es_base (rtx addr
)
2692 if (GET_CODE (addr
) == MEM
)
2693 addr
= XEXP (addr
, 0);
2694 addr
= XVECEXP (addr
, 0, 1);
2695 if (GET_CODE (addr
) == CONST
2696 && GET_CODE (XEXP (addr
, 0)) == ZERO_EXTRACT
)
2697 addr
= XEXP (XEXP (addr
, 0), 0);
2698 /* Mode doesn't matter here. */
2699 return gen_rtx_MEM (HImode
, addr
);
2702 /* Rescans an insn to see if it's recognized again. This is done
2703 carefully to ensure that all the constraint information is accurate
2704 for the newly matched insn. */
2706 insn_ok_now (rtx_insn
* insn
)
2708 rtx pattern
= PATTERN (insn
);
2711 INSN_CODE (insn
) = -1;
2713 if (recog (pattern
, insn
, 0) > -1)
2715 extract_insn (insn
);
2716 if (constrain_operands (1, get_preferred_alternatives (insn
)))
2719 fprintf (stderr
, "\033[32m");
2721 fprintf (stderr
, "\033[0m");
2723 if (SET_P (pattern
))
2724 record_content (SET_DEST (pattern
), SET_SRC (pattern
));
2726 /* We need to detect far addresses that haven't been
2727 converted to es/lo16 format. */
2728 for (i
=0; i
<recog_data
.n_operands
; i
++)
2729 if (GET_CODE (OP (i
)) == MEM
2730 && GET_MODE (XEXP (OP (i
), 0)) == SImode
2731 && GET_CODE (XEXP (OP (i
), 0)) != UNSPEC
)
2738 /* INSN is not OK as-is. It may not be recognized in real mode or
2739 it might not have satisfied its constraints in real mode. Either
2740 way it will require fixups.
2742 It is vital we always re-recognize at this point as some insns
2743 have fewer operands in real mode than virtual mode. If we do
2744 not re-recognize, then the recog_data will refer to real mode
2745 operands and we may read invalid data. Usually this isn't a
2746 problem, but once in a while the data we read is bogus enough
2747 to cause a segfault or other undesirable behavior. */
2750 /* We need to re-recog the insn with virtual registers to get
2752 INSN_CODE (insn
) = -1;
2753 cfun
->machine
->virt_insns_ok
= 1;
2754 if (recog (pattern
, insn
, 0) > -1)
2756 extract_insn (insn
);
2757 /* In theory this should always be true. */
2758 if (constrain_operands (0, get_preferred_alternatives (insn
)))
2760 cfun
->machine
->virt_insns_ok
= 0;
2766 fprintf (stderr
, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
2774 #define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
2775 #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
2776 #define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
2777 #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
2778 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
2780 #define FAILED gcc_unreachable ()
2781 #define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
2782 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
2785 /* Registers into which we move the contents of virtual registers. */
2786 #define X gen_rtx_REG (QImode, X_REG)
2787 #define A gen_rtx_REG (QImode, A_REG)
2788 #define C gen_rtx_REG (QImode, C_REG)
2789 #define B gen_rtx_REG (QImode, B_REG)
2790 #define E gen_rtx_REG (QImode, E_REG)
2791 #define D gen_rtx_REG (QImode, D_REG)
2792 #define L gen_rtx_REG (QImode, L_REG)
2793 #define H gen_rtx_REG (QImode, H_REG)
2795 #define AX gen_rtx_REG (HImode, AX_REG)
2796 #define BC gen_rtx_REG (HImode, BC_REG)
2797 #define DE gen_rtx_REG (HImode, DE_REG)
2798 #define HL gen_rtx_REG (HImode, HL_REG)
2800 /* Returns TRUE if R is a virtual register. */
2802 is_virtual_register (rtx r
)
2804 return (GET_CODE (r
) == REG
2809 /* In all these alloc routines, we expect the following: the insn
2810 pattern is unshared, the insn was previously recognized and failed
2811 due to predicates or constraints, and the operand data is in
2814 static int virt_insn_was_frame
;
2816 /* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2819 EM2 (int line ATTRIBUTE_UNUSED
, rtx r
)
2822 fprintf (stderr
, "\033[36m%d: ", line
);
2824 fprintf (stderr
, "\033[0m");
2826 /*SCHED_GROUP_P (r) = 1;*/
2827 if (virt_insn_was_frame
)
2828 RTX_FRAME_RELATED_P (r
) = 1;
2832 #define EM(x) EM2 (__LINE__, x)
2834 /* Return a suitable RTX for the low half of a __far address. */
2836 rl78_lo16 (rtx addr
)
2840 if (GET_CODE (addr
) == SYMBOL_REF
2841 || GET_CODE (addr
) == CONST
)
2843 r
= gen_rtx_ZERO_EXTRACT (HImode
, addr
, GEN_INT (16), GEN_INT (0));
2844 r
= gen_rtx_CONST (HImode
, r
);
2847 r
= rl78_subreg (HImode
, addr
, SImode
, 0);
2849 r
= gen_es_addr (r
);
2850 cfun
->machine
->uses_es
= true;
2855 /* Return a suitable RTX for the high half's lower byte of a __far address. */
2859 if (GET_CODE (addr
) == SYMBOL_REF
2860 || GET_CODE (addr
) == CONST
)
2862 rtx r
= gen_rtx_ZERO_EXTRACT (QImode
, addr
, GEN_INT (8), GEN_INT (16));
2863 r
= gen_rtx_CONST (QImode
, r
);
2866 return rl78_subreg (QImode
, addr
, SImode
, 2);
2870 add_postponed_content_update (rtx to
, rtx value
)
2872 unsigned char index
;
2874 if ((index
= get_content_index (to
)) == NOT_KNOWN
)
2877 gcc_assert (saved_update_index
== NOT_KNOWN
);
2878 saved_update_index
= index
;
2879 saved_update_value
= get_content_index (value
);
2880 saved_update_mode
= GET_MODE (to
);
2884 process_postponed_content_update (void)
2886 if (saved_update_index
!= NOT_KNOWN
)
2888 update_content (saved_update_index
, saved_update_value
, saved_update_mode
);
2889 saved_update_index
= NOT_KNOWN
;
2893 /* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2894 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2895 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2896 BEFORE is true, FROM otherwise. */
2898 gen_and_emit_move (rtx to
, rtx from
, rtx_insn
*where
, bool before
)
2900 machine_mode mode
= GET_MODE (to
);
2902 if (optimize
&& before
&& already_contains (to
, from
))
2905 display_content_memory (stderr
);
2909 fprintf (dump_file
, " Omit move of %s into ",
2910 get_content_name (get_content_index (from
), mode
));
2911 fprintf (dump_file
, "%s as it already contains this value\n",
2912 get_content_name (get_content_index (to
), mode
));
2917 rtx move
= mode
== QImode
? gen_movqi (to
, from
) : gen_movhi (to
, from
);
2921 if (where
== NULL_RTX
)
2924 emit_insn_before (move
, where
);
2927 rtx note
= find_reg_note (where
, REG_EH_REGION
, NULL_RTX
);
2929 /* If necessary move REG_EH_REGION notes forward.
2930 cf. compiling gcc.dg/pr44545.c. */
2931 if (note
!= NULL_RTX
)
2933 add_reg_note (move
, REG_EH_REGION
, XEXP (note
, 0));
2934 remove_note (where
, note
);
2937 emit_insn_after (move
, where
);
2941 record_content (to
, from
);
2943 add_postponed_content_update (to
, from
);
2946 return before
? to
: from
;
2949 /* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2950 copy it into NEWBASE and return the updated MEM. Otherwise just
2951 return M. Any needed insns are emitted before BEFORE. */
2953 transcode_memory_rtx (rtx m
, rtx newbase
, rtx_insn
*before
)
2955 rtx base
, index
, addendr
;
2962 if (GET_MODE (XEXP (m
, 0)) == SImode
)
2965 rtx seg
= rl78_hi8 (XEXP (m
, 0));
2969 emit_insn_before (EM (gen_movqi (A
, seg
)), before
);
2970 emit_insn_before (EM (gen_movqi_to_es (A
)), before
);
2973 record_content (A
, NULL_RTX
);
2975 new_m
= gen_rtx_MEM (GET_MODE (m
), rl78_lo16 (XEXP (m
, 0)));
2976 MEM_COPY_ATTRIBUTES (new_m
, m
);
2981 characterize_address (XEXP (m
, 0), & base
, & index
, & addendr
);
2982 gcc_assert (index
== NULL_RTX
);
2984 if (base
== NULL_RTX
)
2987 if (addendr
&& GET_CODE (addendr
) == CONST_INT
)
2988 addend
= INTVAL (addendr
);
2990 gcc_assert (REG_P (base
));
2991 gcc_assert (REG_P (newbase
));
2993 int limit
= 256 - GET_MODE_SIZE (GET_MODE (m
));
2995 if (REGNO (base
) == SP_REG
)
2997 if (addend
>= 0 && addend
<= limit
)
3001 /* BASE should be a virtual register. We copy it to NEWBASE. If
3002 the addend is out of range for DE/HL, we use AX to compute the full
3006 || (addend
> limit
&& REGNO (newbase
) != BC_REG
)
3008 && (GET_CODE (addendr
) != CONST_INT
)
3009 && ((REGNO (newbase
) != BC_REG
))
3015 EM (emit_insn_before (gen_movhi (AX
, base
), before
));
3016 EM (emit_insn_before (gen_addhi3 (AX
, AX
, addendr
), before
));
3017 EM (emit_insn_before (gen_movhi (newbase
, AX
), before
));
3018 record_content (AX
, NULL_RTX
);
3019 record_content (newbase
, NULL_RTX
);
3027 base
= gen_and_emit_move (newbase
, base
, before
, true);
3032 record_content (base
, NULL_RTX
);
3033 base
= gen_rtx_PLUS (HImode
, base
, GEN_INT (addend
));
3037 record_content (base
, NULL_RTX
);
3038 base
= gen_rtx_PLUS (HImode
, base
, addendr
);
3043 m
= change_address (m
, GET_MODE (m
), gen_es_addr (base
));
3044 cfun
->machine
->uses_es
= true;
3047 m
= change_address (m
, GET_MODE (m
), base
);
3051 /* Copy SRC to accumulator (A or AX), placing any generated insns
3052 before BEFORE. Returns accumulator RTX. */
3054 move_to_acc (int opno
, rtx_insn
*before
)
3056 rtx src
= OP (opno
);
3057 machine_mode mode
= GET_MODE (src
);
3059 if (REG_P (src
) && REGNO (src
) < 2)
3062 if (mode
== VOIDmode
)
3063 mode
= recog_data
.operand_mode
[opno
];
3065 return gen_and_emit_move (mode
== QImode
? A
: AX
, src
, before
, true);
3069 force_into_acc (rtx src
, rtx_insn
*before
)
3071 machine_mode mode
= GET_MODE (src
);
3074 if (REG_P (src
) && REGNO (src
) < 2)
3077 move
= mode
== QImode
? gen_movqi (A
, src
) : gen_movhi (AX
, src
);
3081 emit_insn_before (move
, before
);
3082 record_content (AX
, NULL_RTX
);
3085 /* Copy accumulator (A or AX) to DEST, placing any generated insns
3086 after AFTER. Returns accumulator RTX. */
3088 move_from_acc (unsigned int opno
, rtx_insn
*after
)
3090 rtx dest
= OP (opno
);
3091 machine_mode mode
= GET_MODE (dest
);
3093 if (REG_P (dest
) && REGNO (dest
) < 2)
3096 return gen_and_emit_move (dest
, mode
== QImode
? A
: AX
, after
, false);
3099 /* Copy accumulator (A or AX) to REGNO, placing any generated insns
3100 before BEFORE. Returns reg RTX. */
3102 move_acc_to_reg (rtx acc
, int regno
, rtx_insn
*before
)
3104 machine_mode mode
= GET_MODE (acc
);
3107 reg
= gen_rtx_REG (mode
, regno
);
3109 return gen_and_emit_move (reg
, acc
, before
, true);
3112 /* Copy SRC to X, placing any generated insns before BEFORE.
3115 move_to_x (int opno
, rtx_insn
*before
)
3117 rtx src
= OP (opno
);
3118 machine_mode mode
= GET_MODE (src
);
3121 if (mode
== VOIDmode
)
3122 mode
= recog_data
.operand_mode
[opno
];
3123 reg
= (mode
== QImode
) ? X
: AX
;
3125 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
3127 OP (opno
) = move_to_acc (opno
, before
);
3128 OP (opno
) = move_acc_to_reg (OP (opno
), X_REG
, before
);
3132 return gen_and_emit_move (reg
, src
, before
, true);
3135 /* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
3136 Returns H/HL RTX. */
3138 move_to_hl (int opno
, rtx_insn
*before
)
3140 rtx src
= OP (opno
);
3141 machine_mode mode
= GET_MODE (src
);
3144 if (mode
== VOIDmode
)
3145 mode
= recog_data
.operand_mode
[opno
];
3146 reg
= (mode
== QImode
) ? L
: HL
;
3148 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
3150 OP (opno
) = move_to_acc (opno
, before
);
3151 OP (opno
) = move_acc_to_reg (OP (opno
), L_REG
, before
);
3155 return gen_and_emit_move (reg
, src
, before
, true);
3158 /* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
3159 Returns E/DE RTX. */
3161 move_to_de (int opno
, rtx_insn
*before
)
3163 rtx src
= OP (opno
);
3164 machine_mode mode
= GET_MODE (src
);
3167 if (mode
== VOIDmode
)
3168 mode
= recog_data
.operand_mode
[opno
];
3170 reg
= (mode
== QImode
) ? E
: DE
;
3172 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
3174 OP (opno
) = move_to_acc (opno
, before
);
3175 OP (opno
) = move_acc_to_reg (OP (opno
), E_REG
, before
);
3179 gen_and_emit_move (reg
, src
, before
, true);
3185 /* Devirtualize an insn of the form (SET (op) (unop (op))). */
3187 rl78_alloc_physical_registers_op1 (rtx_insn
* insn
)
3189 /* op[0] = func op[1] */
3191 /* We first try using A as the destination, then copying it
3193 if (rtx_equal_p (OP (0), OP (1)))
3196 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3200 /* If necessary, load the operands into BC and HL.
3201 Check to see if we already have OP (0) in HL
3202 and if so, swap the order.
3204 It is tempting to perform this optimization when OP(0) does
3205 not hold a MEM, but this leads to bigger code in general.
3206 The problem is that if OP(1) holds a MEM then swapping it
3207 into BC means a BC-relative load is used and these are 3
3208 bytes long vs 1 byte for an HL load. */
3210 && already_contains (HL
, XEXP (OP (0), 0)))
3212 OP (0) = transcode_memory_rtx (OP (0), HL
, insn
);
3213 OP (1) = transcode_memory_rtx (OP (1), BC
, insn
);
3217 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3218 OP (1) = transcode_memory_rtx (OP (1), HL
, insn
);
3224 OP (0) = move_from_acc (0, insn
);
3228 /* Try copying the src to acc first, then. This is for, for
3229 example, ZERO_EXTEND or NOT. */
3230 OP (1) = move_to_acc (1, insn
);
3235 /* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
3236 Assumes that the current insn has already been recognised and hence the
3237 constraint data has been filled in. */
3239 has_constraint (unsigned int opnum
, enum constraint_num constraint
)
3241 const char * p
= recog_data
.constraints
[opnum
];
3243 /* No constraints means anything is accepted. */
3244 if (p
== NULL
|| *p
== 0 || *p
== ',')
3253 len
= CONSTRAINT_LEN (c
, p
);
3254 gcc_assert (len
> 0);
3262 if (lookup_constraint (p
) == constraint
)
3270 /* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
3272 rl78_alloc_physical_registers_op2 (rtx_insn
* insn
)
3280 if (rtx_equal_p (OP (0), OP (1)))
3285 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3286 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3291 OP (1) = transcode_memory_rtx (OP (1), HL
, insn
);
3292 OP (2) = transcode_memory_rtx (OP (2), DE
, insn
);
3295 else if (rtx_equal_p (OP (0), OP (2)))
3297 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3299 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3303 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3304 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3305 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3310 prev
= prev_nonnote_nondebug_insn (insn
);
3311 if (recog_data
.constraints
[1][0] == '%'
3312 && is_virtual_register (OP (1))
3313 && ! is_virtual_register (OP (2))
3314 && ! CONSTANT_P (OP (2)))
3321 /* Make a note of whether (H)L is being used. It matters
3322 because if OP (2) also needs reloading, then we must take
3323 care not to corrupt HL. */
3324 hl_used
= reg_mentioned_p (L
, OP (0)) || reg_mentioned_p (L
, OP (1));
3326 /* If HL is not currently being used and dest == op1 then there are
3327 some possible optimizations available by reloading one of the
3328 operands into HL, before trying to use the accumulator. */
3331 && rtx_equal_p (OP (0), OP (1)))
3333 /* If op0 is a Ws1 type memory address then switching the base
3334 address register to HL might allow us to perform an in-memory
3335 operation. (eg for the INCW instruction).
3337 FIXME: Adding the move into HL is costly if this optimization is not
3338 going to work, so for now, make sure that we know that the new insn will
3339 match the requirements of the addhi3_real pattern. Really we ought to
3340 generate a candidate sequence, test that, and then install it if the
3341 results are good. */
3342 if (satisfies_constraint_Ws1 (OP (0))
3343 && has_constraint (0, CONSTRAINT_Wh1
)
3344 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
3346 rtx base
, index
, addend
, newbase
;
3348 characterize_address (XEXP (OP (0), 0), & base
, & index
, & addend
);
3349 gcc_assert (index
== NULL_RTX
);
3350 gcc_assert (REG_P (base
) && REGNO (base
) == SP_REG
);
3352 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3353 if (addend
!= NULL_RTX
)
3355 newbase
= gen_and_emit_move (HL
, base
, insn
, true);
3356 record_content (newbase
, NULL_RTX
);
3357 newbase
= gen_rtx_PLUS (HImode
, newbase
, addend
);
3359 OP (0) = OP (1) = change_address (OP (0), VOIDmode
, newbase
);
3361 /* We do not want to fail here as this means that
3362 we have inserted useless insns into the stream. */
3366 else if (REG_P (OP (0))
3367 && satisfies_constraint_Ws1 (OP (2))
3368 && has_constraint (2, CONSTRAINT_Wh1
))
3370 rtx base
, index
, addend
, newbase
;
3372 characterize_address (XEXP (OP (2), 0), & base
, & index
, & addend
);
3373 gcc_assert (index
== NULL_RTX
);
3374 gcc_assert (REG_P (base
) && REGNO (base
) == SP_REG
);
3376 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3377 if (addend
!= NULL_RTX
)
3379 gen_and_emit_move (HL
, base
, insn
, true);
3381 if (REGNO (OP (0)) != X_REG
)
3383 OP (1) = move_to_acc (1, insn
);
3384 OP (0) = move_from_acc (0, insn
);
3387 record_content (HL
, NULL_RTX
);
3388 newbase
= gen_rtx_PLUS (HImode
, HL
, addend
);
3390 OP (2) = change_address (OP (2), VOIDmode
, newbase
);
3392 /* We do not want to fail here as this means that
3393 we have inserted useless insns into the stream. */
3399 OP (0) = move_from_acc (0, insn
);
3401 tmp_id
= get_max_insn_count ();
3404 if (rtx_equal_p (OP (1), OP (2)))
3405 OP (2) = OP (1) = move_to_acc (1, insn
);
3407 OP (1) = move_to_acc (1, insn
);
3411 /* If we omitted the move of OP1 into the accumulator (because
3412 it was already there from a previous insn), then force the
3413 generation of the move instruction now. We know that we
3414 are about to emit a move into HL (or DE) via AX, and hence
3415 our optimization to remove the load of OP1 is no longer valid. */
3416 if (tmp_id
== get_max_insn_count ())
3417 force_into_acc (saved_op1
, insn
);
3419 /* We have to copy op2 to HL (or DE), but that involves AX, which
3420 already has a live value. Emit it before those insns. */
3423 first
= next_nonnote_nondebug_insn (prev
);
3425 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3428 OP (2) = hl_used
? move_to_de (2, first
) : move_to_hl (2, first
);
3433 /* Devirtualize an insn of the form SET (PC) (MEM/REG). */
3435 rl78_alloc_physical_registers_ro1 (rtx_insn
* insn
)
3437 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3441 OP (0) = move_to_acc (0, insn
);
3446 /* Devirtualize a compare insn. */
3448 rl78_alloc_physical_registers_cmp (rtx_insn
* insn
)
3452 rtx_insn
*prev
= prev_nonnote_nondebug_insn (insn
);
3455 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3456 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3458 /* HI compares have to have OP (1) in AX, but QI
3459 compares do not, so it is worth checking here. */
3462 /* For an HImode compare, OP (1) must always be in AX.
3463 But if OP (1) is a REG (and not AX), then we can avoid
3464 a reload of OP (1) if we reload OP (2) into AX and invert
3467 && REGNO (OP (1)) != AX_REG
3468 && GET_MODE (OP (1)) == HImode
3471 rtx cmp
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3473 OP (2) = move_to_acc (2, insn
);
3475 switch (GET_CODE (cmp
))
3480 case LTU
: cmp
= gen_rtx_GTU (HImode
, OP (2), OP (1)); break;
3481 case GTU
: cmp
= gen_rtx_LTU (HImode
, OP (2), OP (1)); break;
3482 case LEU
: cmp
= gen_rtx_GEU (HImode
, OP (2), OP (1)); break;
3483 case GEU
: cmp
= gen_rtx_LEU (HImode
, OP (2), OP (1)); break;
3496 if (GET_CODE (cmp
) == EQ
|| GET_CODE (cmp
) == NE
)
3497 PATTERN (insn
) = gen_cbranchhi4_real (cmp
, OP (2), OP (1), OP (3));
3499 PATTERN (insn
) = gen_cbranchhi4_real_inverted (cmp
, OP (2), OP (1), OP (3));
3504 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
3505 should be handled by the second alternative of the cbranchhi_real pattern. */
3506 if (rtx_equal_p (OP (1), OP (2)))
3508 OP (1) = OP (2) = BC
;
3512 tmp_id
= get_max_insn_count ();
3515 OP (1) = move_to_acc (1, insn
);
3519 /* If we omitted the move of OP1 into the accumulator (because
3520 it was already there from a previous insn), then force the
3521 generation of the move instruction now. We know that we
3522 are about to emit a move into HL via AX, and hence our
3523 optimization to remove the load of OP1 is no longer valid. */
3524 if (tmp_id
== get_max_insn_count ())
3525 force_into_acc (saved_op1
, insn
);
3527 /* We have to copy op2 to HL, but that involves the acc, which
3528 already has a live value. Emit it before those insns. */
3530 first
= next_nonnote_nondebug_insn (prev
);
3532 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3534 OP (2) = move_to_hl (2, first
);
3539 /* Like op2, but AX = A * X. */
3541 rl78_alloc_physical_registers_umul (rtx_insn
* insn
)
3543 rtx_insn
*prev
= prev_nonnote_nondebug_insn (insn
);
3548 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3549 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3550 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3554 if (recog_data
.constraints
[1][0] == '%'
3555 && is_virtual_register (OP (1))
3556 && !is_virtual_register (OP (2))
3557 && !CONSTANT_P (OP (2)))
3564 OP (0) = move_from_acc (0, insn
);
3566 tmp_id
= get_max_insn_count ();
3569 if (rtx_equal_p (OP (1), OP (2)))
3571 gcc_assert (GET_MODE (OP (2)) == QImode
);
3572 /* The MULU instruction does not support duplicate arguments
3573 but we know that if we copy OP (2) to X it will do so via
3574 A and thus OP (1) will already be loaded into A. */
3575 OP (2) = move_to_x (2, insn
);
3579 OP (1) = move_to_acc (1, insn
);
3583 /* If we omitted the move of OP1 into the accumulator (because
3584 it was already there from a previous insn), then force the
3585 generation of the move instruction now. We know that we
3586 are about to emit a move into HL (or DE) via AX, and hence
3587 our optimization to remove the load of OP1 is no longer valid. */
3588 if (tmp_id
== get_max_insn_count ())
3589 force_into_acc (saved_op1
, insn
);
3591 /* We have to copy op2 to X, but that involves the acc, which
3592 already has a live value. Emit it before those insns. */
3595 first
= next_nonnote_nondebug_insn (prev
);
3597 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3599 OP (2) = move_to_x (2, first
);
3605 rl78_alloc_address_registers_macax (rtx_insn
* insn
)
3608 bool replace_in_op0
= false;
3609 bool replace_in_op1
= false;
3613 /* Two different MEMs are not allowed. */
3615 for (op
= 2; op
>= 0; op
--)
3617 if (MEM_P (OP (op
)))
3619 if (op
== 0 && replace_in_op0
)
3621 if (op
== 1 && replace_in_op1
)
3627 /* If we replace a MEM, make sure that we replace it for all
3628 occurrences of the same MEM in the insn. */
3629 replace_in_op0
= (op
> 0 && rtx_equal_p (OP (op
), OP (0)));
3630 replace_in_op1
= (op
> 1 && rtx_equal_p (OP (op
), OP (1)));
3632 OP (op
) = transcode_memory_rtx (OP (op
), HL
, insn
);
3635 && ((GET_CODE (XEXP (OP (op
), 0)) == REG
3636 && REGNO (XEXP (OP (op
), 0)) == SP_REG
)
3637 || (GET_CODE (XEXP (OP (op
), 0)) == PLUS
3638 && REGNO (XEXP (XEXP (OP (op
), 0), 0)) == SP_REG
)))
3640 emit_insn_before (gen_movhi (HL
, gen_rtx_REG (HImode
, SP_REG
)), insn
);
3641 OP (op
) = replace_rtx (OP (op
), gen_rtx_REG (HImode
, SP_REG
), HL
);
3649 OP (op
) = transcode_memory_rtx (OP (op
), DE
, insn
);
3652 OP (op
) = transcode_memory_rtx (OP (op
), BC
, insn
);
3663 rl78_alloc_address_registers_div (rtx_insn
* insn
)
3668 /* Scan all insns and devirtualize them. */
3670 rl78_alloc_physical_registers (void)
3672 /* During most of the compile, gcc is dealing with virtual
3673 registers. At this point, we need to assign physical registers
3674 to the vitual ones, and copy in/out as needed. */
3676 rtx_insn
*insn
, *curr
;
3677 enum attr_valloc valloc_method
;
3679 for (insn
= get_insns (); insn
; insn
= curr
)
3683 curr
= next_nonnote_nondebug_insn (insn
);
3686 && (GET_CODE (PATTERN (insn
)) == SET
3687 || GET_CODE (PATTERN (insn
)) == CALL
)
3688 && INSN_CODE (insn
) == -1)
3690 if (GET_CODE (SET_SRC (PATTERN (insn
))) == ASM_OPERANDS
)
3692 i
= recog (PATTERN (insn
), insn
, 0);
3698 INSN_CODE (insn
) = i
;
3702 cfun
->machine
->virt_insns_ok
= 0;
3703 cfun
->machine
->real_insns_ok
= 1;
3705 clear_content_memory ();
3707 for (insn
= get_insns (); insn
; insn
= curr
)
3711 curr
= insn
? next_nonnote_nondebug_insn (insn
) : NULL
;
3716 clear_content_memory ();
3722 fprintf (dump_file
, "Converting insn %d\n", INSN_UID (insn
));
3724 pattern
= PATTERN (insn
);
3725 if (GET_CODE (pattern
) == PARALLEL
)
3726 pattern
= XVECEXP (pattern
, 0, 0);
3727 if (JUMP_P (insn
) || CALL_P (insn
) || GET_CODE (pattern
) == CALL
)
3728 clear_content_memory ();
3729 if (GET_CODE (pattern
) != SET
3730 && GET_CODE (pattern
) != CALL
)
3732 if (GET_CODE (pattern
) == SET
3733 && GET_CODE (SET_SRC (pattern
)) == ASM_OPERANDS
)
3736 valloc_method
= get_attr_valloc (insn
);
3738 PATTERN (insn
) = copy_rtx_if_shared (PATTERN (insn
));
3740 if (valloc_method
== VALLOC_MACAX
)
3742 record_content (AX
, NULL_RTX
);
3743 record_content (BC
, NULL_RTX
);
3744 record_content (DE
, NULL_RTX
);
3746 else if (valloc_method
== VALLOC_DIVHI
)
3748 record_content (AX
, NULL_RTX
);
3749 record_content (BC
, NULL_RTX
);
3751 else if (valloc_method
== VALLOC_DIVSI
)
3753 record_content (AX
, NULL_RTX
);
3754 record_content (BC
, NULL_RTX
);
3755 record_content (DE
, NULL_RTX
);
3756 record_content (HL
, NULL_RTX
);
3759 if (insn_ok_now (insn
))
3762 INSN_CODE (insn
) = -1;
3764 if (RTX_FRAME_RELATED_P (insn
))
3765 virt_insn_was_frame
= 1;
3767 virt_insn_was_frame
= 0;
3769 switch (valloc_method
)
3772 rl78_alloc_physical_registers_op1 (insn
);
3775 rl78_alloc_physical_registers_op2 (insn
);
3778 rl78_alloc_physical_registers_ro1 (insn
);
3781 rl78_alloc_physical_registers_cmp (insn
);
3784 rl78_alloc_physical_registers_umul (insn
);
3785 record_content (AX
, NULL_RTX
);
3788 /* Macro that clobbers AX. */
3789 rl78_alloc_address_registers_macax (insn
);
3790 record_content (AX
, NULL_RTX
);
3791 record_content (BC
, NULL_RTX
);
3792 record_content (DE
, NULL_RTX
);
3795 rl78_alloc_address_registers_div (insn
);
3796 record_content (AX
, NULL_RTX
);
3797 record_content (BC
, NULL_RTX
);
3798 record_content (DE
, NULL_RTX
);
3799 record_content (HL
, NULL_RTX
);
3802 rl78_alloc_address_registers_div (insn
);
3803 record_content (AX
, NULL_RTX
);
3804 record_content (BC
, NULL_RTX
);
3810 if (JUMP_P (insn
) || CALL_P (insn
) || GET_CODE (pattern
) == CALL
)
3811 clear_content_memory ();
3813 process_postponed_content_update ();
3817 fprintf (stderr
, "\033[0m");
3821 /* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3822 This function scans for uses of registers; the last use (i.e. first
3823 encounter when scanning backwards) triggers a REG_DEAD note if the
3824 reg was previously in DEAD[]. */
3826 rl78_note_reg_uses (char *dead
, rtx s
, rtx insn
)
3835 code
= GET_CODE (s
);
3839 /* Compare registers by number. */
3844 fprintf (dump_file
, "note use reg %d size %d on insn %d\n",
3845 r
, GET_MODE_SIZE (GET_MODE (s
)), INSN_UID (insn
));
3846 print_rtl_single (dump_file
, s
);
3849 add_reg_note (insn
, REG_DEAD
, gen_rtx_REG (GET_MODE (s
), r
));
3850 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (s
)); i
++)
3854 /* These codes have no constituent expressions
3864 /* These are kept unique for a given value. */
3871 fmt
= GET_RTX_FORMAT (code
);
3873 for (i
= GET_RTX_LENGTH (code
) - 1; i
>= 0; i
--)
3878 for (j
= XVECLEN (s
, i
) - 1; j
>= 0; j
--)
3879 rl78_note_reg_uses (dead
, XVECEXP (s
, i
, j
), insn
);
3881 else if (fmt
[i
] == 'e')
3882 rl78_note_reg_uses (dead
, XEXP (s
, i
), insn
);
3886 /* Like the previous function, but scan for SETs instead. */
3888 rl78_note_reg_set (char *dead
, rtx d
, rtx insn
)
3892 if (GET_CODE (d
) == MEM
)
3893 rl78_note_reg_uses (dead
, XEXP (d
, 0), insn
);
3895 if (GET_CODE (d
) != REG
)
3898 /* Do not mark the reg unused unless all QImode parts of it are dead. */
3901 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (d
)); i
++)
3905 add_reg_note (insn
, REG_UNUSED
, gen_rtx_REG (GET_MODE (d
), r
));
3907 fprintf (dump_file
, "note set reg %d size %d\n", r
, GET_MODE_SIZE (GET_MODE (d
)));
3908 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (d
)); i
++)
3912 /* This is a rather crude register death pass. Death status is reset
3913 at every jump or call insn. */
3915 rl78_calculate_death_notes (void)
3917 char dead
[FIRST_PSEUDO_REGISTER
];
3922 memset (dead
, 0, sizeof (dead
));
3924 for (insn
= get_last_insn ();
3926 insn
= prev_nonnote_nondebug_insn (insn
))
3930 fprintf (dump_file
, "\n--------------------------------------------------");
3931 fprintf (dump_file
, "\nDead:");
3932 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3934 fprintf (dump_file
, " %s", reg_names
[i
]);
3935 fprintf (dump_file
, "\n");
3936 print_rtl_single (dump_file
, insn
);
3939 switch (GET_CODE (insn
))
3943 if (GET_CODE (p
) == PARALLEL
)
3945 rtx q
= XVECEXP (p
, 0 ,1);
3947 /* This happens with the DIV patterns. */
3948 if (GET_CODE (q
) == SET
)
3952 rl78_note_reg_set (dead
, d
, insn
);
3953 rl78_note_reg_uses (dead
, s
, insn
);
3956 p
= XVECEXP (p
, 0, 0);
3959 switch (GET_CODE (p
))
3964 rl78_note_reg_set (dead
, d
, insn
);
3965 rl78_note_reg_uses (dead
, s
, insn
);
3969 rl78_note_reg_uses (dead
, p
, insn
);
3978 if (INSN_CODE (insn
) == CODE_FOR_rl78_return
)
3980 memset (dead
, 1, sizeof (dead
));
3981 /* We expect a USE just prior to this, which will mark
3982 the actual return registers. The USE will have a
3983 death note, but we aren't going to be modifying it
3989 memset (dead
, 0, sizeof (dead
));
3996 print_rtl_single (dump_file
, insn
);
4000 /* Helper function to reset the origins in RP and the age in AGE for
4003 reset_origins (int *rp
, int *age
)
4006 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4014 set_origin (rtx pat
, rtx_insn
* insn
, int * origins
, int * age
)
4016 rtx src
= SET_SRC (pat
);
4017 rtx dest
= SET_DEST (pat
);
4018 int mb
= GET_MODE_SIZE (GET_MODE (dest
));
4021 if (GET_CODE (dest
) == REG
)
4023 int dr
= REGNO (dest
);
4025 if (GET_CODE (src
) == REG
)
4027 int sr
= REGNO (src
);
4029 int best_age
, best_reg
;
4031 /* See if the copy is not needed. */
4032 for (i
= 0; i
< mb
; i
++)
4033 if (origins
[dr
+ i
] != origins
[sr
+ i
])
4039 fprintf (dump_file
, "deleting because dest already has correct value\n");
4044 if (dr
< 8 || sr
>= 8)
4051 /* See if the copy can be made from another
4052 bank 0 register instead, instead of the
4053 virtual src register. */
4054 for (ar
= 0; ar
< 8; ar
+= mb
)
4058 for (i
= 0; i
< mb
; i
++)
4059 if (origins
[ar
+ i
] != origins
[sr
+ i
])
4062 /* The chip has some reg-reg move limitations. */
4063 if (mb
== 1 && dr
> 3)
4068 if (best_age
== -1 || best_age
> age
[sr
+ i
])
4070 best_age
= age
[sr
+ i
];
4078 /* FIXME: copy debug info too. */
4079 SET_SRC (pat
) = gen_rtx_REG (GET_MODE (src
), best_reg
);
4084 for (i
= 0; i
< mb
; i
++)
4086 origins
[dr
+ i
] = origins
[sr
+ i
];
4087 age
[dr
+ i
] = age
[sr
+ i
] + 1;
4092 /* The destination is computed, its origin is itself. */
4094 fprintf (dump_file
, "resetting origin of r%d for %d byte%s\n",
4095 dr
, mb
, mb
== 1 ? "" : "s");
4097 for (i
= 0; i
< mb
; i
++)
4099 origins
[dr
+ i
] = dr
+ i
;
4104 /* Any registers marked with that reg as an origin are reset. */
4105 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4106 if (origins
[i
] >= dr
&& origins
[i
] < dr
+ mb
)
4113 /* Special case - our MUL patterns uses AX and sometimes BC. */
4114 if (get_attr_valloc (insn
) == VALLOC_MACAX
)
4117 fprintf (dump_file
, "Resetting origin of AX/BC for MUL pattern.\n");
4119 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4120 if (i
<= 3 || origins
[i
] <= 3)
4126 else if (get_attr_valloc (insn
) == VALLOC_DIVHI
)
4129 fprintf (dump_file
, "Resetting origin of AX/DE for DIVHI pattern.\n");
4131 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4136 || origins
[i
] == A_REG
4137 || origins
[i
] == X_REG
4138 || origins
[i
] == D_REG
4139 || origins
[i
] == E_REG
)
4145 else if (get_attr_valloc (insn
) == VALLOC_DIVSI
)
4148 fprintf (dump_file
, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n");
4150 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4151 if (i
<= 7 || origins
[i
] <= 7)
4158 if (GET_CODE (src
) == ASHIFT
4159 || GET_CODE (src
) == ASHIFTRT
4160 || GET_CODE (src
) == LSHIFTRT
)
4162 rtx count
= XEXP (src
, 1);
4164 if (GET_CODE (count
) == REG
)
4166 /* Special case - our pattern clobbers the count register. */
4167 int r
= REGNO (count
);
4170 fprintf (dump_file
, "Resetting origin of r%d for shift.\n", r
);
4172 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4173 if (i
== r
|| origins
[i
] == r
)
4182 /* The idea behind this optimization is to look for cases where we
4183 move data from A to B to C, and instead move from A to B, and A to
4184 C. If B is a virtual register or memory, this is a big win on its
4185 own. If B turns out to be unneeded after this, it's a bigger win.
4186 For each register, we try to determine where it's value originally
4187 came from, if it's propogated purely through moves (and not
4188 computes). The ORIGINS[] array has the regno for the "origin" of
4189 the value in the [regno] it's indexed by. */
4191 rl78_propogate_register_origins (void)
4193 int origins
[FIRST_PSEUDO_REGISTER
];
4194 int age
[FIRST_PSEUDO_REGISTER
];
4196 rtx_insn
*insn
, *ninsn
= NULL
;
4199 reset_origins (origins
, age
);
4201 for (insn
= get_insns (); insn
; insn
= ninsn
)
4203 ninsn
= next_nonnote_nondebug_insn (insn
);
4207 fprintf (dump_file
, "\n");
4208 fprintf (dump_file
, "Origins:");
4209 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4210 if (origins
[i
] != i
)
4211 fprintf (dump_file
, " r%d=r%d", i
, origins
[i
]);
4212 fprintf (dump_file
, "\n");
4213 print_rtl_single (dump_file
, insn
);
4216 switch (GET_CODE (insn
))
4222 reset_origins (origins
, age
);
4229 pat
= PATTERN (insn
);
4231 if (GET_CODE (pat
) == PARALLEL
)
4233 rtx clobber
= XVECEXP (pat
, 0, 1);
4234 pat
= XVECEXP (pat
, 0, 0);
4235 if (GET_CODE (clobber
) == CLOBBER
4236 && GET_CODE (XEXP (clobber
, 0)) == REG
)
4238 int cr
= REGNO (XEXP (clobber
, 0));
4239 int mb
= GET_MODE_SIZE (GET_MODE (XEXP (clobber
, 0)));
4241 fprintf (dump_file
, "reset origins of %d regs at %d\n", mb
, cr
);
4242 for (i
= 0; i
< mb
; i
++)
4244 origins
[cr
+ i
] = cr
+ i
;
4248 /* This happens with the DIV patterns. */
4249 else if (GET_CODE (clobber
) == SET
)
4251 set_origin (clobber
, insn
, origins
, age
);
4257 if (GET_CODE (pat
) == SET
)
4259 set_origin (pat
, insn
, origins
, age
);
4261 else if (GET_CODE (pat
) == CLOBBER
4262 && GET_CODE (XEXP (pat
, 0)) == REG
)
4264 if (REG_P (XEXP (pat
, 0)))
4266 unsigned int reg
= REGNO (XEXP (pat
, 0));
4276 /* Remove any SETs where the destination is unneeded. */
4278 rl78_remove_unused_sets (void)
4280 rtx_insn
*insn
, *ninsn
= NULL
;
4283 for (insn
= get_insns (); insn
; insn
= ninsn
)
4285 ninsn
= next_nonnote_nondebug_insn (insn
);
4287 rtx set
= single_set (insn
);
4291 dest
= SET_DEST (set
);
4293 if (GET_CODE (dest
) != REG
|| REGNO (dest
) > 23)
4296 if (find_regno_note (insn
, REG_UNUSED
, REGNO (dest
)))
4299 fprintf (dump_file
, "deleting because the set register is never used.\n");
4305 /* This is the top of the devritualization pass. */
4309 /* split2 only happens when optimizing, but we need all movSIs to be
4314 rl78_alloc_physical_registers ();
4318 fprintf (dump_file
, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
4319 print_rtl_with_bb (dump_file
, get_insns (), TDF_NONE
);
4322 rl78_propogate_register_origins ();
4323 rl78_calculate_death_notes ();
4327 fprintf (dump_file
, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
4328 print_rtl_with_bb (dump_file
, get_insns (), TDF_NONE
);
4329 fprintf (dump_file
, "\n======================================================================\n");
4332 rl78_remove_unused_sets ();
4334 /* The code after devirtualizing has changed so much that at this point
4335 we might as well just rescan everything. Note that
4336 df_rescan_all_insns is not going to help here because it does not
4337 touch the artificial uses and defs. */
4338 df_finish_pass (true);
4340 df_live_add_problem ();
4341 df_scan_alloc (NULL
);
4348 #undef TARGET_RETURN_IN_MEMORY
4349 #define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
4352 rl78_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
4354 const HOST_WIDE_INT size
= int_size_in_bytes (type
);
4355 return (size
== -1 || size
> 8);
4359 #undef TARGET_RTX_COSTS
4360 #define TARGET_RTX_COSTS rl78_rtx_costs
4363 rl78_rtx_costs (rtx x
,
4365 int outer_code ATTRIBUTE_UNUSED
,
4366 int opno ATTRIBUTE_UNUSED
,
4368 bool speed ATTRIBUTE_UNUSED
)
4370 int code
= GET_CODE (x
);
4372 if (code
== IF_THEN_ELSE
)
4374 *total
= COSTS_N_INSNS (10);
4380 if (code
== MULT
&& ! speed
)
4382 * total
= COSTS_N_INSNS (8);
4394 /* If we are compiling for space then we do not want to use the
4395 inline SImode multiplication patterns or shift sequences.
4396 The cost is not set to 1 or 5 however as we have to allow for
4397 the possibility that we might be converting a leaf function
4398 into a non-leaf function. (There is no way to tell here).
4399 A value of 13 seems to be a reasonable compromise for the
4401 * total
= COSTS_N_INSNS (13);
4402 else if (RL78_MUL_G14
)
4403 *total
= COSTS_N_INSNS (14);
4404 else if (RL78_MUL_G13
)
4405 *total
= COSTS_N_INSNS (29);
4407 *total
= COSTS_N_INSNS (500);
4411 *total
= COSTS_N_INSNS (8);
4417 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
4419 switch (INTVAL (XEXP (x
, 1)))
4421 case 0: *total
= COSTS_N_INSNS (0); break;
4422 case 1: *total
= COSTS_N_INSNS (6); break;
4423 case 2: case 3: case 4: case 5: case 6: case 7:
4424 *total
= COSTS_N_INSNS (10); break;
4425 case 8: *total
= COSTS_N_INSNS (6); break;
4426 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
4427 *total
= COSTS_N_INSNS (10); break;
4428 case 16: *total
= COSTS_N_INSNS (3); break;
4429 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
4430 *total
= COSTS_N_INSNS (4); break;
4431 case 24: *total
= COSTS_N_INSNS (4); break;
4432 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
4433 *total
= COSTS_N_INSNS (5); break;
4437 *total
= COSTS_N_INSNS (10+4*16);
4448 static GTY(()) section
* saddr_section
;
4449 static GTY(()) section
* frodata_section
;
4452 rl78_saddr_p (rtx x
)
4458 if (GET_CODE (x
) == PLUS
)
4460 if (GET_CODE (x
) != SYMBOL_REF
)
4464 if (memcmp (c
, "@s.", 3) == 0)
4475 if (GET_CODE (x
) != CONST_INT
)
4478 if ((INTVAL (x
) & 0xFF00) != 0xFF00)
4484 #undef TARGET_STRIP_NAME_ENCODING
4485 #define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding
4488 rl78_strip_name_encoding (const char * sym
)
4494 else if (*sym
== '@' && sym
[2] == '.')
4501 /* Like rl78_strip_name_encoding, but does not strip leading asterisks. This
4502 is important if the stripped name is going to be passed to assemble_name()
4503 as that handles asterisk prefixed names in a special manner. */
4506 rl78_strip_nonasm_name_encoding (const char * sym
)
4510 if (*sym
== '@' && sym
[2] == '.')
4519 rl78_attrlist_to_encoding (tree list
, tree decl ATTRIBUTE_UNUSED
)
4523 if (is_attribute_p ("saddr", TREE_PURPOSE (list
)))
4525 list
= TREE_CHAIN (list
);
4531 #define RL78_ATTRIBUTES(decl) \
4532 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
4533 : DECL_ATTRIBUTES (decl) \
4534 ? (DECL_ATTRIBUTES (decl)) \
4535 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
4537 #undef TARGET_ENCODE_SECTION_INFO
4538 #define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info
4541 rl78_encode_section_info (tree decl
, rtx rtl
, int first
)
4544 const char * oldname
;
4549 tree rl78_attributes
;
4554 rtlname
= XEXP (rtl
, 0);
4556 if (GET_CODE (rtlname
) == SYMBOL_REF
)
4557 oldname
= XSTR (rtlname
, 0);
4558 else if (GET_CODE (rtlname
) == MEM
4559 && GET_CODE (XEXP (rtlname
, 0)) == SYMBOL_REF
)
4560 oldname
= XSTR (XEXP (rtlname
, 0), 0);
4564 type
= TREE_TYPE (decl
);
4565 if (type
== error_mark_node
)
4567 if (! DECL_P (decl
))
4569 rl78_attributes
= RL78_ATTRIBUTES (decl
);
4571 encoding
= rl78_attrlist_to_encoding (rl78_attributes
, decl
);
4575 newname
= (char *) alloca (strlen (oldname
) + 4);
4576 sprintf (newname
, "@%c.%s", encoding
, oldname
);
4577 idp
= get_identifier (newname
);
4579 gen_rtx_SYMBOL_REF (Pmode
, IDENTIFIER_POINTER (idp
));
4580 SYMBOL_REF_WEAK (XEXP (rtl
, 0)) = DECL_WEAK (decl
);
4581 SET_SYMBOL_REF_DECL (XEXP (rtl
, 0), decl
);
4585 #undef TARGET_ASM_INIT_SECTIONS
4586 #define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections
4589 rl78_asm_init_sections (void)
4592 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
4593 "\t.section .saddr,\"aw\",@progbits");
4595 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
4596 "\t.section .frodata,\"aw\",@progbits");
4599 #undef TARGET_ASM_SELECT_SECTION
4600 #define TARGET_ASM_SELECT_SECTION rl78_select_section
4603 rl78_select_section (tree decl
,
4605 unsigned HOST_WIDE_INT align
)
4609 switch (TREE_CODE (decl
))
4612 if (!TREE_READONLY (decl
)
4613 || TREE_SIDE_EFFECTS (decl
)
4614 || !DECL_INITIAL (decl
)
4615 || (DECL_INITIAL (decl
) != error_mark_node
4616 && !TREE_CONSTANT (DECL_INITIAL (decl
))))
4620 if (! TREE_CONSTANT (decl
))
4628 if (TREE_CODE (decl
) == VAR_DECL
)
4630 const char *name
= XSTR (XEXP (DECL_RTL (decl
), 0), 0);
4632 if (name
[0] == '@' && name
[2] == '.')
4636 return saddr_section
;
4639 if (TYPE_ADDR_SPACE (TREE_TYPE (decl
)) == ADDR_SPACE_FAR
4642 return frodata_section
;
4647 return TARGET_ES0
? frodata_section
: readonly_data_section
;
4649 switch (categorize_decl_for_section (decl
, reloc
))
4651 case SECCAT_TEXT
: return text_section
;
4652 case SECCAT_DATA
: return data_section
;
4653 case SECCAT_BSS
: return bss_section
;
4654 case SECCAT_RODATA
: return TARGET_ES0
? frodata_section
: readonly_data_section
;
4656 return default_select_section (decl
, reloc
, align
);
4661 rl78_output_labelref (FILE *file
, const char *str
)
4665 str2
= targetm
.strip_name_encoding (str
);
4667 fputs (user_label_prefix
, file
);
4672 rl78_output_aligned_common (FILE *stream
,
4673 tree decl ATTRIBUTE_UNUSED
,
4675 int size
, int align
, int global
)
4677 /* We intentionally don't use rl78_section_tag() here. */
4678 if (name
[0] == '@' && name
[2] == '.')
4680 const char *sec
= 0;
4684 switch_to_section (saddr_section
);
4693 while (align
> BITS_PER_UNIT
)
4698 name2
= targetm
.strip_name_encoding (name
);
4700 fprintf (stream
, "\t.global\t_%s\n", name2
);
4701 fprintf (stream
, "\t.p2align %d\n", p2align
);
4702 fprintf (stream
, "\t.type\t_%s,@object\n", name2
);
4703 fprintf (stream
, "\t.size\t_%s,%d\n", name2
, size
);
4704 fprintf (stream
, "_%s:\n\t.zero\t%d\n", name2
, size
);
4711 fprintf (stream
, "\t.local\t");
4712 assemble_name (stream
, name
);
4713 fprintf (stream
, "\n");
4715 fprintf (stream
, "\t.comm\t");
4716 assemble_name (stream
, name
);
4717 fprintf (stream
, ",%u,%u\n", size
, align
/ BITS_PER_UNIT
);
4720 #undef TARGET_INSERT_ATTRIBUTES
4721 #define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes
4724 rl78_insert_attributes (tree decl
, tree
*attributes ATTRIBUTE_UNUSED
)
4727 && TREE_CODE (decl
) == VAR_DECL
4728 && TREE_READONLY (decl
)
4729 && TREE_ADDRESSABLE (decl
)
4730 && TYPE_ADDR_SPACE (TREE_TYPE (decl
)) == ADDR_SPACE_GENERIC
)
4732 tree type
= TREE_TYPE (decl
);
4733 tree attr
= TYPE_ATTRIBUTES (type
);
4734 int q
= TYPE_QUALS_NO_ADDR_SPACE (type
) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR
);
4736 TREE_TYPE (decl
) = build_type_attribute_qual_variant (type
, attr
, q
);
4740 #undef TARGET_ASM_INTEGER
4741 #define TARGET_ASM_INTEGER rl78_asm_out_integer
4744 rl78_asm_out_integer (rtx x
, unsigned int size
, int aligned_p
)
4746 if (default_assemble_integer (x
, size
, aligned_p
))
4751 assemble_integer_with_op (".long\t", x
);
4758 #undef TARGET_UNWIND_WORD_MODE
4759 #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
4761 static scalar_int_mode
4762 rl78_unwind_word_mode (void)
4767 #ifndef USE_COLLECT2
4768 #undef TARGET_ASM_CONSTRUCTOR
4769 #define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor
4770 #undef TARGET_ASM_DESTRUCTOR
4771 #define TARGET_ASM_DESTRUCTOR rl78_asm_destructor
4774 rl78_asm_ctor_dtor (rtx symbol
, int priority
, bool is_ctor
)
4778 if (priority
!= DEFAULT_INIT_PRIORITY
)
4780 /* This section of the function is based upon code copied
4781 from: gcc/varasm.c:get_cdtor_priority_section(). */
4784 sprintf (buf
, "%s.%.5u", is_ctor
? ".ctors" : ".dtors",
4785 MAX_INIT_PRIORITY
- priority
);
4786 sec
= get_section (buf
, 0, NULL
);
4789 sec
= is_ctor
? ctors_section
: dtors_section
;
4791 assemble_addr_to_section (symbol
, sec
);
4795 rl78_asm_constructor (rtx symbol
, int priority
)
4797 rl78_asm_ctor_dtor (symbol
, priority
, true);
4801 rl78_asm_destructor (rtx symbol
, int priority
)
4803 rl78_asm_ctor_dtor (symbol
, priority
, false);
4805 #endif /* ! USE_COLLECT2 */
4807 /* Scan backwards through the insn chain looking to see if the flags
4808 have been set for a comparison of OP against OPERAND. Start with
4809 the insn *before* the current insn. */
4812 rl78_flags_already_set (rtx op
, rtx operand
)
4814 /* We only track the Z flag. */
4815 if (GET_CODE (op
) != EQ
&& GET_CODE (op
) != NE
)
4818 /* This should not happen, but let's be paranoid. */
4819 if (current_output_insn
== NULL_RTX
)
4825 for (insn
= prev_nonnote_nondebug_insn (current_output_insn
);
4827 insn
= prev_nonnote_nondebug_insn (insn
))
4832 if (! INSN_P (insn
))
4835 /* Make sure that the insn can be recognized. */
4836 if (recog_memoized (insn
) == -1)
4839 enum attr_update_Z updated
= get_attr_update_Z (insn
);
4841 rtx set
= single_set (insn
);
4842 bool must_break
= (set
!= NULL_RTX
&& rtx_equal_p (operand
, SET_DEST (set
)));
4848 case UPDATE_Z_CLOBBER
:
4851 case UPDATE_Z_UPDATE_Z
:
4863 /* We have to re-recognize the current insn as the call(s) to
4864 get_attr_update_Z() above will have overwritten the recog_data cache. */
4865 recog_memoized (current_output_insn
);
4866 cleanup_subreg_operands (current_output_insn
);
4867 constrain_operands_cached (current_output_insn
, 1);
4873 rl78_addsi3_internal (rtx
* operands
, unsigned int alternative
)
4875 const char *addH2
= "addw ax, %H2\n\t";
4877 /* If we are adding in a constant symbolic address when -mes0
4878 is active then we know that the address must be <64K and
4879 that it is invalid to access anything above 64K relative to
4880 this address. So we can skip adding in the high bytes. */
4882 && GET_CODE (operands
[2]) == SYMBOL_REF
4883 && TREE_CODE (SYMBOL_REF_DECL (operands
[2])) == VAR_DECL
4884 && TREE_READONLY (SYMBOL_REF_DECL (operands
[2]))
4885 && ! TREE_SIDE_EFFECTS (SYMBOL_REF_DECL (operands
[2])))
4886 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax";
4888 if(CONST_INT_P(operands
[2]))
4890 if((INTVAL(operands
[2]) & 0xFFFF0000) == 0)
4894 else if((INTVAL(operands
[2]) & 0xFFFF0000) == 0x00010000)
4896 addH2
= "incw ax\n\t";
4898 else if((INTVAL(operands
[2]) & 0xFFFF0000) == 0xFFFF0000)
4900 addH2
= "decw ax\n\t";
4904 switch (alternative
)
4908 snprintf(fmt_buffer
, sizeof(fmt_buffer
),
4909 "movw ax, %%h1\n\taddw ax, %%h2\n\tmovw %%h0, ax\n\tmovw ax, %%H1\n\tsknc\n\tincw ax\n\t%smovw %%H0,ax", addH2
);
4912 snprintf(fmt_buffer
, sizeof(fmt_buffer
),
4913 "movw ax, %%h1\n\taddw ax, %%h2\n\tmovw bc, ax\n\tmovw ax, %%H1\n\tsknc\n\tincw ax\n\t%smovw %%H0, ax\n\tmovw ax, bc\n\tmovw %%h0, ax", addH2
);
4923 rl78_emit_libcall (const char *name
, enum rtx_code code
,
4924 enum machine_mode dmode
, enum machine_mode smode
,
4925 int noperands
, rtx
*operands
)
4933 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
4938 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
4939 dmode
, operands
[1], smode
);
4940 equiv
= gen_rtx_fmt_e (code
, dmode
, operands
[1]);
4944 ret
= emit_library_call_value (libcall
, NULL_RTX
,
4946 operands
[1], smode
, operands
[2],
4948 equiv
= gen_rtx_fmt_ee (code
, dmode
, operands
[1], operands
[2]);
4955 insns
= get_insns ();
4957 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
4962 #undef TARGET_PREFERRED_RELOAD_CLASS
4963 #define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
4966 rl78_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, reg_class_t rclass
)
4968 if (rclass
== NO_REGS
)
4975 struct gcc_target targetm
= TARGET_INITIALIZER
;
4977 #include "gt-rl78.h"