1 /* Subroutines used for code generation on Renesas RL78 processors.
2 Copyright (C) 2011-2016 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/>. */
23 #include "coretypes.h"
30 #include "stringpool.h"
34 #include "diagnostic-core.h"
36 #include "stor-layout.h"
39 #include "insn-attr.h"
44 #include "langhooks.h"
45 #include "tree-pass.h"
47 #include "tm-constrs.h" /* for satisfies_constraint_*(). */
50 /* This file should be included last. */
51 #include "target-def.h"
53 static inline bool is_interrupt_func (const_tree decl
);
54 static inline bool is_brk_interrupt_func (const_tree decl
);
55 static void rl78_reorg (void);
56 static const char *rl78_strip_name_encoding (const char *);
57 static const char *rl78_strip_nonasm_name_encoding (const char *);
58 static section
* rl78_select_section (tree
, int, unsigned HOST_WIDE_INT
);
61 /* Debugging statements are tagged with DEBUG0 only so that they can
62 be easily enabled individually, by replacing the '0' with '1' as
67 /* REGISTER_NAMES has the names for individual 8-bit registers, but
68 these have the names we need to use when referring to 16-bit
70 static const char * const word_regnames
[] =
72 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
73 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
74 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
75 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
76 "sp", "ap", "psw", "es", "cs"
79 struct GTY(()) machine_function
81 /* If set, the rest of the fields have been computed. */
83 /* Which register pairs need to be pushed in the prologue. */
84 int need_to_push
[FIRST_PSEUDO_REGISTER
/ 2];
86 /* These fields describe the frame layout... */
88 /* 4 bytes for saved PC */
92 int framesize_outgoing
;
96 /* If set, recog is allowed to match against the "real" patterns. */
98 /* If set, recog is allowed to match against the "virtual" patterns. */
100 /* Set if the current function needs to clean up any trampolines. */
101 int trampolines_used
;
102 /* True if the ES register is used and hence
103 needs to be saved inside interrupt handlers. */
107 /* This is our init_machine_status, as set in
108 rl78_option_override. */
109 static struct machine_function
*
110 rl78_init_machine_status (void)
112 struct machine_function
*m
;
114 m
= ggc_cleared_alloc
<machine_function
> ();
115 m
->virt_insns_ok
= 1;
120 /* This pass converts virtual instructions using virtual registers, to
121 real instructions using real registers. Rather than run it as
122 reorg, we reschedule it before vartrack to help with debugging. */
125 const pass_data pass_data_rl78_devirt
=
129 OPTGROUP_NONE
, /* optinfo_flags */
130 TV_MACH_DEP
, /* tv_id */
131 0, /* properties_required */
132 0, /* properties_provided */
133 0, /* properties_destroyed */
134 0, /* todo_flags_start */
135 0, /* todo_flags_finish */
138 class pass_rl78_devirt
: public rtl_opt_pass
141 pass_rl78_devirt (gcc::context
*ctxt
)
142 : rtl_opt_pass (pass_data_rl78_devirt
, ctxt
)
146 /* opt_pass methods: */
147 virtual unsigned int execute (function
*)
156 make_pass_rl78_devirt (gcc::context
*ctxt
)
158 return new pass_rl78_devirt (ctxt
);
161 /* Redundant move elimination pass. Must be run after the basic block
162 reordering pass for the best effect. */
165 move_elim_pass (void)
167 rtx_insn
*insn
, *ninsn
;
170 for (insn
= get_insns (); insn
; insn
= ninsn
)
174 ninsn
= next_nonnote_nondebug_insn (insn
);
176 if ((set
= single_set (insn
)) == NULL_RTX
)
182 /* If we have two SET insns in a row (without anything
183 between them) and the source of the second one is the
184 destination of the first one, and vice versa, then we
185 can eliminate the second SET. */
187 && rtx_equal_p (SET_DEST (prev
), SET_SRC (set
))
188 && rtx_equal_p (SET_DEST (set
), SET_SRC (prev
))
189 /* ... and none of the operands are volatile. */
190 && ! volatile_refs_p (SET_SRC (prev
))
191 && ! volatile_refs_p (SET_DEST (prev
))
192 && ! volatile_refs_p (SET_SRC (set
))
193 && ! volatile_refs_p (SET_DEST (set
)))
196 fprintf (dump_file
, " Delete insn %d because it is redundant\n",
207 print_rtl_with_bb (dump_file
, get_insns (), 0);
214 const pass_data pass_data_rl78_move_elim
=
217 "move_elim", /* name */
218 OPTGROUP_NONE
, /* optinfo_flags */
219 TV_MACH_DEP
, /* tv_id */
220 0, /* properties_required */
221 0, /* properties_provided */
222 0, /* properties_destroyed */
223 0, /* todo_flags_start */
224 0, /* todo_flags_finish */
227 class pass_rl78_move_elim
: public rtl_opt_pass
230 pass_rl78_move_elim (gcc::context
*ctxt
)
231 : rtl_opt_pass (pass_data_rl78_move_elim
, ctxt
)
235 /* opt_pass methods: */
236 virtual unsigned int execute (function
*) { return move_elim_pass (); }
241 make_pass_rl78_move_elim (gcc::context
*ctxt
)
243 return new pass_rl78_move_elim (ctxt
);
246 #undef TARGET_ASM_FILE_START
247 #define TARGET_ASM_FILE_START rl78_asm_file_start
250 rl78_asm_file_start (void)
256 /* The memory used is 0xffec8 to 0xffedf; real registers are in
257 0xffee0 to 0xffee7. */
258 for (i
= 8; i
< 32; i
++)
259 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", i
, 0xffec0 + i
);
263 for (i
= 0; i
< 8; i
++)
265 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 8 + i
, 0xffef0 + i
);
266 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 16 + i
, 0xffee8 + i
);
267 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 24 + i
, 0xffee0 + i
);
271 opt_pass
*rl78_devirt_pass
= make_pass_rl78_devirt (g
);
272 struct register_pass_info rl78_devirt_info
=
277 PASS_POS_INSERT_BEFORE
280 opt_pass
*rl78_move_elim_pass
= make_pass_rl78_move_elim (g
);
281 struct register_pass_info rl78_move_elim_info
=
286 PASS_POS_INSERT_AFTER
289 register_pass (& rl78_devirt_info
);
290 register_pass (& rl78_move_elim_info
);
294 rl78_output_symbol_ref (FILE * file
, rtx sym
)
296 tree type
= SYMBOL_REF_DECL (sym
);
297 const char *str
= XSTR (sym
, 0);
301 fputs (str
+ 1, file
);
305 str
= rl78_strip_nonasm_name_encoding (str
);
306 if (type
&& TREE_CODE (type
) == FUNCTION_DECL
)
308 fprintf (file
, "%%code(");
309 assemble_name (file
, str
);
313 assemble_name (file
, str
);
317 #undef TARGET_OPTION_OVERRIDE
318 #define TARGET_OPTION_OVERRIDE rl78_option_override
321 rl78_option_override (void)
323 flag_omit_frame_pointer
= 1;
324 flag_no_function_cse
= 1;
325 flag_split_wide_types
= 0;
327 init_machine_status
= rl78_init_machine_status
;
333 for (i
= 24; i
< 32; i
++)
338 && strcmp (lang_hooks
.name
, "GNU C")
339 && strcmp (lang_hooks
.name
, "GNU C11")
340 && strcmp (lang_hooks
.name
, "GNU C89")
341 && strcmp (lang_hooks
.name
, "GNU C99")
342 /* Compiling with -flto results in a language of GNU GIMPLE being used... */
343 && strcmp (lang_hooks
.name
, "GNU GIMPLE"))
344 /* Address spaces are currently only supported by C. */
345 error ("-mes0 can only be used with C");
347 switch (rl78_cpu_type
)
350 rl78_cpu_type
= CPU_G14
;
351 if (rl78_mul_type
== MUL_UNINIT
)
352 rl78_mul_type
= MUL_NONE
;
356 switch (rl78_mul_type
)
358 case MUL_UNINIT
: rl78_mul_type
= MUL_NONE
; break;
359 case MUL_NONE
: break;
360 case MUL_G13
: error ("-mmul=g13 cannot be used with -mcpu=g10"); break;
361 case MUL_G14
: error ("-mmul=g14 cannot be used with -mcpu=g10"); break;
366 switch (rl78_mul_type
)
368 case MUL_UNINIT
: rl78_mul_type
= MUL_G13
; break;
369 case MUL_NONE
: break;
371 /* The S2 core does not have mul/div instructions. */
372 case MUL_G14
: error ("-mmul=g14 cannot be used with -mcpu=g13"); break;
377 switch (rl78_mul_type
)
379 case MUL_UNINIT
: rl78_mul_type
= MUL_G14
; break;
380 case MUL_NONE
: break;
382 /* The G14 core does not have the hardware multiply peripheral used by the
383 G13 core, hence you cannot use G13 multipliy routines on G14 hardware. */
384 case MUL_G13
: error ("-mmul=g13 cannot be used with -mcpu=g14"); break;
390 /* Most registers are 8 bits. Some are 16 bits because, for example,
391 gcc doesn't like dealing with $FP as a register pair (the second
392 half of $fp is also 2 to keep reload happy wrt register pairs, but
393 no register class includes it). This table maps register numbers
395 static const int register_sizes
[] =
397 1, 1, 1, 1, 1, 1, 1, 1,
398 1, 1, 1, 1, 1, 1, 1, 1,
399 1, 1, 1, 1, 1, 1, 2, 2,
400 1, 1, 1, 1, 1, 1, 1, 1,
404 /* Predicates used in the MD patterns. This one is true when virtual
405 insns may be matched, which typically means before (or during) the
408 rl78_virt_insns_ok (void)
411 return cfun
->machine
->virt_insns_ok
;
415 /* Predicates used in the MD patterns. This one is true when real
416 insns may be matched, which typically means after (or during) the
419 rl78_real_insns_ok (void)
422 return cfun
->machine
->real_insns_ok
;
426 /* Implements HARD_REGNO_NREGS. */
428 rl78_hard_regno_nregs (int regno
, machine_mode mode
)
430 int rs
= register_sizes
[regno
];
433 return ((GET_MODE_SIZE (mode
) + rs
- 1) / rs
);
436 /* Implements HARD_REGNO_MODE_OK. */
438 rl78_hard_regno_mode_ok (int regno
, machine_mode mode
)
440 int s
= GET_MODE_SIZE (mode
);
444 /* These are not to be used by gcc. */
445 if (regno
== 23 || regno
== ES_REG
|| regno
== CS_REG
)
447 /* $fp can always be accessed as a 16-bit value. */
448 if (regno
== FP_REG
&& s
== 2)
452 /* Since a reg-reg move is really a reg-mem move, we must
453 enforce alignment. */
454 if (s
> 1 && (regno
% 2))
459 return (mode
== BImode
);
460 /* All other registers must be accessed in their natural sizes. */
461 if (s
== register_sizes
[regno
])
466 /* Simplify_gen_subreg() doesn't handle memory references the way we
467 need it to below, so we use this function for when we must get a
468 valid subreg in a "natural" state. */
470 rl78_subreg (machine_mode mode
, rtx r
, machine_mode omode
, int byte
)
472 if (GET_CODE (r
) == MEM
)
473 return adjust_address (r
, mode
, byte
);
475 return simplify_gen_subreg (mode
, r
, omode
, byte
);
478 /* Used by movsi. Split SImode moves into two HImode moves, using
479 appropriate patterns for the upper and lower halves of symbols. */
481 rl78_expand_movsi (rtx
*operands
)
483 rtx op00
, op02
, op10
, op12
;
485 op00
= rl78_subreg (HImode
, operands
[0], SImode
, 0);
486 op02
= rl78_subreg (HImode
, operands
[0], SImode
, 2);
487 if (GET_CODE (operands
[1]) == CONST
488 || GET_CODE (operands
[1]) == SYMBOL_REF
)
490 op10
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (0));
491 op10
= gen_rtx_CONST (HImode
, op10
);
492 op12
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (16));
493 op12
= gen_rtx_CONST (HImode
, op12
);
497 op10
= rl78_subreg (HImode
, operands
[1], SImode
, 0);
498 op12
= rl78_subreg (HImode
, operands
[1], SImode
, 2);
501 if (rtx_equal_p (operands
[0], operands
[1]))
503 else if (rtx_equal_p (op00
, op12
))
505 emit_move_insn (op02
, op12
);
506 emit_move_insn (op00
, op10
);
510 emit_move_insn (op00
, op10
);
511 emit_move_insn (op02
, op12
);
515 /* Generate code to move an SImode value. */
517 rl78_split_movsi (rtx
*operands
, enum machine_mode omode
)
519 rtx op00
, op02
, op10
, op12
;
521 op00
= rl78_subreg (HImode
, operands
[0], omode
, 0);
522 op02
= rl78_subreg (HImode
, operands
[0], omode
, 2);
524 if (GET_CODE (operands
[1]) == CONST
525 || GET_CODE (operands
[1]) == SYMBOL_REF
)
527 op10
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (0));
528 op10
= gen_rtx_CONST (HImode
, op10
);
529 op12
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (16));
530 op12
= gen_rtx_CONST (HImode
, op12
);
534 op10
= rl78_subreg (HImode
, operands
[1], omode
, 0);
535 op12
= rl78_subreg (HImode
, operands
[1], omode
, 2);
538 if (rtx_equal_p (operands
[0], operands
[1]))
540 else if (rtx_equal_p (op00
, op12
))
556 /* Used by various two-operand expanders which cannot accept all
557 operands in the "far" namespace. Force some such operands into
558 registers so that each pattern has at most one far operand. */
560 rl78_force_nonfar_2 (rtx
*operands
, rtx (*gen
)(rtx
,rtx
))
565 /* FIXME: in the future, be smarter about only doing this if the
566 other operand is also far, assuming the devirtualizer can also
568 if (rl78_far_p (operands
[0]))
570 temp_reg
= operands
[0];
571 operands
[0] = gen_reg_rtx (GET_MODE (operands
[0]));
577 emit_insn (gen (operands
[0], operands
[1]));
579 emit_move_insn (temp_reg
, operands
[0]);
583 /* Likewise, but for three-operand expanders. */
585 rl78_force_nonfar_3 (rtx
*operands
, rtx (*gen
)(rtx
,rtx
,rtx
))
590 /* FIXME: Likewise. */
591 if (rl78_far_p (operands
[1]))
593 rtx temp_reg
= gen_reg_rtx (GET_MODE (operands
[1]));
594 emit_move_insn (temp_reg
, operands
[1]);
595 operands
[1] = temp_reg
;
598 if (rl78_far_p (operands
[0]))
600 temp_reg
= operands
[0];
601 operands
[0] = gen_reg_rtx (GET_MODE (operands
[0]));
607 emit_insn (gen (operands
[0], operands
[1], operands
[2]));
609 emit_move_insn (temp_reg
, operands
[0]);
614 rl78_one_far_p (rtx
*operands
, int n
)
619 for (i
= 0; i
< n
; i
++)
620 if (rl78_far_p (operands
[i
]))
624 else if (rtx_equal_p (operands
[i
], which
))
631 #undef TARGET_CAN_ELIMINATE
632 #define TARGET_CAN_ELIMINATE rl78_can_eliminate
635 rl78_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to ATTRIBUTE_UNUSED
)
640 /* Returns true if the given register needs to be saved by the
643 need_to_save (unsigned int regno
)
645 if (is_interrupt_func (cfun
->decl
))
647 /* We don't know what devirt will need */
651 /* We don't need to save registers that have
652 been reserved for interrupt handlers. */
656 /* If the handler is a non-leaf function then it may call
657 non-interrupt aware routines which will happily clobber
658 any call_used registers, so we have to preserve them.
659 We do not have to worry about the frame pointer register
660 though, as that is handled below. */
661 if (!crtl
->is_leaf
&& call_used_regs
[regno
] && regno
< 22)
664 /* Otherwise we only have to save a register, call_used
665 or not, if it is used by this handler. */
666 return df_regs_ever_live_p (regno
);
669 if (regno
== FRAME_POINTER_REGNUM
670 && (frame_pointer_needed
|| df_regs_ever_live_p (regno
)))
672 if (fixed_regs
[regno
])
674 if (crtl
->calls_eh_return
)
676 if (df_regs_ever_live_p (regno
)
677 && !call_used_regs
[regno
])
682 /* We use this to wrap all emitted insns in the prologue. */
686 RTX_FRAME_RELATED_P (x
) = 1;
690 /* Compute all the frame-related fields in our machine_function
693 rl78_compute_frame_info (void)
697 cfun
->machine
->computed
= 1;
698 cfun
->machine
->framesize_regs
= 0;
699 cfun
->machine
->framesize_locals
= get_frame_size ();
700 cfun
->machine
->framesize_outgoing
= crtl
->outgoing_args_size
;
702 for (i
= 0; i
< 16; i
++)
703 if (need_to_save (i
* 2) || need_to_save (i
* 2 + 1))
705 cfun
->machine
->need_to_push
[i
] = 1;
706 cfun
->machine
->framesize_regs
+= 2;
709 cfun
->machine
->need_to_push
[i
] = 0;
711 if ((cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
) & 1)
712 cfun
->machine
->framesize_locals
++;
714 cfun
->machine
->framesize
= (cfun
->machine
->framesize_regs
715 + cfun
->machine
->framesize_locals
716 + cfun
->machine
->framesize_outgoing
);
719 /* Returns true if the provided function has the specified attribute. */
721 has_func_attr (const_tree decl
, const char * func_attr
)
723 if (decl
== NULL_TREE
)
724 decl
= current_function_decl
;
726 return lookup_attribute (func_attr
, DECL_ATTRIBUTES (decl
)) != NULL_TREE
;
729 /* Returns true if the provided function has the "interrupt" attribute. */
731 is_interrupt_func (const_tree decl
)
733 return has_func_attr (decl
, "interrupt") || has_func_attr (decl
, "brk_interrupt");
736 /* Returns true if the provided function has the "brk_interrupt" attribute. */
738 is_brk_interrupt_func (const_tree decl
)
740 return has_func_attr (decl
, "brk_interrupt");
743 /* Check "interrupt" attributes. */
745 rl78_handle_func_attribute (tree
* node
,
748 int flags ATTRIBUTE_UNUSED
,
751 gcc_assert (DECL_P (* node
));
752 gcc_assert (args
== NULL_TREE
);
754 if (TREE_CODE (* node
) != FUNCTION_DECL
)
756 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
758 * no_add_attrs
= true;
761 /* FIXME: We ought to check that the interrupt and exception
762 handler attributes have been applied to void functions. */
766 /* Check "naked" attributes. */
768 rl78_handle_naked_attribute (tree
* node
,
769 tree name ATTRIBUTE_UNUSED
,
771 int flags ATTRIBUTE_UNUSED
,
774 gcc_assert (DECL_P (* node
));
775 gcc_assert (args
== NULL_TREE
);
777 if (TREE_CODE (* node
) != FUNCTION_DECL
)
779 warning (OPT_Wattributes
, "naked attribute only applies to functions");
780 * no_add_attrs
= true;
783 /* Disable warnings about this function - eg reaching the end without
784 seeing a return statement - because the programmer is doing things
785 that gcc does not know about. */
786 TREE_NO_WARNING (* node
) = 1;
791 /* Check "saddr" attributes. */
793 rl78_handle_saddr_attribute (tree
* node
,
795 tree args ATTRIBUTE_UNUSED
,
796 int flags ATTRIBUTE_UNUSED
,
799 gcc_assert (DECL_P (* node
));
801 if (TREE_CODE (* node
) == FUNCTION_DECL
)
803 warning (OPT_Wattributes
, "%qE attribute doesn't apply to functions",
805 * no_add_attrs
= true;
811 #undef TARGET_ATTRIBUTE_TABLE
812 #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
814 /* Table of RL78-specific attributes. */
815 const struct attribute_spec rl78_attribute_table
[] =
817 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
818 affects_type_identity. */
819 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute
,
821 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute
,
823 { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute
,
825 { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute
,
827 { NULL
, 0, 0, false, false, false, NULL
, false }
832 /* Break down an address RTX into its component base/index/addend
833 portions and return TRUE if the address is of a valid form, else
836 characterize_address (rtx x
, rtx
*base
, rtx
*index
, rtx
*addend
)
842 if (GET_CODE (x
) == UNSPEC
843 && XINT (x
, 1) == UNS_ES_ADDR
)
844 x
= XVECEXP (x
, 0, 1);
846 if (GET_CODE (x
) == REG
)
852 /* We sometimes get these without the CONST wrapper */
853 if (GET_CODE (x
) == PLUS
854 && GET_CODE (XEXP (x
, 0)) == SYMBOL_REF
855 && GET_CODE (XEXP (x
, 1)) == CONST_INT
)
861 if (GET_CODE (x
) == PLUS
)
866 if (GET_CODE (*base
) == SUBREG
)
868 if (GET_MODE (*base
) == HImode
869 && GET_MODE (XEXP (*base
, 0)) == SImode
870 && GET_CODE (XEXP (*base
, 0)) == REG
)
872 /* This is a throw-away rtx just to tell everyone
873 else what effective register we're using. */
874 *base
= gen_rtx_REG (HImode
, REGNO (XEXP (*base
, 0)));
878 if (GET_CODE (*base
) != REG
879 && GET_CODE (x
) == REG
)
886 if (GET_CODE (*base
) != REG
)
889 if (GET_CODE (x
) == ZERO_EXTEND
890 && GET_CODE (XEXP (x
, 0)) == REG
)
892 *index
= XEXP (x
, 0);
897 switch (GET_CODE (x
))
900 if (GET_CODE (XEXP (x
, 0)) == SYMBOL_REF
901 && GET_CODE (XEXP (x
, 0)) == CONST_INT
)
912 switch (GET_CODE (XEXP (x
, 0)))
936 /* Used by the Whb constraint. Match addresses that use HL+B or HL+C
939 rl78_hl_b_c_addr_p (rtx op
)
943 if (GET_CODE (op
) != PLUS
)
947 if (GET_CODE (hl
) == ZERO_EXTEND
)
953 if (GET_CODE (hl
) != REG
)
955 if (GET_CODE (bc
) != ZERO_EXTEND
)
958 if (GET_CODE (bc
) != REG
)
960 if (REGNO (hl
) != HL_REG
)
962 if (REGNO (bc
) != B_REG
&& REGNO (bc
) != C_REG
)
968 #define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
970 /* Return the appropriate mode for a named address address. */
972 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
973 #define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
975 static enum machine_mode
976 rl78_addr_space_address_mode (addr_space_t addrspace
)
980 case ADDR_SPACE_GENERIC
:
982 case ADDR_SPACE_NEAR
:
991 /* Used in various constraints and predicates to match operands in the
992 "far" address space. */
999 fprintf (stderr
, "\033[35mrl78_far_p: "); debug_rtx (x
);
1000 fprintf (stderr
, " = %d\033[0m\n", MEM_ADDR_SPACE (x
) == ADDR_SPACE_FAR
);
1003 /* Not all far addresses are legitimate, because the devirtualizer
1004 can't handle them. */
1005 if (! rl78_as_legitimate_address (GET_MODE (x
), XEXP (x
, 0), false, ADDR_SPACE_FAR
))
1008 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x
))) == 32;
1011 /* Return the appropriate mode for a named address pointer. */
1012 #undef TARGET_ADDR_SPACE_POINTER_MODE
1013 #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
1016 rl78_addr_space_pointer_mode (addr_space_t addrspace
)
1020 case ADDR_SPACE_GENERIC
:
1022 case ADDR_SPACE_NEAR
:
1024 case ADDR_SPACE_FAR
:
1031 /* Returns TRUE for valid addresses. */
1032 #undef TARGET_VALID_POINTER_MODE
1033 #define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
1036 rl78_valid_pointer_mode (machine_mode m
)
1038 return (m
== HImode
|| m
== SImode
);
1041 #undef TARGET_LEGITIMATE_CONSTANT_P
1042 #define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
1045 rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
)
1050 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
1051 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
1054 rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
,
1055 bool strict ATTRIBUTE_UNUSED
, addr_space_t as ATTRIBUTE_UNUSED
)
1057 rtx base
, index
, addend
;
1058 bool is_far_addr
= false;
1061 as_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (as
));
1063 if (GET_CODE (x
) == UNSPEC
1064 && XINT (x
, 1) == UNS_ES_ADDR
)
1066 x
= XVECEXP (x
, 0, 1);
1070 if (as_bits
== 16 && is_far_addr
)
1073 if (! characterize_address (x
, &base
, &index
, &addend
))
1076 /* We can't extract the high/low portions of a PLUS address
1077 involving a register during devirtualization, so make sure all
1078 such __far addresses do not have addends. This forces GCC to do
1079 the sum separately. */
1080 if (addend
&& base
&& as_bits
== 32 && GET_MODE (base
) == SImode
)
1085 int ir
= REGNO (index
);
1086 int br
= REGNO (base
);
1088 #define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
1089 OK (REG_IS (br
, HL_REG
) && REG_IS (ir
, B_REG
), "[hl+b]");
1090 OK (REG_IS (br
, HL_REG
) && REG_IS (ir
, C_REG
), "[hl+c]");
1094 if (strict
&& base
&& GET_CODE (base
) == REG
&& REGNO (base
) >= FIRST_PSEUDO_REGISTER
)
1097 if (! cfun
->machine
->virt_insns_ok
&& base
&& GET_CODE (base
) == REG
1098 && REGNO (base
) >= 8 && REGNO (base
) <= 31)
1104 /* Determine if one named address space is a subset of another. */
1105 #undef TARGET_ADDR_SPACE_SUBSET_P
1106 #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
1109 rl78_addr_space_subset_p (addr_space_t subset
, addr_space_t superset
)
1114 subset_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset
));
1115 superset_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset
));
1117 return (subset_bits
<= superset_bits
);
1120 #undef TARGET_ADDR_SPACE_CONVERT
1121 #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
1123 /* Convert from one address space to another. */
1125 rl78_addr_space_convert (rtx op
, tree from_type
, tree to_type
)
1127 addr_space_t from_as
= TYPE_ADDR_SPACE (TREE_TYPE (from_type
));
1128 addr_space_t to_as
= TYPE_ADDR_SPACE (TREE_TYPE (to_type
));
1133 to_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as
));
1134 from_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as
));
1136 if (to_bits
< from_bits
)
1139 /* This is unpredictable, as we're truncating off usable address
1142 warning (OPT_Waddress
, "converting far pointer to near pointer");
1143 result
= gen_reg_rtx (HImode
);
1144 if (GET_CODE (op
) == SYMBOL_REF
1145 || (GET_CODE (op
) == REG
&& REGNO (op
) >= FIRST_PSEUDO_REGISTER
))
1146 tmp
= gen_rtx_raw_SUBREG (HImode
, op
, 0);
1148 tmp
= simplify_subreg (HImode
, op
, SImode
, 0);
1149 gcc_assert (tmp
!= NULL_RTX
);
1150 emit_move_insn (result
, tmp
);
1153 else if (to_bits
> from_bits
)
1155 /* This always works. */
1156 result
= gen_reg_rtx (SImode
);
1157 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 0), op
);
1158 if (TREE_CODE (from_type
) == POINTER_TYPE
1159 && TREE_CODE (TREE_TYPE (from_type
)) == FUNCTION_TYPE
)
1160 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 2), const0_rtx
);
1162 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 2), GEN_INT (0x0f));
1170 /* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
1172 rl78_regno_mode_code_ok_for_base_p (int regno
, machine_mode mode ATTRIBUTE_UNUSED
,
1173 addr_space_t address_space ATTRIBUTE_UNUSED
,
1174 int outer_code ATTRIBUTE_UNUSED
, int index_code
)
1176 if (regno
<= SP_REG
&& regno
>= 16)
1178 if (index_code
== REG
)
1179 return (regno
== HL_REG
);
1180 if (regno
== C_REG
|| regno
== B_REG
|| regno
== E_REG
|| regno
== L_REG
)
1185 /* Implements MODE_CODE_BASE_REG_CLASS. */
1187 rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED
,
1188 addr_space_t address_space ATTRIBUTE_UNUSED
,
1189 int outer_code ATTRIBUTE_UNUSED
,
1190 int index_code ATTRIBUTE_UNUSED
)
1195 /* Typical stack layout should looks like this after the function's prologue:
1200 | | arguments saved | Increasing
1201 | | on the stack | addresses
1202 PARENT arg pointer -> | | /
1203 -------------------------- ---- -------------------
1204 CHILD |ret | return address
1209 frame pointer -> | | /
1217 | | outgoing | Decreasing
1218 | | arguments | addresses
1219 current stack pointer -> | | / |
1220 -------------------------- ---- ------------------ V
1223 /* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
1224 described in the machine_Function struct definition, above. */
1226 rl78_initial_elimination_offset (int from
, int to
)
1228 int rv
= 0; /* as if arg to arg */
1230 rl78_compute_frame_info ();
1234 case STACK_POINTER_REGNUM
:
1235 rv
+= cfun
->machine
->framesize_outgoing
;
1236 rv
+= cfun
->machine
->framesize_locals
;
1238 case FRAME_POINTER_REGNUM
:
1239 rv
+= cfun
->machine
->framesize_regs
;
1248 case FRAME_POINTER_REGNUM
:
1250 rv
-= cfun
->machine
->framesize_regs
;
1251 case ARG_POINTER_REGNUM
:
1261 rl78_is_naked_func (void)
1263 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl
)) != NULL_TREE
);
1266 /* Expand the function prologue (from the prologue pattern). */
1268 rl78_expand_prologue (void)
1271 rtx sp
= gen_rtx_REG (HImode
, STACK_POINTER_REGNUM
);
1272 rtx ax
= gen_rtx_REG (HImode
, AX_REG
);
1275 if (rl78_is_naked_func ())
1278 /* Always re-compute the frame info - the register usage may have changed. */
1279 rl78_compute_frame_info ();
1281 if (flag_stack_usage_info
)
1282 current_function_static_stack_size
= cfun
->machine
->framesize
;
1284 if (is_interrupt_func (cfun
->decl
) && !TARGET_G10
)
1285 for (i
= 0; i
< 4; i
++)
1286 if (cfun
->machine
->need_to_push
[i
])
1288 /* Select Bank 0 if we are using any registers from Bank 0. */
1289 emit_insn (gen_sel_rb (GEN_INT (0)));
1293 for (i
= 0; i
< 16; i
++)
1294 if (cfun
->machine
->need_to_push
[i
])
1302 emit_move_insn (ax
, gen_rtx_REG (HImode
, reg
));
1308 int need_bank
= i
/4;
1310 if (need_bank
!= rb
)
1312 emit_insn (gen_sel_rb (GEN_INT (need_bank
)));
1317 F (emit_insn (gen_push (gen_rtx_REG (HImode
, reg
))));
1321 emit_insn (gen_sel_rb (GEN_INT (0)));
1323 /* Save ES register inside interrupt functions if it is used. */
1324 if (is_interrupt_func (cfun
->decl
) && cfun
->machine
->uses_es
)
1326 emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode
, A_REG
)));
1327 F (emit_insn (gen_push (ax
)));
1330 if (frame_pointer_needed
)
1332 F (emit_move_insn (ax
, sp
));
1333 F (emit_move_insn (gen_rtx_REG (HImode
, FRAME_POINTER_REGNUM
), ax
));
1336 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1339 /* If we need to subtract more than 254*3 then it is faster and
1340 smaller to move SP into AX and perform the subtraction there. */
1345 emit_move_insn (ax
, sp
);
1346 emit_insn (gen_subhi3 (ax
, ax
, GEN_INT (fs
)));
1347 insn
= F (emit_move_insn (sp
, ax
));
1348 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
1349 gen_rtx_SET (sp
, gen_rtx_PLUS (HImode
, sp
,
1356 int fs_byte
= (fs
> 254) ? 254 : fs
;
1358 F (emit_insn (gen_subhi3 (sp
, sp
, GEN_INT (fs_byte
))));
1365 /* Expand the function epilogue (from the epilogue pattern). */
1367 rl78_expand_epilogue (void)
1370 rtx sp
= gen_rtx_REG (HImode
, STACK_POINTER_REGNUM
);
1371 rtx ax
= gen_rtx_REG (HImode
, AX_REG
);
1374 if (rl78_is_naked_func ())
1377 if (frame_pointer_needed
)
1379 emit_move_insn (ax
, gen_rtx_REG (HImode
, FRAME_POINTER_REGNUM
));
1380 emit_move_insn (sp
, ax
);
1384 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1387 emit_move_insn (ax
, sp
);
1388 emit_insn (gen_addhi3 (ax
, ax
, GEN_INT (fs
)));
1389 emit_move_insn (sp
, ax
);
1395 int fs_byte
= (fs
> 254) ? 254 : fs
;
1397 emit_insn (gen_addhi3 (sp
, sp
, GEN_INT (fs_byte
)));
1403 if (is_interrupt_func (cfun
->decl
) && cfun
->machine
->uses_es
)
1405 emit_insn (gen_pop (gen_rtx_REG (HImode
, AX_REG
)));
1406 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode
, A_REG
)));
1409 for (i
= 15; i
>= 0; i
--)
1410 if (cfun
->machine
->need_to_push
[i
])
1412 rtx dest
= gen_rtx_REG (HImode
, i
* 2);
1417 emit_insn (gen_pop (dest
));
1420 emit_insn (gen_pop (ax
));
1421 emit_move_insn (dest
, ax
);
1422 /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */
1423 emit_insn (gen_use (dest
));
1428 int need_bank
= i
/ 4;
1430 if (need_bank
!= rb
)
1432 emit_insn (gen_sel_rb (GEN_INT (need_bank
)));
1435 emit_insn (gen_pop (dest
));
1440 emit_insn (gen_sel_rb (GEN_INT (0)));
1442 if (cfun
->machine
->trampolines_used
)
1443 emit_insn (gen_trampoline_uninit ());
1445 if (is_brk_interrupt_func (cfun
->decl
))
1446 emit_jump_insn (gen_brk_interrupt_return ());
1447 else if (is_interrupt_func (cfun
->decl
))
1448 emit_jump_insn (gen_interrupt_return ());
1450 emit_jump_insn (gen_rl78_return ());
1453 /* Likewise, for exception handlers. */
1455 rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED
)
1457 /* FIXME - replace this with an indirect jump with stack adjust. */
1458 emit_jump_insn (gen_rl78_return ());
1461 #undef TARGET_ASM_FUNCTION_PROLOGUE
1462 #define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1464 /* We don't use this to actually emit the function prologue. We use
1465 this to insert a comment in the asm file describing the
1468 rl78_start_function (FILE *file
, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED
)
1472 if (cfun
->machine
->framesize
== 0)
1474 fprintf (file
, "\t; start of function\n");
1476 if (cfun
->machine
->framesize_regs
)
1478 fprintf (file
, "\t; push %d:", cfun
->machine
->framesize_regs
);
1479 for (i
= 0; i
< 16; i
++)
1480 if (cfun
->machine
->need_to_push
[i
])
1481 fprintf (file
, " %s", word_regnames
[i
*2]);
1482 fprintf (file
, "\n");
1485 if (frame_pointer_needed
)
1486 fprintf (file
, "\t; $fp points here (r22)\n");
1488 if (cfun
->machine
->framesize_locals
)
1489 fprintf (file
, "\t; locals: %d byte%s\n", cfun
->machine
->framesize_locals
,
1490 cfun
->machine
->framesize_locals
== 1 ? "" : "s");
1492 if (cfun
->machine
->framesize_outgoing
)
1493 fprintf (file
, "\t; outgoing: %d byte%s\n", cfun
->machine
->framesize_outgoing
,
1494 cfun
->machine
->framesize_outgoing
== 1 ? "" : "s");
1496 if (cfun
->machine
->uses_es
)
1497 fprintf (file
, "\t; uses ES register\n");
1500 /* Return an RTL describing where a function return value of type RET_TYPE
1503 #undef TARGET_FUNCTION_VALUE
1504 #define TARGET_FUNCTION_VALUE rl78_function_value
1507 rl78_function_value (const_tree ret_type
,
1508 const_tree fn_decl_or_type ATTRIBUTE_UNUSED
,
1509 bool outgoing ATTRIBUTE_UNUSED
)
1511 machine_mode mode
= TYPE_MODE (ret_type
);
1513 return gen_rtx_REG (mode
, 8);
1516 #undef TARGET_PROMOTE_FUNCTION_MODE
1517 #define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
1520 rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED
,
1522 int *punsignedp ATTRIBUTE_UNUSED
,
1523 const_tree funtype ATTRIBUTE_UNUSED
, int for_return ATTRIBUTE_UNUSED
)
1528 /* Return an RTL expression describing the register holding a function
1529 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
1530 be passed on the stack. CUM describes the previous parameters to the
1531 function and NAMED is false if the parameter is part of a variable
1532 parameter list, or the last named parameter before the start of a
1533 variable parameter list. */
1535 #undef TARGET_FUNCTION_ARG
1536 #define TARGET_FUNCTION_ARG rl78_function_arg
1539 rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
1540 machine_mode mode ATTRIBUTE_UNUSED
,
1541 const_tree type ATTRIBUTE_UNUSED
,
1542 bool named ATTRIBUTE_UNUSED
)
1547 #undef TARGET_FUNCTION_ARG_ADVANCE
1548 #define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1551 rl78_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
, const_tree type
,
1552 bool named ATTRIBUTE_UNUSED
)
1555 CUMULATIVE_ARGS
* cum
= get_cumulative_args (cum_v
);
1557 rounded_size
= ((mode
== BLKmode
)
1558 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
1559 if (rounded_size
& 1)
1561 (*cum
) += rounded_size
;
1564 #undef TARGET_FUNCTION_ARG_BOUNDARY
1565 #define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1568 rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED
,
1569 const_tree type ATTRIBUTE_UNUSED
)
1574 /* Supported modifier letters:
1576 A - address of a MEM
1577 S - SADDR form of a real register
1578 v - real register corresponding to a virtual register
1579 m - minus - negative of CONST_INT value.
1580 C - inverse of a conditional (NE vs EQ for example)
1581 C - complement of an integer
1582 z - collapsed conditional
1583 s - shift count mod 8
1584 S - shift count mod 16
1585 r - reverse shift count (8-(count mod 8))
1588 h - bottom HI of an SI
1590 q - bottom QI of an HI
1592 e - third QI of an SI (i.e. where the ES register gets values from)
1593 E - fourth QI of an SI (i.e. MSB)
1595 p - Add +0 to a zero-indexed HL based address.
1598 /* Implements the bulk of rl78_print_operand, below. We do it this
1599 way because we need to test for a constant at the top level and
1600 insert the '#', but not test for it anywhere else as we recurse
1601 down into the operand. */
1603 rl78_print_operand_1 (FILE * file
, rtx op
, int letter
)
1607 switch (GET_CODE (op
))
1611 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1614 if (rl78_far_p (op
))
1616 fprintf (file
, "es:");
1617 if (GET_CODE (XEXP (op
, 0)) == UNSPEC
)
1618 op
= gen_rtx_MEM (GET_MODE (op
), XVECEXP (XEXP (op
, 0), 0, 1));
1622 op
= adjust_address (op
, HImode
, 2);
1627 op
= adjust_address (op
, HImode
, 0);
1632 op
= adjust_address (op
, QImode
, 1);
1637 op
= adjust_address (op
, QImode
, 0);
1642 op
= adjust_address (op
, QImode
, 2);
1647 op
= adjust_address (op
, QImode
, 3);
1650 if (CONSTANT_P (XEXP (op
, 0)))
1652 if (!rl78_saddr_p (op
))
1653 fprintf (file
, "!");
1654 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1656 else if (GET_CODE (XEXP (op
, 0)) == PLUS
1657 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
)
1659 if (!rl78_saddr_p (op
))
1660 fprintf (file
, "!");
1661 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1663 else if (GET_CODE (XEXP (op
, 0)) == PLUS
1664 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
1665 && REGNO (XEXP (XEXP (op
, 0), 0)) == 2)
1667 rl78_print_operand_1 (file
, XEXP (XEXP (op
, 0), 1), 'u');
1668 fprintf (file
, "[");
1669 rl78_print_operand_1 (file
, XEXP (XEXP (op
, 0), 0), 0);
1670 if (letter
== 'p' && GET_CODE (XEXP (op
, 0)) == REG
)
1671 fprintf (file
, "+0");
1672 fprintf (file
, "]");
1677 fprintf (file
, "[");
1678 rl78_print_operand_1 (file
, op
, letter
);
1679 if (letter
== 'p' && REG_P (op
) && REGNO (op
) == 6)
1680 fprintf (file
, "+0");
1681 fprintf (file
, "]");
1688 fprintf (file
, "%s", reg_names
[REGNO (op
) | 1]);
1689 else if (letter
== 'H')
1690 fprintf (file
, "%s", reg_names
[REGNO (op
) + 2]);
1691 else if (letter
== 'q')
1692 fprintf (file
, "%s", reg_names
[REGNO (op
) & ~1]);
1693 else if (letter
== 'e')
1694 fprintf (file
, "%s", reg_names
[REGNO (op
) + 2]);
1695 else if (letter
== 'E')
1696 fprintf (file
, "%s", reg_names
[REGNO (op
) + 3]);
1697 else if (letter
== 'S')
1698 fprintf (file
, "0x%x", 0xffef8 + REGNO (op
));
1699 else if (GET_MODE (op
) == HImode
1700 && ! (REGNO (op
) & ~0xfe))
1703 fprintf (file
, "%s", word_regnames
[REGNO (op
) % 8]);
1705 fprintf (file
, "%s", word_regnames
[REGNO (op
)]);
1708 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
1713 fprintf (file
, "%ld", INTVAL (op
) >> 8);
1714 else if (letter
== 'H')
1715 fprintf (file
, "%ld", INTVAL (op
) >> 16);
1716 else if (letter
== 'q')
1717 fprintf (file
, "%ld", INTVAL (op
) & 0xff);
1718 else if (letter
== 'h')
1719 fprintf (file
, "%ld", INTVAL (op
) & 0xffff);
1720 else if (letter
== 'e')
1721 fprintf (file
, "%ld", (INTVAL (op
) >> 16) & 0xff);
1722 else if (letter
== 'B')
1724 int ival
= INTVAL (op
);
1727 if (exact_log2 (ival
) >= 0)
1728 fprintf (file
, "%d", exact_log2 (ival
));
1730 fprintf (file
, "%d", exact_log2 (~ival
& 0xff));
1732 else if (letter
== 'E')
1733 fprintf (file
, "%ld", (INTVAL (op
) >> 24) & 0xff);
1734 else if (letter
== 'm')
1735 fprintf (file
, "%ld", - INTVAL (op
));
1736 else if (letter
== 's')
1737 fprintf (file
, "%ld", INTVAL (op
) % 8);
1738 else if (letter
== 'S')
1739 fprintf (file
, "%ld", INTVAL (op
) % 16);
1740 else if (letter
== 'r')
1741 fprintf (file
, "%ld", 8 - (INTVAL (op
) % 8));
1742 else if (letter
== 'C')
1743 fprintf (file
, "%ld", (INTVAL (op
) ^ 0x8000) & 0xffff);
1745 fprintf (file
, "%ld", INTVAL (op
));
1749 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1754 int bits
= INTVAL (XEXP (op
, 1));
1755 int ofs
= INTVAL (XEXP (op
, 2));
1756 if (bits
== 16 && ofs
== 0)
1757 fprintf (file
, "%%lo16(");
1758 else if (bits
== 16 && ofs
== 16)
1759 fprintf (file
, "%%hi16(");
1760 else if (bits
== 8 && ofs
== 16)
1761 fprintf (file
, "%%hi8(");
1764 rl78_print_operand_1 (file
, XEXP (op
, 0), 0);
1765 fprintf (file
, ")");
1770 if (GET_CODE (XEXP (op
, 0)) == REG
)
1771 fprintf (file
, "%s", reg_names
[REGNO (XEXP (op
, 0))]);
1773 print_rtl (file
, op
);
1780 fprintf (file
, "%%hi16(");
1786 fprintf (file
, "%%lo16(");
1792 fprintf (file
, "%%hi8(");
1796 if (letter
== 'q' || letter
== 'Q')
1797 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1799 if (GET_CODE (XEXP (op
, 0)) == ZERO_EXTEND
)
1801 if (GET_CODE (XEXP (op
, 1)) == SYMBOL_REF
1802 && SYMBOL_REF_DECL (XEXP (op
, 1))
1803 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op
, 1))) == FUNCTION_DECL
)
1805 fprintf (file
, "%%code(");
1806 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op
, 1), 0)));
1807 fprintf (file
, "+");
1808 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1809 fprintf (file
, ")");
1813 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
1814 fprintf (file
, "+");
1815 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1820 if (GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1821 && SYMBOL_REF_DECL (XEXP (op
, 0))
1822 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op
, 0))) == FUNCTION_DECL
)
1824 fprintf (file
, "%%code(");
1825 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op
, 0), 0)));
1826 fprintf (file
, "+");
1827 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
1828 fprintf (file
, ")");
1832 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1833 fprintf (file
, "+");
1834 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
1838 fprintf (file
, ")");
1842 if (GET_MODE (op
) == HImode
1843 && SUBREG_BYTE (op
) == 0)
1845 fprintf (file
, "%%lo16(");
1846 rl78_print_operand_1 (file
, SUBREG_REG (op
), 0);
1847 fprintf (file
, ")");
1849 else if (GET_MODE (op
) == HImode
1850 && SUBREG_BYTE (op
) == 2)
1852 fprintf (file
, "%%hi16(");
1853 rl78_print_operand_1 (file
, SUBREG_REG (op
), 0);
1854 fprintf (file
, ")");
1858 fprintf (file
, "(%s)", GET_RTX_NAME (GET_CODE (op
)));
1866 fprintf (file
, "%%hi16(");
1872 fprintf (file
, "%%lo16(");
1878 fprintf (file
, "%%hi8(");
1882 if (letter
== 'q' || letter
== 'Q')
1883 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1885 if (SYMBOL_REF_DECL (op
) && TREE_CODE (SYMBOL_REF_DECL (op
)) == FUNCTION_DECL
)
1887 fprintf (file
, "%%code(");
1888 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (op
, 0)));
1889 fprintf (file
, ")");
1892 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (op
, 0)));
1894 fprintf (file
, ")");
1899 output_asm_label (op
);
1904 fprintf (file
, "#comparison eliminated");
1906 fprintf (file
, letter
== 'C' ? "nc" : "c");
1910 fprintf (file
, "br");
1912 fprintf (file
, letter
== 'C' ? "h" : "nh");
1916 fprintf (file
, "br");
1918 fprintf (file
, letter
== 'C' ? "c" : "nc");
1922 fprintf (file
, "#comparison eliminated");
1924 fprintf (file
, letter
== 'C' ? "nh" : "h");
1928 fprintf (file
, "br");
1930 fprintf (file
, letter
== 'C' ? "nz" : "z");
1934 fprintf (file
, "#comparison eliminated");
1936 fprintf (file
, letter
== 'C' ? "z" : "nz");
1939 /* Note: these assume appropriate adjustments were made so that
1940 unsigned comparisons, which is all this chip has, will
1944 fprintf (file
, "#comparison eliminated");
1946 fprintf (file
, letter
== 'C' ? "nc" : "c");
1950 fprintf (file
, "br");
1952 fprintf (file
, letter
== 'C' ? "h" : "nh");
1956 fprintf (file
, "br");
1958 fprintf (file
, letter
== 'C' ? "c" : "nc");
1962 fprintf (file
, "#comparison eliminated");
1964 fprintf (file
, letter
== 'C' ? "nh" : "h");
1968 fprintf (file
, "(%s)", GET_RTX_NAME (GET_CODE (op
)));
1973 #undef TARGET_PRINT_OPERAND
1974 #define TARGET_PRINT_OPERAND rl78_print_operand
1977 rl78_print_operand (FILE * file
, rtx op
, int letter
)
1979 if (CONSTANT_P (op
) && letter
!= 'u' && letter
!= 's' && letter
!= 'r' && letter
!= 'S' && letter
!= 'B')
1980 fprintf (file
, "#");
1981 rl78_print_operand_1 (file
, op
, letter
);
1984 #undef TARGET_TRAMPOLINE_INIT
1985 #define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
1987 /* Note that the RL78's addressing makes it very difficult to do
1988 trampolines on the stack. So, libgcc has a small pool of
1989 trampolines from which one is allocated to this task. */
1991 rl78_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
1993 rtx mov_addr
, thunk_addr
;
1994 rtx function
= XEXP (DECL_RTL (fndecl
), 0);
1996 mov_addr
= adjust_address (m_tramp
, HImode
, 0);
1997 thunk_addr
= gen_reg_rtx (HImode
);
1999 function
= force_reg (HImode
, function
);
2000 static_chain
= force_reg (HImode
, static_chain
);
2002 emit_insn (gen_trampoline_init (thunk_addr
, function
, static_chain
));
2003 emit_move_insn (mov_addr
, thunk_addr
);
2005 cfun
->machine
->trampolines_used
= 1;
2008 #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
2009 #define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
2012 rl78_trampoline_adjust_address (rtx m_tramp
)
2014 rtx x
= gen_rtx_MEM (HImode
, m_tramp
);
2018 /* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
2019 the "normal" compares, specifically, it only has unsigned compares,
2020 so we must synthesize the missing ones. */
2022 rl78_expand_compare (rtx
*operands
)
2024 if (GET_CODE (operands
[2]) == MEM
)
2025 operands
[2] = copy_to_mode_reg (GET_MODE (operands
[2]), operands
[2]);
2030 /* Define this to 1 if you are debugging the peephole optimizers. */
2031 #define DEBUG_PEEP 0
2033 /* Predicate used to enable the peephole2 patterns in rl78-virt.md.
2034 The default "word" size is a byte so we can effectively use all the
2035 registers, but we want to do 16-bit moves whenever possible. This
2036 function determines when such a move is an option. */
2038 rl78_peep_movhi_p (rtx
*operands
)
2043 /* (set (op0) (op1))
2044 (set (op2) (op3)) */
2046 if (! rl78_virt_insns_ok ())
2050 fprintf (stderr
, "\033[33m");
2051 debug_rtx (operands
[0]);
2052 debug_rtx (operands
[1]);
2053 debug_rtx (operands
[2]);
2054 debug_rtx (operands
[3]);
2055 fprintf (stderr
, "\033[0m");
2058 /* You can move a constant to memory as QImode, but not HImode. */
2059 if (GET_CODE (operands
[0]) == MEM
2060 && GET_CODE (operands
[1]) != REG
)
2063 fprintf (stderr
, "no peep: move constant to memory\n");
2068 if (rtx_equal_p (operands
[0], operands
[3]))
2071 fprintf (stderr
, "no peep: overlapping\n");
2076 for (i
= 0; i
< 2; i
++)
2078 if (GET_CODE (operands
[i
]) != GET_CODE (operands
[i
+2]))
2081 fprintf (stderr
, "no peep: different codes\n");
2085 if (GET_MODE (operands
[i
]) != GET_MODE (operands
[i
+2]))
2088 fprintf (stderr
, "no peep: different modes\n");
2093 switch (GET_CODE (operands
[i
]))
2097 if (REGNO (operands
[i
]) + 1 != REGNO (operands
[i
+2])
2098 || GET_MODE (operands
[i
]) != QImode
)
2101 fprintf (stderr
, "no peep: wrong regnos %d %d %d\n",
2102 REGNO (operands
[i
]), REGNO (operands
[i
+2]),
2107 if (! rl78_hard_regno_mode_ok (REGNO (operands
[i
]), HImode
))
2110 fprintf (stderr
, "no peep: reg %d not HI\n", REGNO (operands
[i
]));
2120 if (GET_MODE (operands
[i
]) != QImode
)
2122 if (MEM_ALIGN (operands
[i
]) < 16)
2124 a
= XEXP (operands
[i
], 0);
2125 if (GET_CODE (a
) == CONST
)
2127 if (GET_CODE (a
) == PLUS
)
2129 if (GET_CODE (a
) == CONST_INT
2133 fprintf (stderr
, "no peep: misaligned mem %d\n", i
);
2134 debug_rtx (operands
[i
]);
2138 m
= adjust_address (operands
[i
], QImode
, 1);
2139 if (! rtx_equal_p (m
, operands
[i
+2]))
2142 fprintf (stderr
, "no peep: wrong mem %d\n", i
);
2144 debug_rtx (operands
[i
+2]);
2152 fprintf (stderr
, "no peep: wrong rtx %d\n", i
);
2158 fprintf (stderr
, "\033[32mpeep!\033[0m\n");
2163 /* Likewise, when a peephole is activated, this function helps compute
2164 the new operands. */
2166 rl78_setup_peep_movhi (rtx
*operands
)
2170 for (i
= 0; i
< 2; i
++)
2172 switch (GET_CODE (operands
[i
]))
2175 operands
[i
+4] = gen_rtx_REG (HImode
, REGNO (operands
[i
]));
2179 operands
[i
+4] = GEN_INT ((INTVAL (operands
[i
]) & 0xff) + ((char) INTVAL (operands
[i
+2])) * 256);
2183 operands
[i
+4] = adjust_address (operands
[i
], HImode
, 0);
2193 How Devirtualization works in the RL78 GCC port
2197 The RL78 is an 8-bit port with some 16-bit operations. It has 32
2198 bytes of register space, in four banks, memory-mapped. One bank is
2199 the "selected" bank and holds the registers used for primary
2200 operations. Since the registers are memory mapped, often you can
2201 still refer to the unselected banks via memory accesses.
2205 The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
2206 and refers to the other banks via their memory addresses, although
2207 they're treated as regular registers internally. These "virtual"
2208 registers are R8 through R23 (bank3 is reserved for asm-based
2209 interrupt handlers).
2211 There are four machine description files:
2213 rl78.md - common register-independent patterns and definitions
2214 rl78-expand.md - expanders
2215 rl78-virt.md - patterns that match BEFORE devirtualization
2216 rl78-real.md - patterns that match AFTER devirtualization
2218 At least through register allocation and reload, gcc is told that it
2219 can do pretty much anything - but may only use the virtual registers.
2220 GCC cannot properly create the varying addressing modes that the RL78
2221 supports in an efficient way.
2223 Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
2224 uses the "valloc" attribute in rl78-virt.md for determining the rules
2225 by which it will replace virtual registers with real registers (or
2226 not) and how to make up addressing modes. For example, insns tagged
2227 with "ro1" have a single read-only parameter, which may need to be
2228 moved from memory/constant/vreg to a suitable real register. As part
2229 of devirtualization, a flag is toggled, disabling the rl78-virt.md
2230 patterns and enabling the rl78-real.md patterns. The new patterns'
2231 constraints are used to determine the real registers used. NOTE:
2232 patterns in rl78-virt.md essentially ignore the constrains and rely on
2233 predicates, where the rl78-real.md ones essentially ignore the
2234 predicates and rely on the constraints.
2236 The devirtualization pass is scheduled via the pass manager (despite
2237 being called "rl78_reorg") so it can be scheduled prior to var-track
2238 (the idea is to let gdb know about the new registers). Ideally, it
2239 would be scheduled right after pro/epilogue generation, so the
2240 post-reload optimizers could operate on the real registers, but when I
2241 tried that there were some issues building the target libraries.
2243 During devirtualization, a simple register move optimizer is run. It
2244 would be better to run a full CSE/propogation pass on it though, but
2245 that has not yet been attempted.
2248 #define DEBUG_ALLOC 0
2250 #define OP(x) (*recog_data.operand_loc[x])
2252 /* This array is used to hold knowledge about the contents of the
2253 real registers (A ... H), the memory-based registers (r8 ... r31)
2254 and the first NUM_STACK_LOCS words on the stack. We use this to
2255 avoid generating redundant move instructions.
2257 A value in the range 0 .. 31 indicates register A .. r31.
2258 A value in the range 32 .. 63 indicates stack slot (value - 32).
2259 A value of NOT_KNOWN indicates that the contents of that location
2262 #define NUM_STACK_LOCS 32
2263 #define NOT_KNOWN 127
2265 static unsigned char content_memory
[32 + NUM_STACK_LOCS
];
2267 static unsigned char saved_update_index
= NOT_KNOWN
;
2268 static unsigned char saved_update_value
;
2269 static machine_mode saved_update_mode
;
2273 clear_content_memory (void)
2275 memset (content_memory
, NOT_KNOWN
, sizeof content_memory
);
2277 fprintf (dump_file
, " clear content memory\n");
2278 saved_update_index
= NOT_KNOWN
;
2281 /* Convert LOC into an index into the content_memory array.
2282 If LOC cannot be converted, return NOT_KNOWN. */
2284 static unsigned char
2285 get_content_index (rtx loc
)
2289 if (loc
== NULL_RTX
)
2294 if (REGNO (loc
) < 32)
2299 mode
= GET_MODE (loc
);
2301 if (! rl78_stack_based_mem (loc
, mode
))
2304 loc
= XEXP (loc
, 0);
2307 /* loc = MEM (SP) */
2310 /* loc = MEM (PLUS (SP, INT)). */
2311 loc
= XEXP (loc
, 1);
2313 if (INTVAL (loc
) < NUM_STACK_LOCS
)
2314 return 32 + INTVAL (loc
);
2319 /* Return a string describing content INDEX in mode MODE.
2320 WARNING: Can return a pointer to a static buffer. */
2322 get_content_name (unsigned char index
, machine_mode mode
)
2324 static char buffer
[128];
2326 if (index
== NOT_KNOWN
)
2330 sprintf (buffer
, "stack slot %d", index
- 32);
2331 else if (mode
== HImode
)
2332 sprintf (buffer
, "%s%s",
2333 reg_names
[index
+ 1], reg_names
[index
]);
2335 return reg_names
[index
];
2343 display_content_memory (FILE * file
)
2347 fprintf (file
, " Known memory contents:\n");
2349 for (i
= 0; i
< sizeof content_memory
; i
++)
2350 if (content_memory
[i
] != NOT_KNOWN
)
2352 fprintf (file
, " %s contains a copy of ", get_content_name (i
, QImode
));
2353 fprintf (file
, "%s\n", get_content_name (content_memory
[i
], QImode
));
2359 update_content (unsigned char index
, unsigned char val
, machine_mode mode
)
2363 gcc_assert (index
< sizeof content_memory
);
2365 content_memory
[index
] = val
;
2366 if (val
!= NOT_KNOWN
)
2367 content_memory
[val
] = index
;
2369 /* Make the entry in dump_file *before* VAL is increased below. */
2372 fprintf (dump_file
, " %s now contains ", get_content_name (index
, mode
));
2373 if (val
== NOT_KNOWN
)
2374 fprintf (dump_file
, "Unknown\n");
2376 fprintf (dump_file
, "%s and vice versa\n", get_content_name (val
, mode
));
2381 val
= val
== NOT_KNOWN
? val
: val
+ 1;
2383 content_memory
[index
+ 1] = val
;
2384 if (val
!= NOT_KNOWN
)
2386 content_memory
[val
] = index
+ 1;
2391 /* Any other places that had INDEX recorded as their contents are now invalid. */
2392 for (i
= 0; i
< sizeof content_memory
; i
++)
2395 || (val
!= NOT_KNOWN
&& i
== val
))
2402 if (content_memory
[i
] == index
2403 || (val
!= NOT_KNOWN
&& content_memory
[i
] == val
))
2405 content_memory
[i
] = NOT_KNOWN
;
2408 fprintf (dump_file
, " %s cleared\n", get_content_name (i
, mode
));
2411 content_memory
[++ i
] = NOT_KNOWN
;
2416 /* Record that LOC contains VALUE.
2417 For HImode locations record that LOC+1 contains VALUE+1.
2418 If LOC is not a register or stack slot, do nothing.
2419 If VALUE is not a register or stack slot, clear the recorded content. */
2422 record_content (rtx loc
, rtx value
)
2425 unsigned char index
;
2428 if ((index
= get_content_index (loc
)) == NOT_KNOWN
)
2431 val
= get_content_index (value
);
2433 mode
= GET_MODE (loc
);
2440 /* This should not happen when optimizing. */
2442 fprintf (stderr
, "ASSIGNMENT of location to itself detected! [%s]\n",
2443 get_content_name (val
, mode
));
2450 update_content (index
, val
, mode
);
2453 /* Returns TRUE if LOC already contains a copy of VALUE. */
2456 already_contains (rtx loc
, rtx value
)
2458 unsigned char index
;
2461 if ((index
= get_content_index (loc
)) == NOT_KNOWN
)
2464 if ((val
= get_content_index (value
)) == NOT_KNOWN
)
2467 if (content_memory
[index
] != val
)
2470 if (GET_MODE (loc
) == HImode
)
2471 return content_memory
[index
+ 1] == val
+ 1;
2477 rl78_es_addr (rtx addr
)
2479 if (GET_CODE (addr
) == MEM
)
2480 addr
= XEXP (addr
, 0);
2481 if (GET_CODE (addr
) != UNSPEC
)
2483 if (XINT (addr
, 1) != UNS_ES_ADDR
)
2489 rl78_es_base (rtx addr
)
2491 if (GET_CODE (addr
) == MEM
)
2492 addr
= XEXP (addr
, 0);
2493 addr
= XVECEXP (addr
, 0, 1);
2494 if (GET_CODE (addr
) == CONST
2495 && GET_CODE (XEXP (addr
, 0)) == ZERO_EXTRACT
)
2496 addr
= XEXP (XEXP (addr
, 0), 0);
2497 /* Mode doesn't matter here. */
2498 return gen_rtx_MEM (HImode
, addr
);
2501 /* Rescans an insn to see if it's recognized again. This is done
2502 carefully to ensure that all the constraint information is accurate
2503 for the newly matched insn. */
2505 insn_ok_now (rtx_insn
* insn
)
2507 rtx pattern
= PATTERN (insn
);
2510 INSN_CODE (insn
) = -1;
2512 if (recog (pattern
, insn
, 0) > -1)
2514 extract_insn (insn
);
2515 if (constrain_operands (1, get_preferred_alternatives (insn
)))
2518 fprintf (stderr
, "\033[32m");
2520 fprintf (stderr
, "\033[0m");
2522 if (SET_P (pattern
))
2523 record_content (SET_DEST (pattern
), SET_SRC (pattern
));
2525 /* We need to detect far addresses that haven't been
2526 converted to es/lo16 format. */
2527 for (i
=0; i
<recog_data
.n_operands
; i
++)
2528 if (GET_CODE (OP (i
)) == MEM
2529 && GET_MODE (XEXP (OP (i
), 0)) == SImode
2530 && GET_CODE (XEXP (OP (i
), 0)) != UNSPEC
)
2538 /* We need to re-recog the insn with virtual registers to get
2540 cfun
->machine
->virt_insns_ok
= 1;
2541 if (recog (pattern
, insn
, 0) > -1)
2543 extract_insn (insn
);
2544 if (constrain_operands (0, get_preferred_alternatives (insn
)))
2546 cfun
->machine
->virt_insns_ok
= 0;
2552 fprintf (stderr
, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
2559 fprintf (stderr
, "\033[31m");
2561 fprintf (stderr
, "\033[0m");
2567 #define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
2568 #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
2569 #define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
2570 #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
2571 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
2573 #define FAILED gcc_unreachable ()
2574 #define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
2575 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
2578 /* Registers into which we move the contents of virtual registers. */
2579 #define X gen_rtx_REG (QImode, X_REG)
2580 #define A gen_rtx_REG (QImode, A_REG)
2581 #define C gen_rtx_REG (QImode, C_REG)
2582 #define B gen_rtx_REG (QImode, B_REG)
2583 #define E gen_rtx_REG (QImode, E_REG)
2584 #define D gen_rtx_REG (QImode, D_REG)
2585 #define L gen_rtx_REG (QImode, L_REG)
2586 #define H gen_rtx_REG (QImode, H_REG)
2588 #define AX gen_rtx_REG (HImode, AX_REG)
2589 #define BC gen_rtx_REG (HImode, BC_REG)
2590 #define DE gen_rtx_REG (HImode, DE_REG)
2591 #define HL gen_rtx_REG (HImode, HL_REG)
2593 /* Returns TRUE if R is a virtual register. */
2595 is_virtual_register (rtx r
)
2597 return (GET_CODE (r
) == REG
2602 /* In all these alloc routines, we expect the following: the insn
2603 pattern is unshared, the insn was previously recognized and failed
2604 due to predicates or constraints, and the operand data is in
2607 static int virt_insn_was_frame
;
2609 /* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2612 EM2 (int line ATTRIBUTE_UNUSED
, rtx r
)
2615 fprintf (stderr
, "\033[36m%d: ", line
);
2617 fprintf (stderr
, "\033[0m");
2619 /*SCHED_GROUP_P (r) = 1;*/
2620 if (virt_insn_was_frame
)
2621 RTX_FRAME_RELATED_P (r
) = 1;
2625 #define EM(x) EM2 (__LINE__, x)
2627 /* Return a suitable RTX for the low half of a __far address. */
2629 rl78_lo16 (rtx addr
)
2633 if (GET_CODE (addr
) == SYMBOL_REF
2634 || GET_CODE (addr
) == CONST
)
2636 r
= gen_rtx_ZERO_EXTRACT (HImode
, addr
, GEN_INT (16), GEN_INT (0));
2637 r
= gen_rtx_CONST (HImode
, r
);
2640 r
= rl78_subreg (HImode
, addr
, SImode
, 0);
2642 r
= gen_es_addr (r
);
2643 cfun
->machine
->uses_es
= true;
2648 /* Return a suitable RTX for the high half's lower byte of a __far address. */
2652 if (GET_CODE (addr
) == SYMBOL_REF
2653 || GET_CODE (addr
) == CONST
)
2655 rtx r
= gen_rtx_ZERO_EXTRACT (QImode
, addr
, GEN_INT (8), GEN_INT (16));
2656 r
= gen_rtx_CONST (QImode
, r
);
2659 return rl78_subreg (QImode
, addr
, SImode
, 2);
2663 add_postponed_content_update (rtx to
, rtx value
)
2665 unsigned char index
;
2667 if ((index
= get_content_index (to
)) == NOT_KNOWN
)
2670 gcc_assert (saved_update_index
== NOT_KNOWN
);
2671 saved_update_index
= index
;
2672 saved_update_value
= get_content_index (value
);
2673 saved_update_mode
= GET_MODE (to
);
2677 process_postponed_content_update (void)
2679 if (saved_update_index
!= NOT_KNOWN
)
2681 update_content (saved_update_index
, saved_update_value
, saved_update_mode
);
2682 saved_update_index
= NOT_KNOWN
;
2686 /* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2687 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2688 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2689 BEFORE is true, FROM otherwise. */
2691 gen_and_emit_move (rtx to
, rtx from
, rtx where
, bool before
)
2693 machine_mode mode
= GET_MODE (to
);
2695 if (optimize
&& before
&& already_contains (to
, from
))
2698 display_content_memory (stderr
);
2702 fprintf (dump_file
, " Omit move of %s into ",
2703 get_content_name (get_content_index (from
), mode
));
2704 fprintf (dump_file
, "%s as it already contains this value\n",
2705 get_content_name (get_content_index (to
), mode
));
2710 rtx move
= mode
== QImode
? gen_movqi (to
, from
) : gen_movhi (to
, from
);
2714 if (where
== NULL_RTX
)
2717 emit_insn_before (move
, where
);
2720 rtx note
= find_reg_note (where
, REG_EH_REGION
, NULL_RTX
);
2722 /* If necessary move REG_EH_REGION notes forward.
2723 cf. compiling gcc.dg/pr44545.c. */
2724 if (note
!= NULL_RTX
)
2726 add_reg_note (move
, REG_EH_REGION
, XEXP (note
, 0));
2727 remove_note (where
, note
);
2730 emit_insn_after (move
, where
);
2734 record_content (to
, from
);
2736 add_postponed_content_update (to
, from
);
2739 return before
? to
: from
;
2742 /* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2743 copy it into NEWBASE and return the updated MEM. Otherwise just
2744 return M. Any needed insns are emitted before BEFORE. */
2746 transcode_memory_rtx (rtx m
, rtx newbase
, rtx before
)
2748 rtx base
, index
, addendr
;
2755 if (GET_MODE (XEXP (m
, 0)) == SImode
)
2758 rtx seg
= rl78_hi8 (XEXP (m
, 0));
2762 emit_insn_before (EM (gen_movqi (A
, seg
)), before
);
2763 emit_insn_before (EM (gen_movqi_to_es (A
)), before
);
2766 record_content (A
, NULL_RTX
);
2768 new_m
= gen_rtx_MEM (GET_MODE (m
), rl78_lo16 (XEXP (m
, 0)));
2769 MEM_COPY_ATTRIBUTES (new_m
, m
);
2774 characterize_address (XEXP (m
, 0), & base
, & index
, & addendr
);
2775 gcc_assert (index
== NULL_RTX
);
2777 if (base
== NULL_RTX
)
2780 if (addendr
&& GET_CODE (addendr
) == CONST_INT
)
2781 addend
= INTVAL (addendr
);
2783 gcc_assert (REG_P (base
));
2784 gcc_assert (REG_P (newbase
));
2786 int limit
= 256 - GET_MODE_SIZE (GET_MODE (m
));
2788 if (REGNO (base
) == SP_REG
)
2790 if (addend
>= 0 && addend
<= limit
)
2794 /* BASE should be a virtual register. We copy it to NEWBASE. If
2795 the addend is out of range for DE/HL, we use AX to compute the full
2799 || (addend
> limit
&& REGNO (newbase
) != BC_REG
)
2801 && (GET_CODE (addendr
) != CONST_INT
)
2802 && ((REGNO (newbase
) != BC_REG
))
2808 EM (emit_insn_before (gen_movhi (AX
, base
), before
));
2809 EM (emit_insn_before (gen_addhi3 (AX
, AX
, addendr
), before
));
2810 EM (emit_insn_before (gen_movhi (newbase
, AX
), before
));
2811 record_content (AX
, NULL_RTX
);
2812 record_content (newbase
, NULL_RTX
);
2820 base
= gen_and_emit_move (newbase
, base
, before
, true);
2825 record_content (base
, NULL_RTX
);
2826 base
= gen_rtx_PLUS (HImode
, base
, GEN_INT (addend
));
2830 record_content (base
, NULL_RTX
);
2831 base
= gen_rtx_PLUS (HImode
, base
, addendr
);
2836 m
= change_address (m
, GET_MODE (m
), gen_es_addr (base
));
2837 cfun
->machine
->uses_es
= true;
2840 m
= change_address (m
, GET_MODE (m
), base
);
2844 /* Copy SRC to accumulator (A or AX), placing any generated insns
2845 before BEFORE. Returns accumulator RTX. */
2847 move_to_acc (int opno
, rtx before
)
2849 rtx src
= OP (opno
);
2850 machine_mode mode
= GET_MODE (src
);
2852 if (REG_P (src
) && REGNO (src
) < 2)
2855 if (mode
== VOIDmode
)
2856 mode
= recog_data
.operand_mode
[opno
];
2858 return gen_and_emit_move (mode
== QImode
? A
: AX
, src
, before
, true);
2862 force_into_acc (rtx src
, rtx before
)
2864 machine_mode mode
= GET_MODE (src
);
2867 if (REG_P (src
) && REGNO (src
) < 2)
2870 move
= mode
== QImode
? gen_movqi (A
, src
) : gen_movhi (AX
, src
);
2874 emit_insn_before (move
, before
);
2875 record_content (AX
, NULL_RTX
);
2878 /* Copy accumulator (A or AX) to DEST, placing any generated insns
2879 after AFTER. Returns accumulator RTX. */
2881 move_from_acc (unsigned int opno
, rtx after
)
2883 rtx dest
= OP (opno
);
2884 machine_mode mode
= GET_MODE (dest
);
2886 if (REG_P (dest
) && REGNO (dest
) < 2)
2889 return gen_and_emit_move (dest
, mode
== QImode
? A
: AX
, after
, false);
2892 /* Copy accumulator (A or AX) to REGNO, placing any generated insns
2893 before BEFORE. Returns reg RTX. */
2895 move_acc_to_reg (rtx acc
, int regno
, rtx before
)
2897 machine_mode mode
= GET_MODE (acc
);
2900 reg
= gen_rtx_REG (mode
, regno
);
2902 return gen_and_emit_move (reg
, acc
, before
, true);
2905 /* Copy SRC to X, placing any generated insns before BEFORE.
2908 move_to_x (int opno
, rtx before
)
2910 rtx src
= OP (opno
);
2911 machine_mode mode
= GET_MODE (src
);
2914 if (mode
== VOIDmode
)
2915 mode
= recog_data
.operand_mode
[opno
];
2916 reg
= (mode
== QImode
) ? X
: AX
;
2918 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
2920 OP (opno
) = move_to_acc (opno
, before
);
2921 OP (opno
) = move_acc_to_reg (OP (opno
), X_REG
, before
);
2925 return gen_and_emit_move (reg
, src
, before
, true);
2928 /* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
2929 Returns H/HL RTX. */
2931 move_to_hl (int opno
, rtx before
)
2933 rtx src
= OP (opno
);
2934 machine_mode mode
= GET_MODE (src
);
2937 if (mode
== VOIDmode
)
2938 mode
= recog_data
.operand_mode
[opno
];
2939 reg
= (mode
== QImode
) ? L
: HL
;
2941 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
2943 OP (opno
) = move_to_acc (opno
, before
);
2944 OP (opno
) = move_acc_to_reg (OP (opno
), L_REG
, before
);
2948 return gen_and_emit_move (reg
, src
, before
, true);
2951 /* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
2952 Returns E/DE RTX. */
2954 move_to_de (int opno
, rtx before
)
2956 rtx src
= OP (opno
);
2957 machine_mode mode
= GET_MODE (src
);
2960 if (mode
== VOIDmode
)
2961 mode
= recog_data
.operand_mode
[opno
];
2963 reg
= (mode
== QImode
) ? E
: DE
;
2965 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
2967 OP (opno
) = move_to_acc (opno
, before
);
2968 OP (opno
) = move_acc_to_reg (OP (opno
), E_REG
, before
);
2972 gen_and_emit_move (reg
, src
, before
, true);
2978 /* Devirtualize an insn of the form (SET (op) (unop (op))). */
2980 rl78_alloc_physical_registers_op1 (rtx_insn
* insn
)
2982 /* op[0] = func op[1] */
2984 /* We first try using A as the destination, then copying it
2986 if (rtx_equal_p (OP (0), OP (1)))
2989 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
2993 /* If necessary, load the operands into BC and HL.
2994 Check to see if we already have OP (0) in HL
2995 and if so, swap the order.
2997 It is tempting to perform this optimization when OP(0) does
2998 not hold a MEM, but this leads to bigger code in general.
2999 The problem is that if OP(1) holds a MEM then swapping it
3000 into BC means a BC-relative load is used and these are 3
3001 bytes long vs 1 byte for an HL load. */
3003 && already_contains (HL
, XEXP (OP (0), 0)))
3005 OP (0) = transcode_memory_rtx (OP (0), HL
, insn
);
3006 OP (1) = transcode_memory_rtx (OP (1), BC
, insn
);
3010 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3011 OP (1) = transcode_memory_rtx (OP (1), HL
, insn
);
3017 OP (0) = move_from_acc (0, insn
);
3021 /* Try copying the src to acc first, then. This is for, for
3022 example, ZERO_EXTEND or NOT. */
3023 OP (1) = move_to_acc (1, insn
);
3028 /* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
3029 Assumes that the current insn has already been recognised and hence the
3030 constraint data has been filled in. */
3032 has_constraint (unsigned int opnum
, enum constraint_num constraint
)
3034 const char * p
= recog_data
.constraints
[opnum
];
3036 /* No constraints means anything is accepted. */
3037 if (p
== NULL
|| *p
== 0 || *p
== ',')
3046 len
= CONSTRAINT_LEN (c
, p
);
3047 gcc_assert (len
> 0);
3055 if (lookup_constraint (p
) == constraint
)
3063 /* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
3065 rl78_alloc_physical_registers_op2 (rtx_insn
* insn
)
3073 if (rtx_equal_p (OP (0), OP (1)))
3078 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3079 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3084 OP (1) = transcode_memory_rtx (OP (1), HL
, insn
);
3085 OP (2) = transcode_memory_rtx (OP (2), DE
, insn
);
3088 else if (rtx_equal_p (OP (0), OP (2)))
3090 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3092 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3096 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3097 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3098 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3103 prev
= prev_nonnote_nondebug_insn (insn
);
3104 if (recog_data
.constraints
[1][0] == '%'
3105 && is_virtual_register (OP (1))
3106 && ! is_virtual_register (OP (2))
3107 && ! CONSTANT_P (OP (2)))
3114 /* Make a note of whether (H)L is being used. It matters
3115 because if OP (2) also needs reloading, then we must take
3116 care not to corrupt HL. */
3117 hl_used
= reg_mentioned_p (L
, OP (0)) || reg_mentioned_p (L
, OP (1));
3119 /* If HL is not currently being used and dest == op1 then there are
3120 some possible optimizations available by reloading one of the
3121 operands into HL, before trying to use the accumulator. */
3124 && rtx_equal_p (OP (0), OP (1)))
3126 /* If op0 is a Ws1 type memory address then switching the base
3127 address register to HL might allow us to perform an in-memory
3128 operation. (eg for the INCW instruction).
3130 FIXME: Adding the move into HL is costly if this optimization is not
3131 going to work, so for now, make sure that we know that the new insn will
3132 match the requirements of the addhi3_real pattern. Really we ought to
3133 generate a candidate sequence, test that, and then install it if the
3134 results are good. */
3135 if (satisfies_constraint_Ws1 (OP (0))
3136 && has_constraint (0, CONSTRAINT_Wh1
)
3137 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
3139 rtx base
, index
, addend
, newbase
;
3141 characterize_address (XEXP (OP (0), 0), & base
, & index
, & addend
);
3142 gcc_assert (index
== NULL_RTX
);
3143 gcc_assert (REG_P (base
) && REGNO (base
) == SP_REG
);
3145 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3146 if (addend
!= NULL_RTX
)
3148 newbase
= gen_and_emit_move (HL
, base
, insn
, true);
3149 record_content (newbase
, NULL_RTX
);
3150 newbase
= gen_rtx_PLUS (HImode
, newbase
, addend
);
3152 OP (0) = OP (1) = change_address (OP (0), VOIDmode
, newbase
);
3154 /* We do not want to fail here as this means that
3155 we have inserted useless insns into the stream. */
3159 else if (REG_P (OP (0))
3160 && satisfies_constraint_Ws1 (OP (2))
3161 && has_constraint (2, CONSTRAINT_Wh1
))
3163 rtx base
, index
, addend
, newbase
;
3165 characterize_address (XEXP (OP (2), 0), & base
, & index
, & addend
);
3166 gcc_assert (index
== NULL_RTX
);
3167 gcc_assert (REG_P (base
) && REGNO (base
) == SP_REG
);
3169 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3170 if (addend
!= NULL_RTX
)
3172 gen_and_emit_move (HL
, base
, insn
, true);
3174 if (REGNO (OP (0)) != X_REG
)
3176 OP (1) = move_to_acc (1, insn
);
3177 OP (0) = move_from_acc (0, insn
);
3180 record_content (HL
, NULL_RTX
);
3181 newbase
= gen_rtx_PLUS (HImode
, HL
, addend
);
3183 OP (2) = change_address (OP (2), VOIDmode
, newbase
);
3185 /* We do not want to fail here as this means that
3186 we have inserted useless insns into the stream. */
3192 OP (0) = move_from_acc (0, insn
);
3194 tmp_id
= get_max_insn_count ();
3197 if (rtx_equal_p (OP (1), OP (2)))
3198 OP (2) = OP (1) = move_to_acc (1, insn
);
3200 OP (1) = move_to_acc (1, insn
);
3204 /* If we omitted the move of OP1 into the accumulator (because
3205 it was already there from a previous insn), then force the
3206 generation of the move instruction now. We know that we
3207 are about to emit a move into HL (or DE) via AX, and hence
3208 our optimization to remove the load of OP1 is no longer valid. */
3209 if (tmp_id
== get_max_insn_count ())
3210 force_into_acc (saved_op1
, insn
);
3212 /* We have to copy op2 to HL (or DE), but that involves AX, which
3213 already has a live value. Emit it before those insns. */
3216 first
= next_nonnote_nondebug_insn (prev
);
3218 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3221 OP (2) = hl_used
? move_to_de (2, first
) : move_to_hl (2, first
);
3226 /* Devirtualize an insn of the form SET (PC) (MEM/REG). */
3228 rl78_alloc_physical_registers_ro1 (rtx_insn
* insn
)
3230 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3234 OP (0) = move_to_acc (0, insn
);
3239 /* Devirtualize a compare insn. */
3241 rl78_alloc_physical_registers_cmp (rtx_insn
* insn
)
3245 rtx_insn
*prev
= prev_nonnote_nondebug_insn (insn
);
3248 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3249 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3251 /* HI compares have to have OP (1) in AX, but QI
3252 compares do not, so it is worth checking here. */
3255 /* For an HImode compare, OP (1) must always be in AX.
3256 But if OP (1) is a REG (and not AX), then we can avoid
3257 a reload of OP (1) if we reload OP (2) into AX and invert
3260 && REGNO (OP (1)) != AX_REG
3261 && GET_MODE (OP (1)) == HImode
3264 rtx cmp
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3266 OP (2) = move_to_acc (2, insn
);
3268 switch (GET_CODE (cmp
))
3273 case LTU
: cmp
= gen_rtx_GTU (HImode
, OP (2), OP (1)); break;
3274 case GTU
: cmp
= gen_rtx_LTU (HImode
, OP (2), OP (1)); break;
3275 case LEU
: cmp
= gen_rtx_GEU (HImode
, OP (2), OP (1)); break;
3276 case GEU
: cmp
= gen_rtx_LEU (HImode
, OP (2), OP (1)); break;
3289 if (GET_CODE (cmp
) == EQ
|| GET_CODE (cmp
) == NE
)
3290 PATTERN (insn
) = gen_cbranchhi4_real (cmp
, OP (2), OP (1), OP (3));
3292 PATTERN (insn
) = gen_cbranchhi4_real_inverted (cmp
, OP (2), OP (1), OP (3));
3297 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
3298 should be handled by the second alternative of the cbranchhi_real pattern. */
3299 if (rtx_equal_p (OP (1), OP (2)))
3301 OP (1) = OP (2) = BC
;
3305 tmp_id
= get_max_insn_count ();
3308 OP (1) = move_to_acc (1, insn
);
3312 /* If we omitted the move of OP1 into the accumulator (because
3313 it was already there from a previous insn), then force the
3314 generation of the move instruction now. We know that we
3315 are about to emit a move into HL via AX, and hence our
3316 optimization to remove the load of OP1 is no longer valid. */
3317 if (tmp_id
== get_max_insn_count ())
3318 force_into_acc (saved_op1
, insn
);
3320 /* We have to copy op2 to HL, but that involves the acc, which
3321 already has a live value. Emit it before those insns. */
3323 first
= next_nonnote_nondebug_insn (prev
);
3325 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3327 OP (2) = move_to_hl (2, first
);
3332 /* Like op2, but AX = A * X. */
3334 rl78_alloc_physical_registers_umul (rtx_insn
* insn
)
3336 rtx_insn
*prev
= prev_nonnote_nondebug_insn (insn
);
3341 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3342 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3343 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3347 if (recog_data
.constraints
[1][0] == '%'
3348 && is_virtual_register (OP (1))
3349 && !is_virtual_register (OP (2))
3350 && !CONSTANT_P (OP (2)))
3357 OP (0) = move_from_acc (0, insn
);
3359 tmp_id
= get_max_insn_count ();
3362 if (rtx_equal_p (OP (1), OP (2)))
3364 gcc_assert (GET_MODE (OP (2)) == QImode
);
3365 /* The MULU instruction does not support duplicate arguments
3366 but we know that if we copy OP (2) to X it will do so via
3367 A and thus OP (1) will already be loaded into A. */
3368 OP (2) = move_to_x (2, insn
);
3372 OP (1) = move_to_acc (1, insn
);
3376 /* If we omitted the move of OP1 into the accumulator (because
3377 it was already there from a previous insn), then force the
3378 generation of the move instruction now. We know that we
3379 are about to emit a move into HL (or DE) via AX, and hence
3380 our optimization to remove the load of OP1 is no longer valid. */
3381 if (tmp_id
== get_max_insn_count ())
3382 force_into_acc (saved_op1
, insn
);
3384 /* We have to copy op2 to X, but that involves the acc, which
3385 already has a live value. Emit it before those insns. */
3388 first
= next_nonnote_nondebug_insn (prev
);
3390 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3392 OP (2) = move_to_x (2, first
);
3398 rl78_alloc_address_registers_macax (rtx_insn
* insn
)
3401 bool replace_in_op0
= false;
3402 bool replace_in_op1
= false;
3406 /* Two different MEMs are not allowed. */
3408 for (op
= 2; op
>= 0; op
--)
3410 if (MEM_P (OP (op
)))
3412 if (op
== 0 && replace_in_op0
)
3414 if (op
== 1 && replace_in_op1
)
3420 /* If we replace a MEM, make sure that we replace it for all
3421 occurrences of the same MEM in the insn. */
3422 replace_in_op0
= (op
> 0 && rtx_equal_p (OP (op
), OP (0)));
3423 replace_in_op1
= (op
> 1 && rtx_equal_p (OP (op
), OP (1)));
3425 OP (op
) = transcode_memory_rtx (OP (op
), HL
, insn
);
3428 && ((GET_CODE (XEXP (OP (op
), 0)) == REG
3429 && REGNO (XEXP (OP (op
), 0)) == SP_REG
)
3430 || (GET_CODE (XEXP (OP (op
), 0)) == PLUS
3431 && REGNO (XEXP (XEXP (OP (op
), 0), 0)) == SP_REG
)))
3433 emit_insn_before (gen_movhi (HL
, gen_rtx_REG (HImode
, SP_REG
)), insn
);
3434 OP (op
) = replace_rtx (OP (op
), gen_rtx_REG (HImode
, SP_REG
), HL
);
3442 OP (op
) = transcode_memory_rtx (OP (op
), DE
, insn
);
3445 OP (op
) = transcode_memory_rtx (OP (op
), BC
, insn
);
3456 rl78_alloc_address_registers_div (rtx_insn
* insn
)
3461 /* Scan all insns and devirtualize them. */
3463 rl78_alloc_physical_registers (void)
3465 /* During most of the compile, gcc is dealing with virtual
3466 registers. At this point, we need to assign physical registers
3467 to the vitual ones, and copy in/out as needed. */
3469 rtx_insn
*insn
, *curr
;
3470 enum attr_valloc valloc_method
;
3472 for (insn
= get_insns (); insn
; insn
= curr
)
3476 curr
= next_nonnote_nondebug_insn (insn
);
3479 && (GET_CODE (PATTERN (insn
)) == SET
3480 || GET_CODE (PATTERN (insn
)) == CALL
)
3481 && INSN_CODE (insn
) == -1)
3483 if (GET_CODE (SET_SRC (PATTERN (insn
))) == ASM_OPERANDS
)
3485 i
= recog (PATTERN (insn
), insn
, 0);
3491 INSN_CODE (insn
) = i
;
3495 cfun
->machine
->virt_insns_ok
= 0;
3496 cfun
->machine
->real_insns_ok
= 1;
3498 clear_content_memory ();
3500 for (insn
= get_insns (); insn
; insn
= curr
)
3504 curr
= insn
? next_nonnote_nondebug_insn (insn
) : NULL
;
3509 clear_content_memory ();
3515 fprintf (dump_file
, "Converting insn %d\n", INSN_UID (insn
));
3517 pattern
= PATTERN (insn
);
3518 if (GET_CODE (pattern
) == PARALLEL
)
3519 pattern
= XVECEXP (pattern
, 0, 0);
3520 if (JUMP_P (insn
) || CALL_P (insn
) || GET_CODE (pattern
) == CALL
)
3521 clear_content_memory ();
3522 if (GET_CODE (pattern
) != SET
3523 && GET_CODE (pattern
) != CALL
)
3525 if (GET_CODE (pattern
) == SET
3526 && GET_CODE (SET_SRC (pattern
)) == ASM_OPERANDS
)
3529 valloc_method
= get_attr_valloc (insn
);
3531 PATTERN (insn
) = copy_rtx_if_shared (PATTERN (insn
));
3533 if (valloc_method
== VALLOC_MACAX
)
3535 record_content (AX
, NULL_RTX
);
3536 record_content (BC
, NULL_RTX
);
3537 record_content (DE
, NULL_RTX
);
3539 else if (valloc_method
== VALLOC_DIVHI
)
3541 record_content (AX
, NULL_RTX
);
3542 record_content (BC
, NULL_RTX
);
3544 else if (valloc_method
== VALLOC_DIVSI
)
3546 record_content (AX
, NULL_RTX
);
3547 record_content (BC
, NULL_RTX
);
3548 record_content (DE
, NULL_RTX
);
3549 record_content (HL
, NULL_RTX
);
3552 if (insn_ok_now (insn
))
3555 INSN_CODE (insn
) = -1;
3557 if (RTX_FRAME_RELATED_P (insn
))
3558 virt_insn_was_frame
= 1;
3560 virt_insn_was_frame
= 0;
3562 switch (valloc_method
)
3565 rl78_alloc_physical_registers_op1 (insn
);
3568 rl78_alloc_physical_registers_op2 (insn
);
3571 rl78_alloc_physical_registers_ro1 (insn
);
3574 rl78_alloc_physical_registers_cmp (insn
);
3577 rl78_alloc_physical_registers_umul (insn
);
3578 record_content (AX
, NULL_RTX
);
3581 /* Macro that clobbers AX. */
3582 rl78_alloc_address_registers_macax (insn
);
3583 record_content (AX
, NULL_RTX
);
3584 record_content (BC
, NULL_RTX
);
3585 record_content (DE
, NULL_RTX
);
3588 rl78_alloc_address_registers_div (insn
);
3589 record_content (AX
, NULL_RTX
);
3590 record_content (BC
, NULL_RTX
);
3591 record_content (DE
, NULL_RTX
);
3592 record_content (HL
, NULL_RTX
);
3595 rl78_alloc_address_registers_div (insn
);
3596 record_content (AX
, NULL_RTX
);
3597 record_content (BC
, NULL_RTX
);
3603 if (JUMP_P (insn
) || CALL_P (insn
) || GET_CODE (pattern
) == CALL
)
3604 clear_content_memory ();
3606 process_postponed_content_update ();
3610 fprintf (stderr
, "\033[0m");
3614 /* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3615 This function scans for uses of registers; the last use (i.e. first
3616 encounter when scanning backwards) triggers a REG_DEAD note if the
3617 reg was previously in DEAD[]. */
3619 rl78_note_reg_uses (char *dead
, rtx s
, rtx insn
)
3628 code
= GET_CODE (s
);
3632 /* Compare registers by number. */
3637 fprintf (dump_file
, "note use reg %d size %d on insn %d\n",
3638 r
, GET_MODE_SIZE (GET_MODE (s
)), INSN_UID (insn
));
3639 print_rtl_single (dump_file
, s
);
3642 add_reg_note (insn
, REG_DEAD
, gen_rtx_REG (GET_MODE (s
), r
));
3643 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (s
)); i
++)
3647 /* These codes have no constituent expressions
3658 /* These are kept unique for a given value. */
3665 fmt
= GET_RTX_FORMAT (code
);
3667 for (i
= GET_RTX_LENGTH (code
) - 1; i
>= 0; i
--)
3672 for (j
= XVECLEN (s
, i
) - 1; j
>= 0; j
--)
3673 rl78_note_reg_uses (dead
, XVECEXP (s
, i
, j
), insn
);
3675 else if (fmt
[i
] == 'e')
3676 rl78_note_reg_uses (dead
, XEXP (s
, i
), insn
);
3680 /* Like the previous function, but scan for SETs instead. */
3682 rl78_note_reg_set (char *dead
, rtx d
, rtx insn
)
3686 if (GET_CODE (d
) == MEM
)
3687 rl78_note_reg_uses (dead
, XEXP (d
, 0), insn
);
3689 if (GET_CODE (d
) != REG
)
3694 add_reg_note (insn
, REG_UNUSED
, gen_rtx_REG (GET_MODE (d
), r
));
3696 fprintf (dump_file
, "note set reg %d size %d\n", r
, GET_MODE_SIZE (GET_MODE (d
)));
3697 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (d
)); i
++)
3701 /* This is a rather crude register death pass. Death status is reset
3702 at every jump or call insn. */
3704 rl78_calculate_death_notes (void)
3706 char dead
[FIRST_PSEUDO_REGISTER
];
3710 memset (dead
, 0, sizeof (dead
));
3712 for (insn
= get_last_insn ();
3714 insn
= prev_nonnote_nondebug_insn (insn
))
3718 fprintf (dump_file
, "\n--------------------------------------------------");
3719 fprintf (dump_file
, "\nDead:");
3720 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3722 fprintf (dump_file
, " %s", reg_names
[i
]);
3723 fprintf (dump_file
, "\n");
3724 print_rtl_single (dump_file
, insn
);
3727 switch (GET_CODE (insn
))
3731 if (GET_CODE (p
) == PARALLEL
)
3733 rtx q
= XVECEXP (p
, 0 ,1);
3735 /* This happens with the DIV patterns. */
3736 if (GET_CODE (q
) == SET
)
3740 rl78_note_reg_set (dead
, d
, insn
);
3741 rl78_note_reg_uses (dead
, s
, insn
);
3744 p
= XVECEXP (p
, 0, 0);
3747 switch (GET_CODE (p
))
3752 rl78_note_reg_set (dead
, d
, insn
);
3753 rl78_note_reg_uses (dead
, s
, insn
);
3757 rl78_note_reg_uses (dead
, p
, insn
);
3766 if (INSN_CODE (insn
) == CODE_FOR_rl78_return
)
3768 memset (dead
, 1, sizeof (dead
));
3769 /* We expect a USE just prior to this, which will mark
3770 the actual return registers. The USE will have a
3771 death note, but we aren't going to be modifying it
3776 memset (dead
, 0, sizeof (dead
));
3783 print_rtl_single (dump_file
, insn
);
3787 /* Helper function to reset the origins in RP and the age in AGE for
3790 reset_origins (int *rp
, int *age
)
3793 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3801 set_origin (rtx pat
, rtx_insn
* insn
, int * origins
, int * age
)
3803 rtx src
= SET_SRC (pat
);
3804 rtx dest
= SET_DEST (pat
);
3805 int mb
= GET_MODE_SIZE (GET_MODE (dest
));
3808 if (GET_CODE (dest
) == REG
)
3810 int dr
= REGNO (dest
);
3812 if (GET_CODE (src
) == REG
)
3814 int sr
= REGNO (src
);
3816 int best_age
, best_reg
;
3818 /* See if the copy is not needed. */
3819 for (i
= 0; i
< mb
; i
++)
3820 if (origins
[dr
+ i
] != origins
[sr
+ i
])
3826 fprintf (dump_file
, "deleting because dest already has correct value\n");
3831 if (dr
< 8 || sr
>= 8)
3838 /* See if the copy can be made from another
3839 bank 0 register instead, instead of the
3840 virtual src register. */
3841 for (ar
= 0; ar
< 8; ar
+= mb
)
3845 for (i
= 0; i
< mb
; i
++)
3846 if (origins
[ar
+ i
] != origins
[sr
+ i
])
3849 /* The chip has some reg-reg move limitations. */
3850 if (mb
== 1 && dr
> 3)
3855 if (best_age
== -1 || best_age
> age
[sr
+ i
])
3857 best_age
= age
[sr
+ i
];
3865 /* FIXME: copy debug info too. */
3866 SET_SRC (pat
) = gen_rtx_REG (GET_MODE (src
), best_reg
);
3871 for (i
= 0; i
< mb
; i
++)
3873 origins
[dr
+ i
] = origins
[sr
+ i
];
3874 age
[dr
+ i
] = age
[sr
+ i
] + 1;
3879 /* The destination is computed, its origin is itself. */
3881 fprintf (dump_file
, "resetting origin of r%d for %d byte%s\n",
3882 dr
, mb
, mb
== 1 ? "" : "s");
3884 for (i
= 0; i
< mb
; i
++)
3886 origins
[dr
+ i
] = dr
+ i
;
3891 /* Any registers marked with that reg as an origin are reset. */
3892 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3893 if (origins
[i
] >= dr
&& origins
[i
] < dr
+ mb
)
3900 /* Special case - our MUL patterns uses AX and sometimes BC. */
3901 if (get_attr_valloc (insn
) == VALLOC_MACAX
)
3904 fprintf (dump_file
, "Resetting origin of AX/BC for MUL pattern.\n");
3906 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3907 if (i
<= 3 || origins
[i
] <= 3)
3913 else if (get_attr_valloc (insn
) == VALLOC_DIVHI
)
3916 fprintf (dump_file
, "Resetting origin of AX/DE for DIVHI pattern.\n");
3918 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3923 || origins
[i
] == A_REG
3924 || origins
[i
] == X_REG
3925 || origins
[i
] == D_REG
3926 || origins
[i
] == E_REG
)
3932 else if (get_attr_valloc (insn
) == VALLOC_DIVSI
)
3935 fprintf (dump_file
, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n");
3937 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3938 if (i
<= 7 || origins
[i
] <= 7)
3945 if (GET_CODE (src
) == ASHIFT
3946 || GET_CODE (src
) == ASHIFTRT
3947 || GET_CODE (src
) == LSHIFTRT
)
3949 rtx count
= XEXP (src
, 1);
3951 if (GET_CODE (count
) == REG
)
3953 /* Special case - our pattern clobbers the count register. */
3954 int r
= REGNO (count
);
3957 fprintf (dump_file
, "Resetting origin of r%d for shift.\n", r
);
3959 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3960 if (i
== r
|| origins
[i
] == r
)
3969 /* The idea behind this optimization is to look for cases where we
3970 move data from A to B to C, and instead move from A to B, and A to
3971 C. If B is a virtual register or memory, this is a big win on its
3972 own. If B turns out to be unneeded after this, it's a bigger win.
3973 For each register, we try to determine where it's value originally
3974 came from, if it's propogated purely through moves (and not
3975 computes). The ORIGINS[] array has the regno for the "origin" of
3976 the value in the [regno] it's indexed by. */
3978 rl78_propogate_register_origins (void)
3980 int origins
[FIRST_PSEUDO_REGISTER
];
3981 int age
[FIRST_PSEUDO_REGISTER
];
3983 rtx_insn
*insn
, *ninsn
= NULL
;
3986 reset_origins (origins
, age
);
3988 for (insn
= get_insns (); insn
; insn
= ninsn
)
3990 ninsn
= next_nonnote_nondebug_insn (insn
);
3994 fprintf (dump_file
, "\n");
3995 fprintf (dump_file
, "Origins:");
3996 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3997 if (origins
[i
] != i
)
3998 fprintf (dump_file
, " r%d=r%d", i
, origins
[i
]);
3999 fprintf (dump_file
, "\n");
4000 print_rtl_single (dump_file
, insn
);
4003 switch (GET_CODE (insn
))
4009 reset_origins (origins
, age
);
4016 pat
= PATTERN (insn
);
4018 if (GET_CODE (pat
) == PARALLEL
)
4020 rtx clobber
= XVECEXP (pat
, 0, 1);
4021 pat
= XVECEXP (pat
, 0, 0);
4022 if (GET_CODE (clobber
) == CLOBBER
4023 && GET_CODE (XEXP (clobber
, 0)) == REG
)
4025 int cr
= REGNO (XEXP (clobber
, 0));
4026 int mb
= GET_MODE_SIZE (GET_MODE (XEXP (clobber
, 0)));
4028 fprintf (dump_file
, "reset origins of %d regs at %d\n", mb
, cr
);
4029 for (i
= 0; i
< mb
; i
++)
4031 origins
[cr
+ i
] = cr
+ i
;
4035 /* This happens with the DIV patterns. */
4036 else if (GET_CODE (clobber
) == SET
)
4038 set_origin (clobber
, insn
, origins
, age
);
4044 if (GET_CODE (pat
) == SET
)
4046 set_origin (pat
, insn
, origins
, age
);
4048 else if (GET_CODE (pat
) == CLOBBER
4049 && GET_CODE (XEXP (pat
, 0)) == REG
)
4051 if (REG_P (XEXP (pat
, 0)))
4053 unsigned int reg
= REGNO (XEXP (pat
, 0));
4063 /* Remove any SETs where the destination is unneeded. */
4065 rl78_remove_unused_sets (void)
4067 rtx_insn
*insn
, *ninsn
= NULL
;
4070 for (insn
= get_insns (); insn
; insn
= ninsn
)
4072 ninsn
= next_nonnote_nondebug_insn (insn
);
4074 rtx set
= single_set (insn
);
4078 dest
= SET_DEST (set
);
4080 if (GET_CODE (dest
) != REG
|| REGNO (dest
) > 23)
4083 if (find_regno_note (insn
, REG_UNUSED
, REGNO (dest
)))
4086 fprintf (dump_file
, "deleting because the set register is never used.\n");
4092 /* This is the top of the devritualization pass. */
4096 /* split2 only happens when optimizing, but we need all movSIs to be
4101 rl78_alloc_physical_registers ();
4105 fprintf (dump_file
, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
4106 print_rtl_with_bb (dump_file
, get_insns (), 0);
4109 rl78_propogate_register_origins ();
4110 rl78_calculate_death_notes ();
4114 fprintf (dump_file
, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
4115 print_rtl_with_bb (dump_file
, get_insns (), 0);
4116 fprintf (dump_file
, "\n======================================================================\n");
4119 rl78_remove_unused_sets ();
4121 /* The code after devirtualizing has changed so much that at this point
4122 we might as well just rescan everything. Note that
4123 df_rescan_all_insns is not going to help here because it does not
4124 touch the artificial uses and defs. */
4125 df_finish_pass (true);
4127 df_live_add_problem ();
4128 df_scan_alloc (NULL
);
4135 #undef TARGET_RETURN_IN_MEMORY
4136 #define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
4139 rl78_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
4141 const HOST_WIDE_INT size
= int_size_in_bytes (type
);
4142 return (size
== -1 || size
> 8);
4146 #undef TARGET_RTX_COSTS
4147 #define TARGET_RTX_COSTS rl78_rtx_costs
4150 rl78_rtx_costs (rtx x
,
4152 int outer_code ATTRIBUTE_UNUSED
,
4153 int opno ATTRIBUTE_UNUSED
,
4155 bool speed ATTRIBUTE_UNUSED
)
4157 int code
= GET_CODE (x
);
4159 if (code
== IF_THEN_ELSE
)
4161 *total
= COSTS_N_INSNS (10);
4167 if (code
== MULT
&& ! speed
)
4169 * total
= COSTS_N_INSNS (8);
4181 /* If we are compiling for space then we do not want to use the
4182 inline SImode multiplication patterns or shift sequences.
4183 The cost is not set to 1 or 5 however as we have to allow for
4184 the possibility that we might be converting a leaf function
4185 into a non-leaf function. (There is no way to tell here).
4186 A value of 13 seems to be a reasonable compromise for the
4188 * total
= COSTS_N_INSNS (13);
4189 else if (RL78_MUL_G14
)
4190 *total
= COSTS_N_INSNS (14);
4191 else if (RL78_MUL_G13
)
4192 *total
= COSTS_N_INSNS (29);
4194 *total
= COSTS_N_INSNS (500);
4198 *total
= COSTS_N_INSNS (8);
4204 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
4206 switch (INTVAL (XEXP (x
, 1)))
4208 case 0: *total
= COSTS_N_INSNS (0); break;
4209 case 1: *total
= COSTS_N_INSNS (6); break;
4210 case 2: case 3: case 4: case 5: case 6: case 7:
4211 *total
= COSTS_N_INSNS (10); break;
4212 case 8: *total
= COSTS_N_INSNS (6); break;
4213 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
4214 *total
= COSTS_N_INSNS (10); break;
4215 case 16: *total
= COSTS_N_INSNS (3); break;
4216 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
4217 *total
= COSTS_N_INSNS (4); break;
4218 case 24: *total
= COSTS_N_INSNS (4); break;
4219 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
4220 *total
= COSTS_N_INSNS (5); break;
4224 *total
= COSTS_N_INSNS (10+4*16);
4235 static GTY(()) section
* saddr_section
;
4236 static GTY(()) section
* frodata_section
;
4239 rl78_saddr_p (rtx x
)
4245 if (GET_CODE (x
) == PLUS
)
4247 if (GET_CODE (x
) != SYMBOL_REF
)
4251 if (memcmp (c
, "@s.", 3) == 0)
4262 if (GET_CODE (x
) != CONST_INT
)
4265 if ((INTVAL (x
) & 0xFF00) != 0xFF00)
4271 #undef TARGET_STRIP_NAME_ENCODING
4272 #define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding
4275 rl78_strip_name_encoding (const char * sym
)
4281 else if (*sym
== '@' && sym
[2] == '.')
4288 /* Like rl78_strip_name_encoding, but does not strip leading asterisks. This
4289 is important if the stripped name is going to be passed to assemble_name()
4290 as that handles asterisk prefixed names in a special manner. */
4293 rl78_strip_nonasm_name_encoding (const char * sym
)
4297 if (*sym
== '@' && sym
[2] == '.')
4306 rl78_attrlist_to_encoding (tree list
, tree decl ATTRIBUTE_UNUSED
)
4310 if (is_attribute_p ("saddr", TREE_PURPOSE (list
)))
4312 list
= TREE_CHAIN (list
);
4318 #define RL78_ATTRIBUTES(decl) \
4319 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
4320 : DECL_ATTRIBUTES (decl) \
4321 ? (DECL_ATTRIBUTES (decl)) \
4322 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
4324 #undef TARGET_ENCODE_SECTION_INFO
4325 #define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info
4328 rl78_encode_section_info (tree decl
, rtx rtl
, int first
)
4331 const char * oldname
;
4336 tree rl78_attributes
;
4341 rtlname
= XEXP (rtl
, 0);
4343 if (GET_CODE (rtlname
) == SYMBOL_REF
)
4344 oldname
= XSTR (rtlname
, 0);
4345 else if (GET_CODE (rtlname
) == MEM
4346 && GET_CODE (XEXP (rtlname
, 0)) == SYMBOL_REF
)
4347 oldname
= XSTR (XEXP (rtlname
, 0), 0);
4351 type
= TREE_TYPE (decl
);
4352 if (type
== error_mark_node
)
4354 if (! DECL_P (decl
))
4356 rl78_attributes
= RL78_ATTRIBUTES (decl
);
4358 encoding
= rl78_attrlist_to_encoding (rl78_attributes
, decl
);
4362 newname
= (char *) alloca (strlen (oldname
) + 4);
4363 sprintf (newname
, "@%c.%s", encoding
, oldname
);
4364 idp
= get_identifier (newname
);
4366 gen_rtx_SYMBOL_REF (Pmode
, IDENTIFIER_POINTER (idp
));
4367 SYMBOL_REF_WEAK (XEXP (rtl
, 0)) = DECL_WEAK (decl
);
4368 SET_SYMBOL_REF_DECL (XEXP (rtl
, 0), decl
);
4372 #undef TARGET_ASM_INIT_SECTIONS
4373 #define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections
4376 rl78_asm_init_sections (void)
4379 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
4380 "\t.section .saddr,\"aw\",@progbits");
4382 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
4383 "\t.section .frodata,\"aw\",@progbits");
4386 #undef TARGET_ASM_SELECT_SECTION
4387 #define TARGET_ASM_SELECT_SECTION rl78_select_section
4390 rl78_select_section (tree decl
,
4392 unsigned HOST_WIDE_INT align
)
4396 switch (TREE_CODE (decl
))
4399 if (!TREE_READONLY (decl
)
4400 || TREE_SIDE_EFFECTS (decl
)
4401 || !DECL_INITIAL (decl
)
4402 || (DECL_INITIAL (decl
) != error_mark_node
4403 && !TREE_CONSTANT (DECL_INITIAL (decl
))))
4407 if (! TREE_CONSTANT (decl
))
4415 if (TREE_CODE (decl
) == VAR_DECL
)
4417 const char *name
= XSTR (XEXP (DECL_RTL (decl
), 0), 0);
4419 if (name
[0] == '@' && name
[2] == '.')
4423 return saddr_section
;
4426 if (TYPE_ADDR_SPACE (TREE_TYPE (decl
)) == ADDR_SPACE_FAR
4429 return frodata_section
;
4434 return TARGET_ES0
? frodata_section
: readonly_data_section
;
4436 switch (categorize_decl_for_section (decl
, reloc
))
4438 case SECCAT_TEXT
: return text_section
;
4439 case SECCAT_DATA
: return data_section
;
4440 case SECCAT_BSS
: return bss_section
;
4441 case SECCAT_RODATA
: return TARGET_ES0
? frodata_section
: readonly_data_section
;
4443 return default_select_section (decl
, reloc
, align
);
4448 rl78_output_labelref (FILE *file
, const char *str
)
4452 str2
= targetm
.strip_name_encoding (str
);
4454 fputs (user_label_prefix
, file
);
4459 rl78_output_aligned_common (FILE *stream
,
4460 tree decl ATTRIBUTE_UNUSED
,
4462 int size
, int align
, int global
)
4464 /* We intentionally don't use rl78_section_tag() here. */
4465 if (name
[0] == '@' && name
[2] == '.')
4467 const char *sec
= 0;
4471 switch_to_section (saddr_section
);
4480 while (align
> BITS_PER_UNIT
)
4485 name2
= targetm
.strip_name_encoding (name
);
4487 fprintf (stream
, "\t.global\t_%s\n", name2
);
4488 fprintf (stream
, "\t.p2align %d\n", p2align
);
4489 fprintf (stream
, "\t.type\t_%s,@object\n", name2
);
4490 fprintf (stream
, "\t.size\t_%s,%d\n", name2
, size
);
4491 fprintf (stream
, "_%s:\n\t.zero\t%d\n", name2
, size
);
4498 fprintf (stream
, "\t.local\t");
4499 assemble_name (stream
, name
);
4500 fprintf (stream
, "\n");
4502 fprintf (stream
, "\t.comm\t");
4503 assemble_name (stream
, name
);
4504 fprintf (stream
, ",%u,%u\n", size
, align
/ BITS_PER_UNIT
);
4507 #undef TARGET_INSERT_ATTRIBUTES
4508 #define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes
4511 rl78_insert_attributes (tree decl
, tree
*attributes ATTRIBUTE_UNUSED
)
4514 && TREE_CODE (decl
) == VAR_DECL
4515 && TREE_READONLY (decl
)
4516 && TREE_ADDRESSABLE (decl
)
4517 && TYPE_ADDR_SPACE (TREE_TYPE (decl
)) == ADDR_SPACE_GENERIC
)
4519 tree type
= TREE_TYPE (decl
);
4520 tree attr
= TYPE_ATTRIBUTES (type
);
4521 int q
= TYPE_QUALS_NO_ADDR_SPACE (type
) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR
);
4523 TREE_TYPE (decl
) = build_type_attribute_qual_variant (type
, attr
, q
);
4527 #undef TARGET_ASM_INTEGER
4528 #define TARGET_ASM_INTEGER rl78_asm_out_integer
4531 rl78_asm_out_integer (rtx x
, unsigned int size
, int aligned_p
)
4533 if (default_assemble_integer (x
, size
, aligned_p
))
4538 assemble_integer_with_op (".long\t", x
);
4545 #undef TARGET_UNWIND_WORD_MODE
4546 #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
4549 rl78_unwind_word_mode (void)
4554 #ifndef USE_COLLECT2
4555 #undef TARGET_ASM_CONSTRUCTOR
4556 #define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor
4557 #undef TARGET_ASM_DESTRUCTOR
4558 #define TARGET_ASM_DESTRUCTOR rl78_asm_destructor
4561 rl78_asm_ctor_dtor (rtx symbol
, int priority
, bool is_ctor
)
4565 if (priority
!= DEFAULT_INIT_PRIORITY
)
4567 /* This section of the function is based upon code copied
4568 from: gcc/varasm.c:get_cdtor_priority_section(). */
4571 sprintf (buf
, "%s.%.5u", is_ctor
? ".ctors" : ".dtors",
4572 MAX_INIT_PRIORITY
- priority
);
4573 sec
= get_section (buf
, 0, NULL
);
4576 sec
= is_ctor
? ctors_section
: dtors_section
;
4578 assemble_addr_to_section (symbol
, sec
);
4582 rl78_asm_constructor (rtx symbol
, int priority
)
4584 rl78_asm_ctor_dtor (symbol
, priority
, true);
4588 rl78_asm_destructor (rtx symbol
, int priority
)
4590 rl78_asm_ctor_dtor (symbol
, priority
, false);
4592 #endif /* ! USE_COLLECT2 */
4594 /* Scan backwards through the insn chain looking to see if the flags
4595 have been set for a comparison of OP against OPERAND. Start with
4596 the insn *before* the current insn. */
4599 rl78_flags_already_set (rtx op
, rtx operand
)
4601 /* We only track the Z flag. */
4602 if (GET_CODE (op
) != EQ
&& GET_CODE (op
) != NE
)
4605 /* This should not happen, but let's be paranoid. */
4606 if (current_output_insn
== NULL_RTX
)
4612 for (insn
= prev_nonnote_nondebug_insn (current_output_insn
);
4614 insn
= prev_nonnote_nondebug_insn (insn
))
4619 if (! INSN_P (insn
))
4622 /* Make sure that the insn can be recognized. */
4623 if (recog_memoized (insn
) == -1)
4626 enum attr_update_Z updated
= get_attr_update_Z (insn
);
4628 rtx set
= single_set (insn
);
4629 bool must_break
= (set
!= NULL_RTX
&& rtx_equal_p (operand
, SET_DEST (set
)));
4635 case UPDATE_Z_CLOBBER
:
4638 case UPDATE_Z_UPDATE_Z
:
4650 /* We have to re-recognize the current insn as the call(s) to
4651 get_attr_update_Z() above will have overwritten the recog_data cache. */
4652 recog_memoized (current_output_insn
);
4653 cleanup_subreg_operands (current_output_insn
);
4654 constrain_operands_cached (current_output_insn
, 1);
4660 rl78_addsi3_internal (rtx
* operands
, unsigned int alternative
)
4662 /* If we are adding in a constant symbolic address when -mes0
4663 is active then we know that the address must be <64K and
4664 that it is invalid to access anything above 64K relative to
4665 this address. So we can skip adding in the high bytes. */
4667 && GET_CODE (operands
[2]) == SYMBOL_REF
4668 && TREE_CODE (SYMBOL_REF_DECL (operands
[2])) == VAR_DECL
4669 && TREE_READONLY (SYMBOL_REF_DECL (operands
[2]))
4670 && ! TREE_SIDE_EFFECTS (SYMBOL_REF_DECL (operands
[2])))
4671 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax";
4673 switch (alternative
)
4677 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax\n\tmovw ax, %H1\n\tsknc\n\tincw ax\n\taddw ax, %H2\n\tmovw %H0, ax";
4679 return "movw ax, %h1\n\taddw ax,%h2\n\tmovw bc, ax\n\tmovw ax, %H1\n\tsknc\n\tincw ax\n\taddw ax, %H2\n\tmovw %H0, ax\n\tmovw ax, bc\n\tmovw %h0, ax";
4686 #undef TARGET_PREFERRED_RELOAD_CLASS
4687 #define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
4690 rl78_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, reg_class_t rclass
)
4692 if (rclass
== NO_REGS
)
4699 struct gcc_target targetm
= TARGET_INITIALIZER
;
4701 #include "gt-rl78.h"