1 /* Subroutines used for code generation on Renesas RL78 processors.
2 Copyright (C) 2011-2015 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 "fold-const.h"
32 #include "stor-layout.h"
35 #include "insn-config.h"
36 #include "conditions.h"
38 #include "insn-attr.h"
46 #include "insn-codes.h"
50 #include "diagnostic-core.h"
57 #include "cfgcleanup.h"
61 #include "langhooks.h"
62 #include "rl78-protos.h"
64 #include "tree-pass.h"
66 #include "tm-constrs.h" /* for satisfies_constraint_*(). */
67 #include "insn-flags.h" /* for gen_*(). */
69 #include "stringpool.h"
71 /* This file should be included last. */
72 #include "target-def.h"
74 static inline bool is_interrupt_func (const_tree decl
);
75 static inline bool is_brk_interrupt_func (const_tree decl
);
76 static void rl78_reorg (void);
77 static const char *rl78_strip_name_encoding (const char *);
78 static const char *rl78_strip_nonasm_name_encoding (const char *);
79 static section
* rl78_select_section (tree
, int, unsigned HOST_WIDE_INT
);
82 /* Debugging statements are tagged with DEBUG0 only so that they can
83 be easily enabled individually, by replacing the '0' with '1' as
88 /* REGISTER_NAMES has the names for individual 8-bit registers, but
89 these have the names we need to use when referring to 16-bit
91 static const char * const word_regnames
[] =
93 "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
94 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
95 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
96 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
97 "sp", "ap", "psw", "es", "cs"
100 struct GTY(()) machine_function
102 /* If set, the rest of the fields have been computed. */
104 /* Which register pairs need to be pushed in the prologue. */
105 int need_to_push
[FIRST_PSEUDO_REGISTER
/ 2];
107 /* These fields describe the frame layout... */
109 /* 4 bytes for saved PC */
112 int framesize_locals
;
113 int framesize_outgoing
;
117 /* If set, recog is allowed to match against the "real" patterns. */
119 /* If set, recog is allowed to match against the "virtual" patterns. */
121 /* Set if the current function needs to clean up any trampolines. */
122 int trampolines_used
;
123 /* True if the ES register is used and hence
124 needs to be saved inside interrupt handlers. */
128 /* This is our init_machine_status, as set in
129 rl78_option_override. */
130 static struct machine_function
*
131 rl78_init_machine_status (void)
133 struct machine_function
*m
;
135 m
= ggc_cleared_alloc
<machine_function
> ();
136 m
->virt_insns_ok
= 1;
141 /* This pass converts virtual instructions using virtual registers, to
142 real instructions using real registers. Rather than run it as
143 reorg, we reschedule it before vartrack to help with debugging. */
146 const pass_data pass_data_rl78_devirt
=
150 OPTGROUP_NONE
, /* optinfo_flags */
151 TV_MACH_DEP
, /* tv_id */
152 0, /* properties_required */
153 0, /* properties_provided */
154 0, /* properties_destroyed */
155 0, /* todo_flags_start */
156 0, /* todo_flags_finish */
159 class pass_rl78_devirt
: public rtl_opt_pass
162 pass_rl78_devirt (gcc::context
*ctxt
)
163 : rtl_opt_pass (pass_data_rl78_devirt
, ctxt
)
167 /* opt_pass methods: */
168 virtual unsigned int execute (function
*)
177 make_pass_rl78_devirt (gcc::context
*ctxt
)
179 return new pass_rl78_devirt (ctxt
);
182 /* Redundant move elimination pass. Must be run after the basic block
183 reordering pass for the best effect. */
186 move_elim_pass (void)
188 rtx_insn
*insn
, *ninsn
;
191 for (insn
= get_insns (); insn
; insn
= ninsn
)
195 ninsn
= next_nonnote_nondebug_insn (insn
);
197 if ((set
= single_set (insn
)) == NULL_RTX
)
203 /* If we have two SET insns in a row (without anything
204 between them) and the source of the second one is the
205 destination of the first one, and vice versa, then we
206 can eliminate the second SET. */
208 && rtx_equal_p (SET_DEST (prev
), SET_SRC (set
))
209 && rtx_equal_p (SET_DEST (set
), SET_SRC (prev
))
210 /* ... and none of the operands are volatile. */
211 && ! volatile_refs_p (SET_SRC (prev
))
212 && ! volatile_refs_p (SET_DEST (prev
))
213 && ! volatile_refs_p (SET_SRC (set
))
214 && ! volatile_refs_p (SET_DEST (set
)))
217 fprintf (dump_file
, " Delete insn %d because it is redundant\n",
228 print_rtl_with_bb (dump_file
, get_insns (), 0);
235 const pass_data pass_data_rl78_move_elim
=
238 "move_elim", /* name */
239 OPTGROUP_NONE
, /* optinfo_flags */
240 TV_MACH_DEP
, /* tv_id */
241 0, /* properties_required */
242 0, /* properties_provided */
243 0, /* properties_destroyed */
244 0, /* todo_flags_start */
245 0, /* todo_flags_finish */
248 class pass_rl78_move_elim
: public rtl_opt_pass
251 pass_rl78_move_elim (gcc::context
*ctxt
)
252 : rtl_opt_pass (pass_data_rl78_move_elim
, ctxt
)
256 /* opt_pass methods: */
257 virtual unsigned int execute (function
*) { return move_elim_pass (); }
262 make_pass_rl78_move_elim (gcc::context
*ctxt
)
264 return new pass_rl78_move_elim (ctxt
);
267 #undef TARGET_ASM_FILE_START
268 #define TARGET_ASM_FILE_START rl78_asm_file_start
271 rl78_asm_file_start (void)
277 /* The memory used is 0xffec8 to 0xffedf; real registers are in
278 0xffee0 to 0xffee7. */
279 for (i
= 8; i
< 32; i
++)
280 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", i
, 0xffec0 + i
);
284 for (i
= 0; i
< 8; i
++)
286 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 8 + i
, 0xffef0 + i
);
287 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 16 + i
, 0xffee8 + i
);
288 fprintf (asm_out_file
, "r%d\t=\t0x%x\n", 24 + i
, 0xffee0 + i
);
292 opt_pass
*rl78_devirt_pass
= make_pass_rl78_devirt (g
);
293 struct register_pass_info rl78_devirt_info
=
298 PASS_POS_INSERT_BEFORE
301 opt_pass
*rl78_move_elim_pass
= make_pass_rl78_move_elim (g
);
302 struct register_pass_info rl78_move_elim_info
=
307 PASS_POS_INSERT_AFTER
310 register_pass (& rl78_devirt_info
);
311 register_pass (& rl78_move_elim_info
);
315 rl78_output_symbol_ref (FILE * file
, rtx sym
)
317 tree type
= SYMBOL_REF_DECL (sym
);
318 const char *str
= XSTR (sym
, 0);
322 fputs (str
+ 1, file
);
326 str
= rl78_strip_nonasm_name_encoding (str
);
327 if (type
&& TREE_CODE (type
) == FUNCTION_DECL
)
329 fprintf (file
, "%%code(");
330 assemble_name (file
, str
);
334 assemble_name (file
, str
);
338 #undef TARGET_OPTION_OVERRIDE
339 #define TARGET_OPTION_OVERRIDE rl78_option_override
342 rl78_option_override (void)
344 flag_omit_frame_pointer
= 1;
345 flag_no_function_cse
= 1;
346 flag_split_wide_types
= 0;
348 init_machine_status
= rl78_init_machine_status
;
354 for (i
= 24; i
< 32; i
++)
359 && strcmp (lang_hooks
.name
, "GNU C")
360 && strcmp (lang_hooks
.name
, "GNU C11")
361 && strcmp (lang_hooks
.name
, "GNU C89")
362 && strcmp (lang_hooks
.name
, "GNU C99")
363 /* Compiling with -flto results in a language of GNU GIMPLE being used... */
364 && strcmp (lang_hooks
.name
, "GNU GIMPLE"))
365 /* Address spaces are currently only supported by C. */
366 error ("-mes0 can only be used with C");
368 switch (rl78_cpu_type
)
371 rl78_cpu_type
= CPU_G14
;
372 if (rl78_mul_type
== MUL_UNINIT
)
373 rl78_mul_type
= MUL_NONE
;
377 switch (rl78_mul_type
)
379 case MUL_UNINIT
: rl78_mul_type
= MUL_NONE
; break;
380 case MUL_NONE
: break;
381 case MUL_G13
: error ("-mmul=g13 cannot be used with -mcpu=g10"); break;
382 case MUL_G14
: error ("-mmul=g14 cannot be used with -mcpu=g10"); break;
387 switch (rl78_mul_type
)
389 case MUL_UNINIT
: rl78_mul_type
= MUL_G13
; break;
390 case MUL_NONE
: break;
392 /* The S2 core does not have mul/div instructions. */
393 case MUL_G14
: error ("-mmul=g14 cannot be used with -mcpu=g13"); break;
398 switch (rl78_mul_type
)
400 case MUL_UNINIT
: rl78_mul_type
= MUL_G14
; break;
401 case MUL_NONE
: break;
403 /* The G14 core does not have the hardware multiply peripheral used by the
404 G13 core, hence you cannot use G13 multipliy routines on G14 hardware. */
405 case MUL_G13
: error ("-mmul=g13 cannot be used with -mcpu=g14"); break;
411 /* Most registers are 8 bits. Some are 16 bits because, for example,
412 gcc doesn't like dealing with $FP as a register pair (the second
413 half of $fp is also 2 to keep reload happy wrt register pairs, but
414 no register class includes it). This table maps register numbers
416 static const int register_sizes
[] =
418 1, 1, 1, 1, 1, 1, 1, 1,
419 1, 1, 1, 1, 1, 1, 1, 1,
420 1, 1, 1, 1, 1, 1, 2, 2,
421 1, 1, 1, 1, 1, 1, 1, 1,
425 /* Predicates used in the MD patterns. This one is true when virtual
426 insns may be matched, which typically means before (or during) the
429 rl78_virt_insns_ok (void)
432 return cfun
->machine
->virt_insns_ok
;
436 /* Predicates used in the MD patterns. This one is true when real
437 insns may be matched, which typically means after (or during) the
440 rl78_real_insns_ok (void)
443 return cfun
->machine
->real_insns_ok
;
447 /* Implements HARD_REGNO_NREGS. */
449 rl78_hard_regno_nregs (int regno
, machine_mode mode
)
451 int rs
= register_sizes
[regno
];
454 return ((GET_MODE_SIZE (mode
) + rs
- 1) / rs
);
457 /* Implements HARD_REGNO_MODE_OK. */
459 rl78_hard_regno_mode_ok (int regno
, machine_mode mode
)
461 int s
= GET_MODE_SIZE (mode
);
465 /* These are not to be used by gcc. */
466 if (regno
== 23 || regno
== ES_REG
|| regno
== CS_REG
)
468 /* $fp can always be accessed as a 16-bit value. */
469 if (regno
== FP_REG
&& s
== 2)
473 /* Since a reg-reg move is really a reg-mem move, we must
474 enforce alignment. */
475 if (s
> 1 && (regno
% 2))
480 return (mode
== BImode
);
481 /* All other registers must be accessed in their natural sizes. */
482 if (s
== register_sizes
[regno
])
487 /* Simplify_gen_subreg() doesn't handle memory references the way we
488 need it to below, so we use this function for when we must get a
489 valid subreg in a "natural" state. */
491 rl78_subreg (machine_mode mode
, rtx r
, machine_mode omode
, int byte
)
493 if (GET_CODE (r
) == MEM
)
494 return adjust_address (r
, mode
, byte
);
496 return simplify_gen_subreg (mode
, r
, omode
, byte
);
499 /* Used by movsi. Split SImode moves into two HImode moves, using
500 appropriate patterns for the upper and lower halves of symbols. */
502 rl78_expand_movsi (rtx
*operands
)
504 rtx op00
, op02
, op10
, op12
;
506 op00
= rl78_subreg (HImode
, operands
[0], SImode
, 0);
507 op02
= rl78_subreg (HImode
, operands
[0], SImode
, 2);
508 if (GET_CODE (operands
[1]) == CONST
509 || GET_CODE (operands
[1]) == SYMBOL_REF
)
511 op10
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (0));
512 op10
= gen_rtx_CONST (HImode
, op10
);
513 op12
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (16));
514 op12
= gen_rtx_CONST (HImode
, op12
);
518 op10
= rl78_subreg (HImode
, operands
[1], SImode
, 0);
519 op12
= rl78_subreg (HImode
, operands
[1], SImode
, 2);
522 if (rtx_equal_p (operands
[0], operands
[1]))
524 else if (rtx_equal_p (op00
, op12
))
526 emit_move_insn (op02
, op12
);
527 emit_move_insn (op00
, op10
);
531 emit_move_insn (op00
, op10
);
532 emit_move_insn (op02
, op12
);
536 /* Generate code to move an SImode value. */
538 rl78_split_movsi (rtx
*operands
, enum machine_mode omode
)
540 rtx op00
, op02
, op10
, op12
;
542 op00
= rl78_subreg (HImode
, operands
[0], omode
, 0);
543 op02
= rl78_subreg (HImode
, operands
[0], omode
, 2);
545 if (GET_CODE (operands
[1]) == CONST
546 || GET_CODE (operands
[1]) == SYMBOL_REF
)
548 op10
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (0));
549 op10
= gen_rtx_CONST (HImode
, op10
);
550 op12
= gen_rtx_ZERO_EXTRACT (HImode
, operands
[1], GEN_INT (16), GEN_INT (16));
551 op12
= gen_rtx_CONST (HImode
, op12
);
555 op10
= rl78_subreg (HImode
, operands
[1], omode
, 0);
556 op12
= rl78_subreg (HImode
, operands
[1], omode
, 2);
559 if (rtx_equal_p (operands
[0], operands
[1]))
561 else if (rtx_equal_p (op00
, op12
))
577 /* Used by various two-operand expanders which cannot accept all
578 operands in the "far" namespace. Force some such operands into
579 registers so that each pattern has at most one far operand. */
581 rl78_force_nonfar_2 (rtx
*operands
, rtx (*gen
)(rtx
,rtx
))
586 /* FIXME: in the future, be smarter about only doing this if the
587 other operand is also far, assuming the devirtualizer can also
589 if (rl78_far_p (operands
[0]))
591 temp_reg
= operands
[0];
592 operands
[0] = gen_reg_rtx (GET_MODE (operands
[0]));
598 emit_insn (gen (operands
[0], operands
[1]));
600 emit_move_insn (temp_reg
, operands
[0]);
604 /* Likewise, but for three-operand expanders. */
606 rl78_force_nonfar_3 (rtx
*operands
, rtx (*gen
)(rtx
,rtx
,rtx
))
611 /* FIXME: Likewise. */
612 if (rl78_far_p (operands
[1]))
614 rtx temp_reg
= gen_reg_rtx (GET_MODE (operands
[1]));
615 emit_move_insn (temp_reg
, operands
[1]);
616 operands
[1] = temp_reg
;
619 if (rl78_far_p (operands
[0]))
621 temp_reg
= operands
[0];
622 operands
[0] = gen_reg_rtx (GET_MODE (operands
[0]));
628 emit_insn (gen (operands
[0], operands
[1], operands
[2]));
630 emit_move_insn (temp_reg
, operands
[0]);
634 #undef TARGET_CAN_ELIMINATE
635 #define TARGET_CAN_ELIMINATE rl78_can_eliminate
638 rl78_can_eliminate (const int from ATTRIBUTE_UNUSED
, const int to ATTRIBUTE_UNUSED
)
643 /* Returns true if the given register needs to be saved by the
646 need_to_save (unsigned int regno
)
648 if (is_interrupt_func (cfun
->decl
))
650 /* We don't know what devirt will need */
654 /* We don't need to save registers that have
655 been reserved for interrupt handlers. */
659 /* If the handler is a non-leaf function then it may call
660 non-interrupt aware routines which will happily clobber
661 any call_used registers, so we have to preserve them.
662 We do not have to worry about the frame pointer register
663 though, as that is handled below. */
664 if (!crtl
->is_leaf
&& call_used_regs
[regno
] && regno
< 22)
667 /* Otherwise we only have to save a register, call_used
668 or not, if it is used by this handler. */
669 return df_regs_ever_live_p (regno
);
672 if (regno
== FRAME_POINTER_REGNUM
673 && (frame_pointer_needed
|| df_regs_ever_live_p (regno
)))
675 if (fixed_regs
[regno
])
677 if (crtl
->calls_eh_return
)
679 if (df_regs_ever_live_p (regno
)
680 && !call_used_regs
[regno
])
685 /* We use this to wrap all emitted insns in the prologue. */
689 RTX_FRAME_RELATED_P (x
) = 1;
693 /* Compute all the frame-related fields in our machine_function
696 rl78_compute_frame_info (void)
700 cfun
->machine
->computed
= 1;
701 cfun
->machine
->framesize_regs
= 0;
702 cfun
->machine
->framesize_locals
= get_frame_size ();
703 cfun
->machine
->framesize_outgoing
= crtl
->outgoing_args_size
;
705 for (i
= 0; i
< 16; i
++)
706 if (need_to_save (i
* 2) || need_to_save (i
* 2 + 1))
708 cfun
->machine
->need_to_push
[i
] = 1;
709 cfun
->machine
->framesize_regs
+= 2;
712 cfun
->machine
->need_to_push
[i
] = 0;
714 if ((cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
) & 1)
715 cfun
->machine
->framesize_locals
++;
717 cfun
->machine
->framesize
= (cfun
->machine
->framesize_regs
718 + cfun
->machine
->framesize_locals
719 + cfun
->machine
->framesize_outgoing
);
722 /* Returns true if the provided function has the specified attribute. */
724 has_func_attr (const_tree decl
, const char * func_attr
)
726 if (decl
== NULL_TREE
)
727 decl
= current_function_decl
;
729 return lookup_attribute (func_attr
, DECL_ATTRIBUTES (decl
)) != NULL_TREE
;
732 /* Returns true if the provided function has the "interrupt" attribute. */
734 is_interrupt_func (const_tree decl
)
736 return has_func_attr (decl
, "interrupt") || has_func_attr (decl
, "brk_interrupt");
739 /* Returns true if the provided function has the "brk_interrupt" attribute. */
741 is_brk_interrupt_func (const_tree decl
)
743 return has_func_attr (decl
, "brk_interrupt");
746 /* Check "interrupt" attributes. */
748 rl78_handle_func_attribute (tree
* node
,
751 int flags ATTRIBUTE_UNUSED
,
754 gcc_assert (DECL_P (* node
));
755 gcc_assert (args
== NULL_TREE
);
757 if (TREE_CODE (* node
) != FUNCTION_DECL
)
759 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
761 * no_add_attrs
= true;
764 /* FIXME: We ought to check that the interrupt and exception
765 handler attributes have been applied to void functions. */
769 /* Check "naked" attributes. */
771 rl78_handle_naked_attribute (tree
* node
,
772 tree name ATTRIBUTE_UNUSED
,
774 int flags ATTRIBUTE_UNUSED
,
777 gcc_assert (DECL_P (* node
));
778 gcc_assert (args
== NULL_TREE
);
780 if (TREE_CODE (* node
) != FUNCTION_DECL
)
782 warning (OPT_Wattributes
, "naked attribute only applies to functions");
783 * no_add_attrs
= true;
786 /* Disable warnings about this function - eg reaching the end without
787 seeing a return statement - because the programmer is doing things
788 that gcc does not know about. */
789 TREE_NO_WARNING (* node
) = 1;
794 /* Check "saddr" attributes. */
796 rl78_handle_saddr_attribute (tree
* node
,
798 tree args ATTRIBUTE_UNUSED
,
799 int flags ATTRIBUTE_UNUSED
,
802 gcc_assert (DECL_P (* node
));
804 if (TREE_CODE (* node
) == FUNCTION_DECL
)
806 warning (OPT_Wattributes
, "%qE attribute doesn't apply to functions",
808 * no_add_attrs
= true;
814 #undef TARGET_ATTRIBUTE_TABLE
815 #define TARGET_ATTRIBUTE_TABLE rl78_attribute_table
817 /* Table of RL78-specific attributes. */
818 const struct attribute_spec rl78_attribute_table
[] =
820 /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
821 affects_type_identity. */
822 { "interrupt", 0, 0, true, false, false, rl78_handle_func_attribute
,
824 { "brk_interrupt", 0, 0, true, false, false, rl78_handle_func_attribute
,
826 { "naked", 0, 0, true, false, false, rl78_handle_naked_attribute
,
828 { "saddr", 0, 0, true, false, false, rl78_handle_saddr_attribute
,
830 { NULL
, 0, 0, false, false, false, NULL
, false }
835 /* Break down an address RTX into its component base/index/addend
836 portions and return TRUE if the address is of a valid form, else
839 characterize_address (rtx x
, rtx
*base
, rtx
*index
, rtx
*addend
)
845 if (GET_CODE (x
) == UNSPEC
846 && XINT (x
, 1) == UNS_ES_ADDR
)
847 x
= XVECEXP (x
, 0, 1);
849 if (GET_CODE (x
) == REG
)
855 /* We sometimes get these without the CONST wrapper */
856 if (GET_CODE (x
) == PLUS
857 && GET_CODE (XEXP (x
, 0)) == SYMBOL_REF
858 && GET_CODE (XEXP (x
, 1)) == CONST_INT
)
864 if (GET_CODE (x
) == PLUS
)
869 if (GET_CODE (*base
) == SUBREG
)
871 if (GET_MODE (*base
) == HImode
872 && GET_MODE (XEXP (*base
, 0)) == SImode
873 && GET_CODE (XEXP (*base
, 0)) == REG
)
875 /* This is a throw-away rtx just to tell everyone
876 else what effective register we're using. */
877 *base
= gen_rtx_REG (HImode
, REGNO (XEXP (*base
, 0)));
881 if (GET_CODE (*base
) != REG
882 && GET_CODE (x
) == REG
)
889 if (GET_CODE (*base
) != REG
)
892 if (GET_CODE (x
) == ZERO_EXTEND
893 && GET_CODE (XEXP (x
, 0)) == REG
)
895 *index
= XEXP (x
, 0);
900 switch (GET_CODE (x
))
903 if (GET_CODE (XEXP (x
, 0)) == SYMBOL_REF
904 && GET_CODE (XEXP (x
, 0)) == CONST_INT
)
915 switch (GET_CODE (XEXP (x
, 0)))
939 /* Used by the Whb constraint. Match addresses that use HL+B or HL+C
942 rl78_hl_b_c_addr_p (rtx op
)
946 if (GET_CODE (op
) != PLUS
)
950 if (GET_CODE (hl
) == ZERO_EXTEND
)
956 if (GET_CODE (hl
) != REG
)
958 if (GET_CODE (bc
) != ZERO_EXTEND
)
961 if (GET_CODE (bc
) != REG
)
963 if (REGNO (hl
) != HL_REG
)
965 if (REGNO (bc
) != B_REG
&& REGNO (bc
) != C_REG
)
971 #define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
973 /* Return the appropriate mode for a named address address. */
975 #undef TARGET_ADDR_SPACE_ADDRESS_MODE
976 #define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
978 static enum machine_mode
979 rl78_addr_space_address_mode (addr_space_t addrspace
)
983 case ADDR_SPACE_GENERIC
:
985 case ADDR_SPACE_NEAR
:
994 /* Used in various constraints and predicates to match operands in the
995 "far" address space. */
1002 fprintf (stderr
, "\033[35mrl78_far_p: "); debug_rtx (x
);
1003 fprintf (stderr
, " = %d\033[0m\n", MEM_ADDR_SPACE (x
) == ADDR_SPACE_FAR
);
1006 /* Not all far addresses are legitimate, because the devirtualizer
1007 can't handle them. */
1008 if (! rl78_as_legitimate_address (GET_MODE (x
), XEXP (x
, 0), false, ADDR_SPACE_FAR
))
1011 return GET_MODE_BITSIZE (rl78_addr_space_address_mode (MEM_ADDR_SPACE (x
))) == 32;
1014 /* Return the appropriate mode for a named address pointer. */
1015 #undef TARGET_ADDR_SPACE_POINTER_MODE
1016 #define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
1019 rl78_addr_space_pointer_mode (addr_space_t addrspace
)
1023 case ADDR_SPACE_GENERIC
:
1025 case ADDR_SPACE_NEAR
:
1027 case ADDR_SPACE_FAR
:
1034 /* Returns TRUE for valid addresses. */
1035 #undef TARGET_VALID_POINTER_MODE
1036 #define TARGET_VALID_POINTER_MODE rl78_valid_pointer_mode
1039 rl78_valid_pointer_mode (machine_mode m
)
1041 return (m
== HImode
|| m
== SImode
);
1044 #undef TARGET_LEGITIMATE_CONSTANT_P
1045 #define TARGET_LEGITIMATE_CONSTANT_P rl78_is_legitimate_constant
1048 rl78_is_legitimate_constant (machine_mode mode ATTRIBUTE_UNUSED
, rtx x ATTRIBUTE_UNUSED
)
1053 #undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
1054 #define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P rl78_as_legitimate_address
1057 rl78_as_legitimate_address (machine_mode mode ATTRIBUTE_UNUSED
, rtx x
,
1058 bool strict ATTRIBUTE_UNUSED
, addr_space_t as ATTRIBUTE_UNUSED
)
1060 rtx base
, index
, addend
;
1061 bool is_far_addr
= false;
1064 as_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (as
));
1066 if (GET_CODE (x
) == UNSPEC
1067 && XINT (x
, 1) == UNS_ES_ADDR
)
1069 x
= XVECEXP (x
, 0, 1);
1073 if (as_bits
== 16 && is_far_addr
)
1076 if (! characterize_address (x
, &base
, &index
, &addend
))
1079 /* We can't extract the high/low portions of a PLUS address
1080 involving a register during devirtualization, so make sure all
1081 such __far addresses do not have addends. This forces GCC to do
1082 the sum separately. */
1083 if (addend
&& base
&& as_bits
== 32 && GET_MODE (base
) == SImode
)
1088 int ir
= REGNO (index
);
1089 int br
= REGNO (base
);
1091 #define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
1092 OK (REG_IS (br
, HL_REG
) && REG_IS (ir
, B_REG
), "[hl+b]");
1093 OK (REG_IS (br
, HL_REG
) && REG_IS (ir
, C_REG
), "[hl+c]");
1097 if (strict
&& base
&& GET_CODE (base
) == REG
&& REGNO (base
) >= FIRST_PSEUDO_REGISTER
)
1100 if (! cfun
->machine
->virt_insns_ok
&& base
&& GET_CODE (base
) == REG
1101 && REGNO (base
) >= 8 && REGNO (base
) <= 31)
1107 /* Determine if one named address space is a subset of another. */
1108 #undef TARGET_ADDR_SPACE_SUBSET_P
1109 #define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
1112 rl78_addr_space_subset_p (addr_space_t subset
, addr_space_t superset
)
1117 subset_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (subset
));
1118 superset_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (superset
));
1120 return (subset_bits
<= superset_bits
);
1123 #undef TARGET_ADDR_SPACE_CONVERT
1124 #define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
1126 /* Convert from one address space to another. */
1128 rl78_addr_space_convert (rtx op
, tree from_type
, tree to_type
)
1130 addr_space_t from_as
= TYPE_ADDR_SPACE (TREE_TYPE (from_type
));
1131 addr_space_t to_as
= TYPE_ADDR_SPACE (TREE_TYPE (to_type
));
1136 to_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (to_as
));
1137 from_bits
= GET_MODE_BITSIZE (rl78_addr_space_address_mode (from_as
));
1139 if (to_bits
< from_bits
)
1142 /* This is unpredictable, as we're truncating off usable address
1145 warning (OPT_Waddress
, "converting far pointer to near pointer");
1146 result
= gen_reg_rtx (HImode
);
1147 if (GET_CODE (op
) == SYMBOL_REF
1148 || (GET_CODE (op
) == REG
&& REGNO (op
) >= FIRST_PSEUDO_REGISTER
))
1149 tmp
= gen_rtx_raw_SUBREG (HImode
, op
, 0);
1151 tmp
= simplify_subreg (HImode
, op
, SImode
, 0);
1152 gcc_assert (tmp
!= NULL_RTX
);
1153 emit_move_insn (result
, tmp
);
1156 else if (to_bits
> from_bits
)
1158 /* This always works. */
1159 result
= gen_reg_rtx (SImode
);
1160 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 0), op
);
1161 if (TREE_CODE (from_type
) == POINTER_TYPE
1162 && TREE_CODE (TREE_TYPE (from_type
)) == FUNCTION_TYPE
)
1163 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 2), const0_rtx
);
1165 emit_move_insn (rl78_subreg (HImode
, result
, SImode
, 2), GEN_INT (0x0f));
1173 /* Implements REGNO_MODE_CODE_OK_FOR_BASE_P. */
1175 rl78_regno_mode_code_ok_for_base_p (int regno
, machine_mode mode ATTRIBUTE_UNUSED
,
1176 addr_space_t address_space ATTRIBUTE_UNUSED
,
1177 int outer_code ATTRIBUTE_UNUSED
, int index_code
)
1179 if (regno
<= SP_REG
&& regno
>= 16)
1181 if (index_code
== REG
)
1182 return (regno
== HL_REG
);
1183 if (regno
== C_REG
|| regno
== B_REG
|| regno
== E_REG
|| regno
== L_REG
)
1188 /* Implements MODE_CODE_BASE_REG_CLASS. */
1190 rl78_mode_code_base_reg_class (machine_mode mode ATTRIBUTE_UNUSED
,
1191 addr_space_t address_space ATTRIBUTE_UNUSED
,
1192 int outer_code ATTRIBUTE_UNUSED
,
1193 int index_code ATTRIBUTE_UNUSED
)
1198 /* Typical stack layout should looks like this after the function's prologue:
1203 | | arguments saved | Increasing
1204 | | on the stack | addresses
1205 PARENT arg pointer -> | | /
1206 -------------------------- ---- -------------------
1207 CHILD |ret | return address
1212 frame pointer -> | | /
1220 | | outgoing | Decreasing
1221 | | arguments | addresses
1222 current stack pointer -> | | / |
1223 -------------------------- ---- ------------------ V
1226 /* Implements INITIAL_ELIMINATION_OFFSET. The frame layout is
1227 described in the machine_Function struct definition, above. */
1229 rl78_initial_elimination_offset (int from
, int to
)
1231 int rv
= 0; /* as if arg to arg */
1233 rl78_compute_frame_info ();
1237 case STACK_POINTER_REGNUM
:
1238 rv
+= cfun
->machine
->framesize_outgoing
;
1239 rv
+= cfun
->machine
->framesize_locals
;
1241 case FRAME_POINTER_REGNUM
:
1242 rv
+= cfun
->machine
->framesize_regs
;
1251 case FRAME_POINTER_REGNUM
:
1253 rv
-= cfun
->machine
->framesize_regs
;
1254 case ARG_POINTER_REGNUM
:
1264 rl78_is_naked_func (void)
1266 return (lookup_attribute ("naked", DECL_ATTRIBUTES (current_function_decl
)) != NULL_TREE
);
1269 /* Expand the function prologue (from the prologue pattern). */
1271 rl78_expand_prologue (void)
1274 rtx sp
= gen_rtx_REG (HImode
, STACK_POINTER_REGNUM
);
1275 rtx ax
= gen_rtx_REG (HImode
, AX_REG
);
1278 if (rl78_is_naked_func ())
1281 /* Always re-compute the frame info - the register usage may have changed. */
1282 rl78_compute_frame_info ();
1284 if (flag_stack_usage_info
)
1285 current_function_static_stack_size
= cfun
->machine
->framesize
;
1287 if (is_interrupt_func (cfun
->decl
) && !TARGET_G10
)
1288 for (i
= 0; i
< 4; i
++)
1289 if (cfun
->machine
->need_to_push
[i
])
1291 /* Select Bank 0 if we are using any registers from Bank 0. */
1292 emit_insn (gen_sel_rb (GEN_INT (0)));
1296 for (i
= 0; i
< 16; i
++)
1297 if (cfun
->machine
->need_to_push
[i
])
1305 emit_move_insn (ax
, gen_rtx_REG (HImode
, reg
));
1311 int need_bank
= i
/4;
1313 if (need_bank
!= rb
)
1315 emit_insn (gen_sel_rb (GEN_INT (need_bank
)));
1320 F (emit_insn (gen_push (gen_rtx_REG (HImode
, reg
))));
1324 emit_insn (gen_sel_rb (GEN_INT (0)));
1326 /* Save ES register inside interrupt functions if it is used. */
1327 if (is_interrupt_func (cfun
->decl
) && cfun
->machine
->uses_es
)
1329 emit_insn (gen_movqi_from_es (gen_rtx_REG (QImode
, A_REG
)));
1330 F (emit_insn (gen_push (ax
)));
1333 if (frame_pointer_needed
)
1335 F (emit_move_insn (ax
, sp
));
1336 F (emit_move_insn (gen_rtx_REG (HImode
, FRAME_POINTER_REGNUM
), ax
));
1339 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1342 /* If we need to subtract more than 254*3 then it is faster and
1343 smaller to move SP into AX and perform the subtraction there. */
1348 emit_move_insn (ax
, sp
);
1349 emit_insn (gen_subhi3 (ax
, ax
, GEN_INT (fs
)));
1350 insn
= F (emit_move_insn (sp
, ax
));
1351 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
,
1352 gen_rtx_SET (sp
, gen_rtx_PLUS (HImode
, sp
,
1359 int fs_byte
= (fs
> 254) ? 254 : fs
;
1361 F (emit_insn (gen_subhi3 (sp
, sp
, GEN_INT (fs_byte
))));
1368 /* Expand the function epilogue (from the epilogue pattern). */
1370 rl78_expand_epilogue (void)
1373 rtx sp
= gen_rtx_REG (HImode
, STACK_POINTER_REGNUM
);
1374 rtx ax
= gen_rtx_REG (HImode
, AX_REG
);
1377 if (rl78_is_naked_func ())
1380 if (frame_pointer_needed
)
1382 emit_move_insn (ax
, gen_rtx_REG (HImode
, FRAME_POINTER_REGNUM
));
1383 emit_move_insn (sp
, ax
);
1387 fs
= cfun
->machine
->framesize_locals
+ cfun
->machine
->framesize_outgoing
;
1390 emit_move_insn (ax
, sp
);
1391 emit_insn (gen_addhi3 (ax
, ax
, GEN_INT (fs
)));
1392 emit_move_insn (sp
, ax
);
1398 int fs_byte
= (fs
> 254) ? 254 : fs
;
1400 emit_insn (gen_addhi3 (sp
, sp
, GEN_INT (fs_byte
)));
1406 if (is_interrupt_func (cfun
->decl
) && cfun
->machine
->uses_es
)
1408 emit_insn (gen_pop (gen_rtx_REG (HImode
, AX_REG
)));
1409 emit_insn (gen_movqi_to_es (gen_rtx_REG (QImode
, A_REG
)));
1412 for (i
= 15; i
>= 0; i
--)
1413 if (cfun
->machine
->need_to_push
[i
])
1415 rtx dest
= gen_rtx_REG (HImode
, i
* 2);
1420 emit_insn (gen_pop (dest
));
1423 emit_insn (gen_pop (ax
));
1424 emit_move_insn (dest
, ax
);
1425 /* Generate a USE of the pop'd register so that DCE will not eliminate the move. */
1426 emit_insn (gen_use (dest
));
1431 int need_bank
= i
/ 4;
1433 if (need_bank
!= rb
)
1435 emit_insn (gen_sel_rb (GEN_INT (need_bank
)));
1438 emit_insn (gen_pop (dest
));
1443 emit_insn (gen_sel_rb (GEN_INT (0)));
1445 if (cfun
->machine
->trampolines_used
)
1446 emit_insn (gen_trampoline_uninit ());
1448 if (is_brk_interrupt_func (cfun
->decl
))
1449 emit_jump_insn (gen_brk_interrupt_return ());
1450 else if (is_interrupt_func (cfun
->decl
))
1451 emit_jump_insn (gen_interrupt_return ());
1453 emit_jump_insn (gen_rl78_return ());
1456 /* Likewise, for exception handlers. */
1458 rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED
)
1460 /* FIXME - replace this with an indirect jump with stack adjust. */
1461 emit_jump_insn (gen_rl78_return ());
1464 #undef TARGET_ASM_FUNCTION_PROLOGUE
1465 #define TARGET_ASM_FUNCTION_PROLOGUE rl78_start_function
1467 /* We don't use this to actually emit the function prologue. We use
1468 this to insert a comment in the asm file describing the
1471 rl78_start_function (FILE *file
, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED
)
1475 if (cfun
->machine
->framesize
== 0)
1477 fprintf (file
, "\t; start of function\n");
1479 if (cfun
->machine
->framesize_regs
)
1481 fprintf (file
, "\t; push %d:", cfun
->machine
->framesize_regs
);
1482 for (i
= 0; i
< 16; i
++)
1483 if (cfun
->machine
->need_to_push
[i
])
1484 fprintf (file
, " %s", word_regnames
[i
*2]);
1485 fprintf (file
, "\n");
1488 if (frame_pointer_needed
)
1489 fprintf (file
, "\t; $fp points here (r22)\n");
1491 if (cfun
->machine
->framesize_locals
)
1492 fprintf (file
, "\t; locals: %d byte%s\n", cfun
->machine
->framesize_locals
,
1493 cfun
->machine
->framesize_locals
== 1 ? "" : "s");
1495 if (cfun
->machine
->framesize_outgoing
)
1496 fprintf (file
, "\t; outgoing: %d byte%s\n", cfun
->machine
->framesize_outgoing
,
1497 cfun
->machine
->framesize_outgoing
== 1 ? "" : "s");
1499 if (cfun
->machine
->uses_es
)
1500 fprintf (file
, "\t; uses ES register\n");
1503 /* Return an RTL describing where a function return value of type RET_TYPE
1506 #undef TARGET_FUNCTION_VALUE
1507 #define TARGET_FUNCTION_VALUE rl78_function_value
1510 rl78_function_value (const_tree ret_type
,
1511 const_tree fn_decl_or_type ATTRIBUTE_UNUSED
,
1512 bool outgoing ATTRIBUTE_UNUSED
)
1514 machine_mode mode
= TYPE_MODE (ret_type
);
1516 return gen_rtx_REG (mode
, 8);
1519 #undef TARGET_PROMOTE_FUNCTION_MODE
1520 #define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
1523 rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED
,
1525 int *punsignedp ATTRIBUTE_UNUSED
,
1526 const_tree funtype ATTRIBUTE_UNUSED
, int for_return ATTRIBUTE_UNUSED
)
1531 /* Return an RTL expression describing the register holding a function
1532 parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
1533 be passed on the stack. CUM describes the previous parameters to the
1534 function and NAMED is false if the parameter is part of a variable
1535 parameter list, or the last named parameter before the start of a
1536 variable parameter list. */
1538 #undef TARGET_FUNCTION_ARG
1539 #define TARGET_FUNCTION_ARG rl78_function_arg
1542 rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED
,
1543 machine_mode mode ATTRIBUTE_UNUSED
,
1544 const_tree type ATTRIBUTE_UNUSED
,
1545 bool named ATTRIBUTE_UNUSED
)
1550 #undef TARGET_FUNCTION_ARG_ADVANCE
1551 #define TARGET_FUNCTION_ARG_ADVANCE rl78_function_arg_advance
1554 rl78_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
, const_tree type
,
1555 bool named ATTRIBUTE_UNUSED
)
1558 CUMULATIVE_ARGS
* cum
= get_cumulative_args (cum_v
);
1560 rounded_size
= ((mode
== BLKmode
)
1561 ? int_size_in_bytes (type
) : GET_MODE_SIZE (mode
));
1562 if (rounded_size
& 1)
1564 (*cum
) += rounded_size
;
1567 #undef TARGET_FUNCTION_ARG_BOUNDARY
1568 #define TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
1571 rl78_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED
,
1572 const_tree type ATTRIBUTE_UNUSED
)
1577 /* Supported modifier letters:
1579 A - address of a MEM
1580 S - SADDR form of a real register
1581 v - real register corresponding to a virtual register
1582 m - minus - negative of CONST_INT value.
1583 C - inverse of a conditional (NE vs EQ for example)
1584 C - complement of an integer
1585 z - collapsed conditional
1586 s - shift count mod 8
1587 S - shift count mod 16
1588 r - reverse shift count (8-(count mod 8))
1591 h - bottom HI of an SI
1593 q - bottom QI of an HI
1595 e - third QI of an SI (i.e. where the ES register gets values from)
1596 E - fourth QI of an SI (i.e. MSB)
1598 p - Add +0 to a zero-indexed HL based address.
1601 /* Implements the bulk of rl78_print_operand, below. We do it this
1602 way because we need to test for a constant at the top level and
1603 insert the '#', but not test for it anywhere else as we recurse
1604 down into the operand. */
1606 rl78_print_operand_1 (FILE * file
, rtx op
, int letter
)
1610 switch (GET_CODE (op
))
1614 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1617 if (rl78_far_p (op
))
1619 fprintf (file
, "es:");
1620 if (GET_CODE (XEXP (op
, 0)) == UNSPEC
)
1621 op
= gen_rtx_MEM (GET_MODE (op
), XVECEXP (XEXP (op
, 0), 0, 1));
1625 op
= adjust_address (op
, HImode
, 2);
1630 op
= adjust_address (op
, HImode
, 0);
1635 op
= adjust_address (op
, QImode
, 1);
1640 op
= adjust_address (op
, QImode
, 0);
1645 op
= adjust_address (op
, QImode
, 2);
1650 op
= adjust_address (op
, QImode
, 3);
1653 if (CONSTANT_P (XEXP (op
, 0)))
1655 if (!rl78_saddr_p (op
))
1656 fprintf (file
, "!");
1657 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1659 else if (GET_CODE (XEXP (op
, 0)) == PLUS
1660 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == SYMBOL_REF
)
1662 if (!rl78_saddr_p (op
))
1663 fprintf (file
, "!");
1664 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1666 else if (GET_CODE (XEXP (op
, 0)) == PLUS
1667 && GET_CODE (XEXP (XEXP (op
, 0), 0)) == REG
1668 && REGNO (XEXP (XEXP (op
, 0), 0)) == 2)
1670 rl78_print_operand_1 (file
, XEXP (XEXP (op
, 0), 1), 'u');
1671 fprintf (file
, "[");
1672 rl78_print_operand_1 (file
, XEXP (XEXP (op
, 0), 0), 0);
1673 if (letter
== 'p' && GET_CODE (XEXP (op
, 0)) == REG
)
1674 fprintf (file
, "+0");
1675 fprintf (file
, "]");
1680 fprintf (file
, "[");
1681 rl78_print_operand_1 (file
, op
, letter
);
1682 if (letter
== 'p' && REG_P (op
) && REGNO (op
) == 6)
1683 fprintf (file
, "+0");
1684 fprintf (file
, "]");
1691 fprintf (file
, "%s", reg_names
[REGNO (op
) | 1]);
1692 else if (letter
== 'H')
1693 fprintf (file
, "%s", reg_names
[REGNO (op
) + 2]);
1694 else if (letter
== 'q')
1695 fprintf (file
, "%s", reg_names
[REGNO (op
) & ~1]);
1696 else if (letter
== 'e')
1697 fprintf (file
, "%s", reg_names
[REGNO (op
) + 2]);
1698 else if (letter
== 'E')
1699 fprintf (file
, "%s", reg_names
[REGNO (op
) + 3]);
1700 else if (letter
== 'S')
1701 fprintf (file
, "0x%x", 0xffef8 + REGNO (op
));
1702 else if (GET_MODE (op
) == HImode
1703 && ! (REGNO (op
) & ~0xfe))
1706 fprintf (file
, "%s", word_regnames
[REGNO (op
) % 8]);
1708 fprintf (file
, "%s", word_regnames
[REGNO (op
)]);
1711 fprintf (file
, "%s", reg_names
[REGNO (op
)]);
1716 fprintf (file
, "%ld", INTVAL (op
) >> 8);
1717 else if (letter
== 'H')
1718 fprintf (file
, "%ld", INTVAL (op
) >> 16);
1719 else if (letter
== 'q')
1720 fprintf (file
, "%ld", INTVAL (op
) & 0xff);
1721 else if (letter
== 'h')
1722 fprintf (file
, "%ld", INTVAL (op
) & 0xffff);
1723 else if (letter
== 'e')
1724 fprintf (file
, "%ld", (INTVAL (op
) >> 16) & 0xff);
1725 else if (letter
== 'B')
1727 int ival
= INTVAL (op
);
1730 if (exact_log2 (ival
) >= 0)
1731 fprintf (file
, "%d", exact_log2 (ival
));
1733 fprintf (file
, "%d", exact_log2 (~ival
& 0xff));
1735 else if (letter
== 'E')
1736 fprintf (file
, "%ld", (INTVAL (op
) >> 24) & 0xff);
1737 else if (letter
== 'm')
1738 fprintf (file
, "%ld", - INTVAL (op
));
1739 else if (letter
== 's')
1740 fprintf (file
, "%ld", INTVAL (op
) % 8);
1741 else if (letter
== 'S')
1742 fprintf (file
, "%ld", INTVAL (op
) % 16);
1743 else if (letter
== 'r')
1744 fprintf (file
, "%ld", 8 - (INTVAL (op
) % 8));
1745 else if (letter
== 'C')
1746 fprintf (file
, "%ld", (INTVAL (op
) ^ 0x8000) & 0xffff);
1748 fprintf (file
, "%ld", INTVAL (op
));
1752 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1757 int bits
= INTVAL (XEXP (op
, 1));
1758 int ofs
= INTVAL (XEXP (op
, 2));
1759 if (bits
== 16 && ofs
== 0)
1760 fprintf (file
, "%%lo16(");
1761 else if (bits
== 16 && ofs
== 16)
1762 fprintf (file
, "%%hi16(");
1763 else if (bits
== 8 && ofs
== 16)
1764 fprintf (file
, "%%hi8(");
1767 rl78_print_operand_1 (file
, XEXP (op
, 0), 0);
1768 fprintf (file
, ")");
1773 if (GET_CODE (XEXP (op
, 0)) == REG
)
1774 fprintf (file
, "%s", reg_names
[REGNO (XEXP (op
, 0))]);
1776 print_rtl (file
, op
);
1783 fprintf (file
, "%%hi16(");
1789 fprintf (file
, "%%lo16(");
1795 fprintf (file
, "%%hi8(");
1799 if (letter
== 'q' || letter
== 'Q')
1800 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1802 if (GET_CODE (XEXP (op
, 0)) == ZERO_EXTEND
)
1804 if (GET_CODE (XEXP (op
, 1)) == SYMBOL_REF
1805 && SYMBOL_REF_DECL (XEXP (op
, 1))
1806 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op
, 1))) == FUNCTION_DECL
)
1808 fprintf (file
, "%%code(");
1809 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op
, 1), 0)));
1810 fprintf (file
, "+");
1811 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1812 fprintf (file
, ")");
1816 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
1817 fprintf (file
, "+");
1818 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1823 if (GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1824 && SYMBOL_REF_DECL (XEXP (op
, 0))
1825 && TREE_CODE (SYMBOL_REF_DECL (XEXP (op
, 0))) == FUNCTION_DECL
)
1827 fprintf (file
, "%%code(");
1828 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (XEXP (op
, 0), 0)));
1829 fprintf (file
, "+");
1830 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
1831 fprintf (file
, ")");
1835 rl78_print_operand_1 (file
, XEXP (op
, 0), letter
);
1836 fprintf (file
, "+");
1837 rl78_print_operand_1 (file
, XEXP (op
, 1), letter
);
1841 fprintf (file
, ")");
1845 if (GET_MODE (op
) == HImode
1846 && SUBREG_BYTE (op
) == 0)
1848 fprintf (file
, "%%lo16(");
1849 rl78_print_operand_1 (file
, SUBREG_REG (op
), 0);
1850 fprintf (file
, ")");
1852 else if (GET_MODE (op
) == HImode
1853 && SUBREG_BYTE (op
) == 2)
1855 fprintf (file
, "%%hi16(");
1856 rl78_print_operand_1 (file
, SUBREG_REG (op
), 0);
1857 fprintf (file
, ")");
1861 fprintf (file
, "(%s)", GET_RTX_NAME (GET_CODE (op
)));
1869 fprintf (file
, "%%hi16(");
1875 fprintf (file
, "%%lo16(");
1881 fprintf (file
, "%%hi8(");
1885 if (letter
== 'q' || letter
== 'Q')
1886 output_operand_lossage ("q/Q modifiers invalid for symbol references");
1888 if (SYMBOL_REF_DECL (op
) && TREE_CODE (SYMBOL_REF_DECL (op
)) == FUNCTION_DECL
)
1890 fprintf (file
, "%%code(");
1891 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (op
, 0)));
1892 fprintf (file
, ")");
1895 assemble_name (file
, rl78_strip_nonasm_name_encoding (XSTR (op
, 0)));
1897 fprintf (file
, ")");
1902 output_asm_label (op
);
1907 fprintf (file
, "#comparison eliminated");
1909 fprintf (file
, letter
== 'C' ? "nc" : "c");
1913 fprintf (file
, "br");
1915 fprintf (file
, letter
== 'C' ? "h" : "nh");
1919 fprintf (file
, "br");
1921 fprintf (file
, letter
== 'C' ? "c" : "nc");
1925 fprintf (file
, "#comparison eliminated");
1927 fprintf (file
, letter
== 'C' ? "nh" : "h");
1931 fprintf (file
, "br");
1933 fprintf (file
, letter
== 'C' ? "nz" : "z");
1937 fprintf (file
, "#comparison eliminated");
1939 fprintf (file
, letter
== 'C' ? "z" : "nz");
1942 /* Note: these assume appropriate adjustments were made so that
1943 unsigned comparisons, which is all this chip has, will
1947 fprintf (file
, "#comparison eliminated");
1949 fprintf (file
, letter
== 'C' ? "nc" : "c");
1953 fprintf (file
, "br");
1955 fprintf (file
, letter
== 'C' ? "h" : "nh");
1959 fprintf (file
, "br");
1961 fprintf (file
, letter
== 'C' ? "c" : "nc");
1965 fprintf (file
, "#comparison eliminated");
1967 fprintf (file
, letter
== 'C' ? "nh" : "h");
1971 fprintf (file
, "(%s)", GET_RTX_NAME (GET_CODE (op
)));
1976 #undef TARGET_PRINT_OPERAND
1977 #define TARGET_PRINT_OPERAND rl78_print_operand
1980 rl78_print_operand (FILE * file
, rtx op
, int letter
)
1982 if (CONSTANT_P (op
) && letter
!= 'u' && letter
!= 's' && letter
!= 'r' && letter
!= 'S' && letter
!= 'B')
1983 fprintf (file
, "#");
1984 rl78_print_operand_1 (file
, op
, letter
);
1987 #undef TARGET_TRAMPOLINE_INIT
1988 #define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
1990 /* Note that the RL78's addressing makes it very difficult to do
1991 trampolines on the stack. So, libgcc has a small pool of
1992 trampolines from which one is allocated to this task. */
1994 rl78_trampoline_init (rtx m_tramp
, tree fndecl
, rtx static_chain
)
1996 rtx mov_addr
, thunk_addr
;
1997 rtx function
= XEXP (DECL_RTL (fndecl
), 0);
1999 mov_addr
= adjust_address (m_tramp
, HImode
, 0);
2000 thunk_addr
= gen_reg_rtx (HImode
);
2002 function
= force_reg (HImode
, function
);
2003 static_chain
= force_reg (HImode
, static_chain
);
2005 emit_insn (gen_trampoline_init (thunk_addr
, function
, static_chain
));
2006 emit_move_insn (mov_addr
, thunk_addr
);
2008 cfun
->machine
->trampolines_used
= 1;
2011 #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS
2012 #define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
2015 rl78_trampoline_adjust_address (rtx m_tramp
)
2017 rtx x
= gen_rtx_MEM (HImode
, m_tramp
);
2021 /* Expander for cbranchqi4 and cbranchhi4. RL78 is missing some of
2022 the "normal" compares, specifically, it only has unsigned compares,
2023 so we must synthesize the missing ones. */
2025 rl78_expand_compare (rtx
*operands
)
2027 if (GET_CODE (operands
[2]) == MEM
)
2028 operands
[2] = copy_to_mode_reg (GET_MODE (operands
[2]), operands
[2]);
2033 /* Define this to 1 if you are debugging the peephole optimizers. */
2034 #define DEBUG_PEEP 0
2036 /* Predicate used to enable the peephole2 patterns in rl78-virt.md.
2037 The default "word" size is a byte so we can effectively use all the
2038 registers, but we want to do 16-bit moves whenever possible. This
2039 function determines when such a move is an option. */
2041 rl78_peep_movhi_p (rtx
*operands
)
2046 /* (set (op0) (op1))
2047 (set (op2) (op3)) */
2049 if (! rl78_virt_insns_ok ())
2053 fprintf (stderr
, "\033[33m");
2054 debug_rtx (operands
[0]);
2055 debug_rtx (operands
[1]);
2056 debug_rtx (operands
[2]);
2057 debug_rtx (operands
[3]);
2058 fprintf (stderr
, "\033[0m");
2061 /* You can move a constant to memory as QImode, but not HImode. */
2062 if (GET_CODE (operands
[0]) == MEM
2063 && GET_CODE (operands
[1]) != REG
)
2066 fprintf (stderr
, "no peep: move constant to memory\n");
2071 if (rtx_equal_p (operands
[0], operands
[3]))
2074 fprintf (stderr
, "no peep: overlapping\n");
2079 for (i
= 0; i
< 2; i
++)
2081 if (GET_CODE (operands
[i
]) != GET_CODE (operands
[i
+2]))
2084 fprintf (stderr
, "no peep: different codes\n");
2088 if (GET_MODE (operands
[i
]) != GET_MODE (operands
[i
+2]))
2091 fprintf (stderr
, "no peep: different modes\n");
2096 switch (GET_CODE (operands
[i
]))
2100 if (REGNO (operands
[i
]) + 1 != REGNO (operands
[i
+2])
2101 || GET_MODE (operands
[i
]) != QImode
)
2104 fprintf (stderr
, "no peep: wrong regnos %d %d %d\n",
2105 REGNO (operands
[i
]), REGNO (operands
[i
+2]),
2110 if (! rl78_hard_regno_mode_ok (REGNO (operands
[i
]), HImode
))
2113 fprintf (stderr
, "no peep: reg %d not HI\n", REGNO (operands
[i
]));
2123 if (GET_MODE (operands
[i
]) != QImode
)
2125 if (MEM_ALIGN (operands
[i
]) < 16)
2127 a
= XEXP (operands
[i
], 0);
2128 if (GET_CODE (a
) == CONST
)
2130 if (GET_CODE (a
) == PLUS
)
2132 if (GET_CODE (a
) == CONST_INT
2136 fprintf (stderr
, "no peep: misaligned mem %d\n", i
);
2137 debug_rtx (operands
[i
]);
2141 m
= adjust_address (operands
[i
], QImode
, 1);
2142 if (! rtx_equal_p (m
, operands
[i
+2]))
2145 fprintf (stderr
, "no peep: wrong mem %d\n", i
);
2147 debug_rtx (operands
[i
+2]);
2155 fprintf (stderr
, "no peep: wrong rtx %d\n", i
);
2161 fprintf (stderr
, "\033[32mpeep!\033[0m\n");
2166 /* Likewise, when a peephole is activated, this function helps compute
2167 the new operands. */
2169 rl78_setup_peep_movhi (rtx
*operands
)
2173 for (i
= 0; i
< 2; i
++)
2175 switch (GET_CODE (operands
[i
]))
2178 operands
[i
+4] = gen_rtx_REG (HImode
, REGNO (operands
[i
]));
2182 operands
[i
+4] = GEN_INT ((INTVAL (operands
[i
]) & 0xff) + ((char) INTVAL (operands
[i
+2])) * 256);
2186 operands
[i
+4] = adjust_address (operands
[i
], HImode
, 0);
2196 How Devirtualization works in the RL78 GCC port
2200 The RL78 is an 8-bit port with some 16-bit operations. It has 32
2201 bytes of register space, in four banks, memory-mapped. One bank is
2202 the "selected" bank and holds the registers used for primary
2203 operations. Since the registers are memory mapped, often you can
2204 still refer to the unselected banks via memory accesses.
2208 The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
2209 and refers to the other banks via their memory addresses, although
2210 they're treated as regular registers internally. These "virtual"
2211 registers are R8 through R23 (bank3 is reserved for asm-based
2212 interrupt handlers).
2214 There are four machine description files:
2216 rl78.md - common register-independent patterns and definitions
2217 rl78-expand.md - expanders
2218 rl78-virt.md - patterns that match BEFORE devirtualization
2219 rl78-real.md - patterns that match AFTER devirtualization
2221 At least through register allocation and reload, gcc is told that it
2222 can do pretty much anything - but may only use the virtual registers.
2223 GCC cannot properly create the varying addressing modes that the RL78
2224 supports in an efficient way.
2226 Sometime after reload, the RL78 backend "devirtualizes" the RTL. It
2227 uses the "valloc" attribute in rl78-virt.md for determining the rules
2228 by which it will replace virtual registers with real registers (or
2229 not) and how to make up addressing modes. For example, insns tagged
2230 with "ro1" have a single read-only parameter, which may need to be
2231 moved from memory/constant/vreg to a suitable real register. As part
2232 of devirtualization, a flag is toggled, disabling the rl78-virt.md
2233 patterns and enabling the rl78-real.md patterns. The new patterns'
2234 constraints are used to determine the real registers used. NOTE:
2235 patterns in rl78-virt.md essentially ignore the constrains and rely on
2236 predicates, where the rl78-real.md ones essentially ignore the
2237 predicates and rely on the constraints.
2239 The devirtualization pass is scheduled via the pass manager (despite
2240 being called "rl78_reorg") so it can be scheduled prior to var-track
2241 (the idea is to let gdb know about the new registers). Ideally, it
2242 would be scheduled right after pro/epilogue generation, so the
2243 post-reload optimizers could operate on the real registers, but when I
2244 tried that there were some issues building the target libraries.
2246 During devirtualization, a simple register move optimizer is run. It
2247 would be better to run a full CSE/propogation pass on it though, but
2248 that has not yet been attempted.
2251 #define DEBUG_ALLOC 0
2253 #define OP(x) (*recog_data.operand_loc[x])
2255 /* This array is used to hold knowledge about the contents of the
2256 real registers (A ... H), the memory-based registers (r8 ... r31)
2257 and the first NUM_STACK_LOCS words on the stack. We use this to
2258 avoid generating redundant move instructions.
2260 A value in the range 0 .. 31 indicates register A .. r31.
2261 A value in the range 32 .. 63 indicates stack slot (value - 32).
2262 A value of NOT_KNOWN indicates that the contents of that location
2265 #define NUM_STACK_LOCS 32
2266 #define NOT_KNOWN 127
2268 static unsigned char content_memory
[32 + NUM_STACK_LOCS
];
2270 static unsigned char saved_update_index
= NOT_KNOWN
;
2271 static unsigned char saved_update_value
;
2272 static machine_mode saved_update_mode
;
2276 clear_content_memory (void)
2278 memset (content_memory
, NOT_KNOWN
, sizeof content_memory
);
2280 fprintf (dump_file
, " clear content memory\n");
2281 saved_update_index
= NOT_KNOWN
;
2284 /* Convert LOC into an index into the content_memory array.
2285 If LOC cannot be converted, return NOT_KNOWN. */
2287 static unsigned char
2288 get_content_index (rtx loc
)
2292 if (loc
== NULL_RTX
)
2297 if (REGNO (loc
) < 32)
2302 mode
= GET_MODE (loc
);
2304 if (! rl78_stack_based_mem (loc
, mode
))
2307 loc
= XEXP (loc
, 0);
2310 /* loc = MEM (SP) */
2313 /* loc = MEM (PLUS (SP, INT)). */
2314 loc
= XEXP (loc
, 1);
2316 if (INTVAL (loc
) < NUM_STACK_LOCS
)
2317 return 32 + INTVAL (loc
);
2322 /* Return a string describing content INDEX in mode MODE.
2323 WARNING: Can return a pointer to a static buffer. */
2325 get_content_name (unsigned char index
, machine_mode mode
)
2327 static char buffer
[128];
2329 if (index
== NOT_KNOWN
)
2333 sprintf (buffer
, "stack slot %d", index
- 32);
2334 else if (mode
== HImode
)
2335 sprintf (buffer
, "%s%s",
2336 reg_names
[index
+ 1], reg_names
[index
]);
2338 return reg_names
[index
];
2346 display_content_memory (FILE * file
)
2350 fprintf (file
, " Known memory contents:\n");
2352 for (i
= 0; i
< sizeof content_memory
; i
++)
2353 if (content_memory
[i
] != NOT_KNOWN
)
2355 fprintf (file
, " %s contains a copy of ", get_content_name (i
, QImode
));
2356 fprintf (file
, "%s\n", get_content_name (content_memory
[i
], QImode
));
2362 update_content (unsigned char index
, unsigned char val
, machine_mode mode
)
2366 gcc_assert (index
< sizeof content_memory
);
2368 content_memory
[index
] = val
;
2369 if (val
!= NOT_KNOWN
)
2370 content_memory
[val
] = index
;
2372 /* Make the entry in dump_file *before* VAL is increased below. */
2375 fprintf (dump_file
, " %s now contains ", get_content_name (index
, mode
));
2376 if (val
== NOT_KNOWN
)
2377 fprintf (dump_file
, "Unknown\n");
2379 fprintf (dump_file
, "%s and vice versa\n", get_content_name (val
, mode
));
2384 val
= val
== NOT_KNOWN
? val
: val
+ 1;
2386 content_memory
[index
+ 1] = val
;
2387 if (val
!= NOT_KNOWN
)
2389 content_memory
[val
] = index
+ 1;
2394 /* Any other places that had INDEX recorded as their contents are now invalid. */
2395 for (i
= 0; i
< sizeof content_memory
; i
++)
2398 || (val
!= NOT_KNOWN
&& i
== val
))
2405 if (content_memory
[i
] == index
2406 || (val
!= NOT_KNOWN
&& content_memory
[i
] == val
))
2408 content_memory
[i
] = NOT_KNOWN
;
2411 fprintf (dump_file
, " %s cleared\n", get_content_name (i
, mode
));
2414 content_memory
[++ i
] = NOT_KNOWN
;
2419 /* Record that LOC contains VALUE.
2420 For HImode locations record that LOC+1 contains VALUE+1.
2421 If LOC is not a register or stack slot, do nothing.
2422 If VALUE is not a register or stack slot, clear the recorded content. */
2425 record_content (rtx loc
, rtx value
)
2428 unsigned char index
;
2431 if ((index
= get_content_index (loc
)) == NOT_KNOWN
)
2434 val
= get_content_index (value
);
2436 mode
= GET_MODE (loc
);
2443 /* This should not happen when optimizing. */
2445 fprintf (stderr
, "ASSIGNMENT of location to itself detected! [%s]\n",
2446 get_content_name (val
, mode
));
2453 update_content (index
, val
, mode
);
2456 /* Returns TRUE if LOC already contains a copy of VALUE. */
2459 already_contains (rtx loc
, rtx value
)
2461 unsigned char index
;
2464 if ((index
= get_content_index (loc
)) == NOT_KNOWN
)
2467 if ((val
= get_content_index (value
)) == NOT_KNOWN
)
2470 if (content_memory
[index
] != val
)
2473 if (GET_MODE (loc
) == HImode
)
2474 return content_memory
[index
+ 1] == val
+ 1;
2480 rl78_es_addr (rtx addr
)
2482 if (GET_CODE (addr
) == MEM
)
2483 addr
= XEXP (addr
, 0);
2484 if (GET_CODE (addr
) != UNSPEC
)
2486 if (XINT (addr
, 1) != UNS_ES_ADDR
)
2492 rl78_es_base (rtx addr
)
2494 if (GET_CODE (addr
) == MEM
)
2495 addr
= XEXP (addr
, 0);
2496 addr
= XVECEXP (addr
, 0, 1);
2497 if (GET_CODE (addr
) == CONST
2498 && GET_CODE (XEXP (addr
, 0)) == ZERO_EXTRACT
)
2499 addr
= XEXP (XEXP (addr
, 0), 0);
2500 /* Mode doesn't matter here. */
2501 return gen_rtx_MEM (HImode
, addr
);
2504 /* Rescans an insn to see if it's recognized again. This is done
2505 carefully to ensure that all the constraint information is accurate
2506 for the newly matched insn. */
2508 insn_ok_now (rtx_insn
* insn
)
2510 rtx pattern
= PATTERN (insn
);
2513 INSN_CODE (insn
) = -1;
2515 if (recog (pattern
, insn
, 0) > -1)
2517 extract_insn (insn
);
2518 if (constrain_operands (1, get_preferred_alternatives (insn
)))
2521 fprintf (stderr
, "\033[32m");
2523 fprintf (stderr
, "\033[0m");
2525 if (SET_P (pattern
))
2526 record_content (SET_DEST (pattern
), SET_SRC (pattern
));
2528 /* We need to detect far addresses that haven't been
2529 converted to es/lo16 format. */
2530 for (i
=0; i
<recog_data
.n_operands
; i
++)
2531 if (GET_CODE (OP (i
)) == MEM
2532 && GET_MODE (XEXP (OP (i
), 0)) == SImode
2533 && GET_CODE (XEXP (OP (i
), 0)) != UNSPEC
)
2541 /* We need to re-recog the insn with virtual registers to get
2543 cfun
->machine
->virt_insns_ok
= 1;
2544 if (recog (pattern
, insn
, 0) > -1)
2546 extract_insn (insn
);
2547 if (constrain_operands (0, get_preferred_alternatives (insn
)))
2549 cfun
->machine
->virt_insns_ok
= 0;
2555 fprintf (stderr
, "\033[41;30m Unrecognized *virtual* insn \033[0m\n");
2562 fprintf (stderr
, "\033[31m");
2564 fprintf (stderr
, "\033[0m");
2570 #define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
2571 #define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
2572 #define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable ()
2573 #define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
2574 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } FAILED
2576 #define FAILED gcc_unreachable ()
2577 #define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
2578 #define MUST_BE_OK(insn) if (insn_ok_now (insn)) return; FAILED
2581 /* Registers into which we move the contents of virtual registers. */
2582 #define X gen_rtx_REG (QImode, X_REG)
2583 #define A gen_rtx_REG (QImode, A_REG)
2584 #define C gen_rtx_REG (QImode, C_REG)
2585 #define B gen_rtx_REG (QImode, B_REG)
2586 #define E gen_rtx_REG (QImode, E_REG)
2587 #define D gen_rtx_REG (QImode, D_REG)
2588 #define L gen_rtx_REG (QImode, L_REG)
2589 #define H gen_rtx_REG (QImode, H_REG)
2591 #define AX gen_rtx_REG (HImode, AX_REG)
2592 #define BC gen_rtx_REG (HImode, BC_REG)
2593 #define DE gen_rtx_REG (HImode, DE_REG)
2594 #define HL gen_rtx_REG (HImode, HL_REG)
2596 /* Returns TRUE if R is a virtual register. */
2598 is_virtual_register (rtx r
)
2600 return (GET_CODE (r
) == REG
2605 /* In all these alloc routines, we expect the following: the insn
2606 pattern is unshared, the insn was previously recognized and failed
2607 due to predicates or constraints, and the operand data is in
2610 static int virt_insn_was_frame
;
2612 /* Hook for all insns we emit. Re-mark them as FRAME_RELATED if
2615 EM2 (int line ATTRIBUTE_UNUSED
, rtx r
)
2618 fprintf (stderr
, "\033[36m%d: ", line
);
2620 fprintf (stderr
, "\033[0m");
2622 /*SCHED_GROUP_P (r) = 1;*/
2623 if (virt_insn_was_frame
)
2624 RTX_FRAME_RELATED_P (r
) = 1;
2628 #define EM(x) EM2 (__LINE__, x)
2630 /* Return a suitable RTX for the low half of a __far address. */
2632 rl78_lo16 (rtx addr
)
2636 if (GET_CODE (addr
) == SYMBOL_REF
2637 || GET_CODE (addr
) == CONST
)
2639 r
= gen_rtx_ZERO_EXTRACT (HImode
, addr
, GEN_INT (16), GEN_INT (0));
2640 r
= gen_rtx_CONST (HImode
, r
);
2643 r
= rl78_subreg (HImode
, addr
, SImode
, 0);
2645 r
= gen_es_addr (r
);
2646 cfun
->machine
->uses_es
= true;
2651 /* Return a suitable RTX for the high half's lower byte of a __far address. */
2655 if (GET_CODE (addr
) == SYMBOL_REF
2656 || GET_CODE (addr
) == CONST
)
2658 rtx r
= gen_rtx_ZERO_EXTRACT (QImode
, addr
, GEN_INT (8), GEN_INT (16));
2659 r
= gen_rtx_CONST (QImode
, r
);
2662 return rl78_subreg (QImode
, addr
, SImode
, 2);
2666 add_postponed_content_update (rtx to
, rtx value
)
2668 unsigned char index
;
2670 if ((index
= get_content_index (to
)) == NOT_KNOWN
)
2673 gcc_assert (saved_update_index
== NOT_KNOWN
);
2674 saved_update_index
= index
;
2675 saved_update_value
= get_content_index (value
);
2676 saved_update_mode
= GET_MODE (to
);
2680 process_postponed_content_update (void)
2682 if (saved_update_index
!= NOT_KNOWN
)
2684 update_content (saved_update_index
, saved_update_value
, saved_update_mode
);
2685 saved_update_index
= NOT_KNOWN
;
2689 /* Generate and emit a move of (register) FROM into TO. if WHERE is not NULL
2690 then if BEFORE is true then emit the insn before WHERE, otherwise emit it
2691 after WHERE. If TO already contains FROM then do nothing. Returns TO if
2692 BEFORE is true, FROM otherwise. */
2694 gen_and_emit_move (rtx to
, rtx from
, rtx where
, bool before
)
2696 machine_mode mode
= GET_MODE (to
);
2698 if (optimize
&& before
&& already_contains (to
, from
))
2701 display_content_memory (stderr
);
2705 fprintf (dump_file
, " Omit move of %s into ",
2706 get_content_name (get_content_index (from
), mode
));
2707 fprintf (dump_file
, "%s as it already contains this value\n",
2708 get_content_name (get_content_index (to
), mode
));
2713 rtx move
= mode
== QImode
? gen_movqi (to
, from
) : gen_movhi (to
, from
);
2717 if (where
== NULL_RTX
)
2720 emit_insn_before (move
, where
);
2723 rtx note
= find_reg_note (where
, REG_EH_REGION
, NULL_RTX
);
2725 /* If necessary move REG_EH_REGION notes forward.
2726 cf. compiling gcc.dg/pr44545.c. */
2727 if (note
!= NULL_RTX
)
2729 add_reg_note (move
, REG_EH_REGION
, XEXP (note
, 0));
2730 remove_note (where
, note
);
2733 emit_insn_after (move
, where
);
2737 record_content (to
, from
);
2739 add_postponed_content_update (to
, from
);
2742 return before
? to
: from
;
2745 /* If M is MEM(REG) or MEM(PLUS(REG,INT)) and REG is virtual then
2746 copy it into NEWBASE and return the updated MEM. Otherwise just
2747 return M. Any needed insns are emitted before BEFORE. */
2749 transcode_memory_rtx (rtx m
, rtx newbase
, rtx before
)
2751 rtx base
, index
, addendr
;
2758 if (GET_MODE (XEXP (m
, 0)) == SImode
)
2761 rtx seg
= rl78_hi8 (XEXP (m
, 0));
2765 emit_insn_before (EM (gen_movqi (A
, seg
)), before
);
2766 emit_insn_before (EM (gen_movqi_to_es (A
)), before
);
2769 record_content (A
, NULL_RTX
);
2771 new_m
= gen_rtx_MEM (GET_MODE (m
), rl78_lo16 (XEXP (m
, 0)));
2772 MEM_COPY_ATTRIBUTES (new_m
, m
);
2777 characterize_address (XEXP (m
, 0), & base
, & index
, & addendr
);
2778 gcc_assert (index
== NULL_RTX
);
2780 if (base
== NULL_RTX
)
2783 if (addendr
&& GET_CODE (addendr
) == CONST_INT
)
2784 addend
= INTVAL (addendr
);
2786 gcc_assert (REG_P (base
));
2787 gcc_assert (REG_P (newbase
));
2789 int limit
= 256 - GET_MODE_SIZE (GET_MODE (m
));
2791 if (REGNO (base
) == SP_REG
)
2793 if (addend
>= 0 && addend
<= limit
)
2797 /* BASE should be a virtual register. We copy it to NEWBASE. If
2798 the addend is out of range for DE/HL, we use AX to compute the full
2802 || (addend
> limit
&& REGNO (newbase
) != BC_REG
)
2804 && (GET_CODE (addendr
) != CONST_INT
)
2805 && ((REGNO (newbase
) != BC_REG
))
2811 EM (emit_insn_before (gen_movhi (AX
, base
), before
));
2812 EM (emit_insn_before (gen_addhi3 (AX
, AX
, addendr
), before
));
2813 EM (emit_insn_before (gen_movhi (newbase
, AX
), before
));
2814 record_content (AX
, NULL_RTX
);
2815 record_content (newbase
, NULL_RTX
);
2823 base
= gen_and_emit_move (newbase
, base
, before
, true);
2828 record_content (base
, NULL_RTX
);
2829 base
= gen_rtx_PLUS (HImode
, base
, GEN_INT (addend
));
2833 record_content (base
, NULL_RTX
);
2834 base
= gen_rtx_PLUS (HImode
, base
, addendr
);
2839 m
= change_address (m
, GET_MODE (m
), gen_es_addr (base
));
2840 cfun
->machine
->uses_es
= true;
2843 m
= change_address (m
, GET_MODE (m
), base
);
2847 /* Copy SRC to accumulator (A or AX), placing any generated insns
2848 before BEFORE. Returns accumulator RTX. */
2850 move_to_acc (int opno
, rtx before
)
2852 rtx src
= OP (opno
);
2853 machine_mode mode
= GET_MODE (src
);
2855 if (REG_P (src
) && REGNO (src
) < 2)
2858 if (mode
== VOIDmode
)
2859 mode
= recog_data
.operand_mode
[opno
];
2861 return gen_and_emit_move (mode
== QImode
? A
: AX
, src
, before
, true);
2865 force_into_acc (rtx src
, rtx before
)
2867 machine_mode mode
= GET_MODE (src
);
2870 if (REG_P (src
) && REGNO (src
) < 2)
2873 move
= mode
== QImode
? gen_movqi (A
, src
) : gen_movhi (AX
, src
);
2877 emit_insn_before (move
, before
);
2878 record_content (AX
, NULL_RTX
);
2881 /* Copy accumulator (A or AX) to DEST, placing any generated insns
2882 after AFTER. Returns accumulator RTX. */
2884 move_from_acc (unsigned int opno
, rtx after
)
2886 rtx dest
= OP (opno
);
2887 machine_mode mode
= GET_MODE (dest
);
2889 if (REG_P (dest
) && REGNO (dest
) < 2)
2892 return gen_and_emit_move (dest
, mode
== QImode
? A
: AX
, after
, false);
2895 /* Copy accumulator (A or AX) to REGNO, placing any generated insns
2896 before BEFORE. Returns reg RTX. */
2898 move_acc_to_reg (rtx acc
, int regno
, rtx before
)
2900 machine_mode mode
= GET_MODE (acc
);
2903 reg
= gen_rtx_REG (mode
, regno
);
2905 return gen_and_emit_move (reg
, acc
, before
, true);
2908 /* Copy SRC to X, placing any generated insns before BEFORE.
2911 move_to_x (int opno
, rtx before
)
2913 rtx src
= OP (opno
);
2914 machine_mode mode
= GET_MODE (src
);
2917 if (mode
== VOIDmode
)
2918 mode
= recog_data
.operand_mode
[opno
];
2919 reg
= (mode
== QImode
) ? X
: AX
;
2921 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
2923 OP (opno
) = move_to_acc (opno
, before
);
2924 OP (opno
) = move_acc_to_reg (OP (opno
), X_REG
, before
);
2928 return gen_and_emit_move (reg
, src
, before
, true);
2931 /* Copy OP (opno) to H or HL, placing any generated insns before BEFORE.
2932 Returns H/HL RTX. */
2934 move_to_hl (int opno
, rtx before
)
2936 rtx src
= OP (opno
);
2937 machine_mode mode
= GET_MODE (src
);
2940 if (mode
== VOIDmode
)
2941 mode
= recog_data
.operand_mode
[opno
];
2942 reg
= (mode
== QImode
) ? L
: HL
;
2944 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
2946 OP (opno
) = move_to_acc (opno
, before
);
2947 OP (opno
) = move_acc_to_reg (OP (opno
), L_REG
, before
);
2951 return gen_and_emit_move (reg
, src
, before
, true);
2954 /* Copy OP (opno) to E or DE, placing any generated insns before BEFORE.
2955 Returns E/DE RTX. */
2957 move_to_de (int opno
, rtx before
)
2959 rtx src
= OP (opno
);
2960 machine_mode mode
= GET_MODE (src
);
2963 if (mode
== VOIDmode
)
2964 mode
= recog_data
.operand_mode
[opno
];
2966 reg
= (mode
== QImode
) ? E
: DE
;
2968 if (mode
== QImode
|| ! is_virtual_register (OP (opno
)))
2970 OP (opno
) = move_to_acc (opno
, before
);
2971 OP (opno
) = move_acc_to_reg (OP (opno
), E_REG
, before
);
2975 gen_and_emit_move (reg
, src
, before
, true);
2981 /* Devirtualize an insn of the form (SET (op) (unop (op))). */
2983 rl78_alloc_physical_registers_op1 (rtx_insn
* insn
)
2985 /* op[0] = func op[1] */
2987 /* We first try using A as the destination, then copying it
2989 if (rtx_equal_p (OP (0), OP (1)))
2992 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
2996 /* If necessary, load the operands into BC and HL.
2997 Check to see if we already have OP (0) in HL
2998 and if so, swap the order.
3000 It is tempting to perform this optimization when OP(0) does
3001 not hold a MEM, but this leads to bigger code in general.
3002 The problem is that if OP(1) holds a MEM then swapping it
3003 into BC means a BC-relative load is used and these are 3
3004 bytes long vs 1 byte for an HL load. */
3006 && already_contains (HL
, XEXP (OP (0), 0)))
3008 OP (0) = transcode_memory_rtx (OP (0), HL
, insn
);
3009 OP (1) = transcode_memory_rtx (OP (1), BC
, insn
);
3013 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3014 OP (1) = transcode_memory_rtx (OP (1), HL
, insn
);
3020 OP (0) = move_from_acc (0, insn
);
3024 /* Try copying the src to acc first, then. This is for, for
3025 example, ZERO_EXTEND or NOT. */
3026 OP (1) = move_to_acc (1, insn
);
3031 /* Returns true if operand OPNUM contains a constraint of type CONSTRAINT.
3032 Assumes that the current insn has already been recognised and hence the
3033 constraint data has been filled in. */
3035 has_constraint (unsigned int opnum
, enum constraint_num constraint
)
3037 const char * p
= recog_data
.constraints
[opnum
];
3039 /* No constraints means anything is accepted. */
3040 if (p
== NULL
|| *p
== 0 || *p
== ',')
3049 len
= CONSTRAINT_LEN (c
, p
);
3050 gcc_assert (len
> 0);
3058 if (lookup_constraint (p
) == constraint
)
3066 /* Devirtualize an insn of the form (SET (op) (binop (op) (op))). */
3068 rl78_alloc_physical_registers_op2 (rtx_insn
* insn
)
3076 if (rtx_equal_p (OP (0), OP (1)))
3081 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3082 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3087 OP (1) = transcode_memory_rtx (OP (1), HL
, insn
);
3088 OP (2) = transcode_memory_rtx (OP (2), DE
, insn
);
3091 else if (rtx_equal_p (OP (0), OP (2)))
3093 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3095 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3099 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3100 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3101 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3106 prev
= prev_nonnote_nondebug_insn (insn
);
3107 if (recog_data
.constraints
[1][0] == '%'
3108 && is_virtual_register (OP (1))
3109 && ! is_virtual_register (OP (2))
3110 && ! CONSTANT_P (OP (2)))
3117 /* Make a note of whether (H)L is being used. It matters
3118 because if OP (2) also needs reloading, then we must take
3119 care not to corrupt HL. */
3120 hl_used
= reg_mentioned_p (L
, OP (0)) || reg_mentioned_p (L
, OP (1));
3122 /* If HL is not currently being used and dest == op1 then there are
3123 some possible optimizations available by reloading one of the
3124 operands into HL, before trying to use the accumulator. */
3127 && rtx_equal_p (OP (0), OP (1)))
3129 /* If op0 is a Ws1 type memory address then switching the base
3130 address register to HL might allow us to perform an in-memory
3131 operation. (eg for the INCW instruction).
3133 FIXME: Adding the move into HL is costly if this optimization is not
3134 going to work, so for now, make sure that we know that the new insn will
3135 match the requirements of the addhi3_real pattern. Really we ought to
3136 generate a candidate sequence, test that, and then install it if the
3137 results are good. */
3138 if (satisfies_constraint_Ws1 (OP (0))
3139 && has_constraint (0, CONSTRAINT_Wh1
)
3140 && (satisfies_constraint_K (OP (2)) || satisfies_constraint_L (OP (2))))
3142 rtx base
, index
, addend
, newbase
;
3144 characterize_address (XEXP (OP (0), 0), & base
, & index
, & addend
);
3145 gcc_assert (index
== NULL_RTX
);
3146 gcc_assert (REG_P (base
) && REGNO (base
) == SP_REG
);
3148 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3149 if (addend
!= NULL_RTX
)
3151 newbase
= gen_and_emit_move (HL
, base
, insn
, true);
3152 record_content (newbase
, NULL_RTX
);
3153 newbase
= gen_rtx_PLUS (HImode
, newbase
, addend
);
3155 OP (0) = OP (1) = change_address (OP (0), VOIDmode
, newbase
);
3157 /* We do not want to fail here as this means that
3158 we have inserted useless insns into the stream. */
3162 else if (REG_P (OP (0))
3163 && satisfies_constraint_Ws1 (OP (2))
3164 && has_constraint (2, CONSTRAINT_Wh1
))
3166 rtx base
, index
, addend
, newbase
;
3168 characterize_address (XEXP (OP (2), 0), & base
, & index
, & addend
);
3169 gcc_assert (index
== NULL_RTX
);
3170 gcc_assert (REG_P (base
) && REGNO (base
) == SP_REG
);
3172 /* Ws1 addressing allows an offset of 0, Wh1 addressing requires a non-zero offset. */
3173 if (addend
!= NULL_RTX
)
3175 gen_and_emit_move (HL
, base
, insn
, true);
3177 if (REGNO (OP (0)) != X_REG
)
3179 OP (1) = move_to_acc (1, insn
);
3180 OP (0) = move_from_acc (0, insn
);
3183 record_content (HL
, NULL_RTX
);
3184 newbase
= gen_rtx_PLUS (HImode
, HL
, addend
);
3186 OP (2) = change_address (OP (2), VOIDmode
, newbase
);
3188 /* We do not want to fail here as this means that
3189 we have inserted useless insns into the stream. */
3195 OP (0) = move_from_acc (0, insn
);
3197 tmp_id
= get_max_insn_count ();
3200 if (rtx_equal_p (OP (1), OP (2)))
3201 OP (2) = OP (1) = move_to_acc (1, insn
);
3203 OP (1) = move_to_acc (1, insn
);
3207 /* If we omitted the move of OP1 into the accumulator (because
3208 it was already there from a previous insn), then force the
3209 generation of the move instruction now. We know that we
3210 are about to emit a move into HL (or DE) via AX, and hence
3211 our optimization to remove the load of OP1 is no longer valid. */
3212 if (tmp_id
== get_max_insn_count ())
3213 force_into_acc (saved_op1
, insn
);
3215 /* We have to copy op2 to HL (or DE), but that involves AX, which
3216 already has a live value. Emit it before those insns. */
3219 first
= next_nonnote_nondebug_insn (prev
);
3221 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3224 OP (2) = hl_used
? move_to_de (2, first
) : move_to_hl (2, first
);
3229 /* Devirtualize an insn of the form SET (PC) (MEM/REG). */
3231 rl78_alloc_physical_registers_ro1 (rtx_insn
* insn
)
3233 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3237 OP (0) = move_to_acc (0, insn
);
3242 /* Devirtualize a compare insn. */
3244 rl78_alloc_physical_registers_cmp (rtx_insn
* insn
)
3248 rtx_insn
*prev
= prev_nonnote_nondebug_insn (insn
);
3251 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3252 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3254 /* HI compares have to have OP (1) in AX, but QI
3255 compares do not, so it is worth checking here. */
3258 /* For an HImode compare, OP (1) must always be in AX.
3259 But if OP (1) is a REG (and not AX), then we can avoid
3260 a reload of OP (1) if we reload OP (2) into AX and invert
3263 && REGNO (OP (1)) != AX_REG
3264 && GET_MODE (OP (1)) == HImode
3267 rtx cmp
= XEXP (SET_SRC (PATTERN (insn
)), 0);
3269 OP (2) = move_to_acc (2, insn
);
3271 switch (GET_CODE (cmp
))
3276 case LTU
: cmp
= gen_rtx_GTU (HImode
, OP (2), OP (1)); break;
3277 case GTU
: cmp
= gen_rtx_LTU (HImode
, OP (2), OP (1)); break;
3278 case LEU
: cmp
= gen_rtx_GEU (HImode
, OP (2), OP (1)); break;
3279 case GEU
: cmp
= gen_rtx_LEU (HImode
, OP (2), OP (1)); break;
3292 if (GET_CODE (cmp
) == EQ
|| GET_CODE (cmp
) == NE
)
3293 PATTERN (insn
) = gen_cbranchhi4_real (cmp
, OP (2), OP (1), OP (3));
3295 PATTERN (insn
) = gen_cbranchhi4_real_inverted (cmp
, OP (2), OP (1), OP (3));
3300 /* Surprisingly, gcc can generate a comparison of a register with itself, but this
3301 should be handled by the second alternative of the cbranchhi_real pattern. */
3302 if (rtx_equal_p (OP (1), OP (2)))
3304 OP (1) = OP (2) = BC
;
3308 tmp_id
= get_max_insn_count ();
3311 OP (1) = move_to_acc (1, insn
);
3315 /* If we omitted the move of OP1 into the accumulator (because
3316 it was already there from a previous insn), then force the
3317 generation of the move instruction now. We know that we
3318 are about to emit a move into HL via AX, and hence our
3319 optimization to remove the load of OP1 is no longer valid. */
3320 if (tmp_id
== get_max_insn_count ())
3321 force_into_acc (saved_op1
, insn
);
3323 /* We have to copy op2 to HL, but that involves the acc, which
3324 already has a live value. Emit it before those insns. */
3326 first
= next_nonnote_nondebug_insn (prev
);
3328 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3330 OP (2) = move_to_hl (2, first
);
3335 /* Like op2, but AX = A * X. */
3337 rl78_alloc_physical_registers_umul (rtx_insn
* insn
)
3339 rtx_insn
*prev
= prev_nonnote_nondebug_insn (insn
);
3344 OP (0) = transcode_memory_rtx (OP (0), BC
, insn
);
3345 OP (1) = transcode_memory_rtx (OP (1), DE
, insn
);
3346 OP (2) = transcode_memory_rtx (OP (2), HL
, insn
);
3350 if (recog_data
.constraints
[1][0] == '%'
3351 && is_virtual_register (OP (1))
3352 && !is_virtual_register (OP (2))
3353 && !CONSTANT_P (OP (2)))
3360 OP (0) = move_from_acc (0, insn
);
3362 tmp_id
= get_max_insn_count ();
3365 if (rtx_equal_p (OP (1), OP (2)))
3367 gcc_assert (GET_MODE (OP (2)) == QImode
);
3368 /* The MULU instruction does not support duplicate arguments
3369 but we know that if we copy OP (2) to X it will do so via
3370 A and thus OP (1) will already be loaded into A. */
3371 OP (2) = move_to_x (2, insn
);
3375 OP (1) = move_to_acc (1, insn
);
3379 /* If we omitted the move of OP1 into the accumulator (because
3380 it was already there from a previous insn), then force the
3381 generation of the move instruction now. We know that we
3382 are about to emit a move into HL (or DE) via AX, and hence
3383 our optimization to remove the load of OP1 is no longer valid. */
3384 if (tmp_id
== get_max_insn_count ())
3385 force_into_acc (saved_op1
, insn
);
3387 /* We have to copy op2 to X, but that involves the acc, which
3388 already has a live value. Emit it before those insns. */
3391 first
= next_nonnote_nondebug_insn (prev
);
3393 for (first
= insn
; prev_nonnote_nondebug_insn (first
); first
= prev_nonnote_nondebug_insn (first
))
3395 OP (2) = move_to_x (2, first
);
3401 rl78_alloc_address_registers_macax (rtx_insn
* insn
)
3404 bool replace_in_op0
= false;
3405 bool replace_in_op1
= false;
3409 /* Two different MEMs are not allowed. */
3411 for (op
= 2; op
>= 0; op
--)
3413 if (MEM_P (OP (op
)))
3415 if (op
== 0 && replace_in_op0
)
3417 if (op
== 1 && replace_in_op1
)
3423 /* If we replace a MEM, make sure that we replace it for all
3424 occurrences of the same MEM in the insn. */
3425 replace_in_op0
= (op
> 0 && rtx_equal_p (OP (op
), OP (0)));
3426 replace_in_op1
= (op
> 1 && rtx_equal_p (OP (op
), OP (1)));
3428 OP (op
) = transcode_memory_rtx (OP (op
), HL
, insn
);
3431 && ((GET_CODE (XEXP (OP (op
), 0)) == REG
3432 && REGNO (XEXP (OP (op
), 0)) == SP_REG
)
3433 || (GET_CODE (XEXP (OP (op
), 0)) == PLUS
3434 && REGNO (XEXP (XEXP (OP (op
), 0), 0)) == SP_REG
)))
3436 emit_insn_before (gen_movhi (HL
, gen_rtx_REG (HImode
, SP_REG
)), insn
);
3437 OP (op
) = replace_rtx (OP (op
), gen_rtx_REG (HImode
, SP_REG
), HL
);
3445 OP (op
) = transcode_memory_rtx (OP (op
), DE
, insn
);
3448 OP (op
) = transcode_memory_rtx (OP (op
), BC
, insn
);
3459 rl78_alloc_address_registers_div (rtx_insn
* insn
)
3464 /* Scan all insns and devirtualize them. */
3466 rl78_alloc_physical_registers (void)
3468 /* During most of the compile, gcc is dealing with virtual
3469 registers. At this point, we need to assign physical registers
3470 to the vitual ones, and copy in/out as needed. */
3472 rtx_insn
*insn
, *curr
;
3473 enum attr_valloc valloc_method
;
3475 for (insn
= get_insns (); insn
; insn
= curr
)
3479 curr
= next_nonnote_nondebug_insn (insn
);
3482 && (GET_CODE (PATTERN (insn
)) == SET
3483 || GET_CODE (PATTERN (insn
)) == CALL
)
3484 && INSN_CODE (insn
) == -1)
3486 if (GET_CODE (SET_SRC (PATTERN (insn
))) == ASM_OPERANDS
)
3488 i
= recog (PATTERN (insn
), insn
, 0);
3494 INSN_CODE (insn
) = i
;
3498 cfun
->machine
->virt_insns_ok
= 0;
3499 cfun
->machine
->real_insns_ok
= 1;
3501 clear_content_memory ();
3503 for (insn
= get_insns (); insn
; insn
= curr
)
3507 curr
= insn
? next_nonnote_nondebug_insn (insn
) : NULL
;
3512 clear_content_memory ();
3518 fprintf (dump_file
, "Converting insn %d\n", INSN_UID (insn
));
3520 pattern
= PATTERN (insn
);
3521 if (GET_CODE (pattern
) == PARALLEL
)
3522 pattern
= XVECEXP (pattern
, 0, 0);
3523 if (JUMP_P (insn
) || CALL_P (insn
) || GET_CODE (pattern
) == CALL
)
3524 clear_content_memory ();
3525 if (GET_CODE (pattern
) != SET
3526 && GET_CODE (pattern
) != CALL
)
3528 if (GET_CODE (pattern
) == SET
3529 && GET_CODE (SET_SRC (pattern
)) == ASM_OPERANDS
)
3532 valloc_method
= get_attr_valloc (insn
);
3534 PATTERN (insn
) = copy_rtx_if_shared (PATTERN (insn
));
3536 if (valloc_method
== VALLOC_MACAX
)
3538 record_content (AX
, NULL_RTX
);
3539 record_content (BC
, NULL_RTX
);
3540 record_content (DE
, NULL_RTX
);
3542 else if (valloc_method
== VALLOC_DIVHI
)
3544 record_content (AX
, NULL_RTX
);
3545 record_content (BC
, NULL_RTX
);
3547 else if (valloc_method
== VALLOC_DIVSI
)
3549 record_content (AX
, NULL_RTX
);
3550 record_content (BC
, NULL_RTX
);
3551 record_content (DE
, NULL_RTX
);
3552 record_content (HL
, NULL_RTX
);
3555 if (insn_ok_now (insn
))
3558 INSN_CODE (insn
) = -1;
3560 if (RTX_FRAME_RELATED_P (insn
))
3561 virt_insn_was_frame
= 1;
3563 virt_insn_was_frame
= 0;
3565 switch (valloc_method
)
3568 rl78_alloc_physical_registers_op1 (insn
);
3571 rl78_alloc_physical_registers_op2 (insn
);
3574 rl78_alloc_physical_registers_ro1 (insn
);
3577 rl78_alloc_physical_registers_cmp (insn
);
3580 rl78_alloc_physical_registers_umul (insn
);
3581 record_content (AX
, NULL_RTX
);
3584 /* Macro that clobbers AX. */
3585 rl78_alloc_address_registers_macax (insn
);
3586 record_content (AX
, NULL_RTX
);
3587 record_content (BC
, NULL_RTX
);
3588 record_content (DE
, NULL_RTX
);
3591 rl78_alloc_address_registers_div (insn
);
3592 record_content (AX
, NULL_RTX
);
3593 record_content (BC
, NULL_RTX
);
3594 record_content (DE
, NULL_RTX
);
3595 record_content (HL
, NULL_RTX
);
3598 rl78_alloc_address_registers_div (insn
);
3599 record_content (AX
, NULL_RTX
);
3600 record_content (BC
, NULL_RTX
);
3606 if (JUMP_P (insn
) || CALL_P (insn
) || GET_CODE (pattern
) == CALL
)
3607 clear_content_memory ();
3609 process_postponed_content_update ();
3613 fprintf (stderr
, "\033[0m");
3617 /* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
3618 This function scans for uses of registers; the last use (i.e. first
3619 encounter when scanning backwards) triggers a REG_DEAD note if the
3620 reg was previously in DEAD[]. */
3622 rl78_note_reg_uses (char *dead
, rtx s
, rtx insn
)
3631 code
= GET_CODE (s
);
3635 /* Compare registers by number. */
3640 fprintf (dump_file
, "note use reg %d size %d on insn %d\n",
3641 r
, GET_MODE_SIZE (GET_MODE (s
)), INSN_UID (insn
));
3642 print_rtl_single (dump_file
, s
);
3645 add_reg_note (insn
, REG_DEAD
, gen_rtx_REG (GET_MODE (s
), r
));
3646 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (s
)); i
++)
3650 /* These codes have no constituent expressions
3661 /* These are kept unique for a given value. */
3668 fmt
= GET_RTX_FORMAT (code
);
3670 for (i
= GET_RTX_LENGTH (code
) - 1; i
>= 0; i
--)
3675 for (j
= XVECLEN (s
, i
) - 1; j
>= 0; j
--)
3676 rl78_note_reg_uses (dead
, XVECEXP (s
, i
, j
), insn
);
3678 else if (fmt
[i
] == 'e')
3679 rl78_note_reg_uses (dead
, XEXP (s
, i
), insn
);
3683 /* Like the previous function, but scan for SETs instead. */
3685 rl78_note_reg_set (char *dead
, rtx d
, rtx insn
)
3689 if (GET_CODE (d
) == MEM
)
3690 rl78_note_reg_uses (dead
, XEXP (d
, 0), insn
);
3692 if (GET_CODE (d
) != REG
)
3697 add_reg_note (insn
, REG_UNUSED
, gen_rtx_REG (GET_MODE (d
), r
));
3699 fprintf (dump_file
, "note set reg %d size %d\n", r
, GET_MODE_SIZE (GET_MODE (d
)));
3700 for (i
= 0; i
< GET_MODE_SIZE (GET_MODE (d
)); i
++)
3704 /* This is a rather crude register death pass. Death status is reset
3705 at every jump or call insn. */
3707 rl78_calculate_death_notes (void)
3709 char dead
[FIRST_PSEUDO_REGISTER
];
3713 memset (dead
, 0, sizeof (dead
));
3715 for (insn
= get_last_insn ();
3717 insn
= prev_nonnote_nondebug_insn (insn
))
3721 fprintf (dump_file
, "\n--------------------------------------------------");
3722 fprintf (dump_file
, "\nDead:");
3723 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3725 fprintf (dump_file
, " %s", reg_names
[i
]);
3726 fprintf (dump_file
, "\n");
3727 print_rtl_single (dump_file
, insn
);
3730 switch (GET_CODE (insn
))
3734 if (GET_CODE (p
) == PARALLEL
)
3736 rtx q
= XVECEXP (p
, 0 ,1);
3738 /* This happens with the DIV patterns. */
3739 if (GET_CODE (q
) == SET
)
3743 rl78_note_reg_set (dead
, d
, insn
);
3744 rl78_note_reg_uses (dead
, s
, insn
);
3747 p
= XVECEXP (p
, 0, 0);
3750 switch (GET_CODE (p
))
3755 rl78_note_reg_set (dead
, d
, insn
);
3756 rl78_note_reg_uses (dead
, s
, insn
);
3760 rl78_note_reg_uses (dead
, p
, insn
);
3769 if (INSN_CODE (insn
) == CODE_FOR_rl78_return
)
3771 memset (dead
, 1, sizeof (dead
));
3772 /* We expect a USE just prior to this, which will mark
3773 the actual return registers. The USE will have a
3774 death note, but we aren't going to be modifying it
3779 memset (dead
, 0, sizeof (dead
));
3786 print_rtl_single (dump_file
, insn
);
3790 /* Helper function to reset the origins in RP and the age in AGE for
3793 reset_origins (int *rp
, int *age
)
3796 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3804 set_origin (rtx pat
, rtx_insn
* insn
, int * origins
, int * age
)
3806 rtx src
= SET_SRC (pat
);
3807 rtx dest
= SET_DEST (pat
);
3808 int mb
= GET_MODE_SIZE (GET_MODE (dest
));
3811 if (GET_CODE (dest
) == REG
)
3813 int dr
= REGNO (dest
);
3815 if (GET_CODE (src
) == REG
)
3817 int sr
= REGNO (src
);
3819 int best_age
, best_reg
;
3821 /* See if the copy is not needed. */
3822 for (i
= 0; i
< mb
; i
++)
3823 if (origins
[dr
+ i
] != origins
[sr
+ i
])
3829 fprintf (dump_file
, "deleting because dest already has correct value\n");
3834 if (dr
< 8 || sr
>= 8)
3841 /* See if the copy can be made from another
3842 bank 0 register instead, instead of the
3843 virtual src register. */
3844 for (ar
= 0; ar
< 8; ar
+= mb
)
3848 for (i
= 0; i
< mb
; i
++)
3849 if (origins
[ar
+ i
] != origins
[sr
+ i
])
3852 /* The chip has some reg-reg move limitations. */
3853 if (mb
== 1 && dr
> 3)
3858 if (best_age
== -1 || best_age
> age
[sr
+ i
])
3860 best_age
= age
[sr
+ i
];
3868 /* FIXME: copy debug info too. */
3869 SET_SRC (pat
) = gen_rtx_REG (GET_MODE (src
), best_reg
);
3874 for (i
= 0; i
< mb
; i
++)
3876 origins
[dr
+ i
] = origins
[sr
+ i
];
3877 age
[dr
+ i
] = age
[sr
+ i
] + 1;
3882 /* The destination is computed, its origin is itself. */
3884 fprintf (dump_file
, "resetting origin of r%d for %d byte%s\n",
3885 dr
, mb
, mb
== 1 ? "" : "s");
3887 for (i
= 0; i
< mb
; i
++)
3889 origins
[dr
+ i
] = dr
+ i
;
3894 /* Any registers marked with that reg as an origin are reset. */
3895 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3896 if (origins
[i
] >= dr
&& origins
[i
] < dr
+ mb
)
3903 /* Special case - our MUL patterns uses AX and sometimes BC. */
3904 if (get_attr_valloc (insn
) == VALLOC_MACAX
)
3907 fprintf (dump_file
, "Resetting origin of AX/BC for MUL pattern.\n");
3909 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3910 if (i
<= 3 || origins
[i
] <= 3)
3916 else if (get_attr_valloc (insn
) == VALLOC_DIVHI
)
3919 fprintf (dump_file
, "Resetting origin of AX/DE for DIVHI pattern.\n");
3921 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3926 || origins
[i
] == A_REG
3927 || origins
[i
] == X_REG
3928 || origins
[i
] == D_REG
3929 || origins
[i
] == E_REG
)
3935 else if (get_attr_valloc (insn
) == VALLOC_DIVSI
)
3938 fprintf (dump_file
, "Resetting origin of AX/BC/DE/HL for DIVSI pattern.\n");
3940 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3941 if (i
<= 7 || origins
[i
] <= 7)
3948 if (GET_CODE (src
) == ASHIFT
3949 || GET_CODE (src
) == ASHIFTRT
3950 || GET_CODE (src
) == LSHIFTRT
)
3952 rtx count
= XEXP (src
, 1);
3954 if (GET_CODE (count
) == REG
)
3956 /* Special case - our pattern clobbers the count register. */
3957 int r
= REGNO (count
);
3960 fprintf (dump_file
, "Resetting origin of r%d for shift.\n", r
);
3962 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
3963 if (i
== r
|| origins
[i
] == r
)
3972 /* The idea behind this optimization is to look for cases where we
3973 move data from A to B to C, and instead move from A to B, and A to
3974 C. If B is a virtual register or memory, this is a big win on its
3975 own. If B turns out to be unneeded after this, it's a bigger win.
3976 For each register, we try to determine where it's value originally
3977 came from, if it's propogated purely through moves (and not
3978 computes). The ORIGINS[] array has the regno for the "origin" of
3979 the value in the [regno] it's indexed by. */
3981 rl78_propogate_register_origins (void)
3983 int origins
[FIRST_PSEUDO_REGISTER
];
3984 int age
[FIRST_PSEUDO_REGISTER
];
3986 rtx_insn
*insn
, *ninsn
= NULL
;
3989 reset_origins (origins
, age
);
3991 for (insn
= get_insns (); insn
; insn
= ninsn
)
3993 ninsn
= next_nonnote_nondebug_insn (insn
);
3997 fprintf (dump_file
, "\n");
3998 fprintf (dump_file
, "Origins:");
3999 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
4000 if (origins
[i
] != i
)
4001 fprintf (dump_file
, " r%d=r%d", i
, origins
[i
]);
4002 fprintf (dump_file
, "\n");
4003 print_rtl_single (dump_file
, insn
);
4006 switch (GET_CODE (insn
))
4012 reset_origins (origins
, age
);
4019 pat
= PATTERN (insn
);
4021 if (GET_CODE (pat
) == PARALLEL
)
4023 rtx clobber
= XVECEXP (pat
, 0, 1);
4024 pat
= XVECEXP (pat
, 0, 0);
4025 if (GET_CODE (clobber
) == CLOBBER
4026 && GET_CODE (XEXP (clobber
, 0)) == REG
)
4028 int cr
= REGNO (XEXP (clobber
, 0));
4029 int mb
= GET_MODE_SIZE (GET_MODE (XEXP (clobber
, 0)));
4031 fprintf (dump_file
, "reset origins of %d regs at %d\n", mb
, cr
);
4032 for (i
= 0; i
< mb
; i
++)
4034 origins
[cr
+ i
] = cr
+ i
;
4038 /* This happens with the DIV patterns. */
4039 else if (GET_CODE (clobber
) == SET
)
4041 set_origin (clobber
, insn
, origins
, age
);
4047 if (GET_CODE (pat
) == SET
)
4049 set_origin (pat
, insn
, origins
, age
);
4051 else if (GET_CODE (pat
) == CLOBBER
4052 && GET_CODE (XEXP (pat
, 0)) == REG
)
4054 if (REG_P (XEXP (pat
, 0)))
4056 unsigned int reg
= REGNO (XEXP (pat
, 0));
4066 /* Remove any SETs where the destination is unneeded. */
4068 rl78_remove_unused_sets (void)
4070 rtx_insn
*insn
, *ninsn
= NULL
;
4073 for (insn
= get_insns (); insn
; insn
= ninsn
)
4075 ninsn
= next_nonnote_nondebug_insn (insn
);
4077 rtx set
= single_set (insn
);
4081 dest
= SET_DEST (set
);
4083 if (GET_CODE (dest
) != REG
|| REGNO (dest
) > 23)
4086 if (find_regno_note (insn
, REG_UNUSED
, REGNO (dest
)))
4089 fprintf (dump_file
, "deleting because the set register is never used.\n");
4095 /* This is the top of the devritualization pass. */
4099 /* split2 only happens when optimizing, but we need all movSIs to be
4104 rl78_alloc_physical_registers ();
4108 fprintf (dump_file
, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
4109 print_rtl_with_bb (dump_file
, get_insns (), 0);
4112 rl78_propogate_register_origins ();
4113 rl78_calculate_death_notes ();
4117 fprintf (dump_file
, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
4118 print_rtl_with_bb (dump_file
, get_insns (), 0);
4119 fprintf (dump_file
, "\n======================================================================\n");
4122 rl78_remove_unused_sets ();
4124 /* The code after devirtualizing has changed so much that at this point
4125 we might as well just rescan everything. Note that
4126 df_rescan_all_insns is not going to help here because it does not
4127 touch the artificial uses and defs. */
4128 df_finish_pass (true);
4130 df_live_add_problem ();
4131 df_scan_alloc (NULL
);
4138 #undef TARGET_RETURN_IN_MEMORY
4139 #define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
4142 rl78_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
4144 const HOST_WIDE_INT size
= int_size_in_bytes (type
);
4145 return (size
== -1 || size
> 8);
4149 #undef TARGET_RTX_COSTS
4150 #define TARGET_RTX_COSTS rl78_rtx_costs
4153 rl78_rtx_costs (rtx x
,
4155 int outer_code ATTRIBUTE_UNUSED
,
4156 int opno ATTRIBUTE_UNUSED
,
4158 bool speed ATTRIBUTE_UNUSED
)
4160 int code
= GET_CODE (x
);
4162 if (code
== IF_THEN_ELSE
)
4164 *total
= COSTS_N_INSNS (10);
4174 *total
= COSTS_N_INSNS (14);
4175 else if (RL78_MUL_G13
)
4176 *total
= COSTS_N_INSNS (29);
4178 *total
= COSTS_N_INSNS (500);
4181 *total
= COSTS_N_INSNS (8);
4186 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
4188 switch (INTVAL (XEXP (x
, 1)))
4190 case 0: *total
= COSTS_N_INSNS (0); break;
4191 case 1: *total
= COSTS_N_INSNS (6); break;
4192 case 2: case 3: case 4: case 5: case 6: case 7:
4193 *total
= COSTS_N_INSNS (10); break;
4194 case 8: *total
= COSTS_N_INSNS (6); break;
4195 case 9: case 10: case 11: case 12: case 13: case 14: case 15:
4196 *total
= COSTS_N_INSNS (10); break;
4197 case 16: *total
= COSTS_N_INSNS (3); break;
4198 case 17: case 18: case 19: case 20: case 21: case 22: case 23:
4199 *total
= COSTS_N_INSNS (4); break;
4200 case 24: *total
= COSTS_N_INSNS (4); break;
4201 case 25: case 26: case 27: case 28: case 29: case 30: case 31:
4202 *total
= COSTS_N_INSNS (5); break;
4206 *total
= COSTS_N_INSNS (10+4*16);
4214 static GTY(()) section
* saddr_section
;
4215 static GTY(()) section
* frodata_section
;
4218 rl78_saddr_p (rtx x
)
4224 if (GET_CODE (x
) == PLUS
)
4226 if (GET_CODE (x
) != SYMBOL_REF
)
4230 if (memcmp (c
, "@s.", 3) == 0)
4241 if (GET_CODE (x
) != CONST_INT
)
4244 if ((INTVAL (x
) & 0xFF00) != 0xFF00)
4250 #undef TARGET_STRIP_NAME_ENCODING
4251 #define TARGET_STRIP_NAME_ENCODING rl78_strip_name_encoding
4254 rl78_strip_name_encoding (const char * sym
)
4260 else if (*sym
== '@' && sym
[2] == '.')
4267 /* Like rl78_strip_name_encoding, but does not strip leading asterisks. This
4268 is important if the stripped name is going to be passed to assemble_name()
4269 as that handles asterisk prefixed names in a special manner. */
4272 rl78_strip_nonasm_name_encoding (const char * sym
)
4276 if (*sym
== '@' && sym
[2] == '.')
4285 rl78_attrlist_to_encoding (tree list
, tree decl ATTRIBUTE_UNUSED
)
4289 if (is_attribute_p ("saddr", TREE_PURPOSE (list
)))
4291 list
= TREE_CHAIN (list
);
4297 #define RL78_ATTRIBUTES(decl) \
4298 (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \
4299 : DECL_ATTRIBUTES (decl) \
4300 ? (DECL_ATTRIBUTES (decl)) \
4301 : TYPE_ATTRIBUTES (TREE_TYPE (decl))
4303 #undef TARGET_ENCODE_SECTION_INFO
4304 #define TARGET_ENCODE_SECTION_INFO rl78_encode_section_info
4307 rl78_encode_section_info (tree decl
, rtx rtl
, int first
)
4310 const char * oldname
;
4315 tree rl78_attributes
;
4320 rtlname
= XEXP (rtl
, 0);
4322 if (GET_CODE (rtlname
) == SYMBOL_REF
)
4323 oldname
= XSTR (rtlname
, 0);
4324 else if (GET_CODE (rtlname
) == MEM
4325 && GET_CODE (XEXP (rtlname
, 0)) == SYMBOL_REF
)
4326 oldname
= XSTR (XEXP (rtlname
, 0), 0);
4330 type
= TREE_TYPE (decl
);
4331 if (type
== error_mark_node
)
4333 if (! DECL_P (decl
))
4335 rl78_attributes
= RL78_ATTRIBUTES (decl
);
4337 encoding
= rl78_attrlist_to_encoding (rl78_attributes
, decl
);
4341 newname
= (char *) alloca (strlen (oldname
) + 4);
4342 sprintf (newname
, "@%c.%s", encoding
, oldname
);
4343 idp
= get_identifier (newname
);
4345 gen_rtx_SYMBOL_REF (Pmode
, IDENTIFIER_POINTER (idp
));
4346 SYMBOL_REF_WEAK (XEXP (rtl
, 0)) = DECL_WEAK (decl
);
4347 SET_SYMBOL_REF_DECL (XEXP (rtl
, 0), decl
);
4351 #undef TARGET_ASM_INIT_SECTIONS
4352 #define TARGET_ASM_INIT_SECTIONS rl78_asm_init_sections
4355 rl78_asm_init_sections (void)
4358 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
4359 "\t.section .saddr,\"aw\",@progbits");
4361 = get_unnamed_section (SECTION_WRITE
, output_section_asm_op
,
4362 "\t.section .frodata,\"aw\",@progbits");
4365 #undef TARGET_ASM_SELECT_SECTION
4366 #define TARGET_ASM_SELECT_SECTION rl78_select_section
4369 rl78_select_section (tree decl
,
4371 unsigned HOST_WIDE_INT align
)
4375 switch (TREE_CODE (decl
))
4378 if (!TREE_READONLY (decl
)
4379 || TREE_SIDE_EFFECTS (decl
)
4380 || !DECL_INITIAL (decl
)
4381 || (DECL_INITIAL (decl
) != error_mark_node
4382 && !TREE_CONSTANT (DECL_INITIAL (decl
))))
4386 if (! TREE_CONSTANT (decl
))
4394 if (TREE_CODE (decl
) == VAR_DECL
)
4396 const char *name
= XSTR (XEXP (DECL_RTL (decl
), 0), 0);
4398 if (name
[0] == '@' && name
[2] == '.')
4402 return saddr_section
;
4405 if (TYPE_ADDR_SPACE (TREE_TYPE (decl
)) == ADDR_SPACE_FAR
4408 return frodata_section
;
4413 return TARGET_ES0
? frodata_section
: readonly_data_section
;
4415 switch (categorize_decl_for_section (decl
, reloc
))
4417 case SECCAT_TEXT
: return text_section
;
4418 case SECCAT_DATA
: return data_section
;
4419 case SECCAT_BSS
: return bss_section
;
4420 case SECCAT_RODATA
: return TARGET_ES0
? frodata_section
: readonly_data_section
;
4422 return default_select_section (decl
, reloc
, align
);
4427 rl78_output_labelref (FILE *file
, const char *str
)
4431 str2
= targetm
.strip_name_encoding (str
);
4433 fputs (user_label_prefix
, file
);
4438 rl78_output_aligned_common (FILE *stream
,
4439 tree decl ATTRIBUTE_UNUSED
,
4441 int size
, int align
, int global
)
4443 /* We intentionally don't use rl78_section_tag() here. */
4444 if (name
[0] == '@' && name
[2] == '.')
4446 const char *sec
= 0;
4450 switch_to_section (saddr_section
);
4459 while (align
> BITS_PER_UNIT
)
4464 name2
= targetm
.strip_name_encoding (name
);
4466 fprintf (stream
, "\t.global\t_%s\n", name2
);
4467 fprintf (stream
, "\t.p2align %d\n", p2align
);
4468 fprintf (stream
, "\t.type\t_%s,@object\n", name2
);
4469 fprintf (stream
, "\t.size\t_%s,%d\n", name2
, size
);
4470 fprintf (stream
, "_%s:\n\t.zero\t%d\n", name2
, size
);
4477 fprintf (stream
, "\t.local\t");
4478 assemble_name (stream
, name
);
4479 fprintf (stream
, "\n");
4481 fprintf (stream
, "\t.comm\t");
4482 assemble_name (stream
, name
);
4483 fprintf (stream
, ",%u,%u\n", size
, align
/ BITS_PER_UNIT
);
4486 #undef TARGET_INSERT_ATTRIBUTES
4487 #define TARGET_INSERT_ATTRIBUTES rl78_insert_attributes
4490 rl78_insert_attributes (tree decl
, tree
*attributes ATTRIBUTE_UNUSED
)
4493 && TREE_CODE (decl
) == VAR_DECL
4494 && TREE_READONLY (decl
)
4495 && TREE_ADDRESSABLE (decl
)
4496 && TYPE_ADDR_SPACE (TREE_TYPE (decl
)) == ADDR_SPACE_GENERIC
)
4498 tree type
= TREE_TYPE (decl
);
4499 tree attr
= TYPE_ATTRIBUTES (type
);
4500 int q
= TYPE_QUALS_NO_ADDR_SPACE (type
) | ENCODE_QUAL_ADDR_SPACE (ADDR_SPACE_FAR
);
4502 TREE_TYPE (decl
) = build_type_attribute_qual_variant (type
, attr
, q
);
4506 #undef TARGET_ASM_INTEGER
4507 #define TARGET_ASM_INTEGER rl78_asm_out_integer
4510 rl78_asm_out_integer (rtx x
, unsigned int size
, int aligned_p
)
4512 if (default_assemble_integer (x
, size
, aligned_p
))
4517 assemble_integer_with_op (".long\t", x
);
4524 #undef TARGET_UNWIND_WORD_MODE
4525 #define TARGET_UNWIND_WORD_MODE rl78_unwind_word_mode
4528 rl78_unwind_word_mode (void)
4533 #ifndef USE_COLLECT2
4534 #undef TARGET_ASM_CONSTRUCTOR
4535 #define TARGET_ASM_CONSTRUCTOR rl78_asm_constructor
4536 #undef TARGET_ASM_DESTRUCTOR
4537 #define TARGET_ASM_DESTRUCTOR rl78_asm_destructor
4540 rl78_asm_ctor_dtor (rtx symbol
, int priority
, bool is_ctor
)
4544 if (priority
!= DEFAULT_INIT_PRIORITY
)
4546 /* This section of the function is based upon code copied
4547 from: gcc/varasm.c:get_cdtor_priority_section(). */
4550 sprintf (buf
, "%s.%.5u", is_ctor
? ".ctors" : ".dtors",
4551 MAX_INIT_PRIORITY
- priority
);
4552 sec
= get_section (buf
, 0, NULL
);
4555 sec
= is_ctor
? ctors_section
: dtors_section
;
4557 assemble_addr_to_section (symbol
, sec
);
4561 rl78_asm_constructor (rtx symbol
, int priority
)
4563 rl78_asm_ctor_dtor (symbol
, priority
, true);
4567 rl78_asm_destructor (rtx symbol
, int priority
)
4569 rl78_asm_ctor_dtor (symbol
, priority
, false);
4571 #endif /* ! USE_COLLECT2 */
4573 /* Scan backwards through the insn chain looking to see if the flags
4574 have been set for a comparison of OP against OPERAND. Start with
4575 the insn *before* the current insn. */
4578 rl78_flags_already_set (rtx op
, rtx operand
)
4580 /* We only track the Z flag. */
4581 if (GET_CODE (op
) != EQ
&& GET_CODE (op
) != NE
)
4584 /* This should not happen, but let's be paranoid. */
4585 if (current_output_insn
== NULL_RTX
)
4591 for (insn
= prev_nonnote_nondebug_insn (current_output_insn
);
4593 insn
= prev_nonnote_nondebug_insn (insn
))
4598 if (! INSN_P (insn
))
4601 /* Make sure that the insn can be recognized. */
4602 if (recog_memoized (insn
) == -1)
4605 enum attr_update_Z updated
= get_attr_update_Z (insn
);
4607 rtx set
= single_set (insn
);
4608 bool must_break
= (set
!= NULL_RTX
&& rtx_equal_p (operand
, SET_DEST (set
)));
4614 case UPDATE_Z_CLOBBER
:
4617 case UPDATE_Z_UPDATE_Z
:
4629 /* We have to re-recognize the current insn as the call(s) to
4630 get_attr_update_Z() above will have overwritten the recog_data cache. */
4631 recog_memoized (current_output_insn
);
4632 cleanup_subreg_operands (current_output_insn
);
4633 constrain_operands_cached (current_output_insn
, 1);
4639 rl78_addsi3_internal (rtx
* operands
, unsigned int alternative
)
4641 /* If we are adding in a constant symbolic address when -mes0
4642 is active then we know that the address must be <64K and
4643 that it is invalid to access anything above 64K relative to
4644 this address. So we can skip adding in the high bytes. */
4646 && GET_CODE (operands
[2]) == SYMBOL_REF
4647 && TREE_CODE (SYMBOL_REF_DECL (operands
[2])) == VAR_DECL
4648 && TREE_READONLY (SYMBOL_REF_DECL (operands
[2]))
4649 && ! TREE_SIDE_EFFECTS (SYMBOL_REF_DECL (operands
[2])))
4650 return "movw ax, %h1\n\taddw ax, %h2\n\tmovw %h0, ax";
4652 switch (alternative
)
4656 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";
4658 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";
4665 #undef TARGET_PREFERRED_RELOAD_CLASS
4666 #define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
4669 rl78_preferred_reload_class (rtx x ATTRIBUTE_UNUSED
, reg_class_t rclass
)
4671 if (rclass
== NO_REGS
)
4678 struct gcc_target targetm
= TARGET_INITIALIZER
;
4680 #include "gt-rl78.h"