136ac495dSmrg /* Subroutines used for code generation on the Renesas M32R cpu.
2*8feb0f0bSmrg Copyright (C) 1996-2020 Free Software Foundation, Inc.
336ac495dSmrg
436ac495dSmrg This file is part of GCC.
536ac495dSmrg
636ac495dSmrg GCC is free software; you can redistribute it and/or modify it
736ac495dSmrg under the terms of the GNU General Public License as published
836ac495dSmrg by the Free Software Foundation; either version 3, or (at your
936ac495dSmrg option) any later version.
1036ac495dSmrg
1136ac495dSmrg GCC is distributed in the hope that it will be useful, but WITHOUT
1236ac495dSmrg ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1336ac495dSmrg or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
1436ac495dSmrg License for more details.
1536ac495dSmrg
1636ac495dSmrg You should have received a copy of the GNU General Public License
1736ac495dSmrg along with GCC; see the file COPYING3. If not see
1836ac495dSmrg <http://www.gnu.org/licenses/>. */
1936ac495dSmrg
20a2dc1f3fSmrg #define IN_TARGET_CODE 1
21a2dc1f3fSmrg
2236ac495dSmrg #include "config.h"
2336ac495dSmrg #include "system.h"
2436ac495dSmrg #include "coretypes.h"
2536ac495dSmrg #include "backend.h"
2636ac495dSmrg #include "target.h"
2736ac495dSmrg #include "rtl.h"
2836ac495dSmrg #include "tree.h"
2936ac495dSmrg #include "df.h"
3036ac495dSmrg #include "memmodel.h"
3136ac495dSmrg #include "tm_p.h"
3236ac495dSmrg #include "stringpool.h"
33a2dc1f3fSmrg #include "attribs.h"
3436ac495dSmrg #include "insn-config.h"
3536ac495dSmrg #include "emit-rtl.h"
3636ac495dSmrg #include "recog.h"
3736ac495dSmrg #include "diagnostic-core.h"
3836ac495dSmrg #include "alias.h"
3936ac495dSmrg #include "stor-layout.h"
4036ac495dSmrg #include "varasm.h"
4136ac495dSmrg #include "calls.h"
4236ac495dSmrg #include "output.h"
4336ac495dSmrg #include "insn-attr.h"
4436ac495dSmrg #include "explow.h"
4536ac495dSmrg #include "expr.h"
4636ac495dSmrg #include "tm-constrs.h"
4736ac495dSmrg #include "builtins.h"
4836ac495dSmrg
4936ac495dSmrg /* This file should be included last. */
5036ac495dSmrg #include "target-def.h"
5136ac495dSmrg
5236ac495dSmrg /* Array of valid operand punctuation characters. */
5336ac495dSmrg static char m32r_punct_chars[256];
5436ac495dSmrg
5536ac495dSmrg /* Machine-specific symbol_ref flags. */
5636ac495dSmrg #define SYMBOL_FLAG_MODEL_SHIFT SYMBOL_FLAG_MACH_DEP_SHIFT
5736ac495dSmrg #define SYMBOL_REF_MODEL(X) \
5836ac495dSmrg ((enum m32r_model) ((SYMBOL_REF_FLAGS (X) >> SYMBOL_FLAG_MODEL_SHIFT) & 3))
5936ac495dSmrg
6036ac495dSmrg /* For string literals, etc. */
6136ac495dSmrg #define LIT_NAME_P(NAME) ((NAME)[0] == '*' && (NAME)[1] == '.')
6236ac495dSmrg
6336ac495dSmrg /* Forward declaration. */
6436ac495dSmrg static void m32r_option_override (void);
6536ac495dSmrg static void init_reg_tables (void);
6636ac495dSmrg static void block_move_call (rtx, rtx, rtx);
6736ac495dSmrg static int m32r_is_insn (rtx);
6836ac495dSmrg static bool m32r_legitimate_address_p (machine_mode, rtx, bool);
6936ac495dSmrg static rtx m32r_legitimize_address (rtx, rtx, machine_mode);
7036ac495dSmrg static bool m32r_mode_dependent_address_p (const_rtx, addr_space_t);
7136ac495dSmrg static tree m32r_handle_model_attribute (tree *, tree, tree, int, bool *);
7236ac495dSmrg static void m32r_print_operand (FILE *, rtx, int);
7336ac495dSmrg static void m32r_print_operand_address (FILE *, machine_mode, rtx);
7436ac495dSmrg static bool m32r_print_operand_punct_valid_p (unsigned char code);
75a2dc1f3fSmrg static void m32r_output_function_prologue (FILE *);
76a2dc1f3fSmrg static void m32r_output_function_epilogue (FILE *);
7736ac495dSmrg
7836ac495dSmrg static void m32r_file_start (void);
7936ac495dSmrg
8036ac495dSmrg static int m32r_adjust_priority (rtx_insn *, int);
8136ac495dSmrg static int m32r_issue_rate (void);
8236ac495dSmrg
8336ac495dSmrg static void m32r_encode_section_info (tree, rtx, int);
8436ac495dSmrg static bool m32r_in_small_data_p (const_tree);
8536ac495dSmrg static bool m32r_return_in_memory (const_tree, const_tree);
8636ac495dSmrg static rtx m32r_function_value (const_tree, const_tree, bool);
8736ac495dSmrg static rtx m32r_libcall_value (machine_mode, const_rtx);
8836ac495dSmrg static bool m32r_function_value_regno_p (const unsigned int);
89*8feb0f0bSmrg static void m32r_setup_incoming_varargs (cumulative_args_t,
90*8feb0f0bSmrg const function_arg_info &,
91*8feb0f0bSmrg int *, int);
9236ac495dSmrg static void init_idents (void);
9336ac495dSmrg static bool m32r_rtx_costs (rtx, machine_mode, int, int, int *, bool speed);
9436ac495dSmrg static int m32r_memory_move_cost (machine_mode, reg_class_t, bool);
95*8feb0f0bSmrg static bool m32r_pass_by_reference (cumulative_args_t,
96*8feb0f0bSmrg const function_arg_info &arg);
97*8feb0f0bSmrg static int m32r_arg_partial_bytes (cumulative_args_t,
98*8feb0f0bSmrg const function_arg_info &);
99*8feb0f0bSmrg static rtx m32r_function_arg (cumulative_args_t, const function_arg_info &);
100*8feb0f0bSmrg static void m32r_function_arg_advance (cumulative_args_t,
101*8feb0f0bSmrg const function_arg_info &);
10236ac495dSmrg static bool m32r_can_eliminate (const int, const int);
10336ac495dSmrg static void m32r_conditional_register_usage (void);
10436ac495dSmrg static void m32r_trampoline_init (rtx, tree, rtx);
10536ac495dSmrg static bool m32r_legitimate_constant_p (machine_mode, rtx);
10636ac495dSmrg static bool m32r_attribute_identifier (const_tree);
107a2dc1f3fSmrg static bool m32r_hard_regno_mode_ok (unsigned int, machine_mode);
108a2dc1f3fSmrg static bool m32r_modes_tieable_p (machine_mode, machine_mode);
109a2dc1f3fSmrg static HOST_WIDE_INT m32r_starting_frame_offset (void);
11036ac495dSmrg
11136ac495dSmrg /* M32R specific attributes. */
11236ac495dSmrg
11336ac495dSmrg static const struct attribute_spec m32r_attribute_table[] =
11436ac495dSmrg {
115a2dc1f3fSmrg /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
116a2dc1f3fSmrg affects_type_identity, handler, exclude } */
117a2dc1f3fSmrg { "interrupt", 0, 0, true, false, false, false, NULL, NULL },
118a2dc1f3fSmrg { "model", 1, 1, true, false, false, false, m32r_handle_model_attribute,
119a2dc1f3fSmrg NULL },
120a2dc1f3fSmrg { NULL, 0, 0, false, false, false, false, NULL, NULL }
12136ac495dSmrg };
12236ac495dSmrg
12336ac495dSmrg /* Initialize the GCC target structure. */
12436ac495dSmrg #undef TARGET_ATTRIBUTE_TABLE
12536ac495dSmrg #define TARGET_ATTRIBUTE_TABLE m32r_attribute_table
12636ac495dSmrg #undef TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P
12736ac495dSmrg #define TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P m32r_attribute_identifier
12836ac495dSmrg
12936ac495dSmrg #undef TARGET_LRA_P
13036ac495dSmrg #define TARGET_LRA_P hook_bool_void_false
13136ac495dSmrg
13236ac495dSmrg #undef TARGET_LEGITIMATE_ADDRESS_P
13336ac495dSmrg #define TARGET_LEGITIMATE_ADDRESS_P m32r_legitimate_address_p
13436ac495dSmrg #undef TARGET_LEGITIMIZE_ADDRESS
13536ac495dSmrg #define TARGET_LEGITIMIZE_ADDRESS m32r_legitimize_address
13636ac495dSmrg #undef TARGET_MODE_DEPENDENT_ADDRESS_P
13736ac495dSmrg #define TARGET_MODE_DEPENDENT_ADDRESS_P m32r_mode_dependent_address_p
13836ac495dSmrg
13936ac495dSmrg #undef TARGET_ASM_ALIGNED_HI_OP
14036ac495dSmrg #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
14136ac495dSmrg #undef TARGET_ASM_ALIGNED_SI_OP
14236ac495dSmrg #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
14336ac495dSmrg
14436ac495dSmrg #undef TARGET_PRINT_OPERAND
14536ac495dSmrg #define TARGET_PRINT_OPERAND m32r_print_operand
14636ac495dSmrg #undef TARGET_PRINT_OPERAND_ADDRESS
14736ac495dSmrg #define TARGET_PRINT_OPERAND_ADDRESS m32r_print_operand_address
14836ac495dSmrg #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
14936ac495dSmrg #define TARGET_PRINT_OPERAND_PUNCT_VALID_P m32r_print_operand_punct_valid_p
15036ac495dSmrg
15136ac495dSmrg #undef TARGET_ASM_FUNCTION_PROLOGUE
15236ac495dSmrg #define TARGET_ASM_FUNCTION_PROLOGUE m32r_output_function_prologue
15336ac495dSmrg #undef TARGET_ASM_FUNCTION_EPILOGUE
15436ac495dSmrg #define TARGET_ASM_FUNCTION_EPILOGUE m32r_output_function_epilogue
15536ac495dSmrg
15636ac495dSmrg #undef TARGET_ASM_FILE_START
15736ac495dSmrg #define TARGET_ASM_FILE_START m32r_file_start
15836ac495dSmrg
15936ac495dSmrg #undef TARGET_SCHED_ADJUST_PRIORITY
16036ac495dSmrg #define TARGET_SCHED_ADJUST_PRIORITY m32r_adjust_priority
16136ac495dSmrg #undef TARGET_SCHED_ISSUE_RATE
16236ac495dSmrg #define TARGET_SCHED_ISSUE_RATE m32r_issue_rate
16336ac495dSmrg
16436ac495dSmrg #undef TARGET_OPTION_OVERRIDE
16536ac495dSmrg #define TARGET_OPTION_OVERRIDE m32r_option_override
16636ac495dSmrg
16736ac495dSmrg #undef TARGET_ENCODE_SECTION_INFO
16836ac495dSmrg #define TARGET_ENCODE_SECTION_INFO m32r_encode_section_info
16936ac495dSmrg #undef TARGET_IN_SMALL_DATA_P
17036ac495dSmrg #define TARGET_IN_SMALL_DATA_P m32r_in_small_data_p
17136ac495dSmrg
17236ac495dSmrg
17336ac495dSmrg #undef TARGET_MEMORY_MOVE_COST
17436ac495dSmrg #define TARGET_MEMORY_MOVE_COST m32r_memory_move_cost
17536ac495dSmrg #undef TARGET_RTX_COSTS
17636ac495dSmrg #define TARGET_RTX_COSTS m32r_rtx_costs
17736ac495dSmrg #undef TARGET_ADDRESS_COST
17836ac495dSmrg #define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
17936ac495dSmrg
18036ac495dSmrg #undef TARGET_PROMOTE_PROTOTYPES
18136ac495dSmrg #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
18236ac495dSmrg #undef TARGET_RETURN_IN_MEMORY
18336ac495dSmrg #define TARGET_RETURN_IN_MEMORY m32r_return_in_memory
18436ac495dSmrg
18536ac495dSmrg #undef TARGET_FUNCTION_VALUE
18636ac495dSmrg #define TARGET_FUNCTION_VALUE m32r_function_value
18736ac495dSmrg #undef TARGET_LIBCALL_VALUE
18836ac495dSmrg #define TARGET_LIBCALL_VALUE m32r_libcall_value
18936ac495dSmrg #undef TARGET_FUNCTION_VALUE_REGNO_P
19036ac495dSmrg #define TARGET_FUNCTION_VALUE_REGNO_P m32r_function_value_regno_p
19136ac495dSmrg
19236ac495dSmrg #undef TARGET_SETUP_INCOMING_VARARGS
19336ac495dSmrg #define TARGET_SETUP_INCOMING_VARARGS m32r_setup_incoming_varargs
19436ac495dSmrg #undef TARGET_MUST_PASS_IN_STACK
19536ac495dSmrg #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
19636ac495dSmrg #undef TARGET_PASS_BY_REFERENCE
19736ac495dSmrg #define TARGET_PASS_BY_REFERENCE m32r_pass_by_reference
19836ac495dSmrg #undef TARGET_ARG_PARTIAL_BYTES
19936ac495dSmrg #define TARGET_ARG_PARTIAL_BYTES m32r_arg_partial_bytes
20036ac495dSmrg #undef TARGET_FUNCTION_ARG
20136ac495dSmrg #define TARGET_FUNCTION_ARG m32r_function_arg
20236ac495dSmrg #undef TARGET_FUNCTION_ARG_ADVANCE
20336ac495dSmrg #define TARGET_FUNCTION_ARG_ADVANCE m32r_function_arg_advance
20436ac495dSmrg
20536ac495dSmrg #undef TARGET_CAN_ELIMINATE
20636ac495dSmrg #define TARGET_CAN_ELIMINATE m32r_can_eliminate
20736ac495dSmrg
20836ac495dSmrg #undef TARGET_CONDITIONAL_REGISTER_USAGE
20936ac495dSmrg #define TARGET_CONDITIONAL_REGISTER_USAGE m32r_conditional_register_usage
21036ac495dSmrg
21136ac495dSmrg #undef TARGET_TRAMPOLINE_INIT
21236ac495dSmrg #define TARGET_TRAMPOLINE_INIT m32r_trampoline_init
21336ac495dSmrg
21436ac495dSmrg #undef TARGET_LEGITIMATE_CONSTANT_P
21536ac495dSmrg #define TARGET_LEGITIMATE_CONSTANT_P m32r_legitimate_constant_p
21636ac495dSmrg
217a2dc1f3fSmrg #undef TARGET_HARD_REGNO_MODE_OK
218a2dc1f3fSmrg #define TARGET_HARD_REGNO_MODE_OK m32r_hard_regno_mode_ok
219a2dc1f3fSmrg
220a2dc1f3fSmrg #undef TARGET_MODES_TIEABLE_P
221a2dc1f3fSmrg #define TARGET_MODES_TIEABLE_P m32r_modes_tieable_p
222a2dc1f3fSmrg
223a2dc1f3fSmrg #undef TARGET_CONSTANT_ALIGNMENT
224a2dc1f3fSmrg #define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
225a2dc1f3fSmrg
226a2dc1f3fSmrg #undef TARGET_STARTING_FRAME_OFFSET
227a2dc1f3fSmrg #define TARGET_STARTING_FRAME_OFFSET m32r_starting_frame_offset
228a2dc1f3fSmrg
229c0a68be4Smrg #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
230c0a68be4Smrg #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
231c0a68be4Smrg
23236ac495dSmrg struct gcc_target targetm = TARGET_INITIALIZER;
23336ac495dSmrg
23436ac495dSmrg /* Called by m32r_option_override to initialize various things. */
23536ac495dSmrg
23636ac495dSmrg void
m32r_init(void)23736ac495dSmrg m32r_init (void)
23836ac495dSmrg {
23936ac495dSmrg init_reg_tables ();
24036ac495dSmrg
24136ac495dSmrg /* Initialize array for TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
24236ac495dSmrg memset (m32r_punct_chars, 0, sizeof (m32r_punct_chars));
24336ac495dSmrg m32r_punct_chars['#'] = 1;
24436ac495dSmrg m32r_punct_chars['@'] = 1; /* ??? no longer used */
24536ac495dSmrg
24636ac495dSmrg /* Provide default value if not specified. */
24736ac495dSmrg if (!global_options_set.x_g_switch_value)
24836ac495dSmrg g_switch_value = SDATA_DEFAULT_SIZE;
24936ac495dSmrg }
25036ac495dSmrg
25136ac495dSmrg static void
m32r_option_override(void)25236ac495dSmrg m32r_option_override (void)
25336ac495dSmrg {
25436ac495dSmrg /* These need to be done at start up.
25536ac495dSmrg It's convenient to do them here. */
25636ac495dSmrg m32r_init ();
25736ac495dSmrg SUBTARGET_OVERRIDE_OPTIONS;
25836ac495dSmrg }
25936ac495dSmrg
26036ac495dSmrg /* Vectors to keep interesting information about registers where it can easily
26136ac495dSmrg be got. We use to use the actual mode value as the bit number, but there
26236ac495dSmrg is (or may be) more than 32 modes now. Instead we use two tables: one
26336ac495dSmrg indexed by hard register number, and one indexed by mode. */
26436ac495dSmrg
26536ac495dSmrg /* The purpose of m32r_mode_class is to shrink the range of modes so that
26636ac495dSmrg they all fit (as bit numbers) in a 32-bit word (again). Each real mode is
26736ac495dSmrg mapped into one m32r_mode_class mode. */
26836ac495dSmrg
26936ac495dSmrg enum m32r_mode_class
27036ac495dSmrg {
27136ac495dSmrg C_MODE,
27236ac495dSmrg S_MODE, D_MODE, T_MODE, O_MODE,
27336ac495dSmrg SF_MODE, DF_MODE, TF_MODE, OF_MODE, A_MODE
27436ac495dSmrg };
27536ac495dSmrg
27636ac495dSmrg /* Modes for condition codes. */
27736ac495dSmrg #define C_MODES (1 << (int) C_MODE)
27836ac495dSmrg
27936ac495dSmrg /* Modes for single-word and smaller quantities. */
28036ac495dSmrg #define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
28136ac495dSmrg
28236ac495dSmrg /* Modes for double-word and smaller quantities. */
28336ac495dSmrg #define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
28436ac495dSmrg
28536ac495dSmrg /* Modes for quad-word and smaller quantities. */
28636ac495dSmrg #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
28736ac495dSmrg
28836ac495dSmrg /* Modes for accumulators. */
28936ac495dSmrg #define A_MODES (1 << (int) A_MODE)
29036ac495dSmrg
29136ac495dSmrg /* Value is 1 if register/mode pair is acceptable on arc. */
29236ac495dSmrg
293a2dc1f3fSmrg static const unsigned int m32r_hard_regno_modes[FIRST_PSEUDO_REGISTER] =
29436ac495dSmrg {
29536ac495dSmrg T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, T_MODES,
29636ac495dSmrg T_MODES, T_MODES, T_MODES, T_MODES, T_MODES, S_MODES, S_MODES, S_MODES,
29736ac495dSmrg S_MODES, C_MODES, A_MODES, A_MODES
29836ac495dSmrg };
29936ac495dSmrg
300a2dc1f3fSmrg static unsigned int m32r_mode_class [NUM_MACHINE_MODES];
30136ac495dSmrg
30236ac495dSmrg enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
30336ac495dSmrg
30436ac495dSmrg static void
init_reg_tables(void)30536ac495dSmrg init_reg_tables (void)
30636ac495dSmrg {
30736ac495dSmrg int i;
30836ac495dSmrg
30936ac495dSmrg for (i = 0; i < NUM_MACHINE_MODES; i++)
31036ac495dSmrg {
31136ac495dSmrg machine_mode m = (machine_mode) i;
31236ac495dSmrg
31336ac495dSmrg switch (GET_MODE_CLASS (m))
31436ac495dSmrg {
31536ac495dSmrg case MODE_INT:
31636ac495dSmrg case MODE_PARTIAL_INT:
31736ac495dSmrg case MODE_COMPLEX_INT:
31836ac495dSmrg if (GET_MODE_SIZE (m) <= 4)
31936ac495dSmrg m32r_mode_class[i] = 1 << (int) S_MODE;
32036ac495dSmrg else if (GET_MODE_SIZE (m) == 8)
32136ac495dSmrg m32r_mode_class[i] = 1 << (int) D_MODE;
32236ac495dSmrg else if (GET_MODE_SIZE (m) == 16)
32336ac495dSmrg m32r_mode_class[i] = 1 << (int) T_MODE;
32436ac495dSmrg else if (GET_MODE_SIZE (m) == 32)
32536ac495dSmrg m32r_mode_class[i] = 1 << (int) O_MODE;
32636ac495dSmrg else
32736ac495dSmrg m32r_mode_class[i] = 0;
32836ac495dSmrg break;
32936ac495dSmrg case MODE_FLOAT:
33036ac495dSmrg case MODE_COMPLEX_FLOAT:
33136ac495dSmrg if (GET_MODE_SIZE (m) <= 4)
33236ac495dSmrg m32r_mode_class[i] = 1 << (int) SF_MODE;
33336ac495dSmrg else if (GET_MODE_SIZE (m) == 8)
33436ac495dSmrg m32r_mode_class[i] = 1 << (int) DF_MODE;
33536ac495dSmrg else if (GET_MODE_SIZE (m) == 16)
33636ac495dSmrg m32r_mode_class[i] = 1 << (int) TF_MODE;
33736ac495dSmrg else if (GET_MODE_SIZE (m) == 32)
33836ac495dSmrg m32r_mode_class[i] = 1 << (int) OF_MODE;
33936ac495dSmrg else
34036ac495dSmrg m32r_mode_class[i] = 0;
34136ac495dSmrg break;
34236ac495dSmrg case MODE_CC:
34336ac495dSmrg m32r_mode_class[i] = 1 << (int) C_MODE;
34436ac495dSmrg break;
34536ac495dSmrg default:
34636ac495dSmrg m32r_mode_class[i] = 0;
34736ac495dSmrg break;
34836ac495dSmrg }
34936ac495dSmrg }
35036ac495dSmrg
35136ac495dSmrg for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
35236ac495dSmrg {
35336ac495dSmrg if (GPR_P (i))
35436ac495dSmrg m32r_regno_reg_class[i] = GENERAL_REGS;
35536ac495dSmrg else if (i == ARG_POINTER_REGNUM)
35636ac495dSmrg m32r_regno_reg_class[i] = GENERAL_REGS;
35736ac495dSmrg else
35836ac495dSmrg m32r_regno_reg_class[i] = NO_REGS;
35936ac495dSmrg }
36036ac495dSmrg }
36136ac495dSmrg
36236ac495dSmrg /* M32R specific attribute support.
36336ac495dSmrg
36436ac495dSmrg interrupt - for interrupt functions
36536ac495dSmrg
36636ac495dSmrg model - select code model used to access object
36736ac495dSmrg
36836ac495dSmrg small: addresses use 24 bits, use bl to make calls
36936ac495dSmrg medium: addresses use 32 bits, use bl to make calls
37036ac495dSmrg large: addresses use 32 bits, use seth/add3/jl to make calls
37136ac495dSmrg
37236ac495dSmrg Grep for MODEL in m32r.h for more info. */
37336ac495dSmrg
37436ac495dSmrg static tree small_ident1;
37536ac495dSmrg static tree small_ident2;
37636ac495dSmrg static tree medium_ident1;
37736ac495dSmrg static tree medium_ident2;
37836ac495dSmrg static tree large_ident1;
37936ac495dSmrg static tree large_ident2;
38036ac495dSmrg
38136ac495dSmrg static void
init_idents(void)38236ac495dSmrg init_idents (void)
38336ac495dSmrg {
38436ac495dSmrg if (small_ident1 == 0)
38536ac495dSmrg {
38636ac495dSmrg small_ident1 = get_identifier ("small");
38736ac495dSmrg small_ident2 = get_identifier ("__small__");
38836ac495dSmrg medium_ident1 = get_identifier ("medium");
38936ac495dSmrg medium_ident2 = get_identifier ("__medium__");
39036ac495dSmrg large_ident1 = get_identifier ("large");
39136ac495dSmrg large_ident2 = get_identifier ("__large__");
39236ac495dSmrg }
39336ac495dSmrg }
39436ac495dSmrg
39536ac495dSmrg /* Handle an "model" attribute; arguments as in
39636ac495dSmrg struct attribute_spec.handler. */
39736ac495dSmrg static tree
m32r_handle_model_attribute(tree * node ATTRIBUTE_UNUSED,tree name,tree args,int flags ATTRIBUTE_UNUSED,bool * no_add_attrs)39836ac495dSmrg m32r_handle_model_attribute (tree *node ATTRIBUTE_UNUSED, tree name,
39936ac495dSmrg tree args, int flags ATTRIBUTE_UNUSED,
40036ac495dSmrg bool *no_add_attrs)
40136ac495dSmrg {
40236ac495dSmrg tree arg;
40336ac495dSmrg
40436ac495dSmrg init_idents ();
40536ac495dSmrg arg = TREE_VALUE (args);
40636ac495dSmrg
40736ac495dSmrg if (arg != small_ident1
40836ac495dSmrg && arg != small_ident2
40936ac495dSmrg && arg != medium_ident1
41036ac495dSmrg && arg != medium_ident2
41136ac495dSmrg && arg != large_ident1
41236ac495dSmrg && arg != large_ident2)
41336ac495dSmrg {
41436ac495dSmrg warning (OPT_Wattributes, "invalid argument of %qs attribute",
41536ac495dSmrg IDENTIFIER_POINTER (name));
41636ac495dSmrg *no_add_attrs = true;
41736ac495dSmrg }
41836ac495dSmrg
41936ac495dSmrg return NULL_TREE;
42036ac495dSmrg }
42136ac495dSmrg
42236ac495dSmrg static bool
m32r_attribute_identifier(const_tree name)42336ac495dSmrg m32r_attribute_identifier (const_tree name)
42436ac495dSmrg {
42536ac495dSmrg return strcmp (IDENTIFIER_POINTER (name), "model") == 0
42636ac495dSmrg || strcmp (IDENTIFIER_POINTER (name), "__model__") == 0;
42736ac495dSmrg }
42836ac495dSmrg
42936ac495dSmrg /* Encode section information of DECL, which is either a VAR_DECL,
43036ac495dSmrg FUNCTION_DECL, STRING_CST, CONSTRUCTOR, or ???.
43136ac495dSmrg
43236ac495dSmrg For the M32R we want to record:
43336ac495dSmrg
43436ac495dSmrg - whether the object lives in .sdata/.sbss.
43536ac495dSmrg - what code model should be used to access the object
43636ac495dSmrg */
43736ac495dSmrg
43836ac495dSmrg static void
m32r_encode_section_info(tree decl,rtx rtl,int first)43936ac495dSmrg m32r_encode_section_info (tree decl, rtx rtl, int first)
44036ac495dSmrg {
44136ac495dSmrg int extra_flags = 0;
44236ac495dSmrg tree model_attr;
44336ac495dSmrg enum m32r_model model;
44436ac495dSmrg
44536ac495dSmrg default_encode_section_info (decl, rtl, first);
44636ac495dSmrg
44736ac495dSmrg if (!DECL_P (decl))
44836ac495dSmrg return;
44936ac495dSmrg
45036ac495dSmrg model_attr = lookup_attribute ("model", DECL_ATTRIBUTES (decl));
45136ac495dSmrg if (model_attr)
45236ac495dSmrg {
45336ac495dSmrg tree id;
45436ac495dSmrg
45536ac495dSmrg init_idents ();
45636ac495dSmrg
45736ac495dSmrg id = TREE_VALUE (TREE_VALUE (model_attr));
45836ac495dSmrg
45936ac495dSmrg if (id == small_ident1 || id == small_ident2)
46036ac495dSmrg model = M32R_MODEL_SMALL;
46136ac495dSmrg else if (id == medium_ident1 || id == medium_ident2)
46236ac495dSmrg model = M32R_MODEL_MEDIUM;
46336ac495dSmrg else if (id == large_ident1 || id == large_ident2)
46436ac495dSmrg model = M32R_MODEL_LARGE;
46536ac495dSmrg else
46636ac495dSmrg gcc_unreachable (); /* shouldn't happen */
46736ac495dSmrg }
46836ac495dSmrg else
46936ac495dSmrg {
47036ac495dSmrg if (TARGET_MODEL_SMALL)
47136ac495dSmrg model = M32R_MODEL_SMALL;
47236ac495dSmrg else if (TARGET_MODEL_MEDIUM)
47336ac495dSmrg model = M32R_MODEL_MEDIUM;
47436ac495dSmrg else if (TARGET_MODEL_LARGE)
47536ac495dSmrg model = M32R_MODEL_LARGE;
47636ac495dSmrg else
47736ac495dSmrg gcc_unreachable (); /* shouldn't happen */
47836ac495dSmrg }
47936ac495dSmrg extra_flags |= model << SYMBOL_FLAG_MODEL_SHIFT;
48036ac495dSmrg
48136ac495dSmrg if (extra_flags)
48236ac495dSmrg SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= extra_flags;
48336ac495dSmrg }
48436ac495dSmrg
48536ac495dSmrg /* Only mark the object as being small data area addressable if
48636ac495dSmrg it hasn't been explicitly marked with a code model.
48736ac495dSmrg
48836ac495dSmrg The user can explicitly put an object in the small data area with the
48936ac495dSmrg section attribute. If the object is in sdata/sbss and marked with a
49036ac495dSmrg code model do both [put the object in .sdata and mark it as being
49136ac495dSmrg addressed with a specific code model - don't mark it as being addressed
49236ac495dSmrg with an SDA reloc though]. This is ok and might be useful at times. If
49336ac495dSmrg the object doesn't fit the linker will give an error. */
49436ac495dSmrg
49536ac495dSmrg static bool
m32r_in_small_data_p(const_tree decl)49636ac495dSmrg m32r_in_small_data_p (const_tree decl)
49736ac495dSmrg {
49836ac495dSmrg const char *section;
49936ac495dSmrg
50036ac495dSmrg if (TREE_CODE (decl) != VAR_DECL)
50136ac495dSmrg return false;
50236ac495dSmrg
50336ac495dSmrg if (lookup_attribute ("model", DECL_ATTRIBUTES (decl)))
50436ac495dSmrg return false;
50536ac495dSmrg
50636ac495dSmrg section = DECL_SECTION_NAME (decl);
50736ac495dSmrg if (section)
50836ac495dSmrg {
50936ac495dSmrg if (strcmp (section, ".sdata") == 0 || strcmp (section, ".sbss") == 0)
51036ac495dSmrg return true;
51136ac495dSmrg }
51236ac495dSmrg else
51336ac495dSmrg {
51436ac495dSmrg if (! TREE_READONLY (decl) && ! TARGET_SDATA_NONE)
51536ac495dSmrg {
51636ac495dSmrg int size = int_size_in_bytes (TREE_TYPE (decl));
51736ac495dSmrg
51836ac495dSmrg if (size > 0 && size <= g_switch_value)
51936ac495dSmrg return true;
52036ac495dSmrg }
52136ac495dSmrg }
52236ac495dSmrg
52336ac495dSmrg return false;
52436ac495dSmrg }
52536ac495dSmrg
52636ac495dSmrg /* Do anything needed before RTL is emitted for each function. */
52736ac495dSmrg
52836ac495dSmrg void
m32r_init_expanders(void)52936ac495dSmrg m32r_init_expanders (void)
53036ac495dSmrg {
53136ac495dSmrg /* ??? At one point there was code here. The function is left in
53236ac495dSmrg to make it easy to experiment. */
53336ac495dSmrg }
53436ac495dSmrg
53536ac495dSmrg int
call_operand(rtx op,machine_mode mode)53636ac495dSmrg call_operand (rtx op, machine_mode mode)
53736ac495dSmrg {
53836ac495dSmrg if (!MEM_P (op))
53936ac495dSmrg return 0;
54036ac495dSmrg op = XEXP (op, 0);
54136ac495dSmrg return call_address_operand (op, mode);
54236ac495dSmrg }
54336ac495dSmrg
54436ac495dSmrg /* Return 1 if OP is a reference to an object in .sdata/.sbss. */
54536ac495dSmrg
54636ac495dSmrg int
small_data_operand(rtx op,machine_mode mode ATTRIBUTE_UNUSED)54736ac495dSmrg small_data_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
54836ac495dSmrg {
54936ac495dSmrg if (! TARGET_SDATA_USE)
55036ac495dSmrg return 0;
55136ac495dSmrg
55236ac495dSmrg if (GET_CODE (op) == SYMBOL_REF)
55336ac495dSmrg return SYMBOL_REF_SMALL_P (op);
55436ac495dSmrg
55536ac495dSmrg if (GET_CODE (op) == CONST
55636ac495dSmrg && GET_CODE (XEXP (op, 0)) == PLUS
55736ac495dSmrg && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
55836ac495dSmrg && satisfies_constraint_J (XEXP (XEXP (op, 0), 1)))
55936ac495dSmrg return SYMBOL_REF_SMALL_P (XEXP (XEXP (op, 0), 0));
56036ac495dSmrg
56136ac495dSmrg return 0;
56236ac495dSmrg }
56336ac495dSmrg
56436ac495dSmrg /* Return 1 if OP is a symbol that can use 24-bit addressing. */
56536ac495dSmrg
56636ac495dSmrg int
addr24_operand(rtx op,machine_mode mode ATTRIBUTE_UNUSED)56736ac495dSmrg addr24_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
56836ac495dSmrg {
56936ac495dSmrg rtx sym;
57036ac495dSmrg
57136ac495dSmrg if (flag_pic)
57236ac495dSmrg return 0;
57336ac495dSmrg
57436ac495dSmrg if (GET_CODE (op) == LABEL_REF)
57536ac495dSmrg return TARGET_ADDR24;
57636ac495dSmrg
57736ac495dSmrg if (GET_CODE (op) == SYMBOL_REF)
57836ac495dSmrg sym = op;
57936ac495dSmrg else if (GET_CODE (op) == CONST
58036ac495dSmrg && GET_CODE (XEXP (op, 0)) == PLUS
58136ac495dSmrg && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
58236ac495dSmrg && satisfies_constraint_M (XEXP (XEXP (op, 0), 1)))
58336ac495dSmrg sym = XEXP (XEXP (op, 0), 0);
58436ac495dSmrg else
58536ac495dSmrg return 0;
58636ac495dSmrg
58736ac495dSmrg if (SYMBOL_REF_MODEL (sym) == M32R_MODEL_SMALL)
58836ac495dSmrg return 1;
58936ac495dSmrg
59036ac495dSmrg if (TARGET_ADDR24
59136ac495dSmrg && (CONSTANT_POOL_ADDRESS_P (sym)
59236ac495dSmrg || LIT_NAME_P (XSTR (sym, 0))))
59336ac495dSmrg return 1;
59436ac495dSmrg
59536ac495dSmrg return 0;
59636ac495dSmrg }
59736ac495dSmrg
59836ac495dSmrg /* Return 1 if OP is a symbol that needs 32-bit addressing. */
59936ac495dSmrg
60036ac495dSmrg int
addr32_operand(rtx op,machine_mode mode)60136ac495dSmrg addr32_operand (rtx op, machine_mode mode)
60236ac495dSmrg {
60336ac495dSmrg rtx sym;
60436ac495dSmrg
60536ac495dSmrg if (GET_CODE (op) == LABEL_REF)
60636ac495dSmrg return TARGET_ADDR32;
60736ac495dSmrg
60836ac495dSmrg if (GET_CODE (op) == SYMBOL_REF)
60936ac495dSmrg sym = op;
61036ac495dSmrg else if (GET_CODE (op) == CONST
61136ac495dSmrg && GET_CODE (XEXP (op, 0)) == PLUS
61236ac495dSmrg && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF
61336ac495dSmrg && CONST_INT_P (XEXP (XEXP (op, 0), 1))
61436ac495dSmrg && ! flag_pic)
61536ac495dSmrg sym = XEXP (XEXP (op, 0), 0);
61636ac495dSmrg else
61736ac495dSmrg return 0;
61836ac495dSmrg
61936ac495dSmrg return (! addr24_operand (sym, mode)
62036ac495dSmrg && ! small_data_operand (sym, mode));
62136ac495dSmrg }
62236ac495dSmrg
62336ac495dSmrg /* Return 1 if OP is a function that can be called with the `bl' insn. */
62436ac495dSmrg
62536ac495dSmrg int
call26_operand(rtx op,machine_mode mode ATTRIBUTE_UNUSED)62636ac495dSmrg call26_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
62736ac495dSmrg {
62836ac495dSmrg if (flag_pic)
62936ac495dSmrg return 1;
63036ac495dSmrg
63136ac495dSmrg if (GET_CODE (op) == SYMBOL_REF)
63236ac495dSmrg return SYMBOL_REF_MODEL (op) != M32R_MODEL_LARGE;
63336ac495dSmrg
63436ac495dSmrg return TARGET_CALL26;
63536ac495dSmrg }
63636ac495dSmrg
63736ac495dSmrg /* Return 1 if OP is a DImode const we want to handle inline.
63836ac495dSmrg This must match the code in the movdi pattern.
63936ac495dSmrg It is used by the 'G' constraint. */
64036ac495dSmrg
64136ac495dSmrg int
easy_di_const(rtx op)64236ac495dSmrg easy_di_const (rtx op)
64336ac495dSmrg {
64436ac495dSmrg rtx high_rtx, low_rtx;
64536ac495dSmrg HOST_WIDE_INT high, low;
64636ac495dSmrg
64736ac495dSmrg split_double (op, &high_rtx, &low_rtx);
64836ac495dSmrg high = INTVAL (high_rtx);
64936ac495dSmrg low = INTVAL (low_rtx);
65036ac495dSmrg /* Pick constants loadable with 2 16-bit `ldi' insns. */
65136ac495dSmrg if (high >= -128 && high <= 127
65236ac495dSmrg && low >= -128 && low <= 127)
65336ac495dSmrg return 1;
65436ac495dSmrg return 0;
65536ac495dSmrg }
65636ac495dSmrg
65736ac495dSmrg /* Return 1 if OP is a DFmode const we want to handle inline.
65836ac495dSmrg This must match the code in the movdf pattern.
65936ac495dSmrg It is used by the 'H' constraint. */
66036ac495dSmrg
66136ac495dSmrg int
easy_df_const(rtx op)66236ac495dSmrg easy_df_const (rtx op)
66336ac495dSmrg {
66436ac495dSmrg long l[2];
66536ac495dSmrg
66636ac495dSmrg REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (op), l);
66736ac495dSmrg if (l[0] == 0 && l[1] == 0)
66836ac495dSmrg return 1;
66936ac495dSmrg if ((l[0] & 0xffff) == 0 && l[1] == 0)
67036ac495dSmrg return 1;
67136ac495dSmrg return 0;
67236ac495dSmrg }
67336ac495dSmrg
67436ac495dSmrg /* Return 1 if OP is (mem (reg ...)).
67536ac495dSmrg This is used in insn length calcs. */
67636ac495dSmrg
67736ac495dSmrg int
memreg_operand(rtx op,machine_mode mode ATTRIBUTE_UNUSED)67836ac495dSmrg memreg_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED)
67936ac495dSmrg {
68036ac495dSmrg return MEM_P (op) && REG_P (XEXP (op, 0));
68136ac495dSmrg }
68236ac495dSmrg
683*8feb0f0bSmrg /* Return nonzero if ARG must be passed by indirect reference. */
68436ac495dSmrg
68536ac495dSmrg static bool
m32r_pass_by_reference(cumulative_args_t,const function_arg_info & arg)686*8feb0f0bSmrg m32r_pass_by_reference (cumulative_args_t, const function_arg_info &arg)
68736ac495dSmrg {
688*8feb0f0bSmrg int size = arg.type_size_in_bytes ();
68936ac495dSmrg return (size < 0 || size > 8);
69036ac495dSmrg }
69136ac495dSmrg
69236ac495dSmrg /* Comparisons. */
69336ac495dSmrg
69436ac495dSmrg /* X and Y are two things to compare using CODE. Emit the compare insn and
69536ac495dSmrg return the rtx for compare [arg0 of the if_then_else].
69636ac495dSmrg If need_compare is true then the comparison insn must be generated, rather
69736ac495dSmrg than being subsumed into the following branch instruction. */
69836ac495dSmrg
69936ac495dSmrg rtx
gen_compare(enum rtx_code code,rtx x,rtx y,int need_compare)70036ac495dSmrg gen_compare (enum rtx_code code, rtx x, rtx y, int need_compare)
70136ac495dSmrg {
70236ac495dSmrg enum rtx_code compare_code;
70336ac495dSmrg enum rtx_code branch_code;
70436ac495dSmrg rtx cc_reg = gen_rtx_REG (CCmode, CARRY_REGNUM);
70536ac495dSmrg int must_swap = 0;
70636ac495dSmrg
70736ac495dSmrg switch (code)
70836ac495dSmrg {
70936ac495dSmrg case EQ: compare_code = EQ; branch_code = NE; break;
71036ac495dSmrg case NE: compare_code = EQ; branch_code = EQ; break;
71136ac495dSmrg case LT: compare_code = LT; branch_code = NE; break;
71236ac495dSmrg case LE: compare_code = LT; branch_code = EQ; must_swap = 1; break;
71336ac495dSmrg case GT: compare_code = LT; branch_code = NE; must_swap = 1; break;
71436ac495dSmrg case GE: compare_code = LT; branch_code = EQ; break;
71536ac495dSmrg case LTU: compare_code = LTU; branch_code = NE; break;
71636ac495dSmrg case LEU: compare_code = LTU; branch_code = EQ; must_swap = 1; break;
71736ac495dSmrg case GTU: compare_code = LTU; branch_code = NE; must_swap = 1; break;
71836ac495dSmrg case GEU: compare_code = LTU; branch_code = EQ; break;
71936ac495dSmrg
72036ac495dSmrg default:
72136ac495dSmrg gcc_unreachable ();
72236ac495dSmrg }
72336ac495dSmrg
72436ac495dSmrg if (need_compare)
72536ac495dSmrg {
72636ac495dSmrg switch (compare_code)
72736ac495dSmrg {
72836ac495dSmrg case EQ:
72936ac495dSmrg if (satisfies_constraint_P (y) /* Reg equal to small const. */
73036ac495dSmrg && y != const0_rtx)
73136ac495dSmrg {
73236ac495dSmrg rtx tmp = gen_reg_rtx (SImode);
73336ac495dSmrg
73436ac495dSmrg emit_insn (gen_addsi3 (tmp, x, GEN_INT (-INTVAL (y))));
73536ac495dSmrg x = tmp;
73636ac495dSmrg y = const0_rtx;
73736ac495dSmrg }
73836ac495dSmrg else if (CONSTANT_P (y)) /* Reg equal to const. */
73936ac495dSmrg {
74036ac495dSmrg rtx tmp = force_reg (GET_MODE (x), y);
74136ac495dSmrg y = tmp;
74236ac495dSmrg }
74336ac495dSmrg
74436ac495dSmrg if (register_operand (y, SImode) /* Reg equal to reg. */
74536ac495dSmrg || y == const0_rtx) /* Reg equal to zero. */
74636ac495dSmrg {
74736ac495dSmrg emit_insn (gen_cmp_eqsi_insn (x, y));
74836ac495dSmrg
74936ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
75036ac495dSmrg }
75136ac495dSmrg break;
75236ac495dSmrg
75336ac495dSmrg case LT:
75436ac495dSmrg if (register_operand (y, SImode)
75536ac495dSmrg || satisfies_constraint_P (y))
75636ac495dSmrg {
75736ac495dSmrg rtx tmp = gen_reg_rtx (SImode); /* Reg compared to reg. */
75836ac495dSmrg
75936ac495dSmrg switch (code)
76036ac495dSmrg {
76136ac495dSmrg case LT:
76236ac495dSmrg emit_insn (gen_cmp_ltsi_insn (x, y));
76336ac495dSmrg code = EQ;
76436ac495dSmrg break;
76536ac495dSmrg case LE:
76636ac495dSmrg if (y == const0_rtx)
76736ac495dSmrg tmp = const1_rtx;
76836ac495dSmrg else
76936ac495dSmrg emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
77036ac495dSmrg emit_insn (gen_cmp_ltsi_insn (x, tmp));
77136ac495dSmrg code = EQ;
77236ac495dSmrg break;
77336ac495dSmrg case GT:
77436ac495dSmrg if (CONST_INT_P (y))
77536ac495dSmrg tmp = gen_rtx_PLUS (SImode, y, const1_rtx);
77636ac495dSmrg else
77736ac495dSmrg emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
77836ac495dSmrg emit_insn (gen_cmp_ltsi_insn (x, tmp));
77936ac495dSmrg code = NE;
78036ac495dSmrg break;
78136ac495dSmrg case GE:
78236ac495dSmrg emit_insn (gen_cmp_ltsi_insn (x, y));
78336ac495dSmrg code = NE;
78436ac495dSmrg break;
78536ac495dSmrg default:
78636ac495dSmrg gcc_unreachable ();
78736ac495dSmrg }
78836ac495dSmrg
78936ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
79036ac495dSmrg }
79136ac495dSmrg break;
79236ac495dSmrg
79336ac495dSmrg case LTU:
79436ac495dSmrg if (register_operand (y, SImode)
79536ac495dSmrg || satisfies_constraint_P (y))
79636ac495dSmrg {
79736ac495dSmrg rtx tmp = gen_reg_rtx (SImode); /* Reg (unsigned) compared to reg. */
79836ac495dSmrg
79936ac495dSmrg switch (code)
80036ac495dSmrg {
80136ac495dSmrg case LTU:
80236ac495dSmrg emit_insn (gen_cmp_ltusi_insn (x, y));
80336ac495dSmrg code = EQ;
80436ac495dSmrg break;
80536ac495dSmrg case LEU:
80636ac495dSmrg if (y == const0_rtx)
80736ac495dSmrg tmp = const1_rtx;
80836ac495dSmrg else
80936ac495dSmrg emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
81036ac495dSmrg emit_insn (gen_cmp_ltusi_insn (x, tmp));
81136ac495dSmrg code = EQ;
81236ac495dSmrg break;
81336ac495dSmrg case GTU:
81436ac495dSmrg if (CONST_INT_P (y))
81536ac495dSmrg tmp = gen_rtx_PLUS (SImode, y, const1_rtx);
81636ac495dSmrg else
81736ac495dSmrg emit_insn (gen_addsi3 (tmp, y, constm1_rtx));
81836ac495dSmrg emit_insn (gen_cmp_ltusi_insn (x, tmp));
81936ac495dSmrg code = NE;
82036ac495dSmrg break;
82136ac495dSmrg case GEU:
82236ac495dSmrg emit_insn (gen_cmp_ltusi_insn (x, y));
82336ac495dSmrg code = NE;
82436ac495dSmrg break;
82536ac495dSmrg default:
82636ac495dSmrg gcc_unreachable ();
82736ac495dSmrg }
82836ac495dSmrg
82936ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, cc_reg, const0_rtx);
83036ac495dSmrg }
83136ac495dSmrg break;
83236ac495dSmrg
83336ac495dSmrg default:
83436ac495dSmrg gcc_unreachable ();
83536ac495dSmrg }
83636ac495dSmrg }
83736ac495dSmrg else
83836ac495dSmrg {
83936ac495dSmrg /* Reg/reg equal comparison. */
84036ac495dSmrg if (compare_code == EQ
84136ac495dSmrg && register_operand (y, SImode))
84236ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, x, y);
84336ac495dSmrg
84436ac495dSmrg /* Reg/zero signed comparison. */
84536ac495dSmrg if ((compare_code == EQ || compare_code == LT)
84636ac495dSmrg && y == const0_rtx)
84736ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, x, y);
84836ac495dSmrg
84936ac495dSmrg /* Reg/smallconst equal comparison. */
85036ac495dSmrg if (compare_code == EQ
85136ac495dSmrg && satisfies_constraint_P (y))
85236ac495dSmrg {
85336ac495dSmrg rtx tmp = gen_reg_rtx (SImode);
85436ac495dSmrg
85536ac495dSmrg emit_insn (gen_addsi3 (tmp, x, GEN_INT (-INTVAL (y))));
85636ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, tmp, const0_rtx);
85736ac495dSmrg }
85836ac495dSmrg
85936ac495dSmrg /* Reg/const equal comparison. */
86036ac495dSmrg if (compare_code == EQ
86136ac495dSmrg && CONSTANT_P (y))
86236ac495dSmrg {
86336ac495dSmrg rtx tmp = force_reg (GET_MODE (x), y);
86436ac495dSmrg
86536ac495dSmrg return gen_rtx_fmt_ee (code, CCmode, x, tmp);
86636ac495dSmrg }
86736ac495dSmrg }
86836ac495dSmrg
86936ac495dSmrg if (CONSTANT_P (y))
87036ac495dSmrg {
87136ac495dSmrg if (must_swap)
87236ac495dSmrg y = force_reg (GET_MODE (x), y);
87336ac495dSmrg else
87436ac495dSmrg {
87536ac495dSmrg int ok_const = reg_or_int16_operand (y, GET_MODE (y));
87636ac495dSmrg
87736ac495dSmrg if (! ok_const)
87836ac495dSmrg y = force_reg (GET_MODE (x), y);
87936ac495dSmrg }
88036ac495dSmrg }
88136ac495dSmrg
88236ac495dSmrg switch (compare_code)
88336ac495dSmrg {
88436ac495dSmrg case EQ :
88536ac495dSmrg emit_insn (gen_cmp_eqsi_insn (must_swap ? y : x, must_swap ? x : y));
88636ac495dSmrg break;
88736ac495dSmrg case LT :
88836ac495dSmrg emit_insn (gen_cmp_ltsi_insn (must_swap ? y : x, must_swap ? x : y));
88936ac495dSmrg break;
89036ac495dSmrg case LTU :
89136ac495dSmrg emit_insn (gen_cmp_ltusi_insn (must_swap ? y : x, must_swap ? x : y));
89236ac495dSmrg break;
89336ac495dSmrg
89436ac495dSmrg default:
89536ac495dSmrg gcc_unreachable ();
89636ac495dSmrg }
89736ac495dSmrg
89836ac495dSmrg return gen_rtx_fmt_ee (branch_code, VOIDmode, cc_reg, CONST0_RTX (CCmode));
89936ac495dSmrg }
90036ac495dSmrg
90136ac495dSmrg bool
gen_cond_store(enum rtx_code code,rtx op0,rtx op1,rtx op2)90236ac495dSmrg gen_cond_store (enum rtx_code code, rtx op0, rtx op1, rtx op2)
90336ac495dSmrg {
90436ac495dSmrg machine_mode mode = GET_MODE (op0);
90536ac495dSmrg
90636ac495dSmrg gcc_assert (mode == SImode);
90736ac495dSmrg switch (code)
90836ac495dSmrg {
90936ac495dSmrg case EQ:
91036ac495dSmrg if (!register_operand (op1, mode))
91136ac495dSmrg op1 = force_reg (mode, op1);
91236ac495dSmrg
91336ac495dSmrg if (TARGET_M32RX || TARGET_M32R2)
91436ac495dSmrg {
91536ac495dSmrg if (!reg_or_zero_operand (op2, mode))
91636ac495dSmrg op2 = force_reg (mode, op2);
91736ac495dSmrg
91836ac495dSmrg emit_insn (gen_seq_insn_m32rx (op0, op1, op2));
91936ac495dSmrg return true;
92036ac495dSmrg }
92136ac495dSmrg if (CONST_INT_P (op2) && INTVAL (op2) == 0)
92236ac495dSmrg {
92336ac495dSmrg emit_insn (gen_seq_zero_insn (op0, op1));
92436ac495dSmrg return true;
92536ac495dSmrg }
92636ac495dSmrg
92736ac495dSmrg if (!reg_or_eq_int16_operand (op2, mode))
92836ac495dSmrg op2 = force_reg (mode, op2);
92936ac495dSmrg
93036ac495dSmrg emit_insn (gen_seq_insn (op0, op1, op2));
93136ac495dSmrg return true;
93236ac495dSmrg
93336ac495dSmrg case NE:
93436ac495dSmrg if (!CONST_INT_P (op2)
93536ac495dSmrg || (INTVAL (op2) != 0 && satisfies_constraint_K (op2)))
93636ac495dSmrg {
93736ac495dSmrg rtx reg;
93836ac495dSmrg
93936ac495dSmrg if (reload_completed || reload_in_progress)
94036ac495dSmrg return false;
94136ac495dSmrg
94236ac495dSmrg reg = gen_reg_rtx (SImode);
94336ac495dSmrg emit_insn (gen_xorsi3 (reg, op1, op2));
94436ac495dSmrg op1 = reg;
94536ac495dSmrg
94636ac495dSmrg if (!register_operand (op1, mode))
94736ac495dSmrg op1 = force_reg (mode, op1);
94836ac495dSmrg
94936ac495dSmrg emit_insn (gen_sne_zero_insn (op0, op1));
95036ac495dSmrg return true;
95136ac495dSmrg }
95236ac495dSmrg return false;
95336ac495dSmrg
95436ac495dSmrg case LT:
95536ac495dSmrg case GT:
95636ac495dSmrg if (code == GT)
95736ac495dSmrg {
95836ac495dSmrg rtx tmp = op2;
95936ac495dSmrg op2 = op1;
96036ac495dSmrg op1 = tmp;
96136ac495dSmrg code = LT;
96236ac495dSmrg }
96336ac495dSmrg
96436ac495dSmrg if (!register_operand (op1, mode))
96536ac495dSmrg op1 = force_reg (mode, op1);
96636ac495dSmrg
96736ac495dSmrg if (!reg_or_int16_operand (op2, mode))
96836ac495dSmrg op2 = force_reg (mode, op2);
96936ac495dSmrg
97036ac495dSmrg emit_insn (gen_slt_insn (op0, op1, op2));
97136ac495dSmrg return true;
97236ac495dSmrg
97336ac495dSmrg case LTU:
97436ac495dSmrg case GTU:
97536ac495dSmrg if (code == GTU)
97636ac495dSmrg {
97736ac495dSmrg rtx tmp = op2;
97836ac495dSmrg op2 = op1;
97936ac495dSmrg op1 = tmp;
98036ac495dSmrg code = LTU;
98136ac495dSmrg }
98236ac495dSmrg
98336ac495dSmrg if (!register_operand (op1, mode))
98436ac495dSmrg op1 = force_reg (mode, op1);
98536ac495dSmrg
98636ac495dSmrg if (!reg_or_int16_operand (op2, mode))
98736ac495dSmrg op2 = force_reg (mode, op2);
98836ac495dSmrg
98936ac495dSmrg emit_insn (gen_sltu_insn (op0, op1, op2));
99036ac495dSmrg return true;
99136ac495dSmrg
99236ac495dSmrg case GE:
99336ac495dSmrg case GEU:
99436ac495dSmrg if (!register_operand (op1, mode))
99536ac495dSmrg op1 = force_reg (mode, op1);
99636ac495dSmrg
99736ac495dSmrg if (!reg_or_int16_operand (op2, mode))
99836ac495dSmrg op2 = force_reg (mode, op2);
99936ac495dSmrg
100036ac495dSmrg if (code == GE)
100136ac495dSmrg emit_insn (gen_sge_insn (op0, op1, op2));
100236ac495dSmrg else
100336ac495dSmrg emit_insn (gen_sgeu_insn (op0, op1, op2));
100436ac495dSmrg return true;
100536ac495dSmrg
100636ac495dSmrg case LE:
100736ac495dSmrg case LEU:
100836ac495dSmrg if (!register_operand (op1, mode))
100936ac495dSmrg op1 = force_reg (mode, op1);
101036ac495dSmrg
101136ac495dSmrg if (CONST_INT_P (op2))
101236ac495dSmrg {
101336ac495dSmrg HOST_WIDE_INT value = INTVAL (op2);
101436ac495dSmrg if (value >= 2147483647)
101536ac495dSmrg {
101636ac495dSmrg emit_move_insn (op0, const1_rtx);
101736ac495dSmrg return true;
101836ac495dSmrg }
101936ac495dSmrg
102036ac495dSmrg op2 = GEN_INT (value + 1);
102136ac495dSmrg if (value < -32768 || value >= 32767)
102236ac495dSmrg op2 = force_reg (mode, op2);
102336ac495dSmrg
102436ac495dSmrg if (code == LEU)
102536ac495dSmrg emit_insn (gen_sltu_insn (op0, op1, op2));
102636ac495dSmrg else
102736ac495dSmrg emit_insn (gen_slt_insn (op0, op1, op2));
102836ac495dSmrg return true;
102936ac495dSmrg }
103036ac495dSmrg
103136ac495dSmrg if (!register_operand (op2, mode))
103236ac495dSmrg op2 = force_reg (mode, op2);
103336ac495dSmrg
103436ac495dSmrg if (code == LEU)
103536ac495dSmrg emit_insn (gen_sleu_insn (op0, op1, op2));
103636ac495dSmrg else
103736ac495dSmrg emit_insn (gen_sle_insn (op0, op1, op2));
103836ac495dSmrg return true;
103936ac495dSmrg
104036ac495dSmrg default:
104136ac495dSmrg gcc_unreachable ();
104236ac495dSmrg }
104336ac495dSmrg }
104436ac495dSmrg
104536ac495dSmrg
104636ac495dSmrg /* Split a 2 word move (DI or DF) into component parts. */
104736ac495dSmrg
104836ac495dSmrg rtx
gen_split_move_double(rtx operands[])104936ac495dSmrg gen_split_move_double (rtx operands[])
105036ac495dSmrg {
105136ac495dSmrg machine_mode mode = GET_MODE (operands[0]);
105236ac495dSmrg rtx dest = operands[0];
105336ac495dSmrg rtx src = operands[1];
105436ac495dSmrg rtx val;
105536ac495dSmrg
105636ac495dSmrg /* We might have (SUBREG (MEM)) here, so just get rid of the
105736ac495dSmrg subregs to make this code simpler. It is safe to call
105836ac495dSmrg alter_subreg any time after reload. */
105936ac495dSmrg if (GET_CODE (dest) == SUBREG)
106036ac495dSmrg alter_subreg (&dest, true);
106136ac495dSmrg if (GET_CODE (src) == SUBREG)
106236ac495dSmrg alter_subreg (&src, true);
106336ac495dSmrg
106436ac495dSmrg start_sequence ();
106536ac495dSmrg if (REG_P (dest))
106636ac495dSmrg {
106736ac495dSmrg int dregno = REGNO (dest);
106836ac495dSmrg
106936ac495dSmrg /* Reg = reg. */
107036ac495dSmrg if (REG_P (src))
107136ac495dSmrg {
107236ac495dSmrg int sregno = REGNO (src);
107336ac495dSmrg
107436ac495dSmrg int reverse = (dregno == sregno + 1);
107536ac495dSmrg
107636ac495dSmrg /* We normally copy the low-numbered register first. However, if
107736ac495dSmrg the first register operand 0 is the same as the second register of
107836ac495dSmrg operand 1, we must copy in the opposite order. */
107936ac495dSmrg emit_insn (gen_rtx_SET (operand_subword (dest, reverse, TRUE, mode),
108036ac495dSmrg operand_subword (src, reverse, TRUE, mode)));
108136ac495dSmrg
108236ac495dSmrg emit_insn (gen_rtx_SET (operand_subword (dest, !reverse, TRUE, mode),
108336ac495dSmrg operand_subword (src, !reverse, TRUE, mode)));
108436ac495dSmrg }
108536ac495dSmrg
108636ac495dSmrg /* Reg = constant. */
108736ac495dSmrg else if (CONST_INT_P (src) || GET_CODE (src) == CONST_DOUBLE)
108836ac495dSmrg {
108936ac495dSmrg rtx words[2];
109036ac495dSmrg split_double (src, &words[0], &words[1]);
109136ac495dSmrg emit_insn (gen_rtx_SET (operand_subword (dest, 0, TRUE, mode),
109236ac495dSmrg words[0]));
109336ac495dSmrg
109436ac495dSmrg emit_insn (gen_rtx_SET (operand_subword (dest, 1, TRUE, mode),
109536ac495dSmrg words[1]));
109636ac495dSmrg }
109736ac495dSmrg
109836ac495dSmrg /* Reg = mem. */
109936ac495dSmrg else if (MEM_P (src))
110036ac495dSmrg {
110136ac495dSmrg /* If the high-address word is used in the address, we must load it
110236ac495dSmrg last. Otherwise, load it first. */
110336ac495dSmrg int reverse = refers_to_regno_p (dregno, XEXP (src, 0));
110436ac495dSmrg
110536ac495dSmrg /* We used to optimize loads from single registers as
110636ac495dSmrg
110736ac495dSmrg ld r1,r3+; ld r2,r3
110836ac495dSmrg
110936ac495dSmrg if r3 were not used subsequently. However, the REG_NOTES aren't
111036ac495dSmrg propagated correctly by the reload phase, and it can cause bad
111136ac495dSmrg code to be generated. We could still try:
111236ac495dSmrg
111336ac495dSmrg ld r1,r3+; ld r2,r3; addi r3,-4
111436ac495dSmrg
111536ac495dSmrg which saves 2 bytes and doesn't force longword alignment. */
111636ac495dSmrg emit_insn (gen_rtx_SET (operand_subword (dest, reverse, TRUE, mode),
111736ac495dSmrg adjust_address (src, SImode,
111836ac495dSmrg reverse * UNITS_PER_WORD)));
111936ac495dSmrg
112036ac495dSmrg emit_insn (gen_rtx_SET (operand_subword (dest, !reverse, TRUE, mode),
112136ac495dSmrg adjust_address (src, SImode,
112236ac495dSmrg !reverse * UNITS_PER_WORD)));
112336ac495dSmrg }
112436ac495dSmrg else
112536ac495dSmrg gcc_unreachable ();
112636ac495dSmrg }
112736ac495dSmrg
112836ac495dSmrg /* Mem = reg. */
112936ac495dSmrg /* We used to optimize loads from single registers as
113036ac495dSmrg
113136ac495dSmrg st r1,r3; st r2,+r3
113236ac495dSmrg
113336ac495dSmrg if r3 were not used subsequently. However, the REG_NOTES aren't
113436ac495dSmrg propagated correctly by the reload phase, and it can cause bad
113536ac495dSmrg code to be generated. We could still try:
113636ac495dSmrg
113736ac495dSmrg st r1,r3; st r2,+r3; addi r3,-4
113836ac495dSmrg
113936ac495dSmrg which saves 2 bytes and doesn't force longword alignment. */
114036ac495dSmrg else if (MEM_P (dest) && REG_P (src))
114136ac495dSmrg {
114236ac495dSmrg emit_insn (gen_rtx_SET (adjust_address (dest, SImode, 0),
114336ac495dSmrg operand_subword (src, 0, TRUE, mode)));
114436ac495dSmrg
114536ac495dSmrg emit_insn (gen_rtx_SET (adjust_address (dest, SImode, UNITS_PER_WORD),
114636ac495dSmrg operand_subword (src, 1, TRUE, mode)));
114736ac495dSmrg }
114836ac495dSmrg
114936ac495dSmrg else
115036ac495dSmrg gcc_unreachable ();
115136ac495dSmrg
115236ac495dSmrg val = get_insns ();
115336ac495dSmrg end_sequence ();
115436ac495dSmrg return val;
115536ac495dSmrg }
115636ac495dSmrg
115736ac495dSmrg
115836ac495dSmrg static int
m32r_arg_partial_bytes(cumulative_args_t cum_v,const function_arg_info & arg)1159*8feb0f0bSmrg m32r_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg)
116036ac495dSmrg {
116136ac495dSmrg CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
116236ac495dSmrg
116336ac495dSmrg int words;
116436ac495dSmrg unsigned int size =
1165*8feb0f0bSmrg (arg.promoted_size_in_bytes () + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
116636ac495dSmrg
116736ac495dSmrg if (*cum >= M32R_MAX_PARM_REGS)
116836ac495dSmrg words = 0;
116936ac495dSmrg else if (*cum + size > M32R_MAX_PARM_REGS)
117036ac495dSmrg words = (*cum + size) - M32R_MAX_PARM_REGS;
117136ac495dSmrg else
117236ac495dSmrg words = 0;
117336ac495dSmrg
117436ac495dSmrg return words * UNITS_PER_WORD;
117536ac495dSmrg }
117636ac495dSmrg
117736ac495dSmrg /* The ROUND_ADVANCE* macros are local to this file. */
117836ac495dSmrg /* Round SIZE up to a word boundary. */
117936ac495dSmrg #define ROUND_ADVANCE(SIZE) \
118036ac495dSmrg (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
118136ac495dSmrg
118236ac495dSmrg /* Round arg MODE/TYPE up to the next word boundary. */
118336ac495dSmrg #define ROUND_ADVANCE_ARG(MODE, TYPE) \
118436ac495dSmrg ((MODE) == BLKmode \
118536ac495dSmrg ? ROUND_ADVANCE ((unsigned int) int_size_in_bytes (TYPE)) \
118636ac495dSmrg : ROUND_ADVANCE ((unsigned int) GET_MODE_SIZE (MODE)))
118736ac495dSmrg
118836ac495dSmrg /* Round CUM up to the necessary point for argument MODE/TYPE. */
118936ac495dSmrg #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) (CUM)
119036ac495dSmrg
119136ac495dSmrg /* Return boolean indicating arg of type TYPE and mode MODE will be passed in
119236ac495dSmrg a reg. This includes arguments that have to be passed by reference as the
119336ac495dSmrg pointer to them is passed in a reg if one is available (and that is what
119436ac495dSmrg we're given).
119536ac495dSmrg This macro is only used in this file. */
119636ac495dSmrg #define PASS_IN_REG_P(CUM, MODE, TYPE) \
119736ac495dSmrg (ROUND_ADVANCE_CUM ((CUM), (MODE), (TYPE)) < M32R_MAX_PARM_REGS)
119836ac495dSmrg
119936ac495dSmrg /* Determine where to put an argument to a function.
120036ac495dSmrg Value is zero to push the argument on the stack,
120136ac495dSmrg or a hard register in which to store the argument.
120236ac495dSmrg
120336ac495dSmrg CUM is a variable of type CUMULATIVE_ARGS which gives info about
120436ac495dSmrg the preceding args and about the function being called.
1205*8feb0f0bSmrg ARG is a description of the argument. */
120636ac495dSmrg /* On the M32R the first M32R_MAX_PARM_REGS args are normally in registers
120736ac495dSmrg and the rest are pushed. */
120836ac495dSmrg
120936ac495dSmrg static rtx
m32r_function_arg(cumulative_args_t cum_v,const function_arg_info & arg)1210*8feb0f0bSmrg m32r_function_arg (cumulative_args_t cum_v, const function_arg_info &arg)
121136ac495dSmrg {
121236ac495dSmrg CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
121336ac495dSmrg
1214*8feb0f0bSmrg return (PASS_IN_REG_P (*cum, arg.mode, arg.type)
1215*8feb0f0bSmrg ? gen_rtx_REG (arg.mode,
1216*8feb0f0bSmrg ROUND_ADVANCE_CUM (*cum, arg.mode, arg.type))
121736ac495dSmrg : NULL_RTX);
121836ac495dSmrg }
121936ac495dSmrg
1220*8feb0f0bSmrg /* Update the data in CUM to advance over argument ARG. */
122136ac495dSmrg
122236ac495dSmrg static void
m32r_function_arg_advance(cumulative_args_t cum_v,const function_arg_info & arg)1223*8feb0f0bSmrg m32r_function_arg_advance (cumulative_args_t cum_v,
1224*8feb0f0bSmrg const function_arg_info &arg)
122536ac495dSmrg {
122636ac495dSmrg CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
122736ac495dSmrg
1228*8feb0f0bSmrg *cum = (ROUND_ADVANCE_CUM (*cum, arg.mode, arg.type)
1229*8feb0f0bSmrg + ROUND_ADVANCE_ARG (arg.mode, arg.type));
123036ac495dSmrg }
123136ac495dSmrg
123236ac495dSmrg /* Worker function for TARGET_RETURN_IN_MEMORY. */
123336ac495dSmrg
123436ac495dSmrg static bool
m32r_return_in_memory(const_tree type,const_tree fntype ATTRIBUTE_UNUSED)123536ac495dSmrg m32r_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
123636ac495dSmrg {
123736ac495dSmrg cumulative_args_t dummy = pack_cumulative_args (NULL);
1238*8feb0f0bSmrg function_arg_info arg (const_cast<tree> (type), /*named=*/false);
1239*8feb0f0bSmrg return m32r_pass_by_reference (dummy, arg);
124036ac495dSmrg }
124136ac495dSmrg
124236ac495dSmrg /* Worker function for TARGET_FUNCTION_VALUE. */
124336ac495dSmrg
124436ac495dSmrg static rtx
m32r_function_value(const_tree valtype,const_tree fn_decl_or_type ATTRIBUTE_UNUSED,bool outgoing ATTRIBUTE_UNUSED)124536ac495dSmrg m32r_function_value (const_tree valtype,
124636ac495dSmrg const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
124736ac495dSmrg bool outgoing ATTRIBUTE_UNUSED)
124836ac495dSmrg {
124936ac495dSmrg return gen_rtx_REG (TYPE_MODE (valtype), 0);
125036ac495dSmrg }
125136ac495dSmrg
125236ac495dSmrg /* Worker function for TARGET_LIBCALL_VALUE. */
125336ac495dSmrg
125436ac495dSmrg static rtx
m32r_libcall_value(machine_mode mode,const_rtx fun ATTRIBUTE_UNUSED)125536ac495dSmrg m32r_libcall_value (machine_mode mode,
125636ac495dSmrg const_rtx fun ATTRIBUTE_UNUSED)
125736ac495dSmrg {
125836ac495dSmrg return gen_rtx_REG (mode, 0);
125936ac495dSmrg }
126036ac495dSmrg
126136ac495dSmrg /* Worker function for TARGET_FUNCTION_VALUE_REGNO_P.
126236ac495dSmrg
126336ac495dSmrg ??? What about r1 in DI/DF values. */
126436ac495dSmrg
126536ac495dSmrg static bool
m32r_function_value_regno_p(const unsigned int regno)126636ac495dSmrg m32r_function_value_regno_p (const unsigned int regno)
126736ac495dSmrg {
126836ac495dSmrg return (regno == 0);
126936ac495dSmrg }
127036ac495dSmrg
127136ac495dSmrg /* Do any needed setup for a variadic function. For the M32R, we must
127236ac495dSmrg create a register parameter block, and then copy any anonymous arguments
127336ac495dSmrg in registers to memory.
127436ac495dSmrg
1275*8feb0f0bSmrg CUM has not been updated for the last named argument (which is given
1276*8feb0f0bSmrg by ARG), and we rely on this fact. */
127736ac495dSmrg
127836ac495dSmrg static void
m32r_setup_incoming_varargs(cumulative_args_t cum,const function_arg_info & arg,int * pretend_size,int no_rtl)1279*8feb0f0bSmrg m32r_setup_incoming_varargs (cumulative_args_t cum,
1280*8feb0f0bSmrg const function_arg_info &arg,
1281*8feb0f0bSmrg int *pretend_size, int no_rtl)
128236ac495dSmrg {
128336ac495dSmrg int first_anon_arg;
128436ac495dSmrg
128536ac495dSmrg if (no_rtl)
128636ac495dSmrg return;
128736ac495dSmrg
128836ac495dSmrg /* All BLKmode values are passed by reference. */
1289*8feb0f0bSmrg gcc_assert (arg.mode != BLKmode);
129036ac495dSmrg
1291*8feb0f0bSmrg first_anon_arg = (ROUND_ADVANCE_CUM (*get_cumulative_args (cum),
1292*8feb0f0bSmrg arg.mode, arg.type)
1293*8feb0f0bSmrg + ROUND_ADVANCE_ARG (arg.mode, arg.type));
129436ac495dSmrg
129536ac495dSmrg if (first_anon_arg < M32R_MAX_PARM_REGS)
129636ac495dSmrg {
129736ac495dSmrg /* Note that first_reg_offset < M32R_MAX_PARM_REGS. */
129836ac495dSmrg int first_reg_offset = first_anon_arg;
129936ac495dSmrg /* Size in words to "pretend" allocate. */
130036ac495dSmrg int size = M32R_MAX_PARM_REGS - first_reg_offset;
130136ac495dSmrg rtx regblock;
130236ac495dSmrg
130336ac495dSmrg regblock = gen_frame_mem (BLKmode,
130436ac495dSmrg plus_constant (Pmode, arg_pointer_rtx,
130536ac495dSmrg FIRST_PARM_OFFSET (0)));
130636ac495dSmrg set_mem_alias_set (regblock, get_varargs_alias_set ());
130736ac495dSmrg move_block_from_reg (first_reg_offset, regblock, size);
130836ac495dSmrg
130936ac495dSmrg *pretend_size = (size * UNITS_PER_WORD);
131036ac495dSmrg }
131136ac495dSmrg }
131236ac495dSmrg
131336ac495dSmrg
131436ac495dSmrg /* Return true if INSN is real instruction bearing insn. */
131536ac495dSmrg
131636ac495dSmrg static int
m32r_is_insn(rtx insn)131736ac495dSmrg m32r_is_insn (rtx insn)
131836ac495dSmrg {
131936ac495dSmrg return (NONDEBUG_INSN_P (insn)
132036ac495dSmrg && GET_CODE (PATTERN (insn)) != USE
132136ac495dSmrg && GET_CODE (PATTERN (insn)) != CLOBBER);
132236ac495dSmrg }
132336ac495dSmrg
132436ac495dSmrg /* Increase the priority of long instructions so that the
132536ac495dSmrg short instructions are scheduled ahead of the long ones. */
132636ac495dSmrg
132736ac495dSmrg static int
m32r_adjust_priority(rtx_insn * insn,int priority)132836ac495dSmrg m32r_adjust_priority (rtx_insn *insn, int priority)
132936ac495dSmrg {
133036ac495dSmrg if (m32r_is_insn (insn)
133136ac495dSmrg && get_attr_insn_size (insn) != INSN_SIZE_SHORT)
133236ac495dSmrg priority <<= 3;
133336ac495dSmrg
133436ac495dSmrg return priority;
133536ac495dSmrg }
133636ac495dSmrg
133736ac495dSmrg
133836ac495dSmrg /* Indicate how many instructions can be issued at the same time.
133936ac495dSmrg This is sort of a lie. The m32r can issue only 1 long insn at
134036ac495dSmrg once, but it can issue 2 short insns. The default therefore is
134136ac495dSmrg set at 2, but this can be overridden by the command line option
134236ac495dSmrg -missue-rate=1. */
134336ac495dSmrg
134436ac495dSmrg static int
m32r_issue_rate(void)134536ac495dSmrg m32r_issue_rate (void)
134636ac495dSmrg {
134736ac495dSmrg return ((TARGET_LOW_ISSUE_RATE) ? 1 : 2);
134836ac495dSmrg }
134936ac495dSmrg
135036ac495dSmrg /* Cost functions. */
135136ac495dSmrg /* Memory is 3 times as expensive as registers.
135236ac495dSmrg ??? Is that the right way to look at it? */
135336ac495dSmrg
135436ac495dSmrg static int
m32r_memory_move_cost(machine_mode mode,reg_class_t rclass ATTRIBUTE_UNUSED,bool in ATTRIBUTE_UNUSED)135536ac495dSmrg m32r_memory_move_cost (machine_mode mode,
135636ac495dSmrg reg_class_t rclass ATTRIBUTE_UNUSED,
135736ac495dSmrg bool in ATTRIBUTE_UNUSED)
135836ac495dSmrg {
135936ac495dSmrg if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
136036ac495dSmrg return 6;
136136ac495dSmrg else
136236ac495dSmrg return 12;
136336ac495dSmrg }
136436ac495dSmrg
136536ac495dSmrg static bool
m32r_rtx_costs(rtx x,machine_mode mode ATTRIBUTE_UNUSED,int outer_code ATTRIBUTE_UNUSED,int opno ATTRIBUTE_UNUSED,int * total,bool speed ATTRIBUTE_UNUSED)136636ac495dSmrg m32r_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
136736ac495dSmrg int outer_code ATTRIBUTE_UNUSED,
136836ac495dSmrg int opno ATTRIBUTE_UNUSED, int *total,
136936ac495dSmrg bool speed ATTRIBUTE_UNUSED)
137036ac495dSmrg {
137136ac495dSmrg int code = GET_CODE (x);
137236ac495dSmrg
137336ac495dSmrg switch (code)
137436ac495dSmrg {
137536ac495dSmrg /* Small integers are as cheap as registers. 4 byte values can be
137636ac495dSmrg fetched as immediate constants - let's give that the cost of an
137736ac495dSmrg extra insn. */
137836ac495dSmrg case CONST_INT:
137936ac495dSmrg if (INT16_P (INTVAL (x)))
138036ac495dSmrg {
138136ac495dSmrg *total = 0;
138236ac495dSmrg return true;
138336ac495dSmrg }
138436ac495dSmrg /* FALLTHRU */
138536ac495dSmrg
138636ac495dSmrg case CONST:
138736ac495dSmrg case LABEL_REF:
138836ac495dSmrg case SYMBOL_REF:
138936ac495dSmrg *total = COSTS_N_INSNS (1);
139036ac495dSmrg return true;
139136ac495dSmrg
139236ac495dSmrg case CONST_DOUBLE:
139336ac495dSmrg {
139436ac495dSmrg rtx high, low;
139536ac495dSmrg
139636ac495dSmrg split_double (x, &high, &low);
139736ac495dSmrg *total = COSTS_N_INSNS (!INT16_P (INTVAL (high))
139836ac495dSmrg + !INT16_P (INTVAL (low)));
139936ac495dSmrg return true;
140036ac495dSmrg }
140136ac495dSmrg
140236ac495dSmrg case MULT:
140336ac495dSmrg *total = COSTS_N_INSNS (3);
140436ac495dSmrg return true;
140536ac495dSmrg
140636ac495dSmrg case DIV:
140736ac495dSmrg case UDIV:
140836ac495dSmrg case MOD:
140936ac495dSmrg case UMOD:
141036ac495dSmrg *total = COSTS_N_INSNS (10);
141136ac495dSmrg return true;
141236ac495dSmrg
141336ac495dSmrg default:
141436ac495dSmrg return false;
141536ac495dSmrg }
141636ac495dSmrg }
141736ac495dSmrg
141836ac495dSmrg /* Type of function DECL.
141936ac495dSmrg
142036ac495dSmrg The result is cached. To reset the cache at the end of a function,
142136ac495dSmrg call with DECL = NULL_TREE. */
142236ac495dSmrg
142336ac495dSmrg enum m32r_function_type
m32r_compute_function_type(tree decl)142436ac495dSmrg m32r_compute_function_type (tree decl)
142536ac495dSmrg {
142636ac495dSmrg /* Cached value. */
142736ac495dSmrg static enum m32r_function_type fn_type = M32R_FUNCTION_UNKNOWN;
142836ac495dSmrg /* Last function we were called for. */
142936ac495dSmrg static tree last_fn = NULL_TREE;
143036ac495dSmrg
143136ac495dSmrg /* Resetting the cached value? */
143236ac495dSmrg if (decl == NULL_TREE)
143336ac495dSmrg {
143436ac495dSmrg fn_type = M32R_FUNCTION_UNKNOWN;
143536ac495dSmrg last_fn = NULL_TREE;
143636ac495dSmrg return fn_type;
143736ac495dSmrg }
143836ac495dSmrg
143936ac495dSmrg if (decl == last_fn && fn_type != M32R_FUNCTION_UNKNOWN)
144036ac495dSmrg return fn_type;
144136ac495dSmrg
144236ac495dSmrg /* Compute function type. */
144336ac495dSmrg fn_type = (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl)) != NULL_TREE
144436ac495dSmrg ? M32R_FUNCTION_INTERRUPT
144536ac495dSmrg : M32R_FUNCTION_NORMAL);
144636ac495dSmrg
144736ac495dSmrg last_fn = decl;
144836ac495dSmrg return fn_type;
144936ac495dSmrg }
145036ac495dSmrg /* Function prologue/epilogue handlers. */
145136ac495dSmrg
145236ac495dSmrg /* M32R stack frames look like:
145336ac495dSmrg
145436ac495dSmrg Before call After call
145536ac495dSmrg +-----------------------+ +-----------------------+
145636ac495dSmrg | | | |
145736ac495dSmrg high | local variables, | | local variables, |
145836ac495dSmrg mem | reg save area, etc. | | reg save area, etc. |
145936ac495dSmrg | | | |
146036ac495dSmrg +-----------------------+ +-----------------------+
146136ac495dSmrg | | | |
146236ac495dSmrg | arguments on stack. | | arguments on stack. |
146336ac495dSmrg | | | |
146436ac495dSmrg SP+0->+-----------------------+ +-----------------------+
146536ac495dSmrg | reg parm save area, |
146636ac495dSmrg | only created for |
146736ac495dSmrg | variable argument |
146836ac495dSmrg | functions |
146936ac495dSmrg +-----------------------+
147036ac495dSmrg | previous frame ptr |
147136ac495dSmrg +-----------------------+
147236ac495dSmrg | |
147336ac495dSmrg | register save area |
147436ac495dSmrg | |
147536ac495dSmrg +-----------------------+
147636ac495dSmrg | return address |
147736ac495dSmrg +-----------------------+
147836ac495dSmrg | |
147936ac495dSmrg | local variables |
148036ac495dSmrg | |
148136ac495dSmrg +-----------------------+
148236ac495dSmrg | |
148336ac495dSmrg | alloca allocations |
148436ac495dSmrg | |
148536ac495dSmrg +-----------------------+
148636ac495dSmrg | |
148736ac495dSmrg low | arguments on stack |
148836ac495dSmrg memory | |
148936ac495dSmrg SP+0->+-----------------------+
149036ac495dSmrg
149136ac495dSmrg Notes:
149236ac495dSmrg 1) The "reg parm save area" does not exist for non variable argument fns.
149336ac495dSmrg 2) The "reg parm save area" can be eliminated completely if we saved regs
149436ac495dSmrg containing anonymous args separately but that complicates things too
149536ac495dSmrg much (so it's not done).
149636ac495dSmrg 3) The return address is saved after the register save area so as to have as
149736ac495dSmrg many insns as possible between the restoration of `lr' and the `jmp lr'. */
149836ac495dSmrg
149936ac495dSmrg /* Structure to be filled in by m32r_compute_frame_size with register
150036ac495dSmrg save masks, and offsets for the current function. */
150136ac495dSmrg struct m32r_frame_info
150236ac495dSmrg {
150336ac495dSmrg unsigned int total_size; /* # bytes that the entire frame takes up. */
150436ac495dSmrg unsigned int extra_size; /* # bytes of extra stuff. */
150536ac495dSmrg unsigned int pretend_size; /* # bytes we push and pretend caller did. */
150636ac495dSmrg unsigned int args_size; /* # bytes that outgoing arguments take up. */
150736ac495dSmrg unsigned int reg_size; /* # bytes needed to store regs. */
150836ac495dSmrg unsigned int var_size; /* # bytes that variables take up. */
150936ac495dSmrg unsigned int gmask; /* Mask of saved gp registers. */
151036ac495dSmrg unsigned int save_fp; /* Nonzero if fp must be saved. */
151136ac495dSmrg unsigned int save_lr; /* Nonzero if lr (return addr) must be saved. */
151236ac495dSmrg int initialized; /* Nonzero if frame size already calculated. */
151336ac495dSmrg };
151436ac495dSmrg
151536ac495dSmrg /* Current frame information calculated by m32r_compute_frame_size. */
151636ac495dSmrg static struct m32r_frame_info current_frame_info;
151736ac495dSmrg
151836ac495dSmrg /* Zero structure to initialize current_frame_info. */
151936ac495dSmrg static struct m32r_frame_info zero_frame_info;
152036ac495dSmrg
152136ac495dSmrg #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
152236ac495dSmrg #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
152336ac495dSmrg
152436ac495dSmrg /* Tell prologue and epilogue if register REGNO should be saved / restored.
152536ac495dSmrg The return address and frame pointer are treated separately.
152636ac495dSmrg Don't consider them here. */
152736ac495dSmrg #define MUST_SAVE_REGISTER(regno, interrupt_p) \
152836ac495dSmrg ((regno) != RETURN_ADDR_REGNUM && (regno) != FRAME_POINTER_REGNUM \
1529*8feb0f0bSmrg && (df_regs_ever_live_p (regno) && (!call_used_regs[regno] || interrupt_p)))
153036ac495dSmrg
153136ac495dSmrg #define MUST_SAVE_FRAME_POINTER (df_regs_ever_live_p (FRAME_POINTER_REGNUM))
153236ac495dSmrg #define MUST_SAVE_RETURN_ADDR (df_regs_ever_live_p (RETURN_ADDR_REGNUM) || crtl->profile)
153336ac495dSmrg
153436ac495dSmrg #define SHORT_INSN_SIZE 2 /* Size of small instructions. */
153536ac495dSmrg #define LONG_INSN_SIZE 4 /* Size of long instructions. */
153636ac495dSmrg
153736ac495dSmrg /* Return the bytes needed to compute the frame pointer from the current
153836ac495dSmrg stack pointer.
153936ac495dSmrg
154036ac495dSmrg SIZE is the size needed for local variables. */
154136ac495dSmrg
154236ac495dSmrg unsigned int
m32r_compute_frame_size(poly_int64 size)1543a2dc1f3fSmrg m32r_compute_frame_size (poly_int64 size) /* # of var. bytes allocated. */
154436ac495dSmrg {
154536ac495dSmrg unsigned int regno;
154636ac495dSmrg unsigned int total_size, var_size, args_size, pretend_size, extra_size;
154736ac495dSmrg unsigned int reg_size;
154836ac495dSmrg unsigned int gmask;
154936ac495dSmrg enum m32r_function_type fn_type;
155036ac495dSmrg int interrupt_p;
155136ac495dSmrg int pic_reg_used = flag_pic && (crtl->uses_pic_offset_table
155236ac495dSmrg | crtl->profile);
155336ac495dSmrg
155436ac495dSmrg var_size = M32R_STACK_ALIGN (size);
155536ac495dSmrg args_size = M32R_STACK_ALIGN (crtl->outgoing_args_size);
155636ac495dSmrg pretend_size = crtl->args.pretend_args_size;
155736ac495dSmrg extra_size = FIRST_PARM_OFFSET (0);
155836ac495dSmrg total_size = extra_size + pretend_size + args_size + var_size;
155936ac495dSmrg reg_size = 0;
156036ac495dSmrg gmask = 0;
156136ac495dSmrg
156236ac495dSmrg /* See if this is an interrupt handler. Call used registers must be saved
156336ac495dSmrg for them too. */
156436ac495dSmrg fn_type = m32r_compute_function_type (current_function_decl);
156536ac495dSmrg interrupt_p = M32R_INTERRUPT_P (fn_type);
156636ac495dSmrg
156736ac495dSmrg /* Calculate space needed for registers. */
156836ac495dSmrg for (regno = 0; regno < M32R_MAX_INT_REGS; regno++)
156936ac495dSmrg {
157036ac495dSmrg if (MUST_SAVE_REGISTER (regno, interrupt_p)
157136ac495dSmrg || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
157236ac495dSmrg {
157336ac495dSmrg reg_size += UNITS_PER_WORD;
157436ac495dSmrg gmask |= 1 << regno;
157536ac495dSmrg }
157636ac495dSmrg }
157736ac495dSmrg
157836ac495dSmrg current_frame_info.save_fp = MUST_SAVE_FRAME_POINTER;
157936ac495dSmrg current_frame_info.save_lr = MUST_SAVE_RETURN_ADDR || pic_reg_used;
158036ac495dSmrg
158136ac495dSmrg reg_size += ((current_frame_info.save_fp + current_frame_info.save_lr)
158236ac495dSmrg * UNITS_PER_WORD);
158336ac495dSmrg total_size += reg_size;
158436ac495dSmrg
158536ac495dSmrg /* ??? Not sure this is necessary, and I don't think the epilogue
158636ac495dSmrg handler will do the right thing if this changes total_size. */
158736ac495dSmrg total_size = M32R_STACK_ALIGN (total_size);
158836ac495dSmrg
158936ac495dSmrg /* frame_size = total_size - (pretend_size + reg_size); */
159036ac495dSmrg
159136ac495dSmrg /* Save computed information. */
159236ac495dSmrg current_frame_info.total_size = total_size;
159336ac495dSmrg current_frame_info.extra_size = extra_size;
159436ac495dSmrg current_frame_info.pretend_size = pretend_size;
159536ac495dSmrg current_frame_info.var_size = var_size;
159636ac495dSmrg current_frame_info.args_size = args_size;
159736ac495dSmrg current_frame_info.reg_size = reg_size;
159836ac495dSmrg current_frame_info.gmask = gmask;
159936ac495dSmrg current_frame_info.initialized = reload_completed;
160036ac495dSmrg
160136ac495dSmrg /* Ok, we're done. */
160236ac495dSmrg return total_size;
160336ac495dSmrg }
160436ac495dSmrg
160536ac495dSmrg /* Worker function for TARGET_CAN_ELIMINATE. */
160636ac495dSmrg
160736ac495dSmrg bool
m32r_can_eliminate(const int from,const int to)160836ac495dSmrg m32r_can_eliminate (const int from, const int to)
160936ac495dSmrg {
161036ac495dSmrg return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
161136ac495dSmrg ? ! frame_pointer_needed
161236ac495dSmrg : true);
161336ac495dSmrg }
161436ac495dSmrg
161536ac495dSmrg
161636ac495dSmrg /* The table we use to reference PIC data. */
161736ac495dSmrg static rtx global_offset_table;
161836ac495dSmrg
161936ac495dSmrg static void
m32r_reload_lr(rtx sp,int size)162036ac495dSmrg m32r_reload_lr (rtx sp, int size)
162136ac495dSmrg {
162236ac495dSmrg rtx lr = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
162336ac495dSmrg
162436ac495dSmrg if (size == 0)
162536ac495dSmrg emit_insn (gen_movsi (lr, gen_frame_mem (Pmode, sp)));
162636ac495dSmrg else if (size < 32768)
162736ac495dSmrg emit_insn (gen_movsi (lr, gen_frame_mem (Pmode,
162836ac495dSmrg gen_rtx_PLUS (Pmode, sp,
162936ac495dSmrg GEN_INT (size)))));
163036ac495dSmrg else
163136ac495dSmrg {
163236ac495dSmrg rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
163336ac495dSmrg
163436ac495dSmrg emit_insn (gen_movsi (tmp, GEN_INT (size)));
163536ac495dSmrg emit_insn (gen_addsi3 (tmp, tmp, sp));
163636ac495dSmrg emit_insn (gen_movsi (lr, gen_frame_mem (Pmode, tmp)));
163736ac495dSmrg }
163836ac495dSmrg
163936ac495dSmrg emit_use (lr);
164036ac495dSmrg }
164136ac495dSmrg
164236ac495dSmrg void
m32r_load_pic_register(void)164336ac495dSmrg m32r_load_pic_register (void)
164436ac495dSmrg {
164536ac495dSmrg global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
164636ac495dSmrg emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
164736ac495dSmrg GEN_INT (TARGET_MODEL_SMALL)));
164836ac495dSmrg
164936ac495dSmrg /* Need to emit this whether or not we obey regdecls,
165036ac495dSmrg since setjmp/longjmp can cause life info to screw up. */
165136ac495dSmrg emit_use (pic_offset_table_rtx);
165236ac495dSmrg }
165336ac495dSmrg
165436ac495dSmrg /* Expand the m32r prologue as a series of insns. */
165536ac495dSmrg
165636ac495dSmrg void
m32r_expand_prologue(void)165736ac495dSmrg m32r_expand_prologue (void)
165836ac495dSmrg {
165936ac495dSmrg int regno;
166036ac495dSmrg int frame_size;
166136ac495dSmrg unsigned int gmask;
166236ac495dSmrg int pic_reg_used = flag_pic && (crtl->uses_pic_offset_table
166336ac495dSmrg | crtl->profile);
166436ac495dSmrg
166536ac495dSmrg if (! current_frame_info.initialized)
166636ac495dSmrg m32r_compute_frame_size (get_frame_size ());
166736ac495dSmrg
166836ac495dSmrg if (flag_stack_usage_info)
166936ac495dSmrg current_function_static_stack_size = current_frame_info.total_size;
167036ac495dSmrg
167136ac495dSmrg gmask = current_frame_info.gmask;
167236ac495dSmrg
167336ac495dSmrg /* These cases shouldn't happen. Catch them now. */
167436ac495dSmrg gcc_assert (current_frame_info.total_size || !gmask);
167536ac495dSmrg
167636ac495dSmrg /* Allocate space for register arguments if this is a variadic function. */
167736ac495dSmrg if (current_frame_info.pretend_size != 0)
167836ac495dSmrg {
167936ac495dSmrg /* Use a HOST_WIDE_INT temporary, since negating an unsigned int gives
168036ac495dSmrg the wrong result on a 64-bit host. */
168136ac495dSmrg HOST_WIDE_INT pretend_size = current_frame_info.pretend_size;
168236ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx,
168336ac495dSmrg stack_pointer_rtx,
168436ac495dSmrg GEN_INT (-pretend_size)));
168536ac495dSmrg }
168636ac495dSmrg
168736ac495dSmrg /* Save any registers we need to and set up fp. */
168836ac495dSmrg if (current_frame_info.save_fp)
168936ac495dSmrg emit_insn (gen_movsi_push (stack_pointer_rtx, frame_pointer_rtx));
169036ac495dSmrg
169136ac495dSmrg gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK);
169236ac495dSmrg
169336ac495dSmrg /* Save any needed call-saved regs (and call-used if this is an
169436ac495dSmrg interrupt handler). */
169536ac495dSmrg for (regno = 0; regno <= M32R_MAX_INT_REGS; ++regno)
169636ac495dSmrg {
169736ac495dSmrg if ((gmask & (1 << regno)) != 0)
169836ac495dSmrg emit_insn (gen_movsi_push (stack_pointer_rtx,
169936ac495dSmrg gen_rtx_REG (Pmode, regno)));
170036ac495dSmrg }
170136ac495dSmrg
170236ac495dSmrg if (current_frame_info.save_lr)
170336ac495dSmrg emit_insn (gen_movsi_push (stack_pointer_rtx,
170436ac495dSmrg gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM)));
170536ac495dSmrg
170636ac495dSmrg /* Allocate the stack frame. */
170736ac495dSmrg frame_size = (current_frame_info.total_size
170836ac495dSmrg - (current_frame_info.pretend_size
170936ac495dSmrg + current_frame_info.reg_size));
171036ac495dSmrg
171136ac495dSmrg if (frame_size == 0)
171236ac495dSmrg ; /* Nothing to do. */
171336ac495dSmrg else if (frame_size <= 32768)
171436ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
171536ac495dSmrg GEN_INT (-frame_size)));
171636ac495dSmrg else
171736ac495dSmrg {
171836ac495dSmrg rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
171936ac495dSmrg
172036ac495dSmrg emit_insn (gen_movsi (tmp, GEN_INT (frame_size)));
172136ac495dSmrg emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
172236ac495dSmrg }
172336ac495dSmrg
172436ac495dSmrg if (frame_pointer_needed)
172536ac495dSmrg emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
172636ac495dSmrg
172736ac495dSmrg if (crtl->profile)
172836ac495dSmrg /* Push lr for mcount (form_pc, x). */
172936ac495dSmrg emit_insn (gen_movsi_push (stack_pointer_rtx,
173036ac495dSmrg gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM)));
173136ac495dSmrg
173236ac495dSmrg if (pic_reg_used)
173336ac495dSmrg {
173436ac495dSmrg m32r_load_pic_register ();
173536ac495dSmrg m32r_reload_lr (stack_pointer_rtx,
173636ac495dSmrg (crtl->profile ? 0 : frame_size));
173736ac495dSmrg }
173836ac495dSmrg
173936ac495dSmrg if (crtl->profile && !pic_reg_used)
174036ac495dSmrg emit_insn (gen_blockage ());
174136ac495dSmrg }
174236ac495dSmrg
174336ac495dSmrg
174436ac495dSmrg /* Set up the stack and frame pointer (if desired) for the function.
174536ac495dSmrg Note, if this is changed, you need to mirror the changes in
174636ac495dSmrg m32r_compute_frame_size which calculates the prolog size. */
174736ac495dSmrg
174836ac495dSmrg static void
m32r_output_function_prologue(FILE * file)1749a2dc1f3fSmrg m32r_output_function_prologue (FILE * file)
175036ac495dSmrg {
175136ac495dSmrg enum m32r_function_type fn_type = m32r_compute_function_type (current_function_decl);
175236ac495dSmrg
175336ac495dSmrg /* If this is an interrupt handler, mark it as such. */
175436ac495dSmrg if (M32R_INTERRUPT_P (fn_type))
175536ac495dSmrg fprintf (file, "\t%s interrupt handler\n", ASM_COMMENT_START);
175636ac495dSmrg
175736ac495dSmrg if (! current_frame_info.initialized)
1758a2dc1f3fSmrg m32r_compute_frame_size (get_frame_size ());
175936ac495dSmrg
176036ac495dSmrg /* This is only for the human reader. */
176136ac495dSmrg fprintf (file,
176236ac495dSmrg "\t%s PROLOGUE, vars= %d, regs= %d, args= %d, extra= %d\n",
176336ac495dSmrg ASM_COMMENT_START,
176436ac495dSmrg current_frame_info.var_size,
176536ac495dSmrg current_frame_info.reg_size / 4,
176636ac495dSmrg current_frame_info.args_size,
176736ac495dSmrg current_frame_info.extra_size);
176836ac495dSmrg }
176936ac495dSmrg
177036ac495dSmrg /* Output RTL to pop register REGNO from the stack. */
177136ac495dSmrg
177236ac495dSmrg static void
pop(int regno)177336ac495dSmrg pop (int regno)
177436ac495dSmrg {
177536ac495dSmrg rtx x;
177636ac495dSmrg
177736ac495dSmrg x = emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, regno),
177836ac495dSmrg stack_pointer_rtx));
177936ac495dSmrg add_reg_note (x, REG_INC, stack_pointer_rtx);
178036ac495dSmrg }
178136ac495dSmrg
178236ac495dSmrg /* Expand the m32r epilogue as a series of insns. */
178336ac495dSmrg
178436ac495dSmrg void
m32r_expand_epilogue(void)178536ac495dSmrg m32r_expand_epilogue (void)
178636ac495dSmrg {
178736ac495dSmrg int regno;
178836ac495dSmrg int noepilogue = FALSE;
178936ac495dSmrg int total_size;
179036ac495dSmrg
179136ac495dSmrg gcc_assert (current_frame_info.initialized);
179236ac495dSmrg total_size = current_frame_info.total_size;
179336ac495dSmrg
179436ac495dSmrg if (total_size == 0)
179536ac495dSmrg {
179636ac495dSmrg rtx_insn *insn = get_last_insn ();
179736ac495dSmrg
179836ac495dSmrg /* If the last insn was a BARRIER, we don't have to write any code
179936ac495dSmrg because a jump (aka return) was put there. */
180036ac495dSmrg if (insn && NOTE_P (insn))
180136ac495dSmrg insn = prev_nonnote_insn (insn);
180236ac495dSmrg if (insn && BARRIER_P (insn))
180336ac495dSmrg noepilogue = TRUE;
180436ac495dSmrg }
180536ac495dSmrg
180636ac495dSmrg if (!noepilogue)
180736ac495dSmrg {
180836ac495dSmrg unsigned int var_size = current_frame_info.var_size;
180936ac495dSmrg unsigned int args_size = current_frame_info.args_size;
181036ac495dSmrg unsigned int gmask = current_frame_info.gmask;
181136ac495dSmrg int can_trust_sp_p = !cfun->calls_alloca;
181236ac495dSmrg
181336ac495dSmrg if (flag_exceptions)
181436ac495dSmrg emit_insn (gen_blockage ());
181536ac495dSmrg
181636ac495dSmrg /* The first thing to do is point the sp at the bottom of the register
181736ac495dSmrg save area. */
181836ac495dSmrg if (can_trust_sp_p)
181936ac495dSmrg {
182036ac495dSmrg unsigned int reg_offset = var_size + args_size;
182136ac495dSmrg
182236ac495dSmrg if (reg_offset == 0)
182336ac495dSmrg ; /* Nothing to do. */
182436ac495dSmrg else if (reg_offset < 32768)
182536ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
182636ac495dSmrg GEN_INT (reg_offset)));
182736ac495dSmrg else
182836ac495dSmrg {
182936ac495dSmrg rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
183036ac495dSmrg
183136ac495dSmrg emit_insn (gen_movsi (tmp, GEN_INT (reg_offset)));
183236ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
183336ac495dSmrg tmp));
183436ac495dSmrg }
183536ac495dSmrg }
183636ac495dSmrg else if (frame_pointer_needed)
183736ac495dSmrg {
183836ac495dSmrg unsigned int reg_offset = var_size + args_size;
183936ac495dSmrg
184036ac495dSmrg if (reg_offset == 0)
184136ac495dSmrg emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
184236ac495dSmrg else if (reg_offset < 32768)
184336ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx,
184436ac495dSmrg GEN_INT (reg_offset)));
184536ac495dSmrg else
184636ac495dSmrg {
184736ac495dSmrg rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
184836ac495dSmrg
184936ac495dSmrg emit_insn (gen_movsi (tmp, GEN_INT (reg_offset)));
185036ac495dSmrg emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
185136ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
185236ac495dSmrg tmp));
185336ac495dSmrg }
185436ac495dSmrg }
185536ac495dSmrg else
185636ac495dSmrg gcc_unreachable ();
185736ac495dSmrg
185836ac495dSmrg if (current_frame_info.save_lr)
185936ac495dSmrg pop (RETURN_ADDR_REGNUM);
186036ac495dSmrg
186136ac495dSmrg /* Restore any saved registers, in reverse order of course. */
186236ac495dSmrg gmask &= ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK);
186336ac495dSmrg for (regno = M32R_MAX_INT_REGS - 1; regno >= 0; --regno)
186436ac495dSmrg {
186536ac495dSmrg if ((gmask & (1L << regno)) != 0)
186636ac495dSmrg pop (regno);
186736ac495dSmrg }
186836ac495dSmrg
186936ac495dSmrg if (current_frame_info.save_fp)
187036ac495dSmrg pop (FRAME_POINTER_REGNUM);
187136ac495dSmrg
187236ac495dSmrg /* Remove varargs area if present. */
187336ac495dSmrg if (current_frame_info.pretend_size != 0)
187436ac495dSmrg emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
187536ac495dSmrg GEN_INT (current_frame_info.pretend_size)));
187636ac495dSmrg
187736ac495dSmrg emit_insn (gen_blockage ());
187836ac495dSmrg }
187936ac495dSmrg }
188036ac495dSmrg
188136ac495dSmrg /* Do any necessary cleanup after a function to restore stack, frame,
188236ac495dSmrg and regs. */
188336ac495dSmrg
188436ac495dSmrg static void
m32r_output_function_epilogue(FILE *)1885a2dc1f3fSmrg m32r_output_function_epilogue (FILE *)
188636ac495dSmrg {
188736ac495dSmrg /* Reset state info for each function. */
188836ac495dSmrg current_frame_info = zero_frame_info;
188936ac495dSmrg m32r_compute_function_type (NULL_TREE);
189036ac495dSmrg }
189136ac495dSmrg
189236ac495dSmrg /* Return nonzero if this function is known to have a null or 1 instruction
189336ac495dSmrg epilogue. */
189436ac495dSmrg
189536ac495dSmrg int
direct_return(void)189636ac495dSmrg direct_return (void)
189736ac495dSmrg {
189836ac495dSmrg if (!reload_completed)
189936ac495dSmrg return FALSE;
190036ac495dSmrg
190136ac495dSmrg if (M32R_INTERRUPT_P (m32r_compute_function_type (current_function_decl)))
190236ac495dSmrg return FALSE;
190336ac495dSmrg
190436ac495dSmrg if (! current_frame_info.initialized)
190536ac495dSmrg m32r_compute_frame_size (get_frame_size ());
190636ac495dSmrg
190736ac495dSmrg return current_frame_info.total_size == 0;
190836ac495dSmrg }
190936ac495dSmrg
191036ac495dSmrg
191136ac495dSmrg /* PIC. */
191236ac495dSmrg
191336ac495dSmrg int
m32r_legitimate_pic_operand_p(rtx x)191436ac495dSmrg m32r_legitimate_pic_operand_p (rtx x)
191536ac495dSmrg {
191636ac495dSmrg if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
191736ac495dSmrg return 0;
191836ac495dSmrg
191936ac495dSmrg if (GET_CODE (x) == CONST
192036ac495dSmrg && GET_CODE (XEXP (x, 0)) == PLUS
192136ac495dSmrg && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
192236ac495dSmrg || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
192336ac495dSmrg && (CONST_INT_P (XEXP (XEXP (x, 0), 1))))
192436ac495dSmrg return 0;
192536ac495dSmrg
192636ac495dSmrg return 1;
192736ac495dSmrg }
192836ac495dSmrg
192936ac495dSmrg rtx
m32r_legitimize_pic_address(rtx orig,rtx reg)193036ac495dSmrg m32r_legitimize_pic_address (rtx orig, rtx reg)
193136ac495dSmrg {
193236ac495dSmrg #ifdef DEBUG_PIC
193336ac495dSmrg printf("m32r_legitimize_pic_address()\n");
193436ac495dSmrg #endif
193536ac495dSmrg
193636ac495dSmrg if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
193736ac495dSmrg {
193836ac495dSmrg rtx pic_ref, address;
193936ac495dSmrg int subregs = 0;
194036ac495dSmrg
194136ac495dSmrg if (reg == 0)
194236ac495dSmrg {
194336ac495dSmrg gcc_assert (!reload_in_progress && !reload_completed);
194436ac495dSmrg reg = gen_reg_rtx (Pmode);
194536ac495dSmrg
194636ac495dSmrg subregs = 1;
194736ac495dSmrg }
194836ac495dSmrg
194936ac495dSmrg if (subregs)
195036ac495dSmrg address = gen_reg_rtx (Pmode);
195136ac495dSmrg else
195236ac495dSmrg address = reg;
195336ac495dSmrg
195436ac495dSmrg crtl->uses_pic_offset_table = 1;
195536ac495dSmrg
195636ac495dSmrg if (GET_CODE (orig) == LABEL_REF
195736ac495dSmrg || (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (orig)))
195836ac495dSmrg {
195936ac495dSmrg emit_insn (gen_gotoff_load_addr (reg, orig));
196036ac495dSmrg emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
196136ac495dSmrg return reg;
196236ac495dSmrg }
196336ac495dSmrg
196436ac495dSmrg emit_insn (gen_pic_load_addr (address, orig));
196536ac495dSmrg
196636ac495dSmrg emit_insn (gen_addsi3 (address, address, pic_offset_table_rtx));
196736ac495dSmrg pic_ref = gen_const_mem (Pmode, address);
196836ac495dSmrg emit_move_insn (reg, pic_ref);
196936ac495dSmrg return reg;
197036ac495dSmrg }
197136ac495dSmrg else if (GET_CODE (orig) == CONST)
197236ac495dSmrg {
197336ac495dSmrg rtx base, offset;
197436ac495dSmrg
197536ac495dSmrg if (GET_CODE (XEXP (orig, 0)) == PLUS
197636ac495dSmrg && XEXP (XEXP (orig, 0), 1) == pic_offset_table_rtx)
197736ac495dSmrg return orig;
197836ac495dSmrg
197936ac495dSmrg if (reg == 0)
198036ac495dSmrg {
198136ac495dSmrg gcc_assert (!reload_in_progress && !reload_completed);
198236ac495dSmrg reg = gen_reg_rtx (Pmode);
198336ac495dSmrg }
198436ac495dSmrg
198536ac495dSmrg if (GET_CODE (XEXP (orig, 0)) == PLUS)
198636ac495dSmrg {
198736ac495dSmrg base = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
198836ac495dSmrg if (base == reg)
198936ac495dSmrg offset = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), NULL_RTX);
199036ac495dSmrg else
199136ac495dSmrg offset = m32r_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), reg);
199236ac495dSmrg }
199336ac495dSmrg else
199436ac495dSmrg return orig;
199536ac495dSmrg
199636ac495dSmrg if (CONST_INT_P (offset))
199736ac495dSmrg {
199836ac495dSmrg if (INT16_P (INTVAL (offset)))
199936ac495dSmrg return plus_constant (Pmode, base, INTVAL (offset));
200036ac495dSmrg else
200136ac495dSmrg {
200236ac495dSmrg gcc_assert (! reload_in_progress && ! reload_completed);
200336ac495dSmrg offset = force_reg (Pmode, offset);
200436ac495dSmrg }
200536ac495dSmrg }
200636ac495dSmrg
200736ac495dSmrg return gen_rtx_PLUS (Pmode, base, offset);
200836ac495dSmrg }
200936ac495dSmrg
201036ac495dSmrg return orig;
201136ac495dSmrg }
201236ac495dSmrg
201336ac495dSmrg static rtx
m32r_legitimize_address(rtx x,rtx orig_x ATTRIBUTE_UNUSED,machine_mode mode ATTRIBUTE_UNUSED)201436ac495dSmrg m32r_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED,
201536ac495dSmrg machine_mode mode ATTRIBUTE_UNUSED)
201636ac495dSmrg {
201736ac495dSmrg if (flag_pic)
201836ac495dSmrg return m32r_legitimize_pic_address (x, NULL_RTX);
201936ac495dSmrg else
202036ac495dSmrg return x;
202136ac495dSmrg }
202236ac495dSmrg
202336ac495dSmrg /* Worker function for TARGET_MODE_DEPENDENT_ADDRESS_P. */
202436ac495dSmrg
202536ac495dSmrg static bool
m32r_mode_dependent_address_p(const_rtx addr,addr_space_t as ATTRIBUTE_UNUSED)202636ac495dSmrg m32r_mode_dependent_address_p (const_rtx addr, addr_space_t as ATTRIBUTE_UNUSED)
202736ac495dSmrg {
202836ac495dSmrg if (GET_CODE (addr) == LO_SUM)
202936ac495dSmrg return true;
203036ac495dSmrg
203136ac495dSmrg return false;
203236ac495dSmrg }
203336ac495dSmrg
203436ac495dSmrg /* Nested function support. */
203536ac495dSmrg
203636ac495dSmrg /* Emit RTL insns to initialize the variable parts of a trampoline.
203736ac495dSmrg FNADDR is an RTX for the address of the function's pure code.
203836ac495dSmrg CXT is an RTX for the static chain value for the function. */
203936ac495dSmrg
204036ac495dSmrg void
m32r_initialize_trampoline(rtx tramp ATTRIBUTE_UNUSED,rtx fnaddr ATTRIBUTE_UNUSED,rtx cxt ATTRIBUTE_UNUSED)204136ac495dSmrg m32r_initialize_trampoline (rtx tramp ATTRIBUTE_UNUSED,
204236ac495dSmrg rtx fnaddr ATTRIBUTE_UNUSED,
204336ac495dSmrg rtx cxt ATTRIBUTE_UNUSED)
204436ac495dSmrg {
204536ac495dSmrg }
204636ac495dSmrg
204736ac495dSmrg static void
m32r_file_start(void)204836ac495dSmrg m32r_file_start (void)
204936ac495dSmrg {
205036ac495dSmrg default_file_start ();
205136ac495dSmrg
205236ac495dSmrg if (flag_verbose_asm)
205336ac495dSmrg fprintf (asm_out_file,
205436ac495dSmrg "%s M32R/D special options: -G %d\n",
205536ac495dSmrg ASM_COMMENT_START, g_switch_value);
205636ac495dSmrg
205736ac495dSmrg if (TARGET_LITTLE_ENDIAN)
205836ac495dSmrg fprintf (asm_out_file, "\t.little\n");
205936ac495dSmrg }
206036ac495dSmrg
206136ac495dSmrg /* Print operand X (an rtx) in assembler syntax to file FILE.
206236ac495dSmrg CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
206336ac495dSmrg For `%' followed by punctuation, CODE is the punctuation and X is null. */
206436ac495dSmrg
206536ac495dSmrg static void
m32r_print_operand(FILE * file,rtx x,int code)206636ac495dSmrg m32r_print_operand (FILE * file, rtx x, int code)
206736ac495dSmrg {
206836ac495dSmrg rtx addr;
206936ac495dSmrg
207036ac495dSmrg switch (code)
207136ac495dSmrg {
207236ac495dSmrg /* The 's' and 'p' codes are used by output_block_move() to
207336ac495dSmrg indicate post-increment 's'tores and 'p're-increment loads. */
207436ac495dSmrg case 's':
207536ac495dSmrg if (REG_P (x))
207636ac495dSmrg fprintf (file, "@+%s", reg_names [REGNO (x)]);
207736ac495dSmrg else
207836ac495dSmrg output_operand_lossage ("invalid operand to %%s code");
207936ac495dSmrg return;
208036ac495dSmrg
208136ac495dSmrg case 'p':
208236ac495dSmrg if (REG_P (x))
208336ac495dSmrg fprintf (file, "@%s+", reg_names [REGNO (x)]);
208436ac495dSmrg else
208536ac495dSmrg output_operand_lossage ("invalid operand to %%p code");
208636ac495dSmrg return;
208736ac495dSmrg
208836ac495dSmrg case 'R' :
208936ac495dSmrg /* Write second word of DImode or DFmode reference,
209036ac495dSmrg register or memory. */
209136ac495dSmrg if (REG_P (x))
209236ac495dSmrg fputs (reg_names[REGNO (x)+1], file);
209336ac495dSmrg else if (MEM_P (x))
209436ac495dSmrg {
209536ac495dSmrg machine_mode mode = GET_MODE (x);
209636ac495dSmrg
209736ac495dSmrg fprintf (file, "@(");
209836ac495dSmrg /* Handle possible auto-increment. Since it is pre-increment and
209936ac495dSmrg we have already done it, we can just use an offset of four. */
210036ac495dSmrg /* ??? This is taken from rs6000.c I think. I don't think it is
210136ac495dSmrg currently necessary, but keep it around. */
210236ac495dSmrg if (GET_CODE (XEXP (x, 0)) == PRE_INC
210336ac495dSmrg || GET_CODE (XEXP (x, 0)) == PRE_DEC)
210436ac495dSmrg output_address (mode, plus_constant (Pmode,
210536ac495dSmrg XEXP (XEXP (x, 0), 0), 4));
210636ac495dSmrg else
210736ac495dSmrg output_address (mode, plus_constant (Pmode, XEXP (x, 0), 4));
210836ac495dSmrg fputc (')', file);
210936ac495dSmrg }
211036ac495dSmrg else
211136ac495dSmrg output_operand_lossage ("invalid operand to %%R code");
211236ac495dSmrg return;
211336ac495dSmrg
211436ac495dSmrg case 'H' : /* High word. */
211536ac495dSmrg case 'L' : /* Low word. */
211636ac495dSmrg if (REG_P (x))
211736ac495dSmrg {
211836ac495dSmrg /* L = least significant word, H = most significant word. */
211936ac495dSmrg if ((WORDS_BIG_ENDIAN != 0) ^ (code == 'L'))
212036ac495dSmrg fputs (reg_names[REGNO (x)], file);
212136ac495dSmrg else
212236ac495dSmrg fputs (reg_names[REGNO (x)+1], file);
212336ac495dSmrg }
212436ac495dSmrg else if (CONST_INT_P (x)
212536ac495dSmrg || GET_CODE (x) == CONST_DOUBLE)
212636ac495dSmrg {
212736ac495dSmrg rtx first, second;
212836ac495dSmrg
212936ac495dSmrg split_double (x, &first, &second);
213036ac495dSmrg fprintf (file, HOST_WIDE_INT_PRINT_HEX,
213136ac495dSmrg code == 'L' ? INTVAL (first) : INTVAL (second));
213236ac495dSmrg }
213336ac495dSmrg else
213436ac495dSmrg output_operand_lossage ("invalid operand to %%H/%%L code");
213536ac495dSmrg return;
213636ac495dSmrg
213736ac495dSmrg case 'A' :
213836ac495dSmrg {
213936ac495dSmrg char str[30];
214036ac495dSmrg
214136ac495dSmrg if (GET_CODE (x) != CONST_DOUBLE
214236ac495dSmrg || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
214336ac495dSmrg fatal_insn ("bad insn for 'A'", x);
214436ac495dSmrg
214536ac495dSmrg real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x), sizeof (str), 0, 1);
214636ac495dSmrg fprintf (file, "%s", str);
214736ac495dSmrg return;
214836ac495dSmrg }
214936ac495dSmrg
215036ac495dSmrg case 'B' : /* Bottom half. */
215136ac495dSmrg case 'T' : /* Top half. */
215236ac495dSmrg /* Output the argument to a `seth' insn (sets the Top half-word).
215336ac495dSmrg For constants output arguments to a seth/or3 pair to set Top and
215436ac495dSmrg Bottom halves. For symbols output arguments to a seth/add3 pair to
215536ac495dSmrg set Top and Bottom halves. The difference exists because for
215636ac495dSmrg constants seth/or3 is more readable but for symbols we need to use
215736ac495dSmrg the same scheme as `ld' and `st' insns (16-bit addend is signed). */
215836ac495dSmrg switch (GET_CODE (x))
215936ac495dSmrg {
216036ac495dSmrg case CONST_INT :
216136ac495dSmrg case CONST_DOUBLE :
216236ac495dSmrg {
216336ac495dSmrg rtx first, second;
216436ac495dSmrg
216536ac495dSmrg split_double (x, &first, &second);
216636ac495dSmrg x = WORDS_BIG_ENDIAN ? second : first;
216736ac495dSmrg fprintf (file, HOST_WIDE_INT_PRINT_HEX,
216836ac495dSmrg (code == 'B'
216936ac495dSmrg ? INTVAL (x) & 0xffff
217036ac495dSmrg : (INTVAL (x) >> 16) & 0xffff));
217136ac495dSmrg }
217236ac495dSmrg return;
217336ac495dSmrg case CONST :
217436ac495dSmrg case SYMBOL_REF :
217536ac495dSmrg if (code == 'B'
217636ac495dSmrg && small_data_operand (x, VOIDmode))
217736ac495dSmrg {
217836ac495dSmrg fputs ("sda(", file);
217936ac495dSmrg output_addr_const (file, x);
218036ac495dSmrg fputc (')', file);
218136ac495dSmrg return;
218236ac495dSmrg }
218336ac495dSmrg /* fall through */
218436ac495dSmrg case LABEL_REF :
218536ac495dSmrg fputs (code == 'T' ? "shigh(" : "low(", file);
218636ac495dSmrg output_addr_const (file, x);
218736ac495dSmrg fputc (')', file);
218836ac495dSmrg return;
218936ac495dSmrg default :
219036ac495dSmrg output_operand_lossage ("invalid operand to %%T/%%B code");
219136ac495dSmrg return;
219236ac495dSmrg }
219336ac495dSmrg break;
219436ac495dSmrg
219536ac495dSmrg case 'U' :
219636ac495dSmrg /* ??? wip */
219736ac495dSmrg /* Output a load/store with update indicator if appropriate. */
219836ac495dSmrg if (MEM_P (x))
219936ac495dSmrg {
220036ac495dSmrg if (GET_CODE (XEXP (x, 0)) == PRE_INC
220136ac495dSmrg || GET_CODE (XEXP (x, 0)) == PRE_DEC)
220236ac495dSmrg fputs (".a", file);
220336ac495dSmrg }
220436ac495dSmrg else
220536ac495dSmrg output_operand_lossage ("invalid operand to %%U code");
220636ac495dSmrg return;
220736ac495dSmrg
220836ac495dSmrg case 'N' :
220936ac495dSmrg /* Print a constant value negated. */
221036ac495dSmrg if (CONST_INT_P (x))
221136ac495dSmrg output_addr_const (file, GEN_INT (- INTVAL (x)));
221236ac495dSmrg else
221336ac495dSmrg output_operand_lossage ("invalid operand to %%N code");
221436ac495dSmrg return;
221536ac495dSmrg
221636ac495dSmrg case 'X' :
221736ac495dSmrg /* Print a const_int in hex. Used in comments. */
221836ac495dSmrg if (CONST_INT_P (x))
221936ac495dSmrg fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
222036ac495dSmrg return;
222136ac495dSmrg
222236ac495dSmrg case '#' :
222336ac495dSmrg fputs (IMMEDIATE_PREFIX, file);
222436ac495dSmrg return;
222536ac495dSmrg
222636ac495dSmrg case 0 :
222736ac495dSmrg /* Do nothing special. */
222836ac495dSmrg break;
222936ac495dSmrg
223036ac495dSmrg default :
223136ac495dSmrg /* Unknown flag. */
223236ac495dSmrg output_operand_lossage ("invalid operand output code");
223336ac495dSmrg }
223436ac495dSmrg
223536ac495dSmrg switch (GET_CODE (x))
223636ac495dSmrg {
223736ac495dSmrg case REG :
223836ac495dSmrg fputs (reg_names[REGNO (x)], file);
223936ac495dSmrg break;
224036ac495dSmrg
224136ac495dSmrg case MEM :
224236ac495dSmrg addr = XEXP (x, 0);
224336ac495dSmrg if (GET_CODE (addr) == PRE_INC)
224436ac495dSmrg {
224536ac495dSmrg if (!REG_P (XEXP (addr, 0)))
224636ac495dSmrg fatal_insn ("pre-increment address is not a register", x);
224736ac495dSmrg
224836ac495dSmrg fprintf (file, "@+%s", reg_names[REGNO (XEXP (addr, 0))]);
224936ac495dSmrg }
225036ac495dSmrg else if (GET_CODE (addr) == PRE_DEC)
225136ac495dSmrg {
225236ac495dSmrg if (!REG_P (XEXP (addr, 0)))
225336ac495dSmrg fatal_insn ("pre-decrement address is not a register", x);
225436ac495dSmrg
225536ac495dSmrg fprintf (file, "@-%s", reg_names[REGNO (XEXP (addr, 0))]);
225636ac495dSmrg }
225736ac495dSmrg else if (GET_CODE (addr) == POST_INC)
225836ac495dSmrg {
225936ac495dSmrg if (!REG_P (XEXP (addr, 0)))
226036ac495dSmrg fatal_insn ("post-increment address is not a register", x);
226136ac495dSmrg
226236ac495dSmrg fprintf (file, "@%s+", reg_names[REGNO (XEXP (addr, 0))]);
226336ac495dSmrg }
226436ac495dSmrg else
226536ac495dSmrg {
226636ac495dSmrg fputs ("@(", file);
226736ac495dSmrg output_address (GET_MODE (x), addr);
226836ac495dSmrg fputc (')', file);
226936ac495dSmrg }
227036ac495dSmrg break;
227136ac495dSmrg
227236ac495dSmrg case CONST_DOUBLE :
227336ac495dSmrg /* We handle SFmode constants here as output_addr_const doesn't. */
227436ac495dSmrg if (GET_MODE (x) == SFmode)
227536ac495dSmrg {
227636ac495dSmrg long l;
227736ac495dSmrg
227836ac495dSmrg REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l);
227936ac495dSmrg fprintf (file, "0x%08lx", l);
228036ac495dSmrg break;
228136ac495dSmrg }
228236ac495dSmrg
228336ac495dSmrg /* FALLTHRU */
228436ac495dSmrg /* Let output_addr_const deal with it. */
228536ac495dSmrg
228636ac495dSmrg default :
228736ac495dSmrg output_addr_const (file, x);
228836ac495dSmrg break;
228936ac495dSmrg }
229036ac495dSmrg }
229136ac495dSmrg
229236ac495dSmrg /* Print a memory address as an operand to reference that memory location. */
229336ac495dSmrg
229436ac495dSmrg static void
m32r_print_operand_address(FILE * file,machine_mode,rtx addr)229536ac495dSmrg m32r_print_operand_address (FILE * file, machine_mode /*mode*/, rtx addr)
229636ac495dSmrg {
229736ac495dSmrg rtx base;
229836ac495dSmrg rtx index = 0;
229936ac495dSmrg int offset = 0;
230036ac495dSmrg
230136ac495dSmrg switch (GET_CODE (addr))
230236ac495dSmrg {
230336ac495dSmrg case REG :
230436ac495dSmrg fputs (reg_names[REGNO (addr)], file);
230536ac495dSmrg break;
230636ac495dSmrg
230736ac495dSmrg case PLUS :
230836ac495dSmrg if (CONST_INT_P (XEXP (addr, 0)))
230936ac495dSmrg offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
231036ac495dSmrg else if (CONST_INT_P (XEXP (addr, 1)))
231136ac495dSmrg offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
231236ac495dSmrg else
231336ac495dSmrg base = XEXP (addr, 0), index = XEXP (addr, 1);
231436ac495dSmrg if (REG_P (base))
231536ac495dSmrg {
231636ac495dSmrg /* Print the offset first (if present) to conform to the manual. */
231736ac495dSmrg if (index == 0)
231836ac495dSmrg {
231936ac495dSmrg if (offset != 0)
232036ac495dSmrg fprintf (file, "%d,", offset);
232136ac495dSmrg fputs (reg_names[REGNO (base)], file);
232236ac495dSmrg }
232336ac495dSmrg /* The chip doesn't support this, but left in for generality. */
232436ac495dSmrg else if (REG_P (index))
232536ac495dSmrg fprintf (file, "%s,%s",
232636ac495dSmrg reg_names[REGNO (base)], reg_names[REGNO (index)]);
232736ac495dSmrg /* Not sure this can happen, but leave in for now. */
232836ac495dSmrg else if (GET_CODE (index) == SYMBOL_REF)
232936ac495dSmrg {
233036ac495dSmrg output_addr_const (file, index);
233136ac495dSmrg fputc (',', file);
233236ac495dSmrg fputs (reg_names[REGNO (base)], file);
233336ac495dSmrg }
233436ac495dSmrg else
233536ac495dSmrg fatal_insn ("bad address", addr);
233636ac495dSmrg }
233736ac495dSmrg else if (GET_CODE (base) == LO_SUM)
233836ac495dSmrg {
233936ac495dSmrg gcc_assert (!index && REG_P (XEXP (base, 0)));
234036ac495dSmrg if (small_data_operand (XEXP (base, 1), VOIDmode))
234136ac495dSmrg fputs ("sda(", file);
234236ac495dSmrg else
234336ac495dSmrg fputs ("low(", file);
234436ac495dSmrg output_addr_const (file, plus_constant (Pmode, XEXP (base, 1),
234536ac495dSmrg offset));
234636ac495dSmrg fputs ("),", file);
234736ac495dSmrg fputs (reg_names[REGNO (XEXP (base, 0))], file);
234836ac495dSmrg }
234936ac495dSmrg else
235036ac495dSmrg fatal_insn ("bad address", addr);
235136ac495dSmrg break;
235236ac495dSmrg
235336ac495dSmrg case LO_SUM :
235436ac495dSmrg if (!REG_P (XEXP (addr, 0)))
235536ac495dSmrg fatal_insn ("lo_sum not of register", addr);
235636ac495dSmrg if (small_data_operand (XEXP (addr, 1), VOIDmode))
235736ac495dSmrg fputs ("sda(", file);
235836ac495dSmrg else
235936ac495dSmrg fputs ("low(", file);
236036ac495dSmrg output_addr_const (file, XEXP (addr, 1));
236136ac495dSmrg fputs ("),", file);
236236ac495dSmrg fputs (reg_names[REGNO (XEXP (addr, 0))], file);
236336ac495dSmrg break;
236436ac495dSmrg
236536ac495dSmrg case PRE_INC : /* Assume SImode. */
236636ac495dSmrg fprintf (file, "+%s", reg_names[REGNO (XEXP (addr, 0))]);
236736ac495dSmrg break;
236836ac495dSmrg
236936ac495dSmrg case PRE_DEC : /* Assume SImode. */
237036ac495dSmrg fprintf (file, "-%s", reg_names[REGNO (XEXP (addr, 0))]);
237136ac495dSmrg break;
237236ac495dSmrg
237336ac495dSmrg case POST_INC : /* Assume SImode. */
237436ac495dSmrg fprintf (file, "%s+", reg_names[REGNO (XEXP (addr, 0))]);
237536ac495dSmrg break;
237636ac495dSmrg
237736ac495dSmrg default :
237836ac495dSmrg output_addr_const (file, addr);
237936ac495dSmrg break;
238036ac495dSmrg }
238136ac495dSmrg }
238236ac495dSmrg
238336ac495dSmrg static bool
m32r_print_operand_punct_valid_p(unsigned char code)238436ac495dSmrg m32r_print_operand_punct_valid_p (unsigned char code)
238536ac495dSmrg {
238636ac495dSmrg return m32r_punct_chars[code];
238736ac495dSmrg }
238836ac495dSmrg
238936ac495dSmrg /* Return true if the operands are the constants 0 and 1. */
239036ac495dSmrg
239136ac495dSmrg int
zero_and_one(rtx operand1,rtx operand2)239236ac495dSmrg zero_and_one (rtx operand1, rtx operand2)
239336ac495dSmrg {
239436ac495dSmrg return
239536ac495dSmrg CONST_INT_P (operand1)
239636ac495dSmrg && CONST_INT_P (operand2)
239736ac495dSmrg && ( ((INTVAL (operand1) == 0) && (INTVAL (operand2) == 1))
239836ac495dSmrg ||((INTVAL (operand1) == 1) && (INTVAL (operand2) == 0)));
239936ac495dSmrg }
240036ac495dSmrg
240136ac495dSmrg /* Generate the correct assembler code to handle the conditional loading of a
240236ac495dSmrg value into a register. It is known that the operands satisfy the
240336ac495dSmrg conditional_move_operand() function above. The destination is operand[0].
240436ac495dSmrg The condition is operand [1]. The 'true' value is operand [2] and the
240536ac495dSmrg 'false' value is operand [3]. */
240636ac495dSmrg
240736ac495dSmrg char *
emit_cond_move(rtx * operands,rtx insn ATTRIBUTE_UNUSED)240836ac495dSmrg emit_cond_move (rtx * operands, rtx insn ATTRIBUTE_UNUSED)
240936ac495dSmrg {
241036ac495dSmrg static char buffer [100];
241136ac495dSmrg const char * dest = reg_names [REGNO (operands [0])];
241236ac495dSmrg
241336ac495dSmrg buffer [0] = 0;
241436ac495dSmrg
241536ac495dSmrg /* Destination must be a register. */
241636ac495dSmrg gcc_assert (REG_P (operands [0]));
241736ac495dSmrg gcc_assert (conditional_move_operand (operands [2], SImode));
241836ac495dSmrg gcc_assert (conditional_move_operand (operands [3], SImode));
241936ac495dSmrg
242036ac495dSmrg /* Check to see if the test is reversed. */
242136ac495dSmrg if (GET_CODE (operands [1]) == NE)
242236ac495dSmrg {
242336ac495dSmrg rtx tmp = operands [2];
242436ac495dSmrg operands [2] = operands [3];
242536ac495dSmrg operands [3] = tmp;
242636ac495dSmrg }
242736ac495dSmrg
242836ac495dSmrg sprintf (buffer, "mvfc %s, cbr", dest);
242936ac495dSmrg
243036ac495dSmrg /* If the true value was '0' then we need to invert the results of the move. */
243136ac495dSmrg if (INTVAL (operands [2]) == 0)
243236ac495dSmrg sprintf (buffer + strlen (buffer), "\n\txor3 %s, %s, #1",
243336ac495dSmrg dest, dest);
243436ac495dSmrg
243536ac495dSmrg return buffer;
243636ac495dSmrg }
243736ac495dSmrg
243836ac495dSmrg /* Returns true if the registers contained in the two
243936ac495dSmrg rtl expressions are different. */
244036ac495dSmrg
244136ac495dSmrg int
m32r_not_same_reg(rtx a,rtx b)244236ac495dSmrg m32r_not_same_reg (rtx a, rtx b)
244336ac495dSmrg {
244436ac495dSmrg int reg_a = -1;
244536ac495dSmrg int reg_b = -2;
244636ac495dSmrg
244736ac495dSmrg while (GET_CODE (a) == SUBREG)
244836ac495dSmrg a = SUBREG_REG (a);
244936ac495dSmrg
245036ac495dSmrg if (REG_P (a))
245136ac495dSmrg reg_a = REGNO (a);
245236ac495dSmrg
245336ac495dSmrg while (GET_CODE (b) == SUBREG)
245436ac495dSmrg b = SUBREG_REG (b);
245536ac495dSmrg
245636ac495dSmrg if (REG_P (b))
245736ac495dSmrg reg_b = REGNO (b);
245836ac495dSmrg
245936ac495dSmrg return reg_a != reg_b;
246036ac495dSmrg }
246136ac495dSmrg
246236ac495dSmrg
246336ac495dSmrg rtx
m32r_function_symbol(const char * name)246436ac495dSmrg m32r_function_symbol (const char *name)
246536ac495dSmrg {
246636ac495dSmrg int extra_flags = 0;
246736ac495dSmrg enum m32r_model model;
246836ac495dSmrg rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
246936ac495dSmrg
247036ac495dSmrg if (TARGET_MODEL_SMALL)
247136ac495dSmrg model = M32R_MODEL_SMALL;
247236ac495dSmrg else if (TARGET_MODEL_MEDIUM)
247336ac495dSmrg model = M32R_MODEL_MEDIUM;
247436ac495dSmrg else if (TARGET_MODEL_LARGE)
247536ac495dSmrg model = M32R_MODEL_LARGE;
247636ac495dSmrg else
247736ac495dSmrg gcc_unreachable (); /* Shouldn't happen. */
247836ac495dSmrg extra_flags |= model << SYMBOL_FLAG_MODEL_SHIFT;
247936ac495dSmrg
248036ac495dSmrg if (extra_flags)
248136ac495dSmrg SYMBOL_REF_FLAGS (sym) |= extra_flags;
248236ac495dSmrg
248336ac495dSmrg return sym;
248436ac495dSmrg }
248536ac495dSmrg
248636ac495dSmrg /* Use a library function to move some bytes. */
248736ac495dSmrg
248836ac495dSmrg static void
block_move_call(rtx dest_reg,rtx src_reg,rtx bytes_rtx)248936ac495dSmrg block_move_call (rtx dest_reg, rtx src_reg, rtx bytes_rtx)
249036ac495dSmrg {
249136ac495dSmrg /* We want to pass the size as Pmode, which will normally be SImode
249236ac495dSmrg but will be DImode if we are using 64-bit longs and pointers. */
249336ac495dSmrg if (GET_MODE (bytes_rtx) != VOIDmode
249436ac495dSmrg && GET_MODE (bytes_rtx) != Pmode)
249536ac495dSmrg bytes_rtx = convert_to_mode (Pmode, bytes_rtx, 1);
249636ac495dSmrg
249736ac495dSmrg emit_library_call (m32r_function_symbol ("memcpy"), LCT_NORMAL,
2498a2dc1f3fSmrg VOIDmode, dest_reg, Pmode, src_reg, Pmode,
249936ac495dSmrg convert_to_mode (TYPE_MODE (sizetype), bytes_rtx,
250036ac495dSmrg TYPE_UNSIGNED (sizetype)),
250136ac495dSmrg TYPE_MODE (sizetype));
250236ac495dSmrg }
250336ac495dSmrg
250436ac495dSmrg /* Expand string/block move operations.
250536ac495dSmrg
250636ac495dSmrg operands[0] is the pointer to the destination.
250736ac495dSmrg operands[1] is the pointer to the source.
250836ac495dSmrg operands[2] is the number of bytes to move.
250936ac495dSmrg operands[3] is the alignment.
251036ac495dSmrg
251136ac495dSmrg Returns 1 upon success, 0 otherwise. */
251236ac495dSmrg
251336ac495dSmrg int
m32r_expand_block_move(rtx operands[])251436ac495dSmrg m32r_expand_block_move (rtx operands[])
251536ac495dSmrg {
251636ac495dSmrg rtx orig_dst = operands[0];
251736ac495dSmrg rtx orig_src = operands[1];
251836ac495dSmrg rtx bytes_rtx = operands[2];
251936ac495dSmrg rtx align_rtx = operands[3];
252036ac495dSmrg int constp = CONST_INT_P (bytes_rtx);
252136ac495dSmrg HOST_WIDE_INT bytes = constp ? INTVAL (bytes_rtx) : 0;
252236ac495dSmrg int align = INTVAL (align_rtx);
252336ac495dSmrg int leftover;
252436ac495dSmrg rtx src_reg;
252536ac495dSmrg rtx dst_reg;
252636ac495dSmrg
252736ac495dSmrg if (constp && bytes <= 0)
252836ac495dSmrg return 1;
252936ac495dSmrg
253036ac495dSmrg /* Move the address into scratch registers. */
253136ac495dSmrg dst_reg = copy_addr_to_reg (XEXP (orig_dst, 0));
253236ac495dSmrg src_reg = copy_addr_to_reg (XEXP (orig_src, 0));
253336ac495dSmrg
253436ac495dSmrg if (align > UNITS_PER_WORD)
253536ac495dSmrg align = UNITS_PER_WORD;
253636ac495dSmrg
253736ac495dSmrg /* If we prefer size over speed, always use a function call.
253836ac495dSmrg If we do not know the size, use a function call.
253936ac495dSmrg If the blocks are not word aligned, use a function call. */
254036ac495dSmrg if (optimize_size || ! constp || align != UNITS_PER_WORD)
254136ac495dSmrg {
254236ac495dSmrg block_move_call (dst_reg, src_reg, bytes_rtx);
254336ac495dSmrg return 0;
254436ac495dSmrg }
254536ac495dSmrg
254636ac495dSmrg leftover = bytes % MAX_MOVE_BYTES;
254736ac495dSmrg bytes -= leftover;
254836ac495dSmrg
254936ac495dSmrg /* If necessary, generate a loop to handle the bulk of the copy. */
255036ac495dSmrg if (bytes)
255136ac495dSmrg {
255236ac495dSmrg rtx_code_label *label = NULL;
255336ac495dSmrg rtx final_src = NULL_RTX;
255436ac495dSmrg rtx at_a_time = GEN_INT (MAX_MOVE_BYTES);
255536ac495dSmrg rtx rounded_total = GEN_INT (bytes);
255636ac495dSmrg rtx new_dst_reg = gen_reg_rtx (SImode);
255736ac495dSmrg rtx new_src_reg = gen_reg_rtx (SImode);
255836ac495dSmrg
255936ac495dSmrg /* If we are going to have to perform this loop more than
256036ac495dSmrg once, then generate a label and compute the address the
256136ac495dSmrg source register will contain upon completion of the final
256236ac495dSmrg iteration. */
256336ac495dSmrg if (bytes > MAX_MOVE_BYTES)
256436ac495dSmrg {
256536ac495dSmrg final_src = gen_reg_rtx (Pmode);
256636ac495dSmrg
256736ac495dSmrg if (INT16_P(bytes))
256836ac495dSmrg emit_insn (gen_addsi3 (final_src, src_reg, rounded_total));
256936ac495dSmrg else
257036ac495dSmrg {
257136ac495dSmrg emit_insn (gen_movsi (final_src, rounded_total));
257236ac495dSmrg emit_insn (gen_addsi3 (final_src, final_src, src_reg));
257336ac495dSmrg }
257436ac495dSmrg
257536ac495dSmrg label = gen_label_rtx ();
257636ac495dSmrg emit_label (label);
257736ac495dSmrg }
257836ac495dSmrg
257936ac495dSmrg /* It is known that output_block_move() will update src_reg to point
258036ac495dSmrg to the word after the end of the source block, and dst_reg to point
258136ac495dSmrg to the last word of the destination block, provided that the block
258236ac495dSmrg is MAX_MOVE_BYTES long. */
2583*8feb0f0bSmrg emit_insn (gen_cpymemsi_internal (dst_reg, src_reg, at_a_time,
258436ac495dSmrg new_dst_reg, new_src_reg));
258536ac495dSmrg emit_move_insn (dst_reg, new_dst_reg);
258636ac495dSmrg emit_move_insn (src_reg, new_src_reg);
258736ac495dSmrg emit_insn (gen_addsi3 (dst_reg, dst_reg, GEN_INT (4)));
258836ac495dSmrg
258936ac495dSmrg if (bytes > MAX_MOVE_BYTES)
259036ac495dSmrg {
259136ac495dSmrg rtx test = gen_rtx_NE (VOIDmode, src_reg, final_src);
259236ac495dSmrg emit_jump_insn (gen_cbranchsi4 (test, src_reg, final_src, label));
259336ac495dSmrg }
259436ac495dSmrg }
259536ac495dSmrg
259636ac495dSmrg if (leftover)
2597*8feb0f0bSmrg emit_insn (gen_cpymemsi_internal (dst_reg, src_reg, GEN_INT (leftover),
259836ac495dSmrg gen_reg_rtx (SImode),
259936ac495dSmrg gen_reg_rtx (SImode)));
260036ac495dSmrg return 1;
260136ac495dSmrg }
260236ac495dSmrg
260336ac495dSmrg
260436ac495dSmrg /* Emit load/stores for a small constant word aligned block_move.
260536ac495dSmrg
260636ac495dSmrg operands[0] is the memory address of the destination.
260736ac495dSmrg operands[1] is the memory address of the source.
260836ac495dSmrg operands[2] is the number of bytes to move.
260936ac495dSmrg operands[3] is a temp register.
261036ac495dSmrg operands[4] is a temp register. */
261136ac495dSmrg
261236ac495dSmrg void
m32r_output_block_move(rtx insn ATTRIBUTE_UNUSED,rtx operands[])261336ac495dSmrg m32r_output_block_move (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
261436ac495dSmrg {
261536ac495dSmrg HOST_WIDE_INT bytes = INTVAL (operands[2]);
261636ac495dSmrg int first_time;
261736ac495dSmrg int got_extra = 0;
261836ac495dSmrg
261936ac495dSmrg gcc_assert (bytes >= 1 && bytes <= MAX_MOVE_BYTES);
262036ac495dSmrg
262136ac495dSmrg /* We do not have a post-increment store available, so the first set of
262236ac495dSmrg stores are done without any increment, then the remaining ones can use
262336ac495dSmrg the pre-increment addressing mode.
262436ac495dSmrg
262536ac495dSmrg Note: expand_block_move() also relies upon this behavior when building
262636ac495dSmrg loops to copy large blocks. */
262736ac495dSmrg first_time = 1;
262836ac495dSmrg
262936ac495dSmrg while (bytes > 0)
263036ac495dSmrg {
263136ac495dSmrg if (bytes >= 8)
263236ac495dSmrg {
263336ac495dSmrg if (first_time)
263436ac495dSmrg {
263536ac495dSmrg output_asm_insn ("ld\t%5, %p1", operands);
263636ac495dSmrg output_asm_insn ("ld\t%6, %p1", operands);
263736ac495dSmrg output_asm_insn ("st\t%5, @%0", operands);
263836ac495dSmrg output_asm_insn ("st\t%6, %s0", operands);
263936ac495dSmrg }
264036ac495dSmrg else
264136ac495dSmrg {
264236ac495dSmrg output_asm_insn ("ld\t%5, %p1", operands);
264336ac495dSmrg output_asm_insn ("ld\t%6, %p1", operands);
264436ac495dSmrg output_asm_insn ("st\t%5, %s0", operands);
264536ac495dSmrg output_asm_insn ("st\t%6, %s0", operands);
264636ac495dSmrg }
264736ac495dSmrg
264836ac495dSmrg bytes -= 8;
264936ac495dSmrg }
265036ac495dSmrg else if (bytes >= 4)
265136ac495dSmrg {
265236ac495dSmrg if (bytes > 4)
265336ac495dSmrg got_extra = 1;
265436ac495dSmrg
265536ac495dSmrg output_asm_insn ("ld\t%5, %p1", operands);
265636ac495dSmrg
265736ac495dSmrg if (got_extra)
265836ac495dSmrg output_asm_insn ("ld\t%6, %p1", operands);
265936ac495dSmrg
266036ac495dSmrg if (first_time)
266136ac495dSmrg output_asm_insn ("st\t%5, @%0", operands);
266236ac495dSmrg else
266336ac495dSmrg output_asm_insn ("st\t%5, %s0", operands);
266436ac495dSmrg
266536ac495dSmrg bytes -= 4;
266636ac495dSmrg }
266736ac495dSmrg else
266836ac495dSmrg {
266936ac495dSmrg /* Get the entire next word, even though we do not want all of it.
267036ac495dSmrg The saves us from doing several smaller loads, and we assume that
267136ac495dSmrg we cannot cause a page fault when at least part of the word is in
267236ac495dSmrg valid memory [since we don't get called if things aren't properly
267336ac495dSmrg aligned]. */
267436ac495dSmrg int dst_offset = first_time ? 0 : 4;
267536ac495dSmrg /* The amount of increment we have to make to the
267636ac495dSmrg destination pointer. */
267736ac495dSmrg int dst_inc_amount = dst_offset + bytes - 4;
267836ac495dSmrg /* The same for the source pointer. */
2679*8feb0f0bSmrg int src_inc_amount = bytes - (got_extra ? 4 : 0);
268036ac495dSmrg int last_shift;
268136ac495dSmrg rtx my_operands[3];
268236ac495dSmrg
268336ac495dSmrg /* If got_extra is true then we have already loaded
268436ac495dSmrg the next word as part of loading and storing the previous word. */
268536ac495dSmrg if (! got_extra)
268636ac495dSmrg output_asm_insn ("ld\t%6, @%1", operands);
268736ac495dSmrg
268836ac495dSmrg if (bytes >= 2)
268936ac495dSmrg {
269036ac495dSmrg bytes -= 2;
269136ac495dSmrg
269236ac495dSmrg output_asm_insn ("sra3\t%5, %6, #16", operands);
269336ac495dSmrg my_operands[0] = operands[5];
269436ac495dSmrg my_operands[1] = GEN_INT (dst_offset);
269536ac495dSmrg my_operands[2] = operands[0];
269636ac495dSmrg output_asm_insn ("sth\t%0, @(%1,%2)", my_operands);
269736ac495dSmrg
269836ac495dSmrg /* If there is a byte left to store then increment the
269936ac495dSmrg destination address and shift the contents of the source
270036ac495dSmrg register down by 8 bits. We could not do the address
270136ac495dSmrg increment in the store half word instruction, because it does
270236ac495dSmrg not have an auto increment mode. */
270336ac495dSmrg if (bytes > 0) /* assert (bytes == 1) */
270436ac495dSmrg {
270536ac495dSmrg dst_offset += 2;
270636ac495dSmrg last_shift = 8;
270736ac495dSmrg }
270836ac495dSmrg }
270936ac495dSmrg else
271036ac495dSmrg last_shift = 24;
271136ac495dSmrg
271236ac495dSmrg if (bytes > 0)
271336ac495dSmrg {
271436ac495dSmrg my_operands[0] = operands[6];
271536ac495dSmrg my_operands[1] = GEN_INT (last_shift);
271636ac495dSmrg output_asm_insn ("srai\t%0, #%1", my_operands);
271736ac495dSmrg my_operands[0] = operands[6];
271836ac495dSmrg my_operands[1] = GEN_INT (dst_offset);
271936ac495dSmrg my_operands[2] = operands[0];
272036ac495dSmrg output_asm_insn ("stb\t%0, @(%1,%2)", my_operands);
272136ac495dSmrg }
272236ac495dSmrg
272336ac495dSmrg /* Update the destination pointer if needed. We have to do
272436ac495dSmrg this so that the patterns matches what we output in this
272536ac495dSmrg function. */
272636ac495dSmrg if (dst_inc_amount
272736ac495dSmrg && !find_reg_note (insn, REG_UNUSED, operands[0]))
272836ac495dSmrg {
272936ac495dSmrg my_operands[0] = operands[0];
273036ac495dSmrg my_operands[1] = GEN_INT (dst_inc_amount);
273136ac495dSmrg output_asm_insn ("addi\t%0, #%1", my_operands);
273236ac495dSmrg }
273336ac495dSmrg
273436ac495dSmrg /* Update the source pointer if needed. We have to do this
273536ac495dSmrg so that the patterns matches what we output in this
273636ac495dSmrg function. */
273736ac495dSmrg if (src_inc_amount
273836ac495dSmrg && !find_reg_note (insn, REG_UNUSED, operands[1]))
273936ac495dSmrg {
274036ac495dSmrg my_operands[0] = operands[1];
274136ac495dSmrg my_operands[1] = GEN_INT (src_inc_amount);
274236ac495dSmrg output_asm_insn ("addi\t%0, #%1", my_operands);
274336ac495dSmrg }
274436ac495dSmrg
274536ac495dSmrg bytes = 0;
274636ac495dSmrg }
274736ac495dSmrg
274836ac495dSmrg first_time = 0;
274936ac495dSmrg }
275036ac495dSmrg }
275136ac495dSmrg
2752a2dc1f3fSmrg /* Implement TARGET_HARD_REGNO_MODE_OK. */
2753a2dc1f3fSmrg
2754a2dc1f3fSmrg static bool
m32r_hard_regno_mode_ok(unsigned int regno,machine_mode mode)2755a2dc1f3fSmrg m32r_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
2756a2dc1f3fSmrg {
2757a2dc1f3fSmrg return (m32r_hard_regno_modes[regno] & m32r_mode_class[mode]) != 0;
2758a2dc1f3fSmrg }
2759a2dc1f3fSmrg
2760a2dc1f3fSmrg /* Implement TARGET_MODES_TIEABLE_P. Tie QI/HI/SI modes together. */
2761a2dc1f3fSmrg
2762a2dc1f3fSmrg static bool
m32r_modes_tieable_p(machine_mode mode1,machine_mode mode2)2763a2dc1f3fSmrg m32r_modes_tieable_p (machine_mode mode1, machine_mode mode2)
2764a2dc1f3fSmrg {
2765a2dc1f3fSmrg return (GET_MODE_CLASS (mode1) == MODE_INT
2766a2dc1f3fSmrg && GET_MODE_CLASS (mode2) == MODE_INT
2767a2dc1f3fSmrg && GET_MODE_SIZE (mode1) <= UNITS_PER_WORD
2768a2dc1f3fSmrg && GET_MODE_SIZE (mode2) <= UNITS_PER_WORD);
2769a2dc1f3fSmrg }
2770a2dc1f3fSmrg
277136ac495dSmrg /* Return true if using NEW_REG in place of OLD_REG is ok. */
277236ac495dSmrg
277336ac495dSmrg int
m32r_hard_regno_rename_ok(unsigned int old_reg ATTRIBUTE_UNUSED,unsigned int new_reg)277436ac495dSmrg m32r_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED,
277536ac495dSmrg unsigned int new_reg)
277636ac495dSmrg {
277736ac495dSmrg /* Interrupt routines can't clobber any register that isn't already used. */
277836ac495dSmrg if (lookup_attribute ("interrupt", DECL_ATTRIBUTES (current_function_decl))
277936ac495dSmrg && !df_regs_ever_live_p (new_reg))
278036ac495dSmrg return 0;
278136ac495dSmrg
278236ac495dSmrg return 1;
278336ac495dSmrg }
278436ac495dSmrg
278536ac495dSmrg rtx
m32r_return_addr(int count)278636ac495dSmrg m32r_return_addr (int count)
278736ac495dSmrg {
278836ac495dSmrg if (count != 0)
278936ac495dSmrg return const0_rtx;
279036ac495dSmrg
279136ac495dSmrg return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNUM);
279236ac495dSmrg }
279336ac495dSmrg
279436ac495dSmrg static void
m32r_trampoline_init(rtx m_tramp,tree fndecl,rtx chain_value)279536ac495dSmrg m32r_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
279636ac495dSmrg {
279736ac495dSmrg emit_move_insn (adjust_address (m_tramp, SImode, 0),
279836ac495dSmrg gen_int_mode (TARGET_LITTLE_ENDIAN ?
279936ac495dSmrg 0x017e8e17 : 0x178e7e01, SImode));
280036ac495dSmrg emit_move_insn (adjust_address (m_tramp, SImode, 4),
280136ac495dSmrg gen_int_mode (TARGET_LITTLE_ENDIAN ?
280236ac495dSmrg 0x0c00ae86 : 0x86ae000c, SImode));
280336ac495dSmrg emit_move_insn (adjust_address (m_tramp, SImode, 8),
280436ac495dSmrg gen_int_mode (TARGET_LITTLE_ENDIAN ?
280536ac495dSmrg 0xe627871e : 0x1e8727e6, SImode));
280636ac495dSmrg emit_move_insn (adjust_address (m_tramp, SImode, 12),
280736ac495dSmrg gen_int_mode (TARGET_LITTLE_ENDIAN ?
280836ac495dSmrg 0xc616c626 : 0x26c61fc6, SImode));
280936ac495dSmrg emit_move_insn (adjust_address (m_tramp, SImode, 16),
281036ac495dSmrg chain_value);
281136ac495dSmrg emit_move_insn (adjust_address (m_tramp, SImode, 20),
281236ac495dSmrg XEXP (DECL_RTL (fndecl), 0));
281336ac495dSmrg
281436ac495dSmrg if (m32r_cache_flush_trap >= 0)
281536ac495dSmrg emit_insn (gen_flush_icache
281636ac495dSmrg (validize_mem (adjust_address (m_tramp, SImode, 0)),
281736ac495dSmrg gen_int_mode (m32r_cache_flush_trap, SImode)));
281836ac495dSmrg else if (m32r_cache_flush_func && m32r_cache_flush_func[0])
281936ac495dSmrg emit_library_call (m32r_function_symbol (m32r_cache_flush_func),
2820a2dc1f3fSmrg LCT_NORMAL, VOIDmode, XEXP (m_tramp, 0), Pmode,
282136ac495dSmrg gen_int_mode (TRAMPOLINE_SIZE, SImode), SImode,
282236ac495dSmrg GEN_INT (3), SImode);
282336ac495dSmrg }
282436ac495dSmrg
282536ac495dSmrg /* True if X is a reg that can be used as a base reg. */
282636ac495dSmrg
282736ac495dSmrg static bool
m32r_rtx_ok_for_base_p(const_rtx x,bool strict)282836ac495dSmrg m32r_rtx_ok_for_base_p (const_rtx x, bool strict)
282936ac495dSmrg {
283036ac495dSmrg if (! REG_P (x))
283136ac495dSmrg return false;
283236ac495dSmrg
283336ac495dSmrg if (strict)
283436ac495dSmrg {
283536ac495dSmrg if (GPR_P (REGNO (x)))
283636ac495dSmrg return true;
283736ac495dSmrg }
283836ac495dSmrg else
283936ac495dSmrg {
284036ac495dSmrg if (GPR_P (REGNO (x))
284136ac495dSmrg || REGNO (x) == ARG_POINTER_REGNUM
284236ac495dSmrg || ! HARD_REGISTER_P (x))
284336ac495dSmrg return true;
284436ac495dSmrg }
284536ac495dSmrg
284636ac495dSmrg return false;
284736ac495dSmrg }
284836ac495dSmrg
284936ac495dSmrg static inline bool
m32r_rtx_ok_for_offset_p(const_rtx x)285036ac495dSmrg m32r_rtx_ok_for_offset_p (const_rtx x)
285136ac495dSmrg {
285236ac495dSmrg return (CONST_INT_P (x) && INT16_P (INTVAL (x)));
285336ac495dSmrg }
285436ac495dSmrg
285536ac495dSmrg static inline bool
m32r_legitimate_offset_addres_p(machine_mode mode ATTRIBUTE_UNUSED,const_rtx x,bool strict)285636ac495dSmrg m32r_legitimate_offset_addres_p (machine_mode mode ATTRIBUTE_UNUSED,
285736ac495dSmrg const_rtx x, bool strict)
285836ac495dSmrg {
285936ac495dSmrg if (GET_CODE (x) == PLUS
286036ac495dSmrg && m32r_rtx_ok_for_base_p (XEXP (x, 0), strict)
286136ac495dSmrg && m32r_rtx_ok_for_offset_p (XEXP (x, 1)))
286236ac495dSmrg return true;
286336ac495dSmrg
286436ac495dSmrg return false;
286536ac495dSmrg }
286636ac495dSmrg
286736ac495dSmrg /* For LO_SUM addresses, do not allow them if the MODE is > 1 word,
286836ac495dSmrg since more than one instruction will be required. */
286936ac495dSmrg
287036ac495dSmrg static inline bool
m32r_legitimate_lo_sum_addres_p(machine_mode mode,const_rtx x,bool strict)287136ac495dSmrg m32r_legitimate_lo_sum_addres_p (machine_mode mode, const_rtx x,
287236ac495dSmrg bool strict)
287336ac495dSmrg {
287436ac495dSmrg if (GET_CODE (x) == LO_SUM
287536ac495dSmrg && (mode != BLKmode && GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
287636ac495dSmrg && m32r_rtx_ok_for_base_p (XEXP (x, 0), strict)
287736ac495dSmrg && CONSTANT_P (XEXP (x, 1)))
287836ac495dSmrg return true;
287936ac495dSmrg
288036ac495dSmrg return false;
288136ac495dSmrg }
288236ac495dSmrg
288336ac495dSmrg /* Is this a load and increment operation. */
288436ac495dSmrg
288536ac495dSmrg static inline bool
m32r_load_postinc_p(machine_mode mode,const_rtx x,bool strict)288636ac495dSmrg m32r_load_postinc_p (machine_mode mode, const_rtx x, bool strict)
288736ac495dSmrg {
288836ac495dSmrg if ((mode == SImode || mode == SFmode)
288936ac495dSmrg && GET_CODE (x) == POST_INC
289036ac495dSmrg && REG_P (XEXP (x, 0))
289136ac495dSmrg && m32r_rtx_ok_for_base_p (XEXP (x, 0), strict))
289236ac495dSmrg return true;
289336ac495dSmrg
289436ac495dSmrg return false;
289536ac495dSmrg }
289636ac495dSmrg
289736ac495dSmrg /* Is this an increment/decrement and store operation. */
289836ac495dSmrg
289936ac495dSmrg static inline bool
m32r_store_preinc_predec_p(machine_mode mode,const_rtx x,bool strict)290036ac495dSmrg m32r_store_preinc_predec_p (machine_mode mode, const_rtx x, bool strict)
290136ac495dSmrg {
290236ac495dSmrg if ((mode == SImode || mode == SFmode)
290336ac495dSmrg && (GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
290436ac495dSmrg && REG_P (XEXP (x, 0)) \
290536ac495dSmrg && m32r_rtx_ok_for_base_p (XEXP (x, 0), strict))
290636ac495dSmrg return true;
290736ac495dSmrg
290836ac495dSmrg return false;
290936ac495dSmrg }
291036ac495dSmrg
291136ac495dSmrg /* Implement TARGET_LEGITIMATE_ADDRESS_P. */
291236ac495dSmrg
291336ac495dSmrg static bool
m32r_legitimate_address_p(machine_mode mode,rtx x,bool strict)291436ac495dSmrg m32r_legitimate_address_p (machine_mode mode, rtx x, bool strict)
291536ac495dSmrg {
291636ac495dSmrg if (m32r_rtx_ok_for_base_p (x, strict)
291736ac495dSmrg || m32r_legitimate_offset_addres_p (mode, x, strict)
291836ac495dSmrg || m32r_legitimate_lo_sum_addres_p (mode, x, strict)
291936ac495dSmrg || m32r_load_postinc_p (mode, x, strict)
292036ac495dSmrg || m32r_store_preinc_predec_p (mode, x, strict))
292136ac495dSmrg return true;
292236ac495dSmrg
292336ac495dSmrg return false;
292436ac495dSmrg }
292536ac495dSmrg
292636ac495dSmrg static void
m32r_conditional_register_usage(void)292736ac495dSmrg m32r_conditional_register_usage (void)
292836ac495dSmrg {
292936ac495dSmrg if (flag_pic)
293036ac495dSmrg fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
293136ac495dSmrg }
293236ac495dSmrg
293336ac495dSmrg /* Implement TARGET_LEGITIMATE_CONSTANT_P
293436ac495dSmrg
293536ac495dSmrg We don't allow (plus symbol large-constant) as the relocations can't
293636ac495dSmrg describe it. INTVAL > 32767 handles both 16-bit and 24-bit relocations.
293736ac495dSmrg We allow all CONST_DOUBLE's as the md file patterns will force the
293836ac495dSmrg constant to memory if they can't handle them. */
293936ac495dSmrg
294036ac495dSmrg static bool
m32r_legitimate_constant_p(machine_mode mode ATTRIBUTE_UNUSED,rtx x)294136ac495dSmrg m32r_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
294236ac495dSmrg {
294336ac495dSmrg return !(GET_CODE (x) == CONST
294436ac495dSmrg && GET_CODE (XEXP (x, 0)) == PLUS
294536ac495dSmrg && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
294636ac495dSmrg || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
294736ac495dSmrg && CONST_INT_P (XEXP (XEXP (x, 0), 1))
294836ac495dSmrg && UINTVAL (XEXP (XEXP (x, 0), 1)) > 32767);
294936ac495dSmrg }
2950a2dc1f3fSmrg
2951a2dc1f3fSmrg /* Implement TARGET_STARTING_FRAME_OFFSET. The frame pointer points at
2952a2dc1f3fSmrg the same place as the stack pointer, except if alloca has been called. */
2953a2dc1f3fSmrg
2954a2dc1f3fSmrg static HOST_WIDE_INT
m32r_starting_frame_offset(void)2955a2dc1f3fSmrg m32r_starting_frame_offset (void)
2956a2dc1f3fSmrg {
2957a2dc1f3fSmrg return M32R_STACK_ALIGN (crtl->outgoing_args_size);
2958a2dc1f3fSmrg }
2959