]>
Commit | Line | Data |
---|---|---|
7b23765d | 1 | /* Output routines for GCC for Renesas / SuperH SH. |
3aea1f79 | 2 | Copyright (C) 1993-2014 Free Software Foundation, Inc. |
7014838c | 3 | Contributed by Steve Chamberlain (sac@cygnus.com). |
9e7454d0 | 4 | Improved by Jim Wilson (wilson@cygnus.com). |
7208c779 | 5 | |
187b36cf | 6 | This file is part of GCC. |
9b754436 | 7 | |
187b36cf | 8 | GCC is free software; you can redistribute it and/or modify |
9b754436 | 9 | it under the terms of the GNU General Public License as published by |
038d1e19 | 10 | the Free Software Foundation; either version 3, or (at your option) |
9b754436 | 11 | any later version. |
12 | ||
187b36cf | 13 | GCC is distributed in the hope that it will be useful, |
9b754436 | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
038d1e19 | 19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
7208c779 | 21 | |
c8a347fc | 22 | #include <sstream> |
23 | #include <vector> | |
24 | #include <algorithm> | |
25 | ||
7208c779 | 26 | #include "config.h" |
7014838c | 27 | #include "system.h" |
805e22b2 | 28 | #include "coretypes.h" |
29 | #include "tm.h" | |
b7dbbdb2 | 30 | #include "insn-config.h" |
7208c779 | 31 | #include "rtl.h" |
7208c779 | 32 | #include "tree.h" |
9ed99284 | 33 | #include "stringpool.h" |
34 | #include "stor-layout.h" | |
35 | #include "calls.h" | |
36 | #include "varasm.h" | |
7208c779 | 37 | #include "flags.h" |
7208c779 | 38 | #include "expr.h" |
d8fc4d0b | 39 | #include "optabs.h" |
299fa1f5 | 40 | #include "reload.h" |
a3020f2f | 41 | #include "hashtab.h" |
42 | #include "hash-set.h" | |
43 | #include "vec.h" | |
44 | #include "machmode.h" | |
45 | #include "hard-reg-set.h" | |
46 | #include "input.h" | |
0a893c29 | 47 | #include "function.h" |
73401833 | 48 | #include "regs.h" |
73401833 | 49 | #include "output.h" |
891b35f2 | 50 | #include "insn-attr.h" |
0b205f4c | 51 | #include "diagnostic-core.h" |
b7dbbdb2 | 52 | #include "recog.h" |
bde36f4a | 53 | #include "dwarf2.h" |
b7dbbdb2 | 54 | #include "tm_p.h" |
a767736d | 55 | #include "target.h" |
56 | #include "target-def.h" | |
e3fac27d | 57 | #include "langhooks.h" |
94ea8568 | 58 | #include "predict.h" |
59 | #include "dominance.h" | |
60 | #include "cfg.h" | |
61 | #include "cfgrtl.h" | |
62 | #include "cfganal.h" | |
63 | #include "lcm.h" | |
64 | #include "cfgbuild.h" | |
65 | #include "cfgcleanup.h" | |
c83ee613 | 66 | #include "basic-block.h" |
3072d30e | 67 | #include "df.h" |
133479bd | 68 | #include "intl.h" |
f77a5bb0 | 69 | #include "sched-int.h" |
9b8dc018 | 70 | #include "params.h" |
5bf8e2fe | 71 | #include "ggc.h" |
bc61cadb | 72 | #include "hash-table.h" |
73 | #include "tree-ssa-alias.h" | |
74 | #include "internal-fn.h" | |
75 | #include "gimple-fold.h" | |
76 | #include "tree-eh.h" | |
77 | #include "gimple-expr.h" | |
78 | #include "is-a.h" | |
e795d6e1 | 79 | #include "gimple.h" |
a8783bee | 80 | #include "gimplify.h" |
59312820 | 81 | #include "cfgloop.h" |
49166fc3 | 82 | #include "alloc-pool.h" |
abff7a2e | 83 | #include "tm-constrs.h" |
fba5dd52 | 84 | #include "opts.h" |
32f5fb24 | 85 | #include "tree-pass.h" |
86 | #include "pass_manager.h" | |
87 | #include "context.h" | |
f7715905 | 88 | #include "builtins.h" |
727d658b | 89 | #include "rtl-iter.h" |
20cdebf8 | 90 | |
8ded0752 | 91 | int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch; |
92 | ||
87e19636 | 93 | /* These are some macros to abstract register modes. */ |
05aca90b | 94 | #define CONST_OK_FOR_I10(VALUE) (((HOST_WIDE_INT)(VALUE)) >= -512 \ |
95 | && ((HOST_WIDE_INT)(VALUE)) <= 511) | |
96 | ||
87e19636 | 97 | #define CONST_OK_FOR_ADD(size) \ |
af2c1324 | 98 | (TARGET_SHMEDIA ? CONST_OK_FOR_I10 (size) : CONST_OK_FOR_I08 (size)) |
87e19636 | 99 | #define GEN_MOV (*(TARGET_SHMEDIA64 ? gen_movdi : gen_movsi)) |
100 | #define GEN_ADD3 (*(TARGET_SHMEDIA64 ? gen_adddi3 : gen_addsi3)) | |
101 | #define GEN_SUB3 (*(TARGET_SHMEDIA64 ? gen_subdi3 : gen_subsi3)) | |
102 | ||
5241f4ad | 103 | /* Used to simplify the logic below. Find the attributes wherever |
104 | they may be. */ | |
105 | #define SH_ATTRIBUTES(decl) \ | |
106 | (TYPE_P (decl)) ? TYPE_ATTRIBUTES (decl) \ | |
107 | : DECL_ATTRIBUTES (decl) \ | |
108 | ? (DECL_ATTRIBUTES (decl)) \ | |
109 | : TYPE_ATTRIBUTES (TREE_TYPE (decl)) | |
110 | ||
0d687b6d | 111 | /* Set to 1 by expand_prologue() when the function is an interrupt handler. */ |
112 | int current_function_interrupt; | |
113 | ||
57d5535b | 114 | tree sh_deferred_function_attributes; |
115 | tree *sh_deferred_function_attributes_tail = &sh_deferred_function_attributes; | |
1504eb7e | 116 | |
9df03d69 | 117 | /* Global variables for machine-dependent things. */ |
7208c779 | 118 | |
1504eb7e | 119 | /* Which cpu are we scheduling for. */ |
120 | enum processor_type sh_cpu; | |
121 | ||
f77a5bb0 | 122 | /* Definitions used in ready queue reordering for first scheduling pass. */ |
123 | ||
124 | /* Reg weights arrays for modes SFmode and SImode, indexed by insn LUID. */ | |
125 | static short *regmode_weight[2]; | |
126 | ||
127 | /* Total SFmode and SImode weights of scheduled insns. */ | |
128 | static int curr_regmode_pressure[2]; | |
129 | ||
3072d30e | 130 | /* Number of r0 life regions. */ |
131 | static int r0_life_regions; | |
132 | ||
f77a5bb0 | 133 | /* If true, skip cycles for Q -> R movement. */ |
134 | static int skip_cycles = 0; | |
135 | ||
6c049e03 | 136 | /* Cached value of can_issue_more. This is cached in sh_variable_issue hook |
f77a5bb0 | 137 | and returned from sh_reorder2. */ |
138 | static short cached_can_issue_more; | |
139 | ||
4c4854c8 | 140 | /* Unique number for UNSPEC_BBR pattern. */ |
141 | static unsigned int unspec_bbr_uid = 1; | |
142 | ||
7208c779 | 143 | /* Provides the class number of the smallest class containing |
1504eb7e | 144 | reg number. */ |
41fafa66 | 145 | enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] = |
7208c779 | 146 | { |
2e3d4844 | 147 | R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, |
7208c779 | 148 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, |
149 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
150 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
87e19636 | 151 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, |
152 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
153 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
154 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
155 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
156 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
157 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
158 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
159 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
160 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
161 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
162 | GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, | |
b00564da | 163 | FP0_REGS,FP_REGS, FP_REGS, FP_REGS, |
164 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
165 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
166 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
87e19636 | 167 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, |
168 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
169 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
170 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
171 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
172 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
173 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
174 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
175 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
176 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
177 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
178 | FP_REGS, FP_REGS, FP_REGS, FP_REGS, | |
179 | TARGET_REGS, TARGET_REGS, TARGET_REGS, TARGET_REGS, | |
180 | TARGET_REGS, TARGET_REGS, TARGET_REGS, TARGET_REGS, | |
1b61190c | 181 | DF_REGS, DF_REGS, DF_REGS, DF_REGS, |
182 | DF_REGS, DF_REGS, DF_REGS, DF_REGS, | |
87e19636 | 183 | NO_REGS, GENERAL_REGS, PR_REGS, T_REGS, |
184 | MAC_REGS, MAC_REGS, FPUL_REGS, FPSCR_REGS, | |
b9a602c6 | 185 | GENERAL_REGS, GENERAL_REGS, |
1b61190c | 186 | }; |
187 | ||
87e19636 | 188 | char sh_register_names[FIRST_PSEUDO_REGISTER] \ |
189 | [MAX_REGISTER_NAME_LENGTH + 1] = SH_REGISTER_NAMES_INITIALIZER; | |
190 | ||
191 | char sh_additional_register_names[ADDREGNAMES_SIZE] \ | |
192 | [MAX_ADDITIONAL_REGISTER_NAME_LENGTH + 1] | |
193 | = SH_ADDITIONAL_REGISTER_NAMES_INITIALIZER; | |
7208c779 | 194 | |
1b61190c | 195 | int assembler_dialect; |
196 | ||
8af3db02 | 197 | static bool shmedia_space_reserved_for_target_registers; |
198 | ||
b82334f7 | 199 | static void split_branches (rtx_insn *); |
04f04b72 | 200 | static int branch_dest (rtx); |
cdf962b7 | 201 | static void print_slot (rtx_sequence *); |
3754d046 | 202 | static rtx_code_label *add_constant (rtx, machine_mode, rtx); |
b82334f7 | 203 | static void dump_table (rtx_insn *, rtx_insn *); |
204 | static bool broken_move (rtx_insn *); | |
205 | static bool mova_p (rtx_insn *); | |
206 | static rtx_insn *find_barrier (int, rtx_insn *, rtx_insn *); | |
50fc2d35 | 207 | static bool noncall_uses_reg (rtx, rtx_insn *, rtx *); |
91a55c11 | 208 | static rtx_insn *gen_block_redirect (rtx_insn *, int, int); |
04f04b72 | 209 | static void sh_reorg (void); |
eb9063bf | 210 | static void sh_option_override (void); |
b324d3bd | 211 | static void output_stack_adjust (int, rtx, int, HARD_REG_SET *, bool); |
722334ea | 212 | static rtx_insn *frame_insn (rtx); |
04f04b72 | 213 | static rtx push (int); |
214 | static void pop (int); | |
215 | static void push_regs (HARD_REG_SET *, int); | |
216 | static int calc_live_regs (HARD_REG_SET *); | |
04f04b72 | 217 | static HOST_WIDE_INT rounded_frame_size (int); |
992d172c | 218 | static bool sh_frame_pointer_required (void); |
7fc0df2f | 219 | static void sh_emit_mode_set (int, int, int, HARD_REG_SET); |
18282db0 | 220 | static int sh_mode_needed (int, rtx_insn *); |
221 | static int sh_mode_after (int, int, rtx_insn *); | |
cea19dab | 222 | static int sh_mode_entry (int); |
223 | static int sh_mode_exit (int); | |
224 | static int sh_mode_priority (int entity, int n); | |
225 | ||
04f04b72 | 226 | static rtx mark_constant_pool_use (rtx); |
6c049e03 | 227 | static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, |
228 | int, bool *); | |
5241f4ad | 229 | static tree sh_handle_resbank_handler_attribute (tree *, tree, |
230 | tree, int, bool *); | |
231 | static tree sh2a_handle_function_vector_handler_attribute (tree *, tree, | |
232 | tree, int, bool *); | |
04f04b72 | 233 | static tree sh_handle_sp_switch_attribute (tree *, tree, tree, int, bool *); |
234 | static tree sh_handle_trap_exit_attribute (tree *, tree, tree, int, bool *); | |
235 | static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *); | |
e8c57574 | 236 | static void sh_print_operand (FILE *, rtx, int); |
237 | static void sh_print_operand_address (FILE *, rtx); | |
238 | static bool sh_print_operand_punct_valid_p (unsigned char code); | |
a24f0184 | 239 | static bool sh_asm_output_addr_const_extra (FILE *file, rtx x); |
04f04b72 | 240 | static void sh_output_function_epilogue (FILE *, HOST_WIDE_INT); |
241 | static void sh_insert_attributes (tree, tree *); | |
761d9126 | 242 | static const char *sh_check_pch_target_flags (int); |
3754d046 | 243 | static int sh_register_move_cost (machine_mode, reg_class_t, reg_class_t); |
18282db0 | 244 | static int sh_adjust_cost (rtx_insn *, rtx, rtx_insn *, int); |
04f04b72 | 245 | static int sh_issue_rate (void); |
18282db0 | 246 | static int sh_dfa_new_cycle (FILE *, int, rtx_insn *, int, int, int *sort_p); |
3754d046 | 247 | static short find_set_regmode_weight (rtx, machine_mode); |
248 | static short find_insn_regmode_weight (rtx, machine_mode); | |
249 | static void find_regmode_weight (basic_block, machine_mode); | |
3072d30e | 250 | static int find_r0_life_regions (basic_block); |
f77a5bb0 | 251 | static void sh_md_init_global (FILE *, int, int); |
252 | static void sh_md_finish_global (FILE *, int); | |
253 | static int rank_for_reorder (const void *, const void *); | |
b24ef467 | 254 | static void swap_reorder (rtx_insn **, int); |
255 | static void ready_reorder (rtx_insn **, int); | |
3754d046 | 256 | static bool high_pressure (machine_mode); |
b24ef467 | 257 | static int sh_reorder (FILE *, int, rtx_insn **, int *, int); |
258 | static int sh_reorder2 (FILE *, int, rtx_insn **, int *, int); | |
f77a5bb0 | 259 | static void sh_md_init (FILE *, int, int); |
18282db0 | 260 | static int sh_variable_issue (FILE *, int, rtx_insn *, int); |
9e7454d0 | 261 | |
04f04b72 | 262 | static bool sh_function_ok_for_sibcall (tree, tree); |
263 | ||
264 | static bool sh_cannot_modify_jumps_p (void); | |
964229b7 | 265 | static reg_class_t sh_target_reg_class (void); |
8af3db02 | 266 | static bool sh_optimize_target_register_callee_saved (bool); |
a9f1838b | 267 | static bool sh_ms_bitfield_layout_p (const_tree); |
04f04b72 | 268 | |
269 | static void sh_init_builtins (void); | |
3213bdbf | 270 | static tree sh_builtin_decl (unsigned, bool); |
3754d046 | 271 | static rtx sh_expand_builtin (tree, rtx, rtx, machine_mode, int); |
6c049e03 | 272 | static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, |
273 | HOST_WIDE_INT, tree); | |
04f04b72 | 274 | static void sh_file_start (void); |
a3b1178e | 275 | static bool flow_dependent_p (rtx, rtx); |
81a410b1 | 276 | static void flow_dependent_p_1 (rtx, const_rtx, void *); |
04f04b72 | 277 | static int shiftcosts (rtx); |
74cf552d | 278 | static int and_xor_ior_costs (rtx, int); |
04f04b72 | 279 | static int addsubcosts (rtx); |
280 | static int multcosts (rtx); | |
281 | static bool unspec_caller_rtx_p (rtx); | |
18282db0 | 282 | static bool sh_cannot_copy_insn_p (rtx_insn *); |
20d892d1 | 283 | static bool sh_rtx_costs (rtx, int, int, int, int *, bool); |
3754d046 | 284 | static int sh_address_cost (rtx, machine_mode, addr_space_t, bool); |
edf54f2a | 285 | static int sh_pr_n_sets (void); |
286 | static rtx sh_allocate_initial_value (rtx); | |
167f2e19 | 287 | static reg_class_t sh_preferred_reload_class (rtx, reg_class_t); |
288 | static reg_class_t sh_secondary_reload (bool, rtx, reg_class_t, | |
3754d046 | 289 | machine_mode, |
167f2e19 | 290 | struct secondary_reload_info *); |
3754d046 | 291 | static bool sh_legitimate_address_p (machine_mode, rtx, bool); |
292 | static rtx sh_legitimize_address (rtx, rtx, machine_mode); | |
ac562325 | 293 | static rtx sh_delegitimize_address (rtx); |
8af3db02 | 294 | static int shmedia_target_regs_stack_space (HARD_REG_SET *); |
295 | static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *); | |
296 | static int shmedia_target_regs_stack_adjust (HARD_REG_SET *); | |
41fafa66 | 297 | static int scavenge_reg (HARD_REG_SET *s); |
298 | struct save_schedule_s; | |
299 | static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *, | |
300 | struct save_schedule_s *, int); | |
45550790 | 301 | |
04f04b72 | 302 | static rtx sh_struct_value_rtx (tree, int); |
5cb06fbb | 303 | static rtx sh_function_value (const_tree, const_tree, bool); |
eb9063bf | 304 | static bool sh_function_value_regno_p (const unsigned int); |
3754d046 | 305 | static rtx sh_libcall_value (machine_mode, const_rtx); |
fb80456a | 306 | static bool sh_return_in_memory (const_tree, const_tree); |
04f04b72 | 307 | static rtx sh_builtin_saveregs (void); |
3754d046 | 308 | static void sh_setup_incoming_varargs (cumulative_args_t, machine_mode, |
6c049e03 | 309 | tree, int *, int); |
39cba157 | 310 | static bool sh_strict_argument_naming (cumulative_args_t); |
311 | static bool sh_pretend_outgoing_varargs_named (cumulative_args_t); | |
2e15d750 | 312 | static tree sh_build_builtin_va_list (void); |
8a58ed0a | 313 | static void sh_va_start (tree, rtx); |
75a70cf9 | 314 | static tree sh_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); |
5cb06fbb | 315 | static bool sh_promote_prototypes (const_tree); |
3754d046 | 316 | static machine_mode sh_promote_function_mode (const_tree type, |
317 | machine_mode, | |
978fcce1 | 318 | int *punsignedp, |
319 | const_tree funtype, | |
905ad4b8 | 320 | int for_return); |
3754d046 | 321 | static bool sh_pass_by_reference (cumulative_args_t, machine_mode, |
fb80456a | 322 | const_tree, bool); |
3754d046 | 323 | static bool sh_callee_copies (cumulative_args_t, machine_mode, |
fb80456a | 324 | const_tree, bool); |
3754d046 | 325 | static int sh_arg_partial_bytes (cumulative_args_t, machine_mode, |
f054eb3c | 326 | tree, bool); |
3754d046 | 327 | static void sh_function_arg_advance (cumulative_args_t, machine_mode, |
a0aaaf80 | 328 | const_tree, bool); |
3754d046 | 329 | static rtx sh_function_arg (cumulative_args_t, machine_mode, |
a0aaaf80 | 330 | const_tree, bool); |
3754d046 | 331 | static bool sh_scalar_mode_supported_p (machine_mode); |
a9f1838b | 332 | static int sh_dwarf_calling_convention (const_tree); |
5241f4ad | 333 | static void sh_encode_section_info (tree, rtx, int); |
a3b1178e | 334 | static bool sh2a_function_vector_p (tree); |
3daf7435 | 335 | static void sh_trampoline_init (rtx, tree, rtx); |
336 | static rtx sh_trampoline_adjust_address (rtx); | |
b2d7ede1 | 337 | static void sh_conditional_register_usage (void); |
3754d046 | 338 | static bool sh_legitimate_constant_p (machine_mode, rtx); |
339 | static int mov_insn_size (machine_mode, bool); | |
340 | static int mov_insn_alignment_mask (machine_mode, bool); | |
91a55c11 | 341 | static bool sequence_insn_p (rtx_insn *); |
d5065e6e | 342 | static void sh_canonicalize_comparison (int *, rtx *, rtx *, bool); |
343 | static void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&, | |
3754d046 | 344 | machine_mode, bool); |
32f5fb24 | 345 | static bool sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2); |
a3df8952 | 346 | |
347 | static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED; | |
ef51d1e3 | 348 | \f |
349 | static const struct attribute_spec sh_attribute_table[] = | |
350 | { | |
ac86af5d | 351 | /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, |
352 | affects_type_identity } */ | |
353 | { "interrupt_handler", 0, 0, true, false, false, | |
354 | sh_handle_interrupt_handler_attribute, false }, | |
355 | { "sp_switch", 1, 1, true, false, false, | |
356 | sh_handle_sp_switch_attribute, false }, | |
357 | { "trap_exit", 1, 1, true, false, false, | |
358 | sh_handle_trap_exit_attribute, false }, | |
359 | { "renesas", 0, 0, false, true, false, | |
360 | sh_handle_renesas_attribute, false }, | |
361 | { "trapa_handler", 0, 0, true, false, false, | |
362 | sh_handle_interrupt_handler_attribute, false }, | |
363 | { "nosave_low_regs", 0, 0, true, false, false, | |
364 | sh_handle_interrupt_handler_attribute, false }, | |
365 | { "resbank", 0, 0, true, false, false, | |
366 | sh_handle_resbank_handler_attribute, false }, | |
367 | { "function_vector", 1, 1, true, false, false, | |
368 | sh2a_handle_function_vector_handler_attribute, false }, | |
ac86af5d | 369 | { NULL, 0, 0, false, false, false, NULL, false } |
ef51d1e3 | 370 | }; |
a767736d | 371 | \f |
372 | /* Initialize the GCC target structure. */ | |
e3c541f0 | 373 | #undef TARGET_ATTRIBUTE_TABLE |
374 | #define TARGET_ATTRIBUTE_TABLE sh_attribute_table | |
a767736d | 375 | |
58356836 | 376 | /* The next two are used for debug info when compiling with -gdwarf. */ |
377 | #undef TARGET_ASM_UNALIGNED_HI_OP | |
378 | #define TARGET_ASM_UNALIGNED_HI_OP "\t.uaword\t" | |
379 | #undef TARGET_ASM_UNALIGNED_SI_OP | |
380 | #define TARGET_ASM_UNALIGNED_SI_OP "\t.ualong\t" | |
381 | ||
4c834714 | 382 | /* These are NULLed out on non-SH5 in TARGET_OPTION_OVERRIDE. */ |
87e19636 | 383 | #undef TARGET_ASM_UNALIGNED_DI_OP |
384 | #define TARGET_ASM_UNALIGNED_DI_OP "\t.uaquad\t" | |
385 | #undef TARGET_ASM_ALIGNED_DI_OP | |
386 | #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" | |
387 | ||
eb9063bf | 388 | #undef TARGET_OPTION_OVERRIDE |
389 | #define TARGET_OPTION_OVERRIDE sh_option_override | |
390 | ||
e8c57574 | 391 | #undef TARGET_PRINT_OPERAND |
392 | #define TARGET_PRINT_OPERAND sh_print_operand | |
393 | #undef TARGET_PRINT_OPERAND_ADDRESS | |
394 | #define TARGET_PRINT_OPERAND_ADDRESS sh_print_operand_address | |
395 | #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P | |
396 | #define TARGET_PRINT_OPERAND_PUNCT_VALID_P sh_print_operand_punct_valid_p | |
a24f0184 | 397 | #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA |
398 | #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA sh_asm_output_addr_const_extra | |
399 | ||
17d9b0c3 | 400 | #undef TARGET_ASM_FUNCTION_EPILOGUE |
401 | #define TARGET_ASM_FUNCTION_EPILOGUE sh_output_function_epilogue | |
402 | ||
c83ee613 | 403 | #undef TARGET_ASM_OUTPUT_MI_THUNK |
404 | #define TARGET_ASM_OUTPUT_MI_THUNK sh_output_mi_thunk | |
405 | ||
406 | #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK | |
6c049e03 | 407 | #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ |
408 | hook_bool_const_tree_hwi_hwi_const_tree_true | |
c83ee613 | 409 | |
92c473b8 | 410 | #undef TARGET_ASM_FILE_START |
411 | #define TARGET_ASM_FILE_START sh_file_start | |
412 | #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE | |
413 | #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true | |
414 | ||
eb9063bf | 415 | #undef TARGET_REGISTER_MOVE_COST |
416 | #define TARGET_REGISTER_MOVE_COST sh_register_move_cost | |
417 | ||
8ee295a7 | 418 | #undef TARGET_INSERT_ATTRIBUTES |
419 | #define TARGET_INSERT_ATTRIBUTES sh_insert_attributes | |
420 | ||
747af5e7 | 421 | #undef TARGET_SCHED_ADJUST_COST |
422 | #define TARGET_SCHED_ADJUST_COST sh_adjust_cost | |
423 | ||
bea4bad2 | 424 | #undef TARGET_SCHED_ISSUE_RATE |
425 | #define TARGET_SCHED_ISSUE_RATE sh_issue_rate | |
426 | ||
f77a5bb0 | 427 | /* The next 5 hooks have been implemented for reenabling sched1. With the |
428 | help of these macros we are limiting the movement of insns in sched1 to | |
9e7454d0 | 429 | reduce the register pressure. The overall idea is to keep count of SImode |
f77a5bb0 | 430 | and SFmode regs required by already scheduled insns. When these counts |
431 | cross some threshold values; give priority to insns that free registers. | |
432 | The insn that frees registers is most likely to be the insn with lowest | |
9e7454d0 | 433 | LUID (original insn order); but such an insn might be there in the stalled |
f77a5bb0 | 434 | queue (Q) instead of the ready queue (R). To solve this, we skip cycles |
9d75589a | 435 | up to a max of 8 cycles so that such insns may move from Q -> R. |
f77a5bb0 | 436 | |
437 | The description of the hooks are as below: | |
438 | ||
439 | TARGET_SCHED_INIT_GLOBAL: Added a new target hook in the generic | |
440 | scheduler; it is called inside the sched_init function just after | |
441 | find_insn_reg_weights function call. It is used to calculate the SImode | |
7bd28bba | 442 | and SFmode weights of insns of basic blocks; much similar to what |
9e7454d0 | 443 | find_insn_reg_weights does. |
f77a5bb0 | 444 | TARGET_SCHED_FINISH_GLOBAL: Corresponding cleanup hook. |
445 | ||
446 | TARGET_SCHED_DFA_NEW_CYCLE: Skip cycles if high register pressure is | |
447 | indicated by TARGET_SCHED_REORDER2; doing this may move insns from | |
448 | (Q)->(R). | |
449 | ||
450 | TARGET_SCHED_REORDER: If the register pressure for SImode or SFmode is | |
451 | high; reorder the ready queue so that the insn with lowest LUID will be | |
452 | issued next. | |
453 | ||
454 | TARGET_SCHED_REORDER2: If the register pressure is high, indicate to | |
455 | TARGET_SCHED_DFA_NEW_CYCLE to skip cycles. | |
456 | ||
457 | TARGET_SCHED_VARIABLE_ISSUE: Cache the value of can_issue_more so that it | |
458 | can be returned from TARGET_SCHED_REORDER2. | |
459 | ||
460 | TARGET_SCHED_INIT: Reset the register pressure counting variables. */ | |
461 | ||
462 | #undef TARGET_SCHED_DFA_NEW_CYCLE | |
463 | #define TARGET_SCHED_DFA_NEW_CYCLE sh_dfa_new_cycle | |
464 | ||
465 | #undef TARGET_SCHED_INIT_GLOBAL | |
466 | #define TARGET_SCHED_INIT_GLOBAL sh_md_init_global | |
467 | ||
468 | #undef TARGET_SCHED_FINISH_GLOBAL | |
469 | #define TARGET_SCHED_FINISH_GLOBAL sh_md_finish_global | |
470 | ||
471 | #undef TARGET_SCHED_VARIABLE_ISSUE | |
472 | #define TARGET_SCHED_VARIABLE_ISSUE sh_variable_issue | |
473 | ||
474 | #undef TARGET_SCHED_REORDER | |
475 | #define TARGET_SCHED_REORDER sh_reorder | |
476 | ||
477 | #undef TARGET_SCHED_REORDER2 | |
478 | #define TARGET_SCHED_REORDER2 sh_reorder2 | |
479 | ||
480 | #undef TARGET_SCHED_INIT | |
481 | #define TARGET_SCHED_INIT sh_md_init | |
482 | ||
ac562325 | 483 | #undef TARGET_DELEGITIMIZE_ADDRESS |
484 | #define TARGET_DELEGITIMIZE_ADDRESS sh_delegitimize_address | |
485 | ||
41e3a0c7 | 486 | #undef TARGET_LEGITIMIZE_ADDRESS |
487 | #define TARGET_LEGITIMIZE_ADDRESS sh_legitimize_address | |
488 | ||
87e19636 | 489 | #undef TARGET_CANNOT_MODIFY_JUMPS_P |
490 | #define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p | |
8af3db02 | 491 | #undef TARGET_BRANCH_TARGET_REGISTER_CLASS |
492 | #define TARGET_BRANCH_TARGET_REGISTER_CLASS sh_target_reg_class | |
493 | #undef TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED | |
494 | #define TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED \ | |
6c049e03 | 495 | sh_optimize_target_register_callee_saved |
87e19636 | 496 | |
497 | #undef TARGET_MS_BITFIELD_LAYOUT_P | |
498 | #define TARGET_MS_BITFIELD_LAYOUT_P sh_ms_bitfield_layout_p | |
499 | ||
e3fac27d | 500 | #undef TARGET_INIT_BUILTINS |
501 | #define TARGET_INIT_BUILTINS sh_init_builtins | |
3213bdbf | 502 | #undef TARGET_BUILTIN_DECL |
503 | #define TARGET_BUILTIN_DECL sh_builtin_decl | |
e3fac27d | 504 | #undef TARGET_EXPAND_BUILTIN |
505 | #define TARGET_EXPAND_BUILTIN sh_expand_builtin | |
506 | ||
805e22b2 | 507 | #undef TARGET_FUNCTION_OK_FOR_SIBCALL |
508 | #define TARGET_FUNCTION_OK_FOR_SIBCALL sh_function_ok_for_sibcall | |
509 | ||
02359f85 | 510 | #undef TARGET_CANNOT_COPY_INSN_P |
511 | #define TARGET_CANNOT_COPY_INSN_P sh_cannot_copy_insn_p | |
fab7adbf | 512 | #undef TARGET_RTX_COSTS |
513 | #define TARGET_RTX_COSTS sh_rtx_costs | |
ec0457a8 | 514 | #undef TARGET_ADDRESS_COST |
515 | #define TARGET_ADDRESS_COST sh_address_cost | |
edf54f2a | 516 | #undef TARGET_ALLOCATE_INITIAL_VALUE |
517 | #define TARGET_ALLOCATE_INITIAL_VALUE sh_allocate_initial_value | |
fab7adbf | 518 | |
2efea8c0 | 519 | #undef TARGET_MACHINE_DEPENDENT_REORG |
520 | #define TARGET_MACHINE_DEPENDENT_REORG sh_reorg | |
521 | ||
e1190e3a | 522 | #undef TARGET_DWARF_REGISTER_SPAN |
523 | #define TARGET_DWARF_REGISTER_SPAN sh_dwarf_register_span | |
524 | ||
cec78553 | 525 | #ifdef HAVE_AS_TLS |
526 | #undef TARGET_HAVE_TLS | |
527 | #define TARGET_HAVE_TLS true | |
528 | #endif | |
529 | ||
45550790 | 530 | #undef TARGET_PROMOTE_PROTOTYPES |
531 | #define TARGET_PROMOTE_PROTOTYPES sh_promote_prototypes | |
978fcce1 | 532 | #undef TARGET_PROMOTE_FUNCTION_MODE |
533 | #define TARGET_PROMOTE_FUNCTION_MODE sh_promote_function_mode | |
45550790 | 534 | |
5cb06fbb | 535 | #undef TARGET_FUNCTION_VALUE |
536 | #define TARGET_FUNCTION_VALUE sh_function_value | |
eb9063bf | 537 | #undef TARGET_FUNCTION_VALUE_REGNO_P |
538 | #define TARGET_FUNCTION_VALUE_REGNO_P sh_function_value_regno_p | |
5cb06fbb | 539 | #undef TARGET_LIBCALL_VALUE |
540 | #define TARGET_LIBCALL_VALUE sh_libcall_value | |
45550790 | 541 | #undef TARGET_STRUCT_VALUE_RTX |
542 | #define TARGET_STRUCT_VALUE_RTX sh_struct_value_rtx | |
543 | #undef TARGET_RETURN_IN_MEMORY | |
544 | #define TARGET_RETURN_IN_MEMORY sh_return_in_memory | |
545 | ||
546 | #undef TARGET_EXPAND_BUILTIN_SAVEREGS | |
547 | #define TARGET_EXPAND_BUILTIN_SAVEREGS sh_builtin_saveregs | |
548 | #undef TARGET_SETUP_INCOMING_VARARGS | |
549 | #define TARGET_SETUP_INCOMING_VARARGS sh_setup_incoming_varargs | |
550 | #undef TARGET_STRICT_ARGUMENT_NAMING | |
551 | #define TARGET_STRICT_ARGUMENT_NAMING sh_strict_argument_naming | |
552 | #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED | |
553 | #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED sh_pretend_outgoing_varargs_named | |
0336f0f0 | 554 | #undef TARGET_MUST_PASS_IN_STACK |
555 | #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size | |
b981d932 | 556 | #undef TARGET_PASS_BY_REFERENCE |
557 | #define TARGET_PASS_BY_REFERENCE sh_pass_by_reference | |
13f08ee7 | 558 | #undef TARGET_CALLEE_COPIES |
559 | #define TARGET_CALLEE_COPIES sh_callee_copies | |
f054eb3c | 560 | #undef TARGET_ARG_PARTIAL_BYTES |
561 | #define TARGET_ARG_PARTIAL_BYTES sh_arg_partial_bytes | |
a0aaaf80 | 562 | #undef TARGET_FUNCTION_ARG |
563 | #define TARGET_FUNCTION_ARG sh_function_arg | |
564 | #undef TARGET_FUNCTION_ARG_ADVANCE | |
565 | #define TARGET_FUNCTION_ARG_ADVANCE sh_function_arg_advance | |
45550790 | 566 | |
2e15d750 | 567 | #undef TARGET_BUILD_BUILTIN_VA_LIST |
568 | #define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list | |
8a58ed0a | 569 | #undef TARGET_EXPAND_BUILTIN_VA_START |
570 | #define TARGET_EXPAND_BUILTIN_VA_START sh_va_start | |
20cdebf8 | 571 | #undef TARGET_GIMPLIFY_VA_ARG_EXPR |
572 | #define TARGET_GIMPLIFY_VA_ARG_EXPR sh_gimplify_va_arg_expr | |
2e15d750 | 573 | |
607ac910 | 574 | #undef TARGET_SCALAR_MODE_SUPPORTED_P |
575 | #define TARGET_SCALAR_MODE_SUPPORTED_P sh_scalar_mode_supported_p | |
9e7454d0 | 576 | #undef TARGET_VECTOR_MODE_SUPPORTED_P |
577 | #define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p | |
578 | ||
761d9126 | 579 | #undef TARGET_CHECK_PCH_TARGET_FLAGS |
580 | #define TARGET_CHECK_PCH_TARGET_FLAGS sh_check_pch_target_flags | |
133479bd | 581 | |
8ff30ff6 | 582 | #undef TARGET_DWARF_CALLING_CONVENTION |
583 | #define TARGET_DWARF_CALLING_CONVENTION sh_dwarf_calling_convention | |
584 | ||
992d172c | 585 | #undef TARGET_FRAME_POINTER_REQUIRED |
586 | #define TARGET_FRAME_POINTER_REQUIRED sh_frame_pointer_required | |
587 | ||
cea19dab | 588 | #undef TARGET_MODE_EMIT |
589 | #define TARGET_MODE_EMIT sh_emit_mode_set | |
590 | ||
591 | #undef TARGET_MODE_NEEDED | |
592 | #define TARGET_MODE_NEEDED sh_mode_needed | |
593 | ||
594 | #undef TARGET_MODE_AFTER | |
595 | #define TARGET_MODE_AFTER sh_mode_after | |
596 | ||
597 | #undef TARGET_MODE_ENTRY | |
598 | #define TARGET_MODE_ENTRY sh_mode_entry | |
599 | ||
600 | #undef TARGET_MODE_EXIT | |
601 | #define TARGET_MODE_EXIT sh_mode_exit | |
602 | ||
603 | #undef TARGET_MODE_PRIORITY | |
604 | #define TARGET_MODE_PRIORITY sh_mode_priority | |
605 | ||
f77a5bb0 | 606 | /* Return regmode weight for insn. */ |
c3583c9c | 607 | #define INSN_REGMODE_WEIGHT(INSN, MODE)\ |
608 | regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] | |
f77a5bb0 | 609 | |
610 | /* Return current register pressure for regmode. */ | |
c3583c9c | 611 | #define CURR_REGMODE_PRESSURE(MODE)\ |
612 | curr_regmode_pressure[((MODE) == SImode) ? 0 : 1] | |
f77a5bb0 | 613 | |
5241f4ad | 614 | #undef TARGET_ENCODE_SECTION_INFO |
615 | #define TARGET_ENCODE_SECTION_INFO sh_encode_section_info | |
616 | ||
4d58fa46 | 617 | #undef TARGET_SECONDARY_RELOAD |
618 | #define TARGET_SECONDARY_RELOAD sh_secondary_reload | |
619 | ||
167f2e19 | 620 | #undef TARGET_PREFERRED_RELOAD_CLASS |
621 | #define TARGET_PREFERRED_RELOAD_CLASS sh_preferred_reload_class | |
622 | ||
b2d7ede1 | 623 | #undef TARGET_CONDITIONAL_REGISTER_USAGE |
624 | #define TARGET_CONDITIONAL_REGISTER_USAGE sh_conditional_register_usage | |
625 | ||
eeabeacf | 626 | #undef TARGET_LEGITIMATE_ADDRESS_P |
627 | #define TARGET_LEGITIMATE_ADDRESS_P sh_legitimate_address_p | |
628 | ||
3daf7435 | 629 | #undef TARGET_TRAMPOLINE_INIT |
630 | #define TARGET_TRAMPOLINE_INIT sh_trampoline_init | |
631 | #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS | |
632 | #define TARGET_TRAMPOLINE_ADJUST_ADDRESS sh_trampoline_adjust_address | |
633 | ||
ca316360 | 634 | #undef TARGET_LEGITIMATE_CONSTANT_P |
635 | #define TARGET_LEGITIMATE_CONSTANT_P sh_legitimate_constant_p | |
636 | ||
d5065e6e | 637 | #undef TARGET_CANONICALIZE_COMPARISON |
638 | #define TARGET_CANONICALIZE_COMPARISON sh_canonicalize_comparison | |
639 | ||
32f5fb24 | 640 | #undef TARGET_FIXED_CONDITION_CODE_REGS |
641 | #define TARGET_FIXED_CONDITION_CODE_REGS sh_fixed_condition_code_regs | |
642 | ||
5241f4ad | 643 | /* Machine-specific symbol_ref flags. */ |
6c049e03 | 644 | #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) |
5241f4ad | 645 | |
940bb42d | 646 | /* The tas.b instruction sets the 7th bit in the byte, i.e. 0x80. This value |
647 | is used by optabs.c atomic op expansion code as well as in sync.md. */ | |
648 | #undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL | |
649 | #define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 0x80 | |
650 | ||
57e4bbfb | 651 | struct gcc_target targetm = TARGET_INITIALIZER; |
47c009e5 | 652 | \f |
7928e854 | 653 | |
654 | /* Information on the currently selected atomic model. | |
655 | This is initialized in sh_option_override. */ | |
656 | static sh_atomic_model selected_atomic_model_; | |
657 | ||
658 | const sh_atomic_model& | |
659 | selected_atomic_model (void) | |
660 | { | |
661 | return selected_atomic_model_; | |
662 | } | |
663 | ||
664 | static sh_atomic_model | |
665 | parse_validate_atomic_model_option (const char* str) | |
666 | { | |
667 | const char* model_names[sh_atomic_model::num_models]; | |
668 | model_names[sh_atomic_model::none] = "none"; | |
669 | model_names[sh_atomic_model::soft_gusa] = "soft-gusa"; | |
670 | model_names[sh_atomic_model::hard_llcs] = "hard-llcs"; | |
671 | model_names[sh_atomic_model::soft_tcb] = "soft-tcb"; | |
672 | model_names[sh_atomic_model::soft_imask] = "soft-imask"; | |
673 | ||
cfaba078 | 674 | const char* model_cdef_names[sh_atomic_model::num_models]; |
675 | model_cdef_names[sh_atomic_model::none] = "NONE"; | |
676 | model_cdef_names[sh_atomic_model::soft_gusa] = "SOFT_GUSA"; | |
677 | model_cdef_names[sh_atomic_model::hard_llcs] = "HARD_LLCS"; | |
678 | model_cdef_names[sh_atomic_model::soft_tcb] = "SOFT_TCB"; | |
679 | model_cdef_names[sh_atomic_model::soft_imask] = "SOFT_IMASK"; | |
680 | ||
7928e854 | 681 | sh_atomic_model ret; |
682 | ret.type = sh_atomic_model::none; | |
cfaba078 | 683 | ret.name = model_names[sh_atomic_model::none]; |
684 | ret.cdef_name = model_cdef_names[sh_atomic_model::none]; | |
7928e854 | 685 | ret.strict = false; |
686 | ret.tcb_gbr_offset = -1; | |
687 | ||
688 | /* Handle empty string as 'none'. */ | |
689 | if (str == NULL || *str == '\0') | |
690 | return ret; | |
691 | ||
692 | #define err_ret(...) do { error (__VA_ARGS__); return ret; } while (0) | |
693 | ||
694 | std::vector<std::string> tokens; | |
695 | for (std::stringstream ss (str); ss.good (); ) | |
696 | { | |
697 | tokens.push_back (std::string ()); | |
698 | std::getline (ss, tokens.back (), ','); | |
699 | } | |
700 | ||
701 | if (tokens.empty ()) | |
702 | err_ret ("invalid atomic model option"); | |
703 | ||
704 | /* The first token must be the atomic model name. */ | |
705 | { | |
706 | for (size_t i = 0; i < sh_atomic_model::num_models; ++i) | |
707 | if (tokens.front () == model_names[i]) | |
708 | { | |
709 | ret.type = (sh_atomic_model::enum_type)i; | |
cfaba078 | 710 | ret.name = model_names[i]; |
711 | ret.cdef_name = model_cdef_names[i]; | |
7928e854 | 712 | goto got_mode_name; |
713 | } | |
714 | ||
715 | err_ret ("invalid atomic model name \"%s\"", tokens.front ().c_str ()); | |
716 | got_mode_name:; | |
717 | } | |
718 | ||
719 | /* Go through the remaining tokens. */ | |
720 | for (size_t i = 1; i < tokens.size (); ++i) | |
721 | { | |
722 | if (tokens[i] == "strict") | |
723 | ret.strict = true; | |
724 | else if (tokens[i].find ("gbr-offset=") == 0) | |
725 | { | |
726 | std::string offset_str = tokens[i].substr (strlen ("gbr-offset=")); | |
727 | ret.tcb_gbr_offset = integral_argument (offset_str.c_str ()); | |
728 | if (offset_str.empty () || ret.tcb_gbr_offset == -1) | |
729 | err_ret ("could not parse gbr-offset value \"%s\" in atomic model " | |
730 | "option", offset_str.c_str ()); | |
731 | } | |
732 | else | |
733 | err_ret ("unknown parameter \"%s\" in atomic model option", | |
6c049e03 | 734 | tokens[i].c_str ()); |
7928e854 | 735 | } |
736 | ||
737 | /* Check that the selection makes sense. */ | |
738 | if (TARGET_SHMEDIA && ret.type != sh_atomic_model::none) | |
739 | err_ret ("atomic operations are not supported on SHmedia"); | |
740 | ||
741 | if (ret.type == sh_atomic_model::soft_gusa && !TARGET_SH3) | |
742 | err_ret ("atomic model %s is only available on SH3 and SH4 targets", | |
cfaba078 | 743 | ret.name); |
7928e854 | 744 | |
745 | if (ret.type == sh_atomic_model::hard_llcs && !TARGET_SH4A) | |
cfaba078 | 746 | err_ret ("atomic model %s is only available on SH4A targets", ret.name); |
7928e854 | 747 | |
748 | if (ret.type == sh_atomic_model::soft_tcb && ret.tcb_gbr_offset == -1) | |
cfaba078 | 749 | err_ret ("atomic model %s requires gbr-offset parameter", ret.name); |
7928e854 | 750 | |
751 | if (ret.type == sh_atomic_model::soft_tcb | |
752 | && (ret.tcb_gbr_offset < 0 || ret.tcb_gbr_offset > 1020 | |
753 | || (ret.tcb_gbr_offset & 3) != 0)) | |
754 | err_ret ("invalid gbr-offset value \"%d\" for atomic model %s; it must be " | |
755 | "a multiple of 4 in the range 0-1020", ret.tcb_gbr_offset, | |
cfaba078 | 756 | ret.name); |
7928e854 | 757 | |
758 | if (ret.type == sh_atomic_model::soft_imask && TARGET_USERMODE) | |
cfaba078 | 759 | err_ret ("cannot use atomic model %s in user mode", ret.name); |
7928e854 | 760 | |
761 | return ret; | |
762 | ||
763 | #undef err_ret | |
764 | } | |
765 | ||
32f5fb24 | 766 | /* Register SH specific RTL passes. */ |
767 | extern opt_pass* make_pass_sh_treg_combine (gcc::context* ctx, bool split_insns, | |
ee8867ef | 768 | const char* name); |
769 | extern opt_pass* make_pass_sh_optimize_sett_clrt (gcc::context* ctx, | |
770 | const char* name); | |
32f5fb24 | 771 | static void |
772 | register_sh_passes (void) | |
773 | { | |
774 | if (!TARGET_SH1) | |
775 | return; | |
776 | ||
777 | /* Running the sh_treg_combine pass after ce1 generates better code when | |
778 | comparisons are combined and reg-reg moves are introduced, because | |
779 | reg-reg moves will be eliminated afterwards. However, there are quite | |
780 | some cases where combine will be unable to fold comparison related insns, | |
781 | thus for now don't do it. | |
782 | register_pass (make_pass_sh_treg_combine (g, false, "sh_treg_combine1"), | |
783 | PASS_POS_INSERT_AFTER, "ce1", 1); | |
784 | */ | |
785 | ||
786 | /* Run sh_treg_combine pass after combine but before register allocation. */ | |
787 | register_pass (make_pass_sh_treg_combine (g, true, "sh_treg_combine2"), | |
788 | PASS_POS_INSERT_AFTER, "split1", 1); | |
789 | ||
790 | /* Run sh_treg_combine pass after register allocation and basic block | |
791 | reordering as this sometimes creates new opportunities. */ | |
792 | register_pass (make_pass_sh_treg_combine (g, true, "sh_treg_combine3"), | |
793 | PASS_POS_INSERT_AFTER, "split4", 1); | |
ee8867ef | 794 | |
795 | /* Optimize sett and clrt insns, by e.g. removing them if the T bit value | |
796 | is known after a conditional branch. | |
797 | This must be done after basic blocks and branch conditions have | |
798 | stabilized and won't be changed by further passes. */ | |
799 | register_pass (make_pass_sh_optimize_sett_clrt (g, "sh_optimize_sett_clrt"), | |
800 | PASS_POS_INSERT_BEFORE, "sched2", 1); | |
32f5fb24 | 801 | } |
802 | ||
eb9063bf | 803 | /* Implement TARGET_OPTION_OVERRIDE macro. Validate and override |
804 | various options, and do some machine dependent initialization. */ | |
805 | static void | |
806 | sh_option_override (void) | |
9b8dc018 | 807 | { |
808 | int regno; | |
809 | ||
810 | SUBTARGET_OVERRIDE_OPTIONS; | |
c17f64cc | 811 | if (optimize > 1 && !optimize_size) |
812 | target_flags |= MASK_SAVE_ALL_TARGET_REGS; | |
383be66e | 813 | |
814 | /* Set default values of TARGET_CBRANCHDI4 and TARGET_CMPEQDI_T. */ | |
815 | TARGET_CBRANCHDI4 = 1; | |
816 | TARGET_CMPEQDI_T = 0; | |
817 | ||
9b8dc018 | 818 | sh_cpu = PROCESSOR_SH1; |
819 | assembler_dialect = 0; | |
820 | if (TARGET_SH2) | |
821 | sh_cpu = PROCESSOR_SH2; | |
822 | if (TARGET_SH2E) | |
823 | sh_cpu = PROCESSOR_SH2E; | |
824 | if (TARGET_SH2A) | |
c4af075b | 825 | sh_cpu = PROCESSOR_SH2A; |
9b8dc018 | 826 | if (TARGET_SH3) |
827 | sh_cpu = PROCESSOR_SH3; | |
828 | if (TARGET_SH3E) | |
829 | sh_cpu = PROCESSOR_SH3E; | |
830 | if (TARGET_SH4) | |
831 | { | |
832 | assembler_dialect = 1; | |
833 | sh_cpu = PROCESSOR_SH4; | |
834 | } | |
5b271aff | 835 | if (TARGET_SH4A) |
9b8dc018 | 836 | { |
837 | assembler_dialect = 1; | |
838 | sh_cpu = PROCESSOR_SH4A; | |
839 | } | |
840 | if (TARGET_SH5) | |
841 | { | |
842 | sh_cpu = PROCESSOR_SH5; | |
843 | target_flags |= MASK_ALIGN_DOUBLE; | |
844 | if (TARGET_SHMEDIA_FPU) | |
845 | target_flags |= MASK_FMOVD; | |
846 | if (TARGET_SHMEDIA) | |
847 | { | |
848 | /* There are no delay slots on SHmedia. */ | |
849 | flag_delayed_branch = 0; | |
850 | /* Relaxation isn't yet supported for SHmedia */ | |
851 | target_flags &= ~MASK_RELAX; | |
852 | /* After reload, if conversion does little good but can cause | |
853 | ICEs: | |
854 | - find_if_block doesn't do anything for SH because we don't | |
855 | have conditional execution patterns. (We use conditional | |
856 | move patterns, which are handled differently, and only | |
857 | before reload). | |
858 | - find_cond_trap doesn't do anything for the SH because we | |
859 | don't have conditional traps. | |
860 | - find_if_case_1 uses redirect_edge_and_branch_force in | |
861 | the only path that does an optimization, and this causes | |
862 | an ICE when branch targets are in registers. | |
863 | - find_if_case_2 doesn't do anything for the SHmedia after | |
864 | reload except when it can redirect a tablejump - and | |
865 | that's rather rare. */ | |
866 | flag_if_conversion2 = 0; | |
867 | if (! strcmp (sh_div_str, "call")) | |
868 | sh_div_strategy = SH_DIV_CALL; | |
869 | else if (! strcmp (sh_div_str, "call2")) | |
870 | sh_div_strategy = SH_DIV_CALL2; | |
871 | if (! strcmp (sh_div_str, "fp") && TARGET_FPU_ANY) | |
872 | sh_div_strategy = SH_DIV_FP; | |
873 | else if (! strcmp (sh_div_str, "inv")) | |
874 | sh_div_strategy = SH_DIV_INV; | |
875 | else if (! strcmp (sh_div_str, "inv:minlat")) | |
876 | sh_div_strategy = SH_DIV_INV_MINLAT; | |
877 | else if (! strcmp (sh_div_str, "inv20u")) | |
878 | sh_div_strategy = SH_DIV_INV20U; | |
879 | else if (! strcmp (sh_div_str, "inv20l")) | |
880 | sh_div_strategy = SH_DIV_INV20L; | |
881 | else if (! strcmp (sh_div_str, "inv:call2")) | |
882 | sh_div_strategy = SH_DIV_INV_CALL2; | |
883 | else if (! strcmp (sh_div_str, "inv:call")) | |
884 | sh_div_strategy = SH_DIV_INV_CALL; | |
885 | else if (! strcmp (sh_div_str, "inv:fp")) | |
886 | { | |
887 | if (TARGET_FPU_ANY) | |
888 | sh_div_strategy = SH_DIV_INV_FP; | |
889 | else | |
890 | sh_div_strategy = SH_DIV_INV; | |
891 | } | |
892 | TARGET_CBRANCHDI4 = 0; | |
893 | /* Assembler CFI isn't yet fully supported for SHmedia. */ | |
894 | flag_dwarf2_cfi_asm = 0; | |
895 | } | |
896 | } | |
897 | else | |
898 | { | |
899 | /* Only the sh64-elf assembler fully supports .quad properly. */ | |
900 | targetm.asm_out.aligned_op.di = NULL; | |
901 | targetm.asm_out.unaligned_op.di = NULL; | |
902 | } | |
aa8ecb42 | 903 | |
904 | /* User/priviledged mode is supported only on SH3*, SH4* and SH5*. | |
905 | Disable it for everything else. */ | |
906 | if (! (TARGET_SH3 || TARGET_SH5) && TARGET_USERMODE) | |
907 | TARGET_USERMODE = false; | |
908 | ||
9b8dc018 | 909 | if (TARGET_SH1) |
910 | { | |
911 | if (! strcmp (sh_div_str, "call-div1")) | |
912 | sh_div_strategy = SH_DIV_CALL_DIV1; | |
913 | else if (! strcmp (sh_div_str, "call-fp") | |
bb057878 | 914 | && (TARGET_FPU_DOUBLE || TARGET_FPU_SINGLE_ONLY |
9b8dc018 | 915 | || (TARGET_SHCOMPACT && TARGET_FPU_ANY))) |
916 | sh_div_strategy = SH_DIV_CALL_FP; | |
9fe603c3 | 917 | else if (! strcmp (sh_div_str, "call-table") && TARGET_DYNSHIFT) |
9b8dc018 | 918 | sh_div_strategy = SH_DIV_CALL_TABLE; |
919 | else | |
920 | /* Pick one that makes most sense for the target in general. | |
921 | It is not much good to use different functions depending | |
922 | on -Os, since then we'll end up with two different functions | |
923 | when some of the code is compiled for size, and some for | |
924 | speed. */ | |
925 | ||
926 | /* SH4 tends to emphasize speed. */ | |
927 | if (TARGET_HARD_SH4) | |
928 | sh_div_strategy = SH_DIV_CALL_TABLE; | |
929 | /* These have their own way of doing things. */ | |
930 | else if (TARGET_SH2A) | |
931 | sh_div_strategy = SH_DIV_INTRINSIC; | |
932 | /* ??? Should we use the integer SHmedia function instead? */ | |
933 | else if (TARGET_SHCOMPACT && TARGET_FPU_ANY) | |
934 | sh_div_strategy = SH_DIV_CALL_FP; | |
6c049e03 | 935 | /* SH1 .. SH3 cores often go into small-footprint systems, so |
9b8dc018 | 936 | default to the smallest implementation available. */ |
9b8dc018 | 937 | else |
938 | sh_div_strategy = SH_DIV_CALL_DIV1; | |
939 | } | |
940 | if (!TARGET_SH1) | |
941 | TARGET_PRETEND_CMOVE = 0; | |
942 | if (sh_divsi3_libfunc[0]) | |
943 | ; /* User supplied - leave it alone. */ | |
944 | else if (TARGET_DIVIDE_CALL_FP) | |
945 | sh_divsi3_libfunc = "__sdivsi3_i4"; | |
946 | else if (TARGET_DIVIDE_CALL_TABLE) | |
947 | sh_divsi3_libfunc = "__sdivsi3_i4i"; | |
948 | else if (TARGET_SH5) | |
949 | sh_divsi3_libfunc = "__sdivsi3_1"; | |
950 | else | |
951 | sh_divsi3_libfunc = "__sdivsi3"; | |
e2c18ed9 | 952 | |
9b8dc018 | 953 | if (sh_branch_cost == -1) |
96d93b11 | 954 | { |
96d93b11 | 955 | /* The SH1 does not have delay slots, hence we get a pipeline stall |
956 | at every branch. The SH4 is superscalar, so the single delay slot | |
e2c18ed9 | 957 | is not sufficient to keep both pipelines filled. |
958 | In any case, set the default branch cost to '2', as it results in | |
959 | slightly overall smaller code and also enables some if conversions | |
960 | that are required for matching special T bit related insns. */ | |
961 | sh_branch_cost = 2; | |
96d93b11 | 962 | } |
9b8dc018 | 963 | |
eb9f349a | 964 | /* Set -mzdcbranch for SH4 / SH4A if not otherwise specified by the user. */ |
965 | if (! global_options_set.x_TARGET_ZDCBRANCH && TARGET_HARD_SH4) | |
966 | TARGET_ZDCBRANCH = 1; | |
967 | ||
9b8dc018 | 968 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) |
969 | if (! VALID_REGISTER_P (regno)) | |
970 | sh_register_names[regno][0] = '\0'; | |
971 | ||
972 | for (regno = 0; regno < ADDREGNAMES_SIZE; regno++) | |
973 | if (! VALID_REGISTER_P (ADDREGNAMES_REGNO (regno))) | |
974 | sh_additional_register_names[regno][0] = '\0'; | |
975 | ||
9b8dc018 | 976 | if ((flag_pic && ! TARGET_PREFERGOT) |
977 | || (TARGET_SHMEDIA && !TARGET_PT_FIXED)) | |
978 | flag_no_function_cse = 1; | |
979 | ||
6c049e03 | 980 | if (targetm.small_register_classes_for_mode_p (VOIDmode)) |
9b8dc018 | 981 | { |
982 | /* Never run scheduling before reload, since that can | |
983 | break global alloc, and generates slower code anyway due | |
984 | to the pressure on R0. */ | |
985 | /* Enable sched1 for SH4 if the user explicitly requests. | |
986 | When sched1 is enabled, the ready queue will be reordered by | |
987 | the target hooks if pressure is high. We can not do this for | |
988 | PIC, SH3 and lower as they give spill failures for R0. */ | |
989 | if (!TARGET_HARD_SH4 || flag_pic) | |
6c049e03 | 990 | flag_schedule_insns = 0; |
9b8dc018 | 991 | /* ??? Current exception handling places basic block boundaries |
992 | after call_insns. It causes the high pressure on R0 and gives | |
993 | spill failures for R0 in reload. See PR 22553 and the thread | |
994 | on gcc-patches | |
6c049e03 | 995 | <http://gcc.gnu.org/ml/gcc-patches/2005-10/msg00816.html>. */ |
9b8dc018 | 996 | else if (flag_exceptions) |
997 | { | |
7332acfc | 998 | if (flag_schedule_insns && global_options_set.x_flag_schedule_insns) |
6c049e03 | 999 | warning (0, "ignoring -fschedule-insns because of exception " |
1000 | "handling bug"); | |
9b8dc018 | 1001 | flag_schedule_insns = 0; |
1002 | } | |
7332acfc | 1003 | else if (flag_schedule_insns |
1004 | && !global_options_set.x_flag_schedule_insns) | |
9b8dc018 | 1005 | flag_schedule_insns = 0; |
1006 | } | |
1007 | ||
901e08a3 | 1008 | /* Unwind info is not correct around the CFG unless either a frame |
1009 | pointer is present or M_A_O_A is set. Fixing this requires rewriting | |
1010 | unwind info generation to be aware of the CFG and propagating states | |
992d172c | 1011 | around edges. */ |
1012 | if ((flag_unwind_tables || flag_asynchronous_unwind_tables | |
901e08a3 | 1013 | || flag_exceptions || flag_non_call_exceptions) |
1014 | && flag_omit_frame_pointer && !TARGET_ACCUMULATE_OUTGOING_ARGS) | |
992d172c | 1015 | { |
901e08a3 | 1016 | warning (0, "unwind tables currently require either a frame pointer " |
1017 | "or -maccumulate-outgoing-args for correctness"); | |
1018 | TARGET_ACCUMULATE_OUTGOING_ARGS = 1; | |
992d172c | 1019 | } |
1020 | ||
06b71e62 | 1021 | /* Unwinding with -freorder-blocks-and-partition does not work on this |
1022 | architecture, because it requires far jumps to label crossing between | |
1023 | hot/cold sections which are rejected on this architecture. */ | |
1024 | if (flag_reorder_blocks_and_partition) | |
1025 | { | |
1026 | if (flag_exceptions) | |
1027 | { | |
1028 | inform (input_location, | |
1029 | "-freorder-blocks-and-partition does not work with " | |
1030 | "exceptions on this architecture"); | |
1031 | flag_reorder_blocks_and_partition = 0; | |
1032 | flag_reorder_blocks = 1; | |
1033 | } | |
1034 | else if (flag_unwind_tables) | |
1035 | { | |
1036 | inform (input_location, | |
1037 | "-freorder-blocks-and-partition does not support unwind " | |
1038 | "info on this architecture"); | |
1039 | flag_reorder_blocks_and_partition = 0; | |
1040 | flag_reorder_blocks = 1; | |
1041 | } | |
1042 | } | |
1043 | ||
164fbbdf | 1044 | /* Adjust loop, jump and function alignment values (in bytes), if those |
1045 | were not specified by the user using -falign-loops, -falign-jumps | |
1046 | and -falign-functions options. | |
1047 | 32 bit alignment is better for speed, because instructions can be | |
1048 | fetched as a pair from a longword boundary. For size use 16 bit | |
1049 | alignment to get more compact code. | |
1050 | Aligning all jumps increases the code size, even if it might | |
1051 | result in slightly faster code. Thus, it is set to the smallest | |
1052 | alignment possible if not specified by the user. */ | |
9b8dc018 | 1053 | if (align_loops == 0) |
164fbbdf | 1054 | { |
1055 | if (TARGET_SH5) | |
1056 | align_loops = 8; | |
1057 | else | |
1058 | align_loops = optimize_size ? 2 : 4; | |
1059 | } | |
1060 | ||
9b8dc018 | 1061 | if (align_jumps == 0) |
164fbbdf | 1062 | { |
1063 | if (TARGET_SHMEDIA) | |
1064 | align_jumps = 1 << CACHE_LOG; | |
1065 | else | |
1066 | align_jumps = 2; | |
1067 | } | |
9b8dc018 | 1068 | else if (align_jumps < (TARGET_SHMEDIA ? 4 : 2)) |
1069 | align_jumps = TARGET_SHMEDIA ? 4 : 2; | |
1070 | ||
9b8dc018 | 1071 | if (align_functions == 0) |
164fbbdf | 1072 | { |
1073 | if (TARGET_SHMEDIA) | |
1074 | align_functions = optimize_size | |
1075 | ? FUNCTION_BOUNDARY/8 : (1 << CACHE_LOG); | |
1076 | else | |
1077 | align_functions = optimize_size ? 2 : 4; | |
1078 | } | |
1079 | ||
9b8dc018 | 1080 | /* The linker relaxation code breaks when a function contains |
1081 | alignments that are larger than that at the start of a | |
1082 | compilation unit. */ | |
1083 | if (TARGET_RELAX) | |
1084 | { | |
6c049e03 | 1085 | int min_align = align_loops > align_jumps ? align_loops : align_jumps; |
9b8dc018 | 1086 | |
6c049e03 | 1087 | /* Also take possible .long constants / mova tables into account. */ |
9b8dc018 | 1088 | if (min_align < 4) |
1089 | min_align = 4; | |
1090 | if (align_functions < min_align) | |
1091 | align_functions = min_align; | |
1092 | } | |
1093 | ||
2b15a89a | 1094 | if (flag_unsafe_math_optimizations) |
1095 | { | |
2b15a89a | 1096 | /* Enable fsca insn for SH4A if not otherwise specified by the user. */ |
1097 | if (global_options_set.x_TARGET_FSCA == 0 && TARGET_SH4A_FP) | |
1098 | TARGET_FSCA = 1; | |
1099 | ||
1100 | /* Enable fsrra insn for SH4A if not otherwise specified by the user. */ | |
1101 | if (global_options_set.x_TARGET_FSRRA == 0 && TARGET_SH4A_FP) | |
1102 | TARGET_FSRRA = 1; | |
1103 | } | |
1104 | ||
1105 | /* Allow fsrra insn only if -funsafe-math-optimizations and | |
1106 | -ffinite-math-only is enabled. */ | |
1107 | TARGET_FSRRA = TARGET_FSRRA | |
1108 | && flag_unsafe_math_optimizations | |
1109 | && flag_finite_math_only; | |
de9013ac | 1110 | |
df3032ff | 1111 | /* If the -mieee option was not explicitly set by the user, turn it on |
1112 | unless -ffinite-math-only was specified. See also PR 33135. */ | |
1113 | if (! global_options_set.x_TARGET_IEEE) | |
1114 | TARGET_IEEE = ! flag_finite_math_only; | |
1115 | ||
9b8dc018 | 1116 | if (sh_fixed_range_str) |
1117 | sh_fix_range (sh_fixed_range_str); | |
1af17d44 | 1118 | |
1119 | /* This target defaults to strict volatile bitfields. */ | |
941a2396 | 1120 | if (flag_strict_volatile_bitfields < 0 && abi_version_at_least(2)) |
1af17d44 | 1121 | flag_strict_volatile_bitfields = 1; |
e10782c9 | 1122 | |
7928e854 | 1123 | /* Parse atomic model option and make sure it is valid for the current |
1124 | target CPU. */ | |
1125 | selected_atomic_model_ | |
1126 | = parse_validate_atomic_model_option (sh_atomic_model_str); | |
32f5fb24 | 1127 | |
1128 | register_sh_passes (); | |
9b8dc018 | 1129 | } |
1130 | \f | |
1504eb7e | 1131 | /* Print the operand address in x to the stream. */ |
e8c57574 | 1132 | static void |
1133 | sh_print_operand_address (FILE *stream, rtx x) | |
7208c779 | 1134 | { |
1135 | switch (GET_CODE (x)) | |
1136 | { | |
1137 | case REG: | |
1b61190c | 1138 | case SUBREG: |
1139 | fprintf (stream, "@%s", reg_names[true_regnum (x)]); | |
7208c779 | 1140 | break; |
73401833 | 1141 | |
7208c779 | 1142 | case PLUS: |
1143 | { | |
1144 | rtx base = XEXP (x, 0); | |
1145 | rtx index = XEXP (x, 1); | |
1146 | ||
7208c779 | 1147 | switch (GET_CODE (index)) |
1148 | { | |
1149 | case CONST_INT: | |
26576132 | 1150 | fprintf (stream, "@(%d,%s)", (int) INTVAL (index), |
1b61190c | 1151 | reg_names[true_regnum (base)]); |
7208c779 | 1152 | break; |
1153 | ||
1154 | case REG: | |
1b61190c | 1155 | case SUBREG: |
1156 | { | |
1157 | int base_num = true_regnum (base); | |
1158 | int index_num = true_regnum (index); | |
1159 | ||
1160 | fprintf (stream, "@(r0,%s)", | |
1161 | reg_names[MAX (base_num, index_num)]); | |
1162 | break; | |
1163 | } | |
7208c779 | 1164 | |
1165 | default: | |
1a6a7a27 | 1166 | gcc_unreachable (); |
7208c779 | 1167 | } |
1168 | } | |
7208c779 | 1169 | break; |
73401833 | 1170 | |
7208c779 | 1171 | case PRE_DEC: |
1b61190c | 1172 | fprintf (stream, "@-%s", reg_names[true_regnum (XEXP (x, 0))]); |
7208c779 | 1173 | break; |
1174 | ||
1175 | case POST_INC: | |
1b61190c | 1176 | fprintf (stream, "@%s+", reg_names[true_regnum (XEXP (x, 0))]); |
7208c779 | 1177 | break; |
1178 | ||
1179 | default: | |
ecf6ff7c | 1180 | x = mark_constant_pool_use (x); |
b60f0749 | 1181 | output_addr_const (stream, x); |
7208c779 | 1182 | break; |
1183 | } | |
1184 | } | |
1185 | ||
1186 | /* Print operand x (an rtx) in assembler syntax to file stream | |
1187 | according to modifier code. | |
1188 | ||
47c009e5 | 1189 | '.' print a .s if insn needs delay slot |
8ded0752 | 1190 | ',' print LOCAL_LABEL_PREFIX |
15cb1799 | 1191 | '@' print trap, rte or rts depending upon pragma interruptness |
73401833 | 1192 | '#' output a nop if there is nothing to put in the delay slot |
1fc184ee | 1193 | ''' print likelihood suffix (/u for unlikely). |
59312820 | 1194 | '>' print branch target if -fverbose-asm |
73401833 | 1195 | 'O' print a constant without the # |
3dfc1807 | 1196 | 'R' print the LSW of a dp value - changes if in little endian |
3dfc1807 | 1197 | 'S' print the MSW of a dp value - changes if in little endian |
1b61190c | 1198 | 'T' print the next word of a dp value - same as 'R' in big endian mode. |
2b2f5cfb | 1199 | 'M' SHMEDIA: print an `x' if `m' will print `base,index'. |
1200 | otherwise: print .b / .w / .l / .s / .d suffix if operand is a MEM. | |
e3fac27d | 1201 | 'N' print 'r63' if the operand is (const_int 0). |
9435e831 | 1202 | 'd' print a V2SF reg as dN instead of fpN. |
87e19636 | 1203 | 'm' print a pair `base,offset' or `base,index', for LD and ST. |
59312820 | 1204 | 'U' Likewise for {LD,ST}{HI,LO}. |
bc1c5420 | 1205 | 'V' print the position of a single bit set. |
1206 | 'W' print the position of a single bit cleared. | |
96a7f216 | 1207 | 't' print a memory address which is a register. |
87e19636 | 1208 | 'u' prints the lowest 16 bits of CONST_INT, as an unsigned value. |
1b61190c | 1209 | 'o' output an operator. */ |
e8c57574 | 1210 | static void |
1211 | sh_print_operand (FILE *stream, rtx x, int code) | |
7208c779 | 1212 | { |
59312820 | 1213 | int regno; |
3754d046 | 1214 | machine_mode mode; |
59312820 | 1215 | |
7208c779 | 1216 | switch (code) |
1217 | { | |
57d5535b | 1218 | tree trapa_attr; |
1219 | ||
47c009e5 | 1220 | case '.': |
3f2613e4 | 1221 | if (final_sequence |
d3ffa7b4 | 1222 | && ! INSN_ANNULLED_BRANCH_P (final_sequence->insn (0)) |
1223 | && get_attr_length (final_sequence->insn (1))) | |
8ded0752 | 1224 | fprintf (stream, ASSEMBLER_DIALECT ? "/s" : ".s"); |
1225 | break; | |
1226 | case ',': | |
1227 | fprintf (stream, "%s", LOCAL_LABEL_PREFIX); | |
47c009e5 | 1228 | break; |
f3d93547 | 1229 | case '@': |
57d5535b | 1230 | trapa_attr = lookup_attribute ("trap_exit", |
1231 | DECL_ATTRIBUTES (current_function_decl)); | |
1232 | if (trapa_attr) | |
6c049e03 | 1233 | fprintf (stream, "trapa #%ld", |
57d5535b | 1234 | (long) TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (trapa_attr)))); |
5df3d11f | 1235 | else if (sh_cfun_interrupt_handler_p ()) |
5241f4ad | 1236 | { |
1237 | if (sh_cfun_resbank_handler_p ()) | |
1238 | fprintf (stream, "resbank\n"); | |
1239 | fprintf (stream, "rte"); | |
1240 | } | |
f3d93547 | 1241 | else |
2e3d4844 | 1242 | fprintf (stream, "rts"); |
f3d93547 | 1243 | break; |
7208c779 | 1244 | case '#': |
1504eb7e | 1245 | /* Output a nop if there's nothing in the delay slot. */ |
7208c779 | 1246 | if (dbr_sequence_length () == 0) |
73401833 | 1247 | fprintf (stream, "\n\tnop"); |
7208c779 | 1248 | break; |
3c4bc54e | 1249 | case '\'': |
1250 | { | |
1251 | rtx note = find_reg_note (current_output_insn, REG_BR_PROB, 0); | |
1252 | ||
9eb946de | 1253 | if (note && XINT (note, 0) * 2 < REG_BR_PROB_BASE) |
3c4bc54e | 1254 | fputs ("/u", stream); |
1255 | break; | |
1256 | } | |
59312820 | 1257 | case '>': |
1258 | if (flag_verbose_asm && JUMP_LABEL (current_output_insn)) | |
1259 | { | |
1260 | fputs ("\t! target: ", stream); | |
1261 | output_addr_const (stream, JUMP_LABEL (current_output_insn)); | |
1262 | } | |
1263 | break; | |
47c009e5 | 1264 | case 'O': |
ecf6ff7c | 1265 | x = mark_constant_pool_use (x); |
97595bfd | 1266 | output_addr_const (stream, x); |
7208c779 | 1267 | break; |
c8cd1805 | 1268 | /* N.B.: %R / %S / %T adjust memory addresses by four. |
1269 | For SHMEDIA, that means they can be used to access the first and | |
1270 | second 32 bit part of a 64 bit (or larger) value that | |
1271 | might be held in floating point registers or memory. | |
1272 | While they can be used to access 64 bit parts of a larger value | |
1273 | held in general purpose registers, that won't work with memory - | |
1274 | neither for fp registers, since the frxx names are used. */ | |
7208c779 | 1275 | case 'R': |
c8cd1805 | 1276 | if (REG_P (x) || GET_CODE (x) == SUBREG) |
1277 | { | |
1278 | regno = true_regnum (x); | |
adb7af07 | 1279 | regno += FP_REGISTER_P (regno) ? 1 : SH_REG_LSW_OFFSET; |
c8cd1805 | 1280 | fputs (reg_names[regno], (stream)); |
1281 | } | |
1282 | else if (MEM_P (x)) | |
1283 | { | |
adb7af07 | 1284 | x = adjust_address (x, SImode, 4 * SH_REG_LSW_OFFSET); |
e8c57574 | 1285 | sh_print_operand_address (stream, XEXP (x, 0)); |
c8cd1805 | 1286 | } |
1287 | else | |
1288 | { | |
1289 | rtx sub = NULL_RTX; | |
1290 | ||
1291 | mode = GET_MODE (x); | |
1292 | if (mode == VOIDmode) | |
1293 | mode = DImode; | |
1294 | if (GET_MODE_SIZE (mode) >= 8) | |
adb7af07 | 1295 | sub = simplify_subreg (SImode, x, mode, 4 * SH_REG_LSW_OFFSET); |
c8cd1805 | 1296 | if (sub) |
e8c57574 | 1297 | sh_print_operand (stream, sub, 0); |
c8cd1805 | 1298 | else |
1299 | output_operand_lossage ("invalid operand to %%R"); | |
1300 | } | |
73401833 | 1301 | break; |
1302 | case 'S': | |
c8cd1805 | 1303 | if (REG_P (x) || GET_CODE (x) == SUBREG) |
1304 | { | |
1305 | regno = true_regnum (x); | |
adb7af07 | 1306 | regno += FP_REGISTER_P (regno) ? 0 : SH_REG_MSW_OFFSET; |
c8cd1805 | 1307 | fputs (reg_names[regno], (stream)); |
1308 | } | |
1309 | else if (MEM_P (x)) | |
1310 | { | |
adb7af07 | 1311 | x = adjust_address (x, SImode, 4 * SH_REG_MSW_OFFSET); |
e8c57574 | 1312 | sh_print_operand_address (stream, XEXP (x, 0)); |
c8cd1805 | 1313 | } |
1314 | else | |
1315 | { | |
1316 | rtx sub = NULL_RTX; | |
1317 | ||
1318 | mode = GET_MODE (x); | |
1319 | if (mode == VOIDmode) | |
1320 | mode = DImode; | |
1321 | if (GET_MODE_SIZE (mode) >= 8) | |
adb7af07 | 1322 | sub = simplify_subreg (SImode, x, mode, 4 * SH_REG_MSW_OFFSET); |
c8cd1805 | 1323 | if (sub) |
e8c57574 | 1324 | sh_print_operand (stream, sub, 0); |
c8cd1805 | 1325 | else |
1326 | output_operand_lossage ("invalid operand to %%S"); | |
1327 | } | |
3dfc1807 | 1328 | break; |
1329 | case 'T': | |
1504eb7e | 1330 | /* Next word of a double. */ |
7208c779 | 1331 | switch (GET_CODE (x)) |
1332 | { | |
1333 | case REG: | |
1334 | fputs (reg_names[REGNO (x) + 1], (stream)); | |
1335 | break; | |
1336 | case MEM: | |
1b61190c | 1337 | if (GET_CODE (XEXP (x, 0)) != PRE_DEC |
1338 | && GET_CODE (XEXP (x, 0)) != POST_INC) | |
eafc6604 | 1339 | x = adjust_address (x, SImode, 4); |
e8c57574 | 1340 | sh_print_operand_address (stream, XEXP (x, 0)); |
7208c779 | 1341 | break; |
b7dbbdb2 | 1342 | default: |
1343 | break; | |
7208c779 | 1344 | } |
1345 | break; | |
96a7f216 | 1346 | |
1347 | case 't': | |
cbb16986 | 1348 | gcc_assert (MEM_P (x)); |
96a7f216 | 1349 | x = XEXP (x, 0); |
1350 | switch (GET_CODE (x)) | |
1351 | { | |
1352 | case REG: | |
1353 | case SUBREG: | |
e8c57574 | 1354 | sh_print_operand (stream, x, 0); |
96a7f216 | 1355 | break; |
1356 | default: | |
1357 | break; | |
1358 | } | |
1359 | break; | |
1360 | ||
1b61190c | 1361 | case 'o': |
1362 | switch (GET_CODE (x)) | |
1363 | { | |
1364 | case PLUS: fputs ("add", stream); break; | |
1365 | case MINUS: fputs ("sub", stream); break; | |
1366 | case MULT: fputs ("mul", stream); break; | |
1367 | case DIV: fputs ("div", stream); break; | |
3c4bc54e | 1368 | case EQ: fputs ("eq", stream); break; |
1369 | case NE: fputs ("ne", stream); break; | |
1370 | case GT: case LT: fputs ("gt", stream); break; | |
1371 | case GE: case LE: fputs ("ge", stream); break; | |
1372 | case GTU: case LTU: fputs ("gtu", stream); break; | |
1373 | case GEU: case LEU: fputs ("geu", stream); break; | |
b7dbbdb2 | 1374 | default: |
1375 | break; | |
1b61190c | 1376 | } |
1377 | break; | |
87e19636 | 1378 | case 'M': |
2b2f5cfb | 1379 | if (TARGET_SHMEDIA) |
1380 | { | |
cbb16986 | 1381 | if (MEM_P (x) |
2b2f5cfb | 1382 | && GET_CODE (XEXP (x, 0)) == PLUS |
cbb16986 | 1383 | && (REG_P (XEXP (XEXP (x, 0), 1)) |
2b2f5cfb | 1384 | || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG)) |
1385 | fputc ('x', stream); | |
1386 | } | |
1387 | else | |
1388 | { | |
cbb16986 | 1389 | if (MEM_P (x)) |
2b2f5cfb | 1390 | { |
1391 | switch (GET_MODE (x)) | |
1392 | { | |
1393 | case QImode: fputs (".b", stream); break; | |
1394 | case HImode: fputs (".w", stream); break; | |
1395 | case SImode: fputs (".l", stream); break; | |
1396 | case SFmode: fputs (".s", stream); break; | |
1397 | case DFmode: fputs (".d", stream); break; | |
1398 | default: gcc_unreachable (); | |
1399 | } | |
1400 | } | |
1401 | } | |
87e19636 | 1402 | break; |
1403 | ||
1404 | case 'm': | |
cbb16986 | 1405 | gcc_assert (MEM_P (x)); |
87e19636 | 1406 | x = XEXP (x, 0); |
59312820 | 1407 | /* Fall through. */ |
1408 | case 'U': | |
87e19636 | 1409 | switch (GET_CODE (x)) |
1410 | { | |
1411 | case REG: | |
1412 | case SUBREG: | |
e8c57574 | 1413 | sh_print_operand (stream, x, 0); |
87e19636 | 1414 | fputs (", 0", stream); |
1415 | break; | |
1416 | ||
1417 | case PLUS: | |
e8c57574 | 1418 | sh_print_operand (stream, XEXP (x, 0), 0); |
87e19636 | 1419 | fputs (", ", stream); |
e8c57574 | 1420 | sh_print_operand (stream, XEXP (x, 1), 0); |
87e19636 | 1421 | break; |
1422 | ||
1423 | default: | |
1a6a7a27 | 1424 | gcc_unreachable (); |
87e19636 | 1425 | } |
1426 | break; | |
1427 | ||
bc1c5420 | 1428 | case 'V': |
1429 | { | |
1430 | int num = exact_log2 (INTVAL (x)); | |
1431 | gcc_assert (num >= 0); | |
1432 | fprintf (stream, "#%d", num); | |
1433 | } | |
1434 | break; | |
1435 | ||
1436 | case 'W': | |
1437 | { | |
1438 | int num = exact_log2 (~INTVAL (x)); | |
1439 | gcc_assert (num >= 0); | |
1440 | fprintf (stream, "#%d", num); | |
1441 | } | |
1442 | break; | |
1443 | ||
9435e831 | 1444 | case 'd': |
cbb16986 | 1445 | gcc_assert (REG_P (x) && GET_MODE (x) == V2SFmode); |
9435e831 | 1446 | |
1447 | fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1); | |
1448 | break; | |
9e7454d0 | 1449 | |
e3fac27d | 1450 | case 'N': |
d3b29bbd | 1451 | if (x == CONST0_RTX (GET_MODE (x))) |
e3fac27d | 1452 | { |
1453 | fprintf ((stream), "r63"); | |
1454 | break; | |
1455 | } | |
1456 | goto default_output; | |
87e19636 | 1457 | case 'u': |
cbb16986 | 1458 | if (CONST_INT_P (x)) |
3c4bc54e | 1459 | { |
87e19636 | 1460 | fprintf ((stream), "%u", (unsigned) INTVAL (x) & (0x10000 - 1)); |
1461 | break; | |
1462 | } | |
1463 | /* Fall through. */ | |
1464 | ||
e3fac27d | 1465 | default_output: |
7208c779 | 1466 | default: |
59312820 | 1467 | regno = 0; |
1468 | mode = GET_MODE (x); | |
1469 | ||
7208c779 | 1470 | switch (GET_CODE (x)) |
1471 | { | |
59312820 | 1472 | case TRUNCATE: |
1473 | { | |
1474 | rtx inner = XEXP (x, 0); | |
1475 | int offset = 0; | |
3754d046 | 1476 | machine_mode inner_mode; |
59312820 | 1477 | |
1478 | /* We might see SUBREGs with vector mode registers inside. */ | |
1479 | if (GET_CODE (inner) == SUBREG | |
1480 | && (GET_MODE_SIZE (GET_MODE (inner)) | |
1481 | == GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner)))) | |
1482 | && subreg_lowpart_p (inner)) | |
1483 | inner = SUBREG_REG (inner); | |
cbb16986 | 1484 | if (CONST_INT_P (inner)) |
59312820 | 1485 | { |
1486 | x = GEN_INT (trunc_int_for_mode (INTVAL (inner), GET_MODE (x))); | |
1487 | goto default_output; | |
1488 | } | |
1489 | inner_mode = GET_MODE (inner); | |
1490 | if (GET_CODE (inner) == SUBREG | |
1491 | && (GET_MODE_SIZE (GET_MODE (inner)) | |
1492 | < GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner)))) | |
cbb16986 | 1493 | && REG_P (SUBREG_REG (inner))) |
59312820 | 1494 | { |
1495 | offset = subreg_regno_offset (REGNO (SUBREG_REG (inner)), | |
1496 | GET_MODE (SUBREG_REG (inner)), | |
1497 | SUBREG_BYTE (inner), | |
1498 | GET_MODE (inner)); | |
1499 | inner = SUBREG_REG (inner); | |
1500 | } | |
cbb16986 | 1501 | if (!REG_P (inner) || GET_MODE_SIZE (inner_mode) > 8) |
59312820 | 1502 | abort (); |
1503 | /* Floating point register pairs are always big endian; | |
35fe320d | 1504 | general purpose registers are 64 bit wide. */ |
59312820 | 1505 | regno = REGNO (inner); |
1506 | regno = (HARD_REGNO_NREGS (regno, inner_mode) | |
1507 | - HARD_REGNO_NREGS (regno, mode)) | |
1508 | + offset; | |
1509 | x = inner; | |
1510 | goto reg; | |
1511 | } | |
1512 | case SIGN_EXTEND: | |
1513 | x = XEXP (x, 0); | |
1514 | goto reg; | |
87e19636 | 1515 | /* FIXME: We need this on SHmedia32 because reload generates |
1516 | some sign-extended HI or QI loads into DImode registers | |
1517 | but, because Pmode is SImode, the address ends up with a | |
1518 | subreg:SI of the DImode register. Maybe reload should be | |
1519 | fixed so as to apply alter_subreg to such loads? */ | |
59312820 | 1520 | case IF_THEN_ELSE: |
1521 | gcc_assert (trapping_target_operand (x, VOIDmode)); | |
1522 | x = XEXP (XEXP (x, 2), 0); | |
1523 | goto default_output; | |
87e19636 | 1524 | case SUBREG: |
1a6a7a27 | 1525 | gcc_assert (SUBREG_BYTE (x) == 0 |
cbb16986 | 1526 | && REG_P (SUBREG_REG (x))); |
87e19636 | 1527 | |
1528 | x = SUBREG_REG (x); | |
1529 | /* Fall through. */ | |
1530 | ||
59312820 | 1531 | reg: |
7208c779 | 1532 | case REG: |
59312820 | 1533 | regno += REGNO (x); |
1534 | if (FP_REGISTER_P (regno) | |
1535 | && mode == V16SFmode) | |
1536 | fprintf ((stream), "mtrx%s", reg_names[regno] + 2); | |
87e19636 | 1537 | else if (FP_REGISTER_P (REGNO (x)) |
59312820 | 1538 | && mode == V4SFmode) |
1539 | fprintf ((stream), "fv%s", reg_names[regno] + 2); | |
cbb16986 | 1540 | else if (REG_P (x) |
59312820 | 1541 | && mode == V2SFmode) |
1542 | fprintf ((stream), "fp%s", reg_names[regno] + 2); | |
87e19636 | 1543 | else if (FP_REGISTER_P (REGNO (x)) |
59312820 | 1544 | && GET_MODE_SIZE (mode) > 4) |
1545 | fprintf ((stream), "d%s", reg_names[regno] + 1); | |
1b61190c | 1546 | else |
59312820 | 1547 | fputs (reg_names[regno], (stream)); |
7208c779 | 1548 | break; |
87e19636 | 1549 | |
7208c779 | 1550 | case MEM: |
1551 | output_address (XEXP (x, 0)); | |
1552 | break; | |
9e7454d0 | 1553 | |
7208c779 | 1554 | default: |
87e19636 | 1555 | if (TARGET_SH1) |
1556 | fputc ('#', stream); | |
7208c779 | 1557 | output_addr_const (stream, x); |
1558 | break; | |
7208c779 | 1559 | } |
1560 | break; | |
1561 | } | |
1562 | } | |
e8c57574 | 1563 | |
1564 | static bool | |
1565 | sh_print_operand_punct_valid_p (unsigned char code) | |
1566 | { | |
1567 | return (code == '.' || code == '#' || code == '@' || code == ',' | |
6c049e03 | 1568 | || code == '$' || code == '\'' || code == '>'); |
e8c57574 | 1569 | } |
a24f0184 | 1570 | |
1571 | /* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */ | |
a24f0184 | 1572 | static bool |
1573 | sh_asm_output_addr_const_extra (FILE *file, rtx x) | |
1574 | { | |
1575 | if (GET_CODE (x) == UNSPEC) | |
1576 | { | |
1577 | switch (XINT (x, 1)) | |
1578 | { | |
1579 | case UNSPEC_DATALABEL: | |
1580 | fputs ("datalabel ", file); | |
1581 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1582 | break; | |
1583 | case UNSPEC_PIC: | |
1584 | /* GLOBAL_OFFSET_TABLE or local symbols, no suffix. */ | |
1585 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1586 | break; | |
1587 | case UNSPEC_GOT: | |
1588 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1589 | fputs ("@GOT", file); | |
1590 | break; | |
1591 | case UNSPEC_GOTOFF: | |
1592 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1593 | fputs ("@GOTOFF", file); | |
1594 | break; | |
1595 | case UNSPEC_PLT: | |
1596 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1597 | fputs ("@PLT", file); | |
1598 | break; | |
1599 | case UNSPEC_GOTPLT: | |
1600 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1601 | fputs ("@GOTPLT", file); | |
1602 | break; | |
1603 | case UNSPEC_DTPOFF: | |
1604 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1605 | fputs ("@DTPOFF", file); | |
1606 | break; | |
1607 | case UNSPEC_GOTTPOFF: | |
1608 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1609 | fputs ("@GOTTPOFF", file); | |
1610 | break; | |
1611 | case UNSPEC_TPOFF: | |
1612 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1613 | fputs ("@TPOFF", file); | |
1614 | break; | |
1615 | case UNSPEC_CALLER: | |
1616 | { | |
1617 | char name[32]; | |
1618 | /* LPCS stands for Label for PIC Call Site. */ | |
1619 | targetm.asm_out.generate_internal_label (name, "LPCS", | |
1620 | INTVAL (XVECEXP (x, 0, 0))); | |
1621 | assemble_name (file, name); | |
1622 | } | |
1623 | break; | |
1624 | case UNSPEC_EXTRACT_S16: | |
1625 | case UNSPEC_EXTRACT_U16: | |
1626 | { | |
1627 | rtx val, shift; | |
1628 | ||
1629 | val = XVECEXP (x, 0, 0); | |
1630 | shift = XVECEXP (x, 0, 1); | |
1631 | fputc ('(', file); | |
1632 | if (shift != const0_rtx) | |
6c049e03 | 1633 | fputc ('(', file); |
a24f0184 | 1634 | if (GET_CODE (val) == CONST |
6c049e03 | 1635 | || GET_RTX_CLASS (GET_CODE (val)) != RTX_OBJ) |
a24f0184 | 1636 | { |
1637 | fputc ('(', file); | |
1638 | output_addr_const (file, val); | |
1639 | fputc (')', file); | |
1640 | } | |
1641 | else | |
1642 | output_addr_const (file, val); | |
1643 | if (shift != const0_rtx) | |
1644 | { | |
1645 | fputs (" >> ", file); | |
1646 | output_addr_const (file, shift); | |
1647 | fputc (')', file); | |
1648 | } | |
1649 | fputs (" & 65535)", file); | |
1650 | } | |
1651 | break; | |
1652 | case UNSPEC_SYMOFF: | |
1653 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1654 | fputc ('-', file); | |
1655 | if (GET_CODE (XVECEXP (x, 0, 1)) == CONST) | |
1656 | { | |
1657 | fputc ('(', file); | |
1658 | output_addr_const (file, XVECEXP (x, 0, 1)); | |
1659 | fputc (')', file); | |
1660 | } | |
1661 | else | |
1662 | output_addr_const (file, XVECEXP (x, 0, 1)); | |
1663 | break; | |
1664 | case UNSPEC_PCREL_SYMOFF: | |
1665 | output_addr_const (file, XVECEXP (x, 0, 0)); | |
1666 | fputs ("-(", file); | |
1667 | output_addr_const (file, XVECEXP (x, 0, 1)); | |
1668 | fputs ("-.)", file); | |
1669 | break; | |
1670 | default: | |
1671 | return false; | |
1672 | } | |
1673 | return true; | |
1674 | } | |
1675 | else | |
1676 | return false; | |
1677 | } | |
7208c779 | 1678 | \f |
5241f4ad | 1679 | /* Encode symbol attributes of a SYMBOL_REF into its |
1680 | SYMBOL_REF_FLAGS. */ | |
1681 | static void | |
1682 | sh_encode_section_info (tree decl, rtx rtl, int first) | |
1683 | { | |
1684 | default_encode_section_info (decl, rtl, first); | |
1685 | ||
1686 | if (TREE_CODE (decl) == FUNCTION_DECL | |
1687 | && sh2a_function_vector_p (decl) && TARGET_SH2A) | |
1688 | SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_FUNCVEC_FUNCTION; | |
1689 | } | |
1690 | ||
7208c779 | 1691 | /* Prepare operands for a move define_expand; specifically, one of the |
73401833 | 1692 | operands must be in a register. */ |
7141d4fc | 1693 | void |
3754d046 | 1694 | prepare_move_operands (rtx operands[], machine_mode mode) |
7208c779 | 1695 | { |
cec78553 | 1696 | if ((mode == SImode || mode == DImode) |
1697 | && flag_pic | |
1698 | && ! ((mode == Pmode || mode == ptr_mode) | |
bc620c5c | 1699 | && tls_symbolic_operand (operands[1], Pmode) != TLS_MODEL_NONE)) |
0abf894c | 1700 | { |
1701 | rtx temp; | |
1702 | if (SYMBOLIC_CONST_P (operands[1])) | |
1703 | { | |
cbb16986 | 1704 | if (MEM_P (operands[0])) |
0abf894c | 1705 | operands[1] = force_reg (Pmode, operands[1]); |
afef6540 | 1706 | else if (TARGET_SHMEDIA |
1707 | && GET_CODE (operands[1]) == LABEL_REF | |
87e19636 | 1708 | && target_reg_operand (operands[0], mode)) |
1709 | /* It's ok. */; | |
0abf894c | 1710 | else |
1711 | { | |
e1ba4a27 | 1712 | temp = (!can_create_pseudo_p () |
1713 | ? operands[0] | |
1714 | : gen_reg_rtx (Pmode)); | |
87e19636 | 1715 | operands[1] = legitimize_pic_address (operands[1], mode, temp); |
0abf894c | 1716 | } |
1717 | } | |
1718 | else if (GET_CODE (operands[1]) == CONST | |
1719 | && GET_CODE (XEXP (operands[1], 0)) == PLUS | |
1720 | && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0))) | |
1721 | { | |
e1ba4a27 | 1722 | temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode); |
0abf894c | 1723 | temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0), |
87e19636 | 1724 | mode, temp); |
1725 | operands[1] = expand_binop (mode, add_optab, temp, | |
0abf894c | 1726 | XEXP (XEXP (operands[1], 0), 1), |
e1ba4a27 | 1727 | (!can_create_pseudo_p () |
1728 | ? temp | |
1729 | : gen_reg_rtx (Pmode)), | |
6883f2aa | 1730 | 0, OPTAB_LIB_WIDEN); |
0abf894c | 1731 | } |
1732 | } | |
1733 | ||
5beb0a57 | 1734 | if (! reload_in_progress && ! reload_completed) |
1735 | { | |
1736 | /* Copy the source to a register if both operands aren't registers. */ | |
1737 | if (! register_operand (operands[0], mode) | |
0edea8ba | 1738 | && ! sh_register_operand (operands[1], mode)) |
5beb0a57 | 1739 | operands[1] = copy_to_mode_reg (mode, operands[1]); |
1740 | ||
cbb16986 | 1741 | if (MEM_P (operands[0]) && ! memory_operand (operands[0], mode)) |
7bc2d3b3 | 1742 | { |
1743 | /* This is like change_address_1 (operands[0], mode, 0, 1) , | |
1744 | except that we can't use that function because it is static. */ | |
8deb3959 | 1745 | rtx new_rtx = change_address (operands[0], mode, 0); |
1746 | MEM_COPY_ATTRIBUTES (new_rtx, operands[0]); | |
1747 | operands[0] = new_rtx; | |
7bc2d3b3 | 1748 | } |
1749 | ||
5beb0a57 | 1750 | /* This case can happen while generating code to move the result |
1751 | of a library call to the target. Reject `st r0,@(rX,rY)' because | |
1752 | reload will fail to find a spill register for rX, since r0 is already | |
1753 | being used for the source. */ | |
59312820 | 1754 | else if (TARGET_SH1 |
1755 | && refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0) | |
cbb16986 | 1756 | && MEM_P (operands[0]) |
5beb0a57 | 1757 | && GET_CODE (XEXP (operands[0], 0)) == PLUS |
cbb16986 | 1758 | && REG_P (XEXP (XEXP (operands[0], 0), 1))) |
5beb0a57 | 1759 | operands[1] = copy_to_mode_reg (mode, operands[1]); |
1760 | } | |
73401833 | 1761 | |
cec78553 | 1762 | if (mode == Pmode || mode == ptr_mode) |
1763 | { | |
330b3f36 | 1764 | rtx op0, op1, opc; |
cec78553 | 1765 | enum tls_model tls_kind; |
1766 | ||
1767 | op0 = operands[0]; | |
1768 | op1 = operands[1]; | |
330b3f36 | 1769 | if (GET_CODE (op1) == CONST |
1770 | && GET_CODE (XEXP (op1, 0)) == PLUS | |
bc620c5c | 1771 | && (tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode) |
1772 | != TLS_MODEL_NONE)) | |
330b3f36 | 1773 | { |
1774 | opc = XEXP (XEXP (op1, 0), 1); | |
1775 | op1 = XEXP (XEXP (op1, 0), 0); | |
1776 | } | |
1777 | else | |
1778 | opc = NULL_RTX; | |
1779 | ||
5ad4e904 | 1780 | if (! reload_in_progress && ! reload_completed |
1781 | && (tls_kind = tls_symbolic_operand (op1, Pmode)) != TLS_MODEL_NONE) | |
cec78553 | 1782 | { |
1783 | rtx tga_op1, tga_ret, tmp, tmp2; | |
1784 | ||
eadf7d4b | 1785 | if (! flag_pic |
1786 | && (tls_kind == TLS_MODEL_GLOBAL_DYNAMIC | |
1787 | || tls_kind == TLS_MODEL_LOCAL_DYNAMIC | |
1788 | || tls_kind == TLS_MODEL_INITIAL_EXEC)) | |
1789 | { | |
1790 | /* Don't schedule insns for getting GOT address when | |
1791 | the first scheduling is enabled, to avoid spill | |
1792 | failures for R0. */ | |
1793 | if (flag_schedule_insns) | |
1794 | emit_insn (gen_blockage ()); | |
1795 | emit_insn (gen_GOTaddr2picreg ()); | |
1796 | emit_use (gen_rtx_REG (SImode, PIC_REG)); | |
1797 | if (flag_schedule_insns) | |
1798 | emit_insn (gen_blockage ()); | |
1799 | } | |
1800 | ||
cec78553 | 1801 | switch (tls_kind) |
1802 | { | |
1803 | case TLS_MODEL_GLOBAL_DYNAMIC: | |
1804 | tga_ret = gen_rtx_REG (Pmode, R0_REG); | |
8cdd3257 | 1805 | emit_call_insn (gen_tls_global_dynamic (tga_ret, op1)); |
eadf7d4b | 1806 | tmp = gen_reg_rtx (Pmode); |
1807 | emit_move_insn (tmp, tga_ret); | |
1808 | op1 = tmp; | |
cec78553 | 1809 | break; |
1810 | ||
1811 | case TLS_MODEL_LOCAL_DYNAMIC: | |
1812 | tga_ret = gen_rtx_REG (Pmode, R0_REG); | |
8cdd3257 | 1813 | emit_call_insn (gen_tls_local_dynamic (tga_ret, op1)); |
cec78553 | 1814 | |
1815 | tmp = gen_reg_rtx (Pmode); | |
1816 | emit_move_insn (tmp, tga_ret); | |
1817 | ||
1818 | if (register_operand (op0, Pmode)) | |
1819 | tmp2 = op0; | |
1820 | else | |
1821 | tmp2 = gen_reg_rtx (Pmode); | |
1822 | ||
1823 | emit_insn (gen_symDTPOFF2reg (tmp2, op1, tmp)); | |
1824 | op1 = tmp2; | |
1825 | break; | |
1826 | ||
1827 | case TLS_MODEL_INITIAL_EXEC: | |
e1ba4a27 | 1828 | tga_op1 = !can_create_pseudo_p () ? op0 : gen_reg_rtx (Pmode); |
cec78553 | 1829 | tmp = gen_sym2GOTTPOFF (op1); |
1830 | emit_insn (gen_tls_initial_exec (tga_op1, tmp)); | |
1831 | op1 = tga_op1; | |
1832 | break; | |
1833 | ||
1834 | case TLS_MODEL_LOCAL_EXEC: | |
1835 | tmp2 = gen_reg_rtx (Pmode); | |
eaed8755 | 1836 | emit_insn (gen_store_gbr (tmp2)); |
cec78553 | 1837 | tmp = gen_reg_rtx (Pmode); |
1838 | emit_insn (gen_symTPOFF2reg (tmp, op1)); | |
cec78553 | 1839 | |
1840 | if (register_operand (op0, Pmode)) | |
1841 | op1 = op0; | |
1842 | else | |
1843 | op1 = gen_reg_rtx (Pmode); | |
1844 | ||
1845 | emit_insn (gen_addsi3 (op1, tmp, tmp2)); | |
1846 | break; | |
1847 | ||
1848 | default: | |
1a6a7a27 | 1849 | gcc_unreachable (); |
cec78553 | 1850 | } |
330b3f36 | 1851 | if (opc) |
1852 | emit_insn (gen_addsi3 (op1, op1, force_reg (SImode, opc))); | |
cec78553 | 1853 | operands[1] = op1; |
1854 | } | |
1855 | } | |
73401833 | 1856 | } |
1857 | ||
d5065e6e | 1858 | /* Implement the canonicalize_comparison target hook for the combine |
1859 | pass. For the target hook this function is invoked via | |
1860 | sh_canonicalize_comparison. This function is also re-used to | |
1861 | canonicalize comparisons in cbranch pattern expanders. */ | |
1862 | static void | |
c91d7b8a | 1863 | sh_canonicalize_comparison (enum rtx_code& cmp, rtx& op0, rtx& op1, |
3754d046 | 1864 | machine_mode mode, |
32f5fb24 | 1865 | bool op0_preserve_value) |
5be30882 | 1866 | { |
c91d7b8a | 1867 | /* When invoked from within the combine pass the mode is not specified, |
1868 | so try to get it from one of the operands. */ | |
1869 | if (mode == VOIDmode) | |
1870 | mode = GET_MODE (op0); | |
1871 | if (mode == VOIDmode) | |
1872 | mode = GET_MODE (op1); | |
1873 | ||
1874 | // We need to have a mode to do something useful here. | |
1875 | if (mode == VOIDmode) | |
1876 | return; | |
1877 | ||
1878 | // Currently, we don't deal with floats here. | |
1879 | if (GET_MODE_CLASS (mode) == MODE_FLOAT) | |
1880 | return; | |
1881 | ||
1882 | // Make sure that the constant operand is the second operand. | |
1883 | if (CONST_INT_P (op0) && !CONST_INT_P (op1)) | |
5be30882 | 1884 | { |
32f5fb24 | 1885 | if (op0_preserve_value) |
1886 | return; | |
1887 | ||
c91d7b8a | 1888 | std::swap (op0, op1); |
1889 | cmp = swap_condition (cmp); | |
5be30882 | 1890 | } |
c91d7b8a | 1891 | |
1892 | if (CONST_INT_P (op1)) | |
5be30882 | 1893 | { |
c91d7b8a | 1894 | /* Try to adjust the constant operand in such a way that available |
6c049e03 | 1895 | comparison insns can be utilized better and the constant can be |
1896 | loaded with a 'mov #imm,Rm' insn. This avoids a load from the | |
1897 | constant pool. */ | |
c91d7b8a | 1898 | const HOST_WIDE_INT val = INTVAL (op1); |
1899 | ||
1900 | /* x > -1 --> x >= 0 | |
1901 | x > 0xFFFFFF7F --> x >= 0xFFFFFF80 | |
1902 | x <= -1 --> x < 0 | |
1903 | x <= 0xFFFFFF7F --> x < 0xFFFFFF80 */ | |
1904 | if ((val == -1 || val == -0x81) && (cmp == GT || cmp == LE)) | |
1905 | { | |
1906 | cmp = cmp == GT ? GE : LT; | |
1907 | op1 = gen_int_mode (val + 1, mode); | |
1908 | } | |
1909 | ||
1910 | /* x >= 1 --> x > 0 | |
1911 | x >= 0x80 --> x > 0x7F | |
1912 | x < 1 --> x <= 0 | |
1913 | x < 0x80 --> x <= 0x7F */ | |
1914 | else if ((val == 1 || val == 0x80) && (cmp == GE || cmp == LT)) | |
5be30882 | 1915 | { |
c91d7b8a | 1916 | cmp = cmp == GE ? GT : LE; |
1917 | op1 = gen_int_mode (val - 1, mode); | |
5be30882 | 1918 | } |
c91d7b8a | 1919 | |
1920 | /* unsigned x >= 1 --> x != 0 | |
1921 | unsigned x < 1 --> x == 0 */ | |
1922 | else if (val == 1 && (cmp == GEU || cmp == LTU)) | |
5be30882 | 1923 | { |
c91d7b8a | 1924 | cmp = cmp == GEU ? NE : EQ; |
1925 | op1 = CONST0_RTX (mode); | |
5be30882 | 1926 | } |
c91d7b8a | 1927 | |
1928 | /* unsigned x >= 0x80 --> unsigned x > 0x7F | |
1929 | unsigned x < 0x80 --> unsigned x < 0x7F */ | |
1930 | else if (val == 0x80 && (cmp == GEU || cmp == LTU)) | |
5be30882 | 1931 | { |
c91d7b8a | 1932 | cmp = cmp == GEU ? GTU : LEU; |
1933 | op1 = gen_int_mode (val - 1, mode); | |
5be30882 | 1934 | } |
c91d7b8a | 1935 | |
1936 | /* unsigned x > 0 --> x != 0 | |
1937 | unsigned x <= 0 --> x == 0 */ | |
1938 | else if (val == 0 && (cmp == GTU || cmp == LEU)) | |
1939 | cmp = cmp == GTU ? NE : EQ; | |
1940 | ||
1941 | /* unsigned x > 0x7FFFFFFF --> signed x < 0 | |
1942 | unsigned x <= 0x7FFFFFFF --> signed x >= 0 */ | |
1943 | else if (mode == SImode && (cmp == GTU || cmp == LEU) | |
1944 | && val == 0x7FFFFFFF) | |
5be30882 | 1945 | { |
c91d7b8a | 1946 | cmp = cmp == GTU ? LT : GE; |
1947 | op1 = const0_rtx; | |
5be30882 | 1948 | } |
c91d7b8a | 1949 | |
1950 | /* unsigned x >= 0x80000000 --> signed x < 0 | |
1951 | unsigned x < 0x80000000 --> signed x >= 0 */ | |
1952 | else if (mode == SImode && (cmp == GEU || cmp == LTU) | |
1953 | && (unsigned HOST_WIDE_INT)val | |
1954 | == ((unsigned HOST_WIDE_INT)0x7FFFFFFF + 1)) | |
5be30882 | 1955 | { |
c91d7b8a | 1956 | cmp = cmp == GEU ? LT : GE; |
1957 | op1 = const0_rtx; | |
5be30882 | 1958 | } |
1959 | } | |
c91d7b8a | 1960 | } |
1961 | ||
d5065e6e | 1962 | /* This function implements the canonicalize_comparison target hook. |
1963 | This wrapper around the internally used sh_canonicalize_comparison | |
1964 | function is needed to do the enum rtx_code <-> int conversion. | |
1965 | Target hooks cannot use enum rtx_code in its definition. */ | |
1966 | static void | |
1967 | sh_canonicalize_comparison (int *code, rtx *op0, rtx *op1, | |
1968 | bool op0_preserve_value) | |
1969 | { | |
1970 | enum rtx_code tmp_code = (enum rtx_code)*code; | |
1971 | sh_canonicalize_comparison (tmp_code, *op0, *op1, | |
1972 | VOIDmode, op0_preserve_value); | |
1973 | *code = (int)tmp_code; | |
1974 | } | |
6c049e03 | 1975 | |
32f5fb24 | 1976 | bool |
1977 | sh_fixed_condition_code_regs (unsigned int* p1, unsigned int* p2) | |
1978 | { | |
1979 | *p1 = T_REG; | |
1980 | *p2 = INVALID_REGNUM; | |
1981 | return true; | |
1982 | } | |
1983 | ||
c91d7b8a | 1984 | enum rtx_code |
3754d046 | 1985 | prepare_cbranch_operands (rtx *operands, machine_mode mode, |
c91d7b8a | 1986 | enum rtx_code comparison) |
1987 | { | |
1988 | /* The scratch reg is only available when this is invoked from within | |
1989 | the cbranchdi4_i splitter, through expand_cbranchdi4. */ | |
1990 | rtx scratch = NULL_RTX; | |
1991 | ||
1992 | if (comparison == LAST_AND_UNUSED_RTX_CODE) | |
1993 | comparison = GET_CODE (operands[0]); | |
1994 | else | |
1995 | scratch = operands[4]; | |
1996 | ||
d5065e6e | 1997 | sh_canonicalize_comparison (comparison, operands[1], operands[2], |
1998 | mode, false); | |
c91d7b8a | 1999 | |
2000 | /* Notice that this function is also invoked after reload by | |
2001 | the cbranchdi4_i pattern, through expand_cbranchdi4. */ | |
2002 | rtx op1 = operands[1]; | |
2003 | ||
e1ba4a27 | 2004 | if (can_create_pseudo_p ()) |
5be30882 | 2005 | operands[1] = force_reg (mode, op1); |
2006 | /* When we are handling DImode comparisons, we want to keep constants so | |
2007 | that we can optimize the component comparisons; however, memory loads | |
2008 | are better issued as a whole so that they can be scheduled well. | |
2009 | SImode equality comparisons allow I08 constants, but only when they | |
2010 | compare r0. Hence, if operands[1] has to be loaded from somewhere else | |
2011 | into a register, that register might as well be r0, and we allow the | |
2012 | constant. If it is already in a register, this is likely to be | |
fa7637bd | 2013 | allocated to a different hard register, thus we load the constant into |
5be30882 | 2014 | a register unless it is zero. */ |
2015 | if (!REG_P (operands[2]) | |
cbb16986 | 2016 | && (!CONST_INT_P (operands[2]) |
5be30882 | 2017 | || (mode == SImode && operands[2] != CONST0_RTX (SImode) |
2018 | && ((comparison != EQ && comparison != NE) | |
2019 | || (REG_P (op1) && REGNO (op1) != R0_REG) | |
abff7a2e | 2020 | || !satisfies_constraint_I08 (operands[2]))))) |
5be30882 | 2021 | { |
2022 | if (scratch && GET_MODE (scratch) == mode) | |
2023 | { | |
2024 | emit_move_insn (scratch, operands[2]); | |
2025 | operands[2] = scratch; | |
2026 | } | |
e1ba4a27 | 2027 | else if (can_create_pseudo_p ()) |
5be30882 | 2028 | operands[2] = force_reg (mode, operands[2]); |
2029 | } | |
2030 | return comparison; | |
2031 | } | |
2032 | ||
2033 | void | |
2034 | expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int probability) | |
2035 | { | |
21910658 | 2036 | rtx (*branch_expander) (rtx) = gen_branch_true; |
5be30882 | 2037 | comparison = prepare_cbranch_operands (operands, SImode, comparison); |
2038 | switch (comparison) | |
2039 | { | |
2040 | case NE: case LT: case LE: case LTU: case LEU: | |
2041 | comparison = reverse_condition (comparison); | |
2042 | branch_expander = gen_branch_false; | |
2043 | default: ; | |
2044 | } | |
3ba0d068 | 2045 | emit_insn (gen_rtx_SET (VOIDmode, get_t_reg_rtx (), |
6c049e03 | 2046 | gen_rtx_fmt_ee (comparison, SImode, |
2047 | operands[1], operands[2]))); | |
b82334f7 | 2048 | rtx_insn *jump = emit_jump_insn (branch_expander (operands[3])); |
5be30882 | 2049 | if (probability >= 0) |
9eb946de | 2050 | add_int_reg_note (jump, REG_BR_PROB, probability); |
5be30882 | 2051 | } |
2052 | ||
2053 | /* ??? How should we distribute probabilities when more than one branch | |
7a288fec | 2054 | is generated. So far we only have some ad-hoc observations: |
5be30882 | 2055 | - If the operands are random, they are likely to differ in both parts. |
2056 | - If comparing items in a hash chain, the operands are random or equal; | |
2057 | operation should be EQ or NE. | |
2058 | - If items are searched in an ordered tree from the root, we can expect | |
2059 | the highpart to be unequal about half of the time; operation should be | |
fa7637bd | 2060 | an inequality comparison, operands non-constant, and overall probability |
5be30882 | 2061 | about 50%. Likewise for quicksort. |
2062 | - Range checks will be often made against constants. Even if we assume for | |
2063 | simplicity an even distribution of the non-constant operand over a | |
2064 | sub-range here, the same probability could be generated with differently | |
2065 | wide sub-ranges - as long as the ratio of the part of the subrange that | |
2066 | is before the threshold to the part that comes after the threshold stays | |
2067 | the same. Thus, we can't really tell anything here; | |
2068 | assuming random distribution is at least simple. | |
2069 | */ | |
5be30882 | 2070 | bool |
2071 | expand_cbranchdi4 (rtx *operands, enum rtx_code comparison) | |
2072 | { | |
2073 | enum rtx_code msw_taken, msw_skip, lsw_taken; | |
b82334f7 | 2074 | rtx_code_label *skip_label = NULL; |
5be30882 | 2075 | rtx op1h, op1l, op2h, op2l; |
2076 | int num_branches; | |
2077 | int prob, rev_prob; | |
2078 | int msw_taken_prob = -1, msw_skip_prob = -1, lsw_taken_prob = -1; | |
feb80442 | 2079 | rtx scratch = operands[4]; |
5be30882 | 2080 | |
2081 | comparison = prepare_cbranch_operands (operands, DImode, comparison); | |
2082 | op1h = gen_highpart_mode (SImode, DImode, operands[1]); | |
2083 | op2h = gen_highpart_mode (SImode, DImode, operands[2]); | |
2084 | op1l = gen_lowpart (SImode, operands[1]); | |
2085 | op2l = gen_lowpart (SImode, operands[2]); | |
6f2543f8 | 2086 | msw_taken = msw_skip = lsw_taken = LAST_AND_UNUSED_RTX_CODE; |
5be30882 | 2087 | prob = split_branch_probability; |
2088 | rev_prob = REG_BR_PROB_BASE - prob; | |
2089 | switch (comparison) | |
2090 | { | |
2091 | /* ??? Should we use the cmpeqdi_t pattern for equality comparisons? | |
2092 | That costs 1 cycle more when the first branch can be predicted taken, | |
2093 | but saves us mispredicts because only one branch needs prediction. | |
2094 | It also enables generating the cmpeqdi_t-1 pattern. */ | |
2095 | case EQ: | |
2096 | if (TARGET_CMPEQDI_T) | |
2097 | { | |
2098 | emit_insn (gen_cmpeqdi_t (operands[1], operands[2])); | |
21910658 | 2099 | emit_jump_insn (gen_branch_true (operands[3])); |
5be30882 | 2100 | return true; |
2101 | } | |
2102 | msw_skip = NE; | |
2103 | lsw_taken = EQ; | |
2104 | if (prob >= 0) | |
2105 | { | |
c91d7b8a | 2106 | // If we had more precision, we'd use rev_prob - (rev_prob >> 32) . |
5be30882 | 2107 | msw_skip_prob = rev_prob; |
2108 | if (REG_BR_PROB_BASE <= 65535) | |
2109 | lsw_taken_prob = prob ? REG_BR_PROB_BASE : 0; | |
2110 | else | |
2111 | { | |
5be30882 | 2112 | lsw_taken_prob |
2113 | = (prob | |
2114 | ? (REG_BR_PROB_BASE | |
3a4303e7 | 2115 | - ((gcov_type) REG_BR_PROB_BASE * rev_prob |
2116 | / ((gcov_type) prob << 32))) | |
5be30882 | 2117 | : 0); |
2118 | } | |
2119 | } | |
2120 | break; | |
2121 | case NE: | |
2122 | if (TARGET_CMPEQDI_T) | |
2123 | { | |
2124 | emit_insn (gen_cmpeqdi_t (operands[1], operands[2])); | |
21910658 | 2125 | emit_jump_insn (gen_branch_false (operands[3])); |
5be30882 | 2126 | return true; |
2127 | } | |
2128 | msw_taken = NE; | |
feb80442 | 2129 | msw_taken_prob = prob; |
5be30882 | 2130 | lsw_taken = NE; |
2131 | lsw_taken_prob = 0; | |
2132 | break; | |
2133 | case GTU: case GT: | |
2134 | msw_taken = comparison; | |
cbb16986 | 2135 | if (CONST_INT_P (op2l) && INTVAL (op2l) == -1) |
5be30882 | 2136 | break; |
2137 | if (comparison != GTU || op2h != CONST0_RTX (SImode)) | |
2138 | msw_skip = swap_condition (msw_taken); | |
2139 | lsw_taken = GTU; | |
2140 | break; | |
2141 | case GEU: case GE: | |
2142 | if (op2l == CONST0_RTX (SImode)) | |
2143 | msw_taken = comparison; | |
2144 | else | |
2145 | { | |
2146 | msw_taken = comparison == GE ? GT : GTU; | |
2147 | msw_skip = swap_condition (msw_taken); | |
2148 | lsw_taken = GEU; | |
2149 | } | |
2150 | break; | |
2151 | case LTU: case LT: | |
2152 | msw_taken = comparison; | |
2153 | if (op2l == CONST0_RTX (SImode)) | |
2154 | break; | |
2155 | msw_skip = swap_condition (msw_taken); | |
2156 | lsw_taken = LTU; | |
2157 | break; | |
2158 | case LEU: case LE: | |
cbb16986 | 2159 | if (CONST_INT_P (op2l) && INTVAL (op2l) == -1) |
5be30882 | 2160 | msw_taken = comparison; |
2161 | else | |
2162 | { | |
2163 | lsw_taken = LEU; | |
2164 | if (comparison == LE) | |
2165 | msw_taken = LT; | |
2166 | else if (op2h != CONST0_RTX (SImode)) | |
2167 | msw_taken = LTU; | |
2168 | else | |
35e3c1ad | 2169 | { |
2170 | msw_skip = swap_condition (LTU); | |
2171 | break; | |
2172 | } | |
5be30882 | 2173 | msw_skip = swap_condition (msw_taken); |
2174 | } | |
2175 | break; | |
2176 | default: return false; | |
2177 | } | |
6f2543f8 | 2178 | num_branches = ((msw_taken != LAST_AND_UNUSED_RTX_CODE) |
2179 | + (msw_skip != LAST_AND_UNUSED_RTX_CODE) | |
2180 | + (lsw_taken != LAST_AND_UNUSED_RTX_CODE)); | |
5be30882 | 2181 | if (comparison != EQ && comparison != NE && num_branches > 1) |
2182 | { | |
2183 | if (!CONSTANT_P (operands[2]) | |
2184 | && prob >= (int) (REG_BR_PROB_BASE * 3 / 8U) | |
2185 | && prob <= (int) (REG_BR_PROB_BASE * 5 / 8U)) | |
2186 | { | |
2187 | msw_taken_prob = prob / 2U; | |
2188 | msw_skip_prob | |
2189 | = REG_BR_PROB_BASE * rev_prob / (REG_BR_PROB_BASE + rev_prob); | |
2190 | lsw_taken_prob = prob; | |
2191 | } | |
2192 | else | |
2193 | { | |
2194 | msw_taken_prob = prob; | |
2195 | msw_skip_prob = REG_BR_PROB_BASE; | |
2196 | /* ??? If we have a constant op2h, should we use that when | |
2197 | calculating lsw_taken_prob? */ | |
2198 | lsw_taken_prob = prob; | |
2199 | } | |
2200 | } | |
2201 | operands[1] = op1h; | |
2202 | operands[2] = op2h; | |
2203 | operands[4] = NULL_RTX; | |
feb80442 | 2204 | if (reload_completed |
79c09794 | 2205 | && ! arith_reg_or_0_operand (op2h, SImode) |
2206 | && (true_regnum (op1h) || (comparison != EQ && comparison != NE)) | |
6f2543f8 | 2207 | && (msw_taken != LAST_AND_UNUSED_RTX_CODE |
2208 | || msw_skip != LAST_AND_UNUSED_RTX_CODE)) | |
feb80442 | 2209 | { |
2210 | emit_move_insn (scratch, operands[2]); | |
2211 | operands[2] = scratch; | |
2212 | } | |
6f2543f8 | 2213 | if (msw_taken != LAST_AND_UNUSED_RTX_CODE) |
5be30882 | 2214 | expand_cbranchsi4 (operands, msw_taken, msw_taken_prob); |
6f2543f8 | 2215 | if (msw_skip != LAST_AND_UNUSED_RTX_CODE) |
5be30882 | 2216 | { |
2217 | rtx taken_label = operands[3]; | |
2218 | ||
9037a84c | 2219 | /* Operands were possibly modified, but msw_skip doesn't expect this. |
2220 | Always use the original ones. */ | |
6f2543f8 | 2221 | if (msw_taken != LAST_AND_UNUSED_RTX_CODE) |
9037a84c | 2222 | { |
2223 | operands[1] = op1h; | |
2224 | operands[2] = op2h; | |
73e5edb6 | 2225 | if (reload_completed |
2226 | && ! arith_reg_or_0_operand (op2h, SImode) | |
2227 | && (true_regnum (op1h) || (comparison != EQ && comparison != NE))) | |
2228 | { | |
2229 | emit_move_insn (scratch, operands[2]); | |
2230 | operands[2] = scratch; | |
2231 | } | |
9037a84c | 2232 | } |
2233 | ||
5be30882 | 2234 | operands[3] = skip_label = gen_label_rtx (); |
2235 | expand_cbranchsi4 (operands, msw_skip, msw_skip_prob); | |
2236 | operands[3] = taken_label; | |
2237 | } | |
2238 | operands[1] = op1l; | |
2239 | operands[2] = op2l; | |
6f2543f8 | 2240 | if (lsw_taken != LAST_AND_UNUSED_RTX_CODE) |
feb80442 | 2241 | { |
2242 | if (reload_completed | |
79c09794 | 2243 | && ! arith_reg_or_0_operand (op2l, SImode) |
2244 | && (true_regnum (op1l) || (lsw_taken != EQ && lsw_taken != NE))) | |
2245 | { | |
2246 | emit_move_insn (scratch, operands[2]); | |
2247 | operands[2] = scratch; | |
2248 | } | |
feb80442 | 2249 | expand_cbranchsi4 (operands, lsw_taken, lsw_taken_prob); |
2250 | } | |
6f2543f8 | 2251 | if (msw_skip != LAST_AND_UNUSED_RTX_CODE) |
5be30882 | 2252 | emit_label (skip_label); |
2253 | return true; | |
2254 | } | |
2255 | ||
21910658 | 2256 | /* Given an operand, return 1 if the evaluated operand plugged into an |
2257 | if_then_else will result in a branch_true, 0 if branch_false, or | |
2258 | -1 if neither nor applies. The truth table goes like this: | |
2259 | ||
2260 | op | cmpval | code | result | |
2261 | ---------+--------+---------+-------------------- | |
2262 | T (0) | 0 | EQ (1) | 0 = 0 ^ (0 == 1) | |
2263 | T (0) | 1 | EQ (1) | 1 = 0 ^ (1 == 1) | |
2264 | T (0) | 0 | NE (0) | 1 = 0 ^ (0 == 0) | |
2265 | T (0) | 1 | NE (0) | 0 = 0 ^ (1 == 0) | |
2266 | !T (1) | 0 | EQ (1) | 1 = 1 ^ (0 == 1) | |
2267 | !T (1) | 1 | EQ (1) | 0 = 1 ^ (1 == 1) | |
2268 | !T (1) | 0 | NE (0) | 0 = 1 ^ (0 == 0) | |
2269 | !T (1) | 1 | NE (0) | 1 = 1 ^ (1 == 0) */ | |
2270 | int | |
2271 | sh_eval_treg_value (rtx op) | |
2272 | { | |
a02ddf20 | 2273 | if (t_reg_operand (op, GET_MODE (op))) |
2274 | return 1; | |
2275 | if (negt_reg_operand (op, GET_MODE (op))) | |
2276 | return 0; | |
2277 | ||
2278 | rtx_code code = GET_CODE (op); | |
21910658 | 2279 | if ((code != EQ && code != NE) || !CONST_INT_P (XEXP (op, 1))) |
2280 | return -1; | |
2281 | ||
2282 | int cmpop = code == EQ ? 1 : 0; | |
2283 | int cmpval = INTVAL (XEXP (op, 1)); | |
2284 | if (cmpval != 0 && cmpval != 1) | |
2285 | return -1; | |
2286 | ||
2287 | int t; | |
2288 | if (t_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))) | |
2289 | t = 0; | |
2290 | else if (negt_reg_operand (XEXP (op, 0), GET_MODE (XEXP (op, 0)))) | |
2291 | t = 1; | |
2292 | else | |
2293 | return -1; | |
2294 | ||
2295 | return t ^ (cmpval == cmpop); | |
2296 | } | |
2297 | ||
b0fa59a9 | 2298 | /* Emit INSN, possibly in a PARALLEL with an USE/CLOBBER of FPSCR bits in case |
2299 | of floating-point comparisons. */ | |
74f4459c | 2300 | static void |
3754d046 | 2301 | sh_emit_set_t_insn (rtx insn, machine_mode mode) |
74f4459c | 2302 | { |
b0fa59a9 | 2303 | if (TARGET_FPU_ANY && GET_MODE_CLASS (mode) == MODE_FLOAT |
2304 | && GET_CODE (insn) != PARALLEL) | |
74f4459c | 2305 | { |
2306 | insn = gen_rtx_PARALLEL (VOIDmode, | |
b0fa59a9 | 2307 | gen_rtvec (3, insn, |
2308 | gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, FPSCR_STAT_REG)), | |
2309 | gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FPSCR_MODES_REG)))); | |
74f4459c | 2310 | } |
b0fa59a9 | 2311 | emit_insn (insn); |
74f4459c | 2312 | } |
2313 | ||
73401833 | 2314 | /* Prepare the operands for an scc instruction; make sure that the |
74f4459c | 2315 | compare has been done and the result is in T_REG. */ |
2316 | void | |
2317 | sh_emit_scc_to_t (enum rtx_code code, rtx op0, rtx op1) | |
73401833 | 2318 | { |
3ba0d068 | 2319 | rtx t_reg = get_t_reg_rtx (); |
73401833 | 2320 | enum rtx_code oldcode = code; |
3754d046 | 2321 | machine_mode mode; |
73401833 | 2322 | |
2323 | /* First need a compare insn. */ | |
2324 | switch (code) | |
7208c779 | 2325 | { |
73401833 | 2326 | case NE: |
2327 | /* It isn't possible to handle this case. */ | |
1a6a7a27 | 2328 | gcc_unreachable (); |
73401833 | 2329 | case LT: |
2330 | code = GT; | |
2331 | break; | |
2332 | case LE: | |
2333 | code = GE; | |
2334 | break; | |
2335 | case LTU: | |
2336 | code = GTU; | |
2337 | break; | |
2338 | case LEU: | |
2339 | code = GEU; | |
2340 | break; | |
7984f145 | 2341 | default: |
2342 | break; | |
7208c779 | 2343 | } |
73401833 | 2344 | if (code != oldcode) |
47c009e5 | 2345 | { |
74f4459c | 2346 | rtx tmp = op0; |
2347 | op0 = op1; | |
2348 | op1 = tmp; | |
97595bfd | 2349 | } |
47c009e5 | 2350 | |
74f4459c | 2351 | mode = GET_MODE (op0); |
e9646547 | 2352 | if (mode == VOIDmode) |
74f4459c | 2353 | mode = GET_MODE (op1); |
e9646547 | 2354 | |
74f4459c | 2355 | op0 = force_reg (mode, op0); |
8ded0752 | 2356 | if ((code != EQ && code != NE |
74f4459c | 2357 | && (op1 != const0_rtx |
8ded0752 | 2358 | || code == GTU || code == GEU || code == LTU || code == LEU)) |
74f4459c | 2359 | || (mode == DImode && op1 != const0_rtx) |
87ed74ef | 2360 | || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)) |
74f4459c | 2361 | op1 = force_reg (mode, op1); |
97595bfd | 2362 | |
74f4459c | 2363 | sh_emit_set_t_insn (gen_rtx_SET (VOIDmode, t_reg, |
2364 | gen_rtx_fmt_ee (code, SImode, op0, op1)), | |
2365 | mode); | |
2366 | } | |
97595bfd | 2367 | |
74f4459c | 2368 | rtx |
3754d046 | 2369 | sh_emit_cheap_store_flag (machine_mode mode, enum rtx_code code, |
74f4459c | 2370 | rtx op0, rtx op1) |
2371 | { | |
2372 | rtx target = gen_reg_rtx (SImode); | |
2373 | rtx tmp; | |
2374 | ||
2375 | gcc_assert (TARGET_SHMEDIA); | |
2376 | switch (code) | |
2377 | { | |
2378 | case EQ: | |
2379 | case GT: | |
2380 | case LT: | |
2381 | case UNORDERED: | |
2382 | case GTU: | |
2383 | case LTU: | |
2384 | tmp = gen_rtx_fmt_ee (code, SImode, op0, op1); | |
2385 | emit_insn (gen_cstore4_media (target, tmp, op0, op1)); | |
2386 | code = NE; | |
2387 | break; | |
2388 | ||
2389 | case NE: | |
2390 | case GE: | |
2391 | case LE: | |
2392 | case ORDERED: | |
2393 | case GEU: | |
2394 | case LEU: | |
2395 | tmp = gen_rtx_fmt_ee (reverse_condition (code), mode, op0, op1); | |
2396 | emit_insn (gen_cstore4_media (target, tmp, op0, op1)); | |
2397 | code = EQ; | |
2398 | break; | |
2399 | ||
2400 | case UNEQ: | |
2401 | case UNGE: | |
2402 | case UNGT: | |
2403 | case UNLE: | |
2404 | case UNLT: | |
2405 | case LTGT: | |
2406 | return NULL_RTX; | |
2407 | ||
2408 | default: | |
2409 | gcc_unreachable (); | |
2410 | } | |
2411 | ||
2412 | if (mode == DImode) | |
2413 | { | |
2414 | rtx t2 = gen_reg_rtx (DImode); | |
2415 | emit_insn (gen_extendsidi2 (t2, target)); | |
2416 | target = t2; | |
2417 | } | |
2418 | ||
2419 | return gen_rtx_fmt_ee (code, VOIDmode, target, const0_rtx); | |
7208c779 | 2420 | } |
2421 | ||
73401833 | 2422 | /* Called from the md file, set up the operands of a compare instruction. */ |
73401833 | 2423 | void |
3754d046 | 2424 | sh_emit_compare_and_branch (rtx *operands, machine_mode mode) |
7208c779 | 2425 | { |
74f4459c | 2426 | enum rtx_code code = GET_CODE (operands[0]); |
2427 | enum rtx_code branch_code; | |
2428 | rtx op0 = operands[1]; | |
2429 | rtx op1 = operands[2]; | |
2430 | rtx insn, tem; | |
2431 | bool need_ccmpeq = false; | |
2432 | ||
2433 | if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT) | |
7208c779 | 2434 | { |
74f4459c | 2435 | op0 = force_reg (mode, op0); |
2436 | op1 = force_reg (mode, op1); | |
7208c779 | 2437 | } |
74f4459c | 2438 | else |
8ded0752 | 2439 | { |
74f4459c | 2440 | if (code != EQ || mode == DImode) |
6c049e03 | 2441 | { |
2442 | /* Force args into regs, since we can't use constants here. */ | |
2443 | op0 = force_reg (mode, op0); | |
2444 | if (op1 != const0_rtx || code == GTU || code == GEU) | |
74f4459c | 2445 | op1 = force_reg (mode, op1); |
2446 | } | |
8ded0752 | 2447 | } |
74f4459c | 2448 | |
2449 | if (GET_MODE_CLASS (mode) == MODE_FLOAT) | |
2450 | { | |
2451 | if (code == LT | |
2452 | || (code == LE && TARGET_IEEE && TARGET_SH2E) | |
2453 | || (code == GE && !(TARGET_IEEE && TARGET_SH2E))) | |
2454 | { | |
2455 | tem = op0, op0 = op1, op1 = tem; | |
2456 | code = swap_condition (code); | |
2457 | } | |
2458 | ||
2459 | /* GE becomes fcmp/gt+fcmp/eq, for SH2E and TARGET_IEEE only. */ | |
2460 | if (code == GE) | |
2461 | { | |
2462 | gcc_assert (TARGET_IEEE && TARGET_SH2E); | |
6c049e03 | 2463 | need_ccmpeq = true; |
74f4459c | 2464 | code = GT; |
2465 | } | |
2466 | ||
2467 | /* Now we can have EQ, NE, GT, LE. NE and LE are then transformed | |
2468 | to EQ/GT respectively. */ | |
2469 | gcc_assert (code == EQ || code == GT || code == NE || code == LE); | |
2470 | } | |
2471 | ||
2472 | switch (code) | |
2473 | { | |
2474 | case EQ: | |
2475 | case GT: | |
2476 | case GE: | |
2477 | case GTU: | |
2478 | case GEU: | |
2479 | branch_code = code; | |
2480 | break; | |
2481 | case NE: | |
2482 | case LT: | |
2483 | case LE: | |
2484 | case LTU: | |
2485 | case LEU: | |
2486 | branch_code = reverse_condition (code); | |
2487 | break; | |
2488 | default: | |
2489 | gcc_unreachable (); | |
2490 | } | |
2491 | ||
2492 | insn = gen_rtx_SET (VOIDmode, | |
3ba0d068 | 2493 | get_t_reg_rtx (), |
74f4459c | 2494 | gen_rtx_fmt_ee (branch_code, SImode, op0, op1)); |
2495 | ||
2496 | sh_emit_set_t_insn (insn, mode); | |
2497 | if (need_ccmpeq) | |
2498 | sh_emit_set_t_insn (gen_ieee_ccmpeqsf_t (op0, op1), mode); | |
2499 | ||
2500 | if (branch_code == code) | |
21910658 | 2501 | emit_jump_insn (gen_branch_true (operands[3])); |
8ded0752 | 2502 | else |
21910658 | 2503 | emit_jump_insn (gen_branch_false (operands[3])); |
74f4459c | 2504 | } |
2505 | ||
2506 | void | |
3754d046 | 2507 | sh_emit_compare_and_set (rtx *operands, machine_mode mode) |
74f4459c | 2508 | { |
2509 | enum rtx_code code = GET_CODE (operands[1]); | |
2510 | rtx op0 = operands[2]; | |
2511 | rtx op1 = operands[3]; | |
b82334f7 | 2512 | rtx_code_label *lab = NULL; |
74f4459c | 2513 | bool invert = false; |
2514 | rtx tem; | |
2515 | ||
2516 | op0 = force_reg (mode, op0); | |
2517 | if ((code != EQ && code != NE | |
2518 | && (op1 != const0_rtx | |
2519 | || code == GTU || code == GEU || code == LTU || code == LEU)) | |
2520 | || (mode == DImode && op1 != const0_rtx) | |
2521 | || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT)) | |
2522 | op1 = force_reg (mode, op1); | |
2523 | ||
2524 | if (GET_MODE_CLASS (mode) == MODE_FLOAT) | |
1b61190c | 2525 | { |
74f4459c | 2526 | if (code == LT || code == LE) |
2527 | { | |
2528 | code = swap_condition (code); | |
2529 | tem = op0, op0 = op1, op1 = tem; | |
2530 | } | |
2531 | if (code == GE) | |
6c049e03 | 2532 | { |
2533 | if (TARGET_IEEE) | |
2534 | { | |
2535 | lab = gen_label_rtx (); | |
2536 | sh_emit_scc_to_t (EQ, op0, op1); | |
2537 | emit_jump_insn (gen_branch_true (lab)); | |
2538 | code = GT; | |
2539 | } | |
2540 | else | |
2541 | { | |
2542 | code = LT; | |
2543 | invert = true; | |
74f4459c | 2544 | } |
6c049e03 | 2545 | } |
1b61190c | 2546 | } |
74f4459c | 2547 | |
2548 | if (code == NE) | |
2549 | { | |
2550 | code = EQ; | |
2551 | invert = true; | |
2552 | } | |
2553 | ||
2554 | sh_emit_scc_to_t (code, op0, op1); | |
2555 | if (lab) | |
2556 | emit_label (lab); | |
2557 | if (invert) | |
3ba0d068 | 2558 | emit_insn (gen_movnegt (operands[0], get_t_reg_rtx ())); |
1b61190c | 2559 | else |
3ba0d068 | 2560 | emit_move_insn (operands[0], get_t_reg_rtx ()); |
7208c779 | 2561 | } |
2562 | \f | |
1504eb7e | 2563 | /* Functions to output assembly code. */ |
7208c779 | 2564 | |
47c009e5 | 2565 | /* Return a sequence of instructions to perform DI or DF move. |
7208c779 | 2566 | |
47c009e5 | 2567 | Since the SH cannot move a DI or DF in one instruction, we have |
1504eb7e | 2568 | to take care when we see overlapping source and dest registers. */ |
b7dbbdb2 | 2569 | const char * |
04f04b72 | 2570 | output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[], |
3754d046 | 2571 | machine_mode mode) |
7208c779 | 2572 | { |
47c009e5 | 2573 | rtx dst = operands[0]; |
2574 | rtx src = operands[1]; | |
47c009e5 | 2575 | |
cbb16986 | 2576 | if (MEM_P (dst) |
1504eb7e | 2577 | && GET_CODE (XEXP (dst, 0)) == PRE_DEC) |
10bb497e | 2578 | return "mov.l %T1,%0" "\n" |
2579 | " mov.l %1,%0"; | |
73401833 | 2580 | |
47c009e5 | 2581 | if (register_operand (dst, mode) |
2582 | && register_operand (src, mode)) | |
7208c779 | 2583 | { |
47c009e5 | 2584 | if (REGNO (src) == MACH_REG) |
10bb497e | 2585 | return "sts mach,%S0" "\n" |
2586 | " sts macl,%R0"; | |
7208c779 | 2587 | |
73401833 | 2588 | /* When mov.d r1,r2 do r2->r3 then r1->r2; |
2589 | when mov.d r1,r0 do r1->r0 then r2->r1. */ | |
47c009e5 | 2590 | if (REGNO (src) + 1 == REGNO (dst)) |
10bb497e | 2591 | return "mov %T1,%T0" "\n" |
2592 | " mov %1,%0"; | |
47c009e5 | 2593 | else |
10bb497e | 2594 | return "mov %1,%0" "\n" |
2595 | " mov %T1,%T0"; | |
47c009e5 | 2596 | } |
cbb16986 | 2597 | else if (CONST_INT_P (src)) |
7208c779 | 2598 | { |
73401833 | 2599 | if (INTVAL (src) < 0) |
2600 | output_asm_insn ("mov #-1,%S0", operands); | |
7208c779 | 2601 | else |
73401833 | 2602 | output_asm_insn ("mov #0,%S0", operands); |
7208c779 | 2603 | |
73401833 | 2604 | return "mov %1,%R0"; |
97595bfd | 2605 | } |
cbb16986 | 2606 | else if (MEM_P (src)) |
7208c779 | 2607 | { |
73401833 | 2608 | int ptrreg = -1; |
47c009e5 | 2609 | int dreg = REGNO (dst); |
2610 | rtx inside = XEXP (src, 0); | |
7208c779 | 2611 | |
1a6a7a27 | 2612 | switch (GET_CODE (inside)) |
7208c779 | 2613 | { |
1a6a7a27 | 2614 | case REG: |
2615 | ptrreg = REGNO (inside); | |
2616 | break; | |
2617 | ||
2618 | case SUBREG: | |
2619 | ptrreg = subreg_regno (inside); | |
2620 | break; | |
2621 | ||
2622 | case PLUS: | |
73401833 | 2623 | ptrreg = REGNO (XEXP (inside, 0)); |
2624 | /* ??? A r0+REG address shouldn't be possible here, because it isn't | |
2625 | an offsettable address. Unfortunately, offsettable addresses use | |
2626 | QImode to check the offset, and a QImode offsettable address | |
2627 | requires r0 for the other operand, which is not currently | |
2628 | supported, so we can't use the 'o' constraint. | |
2629 | Thus we must check for and handle r0+REG addresses here. | |
2630 | We punt for now, since this is likely very rare. */ | |
cbb16986 | 2631 | gcc_assert (!REG_P (XEXP (inside, 1))); |
1a6a7a27 | 2632 | break; |
2633 | ||
2634 | case LABEL_REF: | |
10bb497e | 2635 | return "mov.l %1,%0" "\n" |
2636 | " mov.l %1+4,%T0"; | |
1a6a7a27 | 2637 | case POST_INC: |
10bb497e | 2638 | return "mov.l %1,%0" "\n" |
2639 | " mov.l %1,%T0"; | |
1a6a7a27 | 2640 | default: |
2641 | gcc_unreachable (); | |
7208c779 | 2642 | } |
7208c779 | 2643 | |
73401833 | 2644 | /* Work out the safe way to copy. Copy into the second half first. */ |
2645 | if (dreg == ptrreg) | |
10bb497e | 2646 | return "mov.l %T1,%T0" "\n" |
2647 | " mov.l %1,%0"; | |
7208c779 | 2648 | } |
2649 | ||
10bb497e | 2650 | return "mov.l %1,%0" "\n" |
2651 | " mov.l %T1,%T0"; | |
7208c779 | 2652 | } |
2653 | ||
73401833 | 2654 | /* Print an instruction which would have gone into a delay slot after |
2655 | another instruction, but couldn't because the other instruction expanded | |
2656 | into a sequence where putting the slot insn at the end wouldn't work. */ | |
73401833 | 2657 | static void |
cdf962b7 | 2658 | print_slot (rtx_sequence *seq) |
73401833 | 2659 | { |
cdf962b7 | 2660 | final_scan_insn (seq->insn (1), asm_out_file, optimize, 1, NULL); |
47c009e5 | 2661 | |
dd1286fb | 2662 | seq->insn (1)->set_deleted (); |
73401833 | 2663 | } |
97595bfd | 2664 | |
b7dbbdb2 | 2665 | const char * |
b82334f7 | 2666 | output_far_jump (rtx_insn *insn, rtx op) |
97595bfd | 2667 | { |
8deb3959 | 2668 | struct { rtx lab, reg, op; } this_jmp; |
79f6a8ed | 2669 | rtx_code_label *braf_base_lab = NULL; |
b7dbbdb2 | 2670 | const char *jump; |
8ded0752 | 2671 | int far; |
47fc0706 | 2672 | int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn)); |
b82334f7 | 2673 | rtx_insn *prev; |
97595bfd | 2674 | |
8deb3959 | 2675 | this_jmp.lab = gen_label_rtx (); |
47c009e5 | 2676 | |
15494e01 | 2677 | if (TARGET_SH2 |
2678 | && offset >= -32764 | |
2679 | && offset - get_attr_length (insn) <= 32766) | |
8ded0752 | 2680 | { |
2681 | far = 0; | |
10bb497e | 2682 | jump = "mov.w %O0,%1" "\n" |
2683 | " braf %1"; | |
8ded0752 | 2684 | } |
2685 | else | |
2686 | { | |
2687 | far = 1; | |
0abf894c | 2688 | if (flag_pic) |
d1665c4c | 2689 | { |
2690 | if (TARGET_SH2) | |
10bb497e | 2691 | jump = "mov.l %O0,%1" "\n" |
2692 | " braf %1"; | |
d1665c4c | 2693 | else |
10bb497e | 2694 | jump = "mov.l r0,@-r15" "\n" |
2695 | " mova %O0,r0" "\n" | |
2696 | " mov.l @r0,%1" "\n" | |
2697 | " add r0,%1" "\n" | |
2698 | " mov.l @r15+,r0" "\n" | |
2699 | " jmp @%1"; | |
d1665c4c | 2700 | } |
0abf894c | 2701 | else |
10bb497e | 2702 | jump = "mov.l %O0,%1" "\n" |
2703 | " jmp @%1"; | |
8ded0752 | 2704 | } |
2705 | /* If we have a scratch register available, use it. */ | |
cbb16986 | 2706 | if (NONJUMP_INSN_P ((prev = prev_nonnote_insn (insn))) |
2a6493a5 | 2707 | && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch) |
8ded0752 | 2708 | { |
8deb3959 | 2709 | this_jmp.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0)); |
2710 | if (REGNO (this_jmp.reg) == R0_REG && flag_pic && ! TARGET_SH2) | |
10bb497e | 2711 | jump = "mov.l r1,@-r15" "\n" |
2712 | " mova %O0,r0" "\n" | |
2713 | " mov.l @r0,r1" "\n" | |
2714 | " add r1,r0" "\n" | |
2715 | " mov.l @r15+,r1" "\n" | |
2716 | " jmp @%1"; | |
8deb3959 | 2717 | output_asm_insn (jump, &this_jmp.lab); |
8ded0752 | 2718 | if (dbr_sequence_length ()) |
2719 | print_slot (final_sequence); | |
2720 | else | |
2721 | output_asm_insn ("nop", 0); | |
2722 | } | |
2723 | else | |
2724 | { | |
2725 | /* Output the delay slot insn first if any. */ | |
2726 | if (dbr_sequence_length ()) | |
2727 | print_slot (final_sequence); | |
2728 | ||
8deb3959 | 2729 | this_jmp.reg = gen_rtx_REG (SImode, 13); |
87e19636 | 2730 | /* We must keep the stack aligned to 8-byte boundaries on SH5. |
2731 | Fortunately, MACL is fixed and call-clobbered, and we never | |
2732 | need its value across jumps, so save r13 in it instead of in | |
2733 | the stack. */ | |
2734 | if (TARGET_SH5) | |
10bb497e | 2735 | output_asm_insn ("lds r13,macl", 0); |
87e19636 | 2736 | else |
2737 | output_asm_insn ("mov.l r13,@-r15", 0); | |
8deb3959 | 2738 | output_asm_insn (jump, &this_jmp.lab); |
87e19636 | 2739 | if (TARGET_SH5) |
10bb497e | 2740 | output_asm_insn ("sts macl,r13", 0); |
87e19636 | 2741 | else |
2742 | output_asm_insn ("mov.l @r15+,r13", 0); | |
8ded0752 | 2743 | } |
d1665c4c | 2744 | if (far && flag_pic && TARGET_SH2) |
2745 | { | |
2746 | braf_base_lab = gen_label_rtx (); | |
805e22b2 | 2747 | (*targetm.asm_out.internal_label) (asm_out_file, "L", |
d1665c4c | 2748 | CODE_LABEL_NUMBER (braf_base_lab)); |
2749 | } | |
8ded0752 | 2750 | if (far) |
2751 | output_asm_insn (".align 2", 0); | |
8deb3959 | 2752 | (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this_jmp.lab)); |
2753 | this_jmp.op = op; | |
0abf894c | 2754 | if (far && flag_pic) |
d1665c4c | 2755 | { |
2756 | if (TARGET_SH2) | |
8deb3959 | 2757 | this_jmp.lab = braf_base_lab; |
2758 | output_asm_insn (".long %O2-%O0", &this_jmp.lab); | |
d1665c4c | 2759 | } |
0abf894c | 2760 | else |
8deb3959 | 2761 | output_asm_insn (far ? ".long %O2" : ".word %O2-%O0", &this_jmp.lab); |
97595bfd | 2762 | return ""; |
2763 | } | |
7208c779 | 2764 | |
73401833 | 2765 | /* Local label counter, used for constants in the pool and inside |
2766 | pattern branches. */ | |
73401833 | 2767 | static int lf = 100; |
2768 | ||
2769 | /* Output code for ordinary branches. */ | |
b7dbbdb2 | 2770 | const char * |
d3ffa7b4 | 2771 | output_branch (int logic, rtx_insn *insn, rtx *operands) |
7208c779 | 2772 | { |
fb2fe7e1 | 2773 | switch (get_attr_length (insn)) |
7208c779 | 2774 | { |
9eaab178 | 2775 | case 6: |
2776 | /* This can happen if filling the delay slot has caused a forward | |
2777 | branch to exceed its range (we could reverse it, but only | |
2778 | when we know we won't overextend other branches; this should | |
2779 | best be handled by relaxation). | |
2780 | It can also happen when other condbranches hoist delay slot insn | |
8ded0752 | 2781 | from their destination, thus leading to code size increase. |
2782 | But the branch will still be in the range -4092..+4098 bytes. */ | |
9eaab178 | 2783 | if (! TARGET_RELAX) |
8ded0752 | 2784 | { |
9eaab178 | 2785 | int label = lf++; |
2786 | /* The call to print_slot will clobber the operands. */ | |
2787 | rtx op0 = operands[0]; | |
9e7454d0 | 2788 | |
9eaab178 | 2789 | /* If the instruction in the delay slot is annulled (true), then |
2790 | there is no delay slot where we can put it now. The only safe | |
2791 | place for it is after the label. final will do that by default. */ | |
9e7454d0 | 2792 | |
9eaab178 | 2793 | if (final_sequence |
d3ffa7b4 | 2794 | && ! INSN_ANNULLED_BRANCH_P (final_sequence->insn (0)) |
2795 | && get_attr_length (final_sequence->insn (1))) | |
9eaab178 | 2796 | { |
fb2fe7e1 | 2797 | asm_fprintf (asm_out_file, "\tb%s%ss\t%LLF%d\n", logic ? "f" : "t", |
9eaab178 | 2798 | ASSEMBLER_DIALECT ? "/" : ".", label); |
2799 | print_slot (final_sequence); | |
2800 | } | |
2801 | else | |
fb2fe7e1 | 2802 | asm_fprintf (asm_out_file, "\tb%s\t%LLF%d\n", logic ? "f" : "t", label); |
9e7454d0 | 2803 | |
fb2fe7e1 | 2804 | output_asm_insn ("bra\t%l0", &op0); |
2805 | fprintf (asm_out_file, "\tnop\n"); | |
d767e27e | 2806 | (*targetm.asm_out.internal_label) (asm_out_file, "LF", label); |
9e7454d0 | 2807 | |
9eaab178 | 2808 | return ""; |
8ded0752 | 2809 | } |
9eaab178 | 2810 | /* When relaxing, handle this like a short branch. The linker |
2811 | will fix it up if it still doesn't fit after relaxation. */ | |
2812 | case 2: | |
2813 | return logic ? "bt%.\t%l0" : "bf%.\t%l0"; | |
87ed74ef | 2814 | |
2815 | /* These are for SH2e, in which we have to account for the | |
2816 | extra nop because of the hardware bug in annulled branches. */ | |
2817 | case 8: | |
2818 | if (! TARGET_RELAX) | |
2819 | { | |
2820 | int label = lf++; | |
2821 | ||
1a6a7a27 | 2822 | gcc_assert (!final_sequence |
2823 | || !(INSN_ANNULLED_BRANCH_P | |
2824 | (XVECEXP (final_sequence, 0, 0)))); | |
87ed74ef | 2825 | asm_fprintf (asm_out_file, "b%s%ss\t%LLF%d\n", |
2826 | logic ? "f" : "t", | |
2827 | ASSEMBLER_DIALECT ? "/" : ".", label); | |
2828 | fprintf (asm_out_file, "\tnop\n"); | |
2829 | output_asm_insn ("bra\t%l0", operands); | |
2830 | fprintf (asm_out_file, "\tnop\n"); | |
2831 | (*targetm.asm_out.internal_label) (asm_out_file, "LF", label); | |
2832 | ||
2833 | return ""; | |
2834 | } | |
2835 | /* When relaxing, fall through. */ | |
2836 | case 4: | |
2837 | { | |
2838 | char buffer[10]; | |
9e7454d0 | 2839 | |
87ed74ef | 2840 | sprintf (buffer, "b%s%ss\t%%l0", |
2841 | logic ? "t" : "f", | |
2842 | ASSEMBLER_DIALECT ? "/" : "."); | |
2843 | output_asm_insn (buffer, &operands[0]); | |
2844 | return "nop"; | |
2845 | } | |
2846 | ||
9eaab178 | 2847 | default: |
fb2fe7e1 | 2848 | /* There should be no longer branches now - that would |
2849 | indicate that something has destroyed the branches set | |
2850 | up in machine_dependent_reorg. */ | |
1a6a7a27 | 2851 | gcc_unreachable (); |
8ded0752 | 2852 | } |
8ded0752 | 2853 | } |
7208c779 | 2854 | |
8deb3959 | 2855 | /* Output a code sequence for INSN using TEMPL with OPERANDS; but before, |
5be30882 | 2856 | fill in operands 9 as a label to the successor insn. |
2857 | We try to use jump threading where possible. | |
2858 | IF CODE matches the comparison in the IF_THEN_ELSE of a following jump, | |
2859 | we assume the jump is taken. I.e. EQ means follow jmp and bf, NE means | |
2860 | follow jmp and bt, if the address is in range. */ | |
b7dbbdb2 | 2861 | const char * |
8deb3959 | 2862 | output_branchy_insn (enum rtx_code code, const char *templ, |
b82334f7 | 2863 | rtx_insn *insn, rtx *operands) |
8ded0752 | 2864 | { |
b82334f7 | 2865 | rtx_insn *next_insn = NEXT_INSN (insn); |
3f2613e4 | 2866 | |
cbb16986 | 2867 | if (next_insn && JUMP_P (next_insn) && condjump_p (next_insn)) |
8ded0752 | 2868 | { |
2869 | rtx src = SET_SRC (PATTERN (next_insn)); | |
2870 | if (GET_CODE (src) == IF_THEN_ELSE && GET_CODE (XEXP (src, 0)) != code) | |
2871 | { | |
2872 | /* Following branch not taken */ | |
ed7591be | 2873 | rtx_code_label *lab = gen_label_rtx (); |
2874 | emit_label_after (lab, next_insn); | |
2875 | INSN_ADDRESSES_NEW (lab, | |
47fc0706 | 2876 | INSN_ADDRESSES (INSN_UID (next_insn)) |
2877 | + get_attr_length (next_insn)); | |
ed7591be | 2878 | operands[9] = lab; |
8deb3959 | 2879 | return templ; |
8ded0752 | 2880 | } |
2881 | else | |
2882 | { | |
9eaab178 | 2883 | int offset = (branch_dest (next_insn) |
47fc0706 | 2884 | - INSN_ADDRESSES (INSN_UID (next_insn)) + 4); |
9eaab178 | 2885 | if (offset >= -252 && offset <= 258) |
8ded0752 | 2886 | { |
2887 | if (GET_CODE (src) == IF_THEN_ELSE) | |
2888 | /* branch_true */ | |
2889 | src = XEXP (src, 1); | |
2890 | operands[9] = src; | |
8deb3959 | 2891 | return templ; |
8ded0752 | 2892 | } |
2893 | } | |
7208c779 | 2894 | } |
ed7591be | 2895 | rtx_code_label *lab = gen_label_rtx (); |
2896 | emit_label_after (lab, insn); | |
2897 | INSN_ADDRESSES_NEW (lab, | |
47fc0706 | 2898 | INSN_ADDRESSES (INSN_UID (insn)) |
2899 | + get_attr_length (insn)); | |
ed7591be | 2900 | operands[9] = lab; |
8deb3959 | 2901 | return templ; |
8ded0752 | 2902 | } |
e6c94d0d | 2903 | |
b7dbbdb2 | 2904 | const char * |
b82334f7 | 2905 | output_ieee_ccmpeq (rtx_insn *insn, rtx *operands) |
8ded0752 | 2906 | { |
10bb497e | 2907 | return output_branchy_insn (NE, "bt %l9" "\n" |
2908 | " fcmp/eq %1,%0", | |
aacd46a5 | 2909 | insn, operands); |
7208c779 | 2910 | } |
2e3d4844 | 2911 | \f |
92c473b8 | 2912 | /* Output the start of the assembler file. */ |
92c473b8 | 2913 | static void |
04f04b72 | 2914 | sh_file_start (void) |
7208c779 | 2915 | { |
92c473b8 | 2916 | default_file_start (); |
2917 | ||
2918 | if (TARGET_ELF) | |
2919 | /* We need to show the text section with the proper | |
2920 | attributes as in TEXT_SECTION_ASM_OP, before dwarf2out | |
9fd95d94 | 2921 | emits it without attributes in TEXT_SECTION_ASM_OP, else GAS |
92c473b8 | 2922 | will complain. We can teach GAS specifically about the |
2923 | default attributes for our choice of text section, but | |
2924 | then we would have to change GAS again if/when we change | |
2925 | the text section name. */ | |
2926 | fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP); | |
2927 | else | |
2928 | /* Switch to the data section so that the coffsem symbol | |
2929 | isn't in the text section. */ | |
2f14b1f9 | 2930 | switch_to_section (data_section); |
47c009e5 | 2931 | |
73401833 | 2932 | if (TARGET_LITTLE_ENDIAN) |
92c473b8 | 2933 | fputs ("\t.little\n", asm_out_file); |
87e19636 | 2934 | |
92c473b8 | 2935 | if (!TARGET_ELF) |
2936 | { | |
2937 | if (TARGET_SHCOMPACT) | |
2938 | fputs ("\t.mode\tSHcompact\n", asm_out_file); | |
2939 | else if (TARGET_SHMEDIA) | |
2940 | fprintf (asm_out_file, "\t.mode\tSHmedia\n\t.abi\t%i\n", | |
2941 | TARGET_SHMEDIA64 ? 64 : 32); | |
2942 | } | |
7208c779 | 2943 | } |
97595bfd | 2944 | \f |
02359f85 | 2945 | /* Check if PAT includes UNSPEC_CALLER unspec pattern. */ |
02359f85 | 2946 | static bool |
04f04b72 | 2947 | unspec_caller_rtx_p (rtx pat) |
02359f85 | 2948 | { |
20ba855a | 2949 | rtx base, offset; |
2950 | int i; | |
2951 | ||
2952 | split_const (pat, &base, &offset); | |
2953 | if (GET_CODE (base) == UNSPEC) | |
02359f85 | 2954 | { |
20ba855a | 2955 | if (XINT (base, 1) == UNSPEC_CALLER) |
02359f85 | 2956 | return true; |
20ba855a | 2957 | for (i = 0; i < XVECLEN (base, 0); i++) |
2958 | if (unspec_caller_rtx_p (XVECEXP (base, 0, i))) | |
2959 | return true; | |
02359f85 | 2960 | } |
02359f85 | 2961 | return false; |
2962 | } | |
2963 | ||
2964 | /* Indicate that INSN cannot be duplicated. This is true for insn | |
77aa6362 | 2965 | that generates a unique label. */ |
02359f85 | 2966 | static bool |
18282db0 | 2967 | sh_cannot_copy_insn_p (rtx_insn *insn) |
02359f85 | 2968 | { |
2969 | rtx pat; | |
2970 | ||
2971 | if (!reload_completed || !flag_pic) | |
2972 | return false; | |
2973 | ||
cbb16986 | 2974 | if (!NONJUMP_INSN_P (insn)) |
02359f85 | 2975 | return false; |
2976 | if (asm_noperands (insn) >= 0) | |
2977 | return false; | |
2978 | ||
2979 | pat = PATTERN (insn); | |
2980 | if (GET_CODE (pat) != SET) | |
2981 | return false; | |
2982 | pat = SET_SRC (pat); | |
2983 | ||
2984 | if (unspec_caller_rtx_p (pat)) | |
2985 | return true; | |
2986 | ||
2987 | return false; | |
2988 | } | |
2989 | \f | |
55c71520 | 2990 | /* Number of instructions used to make an arithmetic right shift by N. */ |
e7c691ac | 2991 | static const char ashiftrt_insns[] = |
1504eb7e | 2992 | { 0,1,2,3,4,5,8,8,8,8,8,8,8,8,8,8,2,3,4,5,8,8,8,8,8,8,8,8,8,8,8,2}; |
2993 | ||
55c71520 | 2994 | /* Description of a logical left or right shift, when expanded to a sequence |
2995 | of 1/2/8/16 shifts. | |
2996 | Notice that one bit right shifts clobber the T bit. One bit left shifts | |
2997 | are done with an 'add Rn,Rm' insn and thus do not clobber the T bit. */ | |
2998 | enum | |
2999 | { | |
3000 | ASHL_CLOBBERS_T = 1 << 0, | |
3001 | LSHR_CLOBBERS_T = 1 << 1 | |
3002 | }; | |
3003 | ||
3004 | struct ashl_lshr_sequence | |
3005 | { | |
3006 | char insn_count; | |
3007 | char amount[6]; | |
3008 | char clobbers_t; | |
3009 | }; | |
9e7454d0 | 3010 | |
55c71520 | 3011 | static const struct ashl_lshr_sequence ashl_lshr_seq[32] = |
3012 | { | |
6e7c6395 | 3013 | { 0, { 0 }, 0 }, // 0 |
55c71520 | 3014 | { 1, { 1 }, LSHR_CLOBBERS_T }, |
3015 | { 1, { 2 }, 0 }, | |
3016 | { 2, { 2, 1 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3017 | { 2, { 2, 2 }, 0 }, // 4 |
55c71520 | 3018 | { 3, { 2, 1, 2 }, LSHR_CLOBBERS_T }, |
3019 | { 3, { 2, 2, 2 }, 0 }, | |
3020 | { 4, { 2, 2, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3021 | { 1, { 8 }, 0 }, // 8 |
55c71520 | 3022 | { 2, { 8, 1 }, LSHR_CLOBBERS_T }, |
3023 | { 2, { 8, 2 }, 0 }, | |
3024 | { 3, { 8, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3025 | { 3, { 8, 2, 2 }, 0 }, // 12 |
55c71520 | 3026 | { 4, { 8, 2, 1, 2 }, LSHR_CLOBBERS_T }, |
3027 | { 3, { 8, -2, 8 }, 0 }, | |
3028 | { 3, { 8, -1, 8 }, ASHL_CLOBBERS_T }, | |
6e7c6395 | 3029 | { 1, { 16 }, 0 }, // 16 |
55c71520 | 3030 | { 2, { 16, 1 }, LSHR_CLOBBERS_T }, |
3031 | { 2, { 16, 2 }, 0 }, | |
3032 | { 3, { 16, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3033 | { 3, { 16, 2, 2 }, 0 }, // 20 |
55c71520 | 3034 | { 4, { 16, 2, 1, 2 }, LSHR_CLOBBERS_T }, |
3035 | { 3, { 16, -2, 8 }, 0 }, | |
3036 | { 3, { 16, -1, 8 }, ASHL_CLOBBERS_T }, | |
6e7c6395 | 3037 | { 2, { 16, 8 }, 0 }, // 24 |
55c71520 | 3038 | { 3, { 16, 1, 8 }, LSHR_CLOBBERS_T }, |
3039 | { 3, { 16, 8, 2 }, 0 }, | |
3040 | { 4, { 16, 8, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3041 | { 4, { 16, 8, 2, 2 }, 0 }, // 28 |
55c71520 | 3042 | { 4, { 16, -1, -2, 16 }, ASHL_CLOBBERS_T }, |
3043 | { 3, { 16, -2, 16 }, 0 }, | |
be3ab97a | 3044 | |
3045 | /* For a right shift by 31 a 2 insn shll-movt sequence can be used. | |
3046 | For a left shift by 31 a 2 insn and-rotl sequences can be used. | |
3047 | However, the shift-and combiner code needs this entry here to be in | |
3048 | terms of real shift insns. */ | |
55c71520 | 3049 | { 3, { 16, -1, 16 }, ASHL_CLOBBERS_T } |
3050 | }; | |
2ce8df5a | 3051 | |
55c71520 | 3052 | /* Individual shift amounts for shift amounts < 16, up to three highmost |
3053 | bits might be clobbered. This is typically used when combined with some | |
3054 | kind of sign or zero extension. */ | |
3055 | static const struct ashl_lshr_sequence ext_ashl_lshr_seq[32] = | |
3056 | { | |
6e7c6395 | 3057 | { 0, { 0 }, 0 }, // 0 |
55c71520 | 3058 | { 1, { 1 }, LSHR_CLOBBERS_T }, |
3059 | { 1, { 2 }, 0 }, | |
3060 | { 2, { 2, 1 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3061 | { 2, { 2, 2 }, 0 }, // 4 |
55c71520 | 3062 | { 3, { 2, 1, 2 }, LSHR_CLOBBERS_T }, |
3063 | { 2, { 8, -2 }, 0 }, | |
3064 | { 2, { 8, -1 }, ASHL_CLOBBERS_T }, | |
6e7c6395 | 3065 | { 1, { 8 }, 0 }, // 8 |
55c71520 | 3066 | { 2, { 8, 1 }, LSHR_CLOBBERS_T }, |
3067 | { 2, { 8, 2 }, 0 }, | |
3068 | { 3, { 8, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3069 | { 3, { 8, 2, 2 }, 0 }, // 12 |
55c71520 | 3070 | { 3, { 16, -2, -1 }, ASHL_CLOBBERS_T }, |
3071 | { 2, { 16, -2 }, 0 }, | |
3072 | { 2, { 16, -1 }, ASHL_CLOBBERS_T }, | |
6e7c6395 | 3073 | { 1, { 16 }, 0 }, // 16 |
55c71520 | 3074 | { 2, { 16, 1 }, LSHR_CLOBBERS_T }, |
3075 | { 2, { 16, 2 }, 0 }, | |
3076 | { 3, { 16, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3077 | { 3, { 16, 2, 2 }, 0 }, // 20 |
55c71520 | 3078 | { 4, { 16, 2, 1, 2 }, LSHR_CLOBBERS_T }, |
3079 | { 3, { 16, -2, 8 }, 0 }, | |
3080 | { 3, { 16, -1, 8 }, ASHL_CLOBBERS_T }, | |
6e7c6395 | 3081 | { 2, { 16, 8 }, 0 }, // 24 |
55c71520 | 3082 | { 3, { 16, 1, 8 }, LSHR_CLOBBERS_T }, |
3083 | { 3, { 16, 8, 2 }, 0 }, | |
3084 | { 4, { 16, 8, 1, 2 }, LSHR_CLOBBERS_T }, | |
6e7c6395 | 3085 | { 4, { 16, 8, 2, 2 }, 0 }, // 28 |
55c71520 | 3086 | { 4, { 16, -1, -2, 16 }, ASHL_CLOBBERS_T }, |
3087 | { 3, { 16, -2, 16 }, 0 }, | |
3088 | { 3, { 16, -1, 16 }, ASHL_CLOBBERS_T } | |
3089 | }; | |
3090 | ||
3091 | /* Return true if a shift left consisting of 1/2/8/16 shift instructions | |
3092 | will clobber the T bit. */ | |
3093 | bool | |
3094 | sh_ashlsi_clobbers_t_reg_p (rtx shift_amount) | |
3095 | { | |
3096 | gcc_assert (CONST_INT_P (shift_amount)); | |
be3ab97a | 3097 | |
3098 | const int shift_amount_i = INTVAL (shift_amount) & 31; | |
3099 | ||
3100 | /* Special case for shift count of 31: use and-rotl sequence. */ | |
3101 | if (shift_amount_i == 31) | |
3102 | return true; | |
3103 | ||
3104 | return (ashl_lshr_seq[shift_amount_i].clobbers_t | |
55c71520 | 3105 | & ASHL_CLOBBERS_T) != 0; |
3106 | } | |
2ce8df5a | 3107 | |
6c049e03 | 3108 | /* Return true if a logical right shift consisting of 1/2/8/16 shift |
3109 | instructions will clobber the T bit. */ | |
8cec7a6e | 3110 | bool |
3111 | sh_lshrsi_clobbers_t_reg_p (rtx shift_amount) | |
3112 | { | |
3113 | gcc_assert (CONST_INT_P (shift_amount)); | |
be3ab97a | 3114 | |
3115 | const int shift_amount_i = INTVAL (shift_amount) & 31; | |
3116 | ||
3117 | /* Special case for shift count of 31: use shll-movt sequence. */ | |
3118 | if (shift_amount_i == 31) | |
3119 | return true; | |
3120 | ||
3121 | return (ashl_lshr_seq[shift_amount_i].clobbers_t | |
8cec7a6e | 3122 | & LSHR_CLOBBERS_T) != 0; |
3123 | } | |
3124 | ||
be3ab97a | 3125 | /* Return true if it is potentially beneficial to use a dynamic shift |
3126 | instruction (shad / shar) instead of a combination of 1/2/8/16 | |
3127 | shift instructions for the specified shift count. | |
3128 | If dynamic shifts are not available, always return false. */ | |
3129 | bool | |
3130 | sh_dynamicalize_shift_p (rtx count) | |
3131 | { | |
3132 | gcc_assert (CONST_INT_P (count)); | |
3133 | ||
3134 | const int shift_amount_i = INTVAL (count) & 31; | |
3135 | int insn_count; | |
3136 | ||
3137 | /* For left and right shifts, there are shorter 2 insn sequences for | |
3138 | shift amounts of 31. */ | |
3139 | if (shift_amount_i == 31) | |
3140 | insn_count = 2; | |
3141 | else | |
3142 | insn_count = ashl_lshr_seq[shift_amount_i].insn_count; | |
3143 | ||
3144 | return TARGET_DYNSHIFT && (insn_count > 1 + SH_DYNAMIC_SHIFT_COST); | |
3145 | } | |
3146 | ||
69b02875 | 3147 | /* Assuming we have a value that has been sign-extended by at least one bit, |
6c049e03 | 3148 | can we use the ext_shift_amounts with the last shift turned to an |
3149 | arithmetic shift to shift it by N without data loss, and quicker than by | |
3150 | other means? */ | |
69b02875 | 3151 | #define EXT_SHIFT_SIGNED(n) (((n) | 8) == 15) |
3152 | ||
1504eb7e | 3153 | /* Return the cost of a shift. */ |
fab7adbf | 3154 | static inline int |
04f04b72 | 3155 | shiftcosts (rtx x) |
7208c779 | 3156 | { |
d6fe3e0d | 3157 | int value; |
73401833 | 3158 | |
87e19636 | 3159 | if (TARGET_SHMEDIA) |
e7768fa5 | 3160 | return 1; |
87e19636 | 3161 | |
41f4d177 | 3162 | if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) |
3163 | { | |
3164 | if (GET_MODE (x) == DImode | |
cbb16986 | 3165 | && CONST_INT_P (XEXP (x, 1)) |
41f4d177 | 3166 | && INTVAL (XEXP (x, 1)) == 1) |
e7768fa5 | 3167 | return 2; |
41f4d177 | 3168 | |
3169 | /* Everything else is invalid, because there is no pattern for it. */ | |
e7768fa5 | 3170 | return -1; |
41f4d177 | 3171 | } |
1504eb7e | 3172 | /* If shift by a non constant, then this will be expensive. */ |
cbb16986 | 3173 | if (!CONST_INT_P (XEXP (x, 1))) |
e7768fa5 | 3174 | return SH_DYNAMIC_SHIFT_COST; |
7208c779 | 3175 | |
adb906e2 | 3176 | /* Otherwise, return the true cost in instructions. Cope with out of range |
3177 | shift counts more or less arbitrarily. */ | |
3178 | value = INTVAL (XEXP (x, 1)) & 31; | |
d6fe3e0d | 3179 | |
73401833 | 3180 | if (GET_CODE (x) == ASHIFTRT) |
79f0f2fe | 3181 | { |
3182 | int cost = ashiftrt_insns[value]; | |
e7768fa5 | 3183 | /* If dynamic shifts are available and profitable in this case, then we |
3184 | put the constant in a reg and use shad. */ | |
8ded0752 | 3185 | if (cost > 1 + SH_DYNAMIC_SHIFT_COST) |
3186 | cost = 1 + SH_DYNAMIC_SHIFT_COST; | |
e7768fa5 | 3187 | return cost; |
79f0f2fe | 3188 | } |
73401833 | 3189 | else |
55c71520 | 3190 | return ashl_lshr_seq[value].insn_count; |
97595bfd | 3191 | } |
47c009e5 | 3192 | |
f43912de | 3193 | /* Return the cost of an AND/XOR/IOR operation. */ |
fab7adbf | 3194 | static inline int |
f43912de | 3195 | and_xor_ior_costs (rtx x, int code) |
97595bfd | 3196 | { |
96e7d8df | 3197 | /* On SH1-4 we have only max. SImode operations. |
3198 | Double the cost for modes > SImode. */ | |
3199 | const int cost_scale = !TARGET_SHMEDIA | |
3200 | && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD | |
3201 | ? 2 : 1; | |
73401833 | 3202 | |
f43912de | 3203 | /* A logical operation with two registers is a single cycle |
3204 | instruction. */ | |
cbb16986 | 3205 | if (!CONST_INT_P (XEXP (x, 1))) |
96e7d8df | 3206 | return 1 * cost_scale; |
73401833 | 3207 | |
96e7d8df | 3208 | int i = INTVAL (XEXP (x, 1)); |
87e19636 | 3209 | |
3210 | if (TARGET_SHMEDIA) | |
3211 | { | |
abff7a2e | 3212 | if (satisfies_constraint_I10 (XEXP (x, 1)) |
3213 | || satisfies_constraint_J16 (XEXP (x, 1))) | |
87e19636 | 3214 | return 1; |
3215 | else | |
20d892d1 | 3216 | return 1 + rtx_cost (XEXP (x, 1), AND, 1, !optimize_size); |
87e19636 | 3217 | } |
3218 | ||
f22b6811 | 3219 | /* These constants are single cycle extu.[bw] instructions. */ |
f43912de | 3220 | if ((i == 0xff || i == 0xffff) && code == AND) |
96e7d8df | 3221 | return 1 * cost_scale; |
f43912de | 3222 | /* Constants that can be used in an instruction as an immediate are |
3223 | a single cycle, but this requires r0, so make it a little more | |
3224 | expensive. */ | |
af2c1324 | 3225 | if (CONST_OK_FOR_K08 (i)) |
96e7d8df | 3226 | return 2 * cost_scale; |
f43912de | 3227 | /* Constants that can be loaded with a mov immediate need one more cycle. |
f22b6811 | 3228 | This case is probably unnecessary. */ |
af2c1324 | 3229 | if (CONST_OK_FOR_I08 (i)) |
96e7d8df | 3230 | return 2 * cost_scale; |
f43912de | 3231 | /* Any other constant requires an additional 2 cycle pc-relative load. |
f22b6811 | 3232 | This case is probably unnecessary. */ |
96e7d8df | 3233 | return 3 * cost_scale; |
97595bfd | 3234 | } |
f3d93547 | 3235 | |
d27eb4b1 | 3236 | /* Return the cost of an addition or a subtraction. */ |
fab7adbf | 3237 | static inline int |
04f04b72 | 3238 | addsubcosts (rtx x) |
d27eb4b1 | 3239 | { |
706b7999 | 3240 | if (GET_MODE (x) == SImode) |
3241 | { | |
3242 | /* The addc or subc patterns will eventually become one or two | |
3243 | instructions. Below are some costs for some of the patterns | |
3244 | which combine would reject because the costs of the individual | |
3245 | insns in the patterns are lower. | |
3246 | ||
3247 | FIXME: It would be much easier if we had something like insn cost | |
3248 | attributes and the cost calculation machinery used those attributes | |
3249 | in the first place. This would eliminate redundant recog-like C | |
3250 | code to calculate costs of complex patterns. */ | |
3251 | rtx op0 = XEXP (x, 0); | |
3252 | rtx op1 = XEXP (x, 1); | |
3253 | ||
3254 | if (GET_CODE (x) == PLUS) | |
3255 | { | |
3256 | if (GET_CODE (op0) == AND | |
3257 | && XEXP (op0, 1) == const1_rtx | |
3258 | && (GET_CODE (op1) == PLUS | |
3259 | || (GET_CODE (op1) == MULT && XEXP (op1, 1) == const2_rtx))) | |
3260 | return 1; | |
3261 | ||
3262 | if (GET_CODE (op0) == MULT && XEXP (op0, 1) == const2_rtx | |
3263 | && GET_CODE (op1) == LSHIFTRT | |
3264 | && CONST_INT_P (XEXP (op1, 1)) && INTVAL (XEXP (op1, 1)) == 31) | |
3265 | return 1; | |
3266 | } | |
3267 | } | |
3268 | ||
96e7d8df | 3269 | /* On SH1-4 we have only max. SImode operations. |
3270 | Double the cost for modes > SImode. */ | |
3271 | const int cost_scale = !TARGET_SHMEDIA | |
3272 | && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD | |
3273 | ? 2 : 1; | |
3274 | ||
d27eb4b1 | 3275 | /* Adding a register is a single cycle insn. */ |
cbb16986 | 3276 | if (REG_P (XEXP (x, 1)) |
0d93aeb0 | 3277 | || GET_CODE (XEXP (x, 1)) == SUBREG) |
96e7d8df | 3278 | return 1 * cost_scale; |
d27eb4b1 | 3279 | |
3280 | /* Likewise for small constants. */ | |
cbb16986 | 3281 | if (CONST_INT_P (XEXP (x, 1)) |
87e19636 | 3282 | && CONST_OK_FOR_ADD (INTVAL (XEXP (x, 1)))) |
96e7d8df | 3283 | return 1 * cost_scale; |
d27eb4b1 | 3284 | |
87e19636 | 3285 | if (TARGET_SHMEDIA) |
3286 | switch (GET_CODE (XEXP (x, 1))) | |
3287 | { | |
3288 | case CONST: | |
3289 | case LABEL_REF: | |
3290 | case SYMBOL_REF: | |
3291 | return TARGET_SHMEDIA64 ? 5 : 3; | |
3292 | ||
3293 | case CONST_INT: | |
af2c1324 | 3294 | if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)))) |
6c049e03 | 3295 | return 2; |
af2c1324 | 3296 | else if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)) >> 16)) |
87e19636 | 3297 | return 3; |
af2c1324 | 3298 | else if (CONST_OK_FOR_I16 ((INTVAL (XEXP (x, 1)) >> 16) >> 16)) |
87e19636 | 3299 | return 4; |
3300 | ||
3301 | /* Fall through. */ | |
3302 | default: | |
d767e27e | 3303 | return 5; |
87e19636 | 3304 | } |
3305 | ||
d27eb4b1 | 3306 | /* Any other constant requires a 2 cycle pc-relative load plus an |
3307 | addition. */ | |
96e7d8df | 3308 | return 3 * cost_scale; |
d27eb4b1 | 3309 | } |
3310 | ||
1504eb7e | 3311 | /* Return the cost of a multiply. */ |
fab7adbf | 3312 | static inline int |
04f04b72 | 3313 | multcosts (rtx x ATTRIBUTE_UNUSED) |
97595bfd | 3314 | { |
4906bcbb | 3315 | if (sh_multcost >= 0) |
3316 | return sh_multcost; | |
87e19636 | 3317 | if (TARGET_SHMEDIA) |
59312820 | 3318 | /* ??? We have a mul insn, but it has a latency of three, and doesn't |
3319 | accept constants. Ideally, we would use a cost of one or two and | |
3320 | add the cost of the operand, but disregard the latter when inside loops | |
3321 | and loop invariant code motion is still to follow. | |
3322 | Using a multiply first and splitting it later if it's a loss | |
3323 | doesn't work because of different sign / zero extension semantics | |
3324 | of multiplies vs. shifts. */ | |
c17f64cc | 3325 | return optimize_size ? 2 : 3; |
87e19636 | 3326 | |
97595bfd | 3327 | if (TARGET_SH2) |
f3d93547 | 3328 | { |
3329 | /* We have a mul insn, so we can never take more than the mul and the | |
8cd86814 | 3330 | read of the mac reg, but count more because of the latency and extra |
1504eb7e | 3331 | reg usage. */ |
c17f64cc | 3332 | if (optimize_size) |
2e3d4844 | 3333 | return 2; |
8cd86814 | 3334 | return 3; |
f3d93547 | 3335 | } |
3336 | ||
8cd86814 | 3337 | /* If we're aiming at small code, then just count the number of |
1504eb7e | 3338 | insns in a multiply call sequence. */ |
c17f64cc | 3339 | if (optimize_size) |
73401833 | 3340 | return 5; |
f3d93547 | 3341 | |
1504eb7e | 3342 | /* Otherwise count all the insns in the routine we'd be calling too. */ |
f3d93547 | 3343 | return 20; |
97595bfd | 3344 | } |
47c009e5 | 3345 | |
fab7adbf | 3346 | /* Compute a (partial) cost for rtx X. Return true if the complete |
3347 | cost has been computed, and false if subexpressions should be | |
3348 | scanned. In either case, *TOTAL contains the cost result. */ | |
fab7adbf | 3349 | static bool |
20d892d1 | 3350 | sh_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, |
3351 | int *total, bool speed ATTRIBUTE_UNUSED) | |
fab7adbf | 3352 | { |
3353 | switch (code) | |
3354 | { | |
a846db2c | 3355 | /* The lower-subreg pass decides whether to split multi-word regs |
3356 | into individual regs by looking at the cost for a SET of certain | |
3357 | modes with the following patterns: | |
3358 | (set (reg) (reg)) | |
3359 | (set (reg) (const_int 0)) | |
3360 | On machines that support vector-move operations a multi-word move | |
3361 | is the same cost as individual reg move. On SH there is no | |
3362 | vector-move, so we have to provide the correct cost in the number | |
3363 | of move insns to load/store the reg of the mode in question. */ | |
3364 | case SET: | |
3365 | if (register_operand (SET_DEST (x), VOIDmode) | |
3366 | && (register_operand (SET_SRC (x), VOIDmode) | |
3367 | || satisfies_constraint_Z (SET_SRC (x)))) | |
3368 | { | |
3754d046 | 3369 | const machine_mode mode = GET_MODE (SET_DEST (x)); |
a846db2c | 3370 | *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) |
3371 | / mov_insn_size (mode, TARGET_SH2A)); | |
3372 | return true; | |
3373 | } | |
3374 | return false; | |
3375 | ||
b9a94d16 | 3376 | /* The cost of a mem access is mainly the cost of the address mode. */ |
3377 | case MEM: | |
3378 | *total = sh_address_cost (XEXP (x, 0), GET_MODE (x), MEM_ADDR_SPACE (x), | |
3379 | true); | |
3380 | return true; | |
3381 | ||
3382 | /* The cost of a sign or zero extend depends on whether the source is a | |
3383 | reg or a mem. In case of a mem take the address into acount. */ | |
3384 | case SIGN_EXTEND: | |
3385 | if (REG_P (XEXP (x, 0))) | |
3386 | { | |
3387 | *total = COSTS_N_INSNS (1); | |
3388 | return true; | |
3389 | } | |
3390 | if (MEM_P (XEXP (x, 0))) | |
3391 | { | |
3392 | *total = sh_address_cost (XEXP (XEXP (x, 0), 0), | |
3393 | GET_MODE (XEXP (x, 0)), | |
3394 | MEM_ADDR_SPACE (XEXP (x, 0)), true); | |
3395 | return true; | |
3396 | } | |
3397 | return false; | |
3398 | ||
3399 | case ZERO_EXTEND: | |
3400 | if (REG_P (XEXP (x, 0))) | |
3401 | { | |
3402 | *total = COSTS_N_INSNS (1); | |
3403 | return true; | |
3404 | } | |
3405 | else if (TARGET_SH2A && MEM_P (XEXP (x, 0)) | |
3406 | && (GET_MODE (XEXP (x, 0)) == QImode | |
3407 | || GET_MODE (XEXP (x, 0)) == HImode)) | |
3408 | { | |
3409 | /* Handle SH2A's movu.b and movu.w insn. */ | |
3410 | *total = sh_address_cost (XEXP (XEXP (x, 0), 0), | |
3411 | GET_MODE (XEXP (x, 0)), | |
3412 | MEM_ADDR_SPACE (XEXP (x, 0)), true); | |
3413 | return true; | |
3414 | } | |
3415 | return false; | |
3416 | ||
3417 | /* mems for SFmode and DFmode can be inside a parallel due to | |
3418 | the way the fpscr is handled. */ | |
3419 | case PARALLEL: | |
3420 | for (int i = 0; i < XVECLEN (x, 0); i++) | |
3421 | { | |
3422 | rtx xx = XVECEXP (x, 0, i); | |
3423 | if (GET_CODE (xx) == SET && MEM_P (XEXP (xx, 0))) | |
3424 | { | |
3425 | *total = sh_address_cost (XEXP (XEXP (xx, 0), 0), | |
3426 | GET_MODE (XEXP (xx, 0)), | |
3427 | MEM_ADDR_SPACE (XEXP (xx, 0)), true); | |
3428 | return true; | |
3429 | } | |
3430 | if (GET_CODE (xx) == SET && MEM_P (XEXP (xx, 1))) | |
3431 | { | |
3432 | *total = sh_address_cost (XEXP (XEXP (xx, 1), 0), | |
3433 | GET_MODE (XEXP (xx, 1)), | |
3434 | MEM_ADDR_SPACE (XEXP (xx, 1)), true); | |
3435 | return true; | |
3436 | } | |
3437 | } | |
3438 | ||
3439 | if (sh_1el_vec (x, VOIDmode)) | |
3440 | *total = outer_code != SET; | |
3441 | else if (sh_rep_vec (x, VOIDmode)) | |
3442 | *total = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + 3) / 4 | |
3443 | + (outer_code != SET)); | |
3444 | else | |
3445 | *total = COSTS_N_INSNS (3) + (outer_code != SET); | |
3446 | return true; | |
3447 | ||
fab7adbf | 3448 | case CONST_INT: |
3449 | if (TARGET_SHMEDIA) | |
6c049e03 | 3450 | { |
fab7adbf | 3451 | if (INTVAL (x) == 0) |
3452 | *total = 0; | |
3453 | else if (outer_code == AND && and_operand ((x), DImode)) | |
3454 | *total = 0; | |
3455 | else if ((outer_code == IOR || outer_code == XOR | |
3456 | || outer_code == PLUS) | |
af2c1324 | 3457 | && CONST_OK_FOR_I10 (INTVAL (x))) |
fab7adbf | 3458 | *total = 0; |
af2c1324 | 3459 | else if (CONST_OK_FOR_I16 (INTVAL (x))) |
6c049e03 | 3460 | *total = COSTS_N_INSNS (outer_code != SET); |
af2c1324 | 3461 | else if (CONST_OK_FOR_I16 (INTVAL (x) >> 16)) |
59312820 | 3462 | *total = COSTS_N_INSNS ((outer_code != SET) + 1); |
af2c1324 | 3463 | else if (CONST_OK_FOR_I16 ((INTVAL (x) >> 16) >> 16)) |
561c35b4 | 3464 | *total = COSTS_N_INSNS ((outer_code != SET) + 2); |
6c049e03 | 3465 | else |
561c35b4 | 3466 | *total = COSTS_N_INSNS ((outer_code != SET) + 3); |
fab7adbf | 3467 | return true; |
6c049e03 | 3468 | } |
af2c1324 | 3469 | if (CONST_OK_FOR_I08 (INTVAL (x))) |
fab7adbf | 3470 | *total = 0; |
3471 | else if ((outer_code == AND || outer_code == IOR || outer_code == XOR) | |
af2c1324 | 3472 | && CONST_OK_FOR_K08 (INTVAL (x))) |
fab7adbf | 3473 | *total = 1; |
5be30882 | 3474 | /* prepare_cmp_insn will force costly constants int registers before |
028b5ee2 | 3475 | the cbranch[sd]i4 patterns can see them, so preserve potentially |
5be30882 | 3476 | interesting ones not covered by I08 above. */ |
3477 | else if (outer_code == COMPARE | |
3478 | && ((unsigned HOST_WIDE_INT) INTVAL (x) | |
3479 | == (unsigned HOST_WIDE_INT) 0x7fffffff + 1 | |
3480 | || INTVAL (x) == 0x7fffffff | |
3481 | || INTVAL (x) == 0x80 || INTVAL (x) == -0x81)) | |
3482 | *total = 1; | |
fab7adbf | 3483 | else |
3484 | *total = 8; | |
3485 | return true; | |
3486 | ||
74cf552d | 3487 | case EQ: |
3488 | /* An and with a constant compared against zero is | |
3489 | most likely going to be a TST #imm, R0 instruction. | |
3490 | Notice that this does not catch the zero_extract variants from | |
3491 | the md file. */ | |
3492 | if (GET_CODE (XEXP (x, 0)) == AND | |
3493 | && CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 0) | |
3494 | { | |
3495 | *total = 1; | |
3496 | return true; | |
a61eea5a | 3497 | } |
3498 | else | |
3499 | return false; | |
3500 | ||
3501 | case SMIN: | |
3502 | case SMAX: | |
3503 | /* This is most likely a clips.b or clips.w insn that is being made up | |
3504 | by combine. */ | |
3505 | if (TARGET_SH2A | |
3506 | && (GET_CODE (XEXP (x, 0)) == SMAX || GET_CODE (XEXP (x, 0)) == SMIN) | |
3507 | && CONST_INT_P (XEXP (XEXP (x, 0), 1)) | |
3508 | && REG_P (XEXP (XEXP (x, 0), 0)) | |
3509 | && CONST_INT_P (XEXP (x, 1))) | |
3510 | { | |
3511 | *total = COSTS_N_INSNS (1); | |
3512 | return true; | |
74cf552d | 3513 | } |
3514 | else | |
3515 | return false; | |
3516 | ||
fab7adbf | 3517 | case CONST: |
3518 | case LABEL_REF: | |
3519 | case SYMBOL_REF: | |
3520 | if (TARGET_SHMEDIA64) | |
6c049e03 | 3521 | *total = COSTS_N_INSNS (4); |
fab7adbf | 3522 | else if (TARGET_SHMEDIA32) |
6c049e03 | 3523 | *total = COSTS_N_INSNS (2); |
fab7adbf | 3524 | else |
3525 | *total = 5; | |
3526 | return true; | |
3527 | ||
3528 | case CONST_DOUBLE: | |
3529 | if (TARGET_SHMEDIA) | |
6c049e03 | 3530 | *total = COSTS_N_INSNS (4); |
5be30882 | 3531 | /* prepare_cmp_insn will force costly constants int registers before |
028b5ee2 | 3532 | the cbranchdi4 pattern can see them, so preserve potentially |
5be30882 | 3533 | interesting ones. */ |
3534 | else if (outer_code == COMPARE && GET_MODE (x) == DImode) | |
6c049e03 | 3535 | *total = 1; |
fab7adbf | 3536 | else |
6c049e03 | 3537 | *total = 10; |
fab7adbf | 3538 | return true; |
b9a94d16 | 3539 | |
59312820 | 3540 | case CONST_VECTOR: |
b9a94d16 | 3541 | /* FIXME: This looks broken. Only the last statement has any effect. |
3542 | Probably this could be folded with the PARALLEL case? */ | |
59312820 | 3543 | if (x == CONST0_RTX (GET_MODE (x))) |
3544 | *total = 0; | |
3545 | else if (sh_1el_vec (x, VOIDmode)) | |
3546 | *total = outer_code != SET; | |
3547 | if (sh_rep_vec (x, VOIDmode)) | |
3548 | *total = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + 3) / 4 | |
3549 | + (outer_code != SET)); | |
3550 | *total = COSTS_N_INSNS (3) + (outer_code != SET); | |
3551 | return true; | |
fab7adbf | 3552 | |
3553 | case PLUS: | |
59312820 | 3554 | case MINUS: |
fab7adbf | 3555 | *total = COSTS_N_INSNS (addsubcosts (x)); |
3556 | return true; | |
3557 | ||
3558 | case AND: | |
f43912de | 3559 | case XOR: |
3560 | case IOR: | |
3561 | *total = COSTS_N_INSNS (and_xor_ior_costs (x, code)); | |
fab7adbf | 3562 | return true; |
3563 | ||
3564 | case MULT: | |
3565 | *total = COSTS_N_INSNS (multcosts (x)); | |
3566 | return true; | |
3567 | ||
59d527df | 3568 | case LT: |
3569 | case GE: | |
3570 | /* div0s sign comparison. */ | |
3571 | if (GET_CODE (XEXP (x, 0)) == XOR | |
3572 | && REG_P ((XEXP (XEXP (x, 0), 0))) | |
3573 | && REG_P ((XEXP (XEXP (x, 0), 1))) | |
3574 | && satisfies_constraint_Z (XEXP (x, 1))) | |
3575 | { | |
3576 | *total = COSTS_N_INSNS (1); | |
3577 | return true; | |
3578 | } | |
3579 | else | |
3580 | return false; | |
3581 | ||
3582 | case LSHIFTRT: | |
3583 | /* div0s sign comparison. */ | |
3584 | if (GET_CODE (XEXP (x, 0)) == XOR | |
3585 | && REG_P ((XEXP (XEXP (x, 0), 0))) | |
3586 | && REG_P ((XEXP (XEXP (x, 0), 1))) | |
3587 | && CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) == 31) | |
3588 | { | |
3589 | *total = COSTS_N_INSNS (1); | |
3590 | return true; | |
3591 | } | |
3592 | /* Fall through to shiftcosts. */ | |
fab7adbf | 3593 | case ASHIFT: |
3594 | case ASHIFTRT: | |
e7768fa5 | 3595 | { |
3596 | int cost = shiftcosts (x); | |
3597 | if (cost < 0) | |
3598 | return false; | |
3599 | *total = COSTS_N_INSNS (cost); | |
3600 | return true; | |
3601 | } | |
fab7adbf | 3602 | |
3603 | case DIV: | |
3604 | case UDIV: | |
3605 | case MOD: | |
3606 | case UMOD: | |
3607 | *total = COSTS_N_INSNS (20); | |
3608 | return true; | |
3609 | ||
3610 | case FLOAT: | |
3611 | case FIX: | |
3612 | *total = 100; | |
3613 | return true; | |
3614 | ||
3615 | default: | |
3616 | return false; | |
3617 | } | |
3618 | } | |
3619 | ||
00868707 | 3620 | /* Determine the size of the fundamental move insn that will be used |
3621 | for the specified mode. */ | |
00868707 | 3622 | static inline int |
3754d046 | 3623 | mov_insn_size (machine_mode mode, bool consider_sh2a) |
00868707 | 3624 | { |
3625 | const int mode_sz = GET_MODE_SIZE (mode); | |
3626 | ||
3627 | if ((consider_sh2a && TARGET_SH2A_DOUBLE && mode == DFmode) | |
3628 | || (TARGET_FMOVD && mode == DFmode)) | |
3629 | return mode_sz; | |
3630 | else | |
3631 | { | |
3632 | /* The max. available mode for actual move insns is SImode. | |
3633 | Larger accesses will be split into multiple loads/stores. */ | |
3634 | const int max_mov_sz = GET_MODE_SIZE (SImode); | |
3635 | return mode_sz >= max_mov_sz ? max_mov_sz : mode_sz; | |
3636 | } | |
3637 | } | |
3638 | ||
3639 | /* Determine the maximum possible displacement for a move insn for the | |
3640 | specified mode. */ | |
9db63610 | 3641 | int |
3642 | sh_max_mov_insn_displacement (machine_mode mode, bool consider_sh2a) | |
ec0457a8 | 3643 | { |
00868707 | 3644 | /* The 4 byte displacement move insns are the same as the 2 byte |
3645 | versions but take a 12 bit displacement. All we need to do is to | |
3646 | scale the max. displacement value accordingly. */ | |
3647 | const int disp_scale = consider_sh2a ? (4095 / 15) : 1; | |
3648 | ||
00868707 | 3649 | /* SH2A supports FPU move insns with 12 bit displacements. |
3650 | Other variants to do not support any kind of displacements for | |
3651 | FPU move insns. */ | |
3652 | if (! consider_sh2a && TARGET_FPU_ANY && GET_MODE_CLASS (mode) == MODE_FLOAT) | |
3653 | return 0; | |
3654 | else | |
3655 | { | |
3656 | const int mov_insn_sz = mov_insn_size (mode, consider_sh2a); | |
3657 | const int mode_sz = GET_MODE_SIZE (mode); | |
3658 | int r = 15 * mov_insn_sz * disp_scale; | |
3659 | ||
3660 | /* If the mov insn will be split into multiple loads/stores, the | |
3661 | maximum possible displacement is a bit smaller. */ | |
3662 | if (mode_sz > mov_insn_sz) | |
3663 | r -= mode_sz - mov_insn_sz; | |
3664 | return r; | |
3665 | } | |
3666 | } | |
89cace00 | 3667 | |
00868707 | 3668 | /* Determine the alignment mask for a move insn of the |
3669 | specified mode. */ | |
00868707 | 3670 | static inline int |
3754d046 | 3671 | mov_insn_alignment_mask (machine_mode mode, bool consider_sh2a) |
00868707 | 3672 | { |
3673 | const int mov_insn_sz = mov_insn_size (mode, consider_sh2a); | |
3674 | return mov_insn_sz > 0 ? (mov_insn_sz - 1) : 0; | |
3675 | } | |
3676 | ||
51bc6b40 | 3677 | /* Return the displacement value of a displacement address. */ |
9db63610 | 3678 | HOST_WIDE_INT |
3679 | sh_disp_addr_displacement (rtx x) | |
51bc6b40 | 3680 | { |
3681 | gcc_assert (satisfies_constraint_Sdd (x)); | |
3682 | return INTVAL (XEXP (XEXP (x, 0), 1)); | |
3683 | } | |
3684 | ||
00868707 | 3685 | /* Compute the cost of an address. */ |
00868707 | 3686 | static int |
3754d046 | 3687 | sh_address_cost (rtx x, machine_mode mode, |
d9c5e5f4 | 3688 | addr_space_t as ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED) |
00868707 | 3689 | { |
3ea038fc | 3690 | /* 'GBR + 0'. Account one more because of R0 restriction. */ |
3691 | if (REG_P (x) && REGNO (x) == GBR_REG) | |
3692 | return 2; | |
3693 | ||
b9a94d16 | 3694 | /* Simple reg, post-inc, pre-dec addressing. */ |
3695 | if (REG_P (x) || GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) | |
3696 | return 1; | |
3697 | ||
00868707 | 3698 | /* 'reg + disp' addressing. */ |
b9a94d16 | 3699 | if (GET_CODE (x) == PLUS |
3700 | && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) | |
00868707 | 3701 | { |
3ea038fc | 3702 | /* 'GBR + disp'. Account one more because of R0 restriction. */ |
3703 | if (REGNO (XEXP (x, 0)) == GBR_REG | |
3704 | && gbr_displacement (XEXP (x, 1), mode)) | |
3705 | return 2; | |
3706 | ||
b9a94d16 | 3707 | const HOST_WIDE_INT offset = INTVAL (XEXP (x, 1)); |
00868707 | 3708 | |
b9a94d16 | 3709 | if (offset == 0) |
3710 | return 1; | |
3711 | ||
3712 | /* The displacement would fit into a 2 byte move insn. | |
3713 | HImode and QImode loads/stores with displacement put pressure on | |
3714 | R0 which will most likely require another reg copy. Thus account | |
3715 | a higher cost for that. */ | |
9db63610 | 3716 | if (offset > 0 && offset <= sh_max_mov_insn_displacement (mode, false)) |
b9a94d16 | 3717 | return (mode == HImode || mode == QImode) ? 2 : 1; |
00868707 | 3718 | |
3719 | /* The displacement would fit into a 4 byte move insn (SH2A). */ | |
3720 | if (TARGET_SH2A | |
9db63610 | 3721 | && offset > 0 && offset <= sh_max_mov_insn_displacement (mode, true)) |
b9a94d16 | 3722 | return 2; |
00868707 | 3723 | |
3724 | /* The displacement is probably out of range and will require extra | |
3725 | calculations. */ | |
b9a94d16 | 3726 | return 3; |
00868707 | 3727 | } |
3728 | ||
3729 | /* 'reg + reg' addressing. Account a slightly higher cost because of | |
3730 | increased pressure on R0. */ | |
3731 | if (GET_CODE (x) == PLUS && ! CONSTANT_P (XEXP (x, 1)) | |
3732 | && ! TARGET_SHMEDIA) | |
b9a94d16 | 3733 | return 3; |
00868707 | 3734 | |
b9a94d16 | 3735 | /* Not sure what it is - probably expensive. */ |
3736 | return 10; | |
ec0457a8 | 3737 | } |
fab7adbf | 3738 | |
1504eb7e | 3739 | /* Code to expand a shift. */ |
bb8e9728 | 3740 | static void |
04f04b72 | 3741 | gen_ashift (int type, int n, rtx reg) |
97595bfd | 3742 | { |
bb8e9728 | 3743 | rtx n_rtx; |
3744 | ||
1504eb7e | 3745 | /* Negative values here come from the shift_amounts array. */ |
3746 | if (n < 0) | |
3747 | { | |
3748 | if (type == ASHIFT) | |
3749 | type = LSHIFTRT; | |
3750 | else | |
3751 | type = ASHIFT; | |
3752 | n = -n; | |
3753 | } | |
3754 | ||
bb8e9728 | 3755 | n_rtx = GEN_INT (n); |
3756 | gcc_assert (satisfies_constraint_P27 (n_rtx)); | |
3757 | ||
97595bfd | 3758 | switch (type) |
7208c779 | 3759 | { |
97595bfd | 3760 | case ASHIFTRT: |
bb8e9728 | 3761 | emit_insn (gen_ashrsi3_k (reg, reg, n_rtx)); |
97595bfd | 3762 | break; |
3763 | case LSHIFTRT: | |
1504eb7e | 3764 | if (n == 1) |
6c049e03 | 3765 | emit_insn (gen_shlr (reg, reg)); |
1504eb7e | 3766 | else |
bb8e9728 | 3767 | emit_insn (gen_lshrsi3_k (reg, reg, n_rtx)); |
97595bfd | 3768 | break; |
3769 | case ASHIFT: | |
bb8e9728 | 3770 | emit_insn (gen_ashlsi3_k (reg, reg, n_rtx)); |
97595bfd | 3771 | break; |
bb8e9728 | 3772 | default: |
3773 | gcc_unreachable (); | |
7208c779 | 3774 | } |
7208c779 | 3775 | } |
7208c779 | 3776 | |
6c049e03 | 3777 | /* Code to expand a HImode shift. */ |
bb8e9728 | 3778 | static void |
04f04b72 | 3779 | gen_ashift_hi (int type, int n, rtx reg) |
2ce8df5a | 3780 | { |
3781 | /* Negative values here come from the shift_amounts array. */ | |
3782 | if (n < 0) | |
3783 | { | |
3784 | if (type == ASHIFT) | |
3785 | type = LSHIFTRT; | |
3786 | else | |
3787 | type = ASHIFT; | |
3788 | n = -n; | |
3789 | } | |
3790 | ||
3791 | switch (type) | |
3792 | { | |
3793 | case ASHIFTRT: | |
2ce8df5a | 3794 | case LSHIFTRT: |
4b9cbc29 | 3795 | /* We don't have HImode right shift operations because using the |
3796 | ordinary 32 bit shift instructions for that doesn't generate proper | |
3797 | zero/sign extension. | |
3798 | gen_ashift_hi is only called in contexts where we know that the | |
3799 | sign extension works out correctly. */ | |
7d175685 | 3800 | { |
701e46d0 | 3801 | int offset = 0; |
7d175685 | 3802 | if (GET_CODE (reg) == SUBREG) |
3803 | { | |
701e46d0 | 3804 | offset = SUBREG_BYTE (reg); |
7d175685 | 3805 | reg = SUBREG_REG (reg); |
3806 | } | |
701e46d0 | 3807 | gen_ashift (type, n, gen_rtx_SUBREG (SImode, reg, offset)); |
7d175685 | 3808 | break; |
3809 | } | |
2ce8df5a | 3810 | case ASHIFT: |
3811 | emit_insn (gen_ashlhi3_k (reg, reg, GEN_INT (n))); | |
3812 | break; | |
3813 | } | |
3814 | } | |
3815 | ||
73401833 | 3816 | /* Output RTL to split a constant shift into its component SH constant |
3817 | shift instructions. */ | |
b7dbbdb2 | 3818 | void |
04f04b72 | 3819 | gen_shifty_op (int code, rtx *operands) |
7208c779 | 3820 | { |
1504eb7e | 3821 | int value = INTVAL (operands[2]); |
73401833 | 3822 | int max, i; |
3dfc1807 | 3823 | |
01515da1 | 3824 | /* Truncate the shift count in case it is out of bounds. */ |
adb906e2 | 3825 | value = value & 31; |
9e7454d0 | 3826 | |
73401833 | 3827 | if (value == 31) |
1504eb7e | 3828 | { |
73401833 | 3829 | if (code == LSHIFTRT) |
97595bfd | 3830 | { |
73401833 | 3831 | emit_insn (gen_rotlsi3_1 (operands[0], operands[0])); |
a6be7821 | 3832 | emit_insn (gen_movt (operands[0], get_t_reg_rtx ())); |
73401833 | 3833 | return; |
1504eb7e | 3834 | } |
73401833 | 3835 | else if (code == ASHIFT) |
1504eb7e | 3836 | { |
73401833 | 3837 | /* There is a two instruction sequence for 31 bit left shifts, |
3838 | but it requires r0. */ | |
cbb16986 | 3839 | if (REG_P (operands[0]) && REGNO (operands[0]) == 0) |
97595bfd | 3840 | { |
73401833 | 3841 | emit_insn (gen_andsi3 (operands[0], operands[0], const1_rtx)); |
3842 | emit_insn (gen_rotlsi3_31 (operands[0], operands[0])); | |
3843 | return; | |
97595bfd | 3844 | } |
1504eb7e | 3845 | } |
73401833 | 3846 | } |
37ad966e | 3847 | else if (value == 0) |
3848 | { | |
59312820 | 3849 | /* This can happen even when optimizing, if there were subregs before |
3850 | reload. Don't output a nop here, as this is never optimized away; | |
3851 | use a no-op move instead. */ | |
3852 | emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[0])); | |
37ad966e | 3853 | return; |
3854 | } | |
4248bee7 | 3855 | |
55c71520 | 3856 | max = ashl_lshr_seq[value].insn_count; |
73401833 | 3857 | for (i = 0; i < max; i++) |
55c71520 | 3858 | gen_ashift (code, ashl_lshr_seq[value].amount[i], operands[0]); |
73401833 | 3859 | } |
9e7454d0 | 3860 | |
6c049e03 | 3861 | /* Same as gen_shifty_op, but optimized for values where the topmost bits |
3862 | don't matter. */ | |
b7dbbdb2 | 3863 | void |
04f04b72 | 3864 | gen_shifty_hi_op (int code, rtx *operands) |
2ce8df5a | 3865 | { |
3866 | int value = INTVAL (operands[2]); | |
3867 | int max, i; | |
04f04b72 | 3868 | void (*gen_fun) (int, int, rtx); |
2ce8df5a | 3869 | |
3870 | /* This operation is used by and_shl for SImode values with a few | |
3871 | high bits known to be cleared. */ | |
3872 | value &= 31; | |
3873 | if (value == 0) | |
3874 | { | |
3875 | emit_insn (gen_nop ()); | |
3876 | return; | |
3877 | } | |
3878 | ||
3879 | gen_fun = GET_MODE (operands[0]) == HImode ? gen_ashift_hi : gen_ashift; | |
3880 | if (code == ASHIFT) | |
3881 | { | |
55c71520 | 3882 | max = ext_ashl_lshr_seq[value].insn_count; |
2ce8df5a | 3883 | for (i = 0; i < max; i++) |
55c71520 | 3884 | gen_fun (code, ext_ashl_lshr_seq[value].amount[i], operands[0]); |
2ce8df5a | 3885 | } |
3886 | else | |
3887 | /* When shifting right, emit the shifts in reverse order, so that | |
3888 | solitary negative values come first. */ | |
55c71520 | 3889 | for (i = ext_ashl_lshr_seq[value].insn_count - 1; i >= 0; i--) |
3890 | gen_fun (code, ext_ashl_lshr_seq[value].amount[i], operands[0]); | |
2ce8df5a | 3891 | } |
73401833 | 3892 | |
6c049e03 | 3893 | /* Output RTL for an arithmetic right shift. |
3894 | ??? Rewrite to use super-optimizer sequences. */ | |
a3b1178e | 3895 | bool |
04f04b72 | 3896 | expand_ashiftrt (rtx *operands) |
73401833 | 3897 | { |
3898 | rtx wrk; | |
3899 | char func[18]; | |
73401833 | 3900 | int value; |
3901 | ||
5e3df43c | 3902 | if (TARGET_DYNSHIFT) |
0b89dfaf | 3903 | { |
cbb16986 | 3904 | if (!CONST_INT_P (operands[2])) |
79f0f2fe | 3905 | { |
3906 | rtx count = copy_to_mode_reg (SImode, operands[2]); | |
3907 | emit_insn (gen_negsi2 (count, count)); | |
3908 | emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); | |
a3b1178e | 3909 | return true; |
79f0f2fe | 3910 | } |
8ded0752 | 3911 | else if (ashiftrt_insns[INTVAL (operands[2]) & 31] |
3912 | > 1 + SH_DYNAMIC_SHIFT_COST) | |
79f0f2fe | 3913 | { |
8ded0752 | 3914 | rtx count |
3915 | = force_reg (SImode, GEN_INT (- (INTVAL (operands[2]) & 31))); | |
79f0f2fe | 3916 | emit_insn (gen_ashrsi3_d (operands[0], operands[1], count)); |
a3b1178e | 3917 | return true; |
79f0f2fe | 3918 | } |
0b89dfaf | 3919 | } |
cbb16986 | 3920 | if (!CONST_INT_P (operands[2])) |
a3b1178e | 3921 | return false; |
73401833 | 3922 | |
8ded0752 | 3923 | value = INTVAL (operands[2]) & 31; |
73401833 | 3924 | |
3925 | if (value == 31) | |
3926 | { | |
59312820 | 3927 | /* If we are called from abs expansion, arrange things so that we |
3928 | we can use a single MT instruction that doesn't clobber the source, | |
3929 | if LICM can hoist out the load of the constant zero. */ | |
3930 | if (currently_expanding_to_rtl) | |
3931 | { | |
3932 | emit_insn (gen_cmpgtsi_t (force_reg (SImode, CONST0_RTX (SImode)), | |
3933 | operands[1])); | |
1f215533 | 3934 | emit_insn (gen_mov_neg_si_t (operands[0], get_t_reg_rtx ())); |
a3b1178e | 3935 | return true; |
59312820 | 3936 | } |
73401833 | 3937 | emit_insn (gen_ashrsi2_31 (operands[0], operands[1])); |
a3b1178e | 3938 | return true; |
73401833 | 3939 | } |
3940 | else if (value >= 16 && value <= 19) | |
3941 | { | |
3942 | wrk = gen_reg_rtx (SImode); | |
3943 | emit_insn (gen_ashrsi2_16 (wrk, operands[1])); | |
3944 | value -= 16; | |
3945 | while (value--) | |
3946 | gen_ashift (ASHIFTRT, 1, wrk); | |
3947 | emit_move_insn (operands[0], wrk); | |
a3b1178e | 3948 | return true; |
4248bee7 | 3949 | } |
73401833 | 3950 | /* Expand a short sequence inline, longer call a magic routine. */ |
3951 | else if (value <= 5) | |
3952 | { | |
3953 | wrk = gen_reg_rtx (SImode); | |
3954 | emit_move_insn (wrk, operands[1]); | |
3955 | while (value--) | |
3956 | gen_ashift (ASHIFTRT, 1, wrk); | |
3957 | emit_move_insn (operands[0], wrk); | |
a3b1178e | 3958 | return true; |
73401833 | 3959 | } |
3960 | ||
3961 | wrk = gen_reg_rtx (Pmode); | |
3962 | ||
3963 | /* Load the value into an arg reg and call a helper. */ | |
7014838c | 3964 | emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]); |
73401833 | 3965 | sprintf (func, "__ashiftrt_r4_%d", value); |
59312820 | 3966 | function_symbol (wrk, func, SFUNC_STATIC); |
73401833 | 3967 | emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk)); |
7014838c | 3968 | emit_move_insn (operands[0], gen_rtx_REG (SImode, 4)); |
a3b1178e | 3969 | return true; |
7208c779 | 3970 | } |
2ce8df5a | 3971 | |
3972 | /* Try to find a good way to implement the combiner pattern | |
3973 | [(set (match_operand:SI 0 "register_operand" "r") | |
3974 | (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") | |
3975 | (match_operand:SI 2 "const_int_operand" "n")) | |
3976 | (match_operand:SI 3 "const_int_operand" "n"))) . | |
3977 | LEFT_RTX is operand 2 in the above pattern, and MASK_RTX is operand 3. | |
3978 | return 0 for simple right / left or left/right shift combination. | |
3979 | return 1 for a combination of shifts with zero_extend. | |
3980 | return 2 for a combination of shifts with an AND that needs r0. | |
3981 | return 3 for a combination of shifts with an AND that needs an extra | |
3982 | scratch register, when the three highmost bits of the AND mask are clear. | |
3983 | return 4 for a combination of shifts with an AND that needs an extra | |
3984 | scratch register, when any of the three highmost bits of the AND mask | |
3985 | is set. | |
3986 | If ATTRP is set, store an initial right shift width in ATTRP[0], | |
3987 | and the instruction length in ATTRP[1] . These values are not valid | |
3988 | when returning 0. | |
3989 | When ATTRP is set and returning 1, ATTRP[2] gets set to the index into | |
3990 | shift_amounts for the last shift value that is to be used before the | |
3991 | sign extend. */ | |
3992 | int | |
04f04b72 | 3993 | shl_and_kind (rtx left_rtx, rtx mask_rtx, int *attrp) |
2ce8df5a | 3994 | { |
3995 | unsigned HOST_WIDE_INT mask, lsb, mask2, lsb2; | |
3996 | int left = INTVAL (left_rtx), right; | |
3997 | int best = 0; | |
3998 | int cost, best_cost = 10000; | |
3999 | int best_right = 0, best_len = 0; | |
4000 | int i; | |
4001 | int can_ext; | |
4002 | ||
4003 | if (left < 0 || left > 31) | |
4004 | return 0; | |
cbb16986 | 4005 | if (CONST_INT_P (mask_rtx)) |
2ce8df5a | 4006 | mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> left; |
4007 | else | |
4008 | mask = (unsigned HOST_WIDE_INT) GET_MODE_MASK (SImode) >> left; | |
d767e27e | 4009 | /* Can this be expressed as a right shift / left shift pair? */ |
2ce8df5a | 4010 | lsb = ((mask ^ (mask - 1)) >> 1) + 1; |
4011 | right = exact_log2 (lsb); | |
4012 | mask2 = ~(mask + lsb - 1); | |
4013 | lsb2 = ((mask2 ^ (mask2 - 1)) >> 1) + 1; | |
4014 | /* mask has no zeroes but trailing zeroes <==> ! mask2 */ | |
4015 | if (! mask2) | |
55c71520 | 4016 | best_cost = ashl_lshr_seq[right].insn_count |
4017 | + ashl_lshr_seq[right + left].insn_count; | |
2ce8df5a | 4018 | /* mask has no trailing zeroes <==> ! right */ |
4019 | else if (! right && mask2 == ~(lsb2 - 1)) | |
4020 | { | |
4021 | int late_right = exact_log2 (lsb2); | |
55c71520 | 4022 | best_cost = ashl_lshr_seq[left + late_right].insn_count |
4023 | + ashl_lshr_seq[late_right].insn_count; | |
2ce8df5a | 4024 | } |
d767e27e | 4025 | /* Try to use zero extend. */ |
2ce8df5a | 4026 | if (mask2 == ~(lsb2 - 1)) |
4027 | { | |
4028 | int width, first; | |
4029 | ||
4030 | for (width = 8; width <= 16; width += 8) | |
4031 | { | |
d767e27e | 4032 | /* Can we zero-extend right away? */ |
4033 | if (lsb2 == (unsigned HOST_WIDE_INT) 1 << width) | |
2ce8df5a | 4034 | { |
55c71520 | 4035 | cost = 1 + ext_ashl_lshr_seq[right].insn_count |
4036 | + ext_ashl_lshr_seq[left + right].insn_count; | |
2ce8df5a | 4037 | if (cost < best_cost) |
4038 | { | |
4039 | best = 1; | |
4040 | best_cost = cost; | |
4041 | best_right = right; | |
4042 | best_len = cost; | |
4043 | if (attrp) | |
4044 | attrp[2] = -1; | |
4045 | } | |
4046 | continue; | |
4047 | } | |
4048 | /* ??? Could try to put zero extend into initial right shift, | |
9df03d69 | 4049 | or even shift a bit left before the right shift. */ |
2ce8df5a | 4050 | /* Determine value of first part of left shift, to get to the |
4051 | zero extend cut-off point. */ | |
4052 | first = width - exact_log2 (lsb2) + right; | |
4053 | if (first >= 0 && right + left - first >= 0) | |
4054 | { | |
55c71520 | 4055 | cost = ext_ashl_lshr_seq[right].insn_count |
4056 | + ext_ashl_lshr_seq[first].insn_count + 1 | |
4057 | + ext_ashl_lshr_seq[right + left - first].insn_count; | |
4058 | ||
2ce8df5a | 4059 | if (cost < best_cost) |
4060 | { | |
4061 | best = 1; | |
4062 | best_cost = cost; | |
4063 | best_right = right; | |
4064 | best_len = cost; | |
4065 | if (attrp) | |
4066 | attrp[2] = first; | |
d767e27e | 4067 | } |
2ce8df5a | 4068 | } |
4069 | } | |
4070 | } | |
4071 | /* Try to use r0 AND pattern */ | |
4072 | for (i = 0; i <= 2; i++) | |
4073 | { | |
4074 | if (i > right) | |
4075 | break; | |
af2c1324 | 4076 | if (! CONST_OK_FOR_K08 (mask >> i)) |
2ce8df5a | 4077 | continue; |
55c71520 | 4078 | cost = (i != 0) + 2 + ext_ashl_lshr_seq[left + i].insn_count; |
2ce8df5a | 4079 | if (cost < best_cost) |
4080 | { | |
4081 | best = 2; | |
4082 | best_cost = cost; | |
4083 | best_right = i; | |
4084 | best_len = cost - 1; | |
4085 | } | |
4086 | } | |
4087 | /* Try to use a scratch register to hold the AND operand. */ | |
d767e27e | 4088 | can_ext = ((mask << left) & ((unsigned HOST_WIDE_INT) 3 << 30)) == 0; |
2ce8df5a | 4089 | for (i = 0; i <= 2; i++) |
4090 | { | |
4091 | if (i > right) | |
4092 | break; | |
af2c1324 | 4093 | cost = (i != 0) + (CONST_OK_FOR_I08 (mask >> i) ? 2 : 3) |
55c71520 | 4094 | + (can_ext |
4095 | ? ext_ashl_lshr_seq | |
4096 | : ashl_lshr_seq)[left + i].insn_count; | |
2ce8df5a | 4097 | if (cost < best_cost) |
4098 | { | |
4099 | best = 4 - can_ext; | |
4100 | best_cost = cost; | |
4101 | best_right = i; | |
af2c1324 | 4102 | best_len = cost - 1 - ! CONST_OK_FOR_I08 (mask >> i); |
2ce8df5a | 4103 | } |
4104 | } | |
4105 | ||
4106 | if (attrp) | |
4107 | { | |
4108 | attrp[0] = best_right; | |
4109 | attrp[1] = best_len; | |
4110 | } | |
4111 | return best; | |
4112 | } | |
4113 | ||
4114 | /* This is used in length attributes of the unnamed instructions | |
4115 | corresponding to shl_and_kind return values of 1 and 2. */ | |
4116 | int | |
04f04b72 | 4117 | shl_and_length (rtx insn) |
2ce8df5a | 4118 | { |
4119 | rtx set_src, left_rtx, mask_rtx; | |
4120 | int attributes[3]; | |
4121 | ||
4122 | set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); | |
4123 | left_rtx = XEXP (XEXP (set_src, 0), 1); | |
4124 | mask_rtx = XEXP (set_src, 1); | |
4125 | shl_and_kind (left_rtx, mask_rtx, attributes); | |
4126 | return attributes[1]; | |
4127 | } | |
4128 | ||
4129 | /* This is used in length attribute of the and_shl_scratch instruction. */ | |
2ce8df5a | 4130 | int |
04f04b72 | 4131 | shl_and_scr_length (rtx insn) |
2ce8df5a | 4132 | { |
4133 | rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); | |
55c71520 | 4134 | int len = ashl_lshr_seq[INTVAL (XEXP (set_src, 1)) & 31].insn_count; |
2ce8df5a | 4135 | rtx op = XEXP (set_src, 0); |
55c71520 | 4136 | len += ashl_lshr_seq[INTVAL (XEXP (op, 1)) & 31].insn_count + 1; |
2ce8df5a | 4137 | op = XEXP (XEXP (op, 0), 0); |
55c71520 | 4138 | return len + ashl_lshr_seq[INTVAL (XEXP (op, 1)) & 31].insn_count; |
2ce8df5a | 4139 | } |
4140 | ||
2ce8df5a | 4141 | /* Generate rtl for instructions for which shl_and_kind advised a particular |
4142 | method of generating them, i.e. returned zero. */ | |
a3b1178e | 4143 | bool |
04f04b72 | 4144 | gen_shl_and (rtx dest, rtx left_rtx, rtx mask_rtx, rtx source) |
2ce8df5a | 4145 | { |
4146 | int attributes[3]; | |
4147 | unsigned HOST_WIDE_INT mask; | |
4148 | int kind = shl_and_kind (left_rtx, mask_rtx, attributes); | |
4149 | int right, total_shift; | |
d767e27e | 4150 | void (*shift_gen_fun) (int, rtx *) = gen_shifty_hi_op; |
2ce8df5a | 4151 | |
4152 | right = attributes[0]; | |
4153 | total_shift = INTVAL (left_rtx) + right; | |
4154 | mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> total_shift; | |
4155 | switch (kind) | |
4156 | { | |
4157 | default: | |
a3b1178e | 4158 | return true; |
2ce8df5a | 4159 | case 1: |
4160 | { | |
4161 | int first = attributes[2]; | |
4162 | rtx operands[3]; | |
4163 | ||
4164 | if (first < 0) | |
4165 | { | |
250fc29e | 4166 | emit_insn ((mask << right) <= 0xff |
d767e27e | 4167 | ? gen_zero_extendqisi2 (dest, |
4168 | gen_lowpart (QImode, source)) | |
4169 | : gen_zero_extendhisi2 (dest, | |
4170 | gen_lowpart (HImode, source))); | |
2ce8df5a | 4171 | source = dest; |
4172 | } | |
4173 | if (source != dest) | |
4174 | emit_insn (gen_movsi (dest, source)); | |
4175 | operands[0] = dest; | |
4176 | if (right) | |
4177 | { | |
4178 | operands[2] = GEN_INT (right); | |
4179 | gen_shifty_hi_op (LSHIFTRT, operands); | |
4180 | } | |
4181 | if (first > 0) | |
4182 | { | |
4183 | operands[2] = GEN_INT (first); | |
4184 | gen_shifty_hi_op (ASHIFT, operands); | |
4185 | total_shift -= first; | |
4186 | mask <<= first; | |
4187 | } | |
4188 | if (first >= 0) | |
c721f167 | 4189 | emit_insn (mask <= 0xff |
d767e27e | 4190 | ? gen_zero_extendqisi2 (dest, gen_lowpart (QImode, dest)) |
4191 | : gen_zero_extendhisi2 (dest, gen_lowpart (HImode, dest))); | |
2ce8df5a | 4192 | if (total_shift > 0) |
4193 | { | |
4194 | operands[2] = GEN_INT (total_shift); | |
4195 | gen_shifty_hi_op (ASHIFT, operands); | |
4196 | } | |
4197 | break; | |
4198 | } | |
4199 | case 4: | |
4200 | shift_gen_fun = gen_shifty_op; | |
2ce8df5a | 4201 | case 3: |
74605264 | 4202 | /* If the topmost bit that matters is set, set the topmost bits |
4203 | that don't matter. This way, we might be able to get a shorter | |
4204 | signed constant. */ | |
d767e27e | 4205 | if (mask & ((HOST_WIDE_INT) 1 << (31 - total_shift))) |
4206 | mask |= (HOST_WIDE_INT) ~0 << (31 - total_shift); | |
f8641a34 | 4207 | case 2: |
2ce8df5a | 4208 | /* Don't expand fine-grained when combining, because that will |
4209 | make the pattern fail. */ | |
723c0ee7 | 4210 | if (currently_expanding_to_rtl |
2ce8df5a | 4211 | || reload_in_progress || reload_completed) |
4212 | { | |
4213 | rtx operands[3]; | |
9e7454d0 | 4214 | |
f8641a34 | 4215 | /* Cases 3 and 4 should be handled by this split |
4216 | only while combining */ | |
1a6a7a27 | 4217 | gcc_assert (kind <= 2); |
2ce8df5a | 4218 | if (right) |
4219 | { | |
4220 | emit_insn (gen_lshrsi3 (dest, source, GEN_INT (right))); | |
4221 | source = dest; | |
4222 | } | |
4223 | emit_insn (gen_andsi3 (dest, source, GEN_INT (mask))); | |
2d7f129b | 4224 | if (total_shift) |
4225 | { | |
4226 | operands[0] = dest; | |
4227 | operands[1] = dest; | |
4228 | operands[2] = GEN_INT (total_shift); | |
4229 | shift_gen_fun (ASHIFT, operands); | |
4230 | } | |
2ce8df5a | 4231 | break; |
4232 | } | |
4233 | else | |
4234 | { | |
4235 | int neg = 0; | |
4236 | if (kind != 4 && total_shift < 16) | |
4237 | { | |
55c71520 | 4238 | neg = -ext_ashl_lshr_seq[total_shift].amount[1]; |
2ce8df5a | 4239 | if (neg > 0) |
55c71520 | 4240 | neg -= ext_ashl_lshr_seq[total_shift].amount[2]; |
2ce8df5a | 4241 | else |
4242 | neg = 0; | |
4243 | } | |
4244 | emit_insn (gen_and_shl_scratch (dest, source, | |
4245 | GEN_INT (right), | |
4246 | GEN_INT (mask), | |
4247 | GEN_INT (total_shift + neg), | |
4248 | GEN_INT (neg))); | |
4249 | emit_insn (gen_movsi (dest, dest)); | |
4250 | break; | |
4251 | } | |
4252 | } | |
a3b1178e | 4253 | return false; |
2ce8df5a | 4254 | } |
4255 | ||
4256 | /* Try to find a good way to implement the combiner pattern | |
4257 | [(set (match_operand:SI 0 "register_operand" "=r") | |
4258 | (sign_extract:SI (ashift:SI (match_operand:SI 1 "register_operand" "r") | |
4259 | (match_operand:SI 2 "const_int_operand" "n") | |
4260 | (match_operand:SI 3 "const_int_operand" "n") | |
4261 | (const_int 0))) | |
a5bd34f1 | 4262 | (clobber (reg:SI T_REG))] |
2ce8df5a | 4263 | LEFT_RTX is operand 2 in the above pattern, and SIZE_RTX is operand 3. |
4264 | return 0 for simple left / right shift combination. | |
4265 | return 1 for left shift / 8 bit sign extend / left shift. | |
4266 | return 2 for left shift / 16 bit sign extend / left shift. | |
4267 | return 3 for left shift / 8 bit sign extend / shift / sign extend. | |
4268 | return 4 for left shift / 16 bit sign extend / shift / sign extend. | |
4269 | return 5 for left shift / 16 bit sign extend / right shift | |
4270 | return 6 for < 8 bit sign extend / left shift. | |
4271 | return 7 for < 8 bit sign extend / left shift / single right shift. | |
4272 | If COSTP is nonzero, assign the calculated cost to *COSTP. */ | |
2ce8df5a | 4273 | int |
04f04b72 | 4274 | shl_sext_kind (rtx left_rtx, rtx size_rtx, int *costp) |
2ce8df5a | 4275 | { |
4276 | int left, size, insize, ext; | |
87ed74ef | 4277 | int cost = 0, best_cost; |
2ce8df5a | 4278 | int kind; |
4279 | ||
4280 | left = INTVAL (left_rtx); | |
4281 | size = INTVAL (size_rtx); | |
4282 | insize = size - left; | |
1a6a7a27 | 4283 | gcc_assert (insize > 0); |
2ce8df5a | 4284 | /* Default to left / right shift. */ |
4285 | kind = 0; | |
55c71520 | 4286 | best_cost = ashl_lshr_seq[32 - insize].insn_count |
4287 | + ashl_lshr_seq[32 - size].insn_count; | |
2ce8df5a | 4288 | if (size <= 16) |
4289 | { | |
4290 | /* 16 bit shift / sign extend / 16 bit shift */ | |
55c71520 | 4291 | cost = ashl_lshr_seq[16 - insize].insn_count + 1 |
4292 | + ashl_lshr_seq[16 - size].insn_count; | |
2d7f129b | 4293 | /* If ashiftrt_insns[16 - size] is 8, this choice will be overridden |
4294 | below, by alternative 3 or something even better. */ | |
2ce8df5a | 4295 | if (cost < best_cost) |
4296 | { | |
4297 | kind = 5; | |
4298 | best_cost = cost; | |
4299 | } | |
4300 | } | |
4301 | /* Try a plain sign extend between two shifts. */ | |
4302 | for (ext = 16; ext >= insize; ext -= 8) | |
4303 | { | |
4304 | if (ext <= size) | |
4305 | { | |
55c71520 | 4306 | cost = ext_ashl_lshr_seq[ext - insize].insn_count + 1 |
4307 | + ashl_lshr_seq[size - ext].insn_count; | |
2ce8df5a | 4308 | if (cost < best_cost) |
4309 | { | |
30435bf8 | 4310 | kind = ext / (unsigned) 8; |
2ce8df5a | 4311 | best_cost = cost; |
4312 | } | |
4313 | } | |
69b02875 | 4314 | /* Check if we can do a sloppy shift with a final signed shift |
4315 | restoring the sign. */ | |
4316 | if (EXT_SHIFT_SIGNED (size - ext)) | |
55c71520 | 4317 | cost = ext_ashl_lshr_seq[ext - insize].insn_count |
4318 | + ext_ashl_lshr_seq[size - ext].insn_count + 1; | |
69b02875 | 4319 | /* If not, maybe it's still cheaper to do the second shift sloppy, |
4320 | and do a final sign extend? */ | |
4321 | else if (size <= 16) | |
55c71520 | 4322 | cost = ext_ashl_lshr_seq[ext - insize].insn_count + 1 |
4323 | + ext_ashl_lshr_seq[size > ext ? size - ext : ext - size].insn_count | |
4324 | + 1; | |
69b02875 | 4325 | else |
4326 | continue; | |
4327 | if (cost < best_cost) | |
2ce8df5a | 4328 | { |
30435bf8 | 4329 | kind = ext / (unsigned) 8 + 2; |
69b02875 | 4330 | best_cost = cost; |
2ce8df5a | 4331 | } |
4332 | } | |
4333 | /* Check if we can sign extend in r0 */ | |
4334 | if (insize < 8) | |
4335 | { | |
55c71520 | 4336 | cost = 3 + ashl_lshr_seq[left].insn_count; |
2ce8df5a | 4337 | if (cost < best_cost) |
4338 | { | |
4339 | kind = 6; | |
4340 | best_cost = cost; | |
4341 | } | |
4342 | /* Try the same with a final signed shift. */ | |
4343 | if (left < 31) | |
4344 | { | |
55c71520 | 4345 | cost = 3 + ext_ashl_lshr_seq[left + 1].insn_count + 1; |
2ce8df5a | 4346 | if (cost < best_cost) |
4347 | { | |
4348 | kind = 7; | |
4349 | best_cost = cost; | |
4350 | } | |
4351 | } | |
4352 | } | |
5e3df43c | 4353 | if (TARGET_DYNSHIFT) |
2ce8df5a | 4354 | { |
4355 | /* Try to use a dynamic shift. */ | |
55c71520 | 4356 | cost = ashl_lshr_seq[32 - insize].insn_count + 1 + SH_DYNAMIC_SHIFT_COST; |
2ce8df5a | 4357 | if (cost < best_cost) |
4358 | { | |
4359 | kind = 0; | |
4360 | best_cost = cost; | |
4361 | } | |
4362 | } | |
4363 | if (costp) | |
4364 | *costp = cost; | |
4365 | return kind; | |
4366 | } | |
4367 | ||
4368 | /* Function to be used in the length attribute of the instructions | |
4369 | implementing this pattern. */ | |
2ce8df5a | 4370 | int |
04f04b72 | 4371 | shl_sext_length (rtx insn) |
2ce8df5a | 4372 | { |
4373 | rtx set_src, left_rtx, size_rtx; | |
4374 | int cost; | |
4375 | ||
4376 | set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); | |
4377 | left_rtx = XEXP (XEXP (set_src, 0), 1); | |
4378 | size_rtx = XEXP (set_src, 1); | |
4379 | shl_sext_kind (left_rtx, size_rtx, &cost); | |
4380 | return cost; | |
4381 | } | |
4382 | ||
4383 | /* Generate rtl for this pattern */ | |
a3b1178e | 4384 | bool |
04f04b72 | 4385 | gen_shl_sext (rtx dest, rtx left_rtx, rtx size_rtx, rtx source) |
2ce8df5a | 4386 | { |
4387 | int kind; | |
1a47e85b | 4388 | int left, size, insize, cost; |
2ce8df5a | 4389 | rtx operands[3]; |
4390 | ||
1a47e85b | 4391 | kind = shl_sext_kind (left_rtx, size_rtx, &cost); |
2ce8df5a | 4392 | left = INTVAL (left_rtx); |
4393 | size = INTVAL (size_rtx); | |
4394 | insize = size - left; | |
4395 | switch (kind) | |
4396 | { | |
4397 | case 1: | |
4398 | case 2: | |
4399 | case 3: | |
4400 | case 4: | |
4401 | { | |
4402 | int ext = kind & 1 ? 8 : 16; | |
4403 | int shift2 = size - ext; | |
4404 | ||
4405 | /* Don't expand fine-grained when combining, because that will | |
4406 | make the pattern fail. */ | |
723c0ee7 | 4407 | if (! currently_expanding_to_rtl |
2ce8df5a | 4408 | && ! reload_in_progress && ! reload_completed) |
4409 | { | |
4410 | emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx)); | |
4411 | emit_insn (gen_movsi (dest, source)); | |
4412 | break; | |
4413 | } | |
4414 | if (dest != source) | |
4415 | emit_insn (gen_movsi (dest, source)); | |
4416 | operands[0] = dest; | |
2d7f129b | 4417 | if (ext - insize) |
4418 | { | |
4419 | operands[2] = GEN_INT (ext - insize); | |
4420 | gen_shifty_hi_op (ASHIFT, operands); | |
4421 | } | |
2ce8df5a | 4422 | emit_insn (kind & 1 |
d767e27e | 4423 | ? gen_extendqisi2 (dest, gen_lowpart (QImode, dest)) |
4424 | : gen_extendhisi2 (dest, gen_lowpart (HImode, dest))); | |
2ce8df5a | 4425 | if (kind <= 2) |
4426 | { | |
2d7f129b | 4427 | if (shift2) |
4428 | { | |
4429 | operands[2] = GEN_INT (shift2); | |
4430 | gen_shifty_op (ASHIFT, operands); | |
4431 | } | |
2ce8df5a | 4432 | } |
4433 | else | |
4434 | { | |
2d7f129b | 4435 | if (shift2 > 0) |
2ce8df5a | 4436 | { |
69b02875 | 4437 | if (EXT_SHIFT_SIGNED (shift2)) |
4438 | { | |
4439 | operands[2] = GEN_INT (shift2 + 1); | |
4440 | gen_shifty_op (ASHIFT, operands); | |
bcd9bd66 | 4441 | operands[2] = const1_rtx; |
69b02875 | 4442 | gen_shifty_op (ASHIFTRT, operands); |
4443 | break; | |
4444 | } | |
2ce8df5a | 4445 | operands[2] = GEN_INT (shift2); |
4446 | gen_shifty_hi_op (ASHIFT, operands); | |
4447 | } | |
2d7f129b | 4448 | else if (shift2) |
2ce8df5a | 4449 | { |
4450 | operands[2] = GEN_INT (-shift2); | |
4451 | gen_shifty_hi_op (LSHIFTRT, operands); | |
4452 | } | |
4453 | emit_insn (size <= 8 | |
2d7f129b | 4454 | ? gen_extendqisi2 (dest, gen_lowpart (QImode, dest)) |
4455 | : gen_extendhisi2 (dest, gen_lowpart (HImode, dest))); | |
2ce8df5a | 4456 | } |
4457 | break; | |
4458 | } | |
4459 | case 5: | |
2d7f129b | 4460 | { |
4461 | int i = 16 - size; | |
723c0ee7 | 4462 | if (! currently_expanding_to_rtl |
f2bfaeea | 4463 | && ! reload_in_progress && ! reload_completed) |
4464 | emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx)); | |
4465 | else | |
4466 | { | |
4467 | operands[0] = dest; | |
4468 | operands[2] = GEN_INT (16 - insize); | |
4469 | gen_shifty_hi_op (ASHIFT, operands); | |
4470 | emit_insn (gen_extendhisi2 (dest, gen_lowpart (HImode, dest))); | |
4471 | } | |
2d7f129b | 4472 | /* Don't use gen_ashrsi3 because it generates new pseudos. */ |
4473 | while (--i >= 0) | |
4474 | gen_ashift (ASHIFTRT, 1, dest); | |
4475 | break; | |
4476 | } | |
2ce8df5a | 4477 | case 6: |
4478 | case 7: | |
4479 | /* Don't expand fine-grained when combining, because that will | |
4480 | make the pattern fail. */ | |
723c0ee7 | 4481 | if (! currently_expanding_to_rtl |
2ce8df5a | 4482 | && ! reload_in_progress && ! reload_completed) |
4483 | { | |
4484 | emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx)); | |
4485 | emit_insn (gen_movsi (dest, source)); | |
4486 | break; | |
4487 | } | |
4488 | emit_insn (gen_andsi3 (dest, source, GEN_INT ((1 << insize) - 1))); | |
4489 | emit_insn (gen_xorsi3 (dest, dest, GEN_INT (1 << (insize - 1)))); | |
4490 | emit_insn (gen_addsi3 (dest, dest, GEN_INT (-1 << (insize - 1)))); | |
4491 | operands[0] = dest; | |
4492 | operands[2] = kind == 7 ? GEN_INT (left + 1) : left_rtx; | |
4493 | gen_shifty_op (ASHIFT, operands); | |
4494 | if (kind == 7) | |
bcd9bd66 | 4495 | emit_insn (gen_ashrsi3_k (dest, dest, const1_rtx)); |
2ce8df5a | 4496 | break; |
4497 | default: | |
a3b1178e | 4498 | return true; |
2ce8df5a | 4499 | } |
a3b1178e | 4500 | return false; |
2ce8df5a | 4501 | } |
87e19636 | 4502 | |
4503 | /* Prefix a symbol_ref name with "datalabel". */ | |
87e19636 | 4504 | rtx |
04f04b72 | 4505 | gen_datalabel_ref (rtx sym) |
87e19636 | 4506 | { |
59312820 | 4507 | const char *str; |
4508 | ||
87e19636 | 4509 | if (GET_CODE (sym) == LABEL_REF) |
4510 | return gen_rtx_CONST (GET_MODE (sym), | |
4511 | gen_rtx_UNSPEC (GET_MODE (sym), | |
4512 | gen_rtvec (1, sym), | |
4513 | UNSPEC_DATALABEL)); | |
9e7454d0 | 4514 | |
1a6a7a27 | 4515 | gcc_assert (GET_CODE (sym) == SYMBOL_REF); |
87e19636 | 4516 | |
59312820 | 4517 | str = XSTR (sym, 0); |
4518 | /* Share all SYMBOL_REF strings with the same value - that is important | |
4519 | for cse. */ | |
4520 | str = IDENTIFIER_POINTER (get_identifier (str)); | |
4521 | XSTR (sym, 0) = str; | |
4522 | ||
87e19636 | 4523 | return sym; |
4524 | } | |
4525 | ||
73401833 | 4526 | \f |
49166fc3 | 4527 | static alloc_pool label_ref_list_pool; |
4528 | ||
4529 | typedef struct label_ref_list_d | |
4530 | { | |
b82334f7 | 4531 | rtx_code_label *label; |
49166fc3 | 4532 | struct label_ref_list_d *next; |
4533 | } *label_ref_list_t; | |
4534 | ||
73401833 | 4535 | /* The SH cannot load a large constant into a register, constants have to |
4536 | come from a pc relative load. The reference of a pc relative load | |
442e3cb9 | 4537 | instruction must be less than 1k in front of the instruction. This |
73401833 | 4538 | means that we often have to dump a constant inside a function, and |
4539 | generate code to branch around it. | |
7208c779 | 4540 | |
73401833 | 4541 | It is important to minimize this, since the branches will slow things |
4542 | down and make things bigger. | |
4543 | ||
4544 | Worst case code looks like: | |
4545 | ||
4546 | mov.l L1,rn | |
4547 | bra L2 | |
4548 | nop | |
4549 | align | |
4550 | L1: .long value | |
4551 | L2: | |
4552 | .. | |
4553 | ||
4554 | mov.l L3,rn | |
4555 | bra L4 | |
4556 | nop | |
4557 | align | |
4558 | L3: .long value | |
4559 | L4: | |
4560 | .. | |
4561 | ||
4562 | We fix this by performing a scan before scheduling, which notices which | |
4563 | instructions need to have their operands fetched from the constant table | |
4564 | and builds the table. | |
4565 | ||
4566 | The algorithm is: | |
4567 | ||
4568 | scan, find an instruction which needs a pcrel move. Look forward, find the | |
4569 | last barrier which is within MAX_COUNT bytes of the requirement. | |
4570 | If there isn't one, make one. Process all the instructions between | |
4571 | the find and the barrier. | |
4572 | ||
4573 | In the above example, we can tell that L3 is within 1k of L1, so | |
4574 | the first move can be shrunk from the 3 insn+constant sequence into | |
4575 | just 1 insn, and the constant moved to L3 to make: | |
4576 | ||
4577 | mov.l L1,rn | |
4578 | .. | |
4579 | mov.l L3,rn | |
4580 | bra L4 | |
4581 | nop | |
4582 | align | |
4583 | L3:.long value | |
4584 | L4:.long value | |
4585 | ||
4586 | Then the second move becomes the target for the shortening process. */ | |
4587 | ||
4588 | typedef struct | |
4589 | { | |
4590 | rtx value; /* Value in table. */ | |
b82334f7 | 4591 | rtx_code_label *label; /* Label of value. */ |
49166fc3 | 4592 | label_ref_list_t wend; /* End of window. */ |
3754d046 | 4593 | machine_mode mode; /* Mode of value. */ |
c5ea35c4 | 4594 | |
4595 | /* True if this constant is accessed as part of a post-increment | |
4596 | sequence. Note that HImode constants are never accessed in this way. */ | |
4597 | bool part_of_sequence_p; | |
73401833 | 4598 | } pool_node; |
4599 | ||
4600 | /* The maximum number of constants that can fit into one pool, since | |
59312820 | 4601 | constants in the range 0..510 are at least 2 bytes long, and in the |
4602 | range from there to 1018 at least 4 bytes. */ | |
73401833 | 4603 | |
59312820 | 4604 | #define MAX_POOL_SIZE 372 |
73401833 | 4605 | static pool_node pool_vector[MAX_POOL_SIZE]; |
4606 | static int pool_size; | |
b82334f7 | 4607 | static rtx_code_label *pool_window_label; |
ecf6ff7c | 4608 | static int pool_window_last; |
73401833 | 4609 | |
be7f5947 | 4610 | static int max_labelno_before_reorg; |
4611 | ||
73401833 | 4612 | /* ??? If we need a constant in HImode which is the truncated value of a |
4613 | constant we need in SImode, we could combine the two entries thus saving | |
4614 | two bytes. Is this common enough to be worth the effort of implementing | |
4615 | it? */ | |
4616 | ||
4617 | /* ??? This stuff should be done at the same time that we shorten branches. | |
4618 | As it is now, we must assume that all branches are the maximum size, and | |
4619 | this causes us to almost always output constant pools sooner than | |
4620 | necessary. */ | |
4621 | ||
4622 | /* Add a constant to the pool and return its label. */ | |
b82334f7 | 4623 | static rtx_code_label * |
3754d046 | 4624 | add_constant (rtx x, machine_mode mode, rtx last_value) |
97595bfd | 4625 | { |
4626 | int i; | |
b82334f7 | 4627 | rtx_code_label *lab, *new_rtx; |
49166fc3 | 4628 | label_ref_list_t ref, newref; |
73401833 | 4629 | |
4630 | /* First see if we've already got it. */ | |
4631 | for (i = 0; i < pool_size; i++) | |
97595bfd | 4632 | { |
73401833 | 4633 | if (x->code == pool_vector[i].value->code |
4634 | && mode == pool_vector[i].mode) | |
97595bfd | 4635 | { |
73401833 | 4636 | if (x->code == CODE_LABEL) |
4637 | { | |
4638 | if (XINT (x, 3) != XINT (pool_vector[i].value, 3)) | |
4639 | continue; | |
4640 | } | |
4641 | if (rtx_equal_p (x, pool_vector[i].value)) | |
1b61190c | 4642 | { |
8deb3959 | 4643 | lab = new_rtx = 0; |
1b61190c | 4644 | if (! last_value |
4645 | || ! i | |
4646 | || ! rtx_equal_p (last_value, pool_vector[i-1].value)) | |
4647 | { | |
8deb3959 | 4648 | new_rtx = gen_label_rtx (); |
4649 | LABEL_REFS (new_rtx) = pool_vector[i].label; | |
4650 | pool_vector[i].label = lab = new_rtx; | |
1b61190c | 4651 | } |
ecf6ff7c | 4652 | if (lab && pool_window_label) |
4653 | { | |
49166fc3 | 4654 | newref = (label_ref_list_t) pool_alloc (label_ref_list_pool); |
4655 | newref->label = pool_window_label; | |
ecf6ff7c | 4656 | ref = pool_vector[pool_window_last].wend; |
49166fc3 | 4657 | newref->next = ref; |
ecf6ff7c | 4658 | pool_vector[pool_window_last].wend = newref; |
4659 | } | |
8deb3959 | 4660 | if (new_rtx) |
4661 | pool_window_label = new_rtx; | |
ecf6ff7c | 4662 | pool_window_last = i; |
1b61190c | 4663 | return lab; |
4664 | } | |
97595bfd | 4665 | } |
97595bfd | 4666 | } |
47c009e5 | 4667 | |
73401833 | 4668 | /* Need a new one. */ |
4669 | pool_vector[pool_size].value = x; | |
1b61190c | 4670 | if (last_value && rtx_equal_p (last_value, pool_vector[pool_size - 1].value)) |
c5ea35c4 | 4671 | { |
4672 | lab = 0; | |
4673 | pool_vector[pool_size - 1].part_of_sequence_p = true; | |
4674 | } | |
1b61190c | 4675 | else |
4676 | lab = gen_label_rtx (); | |
73401833 | 4677 | pool_vector[pool_size].mode = mode; |
4678 | pool_vector[pool_size].label = lab; | |
49166fc3 | 4679 | pool_vector[pool_size].wend = NULL; |
c5ea35c4 | 4680 | pool_vector[pool_size].part_of_sequence_p = (lab == 0); |
ecf6ff7c | 4681 | if (lab && pool_window_label) |
4682 | { | |
49166fc3 | 4683 | newref = (label_ref_list_t) pool_alloc (label_ref_list_pool); |
4684 | newref->label = pool_window_label; | |
ecf6ff7c | 4685 | ref = pool_vector[pool_window_last].wend; |
49166fc3 | 4686 | newref->next = ref; |
ecf6ff7c | 4687 | pool_vector[pool_window_last].wend = newref; |
4688 | } | |
4689 | if (lab) | |
4690 | pool_window_label = lab; | |
4691 | pool_window_last = pool_size; | |
73401833 | 4692 | pool_size++; |
4693 | return lab; | |
97595bfd | 4694 | } |
1504eb7e | 4695 | |
51dade95 | 4696 | /* Output the literal table. START, if nonzero, is the first instruction |
4697 | this table is needed for, and also indicates that there is at least one | |
4698 | casesi_worker_2 instruction; We have to emit the operand3 labels from | |
4699 | these insns at a 4-byte aligned position. BARRIER is the barrier | |
4700 | after which we are to place the table. */ | |
47c009e5 | 4701 | static void |
b82334f7 | 4702 | dump_table (rtx_insn *start, rtx_insn *barrier) |
47c009e5 | 4703 | { |
b82334f7 | 4704 | rtx_insn *scan = barrier; |
97595bfd | 4705 | int i; |
c3583c9c | 4706 | bool need_align = true; |
49166fc3 | 4707 | rtx lab; |
4708 | label_ref_list_t ref; | |
c3583c9c | 4709 | bool have_df = false; |
47c009e5 | 4710 | |
1504eb7e | 4711 | /* Do two passes, first time dump out the HI sized constants. */ |
47c009e5 | 4712 | |
97595bfd | 4713 | for (i = 0; i < pool_size; i++) |
47c009e5 | 4714 | { |
73401833 | 4715 | pool_node *p = &pool_vector[i]; |
4716 | ||
97595bfd | 4717 | if (p->mode == HImode) |
4718 | { | |
4719 | if (need_align) | |
4720 | { | |
4721 | scan = emit_insn_after (gen_align_2 (), scan); | |
c3583c9c | 4722 | need_align = false; |
97595bfd | 4723 | } |
ecf6ff7c | 4724 | for (lab = p->label; lab; lab = LABEL_REFS (lab)) |
4725 | scan = emit_label_after (lab, scan); | |
4726 | scan = emit_insn_after (gen_consttable_2 (p->value, const0_rtx), | |
4727 | scan); | |
49166fc3 | 4728 | for (ref = p->wend; ref; ref = ref->next) |
ecf6ff7c | 4729 | { |
49166fc3 | 4730 | lab = ref->label; |
ecf6ff7c | 4731 | scan = emit_insn_after (gen_consttable_window_end (lab), scan); |
4732 | } | |
97595bfd | 4733 | } |
d1b048f6 | 4734 | else if (p->mode == DFmode) |
c3583c9c | 4735 | have_df = true; |
47c009e5 | 4736 | } |
73401833 | 4737 | |
c3583c9c | 4738 | need_align = true; |
47c009e5 | 4739 | |
51dade95 | 4740 | if (start) |
4741 | { | |
4742 | scan = emit_insn_after (gen_align_4 (), scan); | |
c3583c9c | 4743 | need_align = false; |
51dade95 | 4744 | for (; start != barrier; start = NEXT_INSN (start)) |
cbb16986 | 4745 | if (NONJUMP_INSN_P (start) |
51dade95 | 4746 | && recog_memoized (start) == CODE_FOR_casesi_worker_2) |
4747 | { | |
4748 | rtx src = SET_SRC (XVECEXP (PATTERN (start), 0, 0)); | |
4749 | rtx lab = XEXP (XVECEXP (src, 0, 3), 0); | |
4750 | ||
4751 | scan = emit_label_after (lab, scan); | |
4752 | } | |
4753 | } | |
d1b048f6 | 4754 | if (TARGET_FMOVD && TARGET_ALIGN_DOUBLE && have_df) |
87e19636 | 4755 | { |
158a522b | 4756 | rtx_insn *align_insn = NULL; |
87e19636 | 4757 | |
4758 | scan = emit_label_after (gen_label_rtx (), scan); | |
4759 | scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan); | |
c3583c9c | 4760 | need_align = false; |
87e19636 | 4761 | |
4762 | for (i = 0; i < pool_size; i++) | |
4763 | { | |
4764 | pool_node *p = &pool_vector[i]; | |
4765 | ||
4766 | switch (p->mode) | |
4767 | { | |
4768 | case HImode: | |
4769 | break; | |
4770 | case SImode: | |
4771 | case SFmode: | |
c5ea35c4 | 4772 | if (align_insn && !p->part_of_sequence_p) |
87e19636 | 4773 | { |
4774 | for (lab = p->label; lab; lab = LABEL_REFS (lab)) | |
4775 | emit_label_before (lab, align_insn); | |
4776 | emit_insn_before (gen_consttable_4 (p->value, const0_rtx), | |
4777 | align_insn); | |
49166fc3 | 4778 | for (ref = p->wend; ref; ref = ref->next) |
87e19636 | 4779 | { |
49166fc3 | 4780 | lab = ref->label; |
87e19636 | 4781 | emit_insn_before (gen_consttable_window_end (lab), |
d767e27e | 4782 | align_insn); |
87e19636 | 4783 | } |
4784 | delete_insn (align_insn); | |
158a522b | 4785 | align_insn = NULL; |
87e19636 | 4786 | continue; |
4787 | } | |
4788 | else | |
4789 | { | |
4790 | for (lab = p->label; lab; lab = LABEL_REFS (lab)) | |
4791 | scan = emit_label_after (lab, scan); | |
4792 | scan = emit_insn_after (gen_consttable_4 (p->value, | |
4793 | const0_rtx), scan); | |
4794 | need_align = ! need_align; | |
4795 | } | |
4796 | break; | |
4797 | case DFmode: | |
87e19636 | 4798 | if (need_align) |
4799 | { | |
4800 | scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan); | |
4801 | align_insn = scan; | |
c3583c9c | 4802 | need_align = false; |
87e19636 | 4803 | } |
d1b048f6 | 4804 | case DImode: |
87e19636 | 4805 | for (lab = p->label; lab; lab = LABEL_REFS (lab)) |
4806 | scan = emit_label_after (lab, scan); | |
4807 | scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx), | |
4808 | scan); | |
4809 | break; | |
4810 | default: | |
1a6a7a27 | 4811 | gcc_unreachable (); |
87e19636 | 4812 | } |
4813 | ||
4814 | if (p->mode != HImode) | |
4815 | { | |
49166fc3 | 4816 | for (ref = p->wend; ref; ref = ref->next) |
87e19636 | 4817 | { |
49166fc3 | 4818 | lab = ref->label; |
87e19636 | 4819 | scan = emit_insn_after (gen_consttable_window_end (lab), |
4820 | scan); | |
4821 | } | |
4822 | } | |
4823 | } | |
4824 | ||
4825 | pool_size = 0; | |
4826 | } | |
9e7454d0 | 4827 | |
97595bfd | 4828 | for (i = 0; i < pool_size; i++) |
47c009e5 | 4829 | { |
73401833 | 4830 | pool_node *p = &pool_vector[i]; |
47c009e5 | 4831 | |
97595bfd | 4832 | switch (p->mode) |
47c009e5 | 4833 | { |
97595bfd | 4834 | case HImode: |
4835 | break; | |
4836 | case SImode: | |
00f87557 | 4837 | case SFmode: |
97595bfd | 4838 | if (need_align) |
47c009e5 | 4839 | { |
c3583c9c | 4840 | need_align = false; |
f3d93547 | 4841 | scan = emit_label_after (gen_label_rtx (), scan); |
97595bfd | 4842 | scan = emit_insn_after (gen_align_4 (), scan); |
47c009e5 | 4843 | } |
ecf6ff7c | 4844 | for (lab = p->label; lab; lab = LABEL_REFS (lab)) |
4845 | scan = emit_label_after (lab, scan); | |
4846 | scan = emit_insn_after (gen_consttable_4 (p->value, const0_rtx), | |
4847 | scan); | |
97595bfd | 4848 | break; |
00f87557 | 4849 | case DFmode: |
97595bfd | 4850 | case DImode: |
4851 | if (need_align) | |
4852 | { | |
c3583c9c | 4853 | need_align = false; |
f3d93547 | 4854 | scan = emit_label_after (gen_label_rtx (), scan); |
97595bfd | 4855 | scan = emit_insn_after (gen_align_4 (), scan); |
4856 | } | |
ecf6ff7c | 4857 | for (lab = p->label; lab; lab = LABEL_REFS (lab)) |
4858 | scan = emit_label_after (lab, scan); | |
4859 | scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx), | |
4860 | scan); | |
97595bfd | 4861 | break; |
4862 | default: | |
1a6a7a27 | 4863 | gcc_unreachable (); |
47c009e5 | 4864 | } |
ecf6ff7c | 4865 | |
4866 | if (p->mode != HImode) | |
4867 | { | |
49166fc3 | 4868 | for (ref = p->wend; ref; ref = ref->next) |
ecf6ff7c | 4869 | { |
49166fc3 | 4870 | lab = ref->label; |
ecf6ff7c | 4871 | scan = emit_insn_after (gen_consttable_window_end (lab), scan); |
4872 | } | |
4873 | } | |
47c009e5 | 4874 | } |
47c009e5 | 4875 | |
97595bfd | 4876 | scan = emit_insn_after (gen_consttable_end (), scan); |
4877 | scan = emit_barrier_after (scan); | |
4878 | pool_size = 0; | |
b82334f7 | 4879 | pool_window_label = NULL; |
ecf6ff7c | 4880 | pool_window_last = 0; |
97595bfd | 4881 | } |
47c009e5 | 4882 | |
be7f5947 | 4883 | #define MOVA_LABELREF(mova) XVECEXP (SET_SRC (PATTERN (mova)), 0, 0) |
4884 | ||
808a491c | 4885 | /* Nonzero if the insn is a move instruction which needs to be fixed. */ |
73401833 | 4886 | |
4887 | /* ??? For a DImode/DFmode moves, we don't need to fix it if each half of the | |
af2c1324 | 4888 | CONST_DOUBLE input value is CONST_OK_FOR_I08. For a SFmode move, we don't |
4889 | need to fix it if the input value is CONST_OK_FOR_I08. */ | |
a3b1178e | 4890 | static bool |
b82334f7 | 4891 | broken_move (rtx_insn *insn) |
47c009e5 | 4892 | { |
cbb16986 | 4893 | if (NONJUMP_INSN_P (insn)) |
00f87557 | 4894 | { |
4895 | rtx pat = PATTERN (insn); | |
4896 | if (GET_CODE (pat) == PARALLEL) | |
4897 | pat = XVECEXP (pat, 0, 0); | |
4898 | if (GET_CODE (pat) == SET | |
a61b32a8 | 4899 | /* We can load any 8-bit value if we don't care what the high |
00f87557 | 4900 | order bits end up as. */ |
4901 | && GET_MODE (SET_DEST (pat)) != QImode | |
393fac7b | 4902 | && (CONSTANT_P (SET_SRC (pat)) |
31fd081d | 4903 | || (GET_CODE (SET_SRC (pat)) == UNSPEC_VOLATILE |
4904 | && XINT (SET_SRC (pat), 1) == UNSPECV_SP_SWITCH_B) | |
393fac7b | 4905 | /* Match mova_const. */ |
4906 | || (GET_CODE (SET_SRC (pat)) == UNSPEC | |
4907 | && XINT (SET_SRC (pat), 1) == UNSPEC_MOVA | |
4908 | && GET_CODE (XVECEXP (SET_SRC (pat), 0, 0)) == CONST)) | |
87ed74ef | 4909 | && ! (TARGET_SH2E |
8ded0752 | 4910 | && GET_CODE (SET_SRC (pat)) == CONST_DOUBLE |
00f87557 | 4911 | && (fp_zero_operand (SET_SRC (pat)) |
4912 | || fp_one_operand (SET_SRC (pat))) | |
6c049e03 | 4913 | /* In general we don't know the current setting of fpscr, so |
4914 | disable fldi. | |
4ea39690 | 4915 | There is an exception if this was a register-register move |
4916 | before reload - and hence it was ascertained that we have | |
4917 | single precision setting - and in a post-reload optimization | |
4918 | we changed this to do a constant load. In that case | |
4919 | we don't have an r0 clobber, hence we must use fldi. */ | |
c4af075b | 4920 | && (TARGET_FMOVD |
4ea39690 | 4921 | || (GET_CODE (XEXP (XVECEXP (PATTERN (insn), 0, 2), 0)) |
4922 | == SCRATCH)) | |
cbb16986 | 4923 | && REG_P (SET_DEST (pat)) |
e2142b04 | 4924 | && FP_REGISTER_P (REGNO (SET_DEST (pat)))) |
7105fb72 | 4925 | && ! (TARGET_SH2A |
4926 | && GET_MODE (SET_DEST (pat)) == SImode | |
419b390c | 4927 | && (satisfies_constraint_I20 (SET_SRC (pat)) |
4928 | || satisfies_constraint_I28 (SET_SRC (pat)))) | |
abff7a2e | 4929 | && ! satisfies_constraint_I08 (SET_SRC (pat))) |
a3b1178e | 4930 | return true; |
00f87557 | 4931 | } |
f3d93547 | 4932 | |
a3b1178e | 4933 | return false; |
47c009e5 | 4934 | } |
47c009e5 | 4935 | |
6c049e03 | 4936 | /* Return true if the specified insn is a mova insn. */ |
a3b1178e | 4937 | static bool |
b82334f7 | 4938 | mova_p (rtx_insn *insn) |
8ded0752 | 4939 | { |
cbb16986 | 4940 | return (NONJUMP_INSN_P (insn) |
8ded0752 | 4941 | && GET_CODE (PATTERN (insn)) == SET |
4942 | && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC | |
393fac7b | 4943 | && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_MOVA |
4944 | /* Don't match mova_const. */ | |
be7f5947 | 4945 | && GET_CODE (MOVA_LABELREF (insn)) == LABEL_REF); |
8ded0752 | 4946 | } |
4947 | ||
51dade95 | 4948 | /* Fix up a mova from a switch that went out of range. */ |
4949 | static void | |
b82334f7 | 4950 | fixup_mova (rtx_insn *mova) |
51dade95 | 4951 | { |
be7f5947 | 4952 | PUT_MODE (XEXP (MOVA_LABELREF (mova), 0), QImode); |
51dade95 | 4953 | if (! flag_pic) |
4954 | { | |
be7f5947 | 4955 | SET_SRC (PATTERN (mova)) = MOVA_LABELREF (mova); |
51dade95 | 4956 | INSN_CODE (mova) = -1; |
4957 | } | |
4958 | else | |
4959 | { | |
91a55c11 | 4960 | rtx_insn *worker = mova; |
79f6a8ed | 4961 | rtx_code_label *lab = gen_label_rtx (); |
20ba855a | 4962 | rtx wpat, wpat0, wpat1, wsrc, target, base, diff; |
51dade95 | 4963 | |
4964 | do | |
4965 | { | |
4966 | worker = NEXT_INSN (worker); | |
1a6a7a27 | 4967 | gcc_assert (worker |
cbb16986 | 4968 | && !LABEL_P (worker) |
4969 | && !JUMP_P (worker)); | |
4970 | } while (NOTE_P (worker) | |
466c3479 | 4971 | || recog_memoized (worker) != CODE_FOR_casesi_worker_1); |
51dade95 | 4972 | wpat = PATTERN (worker); |
4973 | wpat0 = XVECEXP (wpat, 0, 0); | |
4974 | wpat1 = XVECEXP (wpat, 0, 1); | |
4975 | wsrc = SET_SRC (wpat0); | |
4976 | PATTERN (worker) = (gen_casesi_worker_2 | |
4977 | (SET_DEST (wpat0), XVECEXP (wsrc, 0, 1), | |
4978 | XEXP (XVECEXP (wsrc, 0, 2), 0), lab, | |
4979 | XEXP (wpat1, 0))); | |
4980 | INSN_CODE (worker) = -1; | |
20ba855a | 4981 | target = XVECEXP (SET_SRC (PATTERN (mova)), 0, 0); |
4982 | base = gen_rtx_LABEL_REF (Pmode, lab); | |
4983 | diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, target, base), UNSPEC_SYMOFF); | |
51dade95 | 4984 | SET_SRC (PATTERN (mova)) = gen_rtx_CONST (Pmode, diff); |
4985 | INSN_CODE (mova) = -1; | |
4986 | } | |
4987 | } | |
4988 | ||
be7f5947 | 4989 | /* NEW_MOVA is a mova we've just encountered while scanning forward. Update |
4990 | *num_mova, and check if the new mova is not nested within the first one. | |
4991 | return 0 if *first_mova was replaced, 1 if new_mova was replaced, | |
4992 | 2 if new_mova has been assigned to *first_mova, -1 otherwise.. */ | |
4993 | static int | |
b82334f7 | 4994 | untangle_mova (int *num_mova, rtx_insn **first_mova, rtx_insn *new_mova) |
be7f5947 | 4995 | { |
078bb30c | 4996 | int n_addr = 0; /* Initialization to shut up spurious warning. */ |
4997 | int f_target, n_target = 0; /* Likewise. */ | |
be7f5947 | 4998 | |
4999 | if (optimize) | |
5000 | { | |
741c2f86 | 5001 | /* If NEW_MOVA has no address yet, it will be handled later. */ |
5002 | if (INSN_ADDRESSES_SIZE() <= (unsigned) INSN_UID (new_mova)) | |
5003 | return -1; | |
5004 | ||
be7f5947 | 5005 | n_addr = INSN_ADDRESSES (INSN_UID (new_mova)); |
5006 | n_target = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (new_mova), 0))); | |
5007 | if (n_addr > n_target || n_addr + 1022 < n_target) | |
5008 | { | |
5009 | /* Change the mova into a load. | |
5010 | broken_move will then return true for it. */ | |
5011 | fixup_mova (new_mova); | |
5012 | return 1; | |
5013 | } | |
5014 | } | |
5015 | if (!(*num_mova)++) | |
5016 | { | |
5017 | *first_mova = new_mova; | |
5018 | return 2; | |
5019 | } | |
5020 | if (!optimize | |
5021 | || ((f_target | |
5022 | = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (*first_mova), 0)))) | |
5023 | >= n_target)) | |
5024 | return -1; | |
5025 | ||
5026 | (*num_mova)--; | |
5027 | if (f_target - INSN_ADDRESSES (INSN_UID (*first_mova)) | |
5028 | > n_target - n_addr) | |
5029 | { | |
5030 | fixup_mova (*first_mova); | |
5031 | return 0; | |
5032 | } | |
5033 | else | |
5034 | { | |
5035 | fixup_mova (new_mova); | |
5036 | return 1; | |
5037 | } | |
5038 | } | |
5039 | ||
73401833 | 5040 | /* Find the last barrier from insn FROM which is close enough to hold the |
5041 | constant pool. If we can't find one, then create one near the end of | |
5042 | the range. */ | |
b82334f7 | 5043 | static rtx_insn * |
5044 | find_barrier (int num_mova, rtx_insn *mova, rtx_insn *from) | |
47c009e5 | 5045 | { |
97595bfd | 5046 | int count_si = 0; |
5047 | int count_hi = 0; | |
5048 | int found_hi = 0; | |
5049 | int found_si = 0; | |
87e19636 | 5050 | int found_di = 0; |
9eaab178 | 5051 | int hi_align = 2; |
5052 | int si_align = 2; | |
8ded0752 | 5053 | int leading_mova = num_mova; |
b82334f7 | 5054 | rtx_insn *barrier_before_mova = NULL; |
5055 | rtx_insn *found_barrier = NULL; | |
5056 | rtx_insn *good_barrier = NULL; | |
37ad966e | 5057 | int si_limit; |
5058 | int hi_limit; | |
b82334f7 | 5059 | rtx_insn *orig = from; |
91a55c11 | 5060 | rtx_insn *last_got = NULL; |
b82334f7 | 5061 | rtx_insn *last_symoff = NULL; |
73401833 | 5062 | |
5063 | /* For HImode: range is 510, add 4 because pc counts from address of | |
5064 | second instruction after this one, subtract 2 for the jump instruction | |
9629ee1b | 5065 | that we may need to emit before the table, subtract 2 for the instruction |
5066 | that fills the jump delay slot (in very rare cases, reorg will take an | |
5067 | instruction from after the constant pool or will leave the delay slot | |
5068 | empty). This gives 510. | |
73401833 | 5069 | For SImode: range is 1020, add 4 because pc counts from address of |
5070 | second instruction after this one, subtract 2 in case pc is 2 byte | |
5071 | aligned, subtract 2 for the jump instruction that we may need to emit | |
9629ee1b | 5072 | before the table, subtract 2 for the instruction that fills the jump |
5073 | delay slot. This gives 1018. */ | |
37ad966e | 5074 | |
8ded0752 | 5075 | /* The branch will always be shortened now that the reference address for |
ad87de1e | 5076 | forward branches is the successor address, thus we need no longer make |
8ded0752 | 5077 | adjustments to the [sh]i_limit for -O0. */ |
37ad966e | 5078 | |
8ded0752 | 5079 | si_limit = 1018; |
5080 | hi_limit = 510; | |
e6c94d0d | 5081 | |
37ad966e | 5082 | while (from && count_si < si_limit && count_hi < hi_limit) |
97595bfd | 5083 | { |
9eaab178 | 5084 | int inc = get_attr_length (from); |
5085 | int new_align = 1; | |
8ded0752 | 5086 | |
be7f5947 | 5087 | /* If this is a label that existed at the time of the compute_alignments |
5088 | call, determine the alignment. N.B. When find_barrier recurses for | |
5089 | an out-of-reach mova, we might see labels at the start of previously | |
5090 | inserted constant tables. */ | |
cbb16986 | 5091 | if (LABEL_P (from) |
be7f5947 | 5092 | && CODE_LABEL_NUMBER (from) <= max_labelno_before_reorg) |
887884c5 | 5093 | { |
5094 | if (optimize) | |
5095 | new_align = 1 << label_to_alignment (from); | |
cbb16986 | 5096 | else if (BARRIER_P (prev_nonnote_insn (from))) |
887884c5 | 5097 | new_align = 1 << barrier_align (from); |
5098 | else | |
5099 | new_align = 1; | |
5100 | inc = 0; | |
5101 | } | |
be7f5947 | 5102 | /* In case we are scanning a constant table because of recursion, check |
5103 | for explicit alignments. If the table is long, we might be forced | |
5104 | to emit the new table in front of it; the length of the alignment | |
5105 | might be the last straw. */ | |
cbb16986 | 5106 | else if (NONJUMP_INSN_P (from) |
be7f5947 | 5107 | && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE |
5108 | && XINT (PATTERN (from), 1) == UNSPECV_ALIGN) | |
5109 | new_align = INTVAL (XVECEXP (PATTERN (from), 0, 0)); | |
5110 | /* When we find the end of a constant table, paste the new constant | |
5111 | at the end. That is better than putting it in front because | |
5112 | this way, we don't need extra alignment for adding a 4-byte-aligned | |
5113 | mov(a) label to a 2/4 or 8/4 byte aligned table. */ | |
cbb16986 | 5114 | else if (NONJUMP_INSN_P (from) |
be7f5947 | 5115 | && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE |
5116 | && XINT (PATTERN (from), 1) == UNSPECV_CONST_END) | |
5117 | return from; | |
73401833 | 5118 | |
cbb16986 | 5119 | if (BARRIER_P (from)) |
8ded0752 | 5120 | { |
b82334f7 | 5121 | rtx_insn *next; |
9eaab178 | 5122 | |
8ded0752 | 5123 | found_barrier = from; |
9eaab178 | 5124 | |
ad87de1e | 5125 | /* If we are at the end of the function, or in front of an alignment |
8ded0752 | 5126 | instruction, we need not insert an extra alignment. We prefer |
5127 | this kind of barrier. */ | |
9eaab178 | 5128 | if (barrier_align (from) > 2) |
8ded0752 | 5129 | good_barrier = from; |
af122d60 | 5130 | |
5131 | /* If we are at the end of a hot/cold block, dump the constants | |
5132 | here. */ | |
5133 | next = NEXT_INSN (from); | |
5134 | if (next | |
5135 | && NOTE_P (next) | |
5136 | && NOTE_KIND (next) == NOTE_INSN_SWITCH_TEXT_SECTIONS) | |
5137 | break; | |
8ded0752 | 5138 | } |
73401833 | 5139 | |
73401833 | 5140 | if (broken_move (from)) |
97595bfd | 5141 | { |
8ded0752 | 5142 | rtx pat, src, dst; |
3754d046 | 5143 | machine_mode mode; |
8ded0752 | 5144 | |
5145 | pat = PATTERN (from); | |
5146 | if (GET_CODE (pat) == PARALLEL) | |
5147 | pat = XVECEXP (pat, 0, 0); | |
5148 | src = SET_SRC (pat); | |
5149 | dst = SET_DEST (pat); | |
5150 | mode = GET_MODE (dst); | |
37ad966e | 5151 | |
0bbf4d59 | 5152 | /* GOT pcrelat setting comes in pair of |
5153 | mova .L8,r0 | |
5154 | mov.l .L8,r12 | |
5155 | instructions. (plus add r0,r12). | |
5156 | Remember if we see one without the other. */ | |
6c049e03 | 5157 | if (GET_CODE (src) == UNSPEC && PIC_ADDR_P (XVECEXP (src, 0, 0))) |
91a55c11 | 5158 | last_got = last_got ? NULL : from; |
6c049e03 | 5159 | else if (PIC_ADDR_P (src)) |
91a55c11 | 5160 | last_got = last_got ? NULL : from; |
0bbf4d59 | 5161 | |
37ad966e | 5162 | /* We must explicitly check the mode, because sometimes the |
5163 | front end will generate code to load unsigned constants into | |
5164 | HImode targets without properly sign extending them. */ | |
1b61190c | 5165 | if (mode == HImode |
e75e7428 | 5166 | || (mode == SImode && satisfies_constraint_I16 (src) |
5167 | && REGNO (dst) != FPUL_REG)) | |
22f26681 | 5168 | { |
8ded0752 | 5169 | found_hi += 2; |
22f26681 | 5170 | /* We put the short constants before the long constants, so |
5171 | we must count the length of short constants in the range | |
5172 | for the long constants. */ | |
5173 | /* ??? This isn't optimal, but is easy to do. */ | |
8ded0752 | 5174 | si_limit -= 2; |
22f26681 | 5175 | } |
97595bfd | 5176 | else |
8ded0752 | 5177 | { |
87e19636 | 5178 | /* We dump DF/DI constants before SF/SI ones, because |
5179 | the limit is the same, but the alignment requirements | |
5180 | are higher. We may waste up to 4 additional bytes | |
5181 | for alignment, and the DF/DI constant may have | |
ada8cf8b | 5182 | another SF/SI constant placed before it. */ |
87e19636 | 5183 | if (TARGET_SHCOMPACT |
5184 | && ! found_di | |
5185 | && (mode == DFmode || mode == DImode)) | |
5186 | { | |
5187 | found_di = 1; | |
5188 | si_limit -= 8; | |
5189 | } | |
9eaab178 | 5190 | while (si_align > 2 && found_si + si_align - 2 > count_si) |
5191 | si_align >>= 1; | |
8ded0752 | 5192 | if (found_si > count_si) |
5193 | count_si = found_si; | |
5194 | found_si += GET_MODE_SIZE (mode); | |
5195 | if (num_mova) | |
5196 | si_limit -= GET_MODE_SIZE (mode); | |
5197 | } | |
97595bfd | 5198 | } |
335e16a0 | 5199 | |
9eaab178 | 5200 | if (mova_p (from)) |
8ded0752 | 5201 | { |
be7f5947 | 5202 | switch (untangle_mova (&num_mova, &mova, from)) |
8ded0752 | 5203 | { |
0152fbc1 | 5204 | case 1: |
5205 | if (flag_pic) | |
5206 | { | |
5207 | rtx src = SET_SRC (PATTERN (from)); | |
5208 | if (GET_CODE (src) == CONST | |
5209 | && GET_CODE (XEXP (src, 0)) == UNSPEC | |
5210 | && XINT (XEXP (src, 0), 1) == UNSPEC_SYMOFF) | |
5211 | last_symoff = from; | |
5212 | } | |
5213 | break; | |
be7f5947 | 5214 | case 0: return find_barrier (0, 0, mova); |
5215 | case 2: | |
5216 | { | |
5217 | leading_mova = 0; | |
5218 | barrier_before_mova | |
5219 | = good_barrier ? good_barrier : found_barrier; | |
5220 | } | |
5221 | default: break; | |
8ded0752 | 5222 | } |
5223 | if (found_si > count_si) | |
5224 | count_si = found_si; | |
5225 | } | |
91f71fa3 | 5226 | else if (JUMP_TABLE_DATA_P (from) |
5227 | && GET_CODE (PATTERN (from)) == ADDR_DIFF_VEC) | |
8ded0752 | 5228 | { |
be7f5947 | 5229 | if ((num_mova > 1 && GET_MODE (prev_nonnote_insn (from)) == VOIDmode) |
5230 | || (num_mova | |
5231 | && (prev_nonnote_insn (from) | |
5232 | == XEXP (MOVA_LABELREF (mova), 0)))) | |
8ded0752 | 5233 | num_mova--; |
2a6493a5 | 5234 | if (barrier_align (next_real_insn (from)) == align_jumps_log) |
8ded0752 | 5235 | { |
3398e91d | 5236 | /* We have just passed the barrier in front of the |
bd967f88 | 5237 | ADDR_DIFF_VEC, which is stored in found_barrier. Since |
5238 | the ADDR_DIFF_VEC is accessed as data, just like our pool | |
5239 | constants, this is a good opportunity to accommodate what | |
5240 | we have gathered so far. | |
8ded0752 | 5241 | If we waited any longer, we could end up at a barrier in |
5242 | front of code, which gives worse cache usage for separated | |
5243 | instruction / data caches. */ | |
bd967f88 | 5244 | good_barrier = found_barrier; |
8ded0752 | 5245 | break; |
5246 | } | |
bd967f88 | 5247 | else |
5248 | { | |
5249 | rtx body = PATTERN (from); | |
5250 | inc = XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)); | |
5251 | } | |
8ded0752 | 5252 | } |
0d93aeb0 | 5253 | /* For the SH1, we generate alignments even after jumps-around-jumps. */ |
cbb16986 | 5254 | else if (JUMP_P (from) |
0d93aeb0 | 5255 | && ! TARGET_SH2 |
c17f64cc | 5256 | && ! optimize_size) |
0d93aeb0 | 5257 | new_align = 4; |
335e16a0 | 5258 | |
160c147c | 5259 | /* There is a possibility that a bf is transformed into a bf/s by the |
5260 | delay slot scheduler. */ | |
91f71fa3 | 5261 | if (JUMP_P (from) |
160c147c | 5262 | && get_attr_type (from) == TYPE_CBRANCH |
66bbc864 | 5263 | && ! sequence_insn_p (from)) |
160c147c | 5264 | inc += 2; |
5265 | ||
97595bfd | 5266 | if (found_si) |
9eaab178 | 5267 | { |
0d93aeb0 | 5268 | count_si += inc; |
9eaab178 | 5269 | if (new_align > si_align) |
5270 | { | |
b7dbbdb2 | 5271 | si_limit -= (count_si - 1) & (new_align - si_align); |
9eaab178 | 5272 | si_align = new_align; |
5273 | } | |
b7dbbdb2 | 5274 | count_si = (count_si + new_align - 1) & -new_align; |
9eaab178 | 5275 | } |
97595bfd | 5276 | if (found_hi) |
9eaab178 | 5277 | { |
0d93aeb0 | 5278 | count_hi += inc; |
9eaab178 | 5279 | if (new_align > hi_align) |
5280 | { | |
b7dbbdb2 | 5281 | hi_limit -= (count_hi - 1) & (new_align - hi_align); |
9eaab178 | 5282 | hi_align = new_align; |
5283 | } | |
b7dbbdb2 | 5284 | count_hi = (count_hi + new_align - 1) & -new_align; |
9eaab178 | 5285 | } |
97595bfd | 5286 | from = NEXT_INSN (from); |
5287 | } | |
5288 | ||
8ded0752 | 5289 | if (num_mova) |
17bec211 | 5290 | { |
5291 | if (leading_mova) | |
5292 | { | |
5293 | /* Try as we might, the leading mova is out of range. Change | |
5294 | it into a load (which will become a pcload) and retry. */ | |
51dade95 | 5295 | fixup_mova (mova); |
17bec211 | 5296 | return find_barrier (0, 0, mova); |
5297 | } | |
5298 | else | |
5299 | { | |
5300 | /* Insert the constant pool table before the mova instruction, | |
5301 | to prevent the mova label reference from going out of range. */ | |
5302 | from = mova; | |
5303 | good_barrier = found_barrier = barrier_before_mova; | |
5304 | } | |
5305 | } | |
335e16a0 | 5306 | |
8ded0752 | 5307 | if (found_barrier) |
5308 | { | |
9eaab178 | 5309 | if (good_barrier && next_real_insn (found_barrier)) |
8ded0752 | 5310 | found_barrier = good_barrier; |
8ded0752 | 5311 | } |
5312 | else | |
47c009e5 | 5313 | { |
73401833 | 5314 | /* We didn't find a barrier in time to dump our stuff, |
5315 | so we'll make one. */ | |
b82334f7 | 5316 | rtx_code_label *label = gen_label_rtx (); |
73401833 | 5317 | |
0152fbc1 | 5318 | /* Don't emit a constant table in the middle of insns for |
5319 | casesi_worker_2. This is a bit overkill but is enough | |
5320 | because casesi_worker_2 wouldn't appear so frequently. */ | |
5321 | if (last_symoff) | |
5322 | from = last_symoff; | |
5323 | ||
92e80318 | 5324 | /* If we exceeded the range, then we must back up over the last |
5325 | instruction we looked at. Otherwise, we just need to undo the | |
5326 | NEXT_INSN at the end of the loop. */ | |
64c985e4 | 5327 | if (PREV_INSN (from) != orig |
5328 | && (count_hi > hi_limit || count_si > si_limit)) | |
92e80318 | 5329 | from = PREV_INSN (PREV_INSN (from)); |
5330 | else | |
5331 | from = PREV_INSN (from); | |
5332 | ||
0bbf4d59 | 5333 | /* Don't emit a constant table int the middle of global pointer setting, |
5334 | since that that would move the addressing base GOT into another table. | |
5335 | We need the first mov instruction before the _GLOBAL_OFFSET_TABLE_ | |
6523974f | 5336 | in the pool anyway, so just move up the whole constant pool. |
5337 | ||
5338 | However, avoid doing so when the last single GOT mov is the starting | |
5339 | insn itself. Going past above the start insn would create a negative | |
5340 | offset, causing errors. */ | |
5341 | if (last_got && last_got != orig) | |
0bbf4d59 | 5342 | from = PREV_INSN (last_got); |
5343 | ||
c299b39c | 5344 | /* Don't insert the constant pool table at the position which |
5345 | may be the landing pad. */ | |
5346 | if (flag_exceptions | |
5347 | && CALL_P (from) | |
5348 | && find_reg_note (from, REG_EH_REGION, NULL_RTX)) | |
5349 | from = PREV_INSN (from); | |
5350 | ||
73401833 | 5351 | /* Walk back to be just before any jump or label. |
5352 | Putting it before a label reduces the number of times the branch | |
5353 | around the constant pool table will be hit. Putting it before | |
5354 | a jump makes it more likely that the bra delay slot will be | |
5355 | filled. */ | |
cbb16986 | 5356 | while (NOTE_P (from) || JUMP_P (from) |
5357 | || LABEL_P (from)) | |
73401833 | 5358 | from = PREV_INSN (from); |
5359 | ||
06dfeb27 | 5360 | /* Make sure we do not split between a call and its corresponding |
5361 | CALL_ARG_LOCATION note. */ | |
5362 | if (CALL_P (from)) | |
5363 | { | |
b82334f7 | 5364 | rtx_insn *next = NEXT_INSN (from); |
06dfeb27 | 5365 | if (next && NOTE_P (next) |
5366 | && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION) | |
5367 | from = next; | |
5368 | } | |
5369 | ||
97595bfd | 5370 | from = emit_jump_insn_after (gen_jump (label), from); |
5371 | JUMP_LABEL (from) = label; | |
bdb9edaa | 5372 | LABEL_NUSES (label) = 1; |
97595bfd | 5373 | found_barrier = emit_barrier_after (from); |
5374 | emit_label_after (label, found_barrier); | |
47c009e5 | 5375 | } |
47c009e5 | 5376 | |
73401833 | 5377 | return found_barrier; |
97595bfd | 5378 | } |
47c009e5 | 5379 | |
881ffd32 | 5380 | /* If the instruction INSN is implemented by a special function, and we can |
5381 | positively find the register that is used to call the sfunc, and this | |
5382 | register is not used anywhere else in this instruction - except as the | |
5383 | destination of a set, return this register; else, return 0. */ | |
8ded0752 | 5384 | rtx |
d3ffa7b4 | 5385 | sfunc_uses_reg (rtx_insn *insn) |
881ffd32 | 5386 | { |
5387 | int i; | |
5388 | rtx pattern, part, reg_part, reg; | |
5389 | ||
cbb16986 | 5390 | if (!NONJUMP_INSN_P (insn)) |
c3583c9c | 5391 | return NULL_RTX; |
881ffd32 | 5392 | pattern = PATTERN (insn); |
5393 | if (GET_CODE (pattern) != PARALLEL || get_attr_type (insn) != TYPE_SFUNC) | |
c3583c9c | 5394 | return NULL_RTX; |
881ffd32 | 5395 | |
c3583c9c | 5396 | for (reg_part = NULL_RTX, i = XVECLEN (pattern, 0) - 1; i >= 1; i--) |
881ffd32 | 5397 | { |
5398 | part = XVECEXP (pattern, 0, i); | |
8ded0752 | 5399 | if (GET_CODE (part) == USE && GET_MODE (XEXP (part, 0)) == SImode) |
881ffd32 | 5400 | reg_part = part; |
5401 | } | |
5402 | if (! reg_part) | |
c3583c9c | 5403 | return NULL_RTX; |
881ffd32 | 5404 | reg = XEXP (reg_part, 0); |
5405 | for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--) | |
5406 | { | |
5407 | part = XVECEXP (pattern, 0, i); | |
1b61190c | 5408 | if (part == reg_part || GET_CODE (part) == CLOBBER) |
881ffd32 | 5409 | continue; |
5410 | if (reg_mentioned_p (reg, ((GET_CODE (part) == SET | |
cbb16986 | 5411 | && REG_P (SET_DEST (part))) |
881ffd32 | 5412 | ? SET_SRC (part) : part))) |
c3583c9c | 5413 | return NULL_RTX; |
881ffd32 | 5414 | } |
5415 | return reg; | |
5416 | } | |
5417 | ||
90e84010 | 5418 | /* See if the only way in which INSN uses REG is by calling it, or by |
5419 | setting it while calling it. Set *SET to a SET rtx if the register | |
5420 | is set by INSN. */ | |
a3b1178e | 5421 | static bool |
50fc2d35 | 5422 | noncall_uses_reg (rtx reg, rtx_insn *insn, rtx *set) |
90e84010 | 5423 | { |
881ffd32 | 5424 | rtx pattern, reg2; |
90e84010 | 5425 | |
5426 | *set = NULL_RTX; | |
5427 | ||
881ffd32 | 5428 | reg2 = sfunc_uses_reg (insn); |
5429 | if (reg2 && REGNO (reg2) == REGNO (reg)) | |
5430 | { | |
5431 | pattern = single_set (insn); | |
5432 | if (pattern | |
cbb16986 | 5433 | && REG_P (SET_DEST (pattern)) |
881ffd32 | 5434 | && REGNO (reg) == REGNO (SET_DEST (pattern))) |
5435 | *set = pattern; | |
a3b1178e | 5436 | return false; |
881ffd32 | 5437 | } |
cbb16986 | 5438 | if (!CALL_P (insn)) |
90e84010 | 5439 | { |
5440 | /* We don't use rtx_equal_p because we don't care if the mode is | |
5441 | different. */ | |
5442 | pattern = single_set (insn); | |
5443 | if (pattern | |
cbb16986 | 5444 | && REG_P (SET_DEST (pattern)) |
90e84010 | 5445 | && REGNO (reg) == REGNO (SET_DEST (pattern))) |
5446 | { | |
881ffd32 | 5447 | rtx par, part; |
5448 | int i; | |
5449 | ||
90e84010 | 5450 | *set = pattern; |
881ffd32 | 5451 | par = PATTERN (insn); |
5452 | if (GET_CODE (par) == PARALLEL) | |
5453 | for (i = XVECLEN (par, 0) - 1; i >= 0; i--) | |
5454 | { | |
5455 | part = XVECEXP (par, 0, i); | |
5456 | if (GET_CODE (part) != SET && reg_mentioned_p (reg, part)) | |
a3b1178e | 5457 | return true; |
881ffd32 | 5458 | } |
5459 | return reg_mentioned_p (reg, SET_SRC (pattern)); | |
90e84010 | 5460 | } |
5461 | ||
a3b1178e | 5462 | return true; |
90e84010 | 5463 | } |
5464 | ||
5465 | pattern = PATTERN (insn); | |
5466 | ||
5467 | if (GET_CODE (pattern) == PARALLEL) | |
5468 | { | |
5469 | int i; | |
5470 | ||
5471 | for (i = XVECLEN (pattern, 0) - 1; i >= 1; i--) | |
5472 | if (reg_mentioned_p (reg, XVECEXP (pattern, 0, i))) | |
a3b1178e | 5473 | return true; |
90e84010 | 5474 | pattern = XVECEXP (pattern, 0, 0); |
5475 | } | |
5476 | ||
5477 | if (GET_CODE (pattern) == SET) | |
5478 | { | |
5479 | if (reg_mentioned_p (reg, SET_DEST (pattern))) | |
5480 | { | |
5481 | /* We don't use rtx_equal_p, because we don't care if the | |
6c049e03 | 5482 | mode is different. */ |
cbb16986 | 5483 | if (!REG_P (SET_DEST (pattern)) |
90e84010 | 5484 | || REGNO (reg) != REGNO (SET_DEST (pattern))) |
a3b1178e | 5485 | return true; |
90e84010 | 5486 | |
5487 | *set = pattern; | |
5488 | } | |
5489 | ||
5490 | pattern = SET_SRC (pattern); | |
5491 | } | |
5492 | ||
5493 | if (GET_CODE (pattern) != CALL | |
cbb16986 | 5494 | || !MEM_P (XEXP (pattern, 0)) |
90e84010 | 5495 | || ! rtx_equal_p (reg, XEXP (XEXP (pattern, 0), 0))) |
a3b1178e | 5496 | return true; |
90e84010 | 5497 | |
a3b1178e | 5498 | return false; |
90e84010 | 5499 | } |
5500 | ||
8ded0752 | 5501 | /* Given a X, a pattern of an insn or a part of it, return a mask of used |
5502 | general registers. Bits 0..15 mean that the respective registers | |
5503 | are used as inputs in the instruction. Bits 16..31 mean that the | |
5504 | registers 0..15, respectively, are used as outputs, or are clobbered. | |
5505 | IS_DEST should be set to 16 if X is the destination of a SET, else to 0. */ | |
5506 | int | |
04f04b72 | 5507 | regs_used (rtx x, int is_dest) |
8ded0752 | 5508 | { |
5509 | enum rtx_code code; | |
d2ca078f | 5510 | const char *fmt; |
8ded0752 | 5511 | int i, used = 0; |
5512 | ||
5513 | if (! x) | |
5514 | return used; | |
5515 | code = GET_CODE (x); | |
5516 | switch (code) | |
5517 | { | |
5518 | case REG: | |
5519 | if (REGNO (x) < 16) | |
5520 | return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1) | |
5521 | << (REGNO (x) + is_dest)); | |
5522 | return 0; | |
5523 | case SUBREG: | |
5524 | { | |
5525 | rtx y = SUBREG_REG (x); | |
9e7454d0 | 5526 | |
cbb16986 | 5527 | if (!REG_P (y)) |
8ded0752 | 5528 | break; |
5529 | if (REGNO (y) < 16) | |
5530 | return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1) | |
701e46d0 | 5531 | << (REGNO (y) + |
5532 | subreg_regno_offset (REGNO (y), | |
5533 | GET_MODE (y), | |
5534 | SUBREG_BYTE (x), | |
5535 | GET_MODE (x)) + is_dest)); | |
8ded0752 | 5536 | return 0; |
5537 | } | |
5538 | case SET: | |
5539 | return regs_used (SET_SRC (x), 0) | regs_used (SET_DEST (x), 16); | |
5540 | case RETURN: | |
5541 | /* If there was a return value, it must have been indicated with USE. */ | |
5542 | return 0x00ffff00; | |
5543 | case CLOBBER: | |
5544 | is_dest = 1; | |
5545 | break; | |
5546 | case MEM: | |
5547 | is_dest = 0; | |
5548 | break; | |
5549 | case CALL: | |
5550 | used |= 0x00ff00f0; | |
5551 | break; | |
b7dbbdb2 | 5552 | default: |
5553 | break; | |
8ded0752 | 5554 | } |
5555 | ||
5556 | fmt = GET_RTX_FORMAT (code); | |
5557 | ||
5558 | for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) | |
5559 | { | |
5560 | if (fmt[i] == 'E') | |
5561 | { | |
c3583c9c | 5562 | int j; |
8ded0752 | 5563 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
5564 | used |= regs_used (XVECEXP (x, i, j), is_dest); | |
5565 | } | |
5566 | else if (fmt[i] == 'e') | |
5567 | used |= regs_used (XEXP (x, i), is_dest); | |
5568 | } | |
5569 | return used; | |
5570 | } | |
5571 | ||
5572 | /* Create an instruction that prevents redirection of a conditional branch | |
ad87de1e | 5573 | to the destination of the JUMP with address ADDR. |
8ded0752 | 5574 | If the branch needs to be implemented as an indirect jump, try to find |
5575 | a scratch register for it. | |
5576 | If NEED_BLOCK is 0, don't do anything unless we need a scratch register. | |
5577 | If any preceding insn that doesn't fit into a delay slot is good enough, | |
5578 | pass 1. Pass 2 if a definite blocking insn is needed. | |
5579 | -1 is used internally to avoid deep recursion. | |
5580 | If a blocking instruction is made or recognized, return it. */ | |
91a55c11 | 5581 | static rtx_insn * |
5582 | gen_block_redirect (rtx_insn *jump, int addr, int need_block) | |
8ded0752 | 5583 | { |
5584 | int dead = 0; | |
91a55c11 | 5585 | rtx_insn *prev = prev_nonnote_insn (jump); |
8ded0752 | 5586 | rtx dest; |
5587 | ||
5588 | /* First, check if we already have an instruction that satisfies our need. */ | |
dd1286fb | 5589 | if (prev && NONJUMP_INSN_P (prev) && ! prev->deleted ()) |
8ded0752 | 5590 | { |
5591 | if (INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch) | |
5592 | return prev; | |
5593 | if (GET_CODE (PATTERN (prev)) == USE | |
5594 | || GET_CODE (PATTERN (prev)) == CLOBBER | |
5595 | || get_attr_in_delay_slot (prev) == IN_DELAY_SLOT_YES) | |
5596 | prev = jump; | |
5597 | else if ((need_block &= ~1) < 0) | |
5598 | return prev; | |
5599 | else if (recog_memoized (prev) == CODE_FOR_block_branch_redirect) | |
5600 | need_block = 0; | |
5601 | } | |
b78739b6 | 5602 | if (GET_CODE (PATTERN (jump)) == RETURN) |
5603 | { | |
5604 | if (! need_block) | |
5605 | return prev; | |
5606 | /* Reorg even does nasty things with return insns that cause branches | |
5607 | to go out of range - see find_end_label and callers. */ | |
bcd9bd66 | 5608 | return emit_insn_before (gen_block_branch_redirect (const0_rtx) , jump); |
b78739b6 | 5609 | } |
8ded0752 | 5610 | /* We can't use JUMP_LABEL here because it might be undefined |
5611 | when not optimizing. */ | |
5612 | dest = XEXP (SET_SRC (PATTERN (jump)), 0); | |
5613 | /* If the branch is out of range, try to find a scratch register for it. */ | |
5614 | if (optimize | |
30435bf8 | 5615 | && (INSN_ADDRESSES (INSN_UID (dest)) - addr + (unsigned) 4092 |
5616 | > 4092 + 4098)) | |
8ded0752 | 5617 | { |
91a55c11 | 5618 | rtx_insn *scan; |
8ded0752 | 5619 | /* Don't look for the stack pointer as a scratch register, |
ad87de1e | 5620 | it would cause trouble if an interrupt occurred. */ |
8deb3959 | 5621 | unsigned attempt = 0x7fff, used; |
8ded0752 | 5622 | int jump_left = flag_expensive_optimizations + 1; |
9e7454d0 | 5623 | |
8ded0752 | 5624 | /* It is likely that the most recent eligible instruction is wanted for |
5625 | the delay slot. Therefore, find out which registers it uses, and | |
5626 | try to avoid using them. */ | |
9e7454d0 | 5627 | |
b7dbbdb2 | 5628 | for (scan = jump; (scan = PREV_INSN (scan)); ) |
8ded0752 | 5629 | { |
5630 | enum rtx_code code; | |
5631 | ||
dd1286fb | 5632 | if (scan->deleted ()) |
8ded0752 | 5633 | continue; |
5634 | code = GET_CODE (scan); | |
5635 | if (code == CODE_LABEL || code == JUMP_INSN) | |
5636 | break; | |
5637 | if (code == INSN | |
5638 | && GET_CODE (PATTERN (scan)) != USE | |
5639 | && GET_CODE (PATTERN (scan)) != CLOBBER | |
5640 | && get_attr_in_delay_slot (scan) == IN_DELAY_SLOT_YES) | |
5641 | { | |
8deb3959 | 5642 | attempt &= ~regs_used (PATTERN (scan), 0); |
8ded0752 | 5643 | break; |
5644 | } | |
5645 | } | |
91a55c11 | 5646 | for (used = dead = 0, scan = JUMP_LABEL_AS_INSN (jump); |
17bec211 | 5647 | (scan = NEXT_INSN (scan)); ) |
8ded0752 | 5648 | { |
5649 | enum rtx_code code; | |
5650 | ||
dd1286fb | 5651 | if (scan->deleted ()) |
8ded0752 | 5652 | continue; |
5653 | code = GET_CODE (scan); | |
6720e96c | 5654 | if (INSN_P (scan)) |
8ded0752 | 5655 | { |
5656 | used |= regs_used (PATTERN (scan), 0); | |
5657 | if (code == CALL_INSN) | |
5658 | used |= regs_used (CALL_INSN_FUNCTION_USAGE (scan), 0); | |
5659 | dead |= (used >> 16) & ~used; | |
8deb3959 | 5660 | if (dead & attempt) |
8ded0752 | 5661 | { |
8deb3959 | 5662 | dead &= attempt; |
8ded0752 | 5663 | break; |
5664 | } | |
5665 | if (code == JUMP_INSN) | |
17bec211 | 5666 | { |
5667 | if (jump_left-- && simplejump_p (scan)) | |
91a55c11 | 5668 | scan = JUMP_LABEL_AS_INSN (scan); |
17bec211 | 5669 | else |
5670 | break; | |
5671 | } | |
8ded0752 | 5672 | } |
5673 | } | |
5674 | /* Mask out the stack pointer again, in case it was | |
5675 | the only 'free' register we have found. */ | |
5676 | dead &= 0x7fff; | |
5677 | } | |
5678 | /* If the immediate destination is still in range, check for possible | |
5679 | threading with a jump beyond the delay slot insn. | |
5680 | Don't check if we are called recursively; the jump has been or will be | |
ad87de1e | 5681 | checked in a different invocation then. */ |
9e7454d0 | 5682 | |
8ded0752 | 5683 | else if (optimize && need_block >= 0) |
5684 | { | |
91a55c11 | 5685 | rtx_insn *next = next_active_insn (next_active_insn (dest)); |
cbb16986 | 5686 | if (next && JUMP_P (next) |
8ded0752 | 5687 | && GET_CODE (PATTERN (next)) == SET |
adbcc7c4 | 5688 | && recog_memoized (next) == CODE_FOR_jump_compact) |
8ded0752 | 5689 | { |
5690 | dest = JUMP_LABEL (next); | |
5691 | if (dest | |
30435bf8 | 5692 | && (INSN_ADDRESSES (INSN_UID (dest)) - addr + (unsigned) 4092 |
47fc0706 | 5693 | > 4092 + 4098)) |
5694 | gen_block_redirect (next, INSN_ADDRESSES (INSN_UID (next)), -1); | |
8ded0752 | 5695 | } |
5696 | } | |
5697 | ||
5698 | if (dead) | |
5699 | { | |
7014838c | 5700 | rtx reg = gen_rtx_REG (SImode, exact_log2 (dead & -dead)); |
8ded0752 | 5701 | |
5702 | /* It would be nice if we could convert the jump into an indirect | |
ad87de1e | 5703 | jump / far branch right now, and thus exposing all constituent |
8ded0752 | 5704 | instructions to further optimization. However, reorg uses |
5705 | simplejump_p to determine if there is an unconditional jump where | |
5706 | it should try to schedule instructions from the target of the | |
5707 | branch; simplejump_p fails for indirect jumps even if they have | |
5708 | a JUMP_LABEL. */ | |
91a55c11 | 5709 | rtx_insn *insn = emit_insn_before (gen_indirect_jump_scratch |
5710 | (reg, GEN_INT (unspec_bbr_uid++)), | |
5711 | jump); | |
2a6493a5 | 5712 | /* ??? We would like this to have the scope of the jump, but that |
5713 | scope will change when a delay slot insn of an inner scope is added. | |
5714 | Hence, after delay slot scheduling, we'll have to expect | |
5715 | NOTE_INSN_BLOCK_END notes between the indirect_jump_scratch and | |
5716 | the jump. */ | |
9e7454d0 | 5717 | |
d53c050c | 5718 | INSN_LOCATION (insn) = INSN_LOCATION (jump); |
8ded0752 | 5719 | INSN_CODE (insn) = CODE_FOR_indirect_jump_scratch; |
5720 | return insn; | |
5721 | } | |
5722 | else if (need_block) | |
5723 | /* We can't use JUMP_LABEL here because it might be undefined | |
5724 | when not optimizing. */ | |
5725 | return emit_insn_before (gen_block_branch_redirect | |
4c4854c8 | 5726 | (GEN_INT (unspec_bbr_uid++)), |
5727 | jump); | |
8ded0752 | 5728 | return prev; |
5729 | } | |
5730 | ||
5731 | #define CONDJUMP_MIN -252 | |
5732 | #define CONDJUMP_MAX 262 | |
5733 | struct far_branch | |
5734 | { | |
5735 | /* A label (to be placed) in front of the jump | |
5736 | that jumps to our ultimate destination. */ | |
91a55c11 | 5737 | rtx_insn *near_label; |
8ded0752 | 5738 | /* Where we are going to insert it if we cannot move the jump any farther, |
5739 | or the jump itself if we have picked up an existing jump. */ | |
91a55c11 | 5740 | rtx_insn *insert_place; |
8ded0752 | 5741 | /* The ultimate destination. */ |
91a55c11 | 5742 | rtx_insn *far_label; |
8ded0752 | 5743 | struct far_branch *prev; |
5744 | /* If the branch has already been created, its address; | |
5745 | else the address of its first prospective user. */ | |
5746 | int address; | |
5747 | }; | |
5748 | ||
04f04b72 | 5749 | static void gen_far_branch (struct far_branch *); |
8ded0752 | 5750 | enum mdep_reorg_phase_e mdep_reorg_phase; |
26576132 | 5751 | static void |
04f04b72 | 5752 | gen_far_branch (struct far_branch *bp) |
8ded0752 | 5753 | { |
158a522b | 5754 | rtx_insn *insn = bp->insert_place; |
91a55c11 | 5755 | rtx_insn *jump; |
79f6a8ed | 5756 | rtx_code_label *label = gen_label_rtx (); |
1a6a7a27 | 5757 | int ok; |
8ded0752 | 5758 | |
5759 | emit_label_after (label, insn); | |
5760 | if (bp->far_label) | |
5761 | { | |
5762 | jump = emit_jump_insn_after (gen_jump (bp->far_label), insn); | |
5763 | LABEL_NUSES (bp->far_label)++; | |
5764 | } | |
5765 | else | |
5766 | jump = emit_jump_insn_after (gen_return (), insn); | |
bc22be57 | 5767 | |
1b61190c | 5768 | /* Emit a barrier so that reorg knows that any following instructions |
5769 | are not reachable via a fall-through path. | |
1fc184ee | 5770 | But don't do this when not optimizing, since we wouldn't suppress the |
1b61190c | 5771 | alignment for the barrier then, and could end up with out-of-range |
5772 | pc-relative loads. */ | |
5773 | if (optimize) | |
5774 | emit_barrier_after (jump); | |
8ded0752 | 5775 | emit_label_after (bp->near_label, insn); |
bc22be57 | 5776 | |
5777 | if (bp->far_label) | |
5778 | JUMP_LABEL (jump) = bp->far_label; | |
5779 | else | |
5780 | { | |
5781 | rtx pat = PATTERN (jump); | |
5782 | gcc_assert (ANY_RETURN_P (pat)); | |
5783 | JUMP_LABEL (jump) = pat; | |
5784 | } | |
5785 | ||
1a6a7a27 | 5786 | ok = invert_jump (insn, label, 1); |
5787 | gcc_assert (ok); | |
bc22be57 | 5788 | |
b78739b6 | 5789 | /* If we are branching around a jump (rather than a return), prevent |
5790 | reorg from using an insn from the jump target as the delay slot insn - | |
5791 | when reorg did this, it pessimized code (we rather hide the delay slot) | |
5792 | and it could cause branches to go out of range. */ | |
5793 | if (bp->far_label) | |
5794 | (emit_insn_after | |
5795 | (gen_stuff_delay_slot | |
4c4854c8 | 5796 | (GEN_INT (unspec_bbr_uid++), |
b78739b6 | 5797 | GEN_INT (recog_memoized (insn) == CODE_FOR_branch_false)), |
5798 | insn)); | |
8ded0752 | 5799 | /* Prevent reorg from undoing our splits. */ |
5800 | gen_block_redirect (jump, bp->address += 2, 2); | |
5801 | } | |
5802 | ||
8ded0752 | 5803 | /* Fix up ADDR_DIFF_VECs. */ |
5804 | void | |
91a55c11 | 5805 | fixup_addr_diff_vecs (rtx_insn *first) |
8ded0752 | 5806 | { |
91a55c11 | 5807 | rtx_insn *insn; |
9eaab178 | 5808 | |
8ded0752 | 5809 | for (insn = first; insn; insn = NEXT_INSN (insn)) |
5810 | { | |
91a55c11 | 5811 | rtx vec_lab, pat, prevpat, x, braf_label; |
5812 | rtx_insn *prev; | |
8ded0752 | 5813 | |
77985f1a | 5814 | if (! JUMP_TABLE_DATA_P (insn) |
8ded0752 | 5815 | || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) |
5816 | continue; | |
5817 | pat = PATTERN (insn); | |
9eaab178 | 5818 | vec_lab = XEXP (XEXP (pat, 0), 0); |
8ded0752 | 5819 | |
9eaab178 | 5820 | /* Search the matching casesi_jump_2. */ |
91a55c11 | 5821 | for (prev = as_a <rtx_insn *> (vec_lab); ; prev = PREV_INSN (prev)) |
8ded0752 | 5822 | { |
cbb16986 | 5823 | if (!JUMP_P (prev)) |
9eaab178 | 5824 | continue; |
5825 | prevpat = PATTERN (prev); | |
5826 | if (GET_CODE (prevpat) != PARALLEL || XVECLEN (prevpat, 0) != 2) | |
5827 | continue; | |
5828 | x = XVECEXP (prevpat, 0, 1); | |
5829 | if (GET_CODE (x) != USE) | |
5830 | continue; | |
5831 | x = XEXP (x, 0); | |
5832 | if (GET_CODE (x) == LABEL_REF && XEXP (x, 0) == vec_lab) | |
5833 | break; | |
8ded0752 | 5834 | } |
7105fb72 | 5835 | /* FIXME: This is a bug in the optimizer, but it seems harmless |
5836 | to just avoid panicing. */ | |
5837 | if (!prev) | |
5838 | continue; | |
21022457 | 5839 | |
5840 | /* Emit the reference label of the braf where it belongs, right after | |
5841 | the casesi_jump_2 (i.e. braf). */ | |
5842 | braf_label = XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0); | |
5843 | emit_label_after (braf_label, prev); | |
5844 | ||
9eaab178 | 5845 | /* Fix up the ADDR_DIF_VEC to be relative |
5846 | to the reference address of the braf. */ | |
21022457 | 5847 | XEXP (XEXP (pat, 0), 0) = braf_label; |
8ded0752 | 5848 | } |
8ded0752 | 5849 | } |
5850 | ||
9eaab178 | 5851 | /* BARRIER_OR_LABEL is either a BARRIER or a CODE_LABEL immediately following |
5852 | a barrier. Return the base 2 logarithm of the desired alignment. */ | |
8ded0752 | 5853 | int |
91a55c11 | 5854 | barrier_align (rtx_insn *barrier_or_label) |
8ded0752 | 5855 | { |
cd316116 | 5856 | rtx next, pat; |
9e7454d0 | 5857 | |
5d2dafaf | 5858 | if (! barrier_or_label) |
5859 | return 0; | |
5860 | ||
cd316116 | 5861 | if (LABEL_P (barrier_or_label) |
5862 | && NEXT_INSN (barrier_or_label) | |
5863 | && JUMP_TABLE_DATA_P (NEXT_INSN (barrier_or_label))) | |
9eaab178 | 5864 | return 2; |
8ded0752 | 5865 | |
cd316116 | 5866 | if (BARRIER_P (barrier_or_label) |
5867 | && PREV_INSN (barrier_or_label) | |
5868 | && JUMP_TABLE_DATA_P (PREV_INSN (barrier_or_label))) | |
8ded0752 | 5869 | { |
cd316116 | 5870 | pat = PATTERN (PREV_INSN (barrier_or_label)); |
9eaab178 | 5871 | /* If this is a very small table, we want to keep the alignment after |
5872 | the table to the minimum for proper code alignment. */ | |
c17f64cc | 5873 | return ((optimize_size |
acda5809 | 5874 | || ((unsigned) XVECLEN (pat, 1) * GET_MODE_SIZE (GET_MODE (pat)) |
d767e27e | 5875 | <= (unsigned) 1 << (CACHE_LOG - 2))) |
2a6493a5 | 5876 | ? 1 << TARGET_SHMEDIA : align_jumps_log); |
8ded0752 | 5877 | } |
9eaab178 | 5878 | |
cd316116 | 5879 | next = next_active_insn (barrier_or_label); |
5880 | ||
5881 | if (! next) | |
5882 | return 0; | |
5883 | ||
5884 | pat = PATTERN (next); | |
5885 | ||
5886 | if (GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_ALIGN) | |
5887 | /* This is a barrier in front of a constant table. */ | |
5888 | return 0; | |
5889 | ||
c17f64cc | 5890 | if (optimize_size) |
9eaab178 | 5891 | return 0; |
5892 | ||
ecc15191 | 5893 | if (! TARGET_SH2 || ! optimize) |
2a6493a5 | 5894 | return align_jumps_log; |
9eaab178 | 5895 | |
1b61190c | 5896 | /* When fixing up pcloads, a constant table might be inserted just before |
5897 | the basic block that ends with the barrier. Thus, we can't trust the | |
5898 | instruction lengths before that. */ | |
5899 | if (mdep_reorg_phase > SH_FIXUP_PCLOAD) | |
8ded0752 | 5900 | { |
1b61190c | 5901 | /* Check if there is an immediately preceding branch to the insn beyond |
5902 | the barrier. We must weight the cost of discarding useful information | |
5903 | from the current cache line when executing this branch and there is | |
5904 | an alignment, against that of fetching unneeded insn in front of the | |
5905 | branch target when there is no alignment. */ | |
5906 | ||
9e7454d0 | 5907 | /* There are two delay_slot cases to consider. One is the simple case |
5908 | where the preceding branch is to the insn beyond the barrier (simple | |
5909 | delay slot filling), and the other is where the preceding branch has | |
5910 | a delay slot that is a duplicate of the insn after the barrier | |
5911 | (fill_eager_delay_slots) and the branch is to the insn after the insn | |
fd787fea | 5912 | after the barrier. */ |
5913 | ||
c3583c9c | 5914 | int slot, credit; |
5915 | bool jump_to_next = false; | |
5916 | ||
cd316116 | 5917 | /* Skip to the insn before the JUMP_INSN before the barrier under |
5918 | investigation. */ | |
91a55c11 | 5919 | rtx_insn *prev = prev_real_insn (prev_active_insn (barrier_or_label)); |
1b61190c | 5920 | |
26576132 | 5921 | for (slot = 2, credit = (1 << (CACHE_LOG - 2)) + 2; |
cbb16986 | 5922 | credit >= 0 && prev && NONJUMP_INSN_P (prev); |
1b61190c | 5923 | prev = prev_real_insn (prev)) |
5924 | { | |
c3583c9c | 5925 | jump_to_next = false; |
1b61190c | 5926 | if (GET_CODE (PATTERN (prev)) == USE |
5927 | || GET_CODE (PATTERN (prev)) == CLOBBER) | |
5928 | continue; | |
91a55c11 | 5929 | if (rtx_sequence *prev_seq = dyn_cast <rtx_sequence *> (PATTERN (prev))) |
fd787fea | 5930 | { |
91a55c11 | 5931 | prev = prev_seq->insn (1); |
9e7454d0 | 5932 | if (INSN_UID (prev) == INSN_UID (next)) |
fd787fea | 5933 | { |
5934 | /* Delay slot was filled with insn at jump target. */ | |
c3583c9c | 5935 | jump_to_next = true; |
fd787fea | 5936 | continue; |
5937 | } | |
5938 | } | |
5939 | ||
1b61190c | 5940 | if (slot && |
5941 | get_attr_in_delay_slot (prev) == IN_DELAY_SLOT_YES) | |
5942 | slot = 0; | |
5943 | credit -= get_attr_length (prev); | |
5944 | } | |
4115ac36 | 5945 | if (prev && jump_to_label_p (prev)) |
24f975d6 | 5946 | { |
91a55c11 | 5947 | rtx_insn *x; |
7628b8bf | 5948 | if (jump_to_next |
24f975d6 | 5949 | || next_real_insn (JUMP_LABEL (prev)) == next |
07eac433 | 5950 | /* If relax_delay_slots() decides NEXT was redundant |
5951 | with some previous instruction, it will have | |
5952 | redirected PREV's jump to the following insn. */ | |
67169380 | 5953 | || JUMP_LABEL (prev) == next_nonnote_insn (next) |
7628b8bf | 5954 | /* There is no upper bound on redundant instructions |
5955 | that might have been skipped, but we must not put an | |
24f975d6 | 5956 | alignment where none had been before. */ |
9e7454d0 | 5957 | || (x = (NEXT_INSN (NEXT_INSN (PREV_INSN (prev)))), |
5958 | (INSN_P (x) | |
24f975d6 | 5959 | && (INSN_CODE (x) == CODE_FOR_block_branch_redirect |
72cc4fb4 | 5960 | || INSN_CODE (x) == CODE_FOR_indirect_jump_scratch |
5961 | || INSN_CODE (x) == CODE_FOR_stuff_delay_slot)))) | |
24f975d6 | 5962 | { |
5963 | rtx pat = PATTERN (prev); | |
5964 | if (GET_CODE (pat) == PARALLEL) | |
7628b8bf | 5965 | pat = XVECEXP (pat, 0, 0); |
24f975d6 | 5966 | if (credit - slot >= (GET_CODE (SET_SRC (pat)) == PC ? 2 : 0)) |
5967 | return 0; | |
5968 | } | |
7628b8bf | 5969 | } |
9eaab178 | 5970 | } |
9e7454d0 | 5971 | |
2a6493a5 | 5972 | return align_jumps_log; |
8ded0752 | 5973 | } |
5974 | ||
afd5d59a | 5975 | /* If we are inside a phony loop, almost any kind of label can turn up as the |
5976 | first one in the loop. Aligning a braf label causes incorrect switch | |
5977 | destination addresses; we can detect braf labels because they are | |
5978 | followed by a BARRIER. | |
5979 | Applying loop alignment to small constant or switch tables is a waste | |
5980 | of space, so we suppress this too. */ | |
5981 | int | |
ed3e6e5d | 5982 | sh_loop_align (rtx_insn *label) |
afd5d59a | 5983 | { |
ed3e6e5d | 5984 | rtx_insn *next = label; |
afd5d59a | 5985 | |
164fbbdf | 5986 | if (! optimize || optimize_size) |
5987 | return 0; | |
5988 | ||
afd5d59a | 5989 | do |
5990 | next = next_nonnote_insn (next); | |
cbb16986 | 5991 | while (next && LABEL_P (next)); |
afd5d59a | 5992 | |
5993 | if (! next | |
9204e736 | 5994 | || ! INSN_P (next) |
afd5d59a | 5995 | || recog_memoized (next) == CODE_FOR_consttable_2) |
5996 | return 0; | |
87e19636 | 5997 | |
2a6493a5 | 5998 | return align_loops_log; |
afd5d59a | 5999 | } |
6000 | ||
2efea8c0 | 6001 | /* Do a final pass over the function, just before delayed branch |
90e84010 | 6002 | scheduling. */ |
2efea8c0 | 6003 | static void |
04f04b72 | 6004 | sh_reorg (void) |
97595bfd | 6005 | { |
b82334f7 | 6006 | rtx_insn *first, *insn, *mova = NULL; |
8ded0752 | 6007 | int num_mova; |
7014838c | 6008 | rtx r0_rtx = gen_rtx_REG (Pmode, 0); |
6009 | rtx r0_inc_rtx = gen_rtx_POST_INC (Pmode, r0_rtx); | |
73401833 | 6010 | |
2efea8c0 | 6011 | first = get_insns (); |
be7f5947 | 6012 | max_labelno_before_reorg = max_label_num (); |
2efea8c0 | 6013 | |
5acd0683 | 6014 | /* We must split call insns before introducing `mova's. If we're |
6015 | optimizing, they'll have already been split. Otherwise, make | |
6016 | sure we don't split them too late. */ | |
6017 | if (! optimize) | |
161b1647 | 6018 | split_all_insns_noflow (); |
5acd0683 | 6019 | |
87e19636 | 6020 | if (TARGET_SHMEDIA) |
6021 | return; | |
6022 | ||
90e84010 | 6023 | /* If relaxing, generate pseudo-ops to associate function calls with |
6024 | the symbols they call. It does no harm to not generate these | |
7a288fec | 6025 | pseudo-ops. However, when we can generate them, it enables the |
90e84010 | 6026 | linker to potentially relax the jsr to a bsr, and eliminate the |
6027 | register load and, possibly, the constant pool entry. */ | |
6028 | ||
8ded0752 | 6029 | mdep_reorg_phase = SH_INSERT_USES_LABELS; |
90e84010 | 6030 | if (TARGET_RELAX) |
6031 | { | |
19d2fe05 | 6032 | /* Remove all REG_LABEL_OPERAND notes. We want to use them for our |
6033 | own purposes. This works because none of the remaining passes | |
90e84010 | 6034 | need to look at them. |
6035 | ||
6036 | ??? But it may break in the future. We should use a machine | |
6037 | dependent REG_NOTE, or some other approach entirely. */ | |
6038 | for (insn = first; insn; insn = NEXT_INSN (insn)) | |
6039 | { | |
9204e736 | 6040 | if (INSN_P (insn)) |
90e84010 | 6041 | { |
6042 | rtx note; | |
6043 | ||
19d2fe05 | 6044 | while ((note = find_reg_note (insn, REG_LABEL_OPERAND, |
6045 | NULL_RTX)) != 0) | |
90e84010 | 6046 | remove_note (insn, note); |
6047 | } | |
6048 | } | |
6049 | ||
6050 | for (insn = first; insn; insn = NEXT_INSN (insn)) | |
6051 | { | |
79f6a8ed | 6052 | rtx pattern, reg, set, dies; |
6053 | rtx_code_label *label; | |
b82334f7 | 6054 | rtx_insn *link, *scan; |
90e84010 | 6055 | int rescan = 0, foundinsn = 0; |
6056 | ||
cbb16986 | 6057 | if (CALL_P (insn)) |
881ffd32 | 6058 | { |
6059 | pattern = PATTERN (insn); | |
90e84010 | 6060 | |
881ffd32 | 6061 | if (GET_CODE (pattern) == PARALLEL) |
6062 | pattern = XVECEXP (pattern, 0, 0); | |
6063 | if (GET_CODE (pattern) == SET) | |
6064 | pattern = SET_SRC (pattern); | |
90e84010 | 6065 | |
881ffd32 | 6066 | if (GET_CODE (pattern) != CALL |
cbb16986 | 6067 | || !MEM_P (XEXP (pattern, 0))) |
881ffd32 | 6068 | continue; |
90e84010 | 6069 | |
881ffd32 | 6070 | reg = XEXP (XEXP (pattern, 0), 0); |
6071 | } | |
6072 | else | |
6073 | { | |
6074 | reg = sfunc_uses_reg (insn); | |
6075 | if (! reg) | |
6076 | continue; | |
6077 | } | |
90e84010 | 6078 | |
cbb16986 | 6079 | if (!REG_P (reg)) |
90e84010 | 6080 | continue; |
6081 | ||
3072d30e | 6082 | /* Try scanning backward to find where the register is set. */ |
6083 | link = NULL; | |
6084 | for (scan = PREV_INSN (insn); | |
cbb16986 | 6085 | scan && !LABEL_P (scan); |
3072d30e | 6086 | scan = PREV_INSN (scan)) |
90e84010 | 6087 | { |
3072d30e | 6088 | if (! INSN_P (scan)) |
6c049e03 | 6089 | continue; |
90e84010 | 6090 | |
3072d30e | 6091 | if (! reg_mentioned_p (reg, scan)) |
6c049e03 | 6092 | continue; |
90e84010 | 6093 | |
3072d30e | 6094 | if (noncall_uses_reg (reg, scan, &set)) |
6c049e03 | 6095 | break; |
90e84010 | 6096 | |
3072d30e | 6097 | if (set) |
6098 | { | |
6099 | link = scan; | |
6100 | break; | |
90e84010 | 6101 | } |
6102 | } | |
6103 | ||
6104 | if (! link) | |
6105 | continue; | |
6106 | ||
6107 | /* The register is set at LINK. */ | |
6108 | ||
6109 | /* We can only optimize the function call if the register is | |
6c049e03 | 6110 | being set to a symbol. In theory, we could sometimes |
6111 | optimize calls to a constant location, but the assembler | |
6112 | and linker do not support that at present. */ | |
90e84010 | 6113 | if (GET_CODE (SET_SRC (set)) != SYMBOL_REF |
6114 | && GET_CODE (SET_SRC (set)) != LABEL_REF) | |
6115 | continue; | |
6116 | ||
6117 | /* Scan forward from LINK to the place where REG dies, and | |
6c049e03 | 6118 | make sure that the only insns which use REG are |
6119 | themselves function calls. */ | |
90e84010 | 6120 | |
4fa2e8b8 | 6121 | /* ??? This doesn't work for call targets that were allocated |
6122 | by reload, since there may not be a REG_DEAD note for the | |
6123 | register. */ | |
6124 | ||
90e84010 | 6125 | dies = NULL_RTX; |
6126 | for (scan = NEXT_INSN (link); scan; scan = NEXT_INSN (scan)) | |
6127 | { | |
6128 | rtx scanset; | |
6129 | ||
4fa2e8b8 | 6130 | /* Don't try to trace forward past a CODE_LABEL if we haven't |
6131 | seen INSN yet. Ordinarily, we will only find the setting insn | |
3072d30e | 6132 | if it is in the same basic block. However, |
4fa2e8b8 | 6133 | cross-jumping can insert code labels in between the load and |
6134 | the call, and can result in situations where a single call | |
6135 | insn may have two targets depending on where we came from. */ | |
6136 | ||
cbb16986 | 6137 | if (LABEL_P (scan) && ! foundinsn) |
4fa2e8b8 | 6138 | break; |
6139 | ||
9204e736 | 6140 | if (! INSN_P (scan)) |
90e84010 | 6141 | continue; |
6142 | ||
6143 | /* Don't try to trace forward past a JUMP. To optimize | |
6c049e03 | 6144 | safely, we would have to check that all the |
6145 | instructions at the jump destination did not use REG. */ | |
90e84010 | 6146 | |
cbb16986 | 6147 | if (JUMP_P (scan)) |
90e84010 | 6148 | break; |
6149 | ||
6150 | if (! reg_mentioned_p (reg, scan)) | |
6151 | continue; | |
6152 | ||
6153 | if (noncall_uses_reg (reg, scan, &scanset)) | |
6154 | break; | |
6155 | ||
6156 | if (scan == insn) | |
6157 | foundinsn = 1; | |
6158 | ||
881ffd32 | 6159 | if (scan != insn |
cbb16986 | 6160 | && (CALL_P (scan) || sfunc_uses_reg (scan))) |
90e84010 | 6161 | { |
6162 | /* There is a function call to this register other | |
6c049e03 | 6163 | than the one we are checking. If we optimize |
6164 | this call, we need to rescan again below. */ | |
90e84010 | 6165 | rescan = 1; |
6166 | } | |
6167 | ||
6168 | /* ??? We shouldn't have to worry about SCANSET here. | |
6169 | We should just be able to check for a REG_DEAD note | |
6170 | on a function call. However, the REG_DEAD notes are | |
6171 | apparently not dependable around libcalls; c-torture | |
6172 | execute/920501-2 is a test case. If SCANSET is set, | |
6173 | then this insn sets the register, so it must have | |
6174 | died earlier. Unfortunately, this will only handle | |
6175 | the cases in which the register is, in fact, set in a | |
6176 | later insn. */ | |
6177 | ||
6178 | /* ??? We shouldn't have to use FOUNDINSN here. | |
3072d30e | 6179 | This dates back to when we used LOG_LINKS to find |
6180 | the most recent insn which sets the register. */ | |
90e84010 | 6181 | |
6182 | if (foundinsn | |
6183 | && (scanset | |
6184 | || find_reg_note (scan, REG_DEAD, reg))) | |
6185 | { | |
6186 | dies = scan; | |
6187 | break; | |
6188 | } | |
6189 | } | |
6190 | ||
6191 | if (! dies) | |
6192 | { | |
6193 | /* Either there was a branch, or some insn used REG | |
6c049e03 | 6194 | other than as a function call address. */ |
90e84010 | 6195 | continue; |
6196 | } | |
6197 | ||
19d2fe05 | 6198 | /* Create a code label, and put it in a REG_LABEL_OPERAND note |
6c049e03 | 6199 | on the insn which sets the register, and on each call insn |
6200 | which uses the register. In final_prescan_insn we look for | |
6201 | the REG_LABEL_OPERAND notes, and output the appropriate label | |
6202 | or pseudo-op. */ | |
90e84010 | 6203 | |
6204 | label = gen_label_rtx (); | |
a1ddb869 | 6205 | add_reg_note (link, REG_LABEL_OPERAND, label); |
6206 | add_reg_note (insn, REG_LABEL_OPERAND, label); | |
90e84010 | 6207 | if (rescan) |
6208 | { | |
6209 | scan = link; | |
6210 | do | |
6211 | { | |
881ffd32 | 6212 | rtx reg2; |
6213 | ||
90e84010 | 6214 | scan = NEXT_INSN (scan); |
6215 | if (scan != insn | |
cbb16986 | 6216 | && ((CALL_P (scan) |
881ffd32 | 6217 | && reg_mentioned_p (reg, scan)) |
6218 | || ((reg2 = sfunc_uses_reg (scan)) | |
6219 | && REGNO (reg2) == REGNO (reg)))) | |
a1ddb869 | 6220 | add_reg_note (scan, REG_LABEL_OPERAND, label); |
90e84010 | 6221 | } |
6222 | while (scan != dies); | |
6223 | } | |
6224 | } | |
6225 | } | |
6226 | ||
9eaab178 | 6227 | if (TARGET_SH2) |
6228 | fixup_addr_diff_vecs (first); | |
8ded0752 | 6229 | |
6230 | if (optimize) | |
6231 | { | |
8ded0752 | 6232 | mdep_reorg_phase = SH_SHORTEN_BRANCHES0; |
6233 | shorten_branches (first); | |
6234 | } | |
49166fc3 | 6235 | |
90e84010 | 6236 | /* Scan the function looking for move instructions which have to be |
6237 | changed to pc-relative loads and insert the literal tables. */ | |
49166fc3 | 6238 | label_ref_list_pool = create_alloc_pool ("label references list", |
6239 | sizeof (struct label_ref_list_d), | |
6240 | 30); | |
8ded0752 | 6241 | mdep_reorg_phase = SH_FIXUP_PCLOAD; |
6242 | for (insn = first, num_mova = 0; insn; insn = NEXT_INSN (insn)) | |
97595bfd | 6243 | { |
8ded0752 | 6244 | if (mova_p (insn)) |
6245 | { | |
51dade95 | 6246 | /* ??? basic block reordering can move a switch table dispatch |
6247 | below the switch table. Check if that has happened. | |
6248 | We only have the addresses available when optimizing; but then, | |
6249 | this check shouldn't be needed when not optimizing. */ | |
be7f5947 | 6250 | if (!untangle_mova (&num_mova, &mova, insn)) |
51dade95 | 6251 | { |
be7f5947 | 6252 | insn = mova; |
6253 | num_mova = 0; | |
51dade95 | 6254 | } |
8ded0752 | 6255 | } |
77985f1a | 6256 | else if (JUMP_TABLE_DATA_P (insn) |
8ded0752 | 6257 | && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC |
be7f5947 | 6258 | && num_mova |
6259 | /* ??? loop invariant motion can also move a mova out of a | |
6260 | loop. Since loop does this code motion anyway, maybe we | |
6261 | should wrap UNSPEC_MOVA into a CONST, so that reload can | |
6262 | move it back. */ | |
6263 | && ((num_mova > 1 | |
6264 | && GET_MODE (prev_nonnote_insn (insn)) == VOIDmode) | |
6265 | || (prev_nonnote_insn (insn) | |
6266 | == XEXP (MOVA_LABELREF (mova), 0)))) | |
8ded0752 | 6267 | { |
91a55c11 | 6268 | rtx_insn *scan; |
8ded0752 | 6269 | int total; |
6270 | ||
6271 | num_mova--; | |
6272 | ||
6273 | /* Some code might have been inserted between the mova and | |
6274 | its ADDR_DIFF_VEC. Check if the mova is still in range. */ | |
6275 | for (scan = mova, total = 0; scan != insn; scan = NEXT_INSN (scan)) | |
9eaab178 | 6276 | total += get_attr_length (scan); |
8ded0752 | 6277 | |
6278 | /* range of mova is 1020, add 4 because pc counts from address of | |
6279 | second instruction after this one, subtract 2 in case pc is 2 | |
6280 | byte aligned. Possible alignment needed for the ADDR_DIFF_VEC | |
ad87de1e | 6281 | cancels out with alignment effects of the mova itself. */ |
8ded0752 | 6282 | if (total > 1022) |
6283 | { | |
6284 | /* Change the mova into a load, and restart scanning | |
6285 | there. broken_move will then return true for mova. */ | |
51dade95 | 6286 | fixup_mova (mova); |
8ded0752 | 6287 | insn = mova; |
6288 | } | |
6289 | } | |
51dade95 | 6290 | if (broken_move (insn) |
cbb16986 | 6291 | || (NONJUMP_INSN_P (insn) |
51dade95 | 6292 | && recog_memoized (insn) == CODE_FOR_casesi_worker_2)) |
97595bfd | 6293 | { |
b82334f7 | 6294 | rtx_insn *scan; |
73401833 | 6295 | /* Scan ahead looking for a barrier to stick the constant table |
6296 | behind. */ | |
b82334f7 | 6297 | rtx_insn *barrier = find_barrier (num_mova, mova, insn); |
311f821c | 6298 | rtx_insn *last_float_move = NULL; |
6299 | rtx last_float = 0, *last_float_addr = NULL; | |
51dade95 | 6300 | int need_aligned_label = 0; |
47c009e5 | 6301 | |
8ded0752 | 6302 | if (num_mova && ! mova_p (mova)) |
6303 | { | |
6304 | /* find_barrier had to change the first mova into a | |
6305 | pcload; thus, we have to start with this new pcload. */ | |
6306 | insn = mova; | |
6307 | num_mova = 0; | |
6308 | } | |
1504eb7e | 6309 | /* Now find all the moves between the points and modify them. */ |
97595bfd | 6310 | for (scan = insn; scan != barrier; scan = NEXT_INSN (scan)) |
6311 | { | |
cbb16986 | 6312 | if (LABEL_P (scan)) |
8ded0752 | 6313 | last_float = 0; |
cbb16986 | 6314 | if (NONJUMP_INSN_P (scan) |
51dade95 | 6315 | && recog_memoized (scan) == CODE_FOR_casesi_worker_2) |
6316 | need_aligned_label = 1; | |
97595bfd | 6317 | if (broken_move (scan)) |
6318 | { | |
00f87557 | 6319 | rtx *patp = &PATTERN (scan), pat = *patp; |
6320 | rtx src, dst; | |
97595bfd | 6321 | rtx lab; |
97595bfd | 6322 | rtx newsrc; |
3754d046 | 6323 | machine_mode mode; |
00f87557 | 6324 | |
6325 | if (GET_CODE (pat) == PARALLEL) | |
6326 | patp = &XVECEXP (pat, 0, 0), pat = *patp; | |
6327 | src = SET_SRC (pat); | |
6328 | dst = SET_DEST (pat); | |
6329 | mode = GET_MODE (dst); | |
97595bfd | 6330 | |
e75e7428 | 6331 | if (mode == SImode && satisfies_constraint_I16 (src) |
1b61190c | 6332 | && REGNO (dst) != FPUL_REG) |
97595bfd | 6333 | { |
59a5a83f | 6334 | int offset = 0; |
73401833 | 6335 | |
97595bfd | 6336 | mode = HImode; |
f3d93547 | 6337 | while (GET_CODE (dst) == SUBREG) |
59a5a83f | 6338 | { |
701e46d0 | 6339 | offset += subreg_regno_offset (REGNO (SUBREG_REG (dst)), |
6340 | GET_MODE (SUBREG_REG (dst)), | |
6341 | SUBREG_BYTE (dst), | |
6342 | GET_MODE (dst)); | |
59a5a83f | 6343 | dst = SUBREG_REG (dst); |
6344 | } | |
7014838c | 6345 | dst = gen_rtx_REG (HImode, REGNO (dst) + offset); |
97595bfd | 6346 | } |
cbb16986 | 6347 | if (REG_P (dst) && FP_ANY_REGISTER_P (REGNO (dst))) |
8ded0752 | 6348 | { |
c961a48b | 6349 | /* This must be an insn that clobbers r0. */ |
adbf1ac5 | 6350 | rtx *clobberp = &XVECEXP (PATTERN (scan), 0, |
6351 | XVECLEN (PATTERN (scan), 0) | |
6352 | - 1); | |
6353 | rtx clobber = *clobberp; | |
c961a48b | 6354 | |
1a6a7a27 | 6355 | gcc_assert (GET_CODE (clobber) == CLOBBER |
6356 | && rtx_equal_p (XEXP (clobber, 0), r0_rtx)); | |
c961a48b | 6357 | |
8ded0752 | 6358 | if (last_float |
6359 | && reg_set_between_p (r0_rtx, last_float_move, scan)) | |
6360 | last_float = 0; | |
c5ea35c4 | 6361 | if (last_float |
6362 | && TARGET_SHCOMPACT | |
6363 | && GET_MODE_SIZE (mode) != 4 | |
6364 | && GET_MODE_SIZE (GET_MODE (last_float)) == 4) | |
6365 | last_float = 0; | |
8ded0752 | 6366 | lab = add_constant (src, mode, last_float); |
6367 | if (lab) | |
6368 | emit_insn_before (gen_mova (lab), scan); | |
6369 | else | |
c961a48b | 6370 | { |
6371 | /* There will be a REG_UNUSED note for r0 on | |
6372 | LAST_FLOAT_MOVE; we have to change it to REG_INC, | |
6373 | lest reorg:mark_target_live_regs will not | |
6374 | consider r0 to be used, and we end up with delay | |
d06d4df0 | 6375 | slot insn in front of SCAN that clobbers r0. */ |
c961a48b | 6376 | rtx note |
6377 | = find_regno_note (last_float_move, REG_UNUSED, 0); | |
6378 | ||
46bc3e81 | 6379 | /* If we are not optimizing, then there may not be |
6380 | a note. */ | |
6381 | if (note) | |
bc620c5c | 6382 | PUT_REG_NOTE_KIND (note, REG_INC); |
c961a48b | 6383 | |
6384 | *last_float_addr = r0_inc_rtx; | |
6385 | } | |
8ded0752 | 6386 | last_float_move = scan; |
6387 | last_float = src; | |
aa7e75f2 | 6388 | newsrc = gen_const_mem (mode, |
b7dbbdb2 | 6389 | (((TARGET_SH4 && ! TARGET_FMOVD) |
1b61190c | 6390 | || REGNO (dst) == FPUL_REG) |
8ded0752 | 6391 | ? r0_inc_rtx |
6392 | : r0_rtx)); | |
6393 | last_float_addr = &XEXP (newsrc, 0); | |
c961a48b | 6394 | |
6395 | /* Remove the clobber of r0. */ | |
adbf1ac5 | 6396 | *clobberp = gen_rtx_CLOBBER (GET_MODE (clobber), |
6397 | gen_rtx_SCRATCH (Pmode)); | |
8ded0752 | 6398 | } |
0abf894c | 6399 | /* This is a mova needing a label. Create it. */ |
393fac7b | 6400 | else if (GET_CODE (src) == UNSPEC |
6401 | && XINT (src, 1) == UNSPEC_MOVA | |
6402 | && GET_CODE (XVECEXP (src, 0, 0)) == CONST) | |
0abf894c | 6403 | { |
393fac7b | 6404 | lab = add_constant (XVECEXP (src, 0, 0), mode, 0); |
0abf894c | 6405 | newsrc = gen_rtx_LABEL_REF (VOIDmode, lab); |
f4dba476 | 6406 | newsrc = gen_rtx_UNSPEC (SImode, |
a5bd34f1 | 6407 | gen_rtvec (1, newsrc), |
6408 | UNSPEC_MOVA); | |
0abf894c | 6409 | } |
31fd081d | 6410 | else if (GET_CODE (src) == UNSPEC_VOLATILE |
6411 | && XINT (src, 1) == UNSPECV_SP_SWITCH_B) | |
6412 | { | |
6413 | newsrc = XVECEXP (src, 0, 0); | |
6414 | XVECEXP (src, 0, 0) = gen_const_mem (mode, newsrc); | |
6415 | INSN_CODE (scan) = -1; | |
6416 | continue; | |
6417 | } | |
8ded0752 | 6418 | else |
6419 | { | |
6420 | lab = add_constant (src, mode, 0); | |
e265a6da | 6421 | newsrc = gen_rtx_LABEL_REF (VOIDmode, lab); |
6422 | newsrc = gen_const_mem (mode, newsrc); | |
8ded0752 | 6423 | } |
7014838c | 6424 | *patp = gen_rtx_SET (VOIDmode, dst, newsrc); |
00f87557 | 6425 | INSN_CODE (scan) = -1; |
97595bfd | 6426 | } |
6427 | } | |
51dade95 | 6428 | dump_table (need_aligned_label ? insn : 0, barrier); |
8ded0752 | 6429 | insn = barrier; |
97595bfd | 6430 | } |
6431 | } | |
49166fc3 | 6432 | free_alloc_pool (label_ref_list_pool); |
be7f5947 | 6433 | for (insn = first; insn; insn = NEXT_INSN (insn)) |
6434 | PUT_MODE (insn, VOIDmode); | |
6435 | ||
8ded0752 | 6436 | mdep_reorg_phase = SH_SHORTEN_BRANCHES1; |
47fc0706 | 6437 | INSN_ADDRESSES_FREE (); |
8ded0752 | 6438 | split_branches (first); |
6439 | ||
6440 | /* The INSN_REFERENCES_ARE_DELAYED in sh.h is problematic because it | |
f747aa2d | 6441 | also has an effect on the register that holds the address of the sfunc. |
8ded0752 | 6442 | Insert an extra dummy insn in front of each sfunc that pretends to |
6443 | use this register. */ | |
6444 | if (flag_delayed_branch) | |
6445 | { | |
6446 | for (insn = first; insn; insn = NEXT_INSN (insn)) | |
6447 | { | |
6448 | rtx reg = sfunc_uses_reg (insn); | |
6449 | ||
6450 | if (! reg) | |
6451 | continue; | |
6452 | emit_insn_before (gen_use_sfunc_addr (reg), insn); | |
6453 | } | |
6454 | } | |
6455 | mdep_reorg_phase = SH_AFTER_MDEP_REORG; | |
6456 | } | |
6457 | ||
6c049e03 | 6458 | /* Return the UID of the insn that follows the specified label. */ |
8ded0752 | 6459 | int |
04f04b72 | 6460 | get_dest_uid (rtx label, int max_uid) |
8ded0752 | 6461 | { |
91a55c11 | 6462 | rtx_insn *dest = next_real_insn (label); |
8ded0752 | 6463 | int dest_uid; |
6464 | if (! dest) | |
6465 | /* This can happen for an undefined label. */ | |
6466 | return 0; | |
6467 | dest_uid = INSN_UID (dest); | |
6468 | /* If this is a newly created branch redirection blocking instruction, | |
6469 | we cannot index the branch_uid or insn_addresses arrays with its | |
6470 | uid. But then, we won't need to, because the actual destination is | |
6471 | the following branch. */ | |
6472 | while (dest_uid >= max_uid) | |
6473 | { | |
6474 | dest = NEXT_INSN (dest); | |
6475 | dest_uid = INSN_UID (dest); | |
6476 | } | |
cbb16986 | 6477 | if (JUMP_P (dest) && GET_CODE (PATTERN (dest)) == RETURN) |
8ded0752 | 6478 | return 0; |
6479 | return dest_uid; | |
6480 | } | |
6481 | ||
6482 | /* Split condbranches that are out of range. Also add clobbers for | |
6483 | scratch registers that are needed in far jumps. | |
6484 | We do this before delay slot scheduling, so that it can take our | |
6485 | newly created instructions into account. It also allows us to | |
6486 | find branches with common targets more easily. */ | |
8ded0752 | 6487 | static void |
b82334f7 | 6488 | split_branches (rtx_insn *first) |
8ded0752 | 6489 | { |
b82334f7 | 6490 | rtx_insn *insn; |
8ded0752 | 6491 | struct far_branch **uid_branch, *far_branch_list = 0; |
6492 | int max_uid = get_max_uid (); | |
1a6a7a27 | 6493 | int ok; |
8ded0752 | 6494 | |
6495 | /* Find out which branches are out of range. */ | |
8ded0752 | 6496 | shorten_branches (first); |
6497 | ||
6498 | uid_branch = (struct far_branch **) alloca (max_uid * sizeof *uid_branch); | |
8e547276 | 6499 | memset ((char *) uid_branch, 0, max_uid * sizeof *uid_branch); |
8ded0752 | 6500 | |
6501 | for (insn = first; insn; insn = NEXT_INSN (insn)) | |
9204e736 | 6502 | if (! INSN_P (insn)) |
8ded0752 | 6503 | continue; |
dd1286fb | 6504 | else if (insn->deleted ()) |
8ded0752 | 6505 | { |
6506 | /* Shorten_branches would split this instruction again, | |
6507 | so transform it into a note. */ | |
ad4583d9 | 6508 | SET_INSN_DELETED (insn); |
8ded0752 | 6509 | } |
91f71fa3 | 6510 | else if (JUMP_P (insn)) |
8ded0752 | 6511 | { |
6512 | enum attr_type type = get_attr_type (insn); | |
6513 | if (type == TYPE_CBRANCH) | |
6514 | { | |
91a55c11 | 6515 | rtx_insn *next, *beyond; |
9e7454d0 | 6516 | |
8ded0752 | 6517 | if (get_attr_length (insn) > 4) |
6518 | { | |
6519 | rtx src = SET_SRC (PATTERN (insn)); | |
8ded0752 | 6520 | rtx olabel = XEXP (XEXP (src, 1), 0); |
47fc0706 | 6521 | int addr = INSN_ADDRESSES (INSN_UID (insn)); |
91a55c11 | 6522 | rtx_insn *label = 0; |
8ded0752 | 6523 | int dest_uid = get_dest_uid (olabel, max_uid); |
6524 | struct far_branch *bp = uid_branch[dest_uid]; | |
9e7454d0 | 6525 | |
8ded0752 | 6526 | /* redirect_jump needs a valid JUMP_LABEL, and it might delete |
40df6fd4 | 6527 | the label if the LABEL_NUSES count drops to zero. There is |
8ded0752 | 6528 | always a jump_optimize pass that sets these values, but it |
6529 | proceeds to delete unreferenced code, and then if not | |
ad87de1e | 6530 | optimizing, to un-delete the deleted instructions, thus |
8ded0752 | 6531 | leaving labels with too low uses counts. */ |
6532 | if (! optimize) | |
6533 | { | |
6534 | JUMP_LABEL (insn) = olabel; | |
6535 | LABEL_NUSES (olabel)++; | |
6536 | } | |
6537 | if (! bp) | |
6538 | { | |
6539 | bp = (struct far_branch *) alloca (sizeof *bp); | |
6540 | uid_branch[dest_uid] = bp; | |
6541 | bp->prev = far_branch_list; | |
6542 | far_branch_list = bp; | |
91a55c11 | 6543 | bp->far_label = as_a <rtx_insn *> ( |
6544 | XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), | |
6545 | 0)); | |
8ded0752 | 6546 | LABEL_NUSES (bp->far_label)++; |
6547 | } | |
6548 | else | |
6549 | { | |
6550 | label = bp->near_label; | |
6551 | if (! label && bp->address - addr >= CONDJUMP_MIN) | |
6552 | { | |
91a55c11 | 6553 | rtx_insn *block = bp->insert_place; |
8ded0752 | 6554 | |
6555 | if (GET_CODE (PATTERN (block)) == RETURN) | |
6556 | block = PREV_INSN (block); | |
6557 | else | |
6558 | block = gen_block_redirect (block, | |
6559 | bp->address, 2); | |
6560 | label = emit_label_after (gen_label_rtx (), | |
6561 | PREV_INSN (block)); | |
6562 | bp->near_label = label; | |
6563 | } | |
6564 | else if (label && ! NEXT_INSN (label)) | |
17bec211 | 6565 | { |
6566 | if (addr + 2 - bp->address <= CONDJUMP_MAX) | |
6567 | bp->insert_place = insn; | |
6568 | else | |
6569 | gen_far_branch (bp); | |
6570 | } | |
8ded0752 | 6571 | } |
6572 | if (! label | |
b7dbbdb2 | 6573 | || (NEXT_INSN (label) && bp->address - addr < CONDJUMP_MIN)) |
8ded0752 | 6574 | { |
6575 | bp->near_label = label = gen_label_rtx (); | |
6576 | bp->insert_place = insn; | |
6577 | bp->address = addr; | |
6578 | } | |
5b54eabf | 6579 | ok = redirect_jump (insn, label, 0); |
1a6a7a27 | 6580 | gcc_assert (ok); |
8ded0752 | 6581 | } |
6582 | else | |
6583 | { | |
6584 | /* get_attr_length (insn) == 2 */ | |
6585 | /* Check if we have a pattern where reorg wants to redirect | |
6586 | the branch to a label from an unconditional branch that | |
6587 | is too far away. */ | |
6588 | /* We can't use JUMP_LABEL here because it might be undefined | |
6589 | when not optimizing. */ | |
9eaab178 | 6590 | /* A syntax error might cause beyond to be NULL_RTX. */ |
8ded0752 | 6591 | beyond |
6592 | = next_active_insn (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), | |
6593 | 0)); | |
9e7454d0 | 6594 | |
9eaab178 | 6595 | if (beyond |
cbb16986 | 6596 | && (JUMP_P (beyond) |
b1060622 | 6597 | || ((beyond = next_active_insn (beyond)) |
cbb16986 | 6598 | && JUMP_P (beyond))) |
8ded0752 | 6599 | && GET_CODE (PATTERN (beyond)) == SET |
adbcc7c4 | 6600 | && recog_memoized (beyond) == CODE_FOR_jump_compact |
47fc0706 | 6601 | && ((INSN_ADDRESSES |
6602 | (INSN_UID (XEXP (SET_SRC (PATTERN (beyond)), 0))) | |
30435bf8 | 6603 | - INSN_ADDRESSES (INSN_UID (insn)) + (unsigned) 252) |
8ded0752 | 6604 | > 252 + 258 + 2)) |
6605 | gen_block_redirect (beyond, | |
47fc0706 | 6606 | INSN_ADDRESSES (INSN_UID (beyond)), 1); |
8ded0752 | 6607 | } |
9e7454d0 | 6608 | |
8ded0752 | 6609 | next = next_active_insn (insn); |
6610 | ||
03dac8f9 | 6611 | if (next |
6612 | && (JUMP_P (next) | |
6613 | || ((next = next_active_insn (next)) | |
6614 | && JUMP_P (next))) | |
8ded0752 | 6615 | && GET_CODE (PATTERN (next)) == SET |
adbcc7c4 | 6616 | && recog_memoized (next) == CODE_FOR_jump_compact |
47fc0706 | 6617 | && ((INSN_ADDRESSES |
6618 | (INSN_UID (XEXP (SET_SRC (PATTERN (next)), 0))) | |
30435bf8 | 6619 | - INSN_ADDRESSES (INSN_UID (insn)) + (unsigned) 252) |
8ded0752 | 6620 | > 252 + 258 + 2)) |
47fc0706 | 6621 | gen_block_redirect (next, INSN_ADDRESSES (INSN_UID (next)), 1); |
8ded0752 | 6622 | } |
6623 | else if (type == TYPE_JUMP || type == TYPE_RETURN) | |
6624 | { | |
47fc0706 | 6625 | int addr = INSN_ADDRESSES (INSN_UID (insn)); |
91a55c11 | 6626 | rtx_insn *far_label = 0; |
8ded0752 | 6627 | int dest_uid = 0; |
6628 | struct far_branch *bp; | |
6629 | ||
6630 | if (type == TYPE_JUMP) | |
6631 | { | |
91a55c11 | 6632 | far_label = as_a <rtx_insn *> ( |
6633 | XEXP (SET_SRC (PATTERN (insn)), 0)); | |
8ded0752 | 6634 | dest_uid = get_dest_uid (far_label, max_uid); |
6635 | if (! dest_uid) | |
6636 | { | |
6637 | /* Parse errors can lead to labels outside | |
6638 | the insn stream. */ | |
6639 | if (! NEXT_INSN (far_label)) | |
6640 | continue; | |
6641 | ||
6642 | if (! optimize) | |
6643 | { | |
6644 | JUMP_LABEL (insn) = far_label; | |
6645 | LABEL_NUSES (far_label)++; | |
6646 | } | |
4115ac36 | 6647 | redirect_jump (insn, ret_rtx, 1); |
8ded0752 | 6648 | far_label = 0; |
6649 | } | |
6650 | } | |
6651 | bp = uid_branch[dest_uid]; | |
6652 | if (! bp) | |
6653 | { | |
6654 | bp = (struct far_branch *) alloca (sizeof *bp); | |
6655 | uid_branch[dest_uid] = bp; | |
6656 | bp->prev = far_branch_list; | |
6657 | far_branch_list = bp; | |
6658 | bp->near_label = 0; | |
6659 | bp->far_label = far_label; | |
6660 | if (far_label) | |
6661 | LABEL_NUSES (far_label)++; | |
6662 | } | |
6663 | else if (bp->near_label && ! NEXT_INSN (bp->near_label)) | |
6664 | if (addr - bp->address <= CONDJUMP_MAX) | |
6665 | emit_label_after (bp->near_label, PREV_INSN (insn)); | |
6666 | else | |
6667 | { | |
6668 | gen_far_branch (bp); | |
6669 | bp->near_label = 0; | |
6670 | } | |
6671 | else | |
6672 | bp->near_label = 0; | |
6673 | bp->address = addr; | |
6674 | bp->insert_place = insn; | |
6675 | if (! far_label) | |
6676 | emit_insn_before (gen_block_branch_redirect (const0_rtx), insn); | |
6677 | else | |
6678 | gen_block_redirect (insn, addr, bp->near_label ? 2 : 0); | |
6679 | } | |
6680 | } | |
6681 | /* Generate all pending far branches, | |
6682 | and free our references to the far labels. */ | |
6683 | while (far_branch_list) | |
6684 | { | |
6685 | if (far_branch_list->near_label | |
6686 | && ! NEXT_INSN (far_branch_list->near_label)) | |
6687 | gen_far_branch (far_branch_list); | |
6688 | if (optimize | |
6689 | && far_branch_list->far_label | |
6690 | && ! --LABEL_NUSES (far_branch_list->far_label)) | |
6691 | delete_insn (far_branch_list->far_label); | |
6692 | far_branch_list = far_branch_list->prev; | |
6693 | } | |
bd967f88 | 6694 | |
6695 | /* Instruction length information is no longer valid due to the new | |
6696 | instructions that have been generated. */ | |
6697 | init_insn_lengths (); | |
47c009e5 | 6698 | } |
6699 | ||
73401833 | 6700 | /* Dump out instruction addresses, which is useful for debugging the |
90e84010 | 6701 | constant pool table stuff. |
6702 | ||
6703 | If relaxing, output the label and pseudo-ops used to link together | |
6c049e03 | 6704 | calls and the instruction which set the registers. |
73401833 | 6705 | |
6c049e03 | 6706 | ??? The addresses printed by this routine for insns are nonsense for |
73401833 | 6707 | insns which are inside of a sequence where none of the inner insns have |
6708 | variable length. This is because the second pass of shorten_branches | |
6709 | does not bother to update them. */ | |
2e3d4844 | 6710 | void |
b82334f7 | 6711 | final_prescan_insn (rtx_insn *insn, rtx *opvec ATTRIBUTE_UNUSED, |
04f04b72 | 6712 | int noperands ATTRIBUTE_UNUSED) |
47c009e5 | 6713 | { |
73401833 | 6714 | if (TARGET_DUMPISIZE) |
47fc0706 | 6715 | fprintf (asm_out_file, "\n! at %04x\n", INSN_ADDRESSES (INSN_UID (insn))); |
90e84010 | 6716 | |
6717 | if (TARGET_RELAX) | |
6718 | { | |
6719 | rtx note; | |
6720 | ||
19d2fe05 | 6721 | note = find_reg_note (insn, REG_LABEL_OPERAND, NULL_RTX); |
90e84010 | 6722 | if (note) |
6723 | { | |
6724 | rtx pattern; | |
6725 | ||
6726 | pattern = PATTERN (insn); | |
a866e0f2 | 6727 | if (GET_CODE (pattern) == PARALLEL) |
6728 | pattern = XVECEXP (pattern, 0, 0); | |
1a6a7a27 | 6729 | switch (GET_CODE (pattern)) |
6730 | { | |
1a6a7a27 | 6731 | case SET: |
6732 | if (GET_CODE (SET_SRC (pattern)) != CALL | |
6733 | && get_attr_type (insn) != TYPE_SFUNC) | |
6734 | { | |
6735 | targetm.asm_out.internal_label | |
6736 | (asm_out_file, "L", CODE_LABEL_NUMBER (XEXP (note, 0))); | |
6737 | break; | |
6738 | } | |
6739 | /* else FALLTHROUGH */ | |
6740 | case CALL: | |
6741 | asm_fprintf (asm_out_file, "\t.uses %LL%d\n", | |
6742 | CODE_LABEL_NUMBER (XEXP (note, 0))); | |
6743 | break; | |
6744 | ||
6745 | default: | |
6746 | gcc_unreachable (); | |
6747 | } | |
90e84010 | 6748 | } |
6749 | } | |
97595bfd | 6750 | } |
47c009e5 | 6751 | |
73401833 | 6752 | /* Dump out any constants accumulated in the final pass. These will |
3398e91d | 6753 | only be labels. */ |
b7dbbdb2 | 6754 | const char * |
04f04b72 | 6755 | output_jump_label_table (void) |
97595bfd | 6756 | { |
73401833 | 6757 | int i; |
6758 | ||
6759 | if (pool_size) | |
6760 | { | |
6761 | fprintf (asm_out_file, "\t.align 2\n"); | |
6762 | for (i = 0; i < pool_size; i++) | |
6763 | { | |
6764 | pool_node *p = &pool_vector[i]; | |
6765 | ||
805e22b2 | 6766 | (*targetm.asm_out.internal_label) (asm_out_file, "L", |
73401833 | 6767 | CODE_LABEL_NUMBER (p->label)); |
6768 | output_asm_insn (".long %O0", &p->value); | |
6769 | } | |
6770 | pool_size = 0; | |
6771 | } | |
47c009e5 | 6772 | |
73401833 | 6773 | return ""; |
6774 | } | |
6775 | \f | |
6776 | /* A full frame looks like: | |
1504eb7e | 6777 | |
6778 | arg-5 | |
6779 | arg-4 | |
6780 | [ if current_function_anonymous_args | |
6781 | arg-3 | |
6782 | arg-2 | |
6783 | arg-1 | |
6784 | arg-0 ] | |
6785 | saved-fp | |
6786 | saved-r10 | |
6787 | saved-r11 | |
6788 | saved-r12 | |
6789 | saved-pr | |
6790 | local-n | |
6791 | .. | |
6792 | local-1 | |
6c049e03 | 6793 | local-0 <- fp points here. |
2e3d4844 | 6794 | |
6c049e03 | 6795 | Number of bytes pushed for anonymous args, used to pass information |
6796 | between expand_prologue and expand_epilogue. | |
73401833 | 6797 | |
6c049e03 | 6798 | Adjust the stack by SIZE bytes. REG holds the rtl of the register to be |
41fafa66 | 6799 | adjusted. If epilogue_p is zero, this is for a prologue; otherwise, it's |
66209063 | 6800 | for an epilogue and a negative value means that it's for a sibcall |
6801 | epilogue. If LIVE_REGS_MASK is nonzero, it points to a HARD_REG_SET of | |
6802 | all the registers that are about to be restored, and hence dead. */ | |
73401833 | 6803 | static void |
41fafa66 | 6804 | output_stack_adjust (int size, rtx reg, int epilogue_p, |
b324d3bd | 6805 | HARD_REG_SET *live_regs_mask, bool frame_p) |
73401833 | 6806 | { |
722334ea | 6807 | rtx_insn *(*emit_fn) (rtx) = frame_p ? &frame_insn : &emit_insn; |
73401833 | 6808 | if (size) |
6809 | { | |
87e19636 | 6810 | HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT; |
6811 | ||
7105fb72 | 6812 | /* This test is bogus, as output_stack_adjust is used to re-align the |
6813 | stack. */ | |
6814 | #if 0 | |
1a6a7a27 | 6815 | gcc_assert (!(size % align)); |
7105fb72 | 6816 | #endif |
87e19636 | 6817 | |
6818 | if (CONST_OK_FOR_ADD (size)) | |
363600c8 | 6819 | emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size))); |
b9d4bd5a | 6820 | /* Try to do it with two partial adjustments; however, we must make |
6821 | sure that the stack is properly aligned at all times, in case | |
9df03d69 | 6822 | an interrupt occurs between the two partial adjustments. */ |
87e19636 | 6823 | else if (CONST_OK_FOR_ADD (size / 2 & -align) |
6824 | && CONST_OK_FOR_ADD (size - (size / 2 & -align))) | |
b9d4bd5a | 6825 | { |
363600c8 | 6826 | emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size / 2 & -align))); |
6827 | emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size - (size / 2 & -align)))); | |
b9d4bd5a | 6828 | } |
6829 | else | |
73401833 | 6830 | { |
b9d4bd5a | 6831 | rtx const_reg; |
363600c8 | 6832 | rtx insn; |
41fafa66 | 6833 | int temp = epilogue_p ? 7 : (TARGET_SH5 ? 0 : 1); |
6834 | int i; | |
b9d4bd5a | 6835 | |
6836 | /* If TEMP is invalid, we could temporarily save a general | |
6837 | register to MACL. However, there is currently no need | |
1a6a7a27 | 6838 | to handle this case, so just die when we see it. */ |
66209063 | 6839 | if (epilogue_p < 0 |
6840 | || current_function_interrupt | |
956dd562 | 6841 | || ! call_really_used_regs[temp] || fixed_regs[temp]) |
41fafa66 | 6842 | temp = -1; |
66209063 | 6843 | if (temp < 0 && ! current_function_interrupt |
6844 | && (TARGET_SHMEDIA || epilogue_p >= 0)) | |
41fafa66 | 6845 | { |
6846 | HARD_REG_SET temps; | |
6847 | COPY_HARD_REG_SET (temps, call_used_reg_set); | |
6848 | AND_COMPL_HARD_REG_SET (temps, call_fixed_reg_set); | |
66209063 | 6849 | if (epilogue_p > 0) |
41fafa66 | 6850 | { |
66209063 | 6851 | int nreg = 0; |
abe32cce | 6852 | if (crtl->return_rtx) |
66209063 | 6853 | { |
3754d046 | 6854 | machine_mode mode; |
abe32cce | 6855 | mode = GET_MODE (crtl->return_rtx); |
66209063 | 6856 | if (BASE_RETURN_VALUE_REG (mode) == FIRST_RET_REG) |
6857 | nreg = HARD_REGNO_NREGS (FIRST_RET_REG, mode); | |
6858 | } | |
6859 | for (i = 0; i < nreg; i++) | |
41fafa66 | 6860 | CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i); |
18d50ae6 | 6861 | if (crtl->calls_eh_return) |
41fafa66 | 6862 | { |
6863 | CLEAR_HARD_REG_BIT (temps, EH_RETURN_STACKADJ_REGNO); | |
6864 | for (i = 0; i <= 3; i++) | |
6865 | CLEAR_HARD_REG_BIT (temps, EH_RETURN_DATA_REGNO (i)); | |
6866 | } | |
6867 | } | |
66209063 | 6868 | if (TARGET_SHMEDIA && epilogue_p < 0) |
6869 | for (i = FIRST_TARGET_REG; i <= LAST_TARGET_REG; i++) | |
6870 | CLEAR_HARD_REG_BIT (temps, i); | |
6871 | if (epilogue_p <= 0) | |
41fafa66 | 6872 | { |
6873 | for (i = FIRST_PARM_REG; | |
6874 | i < FIRST_PARM_REG + NPARM_REGS (SImode); i++) | |
6875 | CLEAR_HARD_REG_BIT (temps, i); | |
4ee9c684 | 6876 | if (cfun->static_chain_decl != NULL) |
41fafa66 | 6877 | CLEAR_HARD_REG_BIT (temps, STATIC_CHAIN_REGNUM); |
6878 | } | |
6879 | temp = scavenge_reg (&temps); | |
6880 | } | |
6881 | if (temp < 0 && live_regs_mask) | |
5e9db045 | 6882 | { |
6883 | HARD_REG_SET temps; | |
6884 | ||
6885 | COPY_HARD_REG_SET (temps, *live_regs_mask); | |
6886 | CLEAR_HARD_REG_BIT (temps, REGNO (reg)); | |
6887 | temp = scavenge_reg (&temps); | |
6888 | } | |
b9d4bd5a | 6889 | if (temp < 0) |
66209063 | 6890 | { |
1a6a7a27 | 6891 | rtx adj_reg, tmp_reg, mem; |
6892 | ||
66209063 | 6893 | /* If we reached here, the most likely case is the (sibcall) |
6894 | epilogue for non SHmedia. Put a special push/pop sequence | |
6895 | for such case as the last resort. This looks lengthy but | |
1a6a7a27 | 6896 | would not be problem because it seems to be very |
6897 | rare. */ | |
6898 | ||
6899 | gcc_assert (!TARGET_SHMEDIA && epilogue_p); | |
6900 | ||
6901 | ||
6902 | /* ??? There is still the slight possibility that r4 or | |
6903 | r5 have been reserved as fixed registers or assigned | |
6904 | as global registers, and they change during an | |
6905 | interrupt. There are possible ways to handle this: | |
6906 | ||
6907 | - If we are adjusting the frame pointer (r14), we can do | |
6908 | with a single temp register and an ordinary push / pop | |
6909 | on the stack. | |
6910 | - Grab any call-used or call-saved registers (i.e. not | |
6911 | fixed or globals) for the temps we need. We might | |
6912 | also grab r14 if we are adjusting the stack pointer. | |
6913 | If we can't find enough available registers, issue | |
6914 | a diagnostic and die - the user must have reserved | |
6915 | way too many registers. | |
6916 | But since all this is rather unlikely to happen and | |
6917 | would require extra testing, we just die if r4 / r5 | |
6918 | are not available. */ | |
6919 | gcc_assert (!fixed_regs[4] && !fixed_regs[5] | |
6920 | && !global_regs[4] && !global_regs[5]); | |
6921 | ||
6922 | adj_reg = gen_rtx_REG (GET_MODE (reg), 4); | |
6923 | tmp_reg = gen_rtx_REG (GET_MODE (reg), 5); | |
aa7e75f2 | 6924 | emit_move_insn (gen_tmp_stack_mem (Pmode, reg), adj_reg); |
1a6a7a27 | 6925 | emit_insn (GEN_MOV (adj_reg, GEN_INT (size))); |
6926 | emit_insn (GEN_ADD3 (adj_reg, adj_reg, reg)); | |
aa7e75f2 | 6927 | mem = gen_tmp_stack_mem (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg)); |
1a6a7a27 | 6928 | emit_move_insn (mem, tmp_reg); |
aa7e75f2 | 6929 | emit_move_insn (tmp_reg, gen_tmp_stack_mem (Pmode, reg)); |
6930 | mem = gen_tmp_stack_mem (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg)); | |
6931 | emit_move_insn (mem, tmp_reg); | |
6932 | emit_move_insn (reg, adj_reg); | |
6933 | mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg)); | |
6934 | emit_move_insn (adj_reg, mem); | |
6935 | mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg)); | |
6936 | emit_move_insn (tmp_reg, mem); | |
5e9db045 | 6937 | /* Tell flow the insns that pop r4/r5 aren't dead. */ |
18b42941 | 6938 | emit_use (tmp_reg); |
6939 | emit_use (adj_reg); | |
aa7e75f2 | 6940 | return; |
66209063 | 6941 | } |
87e19636 | 6942 | const_reg = gen_rtx_REG (GET_MODE (reg), temp); |
b9d4bd5a | 6943 | |
6944 | /* If SIZE is negative, subtract the positive value. | |
6945 | This sometimes allows a constant pool entry to be shared | |
6946 | between prologue and epilogue code. */ | |
6947 | if (size < 0) | |
51143b47 | 6948 | { |
87e19636 | 6949 | emit_insn (GEN_MOV (const_reg, GEN_INT (-size))); |
363600c8 | 6950 | insn = emit_fn (GEN_SUB3 (reg, reg, const_reg)); |
51143b47 | 6951 | } |
6952 | else | |
6953 | { | |
87e19636 | 6954 | emit_insn (GEN_MOV (const_reg, GEN_INT (size))); |
363600c8 | 6955 | insn = emit_fn (GEN_ADD3 (reg, reg, const_reg)); |
51143b47 | 6956 | } |
c8ad18ed | 6957 | add_reg_note (insn, REG_FRAME_RELATED_EXPR, |
6958 | gen_rtx_SET (VOIDmode, reg, | |
6959 | gen_rtx_PLUS (SImode, reg, | |
6960 | GEN_INT (size)))); | |
73401833 | 6961 | } |
73401833 | 6962 | } |
6963 | } | |
6964 | ||
6c049e03 | 6965 | /* Emit the specified insn and mark it as frame related. |
6966 | FIXME: Rename this to emit_frame_insn. */ | |
722334ea | 6967 | static rtx_insn * |
04f04b72 | 6968 | frame_insn (rtx x) |
363600c8 | 6969 | { |
722334ea | 6970 | rtx_insn *insn = emit_insn (x); |
6971 | RTX_FRAME_RELATED_P (insn) = 1; | |
6972 | return insn; | |
363600c8 | 6973 | } |
6974 | ||
73401833 | 6975 | /* Output RTL to push register RN onto the stack. */ |
363600c8 | 6976 | static rtx |
04f04b72 | 6977 | push (int rn) |
73401833 | 6978 | { |
6979 | rtx x; | |
1b61190c | 6980 | if (rn == FPUL_REG) |
6981 | x = gen_push_fpul (); | |
88b7f6c6 | 6982 | else if (rn == FPSCR_REG) |
6983 | x = gen_push_fpscr (); | |
6c049e03 | 6984 | else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD |
6985 | && ! TARGET_FPU_SINGLE && FP_OR_XD_REGISTER_P (rn)) | |
1b61190c | 6986 | { |
e2142b04 | 6987 | if (FP_REGISTER_P (rn) && (rn - FIRST_FP_REG) & 1) |
acda5809 | 6988 | return NULL_RTX; |
7014838c | 6989 | x = gen_push_4 (gen_rtx_REG (DFmode, rn)); |
1b61190c | 6990 | } |
87ed74ef | 6991 | else if (TARGET_SH2E && FP_REGISTER_P (rn)) |
7014838c | 6992 | x = gen_push_e (gen_rtx_REG (SFmode, rn)); |
b00564da | 6993 | else |
7014838c | 6994 | x = gen_push (gen_rtx_REG (SImode, rn)); |
b00564da | 6995 | |
363600c8 | 6996 | x = frame_insn (x); |
6f2543f8 | 6997 | add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM)); |
363600c8 | 6998 | return x; |
73401833 | 6999 | } |
7000 | ||
7001 | /* Output RTL to pop register RN from the stack. */ | |
73401833 | 7002 | static void |
04f04b72 | 7003 | pop (int rn) |
73401833 | 7004 | { |
c8ad18ed | 7005 | rtx x, sp_reg, reg; |
1b61190c | 7006 | if (rn == FPUL_REG) |
7007 | x = gen_pop_fpul (); | |
88b7f6c6 | 7008 | else if (rn == FPSCR_REG) |
7009 | x = gen_pop_fpscr (); | |
6c049e03 | 7010 | else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD |
7011 | && ! TARGET_FPU_SINGLE && FP_OR_XD_REGISTER_P (rn)) | |
1b61190c | 7012 | { |
e2142b04 | 7013 | if (FP_REGISTER_P (rn) && (rn - FIRST_FP_REG) & 1) |
1b61190c | 7014 | return; |
7014838c | 7015 | x = gen_pop_4 (gen_rtx_REG (DFmode, rn)); |
1b61190c | 7016 | } |
87ed74ef | 7017 | else if (TARGET_SH2E && FP_REGISTER_P (rn)) |
7014838c | 7018 | x = gen_pop_e (gen_rtx_REG (SFmode, rn)); |
b00564da | 7019 | else |
7014838c | 7020 | x = gen_pop (gen_rtx_REG (SImode, rn)); |
9e7454d0 | 7021 | |
8ded0752 | 7022 | x = emit_insn (x); |
c8ad18ed | 7023 | |
7024 | sp_reg = gen_rtx_REG (SImode, STACK_POINTER_REGNUM); | |
7025 | reg = copy_rtx (GET_CODE (PATTERN (x)) == PARALLEL | |
7026 | ? SET_DEST (XVECEXP (PATTERN (x), 0, 0)) | |
7027 | : SET_DEST (PATTERN (x))); | |
7028 | add_reg_note (x, REG_CFA_RESTORE, reg); | |
7029 | add_reg_note (x, REG_CFA_ADJUST_CFA, | |
7030 | gen_rtx_SET (SImode, sp_reg, | |
7031 | plus_constant (SImode, sp_reg, | |
7032 | GET_MODE_SIZE (GET_MODE (reg))))); | |
6f2543f8 | 7033 | add_reg_note (x, REG_INC, gen_rtx_REG (SImode, STACK_POINTER_REGNUM)); |
c8ad18ed | 7034 | RTX_FRAME_RELATED_P (x) = 1; |
73401833 | 7035 | } |
7036 | ||
8ded0752 | 7037 | /* Generate code to push the regs specified in the mask. */ |
73401833 | 7038 | static void |
04f04b72 | 7039 | push_regs (HARD_REG_SET *mask, int interrupt_handler) |
73401833 | 7040 | { |
2f8b8488 | 7041 | int i = interrupt_handler ? LAST_BANKED_REG + 1 : 0; |
36a2dfdb | 7042 | int skip_fpscr = 0; |
73401833 | 7043 | |
8ded0752 | 7044 | /* Push PR last; this gives better latencies after the prologue, and |
7045 | candidates for the return delay slot when there are no general | |
7046 | registers pushed. */ | |
2f8b8488 | 7047 | for (; i < FIRST_PSEUDO_REGISTER; i++) |
36a2dfdb | 7048 | { |
7049 | /* If this is an interrupt handler, and the SZ bit varies, | |
7050 | and we have to push any floating point register, we need | |
7051 | to switch to the correct precision first. */ | |
7052 | if (i == FIRST_FP_REG && interrupt_handler && TARGET_FMOVD | |
ddc556d1 | 7053 | && hard_reg_set_intersect_p (*mask, reg_class_contents[DF_REGS])) |
36a2dfdb | 7054 | { |
7055 | HARD_REG_SET unsaved; | |
7056 | ||
7057 | push (FPSCR_REG); | |
d767e27e | 7058 | COMPL_HARD_REG_SET (unsaved, *mask); |
36a2dfdb | 7059 | fpscr_set_from_mem (NORMAL_MODE (FP_MODE), unsaved); |
7060 | skip_fpscr = 1; | |
7061 | } | |
7062 | if (i != PR_REG | |
7063 | && (i != FPSCR_REG || ! skip_fpscr) | |
7064 | && TEST_HARD_REG_BIT (*mask, i)) | |
6c049e03 | 7065 | { |
7066 | /* If the ISR has RESBANK attribute assigned, don't push any of | |
7067 | the following registers - R0-R14, MACH, MACL and GBR. */ | |
5241f4ad | 7068 | if (! (sh_cfun_resbank_handler_p () |
7069 | && ((i >= FIRST_GENERAL_REG && i < LAST_GENERAL_REG) | |
7070 | || i == MACH_REG | |
7071 | || i == MACL_REG | |
7072 | || i == GBR_REG))) | |
7073 | push (i); | |
6c049e03 | 7074 | } |
36a2dfdb | 7075 | } |
2f8b8488 | 7076 | |
7077 | /* Push banked registers last to improve delay slot opportunities. */ | |
7078 | if (interrupt_handler) | |
1b5c01d5 | 7079 | { |
7080 | bool use_movml = false; | |
7081 | ||
7082 | if (TARGET_SH2A) | |
7083 | { | |
7084 | unsigned int count = 0; | |
7085 | ||
7086 | for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++) | |
7087 | if (TEST_HARD_REG_BIT (*mask, i)) | |
7088 | count++; | |
7089 | else | |
7090 | break; | |
7091 | ||
7092 | /* Use movml when all banked registers are pushed. */ | |
7093 | if (count == LAST_BANKED_REG - FIRST_BANKED_REG + 1) | |
7094 | use_movml = true; | |
7095 | } | |
7096 | ||
5a333029 | 7097 | if (sh_cfun_resbank_handler_p ()) |
7098 | ; /* Do nothing. */ | |
7099 | else if (use_movml) | |
1b5c01d5 | 7100 | { |
7101 | rtx x, mem, reg, set; | |
7102 | rtx sp_reg = gen_rtx_REG (SImode, STACK_POINTER_REGNUM); | |
7103 | ||
7104 | /* We must avoid scheduling multiple store insn with another | |
7105 | insns. */ | |
7106 | emit_insn (gen_blockage ()); | |
7107 | x = gen_movml_push_banked (sp_reg); | |
7108 | x = frame_insn (x); | |
7109 | for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++) | |
7110 | { | |
29c05e22 | 7111 | mem = gen_rtx_MEM (SImode, plus_constant (Pmode, sp_reg, i * 4)); |
1b5c01d5 | 7112 | reg = gen_rtx_REG (SImode, i); |
7113 | add_reg_note (x, REG_CFA_OFFSET, gen_rtx_SET (SImode, mem, reg)); | |
7114 | } | |
7115 | ||
29c05e22 | 7116 | set = gen_rtx_SET (SImode, sp_reg, |
7117 | plus_constant (Pmode, sp_reg, - 32)); | |
1b5c01d5 | 7118 | add_reg_note (x, REG_CFA_ADJUST_CFA, set); |
7119 | emit_insn (gen_blockage ()); | |
7120 | } | |
7121 | else | |
7122 | for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++) | |
7123 | if (TEST_HARD_REG_BIT (*mask, i)) | |
7124 | push (i); | |
7125 | } | |
2f8b8488 | 7126 | |
5241f4ad | 7127 | /* Don't push PR register for an ISR with RESBANK attribute assigned. */ |
7128 | if (TEST_HARD_REG_BIT (*mask, PR_REG) && !sh_cfun_resbank_handler_p ()) | |
8ded0752 | 7129 | push (PR_REG); |
73401833 | 7130 | } |
7131 | ||
8af3db02 | 7132 | /* Calculate how much extra space is needed to save all callee-saved |
7133 | target registers. | |
7134 | LIVE_REGS_MASK is the register mask calculated by calc_live_regs. */ | |
8af3db02 | 7135 | static int |
7136 | shmedia_target_regs_stack_space (HARD_REG_SET *live_regs_mask) | |
7137 | { | |
7138 | int reg; | |
7139 | int stack_space = 0; | |
7140 | int interrupt_handler = sh_cfun_interrupt_handler_p (); | |
7141 | ||
7142 | for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--) | |
956dd562 | 7143 | if ((! call_really_used_regs[reg] || interrupt_handler) |
6c049e03 | 7144 | && ! TEST_HARD_REG_BIT (*live_regs_mask, reg)) |
8af3db02 | 7145 | /* Leave space to save this target register on the stack, |
ada8cf8b | 7146 | in case target register allocation wants to use it. */ |
8af3db02 | 7147 | stack_space += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg)); |
7148 | return stack_space; | |
7149 | } | |
9e7454d0 | 7150 | |
8af3db02 | 7151 | /* Decide whether we should reserve space for callee-save target registers, |
7152 | in case target register allocation wants to use them. REGS_SAVED is | |
7153 | the space, in bytes, that is already required for register saves. | |
7154 | LIVE_REGS_MASK is the register mask calculated by calc_live_regs. */ | |
8af3db02 | 7155 | static int |
7156 | shmedia_reserve_space_for_target_registers_p (int regs_saved, | |
7157 | HARD_REG_SET *live_regs_mask) | |
7158 | { | |
7159 | if (optimize_size) | |
7160 | return 0; | |
7161 | return shmedia_target_regs_stack_space (live_regs_mask) <= regs_saved; | |
7162 | } | |
7163 | ||
7164 | /* Decide how much space to reserve for callee-save target registers | |
7165 | in case target register allocation wants to use them. | |
7166 | LIVE_REGS_MASK is the register mask calculated by calc_live_regs. */ | |
8af3db02 | 7167 | static int |
7168 | shmedia_target_regs_stack_adjust (HARD_REG_SET *live_regs_mask) | |
7169 | { | |
7170 | if (shmedia_space_reserved_for_target_registers) | |
7171 | return shmedia_target_regs_stack_space (live_regs_mask); | |
7172 | else | |
7173 | return 0; | |
7174 | } | |
7175 | ||
73401833 | 7176 | /* Work out the registers which need to be saved, both as a mask and a |
ed8483c0 | 7177 | count of saved words. Return the count. |
73401833 | 7178 | |
7179 | If doing a pragma interrupt function, then push all regs used by the | |
7180 | function, and if we call another function (we can tell by looking at PR), | |
7181 | make sure that all the regs it clobbers are safe too. */ | |
ed8483c0 | 7182 | static int |
04f04b72 | 7183 | calc_live_regs (HARD_REG_SET *live_regs_mask) |
73401833 | 7184 | { |
bfa0b1cf | 7185 | unsigned int reg; |
8ded0752 | 7186 | int count; |
57d5535b | 7187 | tree attrs; |
7188 | bool interrupt_or_trapa_handler, trapa_handler, interrupt_handler; | |
7189 | bool nosave_low_regs; | |
41fafa66 | 7190 | int pr_live, has_call; |
49f630e1 | 7191 | |
57d5535b | 7192 | attrs = DECL_ATTRIBUTES (current_function_decl); |
7193 | interrupt_or_trapa_handler = sh_cfun_interrupt_handler_p (); | |
7194 | trapa_handler = lookup_attribute ("trapa_handler", attrs) != NULL_TREE; | |
7195 | interrupt_handler = interrupt_or_trapa_handler && ! trapa_handler; | |
7196 | nosave_low_regs = lookup_attribute ("nosave_low_regs", attrs) != NULL_TREE; | |
73401833 | 7197 | |
41fafa66 | 7198 | CLEAR_HARD_REG_SET (*live_regs_mask); |
7105fb72 | 7199 | if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler |
3072d30e | 7200 | && df_regs_ever_live_p (FPSCR_REG)) |
156fac8b | 7201 | target_flags &= ~MASK_FPU_SINGLE; |
1b61190c | 7202 | /* If we can save a lot of saves by switching to double mode, do that. */ |
6c049e03 | 7203 | else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD |
7204 | && TARGET_FPU_SINGLE) | |
1b61190c | 7205 | for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2) |
3072d30e | 7206 | if (df_regs_ever_live_p (reg) && df_regs_ever_live_p (reg+1) |
956dd562 | 7207 | && (! call_really_used_regs[reg] |
57d5535b | 7208 | || interrupt_handler) |
1b61190c | 7209 | && ++count > 2) |
7210 | { | |
156fac8b | 7211 | target_flags &= ~MASK_FPU_SINGLE; |
1b61190c | 7212 | break; |
7213 | } | |
0b1c30e1 | 7214 | /* PR_MEDIA_REG is a general purpose register, thus global_alloc already |
7215 | knows how to use it. That means the pseudo originally allocated for | |
7216 | the initial value can become the PR_MEDIA_REG hard register, as seen for | |
7217 | execute/20010122-1.c:test9. */ | |
7218 | if (TARGET_SHMEDIA) | |
ca474d26 | 7219 | /* ??? this function is called from initial_elimination_offset, hence we |
7220 | can't use the result of sh_media_register_for_return here. */ | |
93ea47c4 | 7221 | pr_live = sh_pr_n_sets (); |
0b1c30e1 | 7222 | else |
7223 | { | |
7224 | rtx pr_initial = has_hard_reg_initial_val (Pmode, PR_REG); | |
7225 | pr_live = (pr_initial | |
cbb16986 | 7226 | ? (!REG_P (pr_initial) |
0a41c525 | 7227 | || REGNO (pr_initial) != (PR_REG)) |
3072d30e | 7228 | : df_regs_ever_live_p (PR_REG)); |
ca474d26 | 7229 | /* For Shcompact, if not optimizing, we end up with a memory reference |
7230 | using the return address pointer for __builtin_return_address even | |
7231 | though there is no actual need to put the PR register on the stack. */ | |
3072d30e | 7232 | pr_live |= df_regs_ever_live_p (RETURN_ADDRESS_POINTER_REGNUM); |
0b1c30e1 | 7233 | } |
87e19636 | 7234 | /* Force PR to be live if the prologue has to call the SHmedia |
7235 | argument decoder or register saver. */ | |
7236 | if (TARGET_SHCOMPACT | |
abe32cce | 7237 | && ((crtl->args.info.call_cookie |
87e19636 | 7238 | & ~ CALL_COOKIE_RET_TRAMP (1)) |
18d50ae6 | 7239 | || crtl->saves_all_registers)) |
87e19636 | 7240 | pr_live = 1; |
41fafa66 | 7241 | has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live; |
bfa0b1cf | 7242 | for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; ) |
73401833 | 7243 | { |
93ea47c4 | 7244 | if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) |
476444cc | 7245 | ? pr_live |
57d5535b | 7246 | : interrupt_handler |
8ded0752 | 7247 | ? (/* Need to save all the regs ever live. */ |
3072d30e | 7248 | (df_regs_ever_live_p (reg) |
956dd562 | 7249 | || (call_really_used_regs[reg] |
7250 | && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG | |
7251 | || reg == PIC_OFFSET_TABLE_REGNUM) | |
41fafa66 | 7252 | && has_call) |
57d5535b | 7253 | || (TARGET_SHMEDIA && has_call |
7254 | && REGISTER_NATURAL_MODE (reg) == SImode | |
41fafa66 | 7255 | && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg)))) |
8ded0752 | 7256 | && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM |
7257 | && reg != RETURN_ADDRESS_POINTER_REGNUM | |
88b7f6c6 | 7258 | && reg != T_REG && reg != GBR_REG |
b0fa59a9 | 7259 | && reg != FPSCR_MODES_REG && reg != FPSCR_STAT_REG |
88b7f6c6 | 7260 | /* Push fpscr only on targets which have FPU */ |
7261 | && (reg != FPSCR_REG || TARGET_FPU_ANY)) | |
8ded0752 | 7262 | : (/* Only push those regs which are used and need to be saved. */ |
6977cd64 | 7263 | (TARGET_SHCOMPACT |
7264 | && flag_pic | |
abe32cce | 7265 | && crtl->args.info.call_cookie |
bfa0b1cf | 7266 | && reg == PIC_OFFSET_TABLE_REGNUM) |
3072d30e | 7267 | || (df_regs_ever_live_p (reg) |
dc9b0799 | 7268 | && ((!call_really_used_regs[reg] |
7269 | && !(reg != PIC_OFFSET_TABLE_REGNUM | |
7270 | && fixed_regs[reg] && call_used_regs[reg])) | |
57d5535b | 7271 | || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY))) |
18d50ae6 | 7272 | || (crtl->calls_eh_return |
bfa0b1cf | 7273 | && (reg == EH_RETURN_DATA_REGNO (0) |
7274 | || reg == EH_RETURN_DATA_REGNO (1) | |
7275 | || reg == EH_RETURN_DATA_REGNO (2) | |
7276 | || reg == EH_RETURN_DATA_REGNO (3))) | |
45550790 | 7277 | || ((reg == MACL_REG || reg == MACH_REG) |
3072d30e | 7278 | && df_regs_ever_live_p (reg) |
45550790 | 7279 | && sh_cfun_attr_renesas_p ()) |
7280 | )) | |
73401833 | 7281 | { |
ed8483c0 | 7282 | SET_HARD_REG_BIT (*live_regs_mask, reg); |
87e19636 | 7283 | count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg)); |
7284 | ||
7105fb72 | 7285 | if ((TARGET_SH4 || TARGET_SH2A_DOUBLE || TARGET_SH5) && TARGET_FMOVD |
87e19636 | 7286 | && GET_MODE_CLASS (REGISTER_NATURAL_MODE (reg)) == MODE_FLOAT) |
17bec211 | 7287 | { |
e2142b04 | 7288 | if (FP_REGISTER_P (reg)) |
17bec211 | 7289 | { |
3072d30e | 7290 | if (! TARGET_FPU_SINGLE && ! df_regs_ever_live_p (reg ^ 1)) |
17bec211 | 7291 | { |
ed8483c0 | 7292 | SET_HARD_REG_BIT (*live_regs_mask, (reg ^ 1)); |
87e19636 | 7293 | count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg ^ 1)); |
17bec211 | 7294 | } |
7295 | } | |
87e19636 | 7296 | else if (XD_REGISTER_P (reg)) |
17bec211 | 7297 | { |
7298 | /* Must switch to double mode to access these registers. */ | |
156fac8b | 7299 | target_flags &= ~MASK_FPU_SINGLE; |
17bec211 | 7300 | } |
7301 | } | |
73401833 | 7302 | } |
57d5535b | 7303 | if (nosave_low_regs && reg == R8_REG) |
7304 | break; | |
73401833 | 7305 | } |
8af3db02 | 7306 | /* If we have a target register optimization pass after prologue / epilogue |
7307 | threading, we need to assume all target registers will be live even if | |
7308 | they aren't now. */ | |
7309 | if (flag_branch_target_load_optimize2 | |
7310 | && TARGET_SAVE_ALL_TARGET_REGS | |
7311 | && shmedia_space_reserved_for_target_registers) | |
7312 | for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--) | |
956dd562 | 7313 | if ((! call_really_used_regs[reg] || interrupt_handler) |
8af3db02 | 7314 | && ! TEST_HARD_REG_BIT (*live_regs_mask, reg)) |
7315 | { | |
7316 | SET_HARD_REG_BIT (*live_regs_mask, reg); | |
7317 | count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg)); | |
7318 | } | |
41fafa66 | 7319 | /* If this is an interrupt handler, we don't have any call-clobbered |
7320 | registers we can conveniently use for target register save/restore. | |
7321 | Make sure we save at least one general purpose register when we need | |
7322 | to save target registers. */ | |
7323 | if (interrupt_handler | |
ddc556d1 | 7324 | && hard_reg_set_intersect_p (*live_regs_mask, |
7325 | reg_class_contents[TARGET_REGS]) | |
7326 | && ! hard_reg_set_intersect_p (*live_regs_mask, | |
7327 | reg_class_contents[GENERAL_REGS])) | |
41fafa66 | 7328 | { |
7329 | SET_HARD_REG_BIT (*live_regs_mask, R0_REG); | |
7330 | count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (R0_REG)); | |
7331 | } | |
73401833 | 7332 | |
ed8483c0 | 7333 | return count; |
73401833 | 7334 | } |
7335 | ||
7336 | /* Code to generate prologue and epilogue sequences */ | |
47c009e5 | 7337 | |
4aa67c38 | 7338 | /* PUSHED is the number of bytes that are being pushed on the |
f10edf5a | 7339 | stack for register saves. Return the frame size, padded |
7340 | appropriately so that the stack stays properly aligned. */ | |
9200a51c | 7341 | static HOST_WIDE_INT |
04f04b72 | 7342 | rounded_frame_size (int pushed) |
9200a51c | 7343 | { |
7344 | HOST_WIDE_INT size = get_frame_size (); | |
7345 | HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT; | |
7346 | ||
992d172c | 7347 | if (ACCUMULATE_OUTGOING_ARGS) |
7348 | size += crtl->outgoing_args_size; | |
7349 | ||
26576132 | 7350 | return ((size + pushed + align - 1) & -align) - pushed; |
9200a51c | 7351 | } |
7352 | ||
87e19636 | 7353 | /* Choose a call-clobbered target-branch register that remains |
7354 | unchanged along the whole function. We set it up as the return | |
7355 | value in the prologue. */ | |
7356 | int | |
04f04b72 | 7357 | sh_media_register_for_return (void) |
87e19636 | 7358 | { |
7359 | int regno; | |
7360 | int tr0_used; | |
7361 | ||
d5bf7b64 | 7362 | if (! crtl->is_leaf) |
87e19636 | 7363 | return -1; |
41fafa66 | 7364 | if (lookup_attribute ("interrupt_handler", |
7365 | DECL_ATTRIBUTES (current_function_decl))) | |
7366 | return -1; | |
59312820 | 7367 | if (sh_cfun_interrupt_handler_p ()) |
7368 | return -1; | |
87e19636 | 7369 | |
3072d30e | 7370 | tr0_used = flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM); |
87e19636 | 7371 | |
7372 | for (regno = FIRST_TARGET_REG + tr0_used; regno <= LAST_TARGET_REG; regno++) | |
3072d30e | 7373 | if (call_really_used_regs[regno] && ! df_regs_ever_live_p (regno)) |
87e19636 | 7374 | return regno; |
7375 | ||
7376 | return -1; | |
7377 | } | |
7378 | ||
41fafa66 | 7379 | /* The maximum registers we need to save are: |
7380 | - 62 general purpose registers (r15 is stack pointer, r63 is zero) | |
7381 | - 32 floating point registers (for each pair, we save none, | |
7382 | one single precision value, or a double precision value). | |
7383 | - 8 target registers | |
7384 | - add 1 entry for a delimiter. */ | |
7385 | #define MAX_SAVED_REGS (62+32+8) | |
7386 | ||
7387 | typedef struct save_entry_s | |
7388 | { | |
7389 | unsigned char reg; | |
7390 | unsigned char mode; | |
7391 | short offset; | |
7392 | } save_entry; | |
7393 | ||
7394 | #define MAX_TEMPS 4 | |
7395 | ||
7396 | /* There will be a delimiter entry with VOIDmode both at the start and the | |
7397 | end of a filled in schedule. The end delimiter has the offset of the | |
7398 | save with the smallest (i.e. most negative) offset. */ | |
7399 | typedef struct save_schedule_s | |
7400 | { | |
7401 | save_entry entries[MAX_SAVED_REGS + 2]; | |
7402 | int temps[MAX_TEMPS+1]; | |
7403 | } save_schedule; | |
7404 | ||
7405 | /* Fill in SCHEDULE according to LIVE_REGS_MASK. If RESTORE is nonzero, | |
7406 | use reverse order. Returns the last entry written to (not counting | |
7407 | the delimiter). OFFSET_BASE is a number to be added to all offset | |
7408 | entries. */ | |
41fafa66 | 7409 | static save_entry * |
7410 | sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule, | |
7411 | int offset_base) | |
7412 | { | |
7413 | int align, i; | |
7414 | save_entry *entry = schedule->entries; | |
7415 | int tmpx = 0; | |
7416 | int offset; | |
7417 | ||
7418 | if (! current_function_interrupt) | |
7419 | for (i = FIRST_GENERAL_REG; tmpx < MAX_TEMPS && i <= LAST_GENERAL_REG; i++) | |
956dd562 | 7420 | if (call_really_used_regs[i] && ! fixed_regs[i] && i != PR_MEDIA_REG |
41fafa66 | 7421 | && ! FUNCTION_ARG_REGNO_P (i) |
7422 | && i != FIRST_RET_REG | |
4ee9c684 | 7423 | && ! (cfun->static_chain_decl != NULL && i == STATIC_CHAIN_REGNUM) |
18d50ae6 | 7424 | && ! (crtl->calls_eh_return |
41fafa66 | 7425 | && (i == EH_RETURN_STACKADJ_REGNO |
1b95b63b | 7426 | || ((unsigned) i >= EH_RETURN_DATA_REGNO (0) |
7427 | && (unsigned) i <= EH_RETURN_DATA_REGNO (3))))) | |
41fafa66 | 7428 | schedule->temps[tmpx++] = i; |
7429 | entry->reg = -1; | |
7430 | entry->mode = VOIDmode; | |
7431 | entry->offset = offset_base; | |
7432 | entry++; | |
7433 | /* We loop twice: first, we save 8-byte aligned registers in the | |
7434 | higher addresses, that are known to be aligned. Then, we | |
7435 | proceed to saving 32-bit registers that don't need 8-byte | |
7436 | alignment. | |
7437 | If this is an interrupt function, all registers that need saving | |
7438 | need to be saved in full. moreover, we need to postpone saving | |
7439 | target registers till we have saved some general purpose registers | |
7440 | we can then use as scratch registers. */ | |
7441 | offset = offset_base; | |
7442 | for (align = 1; align >= 0; align--) | |
7443 | { | |
7444 | for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) | |
7445 | if (TEST_HARD_REG_BIT (*live_regs_mask, i)) | |
7446 | { | |
3754d046 | 7447 | machine_mode mode = REGISTER_NATURAL_MODE (i); |
41fafa66 | 7448 | int reg = i; |
7449 | ||
7450 | if (current_function_interrupt) | |
7451 | { | |
7452 | if (TARGET_REGISTER_P (i)) | |
7453 | continue; | |
7454 | if (GENERAL_REGISTER_P (i)) | |
7455 | mode = DImode; | |
7456 | } | |
7457 | if (mode == SFmode && (i % 2) == 1 | |
7458 | && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i) | |
7459 | && (TEST_HARD_REG_BIT (*live_regs_mask, (i ^ 1)))) | |
7460 | { | |
7461 | mode = DFmode; | |
7462 | i--; | |
7463 | reg--; | |
7464 | } | |
7465 | ||
7466 | /* If we're doing the aligned pass and this is not aligned, | |
7467 | or we're doing the unaligned pass and this is aligned, | |
7468 | skip it. */ | |
7469 | if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) == 0) | |
7470 | != align) | |
7471 | continue; | |
7472 | ||
7473 | if (current_function_interrupt | |
7474 | && GENERAL_REGISTER_P (i) | |
7475 | && tmpx < MAX_TEMPS) | |
7476 | schedule->temps[tmpx++] = i; | |
7477 | ||
7478 | offset -= GET_MODE_SIZE (mode); | |
7479 | entry->reg = i; | |
7480 | entry->mode = mode; | |
7481 | entry->offset = offset; | |
7482 | entry++; | |
7483 | } | |
7484 | if (align && current_function_interrupt) | |
7485 | for (i = LAST_TARGET_REG; i >= FIRST_TARGET_REG; i--) | |
7486 | if (TEST_HARD_REG_BIT (*live_regs_mask, i)) | |
7487 | { | |
7488 | offset -= GET_MODE_SIZE (DImode); | |
7489 | entry->reg = i; | |
7490 | entry->mode = DImode; | |
7491 | entry->offset = offset; | |
7492 | entry++; | |
7493 | } | |
7494 | } | |
7495 | entry->reg = -1; | |
7496 | entry->mode = VOIDmode; | |
7497 | entry->offset = offset; | |
7498 | schedule->temps[tmpx] = -1; | |
7499 | return entry - 1; | |
7500 | } | |
7501 | ||
6c049e03 | 7502 | /* Expand code for the function prologue. */ |
47c009e5 | 7503 | void |
04f04b72 | 7504 | sh_expand_prologue (void) |
47c009e5 | 7505 | { |
ed8483c0 | 7506 | HARD_REG_SET live_regs_mask; |
0f021c78 | 7507 | int d, i; |
87e19636 | 7508 | int d_rounding = 0; |
1b61190c | 7509 | int save_flags = target_flags; |
09a512b9 | 7510 | int pretend_args; |
f47ae7b2 | 7511 | int stack_usage; |
57d5535b | 7512 | tree sp_switch_attr |
7513 | = lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl)); | |
47c009e5 | 7514 | |
5df3d11f | 7515 | current_function_interrupt = sh_cfun_interrupt_handler_p (); |
0d687b6d | 7516 | |
97595bfd | 7517 | /* We have pretend args if we had an object sent partially in registers |
73401833 | 7518 | and partially on the stack, e.g. a large structure. */ |
abe32cce | 7519 | pretend_args = crtl->args.pretend_args_size; |
09a512b9 | 7520 | if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl) |
7521 | && (NPARM_REGS(SImode) | |
abe32cce | 7522 | > crtl->args.info.arg_count[(int) SH_ARG_INT])) |
09a512b9 | 7523 | pretend_args = 0; |
083efe31 | 7524 | |
09a512b9 | 7525 | output_stack_adjust (-pretend_args |
abe32cce | 7526 | - crtl->args.info.stack_regs * 8, |
083efe31 | 7527 | stack_pointer_rtx, 0, NULL, true); |
f47ae7b2 | 7528 | stack_usage = pretend_args + crtl->args.info.stack_regs * 8; |
47c009e5 | 7529 | |
abe32cce | 7530 | if (TARGET_SHCOMPACT && flag_pic && crtl->args.info.call_cookie) |
87708ea5 | 7531 | /* We're going to use the PIC register to load the address of the |
7532 | incoming-argument decoder and/or of the return trampoline from | |
7533 | the GOT, so make sure the PIC register is preserved and | |
7534 | initialized. */ | |
3072d30e | 7535 | df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true); |
87708ea5 | 7536 | |
87e19636 | 7537 | if (TARGET_SHCOMPACT |
abe32cce | 7538 | && (crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1))) |
87e19636 | 7539 | { |
7540 | int reg; | |
7541 | ||
7542 | /* First, make all registers with incoming arguments that will | |
7543 | be pushed onto the stack live, so that register renaming | |
7544 | doesn't overwrite them. */ | |
7545 | for (reg = 0; reg < NPARM_REGS (SImode); reg++) | |
abe32cce | 7546 | if (CALL_COOKIE_STACKSEQ_GET (crtl->args.info.call_cookie) |
87e19636 | 7547 | >= NPARM_REGS (SImode) - reg) |
7548 | for (; reg < NPARM_REGS (SImode); reg++) | |
7549 | emit_insn (gen_shcompact_preserve_incoming_args | |
7550 | (gen_rtx_REG (SImode, FIRST_PARM_REG + reg))); | |
7551 | else if (CALL_COOKIE_INT_REG_GET | |
abe32cce | 7552 | (crtl->args.info.call_cookie, reg) == 1) |
87e19636 | 7553 | emit_insn (gen_shcompact_preserve_incoming_args |
7554 | (gen_rtx_REG (SImode, FIRST_PARM_REG + reg))); | |
7555 | ||
7556 | emit_move_insn (gen_rtx_REG (Pmode, MACL_REG), | |
7557 | stack_pointer_rtx); | |
7558 | emit_move_insn (gen_rtx_REG (SImode, R0_REG), | |
abe32cce | 7559 | GEN_INT (crtl->args.info.call_cookie)); |
87e19636 | 7560 | emit_move_insn (gen_rtx_REG (SImode, MACH_REG), |
7561 | gen_rtx_REG (SImode, R0_REG)); | |
7562 | } | |
7563 | else if (TARGET_SHMEDIA) | |
7564 | { | |
7565 | int tr = sh_media_register_for_return (); | |
7566 | ||
7567 | if (tr >= 0) | |
3072d30e | 7568 | emit_move_insn (gen_rtx_REG (DImode, tr), |
7569 | gen_rtx_REG (DImode, PR_MEDIA_REG)); | |
87e19636 | 7570 | } |
7571 | ||
bf622d7d | 7572 | /* Emit the code for SETUP_VARARGS. */ |
18d50ae6 | 7573 | if (cfun->stdarg) |
47c009e5 | 7574 | { |
09a512b9 | 7575 | if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)) |
8ded0752 | 7576 | { |
b00564da | 7577 | /* Push arg regs as if they'd been provided by caller in stack. */ |
7578 | for (i = 0; i < NPARM_REGS(SImode); i++) | |
7579 | { | |
7580 | int rn = NPARM_REGS(SImode) + FIRST_PARM_REG - i - 1; | |
363600c8 | 7581 | |
9e7454d0 | 7582 | if (i >= (NPARM_REGS(SImode) |
abe32cce | 7583 | - crtl->args.info.arg_count[(int) SH_ARG_INT] |
75c2fa85 | 7584 | )) |
b00564da | 7585 | break; |
168ae443 | 7586 | push (rn); |
f47ae7b2 | 7587 | stack_usage += GET_MODE_SIZE (SImode); |
b00564da | 7588 | } |
8ded0752 | 7589 | } |
47c009e5 | 7590 | } |
b00564da | 7591 | |
15cb1799 | 7592 | /* If we're supposed to switch stacks at function entry, do so now. */ |
57d5535b | 7593 | if (sp_switch_attr) |
7594 | { | |
5e11de88 | 7595 | rtx lab, newsrc; |
57d5535b | 7596 | /* The argument specifies a variable holding the address of the |
7597 | stack the interrupt function should switch to/from at entry/exit. */ | |
5e11de88 | 7598 | tree arg = TREE_VALUE ( TREE_VALUE (sp_switch_attr)); |
57d5535b | 7599 | const char *s |
5e11de88 | 7600 | = ggc_strdup (TREE_STRING_POINTER (arg)); |
57d5535b | 7601 | rtx sp_switch = gen_rtx_SYMBOL_REF (Pmode, s); |
7602 | ||
5e11de88 | 7603 | lab = add_constant (sp_switch, SImode, 0); |
7604 | newsrc = gen_rtx_LABEL_REF (VOIDmode, lab); | |
5e11de88 | 7605 | |
7606 | emit_insn (gen_sp_switch_1 (newsrc)); | |
57d5535b | 7607 | } |
15cb1799 | 7608 | |
ed8483c0 | 7609 | d = calc_live_regs (&live_regs_mask); |
1b61190c | 7610 | /* ??? Maybe we could save some switching if we can move a mode switch |
7611 | that already happens to be at the function start into the prologue. */ | |
36a2dfdb | 7612 | if (target_flags != save_flags && ! current_function_interrupt) |
1b61190c | 7613 | emit_insn (gen_toggle_sz ()); |
9e7454d0 | 7614 | |
87e19636 | 7615 | if (TARGET_SH5) |
7616 | { | |
41fafa66 | 7617 | int offset_base, offset; |
7618 | rtx r0 = NULL_RTX; | |
87e19636 | 7619 | int offset_in_r0 = -1; |
7620 | int sp_in_r0 = 0; | |
8af3db02 | 7621 | int tregs_space = shmedia_target_regs_stack_adjust (&live_regs_mask); |
7622 | int total_size, save_size; | |
41fafa66 | 7623 | save_schedule schedule; |
7624 | save_entry *entry; | |
7625 | int *tmp_pnt; | |
7626 | ||
956dd562 | 7627 | if (call_really_used_regs[R0_REG] && ! fixed_regs[R0_REG] |
41fafa66 | 7628 | && ! current_function_interrupt) |
7629 | r0 = gen_rtx_REG (Pmode, R0_REG); | |
8af3db02 | 7630 | |
7631 | /* D is the actual number of bytes that we need for saving registers, | |
7632 | however, in initial_elimination_offset we have committed to using | |
7633 | an additional TREGS_SPACE amount of bytes - in order to keep both | |
7634 | addresses to arguments supplied by the caller and local variables | |
7635 | valid, we must keep this gap. Place it between the incoming | |
7636 | arguments and the actually saved registers in a bid to optimize | |
7637 | locality of reference. */ | |
7638 | total_size = d + tregs_space; | |
7639 | total_size += rounded_frame_size (total_size); | |
7640 | save_size = total_size - rounded_frame_size (d); | |
7641 | if (save_size % (STACK_BOUNDARY / BITS_PER_UNIT)) | |
87e19636 | 7642 | d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT) |
8af3db02 | 7643 | - save_size % (STACK_BOUNDARY / BITS_PER_UNIT)); |
7644 | ||
7645 | /* If adjusting the stack in a single step costs nothing extra, do so. | |
7646 | I.e. either if a single addi is enough, or we need a movi anyway, | |
7647 | and we don't exceed the maximum offset range (the test for the | |
7648 | latter is conservative for simplicity). */ | |
7649 | if (TARGET_SHMEDIA | |
7650 | && (CONST_OK_FOR_I10 (-total_size) | |
7651 | || (! CONST_OK_FOR_I10 (-(save_size + d_rounding)) | |
7652 | && total_size <= 2044))) | |
7653 | d_rounding = total_size - save_size; | |
87e19636 | 7654 | |
41fafa66 | 7655 | offset_base = d + d_rounding; |
8af3db02 | 7656 | |
7657 | output_stack_adjust (-(save_size + d_rounding), stack_pointer_rtx, | |
b324d3bd | 7658 | 0, NULL, true); |
f47ae7b2 | 7659 | stack_usage += save_size + d_rounding; |
87e19636 | 7660 | |
41fafa66 | 7661 | sh5_schedule_saves (&live_regs_mask, &schedule, offset_base); |
7662 | tmp_pnt = schedule.temps; | |
7663 | for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++) | |
7664 | { | |
3754d046 | 7665 | machine_mode mode = (machine_mode) entry->mode; |
bfa0b1cf | 7666 | unsigned int reg = entry->reg; |
41fafa66 | 7667 | rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX; |
1685bae3 | 7668 | rtx orig_reg_rtx; |
87e19636 | 7669 | |
41fafa66 | 7670 | offset = entry->offset; |
87e19636 | 7671 | |
41fafa66 | 7672 | reg_rtx = gen_rtx_REG (mode, reg); |
87e19636 | 7673 | |
aa7e75f2 | 7674 | mem_rtx = gen_frame_mem (mode, |
7675 | gen_rtx_PLUS (Pmode, | |
7676 | stack_pointer_rtx, | |
7677 | GEN_INT (offset))); | |
87e19636 | 7678 | |
670db79f | 7679 | if (!memory_address_p (mode, XEXP (mem_rtx, 0))) |
7680 | { | |
7681 | gcc_assert (r0); | |
7682 | mem_rtx = NULL_RTX; | |
7683 | } | |
87e19636 | 7684 | |
670db79f | 7685 | if (HAVE_PRE_DECREMENT |
7686 | && (offset_in_r0 - offset == GET_MODE_SIZE (mode) | |
7687 | || mem_rtx == NULL_RTX | |
7688 | || reg == PR_REG || SPECIAL_REGISTER_P (reg))) | |
7689 | { | |
7690 | pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0)); | |
87e19636 | 7691 | |
670db79f | 7692 | if (!memory_address_p (mode, XEXP (pre_dec, 0))) |
41fafa66 | 7693 | pre_dec = NULL_RTX; |
670db79f | 7694 | else |
7695 | { | |
7696 | mem_rtx = NULL_RTX; | |
7697 | offset += GET_MODE_SIZE (mode); | |
7698 | } | |
7699 | } | |
87e19636 | 7700 | |
41fafa66 | 7701 | if (mem_rtx != NULL_RTX) |
7702 | goto addr_ok; | |
87e19636 | 7703 | |
41fafa66 | 7704 | if (offset_in_r0 == -1) |
7705 | { | |
7706 | emit_move_insn (r0, GEN_INT (offset)); | |
7707 | offset_in_r0 = offset; | |
7708 | } | |
7709 | else if (offset != offset_in_r0) | |
7710 | { | |
7711 | emit_move_insn (r0, | |
7712 | gen_rtx_PLUS | |
7713 | (Pmode, r0, | |
7714 | GEN_INT (offset - offset_in_r0))); | |
7715 | offset_in_r0 += offset - offset_in_r0; | |
7716 | } | |
9e7454d0 | 7717 | |
41fafa66 | 7718 | if (pre_dec != NULL_RTX) |
7719 | { | |
7720 | if (! sp_in_r0) | |
87e19636 | 7721 | { |
7722 | emit_move_insn (r0, | |
7723 | gen_rtx_PLUS | |
41fafa66 | 7724 | (Pmode, r0, stack_pointer_rtx)); |
7725 | sp_in_r0 = 1; | |
87e19636 | 7726 | } |
87e19636 | 7727 | |
41fafa66 | 7728 | offset -= GET_MODE_SIZE (mode); |
7729 | offset_in_r0 -= GET_MODE_SIZE (mode); | |
87e19636 | 7730 | |
41fafa66 | 7731 | mem_rtx = pre_dec; |
7732 | } | |
7733 | else if (sp_in_r0) | |
aa7e75f2 | 7734 | mem_rtx = gen_frame_mem (mode, r0); |
41fafa66 | 7735 | else |
aa7e75f2 | 7736 | mem_rtx = gen_frame_mem (mode, |
7737 | gen_rtx_PLUS (Pmode, | |
7738 | stack_pointer_rtx, | |
7739 | r0)); | |
41fafa66 | 7740 | |
7741 | /* We must not use an r0-based address for target-branch | |
7742 | registers or for special registers without pre-dec | |
7743 | memory addresses, since we store their values in r0 | |
7744 | first. */ | |
1a6a7a27 | 7745 | gcc_assert (!TARGET_REGISTER_P (reg) |
7746 | && ((reg != PR_REG && !SPECIAL_REGISTER_P (reg)) | |
7747 | || mem_rtx == pre_dec)); | |
7748 | ||
41fafa66 | 7749 | addr_ok: |
1685bae3 | 7750 | orig_reg_rtx = reg_rtx; |
41fafa66 | 7751 | if (TARGET_REGISTER_P (reg) |
7752 | || ((reg == PR_REG || SPECIAL_REGISTER_P (reg)) | |
7753 | && mem_rtx != pre_dec)) | |
7754 | { | |
7755 | rtx tmp_reg = gen_rtx_REG (GET_MODE (reg_rtx), *tmp_pnt); | |
87e19636 | 7756 | |
41fafa66 | 7757 | emit_move_insn (tmp_reg, reg_rtx); |
87e19636 | 7758 | |
41fafa66 | 7759 | if (REGNO (tmp_reg) == R0_REG) |
7760 | { | |
87e19636 | 7761 | offset_in_r0 = -1; |
7762 | sp_in_r0 = 0; | |
1a6a7a27 | 7763 | gcc_assert (!refers_to_regno_p |
7764 | (R0_REG, R0_REG+1, mem_rtx, (rtx *) 0)); | |
87e19636 | 7765 | } |
7766 | ||
41fafa66 | 7767 | if (*++tmp_pnt <= 0) |
7768 | tmp_pnt = schedule.temps; | |
7769 | ||
7770 | reg_rtx = tmp_reg; | |
87e19636 | 7771 | } |
41fafa66 | 7772 | { |
7773 | rtx insn; | |
7774 | ||
7775 | /* Mark as interesting for dwarf cfi generator */ | |
7776 | insn = emit_move_insn (mem_rtx, reg_rtx); | |
7777 | RTX_FRAME_RELATED_P (insn) = 1; | |
1685bae3 | 7778 | /* If we use an intermediate register for the save, we can't |
7779 | describe this exactly in cfi as a copy of the to-be-saved | |
7780 | register into the temporary register and then the temporary | |
7781 | register on the stack, because the temporary register can | |
7782 | have a different natural size than the to-be-saved register. | |
7783 | Thus, we gloss over the intermediate copy and pretend we do | |
7784 | a direct save from the to-be-saved register. */ | |
7785 | if (REGNO (reg_rtx) != reg) | |
7786 | { | |
6f2543f8 | 7787 | rtx set; |
1685bae3 | 7788 | |
7789 | set = gen_rtx_SET (VOIDmode, mem_rtx, orig_reg_rtx); | |
6f2543f8 | 7790 | add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); |
1685bae3 | 7791 | } |
41fafa66 | 7792 | |
9e7454d0 | 7793 | if (TARGET_SHCOMPACT && (offset_in_r0 != -1)) |
41fafa66 | 7794 | { |
7795 | rtx reg_rtx = gen_rtx_REG (mode, reg); | |
6f2543f8 | 7796 | rtx set; |
aa7e75f2 | 7797 | rtx mem_rtx = gen_frame_mem (mode, |
7798 | gen_rtx_PLUS (Pmode, | |
7799 | stack_pointer_rtx, | |
7800 | GEN_INT (offset))); | |
41fafa66 | 7801 | |
7802 | set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx); | |
6f2543f8 | 7803 | add_reg_note (insn, REG_FRAME_RELATED_EXPR, set); |
41fafa66 | 7804 | } |
7805 | } | |
7806 | } | |
87e19636 | 7807 | |
1a6a7a27 | 7808 | gcc_assert (entry->offset == d_rounding); |
87e19636 | 7809 | } |
7810 | else | |
f47ae7b2 | 7811 | { |
7812 | push_regs (&live_regs_mask, current_function_interrupt); | |
7813 | stack_usage += d; | |
7814 | } | |
0abf894c | 7815 | |
3072d30e | 7816 | if (flag_pic && df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)) |
7817 | emit_insn (gen_GOTaddr2picreg ()); | |
0abf894c | 7818 | |
87e19636 | 7819 | if (SHMEDIA_REGS_STACK_ADJUST ()) |
7820 | { | |
87e19636 | 7821 | /* This must NOT go through the PLT, otherwise mach and macl |
7822 | may be clobbered. */ | |
59312820 | 7823 | function_symbol (gen_rtx_REG (Pmode, R0_REG), |
7824 | (TARGET_FPU_ANY | |
7825 | ? "__GCC_push_shmedia_regs" | |
7826 | : "__GCC_push_shmedia_regs_nofpu"), SFUNC_GOT); | |
87e19636 | 7827 | emit_insn (gen_shmedia_save_restore_regs_compact |
7828 | (GEN_INT (-SHMEDIA_REGS_STACK_ADJUST ()))); | |
7829 | } | |
7830 | ||
36a2dfdb | 7831 | if (target_flags != save_flags && ! current_function_interrupt) |
3072d30e | 7832 | emit_insn (gen_toggle_sz ()); |
b00564da | 7833 | |
1b61190c | 7834 | target_flags = save_flags; |
7835 | ||
87e19636 | 7836 | output_stack_adjust (-rounded_frame_size (d) + d_rounding, |
b324d3bd | 7837 | stack_pointer_rtx, 0, NULL, true); |
f47ae7b2 | 7838 | stack_usage += rounded_frame_size (d) - d_rounding; |
47c009e5 | 7839 | |
7840 | if (frame_pointer_needed) | |
b9a602c6 | 7841 | frame_insn (GEN_MOV (hard_frame_pointer_rtx, stack_pointer_rtx)); |
87e19636 | 7842 | |
87e19636 | 7843 | if (TARGET_SHCOMPACT |
abe32cce | 7844 | && (crtl->args.info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1))) |
87e19636 | 7845 | { |
7846 | /* This must NOT go through the PLT, otherwise mach and macl | |
7847 | may be clobbered. */ | |
59312820 | 7848 | function_symbol (gen_rtx_REG (Pmode, R0_REG), |
7849 | "__GCC_shcompact_incoming_args", SFUNC_GOT); | |
87e19636 | 7850 | emit_insn (gen_shcompact_incoming_args ()); |
7851 | } | |
f47ae7b2 | 7852 | |
8fe7656f | 7853 | /* If we are profiling, make sure no instructions are scheduled before |
7854 | the call to mcount. Similarly if some call instructions are swapped | |
7855 | before frame related insns, it'll confuse the unwinder because | |
7856 | currently SH has no unwind info for function epilogues. */ | |
7857 | if (crtl->profile || flag_exceptions || flag_unwind_tables) | |
7858 | emit_insn (gen_blockage ()); | |
7859 | ||
8c0dd614 | 7860 | if (flag_stack_usage_info) |
f47ae7b2 | 7861 | current_function_static_stack_size = stack_usage; |
47c009e5 | 7862 | } |
7863 | ||
6c049e03 | 7864 | /* Expand code for the function epilogue. */ |
47c009e5 | 7865 | void |
66209063 | 7866 | sh_expand_epilogue (bool sibcall_p) |
47c009e5 | 7867 | { |
ed8483c0 | 7868 | HARD_REG_SET live_regs_mask; |
0f021c78 | 7869 | int d, i; |
87e19636 | 7870 | int d_rounding = 0; |
47c009e5 | 7871 | |
1b61190c | 7872 | int save_flags = target_flags; |
8af3db02 | 7873 | int frame_size, save_size; |
36a2dfdb | 7874 | int fpscr_deferred = 0; |
66209063 | 7875 | int e = sibcall_p ? -1 : 1; |
ba46e0eb | 7876 | |
ed8483c0 | 7877 | d = calc_live_regs (&live_regs_mask); |
ba46e0eb | 7878 | |
8af3db02 | 7879 | save_size = d; |
7880 | frame_size = rounded_frame_size (d); | |
7881 | ||
7882 | if (TARGET_SH5) | |
7883 | { | |
7884 | int tregs_space = shmedia_target_regs_stack_adjust (&live_regs_mask); | |
7885 | int total_size; | |
7886 | if (d % (STACK_BOUNDARY / BITS_PER_UNIT)) | |
6c049e03 | 7887 | d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT) |
7888 | - d % (STACK_BOUNDARY / BITS_PER_UNIT)); | |
8af3db02 | 7889 | |
7890 | total_size = d + tregs_space; | |
7891 | total_size += rounded_frame_size (total_size); | |
7892 | save_size = total_size - frame_size; | |
7893 | ||
7894 | /* If adjusting the stack in a single step costs nothing extra, do so. | |
7895 | I.e. either if a single addi is enough, or we need a movi anyway, | |
7896 | and we don't exceed the maximum offset range (the test for the | |
7897 | latter is conservative for simplicity). */ | |
7898 | if (TARGET_SHMEDIA | |
7899 | && ! frame_pointer_needed | |
7900 | && (CONST_OK_FOR_I10 (total_size) | |
7901 | || (! CONST_OK_FOR_I10 (save_size + d_rounding) | |
7902 | && total_size <= 2044))) | |
7903 | d_rounding = frame_size; | |
87e19636 | 7904 | |
8af3db02 | 7905 | frame_size -= d_rounding; |
7906 | } | |
1504eb7e | 7907 | |
47c009e5 | 7908 | if (frame_pointer_needed) |
64623096 | 7909 | { |
2b0c9242 | 7910 | /* We must avoid scheduling the epilogue with previous basic blocks. |
566998f1 | 7911 | See PR/18032 and PR/40313. */ |
2b0c9242 | 7912 | emit_insn (gen_blockage ()); |
b9a602c6 | 7913 | output_stack_adjust (frame_size, hard_frame_pointer_rtx, e, |
c8ad18ed | 7914 | &live_regs_mask, true); |
b5a24772 | 7915 | |
7916 | /* We must avoid moving the stack pointer adjustment past code | |
7917 | which reads from the local frame, else an interrupt could | |
7918 | occur after the SP adjustment and clobber data in the local | |
7919 | frame. */ | |
7920 | emit_insn (gen_blockage ()); | |
c8ad18ed | 7921 | frame_insn (GEN_MOV (stack_pointer_rtx, hard_frame_pointer_rtx)); |
64623096 | 7922 | } |
ba46e0eb | 7923 | else if (frame_size) |
b5a24772 | 7924 | { |
7925 | /* We must avoid moving the stack pointer adjustment past code | |
7926 | which reads from the local frame, else an interrupt could | |
7927 | occur after the SP adjustment and clobber data in the local | |
7928 | frame. */ | |
7929 | emit_insn (gen_blockage ()); | |
b324d3bd | 7930 | output_stack_adjust (frame_size, stack_pointer_rtx, e, |
c8ad18ed | 7931 | &live_regs_mask, true); |
b5a24772 | 7932 | } |
47c009e5 | 7933 | |
87e19636 | 7934 | if (SHMEDIA_REGS_STACK_ADJUST ()) |
7935 | { | |
59312820 | 7936 | function_symbol (gen_rtx_REG (Pmode, R0_REG), |
7937 | (TARGET_FPU_ANY | |
7938 | ? "__GCC_pop_shmedia_regs" | |
7939 | : "__GCC_pop_shmedia_regs_nofpu"), SFUNC_GOT); | |
87e19636 | 7940 | /* This must NOT go through the PLT, otherwise mach and macl |
7941 | may be clobbered. */ | |
7942 | emit_insn (gen_shmedia_save_restore_regs_compact | |
7943 | (GEN_INT (SHMEDIA_REGS_STACK_ADJUST ()))); | |
7944 | } | |
7945 | ||
1504eb7e | 7946 | /* Pop all the registers. */ |
97595bfd | 7947 | |
36a2dfdb | 7948 | if (target_flags != save_flags && ! current_function_interrupt) |
1b61190c | 7949 | emit_insn (gen_toggle_sz ()); |
87e19636 | 7950 | if (TARGET_SH5) |
7951 | { | |
41fafa66 | 7952 | int offset_base, offset; |
87e19636 | 7953 | int offset_in_r0 = -1; |
7954 | int sp_in_r0 = 0; | |
87e19636 | 7955 | rtx r0 = gen_rtx_REG (Pmode, R0_REG); |
41fafa66 | 7956 | save_schedule schedule; |
7957 | save_entry *entry; | |
7958 | int *tmp_pnt; | |
ca474d26 | 7959 | |
41fafa66 | 7960 | entry = sh5_schedule_saves (&live_regs_mask, &schedule, d_rounding); |
7961 | offset_base = -entry[1].offset + d_rounding; | |
7962 | tmp_pnt = schedule.temps; | |
7963 | for (; entry->mode != VOIDmode; entry--) | |
7964 | { | |
3754d046 | 7965 | machine_mode mode = (machine_mode) entry->mode; |
41fafa66 | 7966 | int reg = entry->reg; |
168ae443 | 7967 | rtx reg_rtx, mem_rtx, post_inc = NULL_RTX; |
87e19636 | 7968 | |
41fafa66 | 7969 | offset = offset_base + entry->offset; |
7970 | reg_rtx = gen_rtx_REG (mode, reg); | |
87e19636 | 7971 | |
aa7e75f2 | 7972 | mem_rtx = gen_frame_mem (mode, |
7973 | gen_rtx_PLUS (Pmode, | |
7974 | stack_pointer_rtx, | |
7975 | GEN_INT (offset))); | |
87e19636 | 7976 | |
670db79f | 7977 | if (!memory_address_p (mode, XEXP (mem_rtx, 0))) |
7978 | mem_rtx = NULL_RTX; | |
87e19636 | 7979 | |
670db79f | 7980 | if (HAVE_POST_INCREMENT |
7981 | && (offset == offset_in_r0 | |
7982 | || (offset + GET_MODE_SIZE (mode) != d + d_rounding | |
7983 | && mem_rtx == NULL_RTX) | |
7984 | || reg == PR_REG || SPECIAL_REGISTER_P (reg))) | |
7985 | { | |
7986 | post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0)); | |
87e19636 | 7987 | |
670db79f | 7988 | if (!memory_address_p (mode, XEXP (post_inc, 0))) |
41fafa66 | 7989 | post_inc = NULL_RTX; |
670db79f | 7990 | else |
41fafa66 | 7991 | mem_rtx = NULL_RTX; |
670db79f | 7992 | } |
9e7454d0 | 7993 | |
41fafa66 | 7994 | if (mem_rtx != NULL_RTX) |
7995 | goto addr_ok; | |
87e19636 | 7996 | |
41fafa66 | 7997 | if (offset_in_r0 == -1) |
7998 | { | |
7999 | emit_move_insn (r0, GEN_INT (offset)); | |
8000 | offset_in_r0 = offset; | |
8001 | } | |
8002 | else if (offset != offset_in_r0) | |
8003 | { | |
8004 | emit_move_insn (r0, | |
8005 | gen_rtx_PLUS | |
8006 | (Pmode, r0, | |
8007 | GEN_INT (offset - offset_in_r0))); | |
8008 | offset_in_r0 += offset - offset_in_r0; | |
8009 | } | |
9e7454d0 | 8010 | |
41fafa66 | 8011 | if (post_inc != NULL_RTX) |
8012 | { | |
8013 | if (! sp_in_r0) | |
87e19636 | 8014 | { |
8015 | emit_move_insn (r0, | |
8016 | gen_rtx_PLUS | |
41fafa66 | 8017 | (Pmode, r0, stack_pointer_rtx)); |
8018 | sp_in_r0 = 1; | |
87e19636 | 8019 | } |
9e7454d0 | 8020 | |
41fafa66 | 8021 | mem_rtx = post_inc; |
87e19636 | 8022 | |
41fafa66 | 8023 | offset_in_r0 += GET_MODE_SIZE (mode); |
8024 | } | |
8025 | else if (sp_in_r0) | |
aa7e75f2 | 8026 | mem_rtx = gen_frame_mem (mode, r0); |
41fafa66 | 8027 | else |
aa7e75f2 | 8028 | mem_rtx = gen_frame_mem (mode, |
8029 | gen_rtx_PLUS (Pmode, | |
8030 | stack_pointer_rtx, | |
8031 | r0)); | |
87e19636 | 8032 | |
1a6a7a27 | 8033 | gcc_assert ((reg != PR_REG && !SPECIAL_REGISTER_P (reg)) |
8034 | || mem_rtx == post_inc); | |
87e19636 | 8035 | |
41fafa66 | 8036 | addr_ok: |
8037 | if ((reg == PR_REG || SPECIAL_REGISTER_P (reg)) | |
8038 | && mem_rtx != post_inc) | |
8039 | { | |
168ae443 | 8040 | emit_move_insn (r0, mem_rtx); |
41fafa66 | 8041 | mem_rtx = r0; |
8042 | } | |
8043 | else if (TARGET_REGISTER_P (reg)) | |
8044 | { | |
8045 | rtx tmp_reg = gen_rtx_REG (mode, *tmp_pnt); | |
8046 | ||
8047 | /* Give the scheduler a bit of freedom by using up to | |
8048 | MAX_TEMPS registers in a round-robin fashion. */ | |
168ae443 | 8049 | emit_move_insn (tmp_reg, mem_rtx); |
41fafa66 | 8050 | mem_rtx = tmp_reg; |
8051 | if (*++tmp_pnt < 0) | |
8052 | tmp_pnt = schedule.temps; | |
87e19636 | 8053 | } |
8054 | ||
168ae443 | 8055 | emit_move_insn (reg_rtx, mem_rtx); |
41fafa66 | 8056 | } |
8057 | ||
1a6a7a27 | 8058 | gcc_assert (entry->offset + offset_base == d + d_rounding); |
87e19636 | 8059 | } |
8af3db02 | 8060 | else /* ! TARGET_SH5 */ |
47c009e5 | 8061 | { |
2f8b8488 | 8062 | int last_reg; |
8063 | ||
8af3db02 | 8064 | save_size = 0; |
5241f4ad | 8065 | /* For an ISR with RESBANK attribute assigned, don't pop PR |
8066 | register. */ | |
8067 | if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG) | |
8068 | && !sh_cfun_resbank_handler_p ()) | |
3072d30e | 8069 | { |
8070 | if (!frame_pointer_needed) | |
8071 | emit_insn (gen_blockage ()); | |
8072 | pop (PR_REG); | |
8073 | } | |
2f8b8488 | 8074 | |
c90c8b4e | 8075 | /* Banked registers are popped first to avoid being scheduled in the |
2f8b8488 | 8076 | delay slot. RTE switches banks before the ds instruction. */ |
8077 | if (current_function_interrupt) | |
8078 | { | |
1b5c01d5 | 8079 | bool use_movml = false; |
8080 | ||
8081 | if (TARGET_SH2A) | |
8082 | { | |
8083 | unsigned int count = 0; | |
8084 | ||
8085 | for (i = FIRST_BANKED_REG; i <= LAST_BANKED_REG; i++) | |
8086 | if (TEST_HARD_REG_BIT (live_regs_mask, i)) | |
8087 | count++; | |
8088 | else | |
8089 | break; | |
8090 | ||
8091 | /* Use movml when all banked register are poped. */ | |
8092 | if (count == LAST_BANKED_REG - FIRST_BANKED_REG + 1) | |
8093 | use_movml = true; | |
8094 | } | |
8095 | ||
5a333029 | 8096 | if (sh_cfun_resbank_handler_p ()) |
8097 | ; /* Do nothing. */ | |
8098 | else if (use_movml) | |
1b5c01d5 | 8099 | { |
8100 | rtx sp_reg = gen_rtx_REG (SImode, STACK_POINTER_REGNUM); | |
8101 | ||
8102 | /* We must avoid scheduling multiple load insn with another | |
8103 | insns. */ | |
8104 | emit_insn (gen_blockage ()); | |
8105 | emit_insn (gen_movml_pop_banked (sp_reg)); | |
8106 | emit_insn (gen_blockage ()); | |
8107 | } | |
8108 | else | |
8109 | for (i = LAST_BANKED_REG; i >= FIRST_BANKED_REG; i--) | |
8110 | if (TEST_HARD_REG_BIT (live_regs_mask, i)) | |
8111 | pop (i); | |
2f8b8488 | 8112 | |
8113 | last_reg = FIRST_PSEUDO_REGISTER - LAST_BANKED_REG - 1; | |
8114 | } | |
8115 | else | |
8116 | last_reg = FIRST_PSEUDO_REGISTER; | |
8117 | ||
8118 | for (i = 0; i < last_reg; i++) | |
8af3db02 | 8119 | { |
8120 | int j = (FIRST_PSEUDO_REGISTER - 1) - i; | |
9e7454d0 | 8121 | |
8af3db02 | 8122 | if (j == FPSCR_REG && current_function_interrupt && TARGET_FMOVD |
ddc556d1 | 8123 | && hard_reg_set_intersect_p (live_regs_mask, |
8124 | reg_class_contents[DF_REGS])) | |
8af3db02 | 8125 | fpscr_deferred = 1; |
5241f4ad | 8126 | /* For an ISR with RESBANK attribute assigned, don't pop |
8127 | following registers, R0-R14, MACH, MACL and GBR. */ | |
8128 | else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j) | |
8129 | && ! (sh_cfun_resbank_handler_p () | |
8130 | && ((j >= FIRST_GENERAL_REG | |
8131 | && j < LAST_GENERAL_REG) | |
8132 | || j == MACH_REG | |
8133 | || j == MACL_REG | |
8134 | || j == GBR_REG))) | |
8af3db02 | 8135 | pop (j); |
2f8b8488 | 8136 | |
8af3db02 | 8137 | if (j == FIRST_FP_REG && fpscr_deferred) |
8138 | pop (FPSCR_REG); | |
8af3db02 | 8139 | } |
47c009e5 | 8140 | } |
36a2dfdb | 8141 | if (target_flags != save_flags && ! current_function_interrupt) |
1b61190c | 8142 | emit_insn (gen_toggle_sz ()); |
8143 | target_flags = save_flags; | |
47c009e5 | 8144 | |
abe32cce | 8145 | output_stack_adjust (crtl->args.pretend_args_size |
8af3db02 | 8146 | + save_size + d_rounding |
abe32cce | 8147 | + crtl->args.info.stack_regs * 8, |
c8ad18ed | 8148 | stack_pointer_rtx, e, NULL, true); |
15cb1799 | 8149 | |
18d50ae6 | 8150 | if (crtl->calls_eh_return) |
805e22b2 | 8151 | emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx, |
8152 | EH_RETURN_STACKADJ_RTX)); | |
8153 | ||
15cb1799 | 8154 | /* Switch back to the normal stack if necessary. */ |
57d5535b | 8155 | if (lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl))) |
15cb1799 | 8156 | emit_insn (gen_sp_switch_2 ()); |
6dc67d01 | 8157 | |
8158 | /* Tell flow the insn that pops PR isn't dead. */ | |
87e19636 | 8159 | /* PR_REG will never be live in SHmedia mode, and we don't need to |
8160 | USE PR_MEDIA_REG, since it will be explicitly copied to TR0_REG | |
8161 | by the return pattern. */ | |
ed8483c0 | 8162 | if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG)) |
18b42941 | 8163 | emit_use (gen_rtx_REG (SImode, PR_REG)); |
47c009e5 | 8164 | } |
8165 | ||
805e22b2 | 8166 | /* Emit code to change the current function's return address to RA. |
8167 | TEMP is available as a scratch register, if needed. */ | |
805e22b2 | 8168 | void |
04f04b72 | 8169 | sh_set_return_address (rtx ra, rtx tmp) |
805e22b2 | 8170 | { |
ed8483c0 | 8171 | HARD_REG_SET live_regs_mask; |
805e22b2 | 8172 | int d; |
805e22b2 | 8173 | int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG; |
8174 | int pr_offset; | |
8175 | ||
ed8483c0 | 8176 | d = calc_live_regs (&live_regs_mask); |
805e22b2 | 8177 | |
8178 | /* If pr_reg isn't life, we can set it (or the register given in | |
8179 | sh_media_register_for_return) directly. */ | |
ed8483c0 | 8180 | if (! TEST_HARD_REG_BIT (live_regs_mask, pr_reg)) |
805e22b2 | 8181 | { |
8182 | rtx rr; | |
8183 | ||
8184 | if (TARGET_SHMEDIA) | |
8185 | { | |
8186 | int rr_regno = sh_media_register_for_return (); | |
8187 | ||
8188 | if (rr_regno < 0) | |
8189 | rr_regno = pr_reg; | |
8190 | ||
8191 | rr = gen_rtx_REG (DImode, rr_regno); | |
8192 | } | |
8193 | else | |
8194 | rr = gen_rtx_REG (SImode, pr_reg); | |
8195 | ||
8196 | emit_insn (GEN_MOV (rr, ra)); | |
8197 | /* Tell flow the register for return isn't dead. */ | |
18b42941 | 8198 | emit_use (rr); |
805e22b2 | 8199 | return; |
8200 | } | |
8201 | ||
8202 | if (TARGET_SH5) | |
8203 | { | |
805e22b2 | 8204 | int offset; |
41fafa66 | 8205 | save_schedule schedule; |
8206 | save_entry *entry; | |
9e7454d0 | 8207 | |
41fafa66 | 8208 | entry = sh5_schedule_saves (&live_regs_mask, &schedule, 0); |
8209 | offset = entry[1].offset; | |
8210 | for (; entry->mode != VOIDmode; entry--) | |
8211 | if (entry->reg == pr_reg) | |
8212 | goto found; | |
805e22b2 | 8213 | |
8214 | /* We can't find pr register. */ | |
1a6a7a27 | 8215 | gcc_unreachable (); |
805e22b2 | 8216 | |
8217 | found: | |
41fafa66 | 8218 | offset = entry->offset - offset; |
8219 | pr_offset = (rounded_frame_size (d) + offset | |
805e22b2 | 8220 | + SHMEDIA_REGS_STACK_ADJUST ()); |
8221 | } | |
8222 | else | |
41fafa66 | 8223 | pr_offset = rounded_frame_size (d); |
805e22b2 | 8224 | |
8225 | emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset))); | |
992d172c | 8226 | |
8227 | if (frame_pointer_needed) | |
8228 | emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx)); | |
8229 | else | |
8230 | emit_insn (GEN_ADD3 (tmp, tmp, stack_pointer_rtx)); | |
805e22b2 | 8231 | |
aa7e75f2 | 8232 | tmp = gen_frame_mem (Pmode, tmp); |
805e22b2 | 8233 | emit_insn (GEN_MOV (tmp, ra)); |
b4dce965 | 8234 | /* Tell this store isn't dead. */ |
8235 | emit_use (tmp); | |
805e22b2 | 8236 | } |
8237 | ||
73401833 | 8238 | /* Clear variables at function end. */ |
17d9b0c3 | 8239 | static void |
04f04b72 | 8240 | sh_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, |
8241 | HOST_WIDE_INT size ATTRIBUTE_UNUSED) | |
73401833 | 8242 | { |
73401833 | 8243 | } |
8244 | ||
45550790 | 8245 | static rtx |
04f04b72 | 8246 | sh_builtin_saveregs (void) |
b00564da | 8247 | { |
b00564da | 8248 | /* First unnamed integer register. */ |
abe32cce | 8249 | int first_intreg = crtl->args.info.arg_count[(int) SH_ARG_INT]; |
b00564da | 8250 | /* Number of integer registers we need to save. */ |
8251 | int n_intregs = MAX (0, NPARM_REGS (SImode) - first_intreg); | |
8252 | /* First unnamed SFmode float reg */ | |
abe32cce | 8253 | int first_floatreg = crtl->args.info.arg_count[(int) SH_ARG_FLOAT]; |
b00564da | 8254 | /* Number of SFmode float regs to save. */ |
8255 | int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg); | |
b7dbbdb2 | 8256 | rtx regbuf, fpregs; |
ab6ab77e | 8257 | int bufsize, regno; |
32c2fdea | 8258 | alias_set_type alias_set; |
b00564da | 8259 | |
87e19636 | 8260 | if (TARGET_SH5) |
8261 | { | |
8262 | if (n_intregs) | |
8263 | { | |
8264 | int pushregs = n_intregs; | |
8265 | ||
8266 | while (pushregs < NPARM_REGS (SImode) - 1 | |
8267 | && (CALL_COOKIE_INT_REG_GET | |
abe32cce | 8268 | (crtl->args.info.call_cookie, |
87e19636 | 8269 | NPARM_REGS (SImode) - pushregs) |
8270 | == 1)) | |
8271 | { | |
abe32cce | 8272 | crtl->args.info.call_cookie |
87e19636 | 8273 | &= ~ CALL_COOKIE_INT_REG (NPARM_REGS (SImode) |
8274 | - pushregs, 1); | |
8275 | pushregs++; | |
8276 | } | |
8277 | ||
8278 | if (pushregs == NPARM_REGS (SImode)) | |
abe32cce | 8279 | crtl->args.info.call_cookie |
87e19636 | 8280 | |= (CALL_COOKIE_INT_REG (0, 1) |
8281 | | CALL_COOKIE_STACKSEQ (pushregs - 1)); | |
8282 | else | |
abe32cce | 8283 | crtl->args.info.call_cookie |
87e19636 | 8284 | |= CALL_COOKIE_STACKSEQ (pushregs); |
8285 | ||
abe32cce | 8286 | crtl->args.pretend_args_size += 8 * n_intregs; |
87e19636 | 8287 | } |
8288 | if (TARGET_SHCOMPACT) | |
8289 | return const0_rtx; | |
8290 | } | |
9e7454d0 | 8291 | |
87ed74ef | 8292 | if (! TARGET_SH2E && ! TARGET_SH4 && ! TARGET_SH5) |
87e19636 | 8293 | { |
8294 | error ("__builtin_saveregs not supported by this subtarget"); | |
8295 | return const0_rtx; | |
8296 | } | |
8297 | ||
8298 | if (TARGET_SHMEDIA) | |
8299 | n_floatregs = 0; | |
8300 | ||
9df03d69 | 8301 | /* Allocate block of memory for the regs. */ |
b00564da | 8302 | /* ??? If n_intregs + n_floatregs == 0, should we allocate at least 1 byte? |
8303 | Or can assign_stack_local accept a 0 SIZE argument? */ | |
8304 | bufsize = (n_intregs * UNITS_PER_WORD) + (n_floatregs * UNITS_PER_WORD); | |
8305 | ||
87e19636 | 8306 | if (TARGET_SHMEDIA) |
aa7e75f2 | 8307 | regbuf = gen_frame_mem (BLKmode, gen_rtx_REG (Pmode, ARG_POINTER_REGNUM)); |
65f753eb | 8308 | else if (n_floatregs & 1) |
8309 | { | |
8310 | rtx addr; | |
8311 | ||
8312 | regbuf = assign_stack_local (BLKmode, bufsize + UNITS_PER_WORD, 0); | |
8313 | addr = copy_to_mode_reg (Pmode, XEXP (regbuf, 0)); | |
8314 | emit_insn (gen_iorsi3 (addr, addr, GEN_INT (UNITS_PER_WORD))); | |
8315 | regbuf = change_address (regbuf, BLKmode, addr); | |
8316 | } | |
faffb001 | 8317 | else if (STACK_BOUNDARY < 64 && TARGET_FPU_DOUBLE && n_floatregs) |
8318 | { | |
8319 | rtx addr, mask; | |
8320 | ||
8321 | regbuf = assign_stack_local (BLKmode, bufsize + UNITS_PER_WORD, 0); | |
29c05e22 | 8322 | addr = copy_to_mode_reg (Pmode, plus_constant (Pmode, |
8323 | XEXP (regbuf, 0), 4)); | |
faffb001 | 8324 | mask = copy_to_mode_reg (Pmode, GEN_INT (-8)); |
8325 | emit_insn (gen_andsi3 (addr, addr, mask)); | |
8326 | regbuf = change_address (regbuf, BLKmode, addr); | |
8327 | } | |
87e19636 | 8328 | else |
faffb001 | 8329 | regbuf = assign_stack_local (BLKmode, bufsize, TARGET_FPU_DOUBLE ? 64 : 0); |
d1de1e66 | 8330 | alias_set = get_varargs_alias_set (); |
ab6ab77e | 8331 | set_mem_alias_set (regbuf, alias_set); |
b00564da | 8332 | |
8333 | /* Save int args. | |
8334 | This is optimized to only save the regs that are necessary. Explicitly | |
8335 | named args need not be saved. */ | |
8336 | if (n_intregs > 0) | |
8337 | move_block_from_reg (BASE_ARG_REG (SImode) + first_intreg, | |
e513d163 | 8338 | adjust_address (regbuf, BLKmode, |
8339 | n_floatregs * UNITS_PER_WORD), | |
530178a9 | 8340 | n_intregs); |
b00564da | 8341 | |
87e19636 | 8342 | if (TARGET_SHMEDIA) |
8343 | /* Return the address of the regbuf. */ | |
8344 | return XEXP (regbuf, 0); | |
8345 | ||
b00564da | 8346 | /* Save float args. |
8347 | This is optimized to only save the regs that are necessary. Explicitly | |
8348 | named args need not be saved. | |
8349 | We explicitly build a pointer to the buffer because it halves the insn | |
8350 | count when not optimizing (otherwise the pointer is built for each reg | |
8ded0752 | 8351 | saved). |
8352 | We emit the moves in reverse order so that we can use predecrement. */ | |
b00564da | 8353 | |
dcf3f9fe | 8354 | fpregs = copy_to_mode_reg (Pmode, |
29c05e22 | 8355 | plus_constant (Pmode, XEXP (regbuf, 0), |
8356 | n_floatregs * UNITS_PER_WORD)); | |
7105fb72 | 8357 | if (TARGET_SH4 || TARGET_SH2A_DOUBLE) |
1b61190c | 8358 | { |
d1de1e66 | 8359 | rtx mem; |
1b61190c | 8360 | for (regno = NPARM_REGS (DFmode) - 2; regno >= first_floatreg; regno -= 2) |
8361 | { | |
8362 | emit_insn (gen_addsi3 (fpregs, fpregs, | |
8363 | GEN_INT (-2 * UNITS_PER_WORD))); | |
aa7e75f2 | 8364 | mem = change_address (regbuf, DFmode, fpregs); |
9e7454d0 | 8365 | emit_move_insn (mem, |
407d9153 | 8366 | gen_rtx_REG (DFmode, BASE_ARG_REG (DFmode) + regno)); |
1b61190c | 8367 | } |
8368 | regno = first_floatreg; | |
8369 | if (regno & 1) | |
8370 | { | |
d767e27e | 8371 | emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (-UNITS_PER_WORD))); |
aa7e75f2 | 8372 | mem = change_address (regbuf, SFmode, fpregs); |
d1de1e66 | 8373 | emit_move_insn (mem, |
adb7af07 | 8374 | gen_rtx_REG (SFmode, BASE_ARG_REG (SFmode) |
8375 | + regno - SH_REG_MSW_OFFSET)); | |
1b61190c | 8376 | } |
8377 | } | |
8378 | else | |
8ded0752 | 8379 | for (regno = NPARM_REGS (SFmode) - 1; regno >= first_floatreg; regno--) |
8380 | { | |
d1de1e66 | 8381 | rtx mem; |
ab6ab77e | 8382 | |
d767e27e | 8383 | emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (-UNITS_PER_WORD))); |
aa7e75f2 | 8384 | mem = change_address (regbuf, SFmode, fpregs); |
d1de1e66 | 8385 | emit_move_insn (mem, |
7014838c | 8386 | gen_rtx_REG (SFmode, BASE_ARG_REG (SFmode) + regno)); |
8ded0752 | 8387 | } |
b00564da | 8388 | |
8389 | /* Return the address of the regbuf. */ | |
8390 | return XEXP (regbuf, 0); | |
8391 | } | |
8392 | ||
d1de1e66 | 8393 | /* Define the `__builtin_va_list' type for the ABI. */ |
2e15d750 | 8394 | static tree |
8395 | sh_build_builtin_va_list (void) | |
d1de1e66 | 8396 | { |
8397 | tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack; | |
cbae1407 | 8398 | tree record, type_decl; |
d1de1e66 | 8399 | |
45550790 | 8400 | if (TARGET_SH5 || (! TARGET_SH2E && ! TARGET_SH4) |
8401 | || TARGET_HITACHI || sh_cfun_attr_renesas_p ()) | |
d1de1e66 | 8402 | return ptr_type_node; |
8403 | ||
89fdb407 | 8404 | record = (*lang_hooks.types.make_type) (RECORD_TYPE); |
cbae1407 | 8405 | type_decl = build_decl (BUILTINS_LOCATION, |
8406 | TYPE_DECL, get_identifier ("__va_list_tag"), record); | |
d1de1e66 | 8407 | |
54e46243 | 8408 | f_next_o = build_decl (BUILTINS_LOCATION, |
8409 | FIELD_DECL, get_identifier ("__va_next_o"), | |
d1de1e66 | 8410 | ptr_type_node); |
54e46243 | 8411 | f_next_o_limit = build_decl (BUILTINS_LOCATION, |
8412 | FIELD_DECL, | |
d1de1e66 | 8413 | get_identifier ("__va_next_o_limit"), |
8414 | ptr_type_node); | |
54e46243 | 8415 | f_next_fp = build_decl (BUILTINS_LOCATION, |
8416 | FIELD_DECL, get_identifier ("__va_next_fp"), | |
d1de1e66 | 8417 | ptr_type_node); |
54e46243 | 8418 | f_next_fp_limit = build_decl (BUILTINS_LOCATION, |
8419 | FIELD_DECL, | |
d1de1e66 | 8420 | get_identifier ("__va_next_fp_limit"), |
8421 | ptr_type_node); | |
54e46243 | 8422 | f_next_stack = build_decl (BUILTINS_LOCATION, |
8423 | FIELD_DECL, get_identifier ("__va_next_stack"), | |
d1de1e66 | 8424 | ptr_type_node); |
8425 | ||
8426 | DECL_FIELD_CONTEXT (f_next_o) = record; | |
8427 | DECL_FIELD_CONTEXT (f_next_o_limit) = record; | |
8428 | DECL_FIELD_CONTEXT (f_next_fp) = record; | |
8429 | DECL_FIELD_CONTEXT (f_next_fp_limit) = record; | |
8430 | DECL_FIELD_CONTEXT (f_next_stack) = record; | |
8431 | ||
bc907808 | 8432 | TYPE_STUB_DECL (record) = type_decl; |
cbae1407 | 8433 | TYPE_NAME (record) = type_decl; |
d1de1e66 | 8434 | TYPE_FIELDS (record) = f_next_o; |
1767a056 | 8435 | DECL_CHAIN (f_next_o) = f_next_o_limit; |
8436 | DECL_CHAIN (f_next_o_limit) = f_next_fp; | |
8437 | DECL_CHAIN (f_next_fp) = f_next_fp_limit; | |
8438 | DECL_CHAIN (f_next_fp_limit) = f_next_stack; | |
d1de1e66 | 8439 | |
8440 | layout_type (record); | |
8441 | ||
8442 | return record; | |
8443 | } | |
8444 | ||
8445 | /* Implement `va_start' for varargs and stdarg. */ | |
8a58ed0a | 8446 | static void |
04f04b72 | 8447 | sh_va_start (tree valist, rtx nextarg) |
d1de1e66 | 8448 | { |
8449 | tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack; | |
8450 | tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack; | |
8451 | tree t, u; | |
8452 | int nfp, nint; | |
8453 | ||
87e19636 | 8454 | if (TARGET_SH5) |
8455 | { | |
8456 | expand_builtin_saveregs (); | |
7df226a2 | 8457 | std_expand_builtin_va_start (valist, nextarg); |
87e19636 | 8458 | return; |
8459 | } | |
8460 | ||
45550790 | 8461 | if ((! TARGET_SH2E && ! TARGET_SH4) |
8462 | || TARGET_HITACHI || sh_cfun_attr_renesas_p ()) | |
d1de1e66 | 8463 | { |
7df226a2 | 8464 | std_expand_builtin_va_start (valist, nextarg); |
d1de1e66 | 8465 | return; |
8466 | } | |
8467 | ||
8468 | f_next_o = TYPE_FIELDS (va_list_type_node); | |
1767a056 | 8469 | f_next_o_limit = DECL_CHAIN (f_next_o); |
8470 | f_next_fp = DECL_CHAIN (f_next_o_limit); | |
8471 | f_next_fp_limit = DECL_CHAIN (f_next_fp); | |
8472 | f_next_stack = DECL_CHAIN (f_next_fp_limit); | |
d1de1e66 | 8473 | |
ed03eadb | 8474 | next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o, |
6374121b | 8475 | NULL_TREE); |
ed03eadb | 8476 | next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit), |
8477 | valist, f_next_o_limit, NULL_TREE); | |
8478 | next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp, | |
8479 | NULL_TREE); | |
8480 | next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit), | |
8481 | valist, f_next_fp_limit, NULL_TREE); | |
8482 | next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack), | |
8483 | valist, f_next_stack, NULL_TREE); | |
d1de1e66 | 8484 | |
8485 | /* Call __builtin_saveregs. */ | |
0de36bdb | 8486 | u = make_tree (sizetype, expand_builtin_saveregs ()); |
8487 | u = fold_convert (ptr_type_node, u); | |
75a70cf9 | 8488 | t = build2 (MODIFY_EXPR, ptr_type_node, next_fp, u); |
d1de1e66 | 8489 | TREE_SIDE_EFFECTS (t) = 1; |
8490 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
8491 | ||
abe32cce | 8492 | nfp = crtl->args.info.arg_count[SH_ARG_FLOAT]; |
d1de1e66 | 8493 | if (nfp < 8) |
8494 | nfp = 8 - nfp; | |
8495 | else | |
8496 | nfp = 0; | |
2cc66f2a | 8497 | u = fold_build_pointer_plus_hwi (u, UNITS_PER_WORD * nfp); |
75a70cf9 | 8498 | t = build2 (MODIFY_EXPR, ptr_type_node, next_fp_limit, u); |
d1de1e66 | 8499 | TREE_SIDE_EFFECTS (t) = 1; |
8500 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
8501 | ||
75a70cf9 | 8502 | t = build2 (MODIFY_EXPR, ptr_type_node, next_o, u); |
d1de1e66 | 8503 | TREE_SIDE_EFFECTS (t) = 1; |
8504 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
8505 | ||
abe32cce | 8506 | nint = crtl->args.info.arg_count[SH_ARG_INT]; |
d1de1e66 | 8507 | if (nint < 4) |
8508 | nint = 4 - nint; | |
8509 | else | |
8510 | nint = 0; | |
2cc66f2a | 8511 | u = fold_build_pointer_plus_hwi (u, UNITS_PER_WORD * nint); |
75a70cf9 | 8512 | t = build2 (MODIFY_EXPR, ptr_type_node, next_o_limit, u); |
d1de1e66 | 8513 | TREE_SIDE_EFFECTS (t) = 1; |
8514 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
8515 | ||
8516 | u = make_tree (ptr_type_node, nextarg); | |
75a70cf9 | 8517 | t = build2 (MODIFY_EXPR, ptr_type_node, next_stack, u); |
d1de1e66 | 8518 | TREE_SIDE_EFFECTS (t) = 1; |
8519 | expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); | |
8520 | } | |
8521 | ||
9ca2c29a | 8522 | /* TYPE is a RECORD_TYPE. If there is only a single nonzero-sized |
9c1799a1 | 8523 | member, return it. */ |
8524 | static tree | |
8525 | find_sole_member (tree type) | |
8526 | { | |
8527 | tree field, member = NULL_TREE; | |
8528 | ||
1767a056 | 8529 | for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) |
9c1799a1 | 8530 | { |
8531 | if (TREE_CODE (field) != FIELD_DECL) | |
8532 | continue; | |
8533 | if (!DECL_SIZE (field)) | |
8534 | return NULL_TREE; | |
8535 | if (integer_zerop (DECL_SIZE (field))) | |
8536 | continue; | |
8537 | if (member) | |
8538 | return NULL_TREE; | |
8539 | member = field; | |
8540 | } | |
8541 | return member; | |
8542 | } | |
d1de1e66 | 8543 | |
6c049e03 | 8544 | /* Implement `va_arg'. */ |
20cdebf8 | 8545 | static tree |
75a70cf9 | 8546 | sh_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, |
8547 | gimple_seq *post_p ATTRIBUTE_UNUSED) | |
d1de1e66 | 8548 | { |
8549 | HOST_WIDE_INT size, rsize; | |
b7dbbdb2 | 8550 | tree tmp, pptr_type_node; |
bfa0b1cf | 8551 | tree addr, lab_over = NULL, result = NULL; |
90d67aec | 8552 | bool pass_by_ref; |
e577f34b | 8553 | tree eff_type; |
20cdebf8 | 8554 | |
90d67aec | 8555 | if (!VOID_TYPE_P (type)) |
8556 | pass_by_ref = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type); | |
8557 | else | |
8558 | pass_by_ref = false; | |
8559 | ||
20cdebf8 | 8560 | if (pass_by_ref) |
8561 | type = build_pointer_type (type); | |
d1de1e66 | 8562 | |
8563 | size = int_size_in_bytes (type); | |
8564 | rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD; | |
8565 | pptr_type_node = build_pointer_type (ptr_type_node); | |
8566 | ||
45550790 | 8567 | if (! TARGET_SH5 && (TARGET_SH2E || TARGET_SH4) |
8568 | && ! (TARGET_HITACHI || sh_cfun_attr_renesas_p ())) | |
d1de1e66 | 8569 | { |
8570 | tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack; | |
8571 | tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack; | |
8572 | int pass_as_float; | |
20cdebf8 | 8573 | tree lab_false; |
9c1799a1 | 8574 | tree member; |
d1de1e66 | 8575 | |
8576 | f_next_o = TYPE_FIELDS (va_list_type_node); | |
1767a056 | 8577 | f_next_o_limit = DECL_CHAIN (f_next_o); |
8578 | f_next_fp = DECL_CHAIN (f_next_o_limit); | |
8579 | f_next_fp_limit = DECL_CHAIN (f_next_fp); | |
8580 | f_next_stack = DECL_CHAIN (f_next_fp_limit); | |
d1de1e66 | 8581 | |
ed03eadb | 8582 | next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o, |
8583 | NULL_TREE); | |
8584 | next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit), | |
8585 | valist, f_next_o_limit, NULL_TREE); | |
8586 | next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp), | |
6c049e03 | 8587 | valist, f_next_fp, NULL_TREE); |
ed03eadb | 8588 | next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit), |
8589 | valist, f_next_fp_limit, NULL_TREE); | |
8590 | next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack), | |
8591 | valist, f_next_stack, NULL_TREE); | |
d1de1e66 | 8592 | |
d8e6ba8f | 8593 | /* Structures with a single member with a distinct mode are passed |
8594 | like their member. This is relevant if the latter has a REAL_TYPE | |
8595 | or COMPLEX_TYPE type. */ | |
e577f34b | 8596 | eff_type = type; |
8597 | while (TREE_CODE (eff_type) == RECORD_TYPE | |
8598 | && (member = find_sole_member (eff_type)) | |
9c1799a1 | 8599 | && (TREE_CODE (TREE_TYPE (member)) == REAL_TYPE |
8600 | || TREE_CODE (TREE_TYPE (member)) == COMPLEX_TYPE | |
8601 | || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE)) | |
ba59da21 | 8602 | { |
9c1799a1 | 8603 | tree field_type = TREE_TYPE (member); |
ba59da21 | 8604 | |
e577f34b | 8605 | if (TYPE_MODE (eff_type) == TYPE_MODE (field_type)) |
8606 | eff_type = field_type; | |
ba59da21 | 8607 | else |
9ba7abb0 | 8608 | { |
e577f34b | 8609 | gcc_assert ((TYPE_ALIGN (eff_type) |
9c1799a1 | 8610 | < GET_MODE_ALIGNMENT (TYPE_MODE (field_type))) |
e577f34b | 8611 | || (TYPE_ALIGN (eff_type) |
9c1799a1 | 8612 | > GET_MODE_BITSIZE (TYPE_MODE (field_type)))); |
8613 | break; | |
9ba7abb0 | 8614 | } |
ba59da21 | 8615 | } |
20cdebf8 | 8616 | |
feef6011 | 8617 | if (TARGET_SH4 || TARGET_SH2A_DOUBLE) |
d1de1e66 | 8618 | { |
e577f34b | 8619 | pass_as_float = ((TREE_CODE (eff_type) == REAL_TYPE && size <= 8) |
8620 | || (TREE_CODE (eff_type) == COMPLEX_TYPE | |
8621 | && TREE_CODE (TREE_TYPE (eff_type)) == REAL_TYPE | |
d1de1e66 | 8622 | && size <= 16)); |
8623 | } | |
8624 | else | |
8625 | { | |
e577f34b | 8626 | pass_as_float = (TREE_CODE (eff_type) == REAL_TYPE && size == 4); |
d1de1e66 | 8627 | } |
8628 | ||
20cdebf8 | 8629 | addr = create_tmp_var (pptr_type_node, NULL); |
54e46243 | 8630 | lab_false = create_artificial_label (UNKNOWN_LOCATION); |
8631 | lab_over = create_artificial_label (UNKNOWN_LOCATION); | |
d1de1e66 | 8632 | |
182cf5a9 | 8633 | valist = build_simple_mem_ref (addr); |
d8e6ba8f | 8634 | |
d1de1e66 | 8635 | if (pass_as_float) |
8636 | { | |
faffb001 | 8637 | tree next_fp_tmp = create_tmp_var (TREE_TYPE (f_next_fp), NULL); |
8638 | tree cmp; | |
e577f34b | 8639 | bool is_double = size == 8 && TREE_CODE (eff_type) == REAL_TYPE; |
65f753eb | 8640 | |
d529bef4 | 8641 | tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_fp)); |
8642 | gimplify_assign (unshare_expr (addr), tmp, pre_p); | |
faffb001 | 8643 | |
d529bef4 | 8644 | gimplify_assign (unshare_expr (next_fp_tmp), valist, pre_p); |
faffb001 | 8645 | tmp = next_fp_limit; |
8646 | if (size > 4 && !is_double) | |
2cc66f2a | 8647 | tmp = fold_build_pointer_plus_hwi (unshare_expr (tmp), 4 - size); |
d529bef4 | 8648 | tmp = build2 (GE_EXPR, boolean_type_node, |
8649 | unshare_expr (next_fp_tmp), unshare_expr (tmp)); | |
ed03eadb | 8650 | cmp = build3 (COND_EXPR, void_type_node, tmp, |
d529bef4 | 8651 | build1 (GOTO_EXPR, void_type_node, |
8652 | unshare_expr (lab_false)), NULL_TREE); | |
faffb001 | 8653 | if (!is_double) |
8654 | gimplify_and_add (cmp, pre_p); | |
d1de1e66 | 8655 | |
e577f34b | 8656 | if (TYPE_ALIGN (eff_type) > BITS_PER_WORD |
8657 | || (is_double || size == 16)) | |
d1de1e66 | 8658 | { |
0de36bdb | 8659 | tmp = fold_convert (sizetype, next_fp_tmp); |
8660 | tmp = build2 (BIT_AND_EXPR, sizetype, tmp, | |
8661 | size_int (UNITS_PER_WORD)); | |
2cc66f2a | 8662 | tmp = fold_build_pointer_plus (unshare_expr (next_fp_tmp), tmp); |
d529bef4 | 8663 | gimplify_assign (unshare_expr (next_fp_tmp), tmp, pre_p); |
d1de1e66 | 8664 | } |
faffb001 | 8665 | if (is_double) |
8666 | gimplify_and_add (cmp, pre_p); | |
d1de1e66 | 8667 | |
d8e6ba8f | 8668 | #ifdef FUNCTION_ARG_SCmode_WART |
e577f34b | 8669 | if (TYPE_MODE (eff_type) == SCmode |
8670 | && TARGET_SH4 && TARGET_LITTLE_ENDIAN) | |
d8e6ba8f | 8671 | { |
e577f34b | 8672 | tree subtype = TREE_TYPE (eff_type); |
20cdebf8 | 8673 | tree real, imag; |
d8e6ba8f | 8674 | |
faffb001 | 8675 | imag |
8676 | = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL); | |
20cdebf8 | 8677 | imag = get_initialized_tmp_var (imag, pre_p, NULL); |
d8e6ba8f | 8678 | |
faffb001 | 8679 | real |
8680 | = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL); | |
20cdebf8 | 8681 | real = get_initialized_tmp_var (real, pre_p, NULL); |
8682 | ||
3c25644b | 8683 | result = build2 (COMPLEX_EXPR, eff_type, real, imag); |
8684 | if (type != eff_type) | |
8685 | result = build1 (VIEW_CONVERT_EXPR, type, result); | |
20cdebf8 | 8686 | result = get_initialized_tmp_var (result, pre_p, NULL); |
d8e6ba8f | 8687 | } |
8688 | #endif /* FUNCTION_ARG_SCmode_WART */ | |
8689 | ||
d529bef4 | 8690 | tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (lab_over)); |
20cdebf8 | 8691 | gimplify_and_add (tmp, pre_p); |
8692 | ||
d529bef4 | 8693 | tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_false)); |
20cdebf8 | 8694 | gimplify_and_add (tmp, pre_p); |
d1de1e66 | 8695 | |
d529bef4 | 8696 | tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_stack)); |
8697 | gimplify_assign (unshare_expr (addr), tmp, pre_p); | |
8698 | gimplify_assign (unshare_expr (next_fp_tmp), | |
8699 | unshare_expr (valist), pre_p); | |
faffb001 | 8700 | |
d529bef4 | 8701 | gimplify_assign (unshare_expr (valist), |
8702 | unshare_expr (next_fp_tmp), post_p); | |
faffb001 | 8703 | valist = next_fp_tmp; |
d1de1e66 | 8704 | } |
8705 | else | |
8706 | { | |
2cc66f2a | 8707 | tmp = fold_build_pointer_plus_hwi (unshare_expr (next_o), rsize); |
d529bef4 | 8708 | tmp = build2 (GT_EXPR, boolean_type_node, tmp, |
8709 | unshare_expr (next_o_limit)); | |
ed03eadb | 8710 | tmp = build3 (COND_EXPR, void_type_node, tmp, |
d529bef4 | 8711 | build1 (GOTO_EXPR, void_type_node, |
8712 | unshare_expr (lab_false)), | |
8713 | NULL_TREE); | |
20cdebf8 | 8714 | gimplify_and_add (tmp, pre_p); |
d1de1e66 | 8715 | |
d529bef4 | 8716 | tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_o)); |
8717 | gimplify_assign (unshare_expr (addr), tmp, pre_p); | |
d1de1e66 | 8718 | |
d529bef4 | 8719 | tmp = build1 (GOTO_EXPR, void_type_node, unshare_expr (lab_over)); |
20cdebf8 | 8720 | gimplify_and_add (tmp, pre_p); |
8721 | ||
d529bef4 | 8722 | tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_false)); |
20cdebf8 | 8723 | gimplify_and_add (tmp, pre_p); |
d1de1e66 | 8724 | |
feef6011 | 8725 | if (size > 4 && ! (TARGET_SH4 || TARGET_SH2A)) |
d529bef4 | 8726 | gimplify_assign (unshare_expr (next_o), |
8727 | unshare_expr (next_o_limit), pre_p); | |
d1de1e66 | 8728 | |
d529bef4 | 8729 | tmp = build1 (ADDR_EXPR, pptr_type_node, unshare_expr (next_stack)); |
8730 | gimplify_assign (unshare_expr (addr), tmp, pre_p); | |
d1de1e66 | 8731 | } |
8732 | ||
20cdebf8 | 8733 | if (!result) |
8734 | { | |
d529bef4 | 8735 | tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over)); |
20cdebf8 | 8736 | gimplify_and_add (tmp, pre_p); |
8737 | } | |
d1de1e66 | 8738 | } |
8739 | ||
8740 | /* ??? In va-sh.h, there had been code to make values larger than | |
8741 | size 8 indirect. This does not match the FUNCTION_ARG macros. */ | |
8742 | ||
20cdebf8 | 8743 | tmp = std_gimplify_va_arg_expr (valist, type, pre_p, NULL); |
d8e6ba8f | 8744 | if (result) |
8745 | { | |
75a70cf9 | 8746 | gimplify_assign (result, tmp, pre_p); |
3c5bea87 | 8747 | result = build1 (NOP_EXPR, TREE_TYPE (result), result); |
d529bef4 | 8748 | tmp = build1 (LABEL_EXPR, void_type_node, unshare_expr (lab_over)); |
20cdebf8 | 8749 | gimplify_and_add (tmp, pre_p); |
d8e6ba8f | 8750 | } |
8751 | else | |
20cdebf8 | 8752 | result = tmp; |
d8e6ba8f | 8753 | |
a3e17e8c | 8754 | if (pass_by_ref) |
063f5fdd | 8755 | result = build_va_arg_indirect_ref (result); |
20cdebf8 | 8756 | |
a3e17e8c | 8757 | return result; |
d1de1e66 | 8758 | } |
8759 | ||
e1190e3a | 8760 | /* 64 bit floating points memory transfers are paired single precision loads |
6c049e03 | 8761 | or store. So DWARF information needs fixing in little endian (unless |
e1190e3a | 8762 | PR=SZ=1 in FPSCR). */ |
8763 | rtx | |
8764 | sh_dwarf_register_span (rtx reg) | |
8765 | { | |
8766 | unsigned regno = REGNO (reg); | |
8767 | ||
8768 | if (WORDS_BIG_ENDIAN || GET_MODE (reg) != DFmode) | |
8769 | return NULL_RTX; | |
8770 | ||
8771 | return | |
8772 | gen_rtx_PARALLEL (VOIDmode, | |
8773 | gen_rtvec (2, | |
3d7c0741 | 8774 | gen_rtx_REG (SFmode, regno + 1), |
8775 | gen_rtx_REG (SFmode, regno))); | |
e1190e3a | 8776 | } |
8777 | ||
3754d046 | 8778 | static machine_mode |
8779 | sh_promote_function_mode (const_tree type, machine_mode mode, | |
c596fd64 | 8780 | int *punsignedp, const_tree funtype, |
d86d3e36 | 8781 | int for_return) |
3b2411a8 | 8782 | { |
8783 | if (sh_promote_prototypes (funtype)) | |
978fcce1 | 8784 | return promote_mode (type, mode, punsignedp); |
3b2411a8 | 8785 | else |
d86d3e36 | 8786 | return default_promote_function_mode (type, mode, punsignedp, funtype, |
8787 | for_return); | |
3b2411a8 | 8788 | } |
8789 | ||
5cb06fbb | 8790 | static bool |
fb80456a | 8791 | sh_promote_prototypes (const_tree type) |
45550790 | 8792 | { |
8793 | if (TARGET_HITACHI) | |
a3b1178e | 8794 | return false; |
45550790 | 8795 | if (! type) |
a3b1178e | 8796 | return true; |
45550790 | 8797 | return ! sh_attr_renesas_p (type); |
8798 | } | |
8799 | ||
b981d932 | 8800 | /* Whether an argument must be passed by reference. On SHcompact, we |
8801 | pretend arguments wider than 32-bits that would have been passed in | |
8802 | registers are passed by reference, so that an SHmedia trampoline | |
8803 | loads them into the full 64-bits registers. */ | |
b981d932 | 8804 | static int |
3754d046 | 8805 | shcompact_byref (const CUMULATIVE_ARGS *cum, machine_mode mode, |
fb80456a | 8806 | const_tree type, bool named) |
b981d932 | 8807 | { |
8808 | unsigned HOST_WIDE_INT size; | |
8809 | ||
8810 | if (type) | |
8811 | size = int_size_in_bytes (type); | |
8812 | else | |
8813 | size = GET_MODE_SIZE (mode); | |
8814 | ||
8815 | if (cum->arg_count[SH_ARG_INT] < NPARM_REGS (SImode) | |
8816 | && (!named | |
8817 | || GET_SH_ARG_CLASS (mode) == SH_ARG_INT | |
8818 | || (GET_SH_ARG_CLASS (mode) == SH_ARG_FLOAT | |
8819 | && cum->arg_count[SH_ARG_FLOAT] >= NPARM_REGS (SFmode))) | |
8820 | && size > 4 | |
8821 | && !SHCOMPACT_FORCE_ON_STACK (mode, type) | |
8822 | && !SH5_WOULD_BE_PARTIAL_NREGS (*cum, mode, type, named)) | |
8823 | return size; | |
8824 | else | |
8825 | return 0; | |
8826 | } | |
8827 | ||
8828 | static bool | |
3754d046 | 8829 | sh_pass_by_reference (cumulative_args_t cum_v, machine_mode mode, |
fb80456a | 8830 | const_tree type, bool named) |
b981d932 | 8831 | { |
39cba157 | 8832 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); |
8833 | ||
b981d932 | 8834 | if (targetm.calls.must_pass_in_stack (mode, type)) |
8835 | return true; | |
8836 | ||
e5a89c0e | 8837 | /* ??? std_gimplify_va_arg_expr passes NULL for cum. That function |
8838 | wants to know about pass-by-reference semantics for incoming | |
8839 | arguments. */ | |
8840 | if (! cum) | |
8841 | return false; | |
8842 | ||
b981d932 | 8843 | if (TARGET_SHCOMPACT) |
8844 | { | |
8845 | cum->byref = shcompact_byref (cum, mode, type, named); | |
8846 | return cum->byref != 0; | |
8847 | } | |
8848 | ||
8849 | return false; | |
8850 | } | |
8851 | ||
13f08ee7 | 8852 | static bool |
3754d046 | 8853 | sh_callee_copies (cumulative_args_t cum, machine_mode mode, |
fb80456a | 8854 | const_tree type, bool named ATTRIBUTE_UNUSED) |
13f08ee7 | 8855 | { |
8856 | /* ??? How can it possibly be correct to return true only on the | |
8857 | caller side of the equation? Is there someplace else in the | |
8858 | sh backend that's magically producing the copies? */ | |
39cba157 | 8859 | return (get_cumulative_args (cum)->outgoing |
13f08ee7 | 8860 | && ((mode == BLKmode ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) |
8861 | % SH_MIN_ALIGN_FOR_CALLEE_COPY == 0)); | |
8862 | } | |
8863 | ||
f0a8ace1 | 8864 | /* Round a register number up to a proper boundary for an arg of mode |
8865 | MODE. | |
8866 | The SH doesn't care about double alignment, so we only | |
8867 | round doubles to even regs when asked to explicitly. */ | |
8868 | static int | |
8869 | sh_round_reg (const CUMULATIVE_ARGS& cum, machine_mode mode) | |
8870 | { | |
8871 | /* FIXME: This used to be a macro and has been copy pasted into this | |
8872 | function as is. Make this more readable. */ | |
8873 | return | |
8874 | (((TARGET_ALIGN_DOUBLE | |
8875 | || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) | |
8876 | && (mode == DFmode || mode == DCmode) | |
8877 | && cum.arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (mode))) | |
8878 | && GET_MODE_UNIT_SIZE (mode) > UNITS_PER_WORD) | |
8879 | ? (cum.arg_count[(int) GET_SH_ARG_CLASS (mode)] | |
8880 | + (cum.arg_count[(int) GET_SH_ARG_CLASS (mode)] & 1)) | |
8881 | : cum.arg_count[(int) GET_SH_ARG_CLASS (mode)]); | |
8882 | } | |
8883 | ||
8884 | /* Return true if arg of the specified mode should be be passed in a register | |
8885 | or false otherwise. */ | |
8886 | static bool | |
8887 | sh_pass_in_reg_p (const CUMULATIVE_ARGS& cum, machine_mode mode, | |
8888 | const_tree type) | |
8889 | { | |
8890 | /* FIXME: This used to be a macro and has been copy pasted into this | |
8891 | function as is. Make this more readable. */ | |
8892 | return | |
8893 | ((type == 0 | |
8894 | || (! TREE_ADDRESSABLE (type) | |
8895 | && (! (TARGET_HITACHI || cum.renesas_abi) | |
8896 | || ! (AGGREGATE_TYPE_P (type) | |
8897 | || (!TARGET_FPU_ANY | |
8898 | && (GET_MODE_CLASS (mode) == MODE_FLOAT | |
8899 | && GET_MODE_SIZE (mode) > GET_MODE_SIZE (SFmode))))))) | |
8900 | && ! cum.force_mem | |
8901 | && (TARGET_SH2E | |
8902 | ? ((mode) == BLKmode | |
8903 | ? ((cum.arg_count[(int) SH_ARG_INT] * UNITS_PER_WORD | |
8904 | + int_size_in_bytes (type)) | |
8905 | <= NPARM_REGS (SImode) * UNITS_PER_WORD) | |
8906 | : ((sh_round_reg (cum, mode) | |
8907 | + HARD_REGNO_NREGS (BASE_ARG_REG (mode), mode)) | |
8908 | <= NPARM_REGS (mode))) | |
8909 | : sh_round_reg (cum, mode) < NPARM_REGS (mode))); | |
8910 | } | |
8911 | ||
f054eb3c | 8912 | static int |
3754d046 | 8913 | sh_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode, |
f054eb3c | 8914 | tree type, bool named ATTRIBUTE_UNUSED) |
8915 | { | |
39cba157 | 8916 | CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); |
f054eb3c | 8917 | int words = 0; |
8918 | ||
8919 | if (!TARGET_SH5 | |
f0a8ace1 | 8920 | && sh_pass_in_reg_p (*cum, mode, type) |
f054eb3c | 8921 | && !(TARGET_SH4 || TARGET_SH2A_DOUBLE) |
f0a8ace1 | 8922 | && (sh_round_reg (*cum, mode) |
f054eb3c | 8923 | + (mode != BLKmode |
f0a8ace1 | 8924 | ? CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD) |
8925 | : CEIL (int_size_in_bytes (type), UNITS_PER_WORD)) | |
f054eb3c | 8926 | > NPARM_REGS (mode))) |
f0a8ace1 | 8927 | words = NPARM_REGS (mode) - sh_round_reg (*cum, mode); |
f054eb3c | 8928 | |
8929 | else if (!TARGET_SHCOMPACT | |
8930 | && SH5_WOULD_BE_PARTIAL_NREGS (*cum, mode, type, named)) | |
8931 | words = NPARM_REGS (SImode) - cum->arg_count[SH_ARG_INT]; | |
8932 | ||
8933 | return words * UNITS_PER_WORD; | |
8934 | } | |
8935 | ||
8936 | ||
45550790 | 8937 | /* Define where to put the arguments to a function. |
8938 | Value is zero to push the argument on the stack, | |
8939 | or a hard register in which to store the argument. | |
8940 | ||
8941 | MODE is the argument's machine mode. | |
8942 | TYPE is the data type of the argument (as a tree). | |
8943 | This is null for libcalls where that information may | |
8944 | not be available. | |
8945 | CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
8946 | the preceding args and about the function being called. | |
8947 | NAMED is nonzero if this argument is a named parameter | |
8948 | (otherwise it is an extra parameter matching an ellipsis). | |
8949 | ||
8950 | On SH the first args are normally in registers | |
8951 | and the rest are pushed. Any arg that starts within the first | |
8952 | NPARM_REGS words is at least partially passed in a register unless | |
8953 | its data type forbids. */ | |
a0aaaf80 | 8954 | static rtx |
3754d046 | 8955 | sh_function_arg (cumulative_args_t ca_v, machine_mode mode, |
a0aaaf80 | 8956 | const_tree type, bool named) |
45550790 | 8957 | { |
39cba157 | 8958 | CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v); |
8959 | ||
45550790 | 8960 | if (! TARGET_SH5 && mode == VOIDmode) |
8961 | return GEN_INT (ca->renesas_abi ? 1 : 0); | |
8962 | ||
8963 | if (! TARGET_SH5 | |
f0a8ace1 | 8964 | && sh_pass_in_reg_p (*ca, mode, type) |
45550790 | 8965 | && (named || ! (TARGET_HITACHI || ca->renesas_abi))) |
8966 | { | |
8967 | int regno; | |
8968 | ||
8969 | if (mode == SCmode && TARGET_SH4 && TARGET_LITTLE_ENDIAN | |
f0a8ace1 | 8970 | && (! FUNCTION_ARG_SCmode_WART || (sh_round_reg (*ca, mode) & 1))) |
45550790 | 8971 | { |
8972 | rtx r1 = gen_rtx_EXPR_LIST (VOIDmode, | |
8973 | gen_rtx_REG (SFmode, | |
8974 | BASE_ARG_REG (mode) | |
f0a8ace1 | 8975 | + (sh_round_reg (*ca, mode) ^ 1)), |
45550790 | 8976 | const0_rtx); |
d767e27e | 8977 | rtx r2 = gen_rtx_EXPR_LIST (VOIDmode, |
8978 | gen_rtx_REG (SFmode, | |
8979 | BASE_ARG_REG (mode) | |
f0a8ace1 | 8980 | + ((sh_round_reg (*ca, mode) + 1) ^ 1)), |
d767e27e | 8981 | GEN_INT (4)); |
45550790 | 8982 | return gen_rtx_PARALLEL(SCmode, gen_rtvec(2, r1, r2)); |
8983 | } | |
8984 | ||
8985 | /* If the alignment of a DF value causes an SF register to be | |
8986 | skipped, we will use that skipped register for the next SF | |
8987 | value. */ | |
8988 | if ((TARGET_HITACHI || ca->renesas_abi) | |
8989 | && ca->free_single_fp_reg | |
8990 | && mode == SFmode) | |
8991 | return gen_rtx_REG (mode, ca->free_single_fp_reg); | |
8992 | ||
f0a8ace1 | 8993 | regno = (BASE_ARG_REG (mode) + sh_round_reg (*ca, mode)) |
45550790 | 8994 | ^ (mode == SFmode && TARGET_SH4 |
c3583c9c | 8995 | && TARGET_LITTLE_ENDIAN |
45550790 | 8996 | && ! TARGET_HITACHI && ! ca->renesas_abi); |
8997 | return gen_rtx_REG (mode, regno); | |
8998 | ||
8999 | } | |
9e7454d0 | 9000 | |
45550790 | 9001 | if (TARGET_SH5) |
9002 | { | |
9003 | if (mode == VOIDmode && TARGET_SHCOMPACT) | |
9004 | return GEN_INT (ca->call_cookie); | |
9005 | ||
9006 | /* The following test assumes unnamed arguments are promoted to | |
9007 | DFmode. */ | |
9008 | if (mode == SFmode && ca->free_single_fp_reg) | |
9009 | return SH5_PROTOTYPED_FLOAT_ARG (*ca, mode, ca->free_single_fp_reg); | |
9010 | ||
9011 | if ((GET_SH_ARG_CLASS (mode) == SH_ARG_FLOAT) | |
9012 | && (named || ! ca->prototype_p) | |
9013 | && ca->arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (SFmode)) | |
9014 | { | |
9015 | if (! ca->prototype_p && TARGET_SHMEDIA) | |
9016 | return SH5_PROTOTYPELESS_FLOAT_ARG (*ca, mode); | |
9017 | ||
9018 | return SH5_PROTOTYPED_FLOAT_ARG (*ca, mode, | |
9019 | FIRST_FP_PARM_REG | |
9020 | + ca->arg_count[(int) SH_ARG_FLOAT]); | |
9021 | } | |
9022 | ||
9023 | if (ca->arg_count[(int) SH_ARG_INT] < NPARM_REGS (SImode) | |
9024 | && (! TARGET_SHCOMPACT | |
9025 | || (! SHCOMPACT_FORCE_ON_STACK (mode, type) | |
9026 | && ! SH5_WOULD_BE_PARTIAL_NREGS (*ca, mode, | |
9027 | type, named)))) | |
9028 | { | |
9029 | return gen_rtx_REG (mode, (FIRST_PARM_REG | |
9030 | + ca->arg_count[(int) SH_ARG_INT])); | |
9031 | } | |
9032 | ||
c3583c9c | 9033 | return NULL_RTX; |
45550790 | 9034 | } |
9035 | ||
c3583c9c | 9036 | return NULL_RTX; |
45550790 | 9037 | } |
9e7454d0 | 9038 | |
45550790 | 9039 | /* Update the data in CUM to advance over an argument |
9040 | of mode MODE and data type TYPE. | |
9041 | (TYPE is null for libcalls where that information may not be | |
9042 | available.) */ | |
a0aaaf80 | 9043 | static void |
3754d046 | 9044 | sh_function_arg_advance (cumulative_args_t ca_v, machine_mode mode, |
a0aaaf80 | 9045 | const_tree type, bool named) |
45550790 | 9046 | { |
39cba157 | 9047 | CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v); |
9048 | ||
d767e27e | 9049 | if (ca->force_mem) |
9050 | ca->force_mem = 0; | |
9051 | else if (TARGET_SH5) | |
9052 | { | |
a0aaaf80 | 9053 | const_tree type2 = (ca->byref && type |
9054 | ? TREE_TYPE (type) | |
9055 | : type); | |
3754d046 | 9056 | machine_mode mode2 = (ca->byref && type |
d767e27e | 9057 | ? TYPE_MODE (type2) |
9058 | : mode); | |
9059 | int dwords = ((ca->byref | |
9060 | ? ca->byref | |
9061 | : mode2 == BLKmode | |
9062 | ? int_size_in_bytes (type2) | |
9063 | : GET_MODE_SIZE (mode2)) + 7) / 8; | |
9064 | int numregs = MIN (dwords, NPARM_REGS (SImode) | |
9065 | - ca->arg_count[(int) SH_ARG_INT]); | |
9066 | ||
9067 | if (numregs) | |
9068 | { | |
9069 | ca->arg_count[(int) SH_ARG_INT] += numregs; | |
9070 | if (TARGET_SHCOMPACT | |
9071 | && SHCOMPACT_FORCE_ON_STACK (mode2, type2)) | |
9072 | { | |
9073 | ca->call_cookie | |
9074 | |= CALL_COOKIE_INT_REG (ca->arg_count[(int) SH_ARG_INT] | |
9075 | - numregs, 1); | |
9076 | /* N.B. We want this also for outgoing. */ | |
9077 | ca->stack_regs += numregs; | |
9078 | } | |
9079 | else if (ca->byref) | |
9080 | { | |
9081 | if (! ca->outgoing) | |
9082 | ca->stack_regs += numregs; | |
9083 | ca->byref_regs += numregs; | |
9084 | ca->byref = 0; | |
9085 | do | |
9086 | ca->call_cookie | |
9087 | |= CALL_COOKIE_INT_REG (ca->arg_count[(int) SH_ARG_INT] | |
9088 | - numregs, 2); | |
9089 | while (--numregs); | |
9090 | ca->call_cookie | |
9091 | |= CALL_COOKIE_INT_REG (ca->arg_count[(int) SH_ARG_INT] | |
9092 | - 1, 1); | |
9093 | } | |
9094 | else if (dwords > numregs) | |
9095 | { | |
9096 | int pushregs = numregs; | |
9097 | ||
9098 | if (TARGET_SHCOMPACT) | |
9099 | ca->stack_regs += numregs; | |
9100 | while (pushregs < NPARM_REGS (SImode) - 1 | |
9101 | && (CALL_COOKIE_INT_REG_GET | |
9102 | (ca->call_cookie, | |
9103 | NPARM_REGS (SImode) - pushregs) | |
9104 | == 1)) | |
9105 | { | |
9106 | ca->call_cookie | |
9107 | &= ~ CALL_COOKIE_INT_REG (NPARM_REGS (SImode) | |
9108 | - pushregs, 1); | |
9109 | pushregs++; | |
9110 | } | |
9111 | if (numregs == NPARM_REGS (SImode)) | |
9112 | ca->call_cookie | |
9113 | |= CALL_COOKIE_INT_REG (0, 1) | |
9114 | | CALL_COOKIE_STACKSEQ (numregs - 1); | |
9115 | else | |
9116 | ca->call_cookie | |
9117 | |= CALL_COOKIE_STACKSEQ (numregs); | |
9118 | } | |
9119 | } | |
9120 | if (GET_SH_ARG_CLASS (mode2) == SH_ARG_FLOAT | |
9121 | && (named || ! ca->prototype_p)) | |
9122 | { | |
9123 | if (mode2 == SFmode && ca->free_single_fp_reg) | |
9124 | ca->free_single_fp_reg = 0; | |
9125 | else if (ca->arg_count[(int) SH_ARG_FLOAT] | |
9126 | < NPARM_REGS (SFmode)) | |
9127 | { | |
9128 | int numfpregs | |
9129 | = MIN ((GET_MODE_SIZE (mode2) + 7) / 8 * 2, | |
9130 | NPARM_REGS (SFmode) | |
9131 | - ca->arg_count[(int) SH_ARG_FLOAT]); | |
9132 | ||
9133 | ca->arg_count[(int) SH_ARG_FLOAT] += numfpregs; | |
9134 | ||
9135 | if (TARGET_SHCOMPACT && ! ca->prototype_p) | |
9136 | { | |
9137 | if (ca->outgoing && numregs > 0) | |
9138 | do | |
9139 | { | |
9140 | ca->call_cookie | |
9141 | |= (CALL_COOKIE_INT_REG | |
9142 | (ca->arg_count[(int) SH_ARG_INT] | |
9143 | - numregs + ((numfpregs - 2) / 2), | |
9144 | 4 + (ca->arg_count[(int) SH_ARG_FLOAT] | |
9145 | - numfpregs) / 2)); | |
9146 | } | |
9147 | while (numfpregs -= 2); | |
9148 | } | |
9149 | else if (mode2 == SFmode && (named) | |
9150 | && (ca->arg_count[(int) SH_ARG_FLOAT] | |
9151 | < NPARM_REGS (SFmode))) | |
9152 | ca->free_single_fp_reg | |
9153 | = FIRST_FP_PARM_REG - numfpregs | |
9154 | + ca->arg_count[(int) SH_ARG_FLOAT] + 1; | |
9155 | } | |
9156 | } | |
9157 | return; | |
9158 | } | |
9159 | ||
9160 | if ((TARGET_HITACHI || ca->renesas_abi) && TARGET_FPU_DOUBLE) | |
9161 | { | |
9162 | /* Note that we've used the skipped register. */ | |
9163 | if (mode == SFmode && ca->free_single_fp_reg) | |
9164 | { | |
9165 | ca->free_single_fp_reg = 0; | |
9166 | return; | |
9167 | } | |
9168 | /* When we have a DF after an SF, there's an SF register that get | |
9169 | skipped in order to align the DF value. We note this skipped | |
9170 | register, because the next SF value will use it, and not the | |
9171 | SF that follows the DF. */ | |
9172 | if (mode == DFmode | |
f0a8ace1 | 9173 | && sh_round_reg (*ca, DFmode) != sh_round_reg (*ca, SFmode)) |
d767e27e | 9174 | { |
f0a8ace1 | 9175 | ca->free_single_fp_reg = (sh_round_reg (*ca, SFmode) |
d767e27e | 9176 | + BASE_ARG_REG (mode)); |
9177 | } | |
9178 | } | |
9179 | ||
7105fb72 | 9180 | if (! ((TARGET_SH4 || TARGET_SH2A) || ca->renesas_abi) |
f0a8ace1 | 9181 | || sh_pass_in_reg_p (*ca, mode, type)) |
d767e27e | 9182 | (ca->arg_count[(int) GET_SH_ARG_CLASS (mode)] |
f0a8ace1 | 9183 | = (sh_round_reg (*ca, mode) |
d767e27e | 9184 | + (mode == BLKmode |
f0a8ace1 | 9185 | ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD) |
9186 | : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD)))); | |
45550790 | 9187 | } |
9188 | ||
45550790 | 9189 | /* The Renesas calling convention doesn't quite fit into this scheme since |
9190 | the address is passed like an invisible argument, but one that is always | |
9191 | passed in memory. */ | |
9192 | static rtx | |
04f04b72 | 9193 | sh_struct_value_rtx (tree fndecl, int incoming ATTRIBUTE_UNUSED) |
45550790 | 9194 | { |
9195 | if (TARGET_HITACHI || sh_attr_renesas_p (fndecl)) | |
c3583c9c | 9196 | return NULL_RTX; |
45550790 | 9197 | return gen_rtx_REG (Pmode, 2); |
9198 | } | |
9199 | ||
5cb06fbb | 9200 | /* Worker function for TARGET_FUNCTION_VALUE. |
9201 | ||
9202 | For the SH, this is like LIBCALL_VALUE, except that we must change the | |
9203 | mode like PROMOTE_MODE does. | |
9204 | ??? PROMOTE_MODE is ignored for non-scalar types. The set of types | |
6c049e03 | 9205 | tested here has to be kept in sync with the one in |
9206 | explow.c:promote_mode. */ | |
5cb06fbb | 9207 | static rtx |
9208 | sh_function_value (const_tree valtype, | |
9209 | const_tree fn_decl_or_type, | |
9210 | bool outgoing ATTRIBUTE_UNUSED) | |
9211 | { | |
9212 | if (fn_decl_or_type | |
9213 | && !DECL_P (fn_decl_or_type)) | |
9214 | fn_decl_or_type = NULL; | |
9215 | ||
9216 | return gen_rtx_REG ( | |
9217 | ((GET_MODE_CLASS (TYPE_MODE (valtype)) == MODE_INT | |
9218 | && GET_MODE_SIZE (TYPE_MODE (valtype)) < 4 | |
9219 | && (TREE_CODE (valtype) == INTEGER_TYPE | |
9220 | || TREE_CODE (valtype) == ENUMERAL_TYPE | |
9221 | || TREE_CODE (valtype) == BOOLEAN_TYPE | |
9222 | || TREE_CODE (valtype) == REAL_TYPE | |
9223 | || TREE_CODE (valtype) == OFFSET_TYPE)) | |
9224 | && sh_promote_prototypes (fn_decl_or_type) | |
9225 | ? (TARGET_SHMEDIA64 ? DImode : SImode) : TYPE_MODE (valtype)), | |
9226 | BASE_RETURN_VALUE_REG (TYPE_MODE (valtype))); | |
9227 | } | |
9228 | ||
9229 | /* Worker function for TARGET_LIBCALL_VALUE. */ | |
5cb06fbb | 9230 | static rtx |
3754d046 | 9231 | sh_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) |
5cb06fbb | 9232 | { |
9233 | return gen_rtx_REG (mode, BASE_RETURN_VALUE_REG (mode)); | |
9234 | } | |
9235 | ||
eb9063bf | 9236 | /* Return true if N is a possible register number of function value. */ |
eb9063bf | 9237 | static bool |
5cb06fbb | 9238 | sh_function_value_regno_p (const unsigned int regno) |
9239 | { | |
9240 | return ((regno) == FIRST_RET_REG | |
9241 | || (TARGET_SH2E && (regno) == FIRST_FP_RET_REG) | |
9242 | || (TARGET_SHMEDIA_FPU && (regno) == FIRST_FP_RET_REG)); | |
9243 | } | |
9244 | ||
6644435d | 9245 | /* Worker function for TARGET_RETURN_IN_MEMORY. */ |
45550790 | 9246 | static bool |
fb80456a | 9247 | sh_return_in_memory (const_tree type, const_tree fndecl) |
45550790 | 9248 | { |
9249 | if (TARGET_SH5) | |
9250 | { | |
9251 | if (TYPE_MODE (type) == BLKmode) | |
9252 | return ((unsigned HOST_WIDE_INT) int_size_in_bytes (type)) > 8; | |
9253 | else | |
9254 | return GET_MODE_SIZE (TYPE_MODE (type)) > 8; | |
9255 | } | |
9256 | else | |
9257 | { | |
9258 | return (TYPE_MODE (type) == BLKmode | |
9259 | || ((TARGET_HITACHI || sh_attr_renesas_p (fndecl)) | |
9260 | && TREE_CODE (type) == RECORD_TYPE)); | |
9261 | } | |
9262 | } | |
9263 | ||
9264 | /* We actually emit the code in sh_expand_prologue. We used to use | |
9265 | a static variable to flag that we need to emit this code, but that | |
9266 | doesn't when inlining, when functions are deferred and then emitted | |
9267 | later. Fortunately, we already have two flags that are part of struct | |
9268 | function that tell if a function uses varargs or stdarg. */ | |
9269 | static void | |
39cba157 | 9270 | sh_setup_incoming_varargs (cumulative_args_t ca, |
3754d046 | 9271 | machine_mode mode, |
09a512b9 | 9272 | tree type, |
9273 | int *pretend_arg_size, | |
04f04b72 | 9274 | int second_time ATTRIBUTE_UNUSED) |
45550790 | 9275 | { |
18d50ae6 | 9276 | gcc_assert (cfun->stdarg); |
09a512b9 | 9277 | if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)) |
9278 | { | |
9279 | int named_parm_regs, anon_parm_regs; | |
9280 | ||
f0a8ace1 | 9281 | named_parm_regs = (sh_round_reg (*get_cumulative_args (ca), mode) |
09a512b9 | 9282 | + (mode == BLKmode |
f0a8ace1 | 9283 | ? CEIL (int_size_in_bytes (type), UNITS_PER_WORD) |
9284 | : CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD))); | |
09a512b9 | 9285 | anon_parm_regs = NPARM_REGS (SImode) - named_parm_regs; |
9286 | if (anon_parm_regs > 0) | |
9287 | *pretend_arg_size = anon_parm_regs * 4; | |
9288 | } | |
45550790 | 9289 | } |
9290 | ||
9291 | static bool | |
39cba157 | 9292 | sh_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED) |
45550790 | 9293 | { |
9294 | return TARGET_SH5; | |
9295 | } | |
9296 | ||
9297 | static bool | |
39cba157 | 9298 | sh_pretend_outgoing_varargs_named (cumulative_args_t ca_v) |
45550790 | 9299 | { |
39cba157 | 9300 | CUMULATIVE_ARGS *ca = get_cumulative_args (ca_v); |
9301 | ||
45550790 | 9302 | return ! (TARGET_HITACHI || ca->renesas_abi) && ! TARGET_SH5; |
9303 | } | |
9304 | ||
9305 | ||
97595bfd | 9306 | /* Define the offset between two registers, one to be eliminated, and |
9307 | the other its replacement, at the start of a routine. */ | |
97595bfd | 9308 | int |
04f04b72 | 9309 | initial_elimination_offset (int from, int to) |
97595bfd | 9310 | { |
9311 | int regs_saved; | |
87e19636 | 9312 | int regs_saved_rounding = 0; |
97595bfd | 9313 | int total_saved_regs_space; |
9200a51c | 9314 | int total_auto_space; |
8ded0752 | 9315 | int save_flags = target_flags; |
87e19636 | 9316 | int copy_flags; |
ed8483c0 | 9317 | HARD_REG_SET live_regs_mask; |
8af3db02 | 9318 | |
9319 | shmedia_space_reserved_for_target_registers = false; | |
ed8483c0 | 9320 | regs_saved = calc_live_regs (&live_regs_mask); |
87e19636 | 9321 | regs_saved += SHMEDIA_REGS_STACK_ADJUST (); |
8af3db02 | 9322 | |
9323 | if (shmedia_reserve_space_for_target_registers_p (regs_saved, &live_regs_mask)) | |
9324 | { | |
9325 | shmedia_space_reserved_for_target_registers = true; | |
9326 | regs_saved += shmedia_target_regs_stack_adjust (&live_regs_mask); | |
9327 | } | |
9328 | ||
87e19636 | 9329 | if (TARGET_SH5 && regs_saved % (STACK_BOUNDARY / BITS_PER_UNIT)) |
9330 | regs_saved_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT) | |
9331 | - regs_saved % (STACK_BOUNDARY / BITS_PER_UNIT)); | |
2e3d4844 | 9332 | |
87e19636 | 9333 | total_auto_space = rounded_frame_size (regs_saved) - regs_saved_rounding; |
9334 | copy_flags = target_flags; | |
8ded0752 | 9335 | target_flags = save_flags; |
b00564da | 9336 | |
87e19636 | 9337 | total_saved_regs_space = regs_saved + regs_saved_rounding; |
47c009e5 | 9338 | |
b9a602c6 | 9339 | if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) |
87e19636 | 9340 | return total_saved_regs_space + total_auto_space |
6c049e03 | 9341 | + crtl->args.info.byref_regs * 8; |
73401833 | 9342 | |
97595bfd | 9343 | if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
87e19636 | 9344 | return total_saved_regs_space + total_auto_space |
6c049e03 | 9345 | + crtl->args.info.byref_regs * 8; |
73401833 | 9346 | |
9347 | /* Initial gap between fp and sp is 0. */ | |
b9a602c6 | 9348 | if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
73401833 | 9349 | return 0; |
9350 | ||
b9a602c6 | 9351 | if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) |
9352 | return rounded_frame_size (0); | |
9353 | ||
9354 | if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) | |
9355 | return rounded_frame_size (0); | |
9356 | ||
1a6a7a27 | 9357 | gcc_assert (from == RETURN_ADDRESS_POINTER_REGNUM |
b9a602c6 | 9358 | && (to == HARD_FRAME_POINTER_REGNUM |
9359 | || to == STACK_POINTER_REGNUM)); | |
1a6a7a27 | 9360 | if (TARGET_SH5) |
acda5809 | 9361 | { |
1a6a7a27 | 9362 | int n = total_saved_regs_space; |
9363 | int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG; | |
9364 | save_schedule schedule; | |
9365 | save_entry *entry; | |
6c049e03 | 9366 | |
1a6a7a27 | 9367 | n += total_auto_space; |
6c049e03 | 9368 | |
1a6a7a27 | 9369 | /* If it wasn't saved, there's not much we can do. */ |
9370 | if (! TEST_HARD_REG_BIT (live_regs_mask, pr_reg)) | |
9371 | return n; | |
6c049e03 | 9372 | |
1a6a7a27 | 9373 | target_flags = copy_flags; |
6c049e03 | 9374 | |
1a6a7a27 | 9375 | sh5_schedule_saves (&live_regs_mask, &schedule, n); |
9376 | for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++) | |
9377 | if (entry->reg == pr_reg) | |
9378 | { | |
9379 | target_flags = save_flags; | |
9380 | return entry->offset; | |
9381 | } | |
9382 | gcc_unreachable (); | |
acda5809 | 9383 | } |
1a6a7a27 | 9384 | else |
9385 | return total_auto_space; | |
97595bfd | 9386 | } |
d47be40b | 9387 | |
9388 | /* Parse the -mfixed-range= option string. */ | |
9389 | void | |
9390 | sh_fix_range (const char *const_str) | |
9391 | { | |
9392 | int i, first, last; | |
9393 | char *str, *dash, *comma; | |
6c049e03 | 9394 | |
d47be40b | 9395 | /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and |
9396 | REG2 are either register names or register numbers. The effect | |
9397 | of this option is to mark the registers in the range from REG1 to | |
9398 | REG2 as ``fixed'' so they won't be used by the compiler. */ | |
6c049e03 | 9399 | |
d47be40b | 9400 | i = strlen (const_str); |
9401 | str = (char *) alloca (i + 1); | |
9402 | memcpy (str, const_str, i + 1); | |
6c049e03 | 9403 | |
d47be40b | 9404 | while (1) |
9405 | { | |
9406 | dash = strchr (str, '-'); | |
9407 | if (!dash) | |
9408 | { | |
9409 | warning (0, "value of -mfixed-range must have form REG1-REG2"); | |
9410 | return; | |
9411 | } | |
9412 | *dash = '\0'; | |
9413 | comma = strchr (dash + 1, ','); | |
9414 | if (comma) | |
9415 | *comma = '\0'; | |
6c049e03 | 9416 | |
d47be40b | 9417 | first = decode_reg_name (str); |
9418 | if (first < 0) | |
9419 | { | |
9420 | warning (0, "unknown register name: %s", str); | |
9421 | return; | |
9422 | } | |
6c049e03 | 9423 | |
d47be40b | 9424 | last = decode_reg_name (dash + 1); |
9425 | if (last < 0) | |
9426 | { | |
9427 | warning (0, "unknown register name: %s", dash + 1); | |
9428 | return; | |
9429 | } | |
6c049e03 | 9430 | |
d47be40b | 9431 | *dash = '-'; |
6c049e03 | 9432 | |
d47be40b | 9433 | if (first > last) |
9434 | { | |
9435 | warning (0, "%s-%s is an empty range", str, dash + 1); | |
9436 | return; | |
9437 | } | |
6c049e03 | 9438 | |
d47be40b | 9439 | for (i = first; i <= last; ++i) |
9440 | fixed_regs[i] = call_used_regs[i] = 1; | |
9441 | ||
9442 | if (!comma) | |
9443 | break; | |
9444 | ||
9445 | *comma = ','; | |
9446 | str = comma + 1; | |
9447 | } | |
9448 | } | |
73401833 | 9449 | \f |
57d5535b | 9450 | /* Insert any deferred function attributes from earlier pragmas. */ |
8ee295a7 | 9451 | static void |
04f04b72 | 9452 | sh_insert_attributes (tree node, tree *attributes) |
49f630e1 | 9453 | { |
57d5535b | 9454 | tree attrs; |
9455 | ||
9456 | if (TREE_CODE (node) != FUNCTION_DECL) | |
49f630e1 | 9457 | return; |
9458 | ||
9459 | /* We are only interested in fields. */ | |
ce45a448 | 9460 | if (!DECL_P (node)) |
49f630e1 | 9461 | return; |
9462 | ||
57d5535b | 9463 | /* Append the attributes to the deferred attributes. */ |
9464 | *sh_deferred_function_attributes_tail = *attributes; | |
9465 | attrs = sh_deferred_function_attributes; | |
9466 | if (!attrs) | |
9467 | return; | |
9468 | ||
9469 | /* Some attributes imply or require the interrupt attribute. */ | |
9470 | if (!lookup_attribute ("interrupt_handler", attrs) | |
9471 | && !lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (node))) | |
9472 | { | |
9473 | /* If we have a trapa_handler, but no interrupt_handler attribute, | |
9474 | insert an interrupt_handler attribute. */ | |
9475 | if (lookup_attribute ("trapa_handler", attrs) != NULL_TREE) | |
9476 | /* We can't use sh_pr_interrupt here because that's not in the | |
9477 | java frontend. */ | |
9478 | attrs | |
9479 | = tree_cons (get_identifier("interrupt_handler"), NULL_TREE, attrs); | |
5241f4ad | 9480 | /* However, for sp_switch, trap_exit, nosave_low_regs and resbank, |
9481 | if the interrupt attribute is missing, we ignore the attribute | |
9482 | and warn. */ | |
57d5535b | 9483 | else if (lookup_attribute ("sp_switch", attrs) |
9484 | || lookup_attribute ("trap_exit", attrs) | |
5241f4ad | 9485 | || lookup_attribute ("nosave_low_regs", attrs) |
9486 | || lookup_attribute ("resbank", attrs)) | |
57d5535b | 9487 | { |
9488 | tree *tail; | |
9489 | ||
9490 | for (tail = attributes; attrs; attrs = TREE_CHAIN (attrs)) | |
9491 | { | |
9492 | if (is_attribute_p ("sp_switch", TREE_PURPOSE (attrs)) | |
9493 | || is_attribute_p ("trap_exit", TREE_PURPOSE (attrs)) | |
5241f4ad | 9494 | || is_attribute_p ("nosave_low_regs", TREE_PURPOSE (attrs)) |
9495 | || is_attribute_p ("resbank", TREE_PURPOSE (attrs))) | |
57d5535b | 9496 | warning (OPT_Wattributes, |
67a779df | 9497 | "%qE attribute only applies to interrupt functions", |
9498 | TREE_PURPOSE (attrs)); | |
57d5535b | 9499 | else |
9500 | { | |
9501 | *tail = tree_cons (TREE_PURPOSE (attrs), NULL_TREE, | |
9502 | NULL_TREE); | |
9503 | tail = &TREE_CHAIN (*tail); | |
9504 | } | |
9505 | } | |
9506 | attrs = *attributes; | |
9507 | } | |
9508 | } | |
9509 | ||
9510 | /* Install the processed list. */ | |
9511 | *attributes = attrs; | |
9512 | ||
9513 | /* Clear deferred attributes. */ | |
9514 | sh_deferred_function_attributes = NULL_TREE; | |
9515 | sh_deferred_function_attributes_tail = &sh_deferred_function_attributes; | |
49f630e1 | 9516 | |
9517 | return; | |
9518 | } | |
9519 | ||
a89db615 | 9520 | /*------------------------------------------------------------------------------ |
db8d13f8 | 9521 | Target specific attributes |
a89db615 | 9522 | Supported attributes are: |
9523 | ||
9524 | * interrupt_handler | |
9525 | Specifies this function is an interrupt handler. | |
9526 | ||
9527 | * trapa_handler | |
9528 | Like interrupt_handler, but don't save all registers. | |
9529 | ||
9530 | * sp_switch | |
9531 | Specifies an alternate stack for an interrupt handler to run on. | |
9532 | ||
9533 | * trap_exit | |
9534 | Use a trapa to exit an interrupt function instead of rte. | |
9535 | ||
9536 | * nosave_low_regs | |
9537 | Don't save r0..r7 in an interrupt handler function. | |
9538 | This is useful on SH3* and SH4*, which have a separate set of low | |
9539 | regs for user and privileged modes. | |
9540 | This is mainly to be used for non-reentrant interrupt handlers (i.e. | |
9541 | those that run with interrupts disabled and thus can't be | |
9542 | interrupted thenselves). | |
9543 | ||
9544 | * renesas | |
9545 | Use Renesas calling/layout conventions (functions and structures). | |
9546 | ||
9547 | * resbank | |
9548 | In case of an interrupt handler function, use a register bank to | |
9549 | save registers R0-R14, MACH, MACL, GBR and PR. | |
9550 | This is available only on SH2A targets. | |
9551 | ||
9552 | * function_vector | |
9553 | Declares a function to be called using the TBR relative addressing | |
9554 | mode. Takes an argument that specifies the slot number in the table | |
9555 | where this function can be looked up by the JSR/N @@(disp8,TBR) insn. | |
45550790 | 9556 | */ |
15cb1799 | 9557 | |
5241f4ad | 9558 | /* Handle a 'resbank' attribute. */ |
9559 | static tree | |
9560 | sh_handle_resbank_handler_attribute (tree * node, tree name, | |
6c049e03 | 9561 | tree args ATTRIBUTE_UNUSED, |
9562 | int flags ATTRIBUTE_UNUSED, | |
9563 | bool * no_add_attrs) | |
5241f4ad | 9564 | { |
9565 | if (!TARGET_SH2A) | |
9566 | { | |
67a779df | 9567 | warning (OPT_Wattributes, "%qE attribute is supported only for SH2A", |
6c049e03 | 9568 | name); |
5241f4ad | 9569 | *no_add_attrs = true; |
9570 | } | |
9571 | if (TREE_CODE (*node) != FUNCTION_DECL) | |
9572 | { | |
67a779df | 9573 | warning (OPT_Wattributes, "%qE attribute only applies to functions", |
6c049e03 | 9574 | name); |
5241f4ad | 9575 | *no_add_attrs = true; |
9576 | } | |
9577 | ||
9578 | return NULL_TREE; | |
9579 | } | |
9580 | ||
e3c541f0 | 9581 | /* Handle an "interrupt_handler" attribute; arguments as in |
9582 | struct attribute_spec.handler. */ | |
9583 | static tree | |
04f04b72 | 9584 | sh_handle_interrupt_handler_attribute (tree *node, tree name, |
6c049e03 | 9585 | tree args ATTRIBUTE_UNUSED, |
9586 | int flags ATTRIBUTE_UNUSED, | |
9587 | bool *no_add_attrs) | |
e3c541f0 | 9588 | { |
9589 | if (TREE_CODE (*node) != FUNCTION_DECL) | |
15cb1799 | 9590 | { |
67a779df | 9591 | warning (OPT_Wattributes, "%qE attribute only applies to functions", |
6c049e03 | 9592 | name); |
e3c541f0 | 9593 | *no_add_attrs = true; |
15cb1799 | 9594 | } |
154b29aa | 9595 | else if (TARGET_SHCOMPACT) |
9596 | { | |
9597 | error ("attribute interrupt_handler is not compatible with -m5-compact"); | |
9598 | *no_add_attrs = true; | |
9599 | } | |
15cb1799 | 9600 | |
e3c541f0 | 9601 | return NULL_TREE; |
9602 | } | |
9603 | ||
5241f4ad | 9604 | /* Handle an 'function_vector' attribute; arguments as in |
9605 | struct attribute_spec.handler. */ | |
9606 | static tree | |
9607 | sh2a_handle_function_vector_handler_attribute (tree * node, tree name, | |
6c049e03 | 9608 | tree args ATTRIBUTE_UNUSED, |
9609 | int flags ATTRIBUTE_UNUSED, | |
9610 | bool * no_add_attrs) | |
5241f4ad | 9611 | { |
9612 | if (!TARGET_SH2A) | |
9613 | { | |
67a779df | 9614 | warning (OPT_Wattributes, "%qE attribute only applies to SH2A", |
6c049e03 | 9615 | name); |
5241f4ad | 9616 | *no_add_attrs = true; |
9617 | } | |
9618 | else if (TREE_CODE (*node) != FUNCTION_DECL) | |
9619 | { | |
67a779df | 9620 | warning (OPT_Wattributes, "%qE attribute only applies to functions", |
6c049e03 | 9621 | name); |
5241f4ad | 9622 | *no_add_attrs = true; |
9623 | } | |
9624 | else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) | |
9625 | { | |
9626 | /* The argument must be a constant integer. */ | |
9627 | warning (OPT_Wattributes, | |
6c049e03 | 9628 | "%qE attribute argument not an integer constant", |
9629 | name); | |
5241f4ad | 9630 | *no_add_attrs = true; |
9631 | } | |
9632 | else if (TREE_INT_CST_LOW (TREE_VALUE (args)) > 255) | |
9633 | { | |
9634 | /* The argument value must be between 0 to 255. */ | |
9635 | warning (OPT_Wattributes, | |
6c049e03 | 9636 | "%qE attribute argument should be between 0 to 255", |
9637 | name); | |
5241f4ad | 9638 | *no_add_attrs = true; |
9639 | } | |
9640 | return NULL_TREE; | |
9641 | } | |
9642 | ||
a3b1178e | 9643 | /* Returns true if current function has been assigned the attribute |
5241f4ad | 9644 | 'function_vector'. */ |
a3b1178e | 9645 | bool |
5241f4ad | 9646 | sh2a_is_function_vector_call (rtx x) |
9647 | { | |
9648 | if (GET_CODE (x) == SYMBOL_REF | |
9649 | && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION)) | |
9650 | { | |
9651 | tree tr = SYMBOL_REF_DECL (x); | |
9652 | ||
9653 | if (sh2a_function_vector_p (tr)) | |
a3b1178e | 9654 | return true; |
5241f4ad | 9655 | } |
9656 | ||
a3b1178e | 9657 | return false; |
5241f4ad | 9658 | } |
9659 | ||
851d9296 | 9660 | /* Returns the function vector number, if the attribute |
5241f4ad | 9661 | 'function_vector' is assigned, otherwise returns zero. */ |
9662 | int | |
9663 | sh2a_get_function_vector_number (rtx x) | |
9664 | { | |
9665 | int num; | |
9666 | tree list, t; | |
9667 | ||
9668 | if ((GET_CODE (x) == SYMBOL_REF) | |
9669 | && (SYMBOL_REF_FLAGS (x) & SYMBOL_FLAG_FUNCVEC_FUNCTION)) | |
9670 | { | |
9671 | t = SYMBOL_REF_DECL (x); | |
9672 | ||
9673 | if (TREE_CODE (t) != FUNCTION_DECL) | |
6c049e03 | 9674 | return 0; |
5241f4ad | 9675 | |
9676 | list = SH_ATTRIBUTES (t); | |
9677 | while (list) | |
6c049e03 | 9678 | { |
9679 | if (is_attribute_p ("function_vector", TREE_PURPOSE (list))) | |
9680 | { | |
9681 | num = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (list))); | |
9682 | return num; | |
9683 | } | |
5241f4ad | 9684 | |
6c049e03 | 9685 | list = TREE_CHAIN (list); |
9686 | } | |
5241f4ad | 9687 | |
9688 | return 0; | |
9689 | } | |
9690 | else | |
9691 | return 0; | |
9692 | } | |
9693 | ||
e3c541f0 | 9694 | /* Handle an "sp_switch" attribute; arguments as in |
9695 | struct attribute_spec.handler. */ | |
9696 | static tree | |
04f04b72 | 9697 | sh_handle_sp_switch_attribute (tree *node, tree name, tree args, |
9698 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) | |
e3c541f0 | 9699 | { |
9700 | if (TREE_CODE (*node) != FUNCTION_DECL) | |
9701 | { | |
67a779df | 9702 | warning (OPT_Wattributes, "%qE attribute only applies to functions", |
9703 | name); | |
e3c541f0 | 9704 | *no_add_attrs = true; |
9705 | } | |
e3c541f0 | 9706 | else if (TREE_CODE (TREE_VALUE (args)) != STRING_CST) |
9707 | { | |
15cb1799 | 9708 | /* The argument must be a constant string. */ |
67a779df | 9709 | warning (OPT_Wattributes, "%qE attribute argument not a string constant", |
9710 | name); | |
e3c541f0 | 9711 | *no_add_attrs = true; |
9712 | } | |
15cb1799 | 9713 | |
e3c541f0 | 9714 | return NULL_TREE; |
9715 | } | |
9716 | ||
9717 | /* Handle an "trap_exit" attribute; arguments as in | |
9718 | struct attribute_spec.handler. */ | |
9719 | static tree | |
04f04b72 | 9720 | sh_handle_trap_exit_attribute (tree *node, tree name, tree args, |
9721 | int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) | |
e3c541f0 | 9722 | { |
9723 | if (TREE_CODE (*node) != FUNCTION_DECL) | |
9724 | { | |
67a779df | 9725 | warning (OPT_Wattributes, "%qE attribute only applies to functions", |
9726 | name); | |
e3c541f0 | 9727 | *no_add_attrs = true; |
9728 | } | |
57d5535b | 9729 | /* The argument specifies a trap number to be used in a trapa instruction |
9730 | at function exit (instead of an rte instruction). */ | |
e3c541f0 | 9731 | else if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST) |
9732 | { | |
15cb1799 | 9733 | /* The argument must be a constant integer. */ |
67a779df | 9734 | warning (OPT_Wattributes, "%qE attribute argument not an " |
9735 | "integer constant", name); | |
e3c541f0 | 9736 | *no_add_attrs = true; |
9737 | } | |
b7dbbdb2 | 9738 | |
e3c541f0 | 9739 | return NULL_TREE; |
15cb1799 | 9740 | } |
9741 | ||
45550790 | 9742 | static tree |
04f04b72 | 9743 | sh_handle_renesas_attribute (tree *node ATTRIBUTE_UNUSED, |
9744 | tree name ATTRIBUTE_UNUSED, | |
9745 | tree args ATTRIBUTE_UNUSED, | |
9746 | int flags ATTRIBUTE_UNUSED, | |
9747 | bool *no_add_attrs ATTRIBUTE_UNUSED) | |
45550790 | 9748 | { |
9749 | return NULL_TREE; | |
9750 | } | |
9751 | ||
9752 | /* True if __attribute__((renesas)) or -mrenesas. */ | |
a3b1178e | 9753 | bool |
fb80456a | 9754 | sh_attr_renesas_p (const_tree td) |
45550790 | 9755 | { |
9756 | if (TARGET_HITACHI) | |
a3b1178e | 9757 | return true; |
c3583c9c | 9758 | if (td == NULL_TREE) |
a3b1178e | 9759 | return false; |
45550790 | 9760 | if (DECL_P (td)) |
9761 | td = TREE_TYPE (td); | |
faffb001 | 9762 | if (td == error_mark_node) |
a3b1178e | 9763 | return false; |
45550790 | 9764 | return (lookup_attribute ("renesas", TYPE_ATTRIBUTES (td)) |
9765 | != NULL_TREE); | |
9766 | } | |
9767 | ||
9768 | /* True if __attribute__((renesas)) or -mrenesas, for the current | |
9769 | function. */ | |
a3b1178e | 9770 | bool |
04f04b72 | 9771 | sh_cfun_attr_renesas_p (void) |
45550790 | 9772 | { |
9773 | return sh_attr_renesas_p (current_function_decl); | |
9774 | } | |
9775 | ||
6c049e03 | 9776 | /* Returns true if the current function has the "interrupt_handler" |
9777 | attribute set. */ | |
a3b1178e | 9778 | bool |
04f04b72 | 9779 | sh_cfun_interrupt_handler_p (void) |
5df3d11f | 9780 | { |
9781 | return (lookup_attribute ("interrupt_handler", | |
9782 | DECL_ATTRIBUTES (current_function_decl)) | |
9783 | != NULL_TREE); | |
9784 | } | |
133479bd | 9785 | |
a3b1178e | 9786 | /* Returns true if FUNC has been assigned the attribute |
5241f4ad | 9787 | "function_vector". */ |
a3b1178e | 9788 | bool |
5241f4ad | 9789 | sh2a_function_vector_p (tree func) |
9790 | { | |
9791 | tree list; | |
9792 | if (TREE_CODE (func) != FUNCTION_DECL) | |
a3b1178e | 9793 | return false; |
5241f4ad | 9794 | |
9795 | list = SH_ATTRIBUTES (func); | |
9796 | while (list) | |
9797 | { | |
9798 | if (is_attribute_p ("function_vector", TREE_PURPOSE (list))) | |
6c049e03 | 9799 | return true; |
5241f4ad | 9800 | |
9801 | list = TREE_CHAIN (list); | |
9802 | } | |
a3b1178e | 9803 | return false; |
5241f4ad | 9804 | } |
9805 | ||
6c049e03 | 9806 | /* Returns true if given tree has the "resbank" attribute set. */ |
a3b1178e | 9807 | bool |
5241f4ad | 9808 | sh_cfun_resbank_handler_p (void) |
9809 | { | |
9810 | return ((lookup_attribute ("resbank", | |
6c049e03 | 9811 | DECL_ATTRIBUTES (current_function_decl)) |
9812 | != NULL_TREE) | |
9813 | && (lookup_attribute ("interrupt_handler", | |
9814 | DECL_ATTRIBUTES (current_function_decl)) | |
9815 | != NULL_TREE) && TARGET_SH2A); | |
5241f4ad | 9816 | } |
9817 | ||
c8378feb | 9818 | /* Returns true if the current function has a "trap_exit" attribute set. */ |
c8378feb | 9819 | bool |
9820 | sh_cfun_trap_exit_p (void) | |
9821 | { | |
9822 | return lookup_attribute ("trap_exit", DECL_ATTRIBUTES (current_function_decl)) | |
9823 | != NULL_TREE; | |
9824 | } | |
9825 | ||
761d9126 | 9826 | /* Implement TARGET_CHECK_PCH_TARGET_FLAGS. */ |
761d9126 | 9827 | static const char * |
9828 | sh_check_pch_target_flags (int old_flags) | |
9829 | { | |
156fac8b | 9830 | if ((old_flags ^ target_flags) & (MASK_SH1 | MASK_SH2 | MASK_SH3 |
9831 | | MASK_SH_E | MASK_HARD_SH4 | |
9832 | | MASK_FPU_SINGLE | MASK_SH4)) | |
9833 | return _("created and used with different architectures / ABIs"); | |
9834 | if ((old_flags ^ target_flags) & MASK_HITACHI) | |
9835 | return _("created and used with different ABIs"); | |
9836 | if ((old_flags ^ target_flags) & MASK_LITTLE_ENDIAN) | |
9837 | return _("created and used with different endianness"); | |
133479bd | 9838 | return NULL; |
133479bd | 9839 | } |
97595bfd | 9840 | \f |
73401833 | 9841 | /* Predicates used by the templates. */ |
97595bfd | 9842 | |
a3b1178e | 9843 | /* Returns true if OP is MACL, MACH or PR. The input must be a REG rtx. |
73401833 | 9844 | Used only in general_movsrc_operand. */ |
a3b1178e | 9845 | bool |
3754d046 | 9846 | system_reg_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED) |
97595bfd | 9847 | { |
73401833 | 9848 | switch (REGNO (op)) |
97595bfd | 9849 | { |
73401833 | 9850 | case PR_REG: |
9851 | case MACL_REG: | |
9852 | case MACH_REG: | |
a3b1178e | 9853 | return true; |
97595bfd | 9854 | } |
a3b1178e | 9855 | return false; |
97595bfd | 9856 | } |
97595bfd | 9857 | |
a3b1178e | 9858 | /* Returns true if OP is a floating point value with value 0.0. */ |
a3b1178e | 9859 | bool |
04f04b72 | 9860 | fp_zero_operand (rtx op) |
f3d93547 | 9861 | { |
b00564da | 9862 | REAL_VALUE_TYPE r; |
f3d93547 | 9863 | |
b00564da | 9864 | if (GET_MODE (op) != SFmode) |
a3b1178e | 9865 | return false; |
b00564da | 9866 | |
9867 | REAL_VALUE_FROM_CONST_DOUBLE (r, op); | |
e6c94d0d | 9868 | return REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r); |
f3d93547 | 9869 | } |
9870 | ||
a3b1178e | 9871 | /* Returns true if OP is a floating point value with value 1.0. */ |
a3b1178e | 9872 | bool |
04f04b72 | 9873 | fp_one_operand (rtx op) |
f3d93547 | 9874 | { |
b00564da | 9875 | REAL_VALUE_TYPE r; |
9876 | ||
9877 | if (GET_MODE (op) != SFmode) | |
a3b1178e | 9878 | return false; |
b00564da | 9879 | |
9880 | REAL_VALUE_FROM_CONST_DOUBLE (r, op); | |
9881 | return REAL_VALUES_EQUAL (r, dconst1); | |
f3d93547 | 9882 | } |
8ded0752 | 9883 | |
6c049e03 | 9884 | /* Return the TLS type for TLS symbols. */ |
bc620c5c | 9885 | enum tls_model |
3754d046 | 9886 | tls_symbolic_operand (rtx op, machine_mode mode ATTRIBUTE_UNUSED) |
cec78553 | 9887 | { |
cec78553 | 9888 | if (GET_CODE (op) != SYMBOL_REF) |
bc620c5c | 9889 | return TLS_MODEL_NONE; |
2fb8cf90 | 9890 | return SYMBOL_REF_TLS_MODEL (op); |
cec78553 | 9891 | } |
8ded0752 | 9892 | \f |
9eaab178 | 9893 | /* Return the destination address of a branch. */ |
b7dbbdb2 | 9894 | static int |
04f04b72 | 9895 | branch_dest (rtx branch) |
8ded0752 | 9896 | { |
9eaab178 | 9897 | rtx dest = SET_SRC (PATTERN (branch)); |
9898 | int dest_uid; | |
8ded0752 | 9899 | |
9900 | if (GET_CODE (dest) == IF_THEN_ELSE) | |
9901 | dest = XEXP (dest, 1); | |
9902 | dest = XEXP (dest, 0); | |
9903 | dest_uid = INSN_UID (dest); | |
47fc0706 | 9904 | return INSN_ADDRESSES (dest_uid); |
8ded0752 | 9905 | } |
72bccaaa | 9906 | \f |
808a491c | 9907 | /* Return nonzero if REG is not used after INSN. |
72bccaaa | 9908 | We assume REG is a reload reg, and therefore does |
e020b473 | 9909 | not live past labels. It may live past calls or jumps though. */ |
a3b1178e | 9910 | bool |
91a55c11 | 9911 | reg_unused_after (rtx reg, rtx_insn *insn) |
72bccaaa | 9912 | { |
0f7bb88e | 9913 | enum rtx_code code; |
72bccaaa | 9914 | rtx set; |
9915 | ||
9916 | /* If the reg is set by this instruction, then it is safe for our | |
9917 | case. Disregard the case where this is a store to memory, since | |
9918 | we are checking a register used in the store address. */ | |
9919 | set = single_set (insn); | |
cbb16986 | 9920 | if (set && !MEM_P (SET_DEST (set)) |
72bccaaa | 9921 | && reg_overlap_mentioned_p (reg, SET_DEST (set))) |
a3b1178e | 9922 | return true; |
72bccaaa | 9923 | |
b7dbbdb2 | 9924 | while ((insn = NEXT_INSN (insn))) |
72bccaaa | 9925 | { |
6720e96c | 9926 | rtx set; |
9927 | if (!INSN_P (insn)) | |
9928 | continue; | |
9929 | ||
72bccaaa | 9930 | code = GET_CODE (insn); |
0f7bb88e | 9931 | |
87faf2d3 | 9932 | #if 0 |
9933 | /* If this is a label that existed before reload, then the register | |
7a288fec | 9934 | is dead here. However, if this is a label added by reorg, then |
87faf2d3 | 9935 | the register may still be live here. We can't tell the difference, |
9936 | so we just ignore labels completely. */ | |
0f7bb88e | 9937 | if (code == CODE_LABEL) |
72bccaaa | 9938 | return 1; |
87faf2d3 | 9939 | /* else */ |
9940 | #endif | |
72bccaaa | 9941 | |
e020b473 | 9942 | if (code == JUMP_INSN) |
a3b1178e | 9943 | return false; |
e020b473 | 9944 | |
0f7bb88e | 9945 | /* If this is a sequence, we must handle them all at once. |
9946 | We could have for instance a call that sets the target register, | |
ebb11c7b | 9947 | and an insn in a delay slot that uses the register. In this case, |
0f7bb88e | 9948 | we must return 0. */ |
e020b473 | 9949 | else if (code == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE) |
72bccaaa | 9950 | { |
50fc2d35 | 9951 | rtx_sequence *seq = as_a <rtx_sequence *> (PATTERN (insn)); |
0f7bb88e | 9952 | int i; |
9953 | int retval = 0; | |
9954 | ||
50fc2d35 | 9955 | for (i = 0; i < seq->len (); i++) |
0f7bb88e | 9956 | { |
50fc2d35 | 9957 | rtx_insn *this_insn = seq->insn (i); |
0f7bb88e | 9958 | rtx set = single_set (this_insn); |
9959 | ||
cbb16986 | 9960 | if (CALL_P (this_insn)) |
0f7bb88e | 9961 | code = CALL_INSN; |
cbb16986 | 9962 | else if (JUMP_P (this_insn)) |
fafe466d | 9963 | { |
9964 | if (INSN_ANNULLED_BRANCH_P (this_insn)) | |
a3b1178e | 9965 | return false; |
fafe466d | 9966 | code = JUMP_INSN; |
9967 | } | |
72bccaaa | 9968 | |
0f7bb88e | 9969 | if (set && reg_overlap_mentioned_p (reg, SET_SRC (set))) |
a3b1178e | 9970 | return false; |
0f7bb88e | 9971 | if (set && reg_overlap_mentioned_p (reg, SET_DEST (set))) |
9972 | { | |
cbb16986 | 9973 | if (!MEM_P (SET_DEST (set))) |
a3b1178e | 9974 | retval = true; |
0f7bb88e | 9975 | else |
a3b1178e | 9976 | return false; |
0f7bb88e | 9977 | } |
c3583c9c | 9978 | if (set == NULL_RTX |
0f7bb88e | 9979 | && reg_overlap_mentioned_p (reg, PATTERN (this_insn))) |
a3b1178e | 9980 | return false; |
0f7bb88e | 9981 | } |
9982 | if (retval == 1) | |
a3b1178e | 9983 | return true; |
fafe466d | 9984 | else if (code == JUMP_INSN) |
a3b1178e | 9985 | return false; |
0f7bb88e | 9986 | } |
72bccaaa | 9987 | |
6720e96c | 9988 | set = single_set (insn); |
9989 | if (set && reg_overlap_mentioned_p (reg, SET_SRC (set))) | |
a3b1178e | 9990 | return false; |
6720e96c | 9991 | if (set && reg_overlap_mentioned_p (reg, SET_DEST (set))) |
cbb16986 | 9992 | return !MEM_P (SET_DEST (set)); |
6720e96c | 9993 | if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn))) |
a3b1178e | 9994 | return false; |
0f7bb88e | 9995 | |
956dd562 | 9996 | if (code == CALL_INSN && call_really_used_regs[REGNO (reg)]) |
a3b1178e | 9997 | return true; |
72bccaaa | 9998 | } |
a3b1178e | 9999 | return true; |
72bccaaa | 10000 | } |
1b61190c | 10001 | \f |
26576132 | 10002 | #include "ggc.h" |
1b61190c | 10003 | |
a6be7821 | 10004 | static GTY(()) rtx t_reg_rtx; |
10005 | rtx | |
10006 | get_t_reg_rtx (void) | |
10007 | { | |
10008 | if (! t_reg_rtx) | |
10009 | t_reg_rtx = gen_rtx_REG (SImode, T_REG); | |
10010 | return t_reg_rtx; | |
10011 | } | |
10012 | ||
37430745 | 10013 | static GTY(()) tree fpscr_values; |
10014 | ||
10015 | static void | |
10016 | emit_fpu_switch (rtx scratch, int index) | |
10017 | { | |
10018 | rtx dst, src; | |
10019 | ||
10020 | if (fpscr_values == NULL) | |
10021 | { | |
10022 | tree t; | |
10023 | ||
10024 | t = build_index_type (integer_one_node); | |
10025 | t = build_array_type (integer_type_node, t); | |
54e46243 | 10026 | t = build_decl (BUILTINS_LOCATION, |
10027 | VAR_DECL, get_identifier ("__fpscr_values"), t); | |
37430745 | 10028 | DECL_ARTIFICIAL (t) = 1; |
10029 | DECL_IGNORED_P (t) = 1; | |
10030 | DECL_EXTERNAL (t) = 1; | |
10031 | TREE_STATIC (t) = 1; | |
f0d1c8d5 | 10032 | TREE_PUBLIC (t) = 1; |
37430745 | 10033 | TREE_USED (t) = 1; |
10034 | ||
10035 | fpscr_values = t; | |
10036 | } | |
10037 | ||
10038 | src = DECL_RTL (fpscr_values); | |
e1ba4a27 | 10039 | if (!can_create_pseudo_p ()) |
37430745 | 10040 | { |
10041 | emit_move_insn (scratch, XEXP (src, 0)); | |
10042 | if (index != 0) | |
10043 | emit_insn (gen_addsi3 (scratch, scratch, GEN_INT (index * 4))); | |
81298240 | 10044 | src = adjust_automodify_address (src, SImode, scratch, index * 4); |
37430745 | 10045 | } |
10046 | else | |
81298240 | 10047 | src = adjust_address (src, SImode, index * 4); |
37430745 | 10048 | |
81298240 | 10049 | emit_insn (gen_lds_fpscr (src)); |
37430745 | 10050 | } |
1b61190c | 10051 | \f |
04f04b72 | 10052 | static rtx get_free_reg (HARD_REG_SET); |
18862b5a | 10053 | |
10054 | /* This function returns a register to use to load the address to load | |
10055 | the fpscr from. Currently it always returns r1 or r7, but when we are | |
10056 | able to use pseudo registers after combine, or have a better mechanism | |
10057 | for choosing a register, it should be done here. */ | |
10058 | /* REGS_LIVE is the liveness information for the point for which we | |
10059 | need this allocation. In some bare-bones exit blocks, r1 is live at the | |
10060 | start. We can even have all of r0..r3 being live: | |
10061 | __complex__ long long f (double d) { if (d == 0) return 2; else return 3; } | |
10062 | INSN before which new insns are placed with will clobber the register | |
10063 | we return. If a basic block consists only of setting the return value | |
10064 | register to a pseudo and using that register, the return value is not | |
10065 | live before or after this block, yet we we'll insert our insns right in | |
10066 | the middle. */ | |
18862b5a | 10067 | static rtx |
04f04b72 | 10068 | get_free_reg (HARD_REG_SET regs_live) |
1b61190c | 10069 | { |
18862b5a | 10070 | if (! TEST_HARD_REG_BIT (regs_live, 1)) |
10071 | return gen_rtx_REG (Pmode, 1); | |
1b61190c | 10072 | |
ed5527ca | 10073 | /* Hard reg 1 is live; since this is a small register classes target, |
18862b5a | 10074 | there shouldn't be anything but a jump before the function end. */ |
1a6a7a27 | 10075 | gcc_assert (!TEST_HARD_REG_BIT (regs_live, 7)); |
10076 | return gen_rtx_REG (Pmode, 7); | |
18862b5a | 10077 | } |
1b61190c | 10078 | |
9e7454d0 | 10079 | /* This function will set the fpscr from memory. |
18862b5a | 10080 | MODE is the mode we are setting it to. */ |
10081 | void | |
04f04b72 | 10082 | fpscr_set_from_mem (int mode, HARD_REG_SET regs_live) |
18862b5a | 10083 | { |
bc620c5c | 10084 | enum attr_fp_mode fp_mode = (enum attr_fp_mode) mode; |
37430745 | 10085 | enum attr_fp_mode norm_mode = ACTUAL_NORMAL_MODE (FP_MODE); |
395df746 | 10086 | rtx addr_reg; |
18862b5a | 10087 | |
e1ba4a27 | 10088 | addr_reg = !can_create_pseudo_p () ? get_free_reg (regs_live) : NULL_RTX; |
37430745 | 10089 | emit_fpu_switch (addr_reg, fp_mode == norm_mode); |
1b61190c | 10090 | } |
2522e445 | 10091 | |
10092 | /* Is the given character a logical line separator for the assembler? */ | |
10093 | #ifndef IS_ASM_LOGICAL_LINE_SEPARATOR | |
0cb73417 | 10094 | #define IS_ASM_LOGICAL_LINE_SEPARATOR(C, STR) ((C) == ';') |
2522e445 | 10095 | #endif |
10096 | ||
66bbc864 | 10097 | static bool |
91a55c11 | 10098 | sequence_insn_p (rtx_insn *insn) |
66bbc864 | 10099 | { |
b82334f7 | 10100 | rtx_insn *prev, *next; |
66bbc864 | 10101 | |
10102 | prev = PREV_INSN (insn); | |
10103 | if (prev == NULL) | |
10104 | return false; | |
10105 | ||
10106 | next = NEXT_INSN (prev); | |
10107 | if (next == NULL) | |
10108 | return false; | |
10109 | ||
c53274a5 | 10110 | return INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE; |
66bbc864 | 10111 | } |
10112 | ||
2522e445 | 10113 | int |
b82334f7 | 10114 | sh_insn_length_adjustment (rtx_insn *insn) |
2522e445 | 10115 | { |
10116 | /* Instructions with unfilled delay slots take up an extra two bytes for | |
10117 | the nop in the delay slot. */ | |
cbb16986 | 10118 | if (((NONJUMP_INSN_P (insn) |
e3fac27d | 10119 | && GET_CODE (PATTERN (insn)) != USE |
10120 | && GET_CODE (PATTERN (insn)) != CLOBBER) | |
91f71fa3 | 10121 | || CALL_P (insn) || JUMP_P (insn)) |
66bbc864 | 10122 | && ! sequence_insn_p (insn) |
2522e445 | 10123 | && get_attr_needs_delay_slot (insn) == NEEDS_DELAY_SLOT_YES) |
10124 | return 2; | |
10125 | ||
87ed74ef | 10126 | /* SH2e has a bug that prevents the use of annulled branches, so if |
10127 | the delay slot is not filled, we'll have to put a NOP in it. */ | |
6f2543f8 | 10128 | if (sh_cpu_attr == CPU_SH2E |
91f71fa3 | 10129 | && JUMP_P (insn) |
87ed74ef | 10130 | && get_attr_type (insn) == TYPE_CBRANCH |
66bbc864 | 10131 | && ! sequence_insn_p (insn)) |
87ed74ef | 10132 | return 2; |
10133 | ||
2522e445 | 10134 | /* sh-dsp parallel processing insn take four bytes instead of two. */ |
9e7454d0 | 10135 | |
cbb16986 | 10136 | if (NONJUMP_INSN_P (insn)) |
2522e445 | 10137 | { |
10138 | int sum = 0; | |
10139 | rtx body = PATTERN (insn); | |
8deb3959 | 10140 | const char *templ; |
5e20801c | 10141 | char c; |
c3583c9c | 10142 | bool maybe_label = true; |
2522e445 | 10143 | |
10144 | if (GET_CODE (body) == ASM_INPUT) | |
8deb3959 | 10145 | templ = XSTR (body, 0); |
2522e445 | 10146 | else if (asm_noperands (body) >= 0) |
8deb3959 | 10147 | templ |
796e4476 | 10148 | = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); |
2522e445 | 10149 | else |
10150 | return 0; | |
10151 | do | |
10152 | { | |
10153 | int ppi_adjust = 0; | |
10154 | ||
10155 | do | |
8deb3959 | 10156 | c = *templ++; |
2522e445 | 10157 | while (c == ' ' || c == '\t'); |
10158 | /* all sh-dsp parallel-processing insns start with p. | |
10159 | The only non-ppi sh insn starting with p is pref. | |
10160 | The only ppi starting with pr is prnd. */ | |
8deb3959 | 10161 | if ((c == 'p' || c == 'P') && strncasecmp ("re", templ, 2)) |
2522e445 | 10162 | ppi_adjust = 2; |
10163 | /* The repeat pseudo-insn expands two three insns, a total of | |
10164 | six bytes in size. */ | |
10165 | else if ((c == 'r' || c == 'R') | |
8deb3959 | 10166 | && ! strncasecmp ("epeat", templ, 5)) |
2522e445 | 10167 | ppi_adjust = 4; |
0cb73417 | 10168 | while (c && c != '\n' |
8deb3959 | 10169 | && ! IS_ASM_LOGICAL_LINE_SEPARATOR (c, templ)) |
2522e445 | 10170 | { |
10171 | /* If this is a label, it is obviously not a ppi insn. */ | |
10172 | if (c == ':' && maybe_label) | |
10173 | { | |
10174 | ppi_adjust = 0; | |
10175 | break; | |
10176 | } | |
10177 | else if (c == '\'' || c == '"') | |
c3583c9c | 10178 | maybe_label = false; |
8deb3959 | 10179 | c = *templ++; |
2522e445 | 10180 | } |
10181 | sum += ppi_adjust; | |
10182 | maybe_label = c != ':'; | |
10183 | } | |
10184 | while (c); | |
10185 | return sum; | |
10186 | } | |
10187 | return 0; | |
10188 | } | |
0abf894c | 10189 | \f |
36fa166c | 10190 | /* Return TRUE for a valid displacement for the REG+disp addressing |
10191 | with MODE. */ | |
36fa166c | 10192 | bool |
3754d046 | 10193 | sh_legitimate_index_p (machine_mode mode, rtx op, bool consider_sh2a, |
51bc6b40 | 10194 | bool allow_zero) |
36fa166c | 10195 | { |
00868707 | 10196 | if (! CONST_INT_P (op)) |
10197 | return false; | |
36fa166c | 10198 | |
00868707 | 10199 | if (TARGET_SHMEDIA) |
10200 | { | |
10201 | int size; | |
36fa166c | 10202 | |
00868707 | 10203 | /* Check if this is the address of an unaligned load / store. */ |
10204 | if (mode == VOIDmode) | |
05aca90b | 10205 | return satisfies_constraint_I06 (op); |
36fa166c | 10206 | |
00868707 | 10207 | size = GET_MODE_SIZE (mode); |
10208 | return (!(INTVAL (op) & (size - 1)) | |
10209 | && INTVAL (op) >= -512 * size | |
10210 | && INTVAL (op) < 512 * size); | |
10211 | } | |
10212 | else | |
10213 | { | |
10214 | const HOST_WIDE_INT offset = INTVAL (op); | |
9db63610 | 10215 | const int max_disp = sh_max_mov_insn_displacement (mode, consider_sh2a); |
51bc6b40 | 10216 | const int align_mask = mov_insn_alignment_mask (mode, consider_sh2a); |
89cace00 | 10217 | |
00868707 | 10218 | /* If the mode does not support any displacement always return false. |
10219 | Even though an index of '0' is actually always valid, it will cause | |
10220 | troubles when e.g. a DFmode move is split into two SFmode moves, | |
10221 | where one SFmode move will have index '0' and the other move will | |
10222 | have index '4'. */ | |
51bc6b40 | 10223 | if (!allow_zero && max_disp < 1) |
00868707 | 10224 | return false; |
36fa166c | 10225 | |
00868707 | 10226 | return offset >= 0 && offset <= max_disp && (offset & align_mask) == 0; |
36fa166c | 10227 | } |
36fa166c | 10228 | } |
10229 | ||
10230 | /* Recognize an RTL expression that is a valid memory address for | |
10231 | an instruction. | |
10232 | The MODE argument is the machine mode for the MEM expression | |
10233 | that wants to use this address. | |
10234 | Allow REG | |
10235 | REG+disp | |
10236 | REG+r0 | |
10237 | REG++ | |
3ea038fc | 10238 | --REG |
10239 | GBR | |
10240 | GBR+disp */ | |
eeabeacf | 10241 | static bool |
3754d046 | 10242 | sh_legitimate_address_p (machine_mode mode, rtx x, bool strict) |
36fa166c | 10243 | { |
3a51c3c9 | 10244 | if (! ALLOW_INDEXED_ADDRESS |
10245 | && GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1))) | |
10246 | return false; | |
10247 | ||
3ea038fc | 10248 | if (REG_P (x) && REGNO (x) == GBR_REG) |
10249 | return true; | |
10250 | ||
36fa166c | 10251 | if (MAYBE_BASE_REGISTER_RTX_P (x, strict)) |
10252 | return true; | |
10253 | else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) | |
10254 | && ! TARGET_SHMEDIA | |
10255 | && MAYBE_BASE_REGISTER_RTX_P (XEXP (x, 0), strict)) | |
10256 | return true; | |
81298240 | 10257 | else if (GET_CODE (x) == PLUS) |
36fa166c | 10258 | { |
10259 | rtx xop0 = XEXP (x, 0); | |
10260 | rtx xop1 = XEXP (x, 1); | |
10261 | ||
3ea038fc | 10262 | if (REG_P (xop0) && REGNO (xop0) == GBR_REG) |
10263 | return gbr_displacement (xop1, mode); | |
10264 | ||
36fa166c | 10265 | if (GET_MODE_SIZE (mode) <= 8 |
10266 | && MAYBE_BASE_REGISTER_RTX_P (xop0, strict) | |
51bc6b40 | 10267 | && sh_legitimate_index_p (mode, xop1, TARGET_SH2A, false)) |
36fa166c | 10268 | return true; |
10269 | ||
10270 | if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode | |
10271 | || ((xop0 == stack_pointer_rtx | |
10272 | || xop0 == hard_frame_pointer_rtx) | |
10273 | && REG_P (xop1) && REGNO (xop1) == R0_REG) | |
10274 | || ((xop1 == stack_pointer_rtx | |
10275 | || xop1 == hard_frame_pointer_rtx) | |
10276 | && REG_P (xop0) && REGNO (xop0) == R0_REG)) | |
10277 | && ((!TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 4) | |
10278 | || (TARGET_SHMEDIA && GET_MODE_SIZE (mode) <= 8) | |
10279 | || ((TARGET_SH4 || TARGET_SH2A_DOUBLE) | |
10280 | && TARGET_FMOVD && mode == DFmode))) | |
10281 | { | |
10282 | if (MAYBE_BASE_REGISTER_RTX_P (xop1, strict) | |
10283 | && MAYBE_INDEX_REGISTER_RTX_P (xop0, strict)) | |
10284 | return true; | |
10285 | if (MAYBE_INDEX_REGISTER_RTX_P (xop1, strict) | |
10286 | && MAYBE_BASE_REGISTER_RTX_P (xop0, strict)) | |
10287 | return true; | |
10288 | } | |
10289 | } | |
10290 | ||
10291 | return false; | |
10292 | } | |
10293 | \f | |
55e0f12f | 10294 | /* Return TRUE if X references a SYMBOL_REF or LABEL_REF whose symbol |
10295 | isn't protected by a PIC unspec. */ | |
a3b1178e | 10296 | bool |
04f04b72 | 10297 | nonpic_symbol_mentioned_p (rtx x) |
0abf894c | 10298 | { |
a3b1178e | 10299 | const char *fmt; |
10300 | int i; | |
0abf894c | 10301 | |
87e19636 | 10302 | if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF |
10303 | || GET_CODE (x) == PC) | |
a3b1178e | 10304 | return true; |
0abf894c | 10305 | |
87e19636 | 10306 | /* We don't want to look into the possible MEM location of a |
10307 | CONST_DOUBLE, since we're not going to use it, in general. */ | |
10308 | if (GET_CODE (x) == CONST_DOUBLE) | |
a3b1178e | 10309 | return false; |
87e19636 | 10310 | |
0abf894c | 10311 | if (GET_CODE (x) == UNSPEC |
a5bd34f1 | 10312 | && (XINT (x, 1) == UNSPEC_PIC |
10313 | || XINT (x, 1) == UNSPEC_GOT | |
10314 | || XINT (x, 1) == UNSPEC_GOTOFF | |
87e19636 | 10315 | || XINT (x, 1) == UNSPEC_GOTPLT |
cec78553 | 10316 | || XINT (x, 1) == UNSPEC_GOTTPOFF |
10317 | || XINT (x, 1) == UNSPEC_DTPOFF | |
1cdf9df5 | 10318 | || XINT (x, 1) == UNSPEC_TPOFF |
20ba855a | 10319 | || XINT (x, 1) == UNSPEC_PLT |
10320 | || XINT (x, 1) == UNSPEC_SYMOFF | |
10321 | || XINT (x, 1) == UNSPEC_PCREL_SYMOFF)) | |
a3b1178e | 10322 | return false; |
0abf894c | 10323 | |
10324 | fmt = GET_RTX_FORMAT (GET_CODE (x)); | |
10325 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) | |
10326 | { | |
10327 | if (fmt[i] == 'E') | |
10328 | { | |
a3b1178e | 10329 | int j; |
0abf894c | 10330 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) |
10331 | if (nonpic_symbol_mentioned_p (XVECEXP (x, i, j))) | |
a3b1178e | 10332 | return true; |
0abf894c | 10333 | } |
10334 | else if (fmt[i] == 'e' && nonpic_symbol_mentioned_p (XEXP (x, i))) | |
a3b1178e | 10335 | return true; |
0abf894c | 10336 | } |
10337 | ||
a3b1178e | 10338 | return false; |
0abf894c | 10339 | } |
10340 | ||
10341 | /* Convert a non-PIC address in `orig' to a PIC address using @GOT or | |
9df03d69 | 10342 | @GOTOFF in `reg'. */ |
0abf894c | 10343 | rtx |
3754d046 | 10344 | legitimize_pic_address (rtx orig, machine_mode mode ATTRIBUTE_UNUSED, |
04f04b72 | 10345 | rtx reg) |
0abf894c | 10346 | { |
bc620c5c | 10347 | if (tls_symbolic_operand (orig, Pmode) != TLS_MODEL_NONE) |
cec78553 | 10348 | return orig; |
10349 | ||
0abf894c | 10350 | if (GET_CODE (orig) == LABEL_REF |
2fb8cf90 | 10351 | || (GET_CODE (orig) == SYMBOL_REF && SYMBOL_REF_LOCAL_P (orig))) |
0abf894c | 10352 | { |
c3583c9c | 10353 | if (reg == NULL_RTX) |
0abf894c | 10354 | reg = gen_reg_rtx (Pmode); |
10355 | ||
10356 | emit_insn (gen_symGOTOFF2reg (reg, orig)); | |
10357 | return reg; | |
10358 | } | |
10359 | else if (GET_CODE (orig) == SYMBOL_REF) | |
10360 | { | |
c3583c9c | 10361 | if (reg == NULL_RTX) |
0abf894c | 10362 | reg = gen_reg_rtx (Pmode); |
10363 | ||
10364 | emit_insn (gen_symGOT2reg (reg, orig)); | |
10365 | return reg; | |
10366 | } | |
10367 | return orig; | |
10368 | } | |
ecf6ff7c | 10369 | |
fa9db843 | 10370 | /* Given a (logical) mode size and an offset in bytes, try to find a the |
10371 | appropriate displacement value for a mov insn. On SH the displacements | |
10372 | are limited to max. 60 bytes for SImode, max. 30 bytes in HImode and max. | |
10373 | 15 bytes in QImode. To compensate this we create a new base address by | |
10374 | adding an adjustment value to it. | |
10375 | ||
10376 | If the originally requested offset is greater than 127 we prefer using | |
10377 | values 124..127 over 128..131 to increase opportunities to use the | |
10378 | add #imm, Rn insn. | |
10379 | ||
10380 | In some cases it is possible that a requested offset might seem unaligned | |
10381 | or inappropriate for the mode size, like offset = 2 and mode size = 4. | |
10382 | This is compensated by adjusting the base address so that the effective | |
10383 | address of the displacement move insn will be aligned. | |
10384 | ||
10385 | This is not the best possible way of rebasing the base address, as it | |
10386 | does not look at other present displacement addressings around it. | |
10387 | In some cases this can create more base address adjustments than would | |
10388 | actually be necessary. */ | |
fa9db843 | 10389 | struct disp_adjust |
10390 | { | |
10391 | rtx offset_adjust; | |
10392 | rtx mov_disp; | |
fa9db843 | 10393 | }; |
10394 | ||
10395 | static struct disp_adjust | |
3754d046 | 10396 | sh_find_mov_disp_adjust (machine_mode mode, HOST_WIDE_INT offset) |
fa9db843 | 10397 | { |
00868707 | 10398 | struct disp_adjust res = { NULL_RTX, NULL_RTX }; |
fa9db843 | 10399 | |
00868707 | 10400 | /* Do not try to use SH2A's large displacements here, because this would |
10401 | effectively disable the small displacement insns. */ | |
10402 | const int mode_sz = GET_MODE_SIZE (mode); | |
10403 | const int mov_insn_sz = mov_insn_size (mode, false); | |
9db63610 | 10404 | const int max_disp = sh_max_mov_insn_displacement (mode, false); |
00868707 | 10405 | const int max_disp_next = max_disp + mov_insn_sz; |
10406 | HOST_WIDE_INT align_modifier = offset > 127 ? mov_insn_sz : 0; | |
fa9db843 | 10407 | HOST_WIDE_INT offset_adjust; |
41e3a0c7 | 10408 | |
fa9db843 | 10409 | /* In some cases this actually does happen and we must check for it. */ |
00868707 | 10410 | if (mode_sz < 1 || mode_sz > 8 || max_disp < 1) |
fa9db843 | 10411 | return res; |
10412 | ||
fa9db843 | 10413 | /* Keeps the previous behavior for QImode displacement addressing. |
10414 | This just decides how the offset is re-based. Removing this special | |
10415 | case will result in slightly bigger code on average, but it's not that | |
10416 | bad actually. */ | |
00868707 | 10417 | if (mov_insn_sz == 1) |
fa9db843 | 10418 | align_modifier = 0; |
10419 | ||
fa9db843 | 10420 | offset_adjust = ((offset + align_modifier) & ~max_disp) - align_modifier; |
10421 | ||
00868707 | 10422 | if (mode_sz + offset - offset_adjust <= max_disp_next) |
fa9db843 | 10423 | { |
10424 | res.offset_adjust = GEN_INT (offset_adjust); | |
10425 | res.mov_disp = GEN_INT (offset - offset_adjust); | |
10426 | } | |
10427 | ||
10428 | return res; | |
10429 | } | |
10430 | ||
10431 | /* Try to modify an illegitimate address and make it legitimate. | |
10432 | If we find one, return the new, valid address. | |
10433 | Otherwise, return the original address. */ | |
41e3a0c7 | 10434 | static rtx |
3754d046 | 10435 | sh_legitimize_address (rtx x, rtx oldx, machine_mode mode) |
41e3a0c7 | 10436 | { |
10437 | if (flag_pic) | |
10438 | x = legitimize_pic_address (oldx, mode, NULL_RTX); | |
10439 | ||
fa9db843 | 10440 | if (TARGET_SHMEDIA) |
10441 | return x; | |
41e3a0c7 | 10442 | |
fa9db843 | 10443 | if (((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) |
10444 | || (TARGET_SH2E && mode == SFmode)) | |
10445 | return x; | |
41e3a0c7 | 10446 | |
fa9db843 | 10447 | if (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) |
10448 | && BASE_REGISTER_RTX_P (XEXP (x, 0))) | |
89cace00 | 10449 | { |
00868707 | 10450 | struct disp_adjust adj = sh_find_mov_disp_adjust (mode, |
fa9db843 | 10451 | INTVAL (XEXP (x, 1))); |
10452 | ||
10453 | if (adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX) | |
89cace00 | 10454 | { |
10455 | rtx sum = expand_binop (Pmode, add_optab, XEXP (x, 0), | |
fa9db843 | 10456 | adj.offset_adjust, NULL_RTX, 0, |
10457 | OPTAB_LIB_WIDEN); | |
10458 | return gen_rtx_PLUS (Pmode, sum, adj.mov_disp); | |
89cace00 | 10459 | } |
10460 | } | |
41e3a0c7 | 10461 | return x; |
10462 | } | |
10463 | ||
fa9db843 | 10464 | /* Attempt to replace *p, which is an address that needs reloading, with |
299fa1f5 | 10465 | a valid memory address for an operand of mode MODE. |
10466 | Like for sh_legitimize_address, for the SH we try to get a normal form | |
10467 | of the address. That will allow inheritance of the address reloads. */ | |
299fa1f5 | 10468 | bool |
3754d046 | 10469 | sh_legitimize_reload_address (rtx *p, machine_mode mode, int opnum, |
299fa1f5 | 10470 | int itype) |
10471 | { | |
10472 | enum reload_type type = (enum reload_type) itype; | |
fa9db843 | 10473 | const int mode_sz = GET_MODE_SIZE (mode); |
299fa1f5 | 10474 | |
3a51c3c9 | 10475 | if (! ALLOW_INDEXED_ADDRESS |
10476 | && GET_CODE (*p) == PLUS | |
10477 | && REG_P (XEXP (*p, 0)) && REG_P (XEXP (*p, 1))) | |
10478 | { | |
10479 | *p = copy_rtx (*p); | |
10480 | push_reload (*p, NULL_RTX, p, NULL, | |
10481 | BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); | |
10482 | return true; | |
10483 | } | |
10484 | ||
10485 | if (! ALLOW_INDEXED_ADDRESS | |
10486 | && GET_CODE (*p) == PLUS | |
10487 | && GET_CODE (XEXP (*p, 0)) == PLUS) | |
10488 | { | |
10489 | rtx sum = gen_rtx_PLUS (Pmode, XEXP (XEXP (*p, 0), 0), | |
10490 | XEXP (XEXP (*p, 0), 1)); | |
10491 | *p = gen_rtx_PLUS (Pmode, sum, XEXP (*p, 1)); | |
10492 | push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL, | |
10493 | BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); | |
10494 | return true; | |
10495 | } | |
10496 | ||
fa9db843 | 10497 | if (TARGET_SHMEDIA) |
10498 | return false; | |
10499 | ||
10500 | if (GET_CODE (*p) == PLUS && CONST_INT_P (XEXP (*p, 1)) | |
c011be89 | 10501 | && MAYBE_BASE_REGISTER_RTX_P (XEXP (*p, 0), true) |
299fa1f5 | 10502 | && (ALLOW_INDEXED_ADDRESS |
10503 | || XEXP (*p, 0) == stack_pointer_rtx | |
10504 | || XEXP (*p, 0) == hard_frame_pointer_rtx)) | |
10505 | { | |
fa9db843 | 10506 | const HOST_WIDE_INT offset = INTVAL (XEXP (*p, 1)); |
00868707 | 10507 | struct disp_adjust adj = sh_find_mov_disp_adjust (mode, offset); |
299fa1f5 | 10508 | |
10509 | if (TARGET_SH2A && mode == DFmode && (offset & 0x7)) | |
10510 | { | |
10511 | push_reload (*p, NULL_RTX, p, NULL, | |
10512 | BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); | |
fa9db843 | 10513 | return true; |
299fa1f5 | 10514 | } |
fa9db843 | 10515 | |
299fa1f5 | 10516 | if (TARGET_SH2E && mode == SFmode) |
10517 | { | |
10518 | *p = copy_rtx (*p); | |
10519 | push_reload (*p, NULL_RTX, p, NULL, | |
10520 | BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); | |
fa9db843 | 10521 | return true; |
299fa1f5 | 10522 | } |
fa9db843 | 10523 | |
10524 | /* FIXME: Do not allow to legitimize QImode and HImode displacement | |
10525 | moves because then reload has a problem figuring the constraint | |
10526 | that the move insn target/source reg must be R0. | |
10527 | Or maybe some handling is wrong in sh_secondary_reload for this | |
10528 | to work properly? */ | |
10529 | if ((mode_sz == 4 || mode_sz == 8) | |
10530 | && ! (TARGET_SH4 && mode == DFmode) | |
10531 | && adj.offset_adjust != NULL_RTX && adj.mov_disp != NULL_RTX) | |
10532 | { | |
10533 | rtx sum = gen_rtx_PLUS (Pmode, XEXP (*p, 0), adj.offset_adjust); | |
10534 | *p = gen_rtx_PLUS (Pmode, sum, adj.mov_disp); | |
299fa1f5 | 10535 | push_reload (sum, NULL_RTX, &XEXP (*p, 0), NULL, |
10536 | BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); | |
fa9db843 | 10537 | return true; |
299fa1f5 | 10538 | } |
10539 | } | |
fa9db843 | 10540 | |
299fa1f5 | 10541 | /* We must re-recognize what we created before. */ |
fa9db843 | 10542 | if (GET_CODE (*p) == PLUS |
10543 | && (mode_sz == 4 || mode_sz == 8) | |
10544 | && GET_CODE (XEXP (*p, 0)) == PLUS | |
10545 | && CONST_INT_P (XEXP (XEXP (*p, 0), 1)) | |
10546 | && MAYBE_BASE_REGISTER_RTX_P (XEXP (XEXP (*p, 0), 0), true) | |
10547 | && CONST_INT_P (XEXP (*p, 1)) | |
10548 | && ! (TARGET_SH2E && mode == SFmode)) | |
299fa1f5 | 10549 | { |
10550 | /* Because this address is so complex, we know it must have | |
10551 | been created by LEGITIMIZE_RELOAD_ADDRESS before; thus, | |
10552 | it is already unshared, and needs no further unsharing. */ | |
10553 | push_reload (XEXP (*p, 0), NULL_RTX, &XEXP (*p, 0), NULL, | |
10554 | BASE_REG_CLASS, Pmode, VOIDmode, 0, 0, opnum, type); | |
fa9db843 | 10555 | return true; |
299fa1f5 | 10556 | } |
10557 | ||
10558 | return false; | |
299fa1f5 | 10559 | } |
10560 | ||
ac562325 | 10561 | /* In the name of slightly smaller debug output, and to cater to |
10562 | general assembler lossage, recognize various UNSPEC sequences | |
10563 | and turn them back into a direct symbol reference. */ | |
ac562325 | 10564 | static rtx |
10565 | sh_delegitimize_address (rtx orig_x) | |
10566 | { | |
10567 | rtx x, y; | |
10568 | ||
10569 | orig_x = delegitimize_mem_from_attrs (orig_x); | |
10570 | ||
10571 | x = orig_x; | |
10572 | if (MEM_P (x)) | |
10573 | x = XEXP (x, 0); | |
10574 | if (GET_CODE (x) == CONST) | |
10575 | { | |
10576 | y = XEXP (x, 0); | |
10577 | if (GET_CODE (y) == UNSPEC) | |
10578 | { | |
10579 | if (XINT (y, 1) == UNSPEC_GOT | |
ebd1f2ea | 10580 | || XINT (y, 1) == UNSPEC_GOTOFF |
10581 | || XINT (y, 1) == UNSPEC_SYMOFF) | |
ac562325 | 10582 | return XVECEXP (y, 0, 0); |
ebd1f2ea | 10583 | else if (XINT (y, 1) == UNSPEC_PCREL_SYMOFF) |
10584 | { | |
10585 | if (GET_CODE (XVECEXP (y, 0, 0)) == CONST) | |
10586 | { | |
10587 | rtx symplt = XEXP (XVECEXP (y, 0, 0), 0); | |
10588 | ||
10589 | if (GET_CODE (symplt) == UNSPEC | |
10590 | && XINT (symplt, 1) == UNSPEC_PLT) | |
10591 | return XVECEXP (symplt, 0, 0); | |
10592 | } | |
10593 | } | |
ac562325 | 10594 | else if (TARGET_SHMEDIA |
10595 | && (XINT (y, 1) == UNSPEC_EXTRACT_S16 | |
10596 | || XINT (y, 1) == UNSPEC_EXTRACT_U16)) | |
10597 | { | |
10598 | rtx offset = XVECEXP (y, 0, 1); | |
10599 | ||
10600 | x = gen_rtx_PLUS (Pmode, XVECEXP (y, 0, 0), offset); | |
10601 | if (MEM_P (orig_x)) | |
10602 | x = replace_equiv_address_nv (orig_x, x); | |
10603 | return x; | |
10604 | } | |
10605 | } | |
10606 | } | |
10607 | ||
10608 | return orig_x; | |
10609 | } | |
10610 | ||
ecf6ff7c | 10611 | /* Mark the use of a constant in the literal table. If the constant |
10612 | has multiple labels, make it unique. */ | |
e3fac27d | 10613 | static rtx |
04f04b72 | 10614 | mark_constant_pool_use (rtx x) |
ecf6ff7c | 10615 | { |
91a55c11 | 10616 | rtx_insn *insn, *lab; |
10617 | rtx pattern; | |
ecf6ff7c | 10618 | |
c3583c9c | 10619 | if (x == NULL_RTX) |
ecf6ff7c | 10620 | return x; |
10621 | ||
10622 | switch (GET_CODE (x)) | |
10623 | { | |
10624 | case LABEL_REF: | |
10625 | x = XEXP (x, 0); | |
10626 | case CODE_LABEL: | |
10627 | break; | |
10628 | default: | |
10629 | return x; | |
10630 | } | |
10631 | ||
10632 | /* Get the first label in the list of labels for the same constant | |
10633 | and delete another labels in the list. */ | |
91a55c11 | 10634 | lab = as_a <rtx_insn *> (x); |
10635 | for (insn = PREV_INSN (lab); insn; insn = PREV_INSN (insn)) | |
ecf6ff7c | 10636 | { |
cbb16986 | 10637 | if (!LABEL_P (insn) |
ecf6ff7c | 10638 | || LABEL_REFS (insn) != NEXT_INSN (insn)) |
10639 | break; | |
10640 | lab = insn; | |
10641 | } | |
10642 | ||
91a55c11 | 10643 | for (rtx insn = LABEL_REFS (lab); insn; insn = LABEL_REFS (insn)) |
dd1286fb | 10644 | as_a<rtx_insn *> (insn)->set_deleted (); |
ecf6ff7c | 10645 | |
10646 | /* Mark constants in a window. */ | |
91a55c11 | 10647 | for (insn = NEXT_INSN (as_a <rtx_insn *> (x)); insn; insn = NEXT_INSN (insn)) |
ecf6ff7c | 10648 | { |
cbb16986 | 10649 | if (!NONJUMP_INSN_P (insn)) |
ecf6ff7c | 10650 | continue; |
10651 | ||
10652 | pattern = PATTERN (insn); | |
10653 | if (GET_CODE (pattern) != UNSPEC_VOLATILE) | |
10654 | continue; | |
10655 | ||
10656 | switch (XINT (pattern, 1)) | |
10657 | { | |
10658 | case UNSPECV_CONST2: | |
10659 | case UNSPECV_CONST4: | |
10660 | case UNSPECV_CONST8: | |
10661 | XVECEXP (pattern, 0, 1) = const1_rtx; | |
10662 | break; | |
10663 | case UNSPECV_WINDOW_END: | |
10664 | if (XVECEXP (pattern, 0, 0) == x) | |
10665 | return lab; | |
10666 | break; | |
10667 | case UNSPECV_CONST_END: | |
10668 | return lab; | |
10669 | default: | |
10670 | break; | |
10671 | } | |
10672 | } | |
10673 | ||
10674 | return lab; | |
10675 | } | |
e95ebfe0 | 10676 | \f |
10677 | /* Return true if it's possible to redirect BRANCH1 to the destination | |
10678 | of an unconditional jump BRANCH2. We only want to do this if the | |
10679 | resulting branch will have a short displacement. */ | |
a3b1178e | 10680 | bool |
91a55c11 | 10681 | sh_can_redirect_branch (rtx_insn *branch1, rtx_insn *branch2) |
e95ebfe0 | 10682 | { |
10683 | if (flag_expensive_optimizations && simplejump_p (branch2)) | |
10684 | { | |
10685 | rtx dest = XEXP (SET_SRC (single_set (branch2)), 0); | |
b82334f7 | 10686 | rtx_insn *insn; |
e95ebfe0 | 10687 | int distance; |
9e7454d0 | 10688 | |
10689 | for (distance = 0, insn = NEXT_INSN (branch1); | |
10690 | insn && distance < 256; | |
e95ebfe0 | 10691 | insn = PREV_INSN (insn)) |
10692 | { | |
9e7454d0 | 10693 | if (insn == dest) |
a3b1178e | 10694 | return true; |
e95ebfe0 | 10695 | else |
10696 | distance += get_attr_length (insn); | |
10697 | } | |
9e7454d0 | 10698 | for (distance = 0, insn = NEXT_INSN (branch1); |
10699 | insn && distance < 256; | |
e95ebfe0 | 10700 | insn = NEXT_INSN (insn)) |
10701 | { | |
9e7454d0 | 10702 | if (insn == dest) |
a3b1178e | 10703 | return true; |
e95ebfe0 | 10704 | else |
10705 | distance += get_attr_length (insn); | |
10706 | } | |
10707 | } | |
a3b1178e | 10708 | return false; |
e95ebfe0 | 10709 | } |
10710 | ||
808a491c | 10711 | /* Return nonzero if register old_reg can be renamed to register new_reg. */ |
a3b1178e | 10712 | bool |
04f04b72 | 10713 | sh_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED, |
10714 | unsigned int new_reg) | |
c67138a9 | 10715 | { |
d767e27e | 10716 | /* Interrupt functions can only use registers that have already been |
10717 | saved by the prologue, even if they would normally be | |
10718 | call-clobbered. */ | |
3072d30e | 10719 | if (sh_cfun_interrupt_handler_p () && !df_regs_ever_live_p (new_reg)) |
a3b1178e | 10720 | return false; |
c67138a9 | 10721 | |
a3b1178e | 10722 | return true; |
c67138a9 | 10723 | } |
10724 | ||
83b35a61 | 10725 | /* Function to update the integer COST |
747af5e7 | 10726 | based on the relationship between INSN that is dependent on |
10727 | DEP_INSN through the dependence LINK. The default is to make no | |
10728 | adjustment to COST. This can be used for example to specify to | |
10729 | the scheduler that an output- or anti-dependence does not incur | |
83b35a61 | 10730 | the same cost as a data-dependence. The return value should be |
10731 | the new value for COST. */ | |
747af5e7 | 10732 | static int |
18282db0 | 10733 | sh_adjust_cost (rtx_insn *insn, rtx link ATTRIBUTE_UNUSED, |
10734 | rtx_insn *dep_insn, int cost) | |
747af5e7 | 10735 | { |
ab55c58f | 10736 | rtx reg, use_pat; |
747af5e7 | 10737 | |
dca8af3e | 10738 | if (TARGET_SHMEDIA) |
10739 | { | |
10740 | /* On SHmedia, if the dependence is an anti-dependence or | |
ada8cf8b | 10741 | output-dependence, there is no cost. */ |
dca8af3e | 10742 | if (REG_NOTE_KIND (link) != 0) |
59312820 | 10743 | { |
10744 | /* However, dependencies between target register loads and | |
10745 | uses of the register in a subsequent block that are separated | |
10746 | by a conditional branch are not modelled - we have to do with | |
10747 | the anti-dependency between the target register load and the | |
10748 | conditional branch that ends the current block. */ | |
10749 | if (REG_NOTE_KIND (link) == REG_DEP_ANTI | |
10750 | && GET_CODE (PATTERN (dep_insn)) == SET | |
10751 | && (get_attr_type (dep_insn) == TYPE_PT_MEDIA | |
10752 | || get_attr_type (dep_insn) == TYPE_PTABS_MEDIA) | |
10753 | && get_attr_type (insn) == TYPE_CBRANCH_MEDIA) | |
10754 | { | |
10755 | int orig_cost = cost; | |
10756 | rtx note = find_reg_note (insn, REG_BR_PROB, 0); | |
9eb946de | 10757 | rtx target = ((!note || XINT (note, 0) * 2 < REG_BR_PROB_BASE) |
59312820 | 10758 | ? insn : JUMP_LABEL (insn)); |
10759 | /* On the likely path, the branch costs 1, on the unlikely path, | |
10760 | it costs 3. */ | |
10761 | cost--; | |
10762 | do | |
10763 | target = next_active_insn (target); | |
10764 | while (target && ! flow_dependent_p (target, dep_insn) | |
10765 | && --cost > 0); | |
10766 | /* If two branches are executed in immediate succession, with the | |
10767 | first branch properly predicted, this causes a stall at the | |
10768 | second branch, hence we won't need the target for the | |
10769 | second branch for two cycles after the launch of the first | |
10770 | branch. */ | |
10771 | if (cost > orig_cost - 2) | |
10772 | cost = orig_cost - 2; | |
10773 | } | |
10774 | else | |
10775 | cost = 0; | |
10776 | } | |
dca8af3e | 10777 | |
59312820 | 10778 | else if (get_attr_is_mac_media (insn) |
10779 | && get_attr_is_mac_media (dep_insn)) | |
10780 | cost = 1; | |
10781 | ||
10782 | else if (! reload_completed | |
10783 | && GET_CODE (PATTERN (insn)) == SET | |
10784 | && GET_CODE (SET_SRC (PATTERN (insn))) == FLOAT | |
10785 | && GET_CODE (PATTERN (dep_insn)) == SET | |
10786 | && fp_arith_reg_operand (SET_SRC (PATTERN (dep_insn)), VOIDmode) | |
10787 | && cost < 4) | |
10788 | cost = 4; | |
10789 | /* Schedule the ptabs for a casesi_jump_media in preference to stuff | |
10790 | that is needed at the target. */ | |
10791 | else if (get_attr_type (insn) == TYPE_JUMP_MEDIA | |
10792 | && ! flow_dependent_p (insn, dep_insn)) | |
10793 | cost--; | |
dca8af3e | 10794 | } |
ab55c58f | 10795 | else if (REG_NOTE_KIND (link) == 0) |
747af5e7 | 10796 | { |
5be30882 | 10797 | enum attr_type type; |
10798 | rtx dep_set; | |
ab55c58f | 10799 | |
10800 | if (recog_memoized (insn) < 0 | |
10801 | || recog_memoized (dep_insn) < 0) | |
83b35a61 | 10802 | return cost; |
ab55c58f | 10803 | |
5be30882 | 10804 | dep_set = single_set (dep_insn); |
ab55c58f | 10805 | |
5be30882 | 10806 | /* The latency that we specify in the scheduling description refers |
10807 | to the actual output, not to an auto-increment register; for that, | |
10808 | the latency is one. */ | |
10809 | if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1) | |
10810 | { | |
10811 | rtx set = single_set (insn); | |
10812 | ||
10813 | if (set | |
10814 | && !reg_mentioned_p (SET_DEST (dep_set), SET_SRC (set)) | |
10815 | && (!MEM_P (SET_DEST (set)) | |
10816 | || !reg_mentioned_p (SET_DEST (dep_set), | |
10817 | XEXP (SET_DEST (set), 0)))) | |
10818 | cost = 1; | |
10819 | } | |
747af5e7 | 10820 | /* The only input for a call that is timing-critical is the |
10821 | function's address. */ | |
cbb16986 | 10822 | if (CALL_P (insn)) |
ab55c58f | 10823 | { |
cf7fb72d | 10824 | rtx call = get_call_rtx_from (insn); |
10825 | if (call | |
59312820 | 10826 | /* sibcalli_thunk uses a symbol_ref in an unspec. */ |
10827 | && (GET_CODE (XEXP (XEXP (call, 0), 0)) == UNSPEC | |
10828 | || ! reg_set_p (XEXP (XEXP (call, 0), 0), dep_insn))) | |
5be30882 | 10829 | cost -= TARGET_SH4_300 ? 3 : 6; |
ab55c58f | 10830 | } |
747af5e7 | 10831 | /* Likewise, the most timing critical input for an sfuncs call |
10832 | is the function address. However, sfuncs typically start | |
10833 | using their arguments pretty quickly. | |
5be30882 | 10834 | Assume a four cycle delay for SH4 before they are needed. |
10835 | Cached ST40-300 calls are quicker, so assume only a one | |
10836 | cycle delay there. | |
10837 | ??? Maybe we should encode the delays till input registers | |
10838 | are needed by sfuncs into the sfunc call insn. */ | |
ab55c58f | 10839 | /* All sfunc calls are parallels with at least four components. |
10840 | Exploit this to avoid unnecessary calls to sfunc_uses_reg. */ | |
10841 | else if (GET_CODE (PATTERN (insn)) == PARALLEL | |
10842 | && XVECLEN (PATTERN (insn), 0) >= 4 | |
10843 | && (reg = sfunc_uses_reg (insn))) | |
10844 | { | |
10845 | if (! reg_set_p (reg, dep_insn)) | |
5be30882 | 10846 | cost -= TARGET_SH4_300 ? 1 : 4; |
10847 | } | |
10848 | if (TARGET_HARD_SH4 && !TARGET_SH4_300) | |
10849 | { | |
10850 | enum attr_type dep_type = get_attr_type (dep_insn); | |
10851 | ||
10852 | if (dep_type == TYPE_FLOAD || dep_type == TYPE_PCFLOAD) | |
10853 | cost--; | |
10854 | else if ((dep_type == TYPE_LOAD_SI || dep_type == TYPE_PCLOAD_SI) | |
10855 | && (type = get_attr_type (insn)) != TYPE_CALL | |
10856 | && type != TYPE_SFUNC) | |
10857 | cost--; | |
10858 | /* When the preceding instruction loads the shift amount of | |
10859 | the following SHAD/SHLD, the latency of the load is increased | |
10860 | by 1 cycle. */ | |
10861 | if (get_attr_type (insn) == TYPE_DYN_SHIFT | |
10862 | && get_attr_any_int_load (dep_insn) == ANY_INT_LOAD_YES | |
99971c03 | 10863 | && reg_overlap_mentioned_p (SET_DEST (dep_set), |
5be30882 | 10864 | XEXP (SET_SRC (single_set (insn)), |
10865 | 1))) | |
10866 | cost++; | |
10867 | /* When an LS group instruction with a latency of less than | |
10868 | 3 cycles is followed by a double-precision floating-point | |
10869 | instruction, FIPR, or FTRV, the latency of the first | |
10870 | instruction is increased to 3 cycles. */ | |
10871 | else if (cost < 3 | |
10872 | && get_attr_insn_class (dep_insn) == INSN_CLASS_LS_GROUP | |
10873 | && get_attr_dfp_comp (insn) == DFP_COMP_YES) | |
10874 | cost = 3; | |
10875 | /* The lsw register of a double-precision computation is ready one | |
10876 | cycle earlier. */ | |
10877 | else if (reload_completed | |
10878 | && get_attr_dfp_comp (dep_insn) == DFP_COMP_YES | |
10879 | && (use_pat = single_set (insn)) | |
10880 | && ! regno_use_in (REGNO (SET_DEST (single_set (dep_insn))), | |
10881 | SET_SRC (use_pat))) | |
10882 | cost -= 1; | |
10883 | ||
10884 | if (get_attr_any_fp_comp (dep_insn) == ANY_FP_COMP_YES | |
10885 | && get_attr_late_fp_use (insn) == LATE_FP_USE_YES) | |
10886 | cost -= 1; | |
10887 | } | |
10888 | else if (TARGET_SH4_300) | |
10889 | { | |
10890 | /* Stores need their input register two cycles later. */ | |
10891 | if (dep_set && cost >= 1 | |
10892 | && ((type = get_attr_type (insn)) == TYPE_STORE | |
10893 | || type == TYPE_PSTORE | |
10894 | || type == TYPE_FSTORE || type == TYPE_MAC_MEM)) | |
10895 | { | |
10896 | rtx set = single_set (insn); | |
10897 | ||
10898 | if (!reg_mentioned_p (SET_SRC (set), XEXP (SET_DEST (set), 0)) | |
10899 | && rtx_equal_p (SET_SRC (set), SET_DEST (dep_set))) | |
10900 | { | |
10901 | cost -= 2; | |
10902 | /* But don't reduce the cost below 1 if the address depends | |
10903 | on a side effect of dep_insn. */ | |
10904 | if (cost < 1 | |
10905 | && modified_in_p (XEXP (SET_DEST (set), 0), dep_insn)) | |
10906 | cost = 1; | |
10907 | } | |
10908 | } | |
10909 | } | |
ab55c58f | 10910 | } |
10911 | /* An anti-dependence penalty of two applies if the first insn is a double | |
10912 | precision fadd / fsub / fmul. */ | |
5be30882 | 10913 | else if (!TARGET_SH4_300 |
10914 | && REG_NOTE_KIND (link) == REG_DEP_ANTI | |
ab55c58f | 10915 | && recog_memoized (dep_insn) >= 0 |
5be30882 | 10916 | && (get_attr_type (dep_insn) == TYPE_DFP_ARITH |
10917 | || get_attr_type (dep_insn) == TYPE_DFP_MUL) | |
ab55c58f | 10918 | /* A lot of alleged anti-flow dependences are fake, |
10919 | so check this one is real. */ | |
10920 | && flow_dependent_p (dep_insn, insn)) | |
747af5e7 | 10921 | cost = 2; |
ab55c58f | 10922 | |
747af5e7 | 10923 | return cost; |
10924 | } | |
476444cc | 10925 | |
ab55c58f | 10926 | /* Check if INSN is flow-dependent on DEP_INSN. Can also be used to check |
10927 | if DEP_INSN is anti-flow dependent on INSN. */ | |
a3b1178e | 10928 | static bool |
04f04b72 | 10929 | flow_dependent_p (rtx insn, rtx dep_insn) |
ab55c58f | 10930 | { |
10931 | rtx tmp = PATTERN (insn); | |
10932 | ||
10933 | note_stores (PATTERN (dep_insn), flow_dependent_p_1, &tmp); | |
10934 | return tmp == NULL_RTX; | |
10935 | } | |
10936 | ||
10937 | /* A helper function for flow_dependent_p called through note_stores. */ | |
10938 | static void | |
81a410b1 | 10939 | flow_dependent_p_1 (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data) |
ab55c58f | 10940 | { |
10941 | rtx * pinsn = (rtx *) data; | |
10942 | ||
10943 | if (*pinsn && reg_referenced_p (x, *pinsn)) | |
10944 | *pinsn = NULL_RTX; | |
10945 | } | |
10946 | ||
edf54f2a | 10947 | /* For use by sh_allocate_initial_value. Note that sh.md contains some |
476444cc | 10948 | 'special function' patterns (type sfunc) that clobber pr, but that |
10949 | do not look like function calls to leaf_function_p. Hence we must | |
10950 | do this extra check. */ | |
edf54f2a | 10951 | static int |
04f04b72 | 10952 | sh_pr_n_sets (void) |
476444cc | 10953 | { |
3072d30e | 10954 | return DF_REG_DEF_COUNT (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG); |
476444cc | 10955 | } |
87e19636 | 10956 | |
edf54f2a | 10957 | /* Return where to allocate pseudo for a given hard register initial |
10958 | value. */ | |
10959 | static rtx | |
10960 | sh_allocate_initial_value (rtx hard_reg) | |
10961 | { | |
10962 | rtx x; | |
10963 | ||
10964 | if (REGNO (hard_reg) == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG)) | |
10965 | { | |
d5bf7b64 | 10966 | if (crtl->is_leaf |
edf54f2a | 10967 | && ! sh_pr_n_sets () |
10968 | && ! (TARGET_SHCOMPACT | |
abe32cce | 10969 | && ((crtl->args.info.call_cookie |
edf54f2a | 10970 | & ~ CALL_COOKIE_RET_TRAMP (1)) |
18d50ae6 | 10971 | || crtl->saves_all_registers))) |
edf54f2a | 10972 | x = hard_reg; |
10973 | else | |
aa7e75f2 | 10974 | x = gen_frame_mem (Pmode, return_address_pointer_rtx); |
edf54f2a | 10975 | } |
10976 | else | |
10977 | x = NULL_RTX; | |
10978 | ||
10979 | return x; | |
10980 | } | |
10981 | ||
ab55c58f | 10982 | /* This function returns "2" to indicate dual issue for the SH4 |
10983 | processor. To be used by the DFA pipeline description. */ | |
bea4bad2 | 10984 | static int |
d767e27e | 10985 | sh_issue_rate (void) |
bea4bad2 | 10986 | { |
ab55c58f | 10987 | if (TARGET_SUPERSCALAR) |
10988 | return 2; | |
10989 | else | |
10990 | return 1; | |
bea4bad2 | 10991 | } |
10992 | ||
f77a5bb0 | 10993 | /* Functions for ready queue reordering for sched1. */ |
10994 | ||
10995 | /* Get weight for mode for a set x. */ | |
10996 | static short | |
3754d046 | 10997 | find_set_regmode_weight (rtx x, machine_mode mode) |
f77a5bb0 | 10998 | { |
10999 | if (GET_CODE (x) == CLOBBER && register_operand (SET_DEST (x), mode)) | |
11000 | return 1; | |
11001 | if (GET_CODE (x) == SET && register_operand (SET_DEST (x), mode)) | |
11002 | { | |
cbb16986 | 11003 | if (REG_P (SET_DEST (x))) |
f77a5bb0 | 11004 | { |
11005 | if (!reg_mentioned_p (SET_DEST (x), SET_SRC (x))) | |
11006 | return 1; | |
11007 | else | |
11008 | return 0; | |
11009 | } | |
11010 | return 1; | |
11011 | } | |
11012 | return 0; | |
11013 | } | |
11014 | ||
11015 | /* Get regmode weight for insn. */ | |
11016 | static short | |
3754d046 | 11017 | find_insn_regmode_weight (rtx insn, machine_mode mode) |
f77a5bb0 | 11018 | { |
11019 | short reg_weight = 0; | |
11020 | rtx x; | |
11021 | ||
11022 | /* Increment weight for each register born here. */ | |
11023 | x = PATTERN (insn); | |
11024 | reg_weight += find_set_regmode_weight (x, mode); | |
11025 | if (GET_CODE (x) == PARALLEL) | |
11026 | { | |
11027 | int j; | |
11028 | for (j = XVECLEN (x, 0) - 1; j >= 0; j--) | |
11029 | { | |
11030 | x = XVECEXP (PATTERN (insn), 0, j); | |
11031 | reg_weight += find_set_regmode_weight (x, mode); | |
11032 | } | |
11033 | } | |
11034 | /* Decrement weight for each register that dies here. */ | |
11035 | for (x = REG_NOTES (insn); x; x = XEXP (x, 1)) | |
11036 | { | |
11037 | if (REG_NOTE_KIND (x) == REG_DEAD || REG_NOTE_KIND (x) == REG_UNUSED) | |
11038 | { | |
11039 | rtx note = XEXP (x, 0); | |
cbb16986 | 11040 | if (REG_P (note) && GET_MODE (note) == mode) |
f77a5bb0 | 11041 | reg_weight--; |
11042 | } | |
11043 | } | |
11044 | return reg_weight; | |
11045 | } | |
11046 | ||
11047 | /* Calculate regmode weights for all insns of a basic block. */ | |
11048 | static void | |
3754d046 | 11049 | find_regmode_weight (basic_block b, machine_mode mode) |
f77a5bb0 | 11050 | { |
6fe7b8c2 | 11051 | rtx_insn *insn, *next_tail, *head, *tail; |
f77a5bb0 | 11052 | |
078bb30c | 11053 | get_ebb_head_tail (b, b, &head, &tail); |
f77a5bb0 | 11054 | next_tail = NEXT_INSN (tail); |
11055 | ||
11056 | for (insn = head; insn != next_tail; insn = NEXT_INSN (insn)) | |
11057 | { | |
11058 | /* Handle register life information. */ | |
11059 | if (!INSN_P (insn)) | |
11060 | continue; | |
11061 | ||
11062 | if (mode == SFmode) | |
11063 | INSN_REGMODE_WEIGHT (insn, mode) = | |
10bb497e | 11064 | find_insn_regmode_weight (insn, mode) |
11065 | + 2 * find_insn_regmode_weight (insn, DFmode); | |
f77a5bb0 | 11066 | else if (mode == SImode) |
11067 | INSN_REGMODE_WEIGHT (insn, mode) = | |
10bb497e | 11068 | find_insn_regmode_weight (insn, mode) |
11069 | + 2 * find_insn_regmode_weight (insn, DImode); | |
f77a5bb0 | 11070 | } |
11071 | } | |
11072 | ||
11073 | /* Comparison function for ready queue sorting. */ | |
11074 | static int | |
b60226ef | 11075 | rank_for_reorder (const void *x, const void *y) |
f77a5bb0 | 11076 | { |
b24ef467 | 11077 | rtx_insn *tmp = *(rtx_insn * const *) y; |
11078 | rtx_insn *tmp2 = *(rtx_insn * const *) x; | |
f77a5bb0 | 11079 | |
11080 | /* The insn in a schedule group should be issued the first. */ | |
11081 | if (SCHED_GROUP_P (tmp) != SCHED_GROUP_P (tmp2)) | |
11082 | return SCHED_GROUP_P (tmp2) ? 1 : -1; | |
11083 | ||
9e7454d0 | 11084 | /* If insns are equally good, sort by INSN_LUID (original insn order), This |
f77a5bb0 | 11085 | minimizes instruction movement, thus minimizing sched's effect on |
11086 | register pressure. */ | |
11087 | return INSN_LUID (tmp) - INSN_LUID (tmp2); | |
11088 | } | |
11089 | ||
11090 | /* Resort the array A in which only element at index N may be out of order. */ | |
11091 | static void | |
b24ef467 | 11092 | swap_reorder (rtx_insn **a, int n) |
f77a5bb0 | 11093 | { |
b24ef467 | 11094 | rtx_insn *insn = a[n - 1]; |
f77a5bb0 | 11095 | int i = n - 2; |
11096 | ||
11097 | while (i >= 0 && rank_for_reorder (a + i, &insn) >= 0) | |
11098 | { | |
11099 | a[i + 1] = a[i]; | |
11100 | i -= 1; | |
11101 | } | |
11102 | a[i + 1] = insn; | |
11103 | } | |
11104 | ||
855d5778 | 11105 | /* Sort the ready list by ascending priority. */ |
f77a5bb0 | 11106 | static void |
b24ef467 | 11107 | ready_reorder (rtx_insn **ready, int nready) |
f77a5bb0 | 11108 | { |
855d5778 | 11109 | if (nready == 2) |
11110 | swap_reorder (ready, nready); | |
11111 | else if (nready > 2) | |
b24ef467 | 11112 | qsort (ready, nready, sizeof (rtx_insn *), rank_for_reorder); |
f77a5bb0 | 11113 | } |
11114 | ||
3072d30e | 11115 | /* Count life regions of r0 for a block. */ |
11116 | static int | |
11117 | find_r0_life_regions (basic_block b) | |
11118 | { | |
b82334f7 | 11119 | rtx_insn *end, *insn; |
3072d30e | 11120 | rtx pset; |
11121 | rtx r0_reg; | |
11122 | int live; | |
11123 | int set; | |
11124 | int death = 0; | |
11125 | ||
deb2741b | 11126 | if (REGNO_REG_SET_P (df_get_live_in (b), R0_REG)) |
3072d30e | 11127 | { |
11128 | set = 1; | |
11129 | live = 1; | |
11130 | } | |
11131 | else | |
11132 | { | |
11133 | set = 0; | |
11134 | live = 0; | |
11135 | } | |
11136 | ||
11137 | insn = BB_HEAD (b); | |
11138 | end = BB_END (b); | |
11139 | r0_reg = gen_rtx_REG (SImode, R0_REG); | |
11140 | while (1) | |
11141 | { | |
11142 | if (INSN_P (insn)) | |
11143 | { | |
11144 | if (find_regno_note (insn, REG_DEAD, R0_REG)) | |
11145 | { | |
11146 | death++; | |
11147 | live = 0; | |
11148 | } | |
11149 | if (!live | |
11150 | && (pset = single_set (insn)) | |
11151 | && reg_overlap_mentioned_p (r0_reg, SET_DEST (pset)) | |
11152 | && !find_regno_note (insn, REG_UNUSED, R0_REG)) | |
11153 | { | |
11154 | set++; | |
11155 | live = 1; | |
11156 | } | |
11157 | } | |
11158 | if (insn == end) | |
11159 | break; | |
11160 | insn = NEXT_INSN (insn); | |
11161 | } | |
11162 | return set - death; | |
11163 | } | |
11164 | ||
f77a5bb0 | 11165 | /* Calculate regmode weights for all insns of all basic block. */ |
11166 | static void | |
b60226ef | 11167 | sh_md_init_global (FILE *dump ATTRIBUTE_UNUSED, |
11168 | int verbose ATTRIBUTE_UNUSED, | |
11169 | int old_max_uid) | |
f77a5bb0 | 11170 | { |
11171 | basic_block b; | |
11172 | ||
11173 | regmode_weight[0] = (short *) xcalloc (old_max_uid, sizeof (short)); | |
11174 | regmode_weight[1] = (short *) xcalloc (old_max_uid, sizeof (short)); | |
3072d30e | 11175 | r0_life_regions = 0; |
f77a5bb0 | 11176 | |
7a46197b | 11177 | FOR_EACH_BB_REVERSE_FN (b, cfun) |
f77a5bb0 | 11178 | { |
078bb30c | 11179 | find_regmode_weight (b, SImode); |
11180 | find_regmode_weight (b, SFmode); | |
3072d30e | 11181 | if (!reload_completed) |
11182 | r0_life_regions += find_r0_life_regions (b); | |
f77a5bb0 | 11183 | } |
11184 | ||
11185 | CURR_REGMODE_PRESSURE (SImode) = 0; | |
11186 | CURR_REGMODE_PRESSURE (SFmode) = 0; | |
f77a5bb0 | 11187 | } |
11188 | ||
11189 | /* Cleanup. */ | |
11190 | static void | |
b60226ef | 11191 | sh_md_finish_global (FILE *dump ATTRIBUTE_UNUSED, |
11192 | int verbose ATTRIBUTE_UNUSED) | |
f77a5bb0 | 11193 | { |
11194 | if (regmode_weight[0]) | |
11195 | { | |
11196 | free (regmode_weight[0]); | |
11197 | regmode_weight[0] = NULL; | |
11198 | } | |
11199 | if (regmode_weight[1]) | |
11200 | { | |
11201 | free (regmode_weight[1]); | |
11202 | regmode_weight[1] = NULL; | |
11203 | } | |
11204 | } | |
11205 | ||
607ac910 | 11206 | /* The scalar modes supported differs from the default version in TImode |
11207 | for 32-bit SHMEDIA. */ | |
11208 | static bool | |
3754d046 | 11209 | sh_scalar_mode_supported_p (machine_mode mode) |
607ac910 | 11210 | { |
11211 | if (TARGET_SHMEDIA32 && mode == TImode) | |
11212 | return false; | |
11213 | ||
11214 | return default_scalar_mode_supported_p (mode); | |
11215 | } | |
11216 | ||
f77a5bb0 | 11217 | /* Cache the can_issue_more so that we can return it from reorder2. Also, |
11218 | keep count of register pressures on SImode and SFmode. */ | |
11219 | static int | |
b60226ef | 11220 | sh_variable_issue (FILE *dump ATTRIBUTE_UNUSED, |
11221 | int sched_verbose ATTRIBUTE_UNUSED, | |
18282db0 | 11222 | rtx_insn *insn, |
b60226ef | 11223 | int can_issue_more) |
f77a5bb0 | 11224 | { |
11225 | if (GET_CODE (PATTERN (insn)) != USE | |
11226 | && GET_CODE (PATTERN (insn)) != CLOBBER) | |
11227 | cached_can_issue_more = can_issue_more - 1; | |
11228 | else | |
11229 | cached_can_issue_more = can_issue_more; | |
11230 | ||
11231 | if (reload_completed) | |
11232 | return cached_can_issue_more; | |
11233 | ||
11234 | CURR_REGMODE_PRESSURE (SImode) += INSN_REGMODE_WEIGHT (insn, SImode); | |
11235 | CURR_REGMODE_PRESSURE (SFmode) += INSN_REGMODE_WEIGHT (insn, SFmode); | |
11236 | ||
11237 | return cached_can_issue_more; | |
11238 | } | |
11239 | ||
11240 | static void | |
b60226ef | 11241 | sh_md_init (FILE *dump ATTRIBUTE_UNUSED, |
11242 | int verbose ATTRIBUTE_UNUSED, | |
11243 | int veclen ATTRIBUTE_UNUSED) | |
f77a5bb0 | 11244 | { |
11245 | CURR_REGMODE_PRESSURE (SImode) = 0; | |
11246 | CURR_REGMODE_PRESSURE (SFmode) = 0; | |
11247 | } | |
11248 | ||
11249 | /* Some magic numbers. */ | |
11250 | /* Pressure on register r0 can lead to spill failures. so avoid sched1 for | |
11251 | functions that already have high pressure on r0. */ | |
11252 | #define R0_MAX_LIFE_REGIONS 2 | |
0aee14a5 | 11253 | /* Register Pressure thresholds for SImode and SFmode registers. */ |
f77a5bb0 | 11254 | #define SIMODE_MAX_WEIGHT 5 |
11255 | #define SFMODE_MAX_WEIGHT 10 | |
11256 | ||
11257 | /* Return true if the pressure is high for MODE. */ | |
a3b1178e | 11258 | static bool |
3754d046 | 11259 | high_pressure (machine_mode mode) |
f77a5bb0 | 11260 | { |
11261 | /* Pressure on register r0 can lead to spill failures. so avoid sched1 for | |
11262 | functions that already have high pressure on r0. */ | |
3072d30e | 11263 | if (r0_life_regions >= R0_MAX_LIFE_REGIONS) |
a3b1178e | 11264 | return true; |
f77a5bb0 | 11265 | |
11266 | if (mode == SFmode) | |
11267 | return (CURR_REGMODE_PRESSURE (SFmode) > SFMODE_MAX_WEIGHT); | |
11268 | else | |
11269 | return (CURR_REGMODE_PRESSURE (SImode) > SIMODE_MAX_WEIGHT); | |
11270 | } | |
11271 | ||
11272 | /* Reorder ready queue if register pressure is high. */ | |
11273 | static int | |
b60226ef | 11274 | sh_reorder (FILE *dump ATTRIBUTE_UNUSED, |
11275 | int sched_verbose ATTRIBUTE_UNUSED, | |
b24ef467 | 11276 | rtx_insn **ready, |
b60226ef | 11277 | int *n_readyp, |
11278 | int clock_var ATTRIBUTE_UNUSED) | |
f77a5bb0 | 11279 | { |
11280 | if (reload_completed) | |
11281 | return sh_issue_rate (); | |
11282 | ||
11283 | if (high_pressure (SFmode) || high_pressure (SImode)) | |
11284 | { | |
11285 | ready_reorder (ready, *n_readyp); | |
11286 | } | |
11287 | ||
11288 | return sh_issue_rate (); | |
11289 | } | |
11290 | ||
11291 | /* Skip cycles if the current register pressure is high. */ | |
9e7454d0 | 11292 | static int |
b60226ef | 11293 | sh_reorder2 (FILE *dump ATTRIBUTE_UNUSED, |
11294 | int sched_verbose ATTRIBUTE_UNUSED, | |
b24ef467 | 11295 | rtx_insn **ready ATTRIBUTE_UNUSED, |
b60226ef | 11296 | int *n_readyp ATTRIBUTE_UNUSED, |
11297 | int clock_var ATTRIBUTE_UNUSED) | |
f77a5bb0 | 11298 | { |
11299 | if (reload_completed) | |
11300 | return cached_can_issue_more; | |
11301 | ||
9e7454d0 | 11302 | if (high_pressure(SFmode) || high_pressure (SImode)) |
f77a5bb0 | 11303 | skip_cycles = 1; |
11304 | ||
11305 | return cached_can_issue_more; | |
11306 | } | |
11307 | ||
11308 | /* Skip cycles without sorting the ready queue. This will move insn from | |
11309 | Q->R. If this is the last cycle we are skipping; allow sorting of ready | |
9e7454d0 | 11310 | queue by sh_reorder. */ |
f77a5bb0 | 11311 | |
9e7454d0 | 11312 | /* Generally, skipping these many cycles are sufficient for all insns to move |
11313 | from Q -> R. */ | |
11314 | #define MAX_SKIPS 8 | |
f77a5bb0 | 11315 | |
11316 | static int | |
b60226ef | 11317 | sh_dfa_new_cycle (FILE *sched_dump ATTRIBUTE_UNUSED, |
11318 | int sched_verbose ATTRIBUTE_UNUSED, | |
18282db0 | 11319 | rtx_insn *insn ATTRIBUTE_UNUSED, |
b60226ef | 11320 | int last_clock_var, |
11321 | int clock_var, | |
11322 | int *sort_p) | |
f77a5bb0 | 11323 | { |
11324 | if (reload_completed) | |
d767e27e | 11325 | return 0; |
f77a5bb0 | 11326 | |
9e7454d0 | 11327 | if (skip_cycles) |
f77a5bb0 | 11328 | { |
d767e27e | 11329 | if ((clock_var - last_clock_var) < MAX_SKIPS) |
11330 | { | |
11331 | *sort_p = 0; | |
11332 | return 1; | |
11333 | } | |
11334 | /* If this is the last cycle we are skipping, allow reordering of R. */ | |
11335 | if ((clock_var - last_clock_var) == MAX_SKIPS) | |
11336 | { | |
11337 | *sort_p = 1; | |
11338 | return 1; | |
11339 | } | |
f77a5bb0 | 11340 | } |
f77a5bb0 | 11341 | |
11342 | skip_cycles = 0; | |
11343 | ||
11344 | return 0; | |
11345 | } | |
11346 | ||
87e19636 | 11347 | /* SHmedia requires registers for branches, so we can't generate new |
11348 | branches past reload. */ | |
11349 | static bool | |
04f04b72 | 11350 | sh_cannot_modify_jumps_p (void) |
87e19636 | 11351 | { |
11352 | return (TARGET_SHMEDIA && (reload_in_progress || reload_completed)); | |
11353 | } | |
11354 | ||
964229b7 | 11355 | static reg_class_t |
8af3db02 | 11356 | sh_target_reg_class (void) |
11357 | { | |
11358 | return TARGET_SHMEDIA ? TARGET_REGS : NO_REGS; | |
11359 | } | |
11360 | ||
11361 | static bool | |
11362 | sh_optimize_target_register_callee_saved (bool after_prologue_epilogue_gen) | |
11363 | { | |
59312820 | 11364 | if (! shmedia_space_reserved_for_target_registers) |
11365 | return 0; | |
11366 | if (after_prologue_epilogue_gen && ! TARGET_SAVE_ALL_TARGET_REGS) | |
11367 | return 0; | |
10bb497e | 11368 | |
11369 | HARD_REG_SET dummy; | |
59312820 | 11370 | if (calc_live_regs (&dummy) >= 6 * 8) |
11371 | return 1; | |
59312820 | 11372 | return 0; |
8af3db02 | 11373 | } |
11374 | ||
87e19636 | 11375 | static bool |
a9f1838b | 11376 | sh_ms_bitfield_layout_p (const_tree record_type ATTRIBUTE_UNUSED) |
87e19636 | 11377 | { |
45550790 | 11378 | return (TARGET_SH5 || TARGET_HITACHI || sh_attr_renesas_p (record_type)); |
87e19636 | 11379 | } |
e40c2d35 | 11380 | \f |
9e7454d0 | 11381 | /* |
e40c2d35 | 11382 | On the SH1..SH4, the trampoline looks like |
11383 | 2 0002 D202 mov.l l2,r2 | |
11384 | 1 0000 D301 mov.l l1,r3 | |
11385 | 3 0004 422B jmp @r2 | |
11386 | 4 0006 0009 nop | |
11387 | 5 0008 00000000 l1: .long area | |
11388 | 6 000c 00000000 l2: .long function | |
11389 | ||
11390 | SH5 (compact) uses r1 instead of r3 for the static chain. */ | |
11391 | ||
11392 | ||
11393 | /* Emit RTL insns to initialize the variable parts of a trampoline. | |
11394 | FNADDR is an RTX for the address of the function's pure code. | |
11395 | CXT is an RTX for the static chain value for the function. */ | |
3daf7435 | 11396 | static void |
11397 | sh_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt) | |
e40c2d35 | 11398 | { |
3daf7435 | 11399 | rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); |
11400 | rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0)); | |
aa7e75f2 | 11401 | |
e40c2d35 | 11402 | if (TARGET_SHMEDIA64) |
11403 | { | |
11404 | rtx tramp_templ; | |
11405 | int fixed_len; | |
11406 | ||
11407 | rtx movi1 = GEN_INT (0xcc000010); | |
11408 | rtx shori1 = GEN_INT (0xc8000010); | |
11409 | rtx src, dst; | |
11410 | ||
11411 | /* The following trampoline works within a +- 128 KB range for cxt: | |
11412 | ptb/u cxt,tr1; movi fnaddr >> 48,r0; shori fnaddr >> 32,r0; | |
6c049e03 | 11413 | shori fnaddr >> 16,r0; shori fnaddr,r0; ptabs/l r0,tr0 |
11414 | gettr tr1,r1; blink tr0,r63 */ | |
e40c2d35 | 11415 | /* Address rounding makes it hard to compute the exact bounds of the |
11416 | offset for this trampoline, but we have a rather generous offset | |
11417 | range, so frame_offset should do fine as an upper bound. */ | |
11418 | if (cxt == virtual_stack_vars_rtx && frame_offset < 0x20000) | |
11419 | { | |
11420 | /* ??? could optimize this trampoline initialization | |
11421 | by writing DImode words with two insns each. */ | |
11422 | rtx mask = force_reg (DImode, GEN_INT (0x3fffc00)); | |
11423 | rtx insn = gen_rtx_MINUS (DImode, cxt, tramp); | |
11424 | insn = gen_rtx_ASHIFT (DImode, insn, GEN_INT (10-2)); | |
11425 | insn = gen_rtx_AND (DImode, insn, mask); | |
11426 | /* Or in ptb/u .,tr1 pattern */ | |
11427 | insn = gen_rtx_IOR (DImode, insn, gen_int_mode (0xec000010, SImode)); | |
11428 | insn = force_operand (insn, NULL_RTX); | |
11429 | insn = gen_lowpart (SImode, insn); | |
aa7e75f2 | 11430 | emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX), insn); |
e40c2d35 | 11431 | insn = gen_rtx_LSHIFTRT (DImode, fnaddr, GEN_INT (38)); |
11432 | insn = gen_rtx_AND (DImode, insn, mask); | |
11433 | insn = force_operand (gen_rtx_IOR (DImode, movi1, insn), NULL_RTX); | |
11434 | insn = gen_lowpart (SImode, insn); | |
aa7e75f2 | 11435 | emit_move_insn (adjust_address (tramp_mem, SImode, 4), insn); |
e40c2d35 | 11436 | insn = gen_rtx_LSHIFTRT (DImode, fnaddr, GEN_INT (22)); |
11437 | insn = gen_rtx_AND (DImode, insn, mask); | |
11438 | insn = force_operand (gen_rtx_IOR (DImode, shori1, insn), NULL_RTX); | |
11439 | insn = gen_lowpart (SImode, insn); | |
aa7e75f2 | 11440 | emit_move_insn (adjust_address (tramp_mem, SImode, 8), insn); |
e40c2d35 | 11441 | insn = gen_rtx_LSHIFTRT (DImode, fnaddr, GEN_INT (6)); |
11442 | insn = gen_rtx_AND (DImode, insn, mask); | |
11443 | insn = force_operand (gen_rtx_IOR (DImode, shori1, insn), NULL_RTX); | |
11444 | insn = gen_lowpart (SImode, insn); | |
aa7e75f2 | 11445 | emit_move_insn (adjust_address (tramp_mem, SImode, 12), insn); |
e40c2d35 | 11446 | insn = gen_rtx_ASHIFT (DImode, fnaddr, GEN_INT (10)); |
11447 | insn = gen_rtx_AND (DImode, insn, mask); | |
11448 | insn = force_operand (gen_rtx_IOR (DImode, shori1, insn), NULL_RTX); | |
11449 | insn = gen_lowpart (SImode, insn); | |
aa7e75f2 | 11450 | emit_move_insn (adjust_address (tramp_mem, SImode, 16), insn); |
11451 | emit_move_insn (adjust_address (tramp_mem, SImode, 20), | |
e40c2d35 | 11452 | GEN_INT (0x6bf10600)); |
aa7e75f2 | 11453 | emit_move_insn (adjust_address (tramp_mem, SImode, 24), |
e40c2d35 | 11454 | GEN_INT (0x4415fc10)); |
aa7e75f2 | 11455 | emit_move_insn (adjust_address (tramp_mem, SImode, 28), |
e40c2d35 | 11456 | GEN_INT (0x4401fff0)); |
11457 | emit_insn (gen_ic_invalidate_line (tramp)); | |
11458 | return; | |
11459 | } | |
11460 | tramp_templ = gen_rtx_SYMBOL_REF (Pmode,"__GCC_nested_trampoline"); | |
11461 | fixed_len = TRAMPOLINE_SIZE - 2 * GET_MODE_SIZE (Pmode); | |
11462 | ||
11463 | tramp_templ = gen_datalabel_ref (tramp_templ); | |
aa7e75f2 | 11464 | dst = tramp_mem; |
11465 | src = gen_const_mem (BLKmode, tramp_templ); | |
e40c2d35 | 11466 | set_mem_align (dst, 256); |
11467 | set_mem_align (src, 64); | |
0378dbdc | 11468 | emit_block_move (dst, src, GEN_INT (fixed_len), BLOCK_OP_NORMAL); |
e40c2d35 | 11469 | |
aa7e75f2 | 11470 | emit_move_insn (adjust_address (tramp_mem, Pmode, fixed_len), fnaddr); |
11471 | emit_move_insn (adjust_address (tramp_mem, Pmode, | |
11472 | fixed_len + GET_MODE_SIZE (Pmode)), | |
e40c2d35 | 11473 | cxt); |
11474 | emit_insn (gen_ic_invalidate_line (tramp)); | |
11475 | return; | |
11476 | } | |
11477 | else if (TARGET_SHMEDIA) | |
11478 | { | |
11479 | /* movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0 | |
11480 | movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */ | |
11481 | rtx quad0 = gen_reg_rtx (DImode), cxtload = gen_reg_rtx (DImode); | |
11482 | rtx quad1 = gen_reg_rtx (DImode), quad2 = gen_reg_rtx (DImode); | |
11483 | /* movi 0,r1: 0xcc000010 shori 0,r1: c8000010 concatenated, | |
0924aa1d | 11484 | rotated 10 right, and higher 16 bit of every 32 selected. */ |
e40c2d35 | 11485 | rtx movishori |
11486 | = force_reg (V2HImode, (simplify_gen_subreg | |
11487 | (V2HImode, GEN_INT (0x4330432), SImode, 0))); | |
11488 | rtx ptabs = force_reg (DImode, GEN_INT (0x6bf10600)); | |
11489 | rtx blink = force_reg (DImode, GEN_INT (0x4401fff0)); | |
11490 | ||
e40c2d35 | 11491 | fnaddr = force_reg (SImode, fnaddr); |
11492 | cxt = force_reg (SImode, cxt); | |
11493 | emit_insn (gen_mshflo_w_x (gen_rtx_SUBREG (V4HImode, quad0, 0), | |
11494 | gen_rtx_SUBREG (V2HImode, fnaddr, 0), | |
11495 | movishori)); | |
e586c16d | 11496 | emit_insn (gen_rotrdi3_mextr (quad0, quad0, |
e40c2d35 | 11497 | GEN_INT (TARGET_LITTLE_ENDIAN ? 24 : 56))); |
bcd9bd66 | 11498 | emit_insn (gen_ashldi3_media (quad0, quad0, const2_rtx)); |
aa7e75f2 | 11499 | emit_move_insn (change_address (tramp_mem, DImode, NULL_RTX), quad0); |
e40c2d35 | 11500 | emit_insn (gen_mshflo_w_x (gen_rtx_SUBREG (V4HImode, cxtload, 0), |
11501 | gen_rtx_SUBREG (V2HImode, cxt, 0), | |
11502 | movishori)); | |
e586c16d | 11503 | emit_insn (gen_rotrdi3_mextr (cxtload, cxtload, |
e40c2d35 | 11504 | GEN_INT (TARGET_LITTLE_ENDIAN ? 24 : 56))); |
bcd9bd66 | 11505 | emit_insn (gen_ashldi3_media (cxtload, cxtload, const2_rtx)); |
e40c2d35 | 11506 | if (TARGET_LITTLE_ENDIAN) |
11507 | { | |
11508 | emit_insn (gen_mshflo_l_di (quad1, ptabs, cxtload)); | |
11509 | emit_insn (gen_mextr4 (quad2, cxtload, blink)); | |
11510 | } | |
11511 | else | |
11512 | { | |
11513 | emit_insn (gen_mextr4 (quad1, cxtload, ptabs)); | |
11514 | emit_insn (gen_mshflo_l_di (quad2, blink, cxtload)); | |
11515 | } | |
aa7e75f2 | 11516 | emit_move_insn (adjust_address (tramp_mem, DImode, 8), quad1); |
11517 | emit_move_insn (adjust_address (tramp_mem, DImode, 16), quad2); | |
e40c2d35 | 11518 | emit_insn (gen_ic_invalidate_line (tramp)); |
11519 | return; | |
11520 | } | |
11521 | else if (TARGET_SHCOMPACT) | |
11522 | { | |
11523 | emit_insn (gen_initialize_trampoline (tramp, cxt, fnaddr)); | |
11524 | return; | |
11525 | } | |
aa7e75f2 | 11526 | emit_move_insn (change_address (tramp_mem, SImode, NULL_RTX), |
e40c2d35 | 11527 | gen_int_mode (TARGET_LITTLE_ENDIAN ? 0xd301d202 : 0xd202d301, |
11528 | SImode)); | |
aa7e75f2 | 11529 | emit_move_insn (adjust_address (tramp_mem, SImode, 4), |
e40c2d35 | 11530 | gen_int_mode (TARGET_LITTLE_ENDIAN ? 0x0009422b : 0x422b0009, |
11531 | SImode)); | |
aa7e75f2 | 11532 | emit_move_insn (adjust_address (tramp_mem, SImode, 8), cxt); |
11533 | emit_move_insn (adjust_address (tramp_mem, SImode, 12), fnaddr); | |
2e752f00 | 11534 | if (TARGET_HARD_SH4 || TARGET_SH5) |
e40c2d35 | 11535 | { |
bc3f5c21 | 11536 | if (!TARGET_INLINE_IC_INVALIDATE |
5b271aff | 11537 | || (!(TARGET_SH4A || TARGET_SH4_300) && TARGET_USERMODE)) |
59312820 | 11538 | emit_library_call (function_symbol (NULL, "__ic_invalidate", |
11539 | FUNCTION_ORDINARY), | |
6f2543f8 | 11540 | LCT_NORMAL, VOIDmode, 1, tramp, SImode); |
e40c2d35 | 11541 | else |
11542 | emit_insn (gen_ic_invalidate_line (tramp)); | |
11543 | } | |
11544 | } | |
11545 | ||
3daf7435 | 11546 | /* On SH5, trampolines are SHmedia code, so add 1 to the address. */ |
3daf7435 | 11547 | static rtx |
11548 | sh_trampoline_adjust_address (rtx tramp) | |
11549 | { | |
11550 | if (TARGET_SHMEDIA) | |
11551 | tramp = expand_simple_binop (Pmode, PLUS, tramp, const1_rtx, | |
11552 | gen_reg_rtx (Pmode), 0, OPTAB_LIB_WIDEN); | |
11553 | return tramp; | |
11554 | } | |
11555 | ||
805e22b2 | 11556 | /* FIXME: This is overly conservative. A SHcompact function that |
11557 | receives arguments ``by reference'' will have them stored in its | |
11558 | own stack frame, so it must not pass pointers or references to | |
11559 | these arguments to other functions by means of sibling calls. */ | |
59312820 | 11560 | /* If PIC, we cannot make sibling calls to global functions |
11561 | because the PLT requires r12 to be live. */ | |
805e22b2 | 11562 | static bool |
04f04b72 | 11563 | sh_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) |
805e22b2 | 11564 | { |
59312820 | 11565 | return (1 |
805e22b2 | 11566 | && (! TARGET_SHCOMPACT |
abe32cce | 11567 | || crtl->args.info.stack_regs == 0) |
59312820 | 11568 | && ! sh_cfun_interrupt_handler_p () |
11569 | && (! flag_pic | |
11570 | || (decl && ! TREE_PUBLIC (decl)) | |
11571 | || (decl && DECL_VISIBILITY (decl) != VISIBILITY_DEFAULT))); | |
805e22b2 | 11572 | } |
e3fac27d | 11573 | \f |
11574 | /* Machine specific built-in functions. */ | |
11575 | ||
11576 | struct builtin_description | |
11577 | { | |
70695242 | 11578 | bool (* const is_enabled) (void); |
e3fac27d | 11579 | const enum insn_code icode; |
11580 | const char *const name; | |
11581 | int signature; | |
3213bdbf | 11582 | tree fndecl; |
e3fac27d | 11583 | }; |
11584 | ||
70695242 | 11585 | static bool |
11586 | shmedia_builtin_p (void) | |
11587 | { | |
11588 | return TARGET_SHMEDIA; | |
11589 | } | |
11590 | ||
46e4453e | 11591 | /* This function can be used if there are any built-ins that are not for |
81298240 | 11592 | SHmedia. It's commented out to avoid the defined-but-unused warning. */ |
eaed8755 | 11593 | static bool |
11594 | sh1_builtin_p (void) | |
11595 | { | |
11596 | return TARGET_SH1; | |
11597 | } | |
11598 | ||
e3fac27d | 11599 | /* describe number and signedness of arguments; arg[0] == result |
11600 | (1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */ | |
a61b32a8 | 11601 | /* 9: 64-bit pointer, 10: 32-bit pointer */ |
e3fac27d | 11602 | static const char signature_args[][4] = |
11603 | { | |
11604 | #define SH_BLTIN_V2SI2 0 | |
11605 | { 4, 4 }, | |
11606 | #define SH_BLTIN_V4HI2 1 | |
11607 | { 4, 4 }, | |
11608 | #define SH_BLTIN_V2SI3 2 | |
11609 | { 4, 4, 4 }, | |
11610 | #define SH_BLTIN_V4HI3 3 | |
11611 | { 4, 4, 4 }, | |
11612 | #define SH_BLTIN_V8QI3 4 | |
11613 | { 4, 4, 4 }, | |
11614 | #define SH_BLTIN_MAC_HISI 5 | |
11615 | { 1, 4, 4, 1 }, | |
11616 | #define SH_BLTIN_SH_HI 6 | |
11617 | { 4, 4, 1 }, | |
11618 | #define SH_BLTIN_SH_SI 7 | |
11619 | { 4, 4, 1 }, | |
11620 | #define SH_BLTIN_V4HI2V2SI 8 | |
11621 | { 4, 4, 4 }, | |
11622 | #define SH_BLTIN_V4HI2V8QI 9 | |
11623 | { 4, 4, 4 }, | |
11624 | #define SH_BLTIN_SISF 10 | |
11625 | { 4, 2 }, | |
11626 | #define SH_BLTIN_LDUA_L 11 | |
59312820 | 11627 | { 2, 10 }, |
e3fac27d | 11628 | #define SH_BLTIN_LDUA_Q 12 |
59312820 | 11629 | { 1, 10 }, |
e3fac27d | 11630 | #define SH_BLTIN_STUA_L 13 |
59312820 | 11631 | { 0, 10, 2 }, |
e3fac27d | 11632 | #define SH_BLTIN_STUA_Q 14 |
59312820 | 11633 | { 0, 10, 1 }, |
11634 | #define SH_BLTIN_LDUA_L64 15 | |
11635 | { 2, 9 }, | |
11636 | #define SH_BLTIN_LDUA_Q64 16 | |
11637 | { 1, 9 }, | |
11638 | #define SH_BLTIN_STUA_L64 17 | |
11639 | { 0, 9, 2 }, | |
11640 | #define SH_BLTIN_STUA_Q64 18 | |
11641 | { 0, 9, 1 }, | |
11642 | #define SH_BLTIN_NUM_SHARED_SIGNATURES 19 | |
11643 | #define SH_BLTIN_2 19 | |
11644 | #define SH_BLTIN_SU 19 | |
e3fac27d | 11645 | { 1, 2 }, |
59312820 | 11646 | #define SH_BLTIN_3 20 |
11647 | #define SH_BLTIN_SUS 20 | |
e3fac27d | 11648 | { 2, 2, 1 }, |
59312820 | 11649 | #define SH_BLTIN_PSSV 21 |
e3fac27d | 11650 | { 0, 8, 2, 2 }, |
59312820 | 11651 | #define SH_BLTIN_XXUU 22 |
11652 | #define SH_BLTIN_UUUU 22 | |
e3fac27d | 11653 | { 1, 1, 1, 1 }, |
59312820 | 11654 | #define SH_BLTIN_PV 23 |
e3fac27d | 11655 | { 0, 8 }, |
eaed8755 | 11656 | #define SH_BLTIN_VP 24 |
11657 | { 8, 0 }, | |
81298240 | 11658 | #define SH_BLTIN_UV 25 |
11659 | { 1, 0 }, | |
11660 | #define SH_BLTIN_VU 26 | |
11661 | { 0, 1 }, | |
e3fac27d | 11662 | }; |
ada8cf8b | 11663 | /* mcmv: operands considered unsigned. */ |
e3fac27d | 11664 | /* mmulsum_wq, msad_ubq: result considered unsigned long long. */ |
ada8cf8b | 11665 | /* mperm: control value considered unsigned int. */ |
11666 | /* mshalds, mshard, mshards, mshlld, mshlrd: shift count is unsigned int. */ | |
e3fac27d | 11667 | /* mshards_q: returns signed short. */ |
11668 | /* nsb: takes long long arg, returns unsigned char. */ | |
3213bdbf | 11669 | static struct builtin_description bdesc[] = |
11670 | { | |
70695242 | 11671 | { shmedia_builtin_p, |
11672 | CODE_FOR_absv2si2, "__builtin_absv2si2", SH_BLTIN_V2SI2, 0 }, | |
11673 | { shmedia_builtin_p, | |
11674 | CODE_FOR_absv4hi2, "__builtin_absv4hi2", SH_BLTIN_V4HI2, 0 }, | |
11675 | { shmedia_builtin_p, | |
11676 | CODE_FOR_addv2si3, "__builtin_addv2si3", SH_BLTIN_V2SI3, 0 }, | |
11677 | { shmedia_builtin_p, | |
11678 | CODE_FOR_addv4hi3, "__builtin_addv4hi3", SH_BLTIN_V4HI3, 0 }, | |
11679 | { shmedia_builtin_p, | |
11680 | CODE_FOR_ssaddv2si3,"__builtin_ssaddv2si3", SH_BLTIN_V2SI3, 0 }, | |
11681 | { shmedia_builtin_p, | |
11682 | CODE_FOR_usaddv8qi3,"__builtin_usaddv8qi3", SH_BLTIN_V8QI3, 0 }, | |
11683 | { shmedia_builtin_p, | |
11684 | CODE_FOR_ssaddv4hi3,"__builtin_ssaddv4hi3", SH_BLTIN_V4HI3, 0 }, | |
11685 | { shmedia_builtin_p, | |
11686 | CODE_FOR_alloco_i, "__builtin_sh_media_ALLOCO", SH_BLTIN_PV, 0 }, | |
11687 | { shmedia_builtin_p, | |
11688 | CODE_FOR_negcmpeqv8qi,"__builtin_sh_media_MCMPEQ_B", SH_BLTIN_V8QI3, 0 }, | |
11689 | { shmedia_builtin_p, | |
11690 | CODE_FOR_negcmpeqv2si,"__builtin_sh_media_MCMPEQ_L", SH_BLTIN_V2SI3, 0 }, | |
11691 | { shmedia_builtin_p, | |
11692 | CODE_FOR_negcmpeqv4hi,"__builtin_sh_media_MCMPEQ_W", SH_BLTIN_V4HI3, 0 }, | |
11693 | { shmedia_builtin_p, | |
11694 | CODE_FOR_negcmpgtuv8qi,"__builtin_sh_media_MCMPGT_UB", SH_BLTIN_V8QI3, 0 }, | |
11695 | { shmedia_builtin_p, | |
11696 | CODE_FOR_negcmpgtv2si,"__builtin_sh_media_MCMPGT_L", SH_BLTIN_V2SI3, 0 }, | |
11697 | { shmedia_builtin_p, | |
11698 | CODE_FOR_negcmpgtv4hi,"__builtin_sh_media_MCMPGT_W", SH_BLTIN_V4HI3, 0 }, | |
11699 | { shmedia_builtin_p, | |
11700 | CODE_FOR_mcmv, "__builtin_sh_media_MCMV", SH_BLTIN_UUUU, 0 }, | |
11701 | { shmedia_builtin_p, | |
11702 | CODE_FOR_mcnvs_lw, "__builtin_sh_media_MCNVS_LW", SH_BLTIN_3, 0 }, | |
11703 | { shmedia_builtin_p, | |
11704 | CODE_FOR_mcnvs_wb, "__builtin_sh_media_MCNVS_WB", SH_BLTIN_V4HI2V8QI, 0 }, | |
11705 | { shmedia_builtin_p, | |
11706 | CODE_FOR_mcnvs_wub, "__builtin_sh_media_MCNVS_WUB", SH_BLTIN_V4HI2V8QI, 0 }, | |
11707 | { shmedia_builtin_p, | |
11708 | CODE_FOR_mextr1, "__builtin_sh_media_MEXTR1", SH_BLTIN_V8QI3, 0 }, | |
11709 | { shmedia_builtin_p, | |
11710 | CODE_FOR_mextr2, "__builtin_sh_media_MEXTR2", SH_BLTIN_V8QI3, 0 }, | |
11711 | { shmedia_builtin_p, | |
11712 | CODE_FOR_mextr3, "__builtin_sh_media_MEXTR3", SH_BLTIN_V8QI3, 0 }, | |
11713 | { shmedia_builtin_p, | |
11714 | CODE_FOR_mextr4, "__builtin_sh_media_MEXTR4", SH_BLTIN_V8QI3, 0 }, | |
11715 | { shmedia_builtin_p, | |
11716 | CODE_FOR_mextr5, "__builtin_sh_media_MEXTR5", SH_BLTIN_V8QI3, 0 }, | |
11717 | { shmedia_builtin_p, | |
11718 | CODE_FOR_mextr6, "__builtin_sh_media_MEXTR6", SH_BLTIN_V8QI3, 0 }, | |
11719 | { shmedia_builtin_p, | |
11720 | CODE_FOR_mextr7, "__builtin_sh_media_MEXTR7", SH_BLTIN_V8QI3, 0 }, | |
11721 | { shmedia_builtin_p, | |
11722 | CODE_FOR_mmacfx_wl, "__builtin_sh_media_MMACFX_WL", SH_BLTIN_MAC_HISI, 0 }, | |
11723 | { shmedia_builtin_p, | |
11724 | CODE_FOR_mmacnfx_wl,"__builtin_sh_media_MMACNFX_WL", SH_BLTIN_MAC_HISI, 0 }, | |
11725 | { shmedia_builtin_p, | |
11726 | CODE_FOR_mulv2si3, "__builtin_mulv2si3", SH_BLTIN_V2SI3, 0 }, | |
11727 | { shmedia_builtin_p, | |
11728 | CODE_FOR_mulv4hi3, "__builtin_mulv4hi3", SH_BLTIN_V4HI3, 0 }, | |
11729 | { shmedia_builtin_p, | |
11730 | CODE_FOR_mmulfx_l, "__builtin_sh_media_MMULFX_L", SH_BLTIN_V2SI3, 0 }, | |
11731 | { shmedia_builtin_p, | |
11732 | CODE_FOR_mmulfx_w, "__builtin_sh_media_MMULFX_W", SH_BLTIN_V4HI3, 0 }, | |
11733 | { shmedia_builtin_p, | |
11734 | CODE_FOR_mmulfxrp_w,"__builtin_sh_media_MMULFXRP_W", SH_BLTIN_V4HI3, 0 }, | |
11735 | { shmedia_builtin_p, | |
11736 | CODE_FOR_mmulhi_wl, "__builtin_sh_media_MMULHI_WL", SH_BLTIN_V4HI2V2SI, 0 }, | |
11737 | { shmedia_builtin_p, | |
11738 | CODE_FOR_mmullo_wl, "__builtin_sh_media_MMULLO_WL", SH_BLTIN_V4HI2V2SI, 0 }, | |
11739 | { shmedia_builtin_p, | |
11740 | CODE_FOR_mmulsum_wq,"__builtin_sh_media_MMULSUM_WQ", SH_BLTIN_XXUU, 0 }, | |
11741 | { shmedia_builtin_p, | |
11742 | CODE_FOR_mperm_w, "__builtin_sh_media_MPERM_W", SH_BLTIN_SH_HI, 0 }, | |
11743 | { shmedia_builtin_p, | |
11744 | CODE_FOR_msad_ubq, "__builtin_sh_media_MSAD_UBQ", SH_BLTIN_XXUU, 0 }, | |
11745 | { shmedia_builtin_p, | |
11746 | CODE_FOR_mshalds_l, "__builtin_sh_media_MSHALDS_L", SH_BLTIN_SH_SI, 0 }, | |
11747 | { shmedia_builtin_p, | |
11748 | CODE_FOR_mshalds_w, "__builtin_sh_media_MSHALDS_W", SH_BLTIN_SH_HI, 0 }, | |
11749 | { shmedia_builtin_p, | |
11750 | CODE_FOR_ashrv2si3, "__builtin_ashrv2si3", SH_BLTIN_SH_SI, 0 }, | |
11751 | { shmedia_builtin_p, | |
11752 | CODE_FOR_ashrv4hi3, "__builtin_ashrv4hi3", SH_BLTIN_SH_HI, 0 }, | |
11753 | { shmedia_builtin_p, | |
11754 | CODE_FOR_mshards_q, "__builtin_sh_media_MSHARDS_Q", SH_BLTIN_SUS, 0 }, | |
11755 | { shmedia_builtin_p, | |
11756 | CODE_FOR_mshfhi_b, "__builtin_sh_media_MSHFHI_B", SH_BLTIN_V8QI3, 0 }, | |
11757 | { shmedia_builtin_p, | |
11758 | CODE_FOR_mshfhi_l, "__builtin_sh_media_MSHFHI_L", SH_BLTIN_V2SI3, 0 }, | |
11759 | { shmedia_builtin_p, | |
11760 | CODE_FOR_mshfhi_w, "__builtin_sh_media_MSHFHI_W", SH_BLTIN_V4HI3, 0 }, | |
11761 | { shmedia_builtin_p, | |
11762 | CODE_FOR_mshflo_b, "__builtin_sh_media_MSHFLO_B", SH_BLTIN_V8QI3, 0 }, | |
11763 | { shmedia_builtin_p, | |
11764 | CODE_FOR_mshflo_l, "__builtin_sh_media_MSHFLO_L", SH_BLTIN_V2SI3, 0 }, | |
11765 | { shmedia_builtin_p, | |
11766 | CODE_FOR_mshflo_w, "__builtin_sh_media_MSHFLO_W", SH_BLTIN_V4HI3, 0 }, | |
11767 | { shmedia_builtin_p, | |
11768 | CODE_FOR_ashlv2si3, "__builtin_ashlv2si3", SH_BLTIN_SH_SI, 0 }, | |
11769 | { shmedia_builtin_p, | |
11770 | CODE_FOR_ashlv4hi3, "__builtin_ashlv4hi3", SH_BLTIN_SH_HI, 0 }, | |
11771 | { shmedia_builtin_p, | |
11772 | CODE_FOR_lshrv2si3, "__builtin_lshrv2si3", SH_BLTIN_SH_SI, 0 }, | |
11773 | { shmedia_builtin_p, | |
11774 | CODE_FOR_lshrv4hi3, "__builtin_lshrv4hi3", SH_BLTIN_SH_HI, 0 }, | |
11775 | { shmedia_builtin_p, | |
11776 | CODE_FOR_subv2si3, "__builtin_subv2si3", SH_BLTIN_V2SI3, 0 }, | |
11777 | { shmedia_builtin_p, | |
11778 | CODE_FOR_subv4hi3, "__builtin_subv4hi3", SH_BLTIN_V4HI3, 0 }, | |
11779 | { shmedia_builtin_p, | |
11780 | CODE_FOR_sssubv2si3,"__builtin_sssubv2si3", SH_BLTIN_V2SI3, 0 }, | |
11781 | { shmedia_builtin_p, | |
11782 | CODE_FOR_ussubv8qi3,"__builtin_ussubv8qi3", SH_BLTIN_V8QI3, 0 }, | |
11783 | { shmedia_builtin_p, | |
11784 | CODE_FOR_sssubv4hi3,"__builtin_sssubv4hi3", SH_BLTIN_V4HI3, 0 }, | |
11785 | { shmedia_builtin_p, | |
11786 | CODE_FOR_fcosa_s, "__builtin_sh_media_FCOSA_S", SH_BLTIN_SISF, 0 }, | |
11787 | { shmedia_builtin_p, | |
11788 | CODE_FOR_fsina_s, "__builtin_sh_media_FSINA_S", SH_BLTIN_SISF, 0 }, | |
11789 | { shmedia_builtin_p, | |
11790 | CODE_FOR_fipr, "__builtin_sh_media_FIPR_S", SH_BLTIN_3, 0 }, | |
11791 | { shmedia_builtin_p, | |
11792 | CODE_FOR_ftrv, "__builtin_sh_media_FTRV_S", SH_BLTIN_3, 0 }, | |
11793 | { shmedia_builtin_p, | |
11794 | CODE_FOR_sqrtdf2, "__builtin_sh_media_FSQRT_D", SH_BLTIN_2, 0 }, | |
11795 | { shmedia_builtin_p, | |
11796 | CODE_FOR_sqrtsf2, "__builtin_sh_media_FSQRT_S", SH_BLTIN_2, 0 }, | |
11797 | { shmedia_builtin_p, | |
11798 | CODE_FOR_fsrra_s, "__builtin_sh_media_FSRRA_S", SH_BLTIN_2, 0 }, | |
11799 | { shmedia_builtin_p, | |
11800 | CODE_FOR_ldhi_l, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L, 0 }, | |
11801 | { shmedia_builtin_p, | |
11802 | CODE_FOR_ldhi_q, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q, 0 }, | |
11803 | { shmedia_builtin_p, | |
11804 | CODE_FOR_ldlo_l, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L, 0 }, | |
11805 | { shmedia_builtin_p, | |
11806 | CODE_FOR_ldlo_q, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q, 0 }, | |
11807 | { shmedia_builtin_p, | |
11808 | CODE_FOR_sthi_l, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L, 0 }, | |
11809 | { shmedia_builtin_p, | |
11810 | CODE_FOR_sthi_q, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q, 0 }, | |
11811 | { shmedia_builtin_p, | |
11812 | CODE_FOR_stlo_l, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L, 0 }, | |
11813 | { shmedia_builtin_p, | |
11814 | CODE_FOR_stlo_q, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q, 0 }, | |
11815 | { shmedia_builtin_p, | |
11816 | CODE_FOR_ldhi_l64, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L64, 0 }, | |
11817 | { shmedia_builtin_p, | |
11818 | CODE_FOR_ldhi_q64, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q64, 0 }, | |
11819 | { shmedia_builtin_p, | |
11820 | CODE_FOR_ldlo_l64, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L64, 0 }, | |
11821 | { shmedia_builtin_p, | |
11822 | CODE_FOR_ldlo_q64, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q64, 0 }, | |
11823 | { shmedia_builtin_p, | |
11824 | CODE_FOR_sthi_l64, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L64, 0 }, | |
11825 | { shmedia_builtin_p, | |
11826 | CODE_FOR_sthi_q64, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q64, 0 }, | |
11827 | { shmedia_builtin_p, | |
11828 | CODE_FOR_stlo_l64, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L64, 0 }, | |
11829 | { shmedia_builtin_p, | |
11830 | CODE_FOR_stlo_q64, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q64, 0 }, | |
11831 | { shmedia_builtin_p, | |
11832 | CODE_FOR_nsb, "__builtin_sh_media_NSB", SH_BLTIN_SU, 0 }, | |
11833 | { shmedia_builtin_p, | |
11834 | CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 }, | |
11835 | { shmedia_builtin_p, | |
11836 | CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 }, | |
81298240 | 11837 | |
11838 | { sh1_builtin_p, | |
11839 | CODE_FOR_sts_fpscr, "__builtin_sh_get_fpscr", SH_BLTIN_UV, 0 }, | |
11840 | { sh1_builtin_p, | |
11841 | CODE_FOR_set_fpscr, "__builtin_sh_set_fpscr", SH_BLTIN_VU, 0 }, | |
e3fac27d | 11842 | }; |
11843 | ||
11844 | static void | |
70695242 | 11845 | sh_init_builtins (void) |
e3fac27d | 11846 | { |
11847 | tree shared[SH_BLTIN_NUM_SHARED_SIGNATURES]; | |
c5006c15 | 11848 | memset (shared, 0, sizeof shared); |
70695242 | 11849 | |
11850 | for (unsigned int di = 0; di < ARRAY_SIZE (bdesc); ++di) | |
e3fac27d | 11851 | { |
70695242 | 11852 | builtin_description* d = &bdesc[di]; |
11853 | ||
11854 | if (!d->is_enabled ()) | |
11855 | continue; | |
11856 | ||
11857 | tree type, arg_type = NULL_TREE; | |
e3fac27d | 11858 | int signature = d->signature; |
e3fac27d | 11859 | |
11860 | if (signature < SH_BLTIN_NUM_SHARED_SIGNATURES && shared[signature]) | |
11861 | type = shared[signature]; | |
11862 | else | |
11863 | { | |
11864 | int has_result = signature_args[signature][0] != 0; | |
03e08c98 | 11865 | tree args[3]; |
e3fac27d | 11866 | |
59312820 | 11867 | if ((signature_args[signature][1] & 8) |
11868 | && (((signature_args[signature][1] & 1) && TARGET_SHMEDIA32) | |
11869 | || ((signature_args[signature][1] & 2) && TARGET_SHMEDIA64))) | |
e3fac27d | 11870 | continue; |
11871 | if (! TARGET_FPU_ANY | |
11872 | && FLOAT_MODE_P (insn_data[d->icode].operand[0].mode)) | |
11873 | continue; | |
70695242 | 11874 | for (unsigned int i = 0; i < ARRAY_SIZE (args); i++) |
03e08c98 | 11875 | args[i] = NULL_TREE; |
70695242 | 11876 | for (int i = 3; ; i--) |
e3fac27d | 11877 | { |
11878 | int arg = signature_args[signature][i]; | |
11879 | int opno = i - 1 + has_result; | |
11880 | ||
59312820 | 11881 | if (arg & 8) |
e3fac27d | 11882 | arg_type = ptr_type_node; |
11883 | else if (arg) | |
59312820 | 11884 | arg_type = (*lang_hooks.types.type_for_mode) |
70695242 | 11885 | (insn_data[d->icode].operand[opno].mode, (arg & 1)); |
e3fac27d | 11886 | else if (i) |
11887 | continue; | |
11888 | else | |
11889 | arg_type = void_type_node; | |
11890 | if (i == 0) | |
11891 | break; | |
03e08c98 | 11892 | args[i-1] = arg_type; |
e3fac27d | 11893 | } |
03e08c98 | 11894 | type = build_function_type_list (arg_type, args[0], args[1], |
11895 | args[2], NULL_TREE); | |
e3fac27d | 11896 | if (signature < SH_BLTIN_NUM_SHARED_SIGNATURES) |
11897 | shared[signature] = type; | |
11898 | } | |
3213bdbf | 11899 | d->fndecl = |
11900 | add_builtin_function (d->name, type, d - bdesc, BUILT_IN_MD, | |
11901 | NULL, NULL_TREE); | |
e3fac27d | 11902 | } |
11903 | } | |
11904 | ||
9e7454d0 | 11905 | /* Implements target hook vector_mode_supported_p. */ |
11906 | bool | |
3754d046 | 11907 | sh_vector_mode_supported_p (machine_mode mode) |
9e7454d0 | 11908 | { |
11909 | if (TARGET_FPU_ANY | |
11910 | && ((mode == V2SFmode) | |
11911 | || (mode == V4SFmode) | |
11912 | || (mode == V16SFmode))) | |
11913 | return true; | |
11914 | ||
11915 | else if (TARGET_SHMEDIA | |
11916 | && ((mode == V8QImode) | |
11917 | || (mode == V2HImode) | |
11918 | || (mode == V4HImode) | |
11919 | || (mode == V2SImode))) | |
11920 | return true; | |
11921 | ||
11922 | return false; | |
11923 | } | |
11924 | ||
992d172c | 11925 | bool |
11926 | sh_frame_pointer_required (void) | |
11927 | { | |
11928 | /* If needed override this in other tm.h files to cope with various OS | |
11929 | lossage requiring a frame pointer. */ | |
11930 | if (SUBTARGET_FRAME_POINTER_REQUIRED) | |
11931 | return true; | |
11932 | ||
11933 | if (crtl->profile) | |
11934 | return true; | |
11935 | ||
11936 | return false; | |
11937 | } | |
11938 | ||
8ff30ff6 | 11939 | /* Implements target hook dwarf_calling_convention. Return an enum |
11940 | of dwarf_calling_convention. */ | |
11941 | int | |
a9f1838b | 11942 | sh_dwarf_calling_convention (const_tree func) |
8ff30ff6 | 11943 | { |
11944 | if (sh_attr_renesas_p (func)) | |
7126085a | 11945 | return DW_CC_GNU_renesas_sh; |
8ff30ff6 | 11946 | |
11947 | return DW_CC_normal; | |
11948 | } | |
11949 | ||
3213bdbf | 11950 | /* Returns the sh builtin decl for CODE. */ |
3213bdbf | 11951 | static tree |
11952 | sh_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) | |
70695242 | 11953 | { |
11954 | if (code >= ARRAY_SIZE (bdesc)) | |
11955 | return error_mark_node; | |
11956 | ||
11957 | if (!bdesc[code].is_enabled ()) | |
11958 | return error_mark_node; | |
11959 | ||
11960 | return bdesc[code].fndecl; | |
3213bdbf | 11961 | } |
11962 | ||
e3fac27d | 11963 | /* Expand an expression EXP that calls a built-in function, |
11964 | with result going to TARGET if that's convenient | |
11965 | (and in mode MODE if that's convenient). | |
11966 | SUBTARGET may be used as the target for computing one of EXP's operands. | |
11967 | IGNORE is nonzero if the value is to be ignored. */ | |
e3fac27d | 11968 | static rtx |
04f04b72 | 11969 | sh_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED, |
3754d046 | 11970 | machine_mode mode ATTRIBUTE_UNUSED, int ignore) |
e3fac27d | 11971 | { |
c2f47e15 | 11972 | tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); |
e3fac27d | 11973 | unsigned int fcode = DECL_FUNCTION_CODE (fndecl); |
11974 | const struct builtin_description *d = &bdesc[fcode]; | |
11975 | enum insn_code icode = d->icode; | |
11976 | int signature = d->signature; | |
70695242 | 11977 | int nop = 0; |
e3fac27d | 11978 | rtx op[4]; |
e3fac27d | 11979 | |
11980 | if (signature_args[signature][0]) | |
11981 | { | |
11982 | if (ignore) | |
c3583c9c | 11983 | return NULL_RTX; |
e3fac27d | 11984 | |
3754d046 | 11985 | machine_mode tmode = insn_data[icode].operand[0].mode; |
70695242 | 11986 | if (! target || GET_MODE (target) != tmode |
e3fac27d | 11987 | || ! (*insn_data[icode].operand[0].predicate) (target, tmode)) |
11988 | target = gen_reg_rtx (tmode); | |
11989 | op[nop++] = target; | |
11990 | } | |
11991 | else | |
70695242 | 11992 | target = NULL_RTX; |
e3fac27d | 11993 | |
70695242 | 11994 | for (int i = 1; i <= 3; i++, nop++) |
e3fac27d | 11995 | { |
11996 | tree arg; | |
3754d046 | 11997 | machine_mode opmode, argmode; |
59312820 | 11998 | tree optype; |
e3fac27d | 11999 | |
12000 | if (! signature_args[signature][i]) | |
12001 | break; | |
c2f47e15 | 12002 | arg = CALL_EXPR_ARG (exp, i - 1); |
dec9884d | 12003 | if (arg == error_mark_node) |
12004 | return const0_rtx; | |
59312820 | 12005 | if (signature_args[signature][i] & 8) |
12006 | { | |
12007 | opmode = ptr_mode; | |
12008 | optype = ptr_type_node; | |
12009 | } | |
12010 | else | |
12011 | { | |
12012 | opmode = insn_data[icode].operand[nop].mode; | |
12013 | optype = (*lang_hooks.types.type_for_mode) (opmode, 0); | |
12014 | } | |
e3fac27d | 12015 | argmode = TYPE_MODE (TREE_TYPE (arg)); |
12016 | if (argmode != opmode) | |
59312820 | 12017 | arg = build1 (NOP_EXPR, optype, arg); |
6f2543f8 | 12018 | op[nop] = expand_expr (arg, NULL_RTX, opmode, EXPAND_NORMAL); |
e3fac27d | 12019 | if (! (*insn_data[icode].operand[nop].predicate) (op[nop], opmode)) |
12020 | op[nop] = copy_to_mode_reg (opmode, op[nop]); | |
12021 | } | |
12022 | ||
70695242 | 12023 | rtx pat = NULL_RTX; |
12024 | ||
e3fac27d | 12025 | switch (nop) |
12026 | { | |
12027 | case 1: | |
12028 | pat = (*insn_data[d->icode].genfun) (op[0]); | |
12029 | break; | |
12030 | case 2: | |
12031 | pat = (*insn_data[d->icode].genfun) (op[0], op[1]); | |
12032 | break; | |
12033 | case 3: | |
12034 | pat = (*insn_data[d->icode].genfun) (op[0], op[1], op[2]); | |
12035 | break; | |
12036 | case 4: | |
12037 | pat = (*insn_data[d->icode].genfun) (op[0], op[1], op[2], op[3]); | |
12038 | break; | |
83b35a61 | 12039 | default: |
1a6a7a27 | 12040 | gcc_unreachable (); |
e3fac27d | 12041 | } |
12042 | if (! pat) | |
c3583c9c | 12043 | return NULL_RTX; |
e3fac27d | 12044 | emit_insn (pat); |
12045 | return target; | |
12046 | } | |
d3b29bbd | 12047 | |
12048 | void | |
04f04b72 | 12049 | sh_expand_unop_v2sf (enum rtx_code code, rtx op0, rtx op1) |
d3b29bbd | 12050 | { |
12051 | rtx sel0 = const0_rtx; | |
12052 | rtx sel1 = const1_rtx; | |
04f04b72 | 12053 | rtx (*fn) (rtx, rtx, rtx, rtx, rtx) = gen_unary_sf_op; |
d3b29bbd | 12054 | rtx op = gen_rtx_fmt_e (code, SFmode, op1); |
12055 | ||
12056 | emit_insn ((*fn) (op0, op1, op, sel0, sel0)); | |
12057 | emit_insn ((*fn) (op0, op1, op, sel1, sel1)); | |
12058 | } | |
12059 | ||
12060 | void | |
04f04b72 | 12061 | sh_expand_binop_v2sf (enum rtx_code code, rtx op0, rtx op1, rtx op2) |
d3b29bbd | 12062 | { |
d3b29bbd | 12063 | rtx op = gen_rtx_fmt_ee (code, SFmode, op1, op2); |
12064 | ||
0c527910 | 12065 | emit_insn (gen_binary_sf_op0 (op0, op1, op2, op)); |
12066 | emit_insn (gen_binary_sf_op1 (op0, op1, op2, op)); | |
d3b29bbd | 12067 | } |
12068 | ||
32e68083 | 12069 | /* Return true if hard register REGNO can hold a value of machine-mode MODE. |
12070 | We can allow any mode in any general register. The special registers | |
12071 | only allow SImode. Don't allow any mode in the PR. | |
12072 | ||
12073 | We cannot hold DCmode values in the XD registers because alter_reg | |
12074 | handles subregs of them incorrectly. We could work around this by | |
12075 | spacing the XD registers like the DR registers, but this would require | |
12076 | additional memory in every compilation to hold larger register vectors. | |
12077 | We could hold SFmode / SCmode values in XD registers, but that | |
12078 | would require a tertiary reload when reloading from / to memory, | |
12079 | and a secondary reload to reload from / to general regs; that | |
9d75589a | 12080 | seems to be a losing proposition. |
32e68083 | 12081 | |
12082 | We want to allow TImode FP regs so that when V4SFmode is loaded as TImode, | |
12083 | it won't be ferried through GP registers first. */ | |
32e68083 | 12084 | bool |
3754d046 | 12085 | sh_hard_regno_mode_ok (unsigned int regno, machine_mode mode) |
32e68083 | 12086 | { |
12087 | if (SPECIAL_REGISTER_P (regno)) | |
12088 | return mode == SImode; | |
12089 | ||
12090 | if (regno == FPUL_REG) | |
12091 | return (mode == SImode || mode == SFmode); | |
12092 | ||
12093 | if (FP_REGISTER_P (regno) && mode == SFmode) | |
12094 | return true; | |
12095 | ||
12096 | if (mode == V2SFmode) | |
12097 | { | |
12098 | if (((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 2 == 0) | |
12099 | || GENERAL_REGISTER_P (regno))) | |
12100 | return true; | |
12101 | else | |
12102 | return false; | |
12103 | } | |
12104 | ||
12105 | if (mode == V4SFmode) | |
12106 | { | |
12107 | if ((FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 4 == 0) | |
12108 | || GENERAL_REGISTER_P (regno)) | |
12109 | return true; | |
12110 | else | |
12111 | return false; | |
12112 | } | |
12113 | ||
12114 | if (mode == V16SFmode) | |
12115 | { | |
12116 | if (TARGET_SHMEDIA) | |
12117 | { | |
12118 | if (FP_REGISTER_P (regno) && (regno - FIRST_FP_REG) % 16 == 0) | |
12119 | return true; | |
12120 | else | |
12121 | return false; | |
12122 | } | |
12123 | else | |
12124 | return regno == FIRST_XD_REG; | |
12125 | } | |
12126 | ||
12127 | if (FP_REGISTER_P (regno)) | |
12128 | { | |
12129 | if (mode == SFmode | |
12130 | || mode == SImode | |
12131 | || ((TARGET_SH2E || TARGET_SHMEDIA) && mode == SCmode) | |
12132 | || ((((TARGET_SH4 || TARGET_SH2A_DOUBLE) && mode == DFmode) | |
12133 | || mode == DCmode | |
12134 | || (TARGET_SHMEDIA | |
12135 | && (mode == DFmode || mode == DImode | |
12136 | || mode == V2SFmode || mode == TImode))) | |
12137 | && ((regno - FIRST_FP_REG) & 1) == 0) | |
12138 | || ((TARGET_SH4 || TARGET_SHMEDIA) && mode == TImode | |
12139 | && ((regno - FIRST_FP_REG) & 3) == 0)) | |
12140 | return true; | |
12141 | else | |
12142 | return false; | |
12143 | } | |
12144 | ||
12145 | if (XD_REGISTER_P (regno)) | |
12146 | return mode == DFmode; | |
12147 | ||
12148 | if (TARGET_REGISTER_P (regno)) | |
12149 | return (mode == DImode || mode == SImode || mode == PDImode); | |
12150 | ||
12151 | if (regno == PR_REG) | |
12152 | return mode == SImode; | |
12153 | ||
12154 | if (regno == FPSCR_REG) | |
81298240 | 12155 | return mode == SImode; |
32e68083 | 12156 | |
12157 | /* FIXME. This works around PR target/37633 for -O0. */ | |
12158 | if (!optimize && TARGET_SHMEDIA32 && GET_MODE_SIZE (mode) > 4) | |
12159 | { | |
12160 | unsigned int n = GET_MODE_SIZE (mode) / 8; | |
12161 | ||
12162 | if (regno >= FIRST_GENERAL_REG + 10 - n + 1 | |
12163 | && regno <= FIRST_GENERAL_REG + 14) | |
12164 | return false; | |
12165 | } | |
12166 | ||
12167 | return true; | |
12168 | } | |
12169 | ||
897118e8 | 12170 | /* Return the class of registers for which a mode change from FROM to TO |
12171 | is invalid. */ | |
22aae821 | 12172 | bool |
3754d046 | 12173 | sh_cannot_change_mode_class (machine_mode from, machine_mode to, |
8deb3959 | 12174 | enum reg_class rclass) |
897118e8 | 12175 | { |
9435e831 | 12176 | /* We want to enable the use of SUBREGs as a means to |
12177 | VEC_SELECT a single element of a vector. */ | |
89cace00 | 12178 | |
12179 | /* This effectively disallows using GENERAL_REGS for SFmode vector subregs. | |
12180 | This can be problematic when SFmode vector subregs need to be accessed | |
12181 | on the stack with displacement addressing, as it happens with -O0. | |
12182 | Thus we disallow the mode change for -O0. */ | |
9435e831 | 12183 | if (to == SFmode && VECTOR_MODE_P (from) && GET_MODE_INNER (from) == SFmode) |
89cace00 | 12184 | return optimize ? (reg_classes_intersect_p (GENERAL_REGS, rclass)) : false; |
9435e831 | 12185 | |
897118e8 | 12186 | if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to)) |
12187 | { | |
d767e27e | 12188 | if (TARGET_LITTLE_ENDIAN) |
12189 | { | |
12190 | if (GET_MODE_SIZE (to) < 8 || GET_MODE_SIZE (from) < 8) | |
8deb3959 | 12191 | return reg_classes_intersect_p (DF_REGS, rclass); |
d767e27e | 12192 | } |
12193 | else | |
12194 | { | |
12195 | if (GET_MODE_SIZE (from) < 8) | |
ec3c739c | 12196 | return reg_classes_intersect_p (DF_REGS, rclass); |
d767e27e | 12197 | } |
897118e8 | 12198 | } |
89cace00 | 12199 | return false; |
897118e8 | 12200 | } |
12201 | ||
ed5527ca | 12202 | /* Return true if registers in machine mode MODE will likely be |
12203 | allocated to registers in small register classes. */ | |
1d45023e | 12204 | bool |
3754d046 | 12205 | sh_small_register_classes_for_mode_p (machine_mode mode ATTRIBUTE_UNUSED) |
ed5527ca | 12206 | { |
12207 | return (! TARGET_SHMEDIA); | |
12208 | } | |
33946087 | 12209 | |
12210 | /* If ADDRESS refers to a CODE_LABEL, add NUSES to the number of times | |
12211 | that label is used. */ | |
33946087 | 12212 | void |
04f04b72 | 12213 | sh_mark_label (rtx address, int nuses) |
33946087 | 12214 | { |
12215 | if (GOTOFF_P (address)) | |
12216 | { | |
12217 | /* Extract the label or symbol. */ | |
12218 | address = XEXP (address, 0); | |
12219 | if (GET_CODE (address) == PLUS) | |
12220 | address = XEXP (address, 0); | |
12221 | address = XVECEXP (address, 0, 0); | |
12222 | } | |
12223 | if (GET_CODE (address) == LABEL_REF | |
cbb16986 | 12224 | && LABEL_P (XEXP (address, 0))) |
33946087 | 12225 | LABEL_NUSES (XEXP (address, 0)) += nuses; |
12226 | } | |
12227 | ||
83b35a61 | 12228 | /* Compute extra cost of moving data between one register class |
6c049e03 | 12229 | and another. |
83b35a61 | 12230 | |
6c049e03 | 12231 | If SECONDARY*_RELOAD_CLASS says something about the src/dst pair, regclass |
e04da7b6 | 12232 | uses this information. Hence, the general register <-> floating point |
83b35a61 | 12233 | register information here is not used for SFmode. */ |
eb9063bf | 12234 | static int |
3754d046 | 12235 | sh_register_move_cost (machine_mode mode, |
eb9063bf | 12236 | reg_class_t srcclass, reg_class_t dstclass) |
83b35a61 | 12237 | { |
12238 | if (dstclass == T_REGS || dstclass == PR_REGS) | |
12239 | return 10; | |
12240 | ||
f9afdd51 | 12241 | if (dstclass == MAC_REGS && srcclass == MAC_REGS) |
12242 | return 4; | |
12243 | ||
e04da7b6 | 12244 | if (mode == SImode && ! TARGET_SHMEDIA && TARGET_FMOVD |
12245 | && REGCLASS_HAS_FP_REG (srcclass) | |
12246 | && REGCLASS_HAS_FP_REG (dstclass)) | |
12247 | return 4; | |
12248 | ||
b7e76f11 | 12249 | if (REGCLASS_HAS_FP_REG (dstclass) && srcclass == T_REGS) |
12250 | return ((TARGET_HARD_SH4 && !optimize_size) ? 10 : 7); | |
12251 | ||
0ec45dc1 | 12252 | if ((REGCLASS_HAS_FP_REG (dstclass) && srcclass == MAC_REGS) |
d767e27e | 12253 | || (dstclass == MAC_REGS && REGCLASS_HAS_FP_REG (srcclass))) |
0ec45dc1 | 12254 | return 9; |
12255 | ||
83b35a61 | 12256 | if ((REGCLASS_HAS_FP_REG (dstclass) |
12257 | && REGCLASS_HAS_GENERAL_REG (srcclass)) | |
12258 | || (REGCLASS_HAS_GENERAL_REG (dstclass) | |
12259 | && REGCLASS_HAS_FP_REG (srcclass))) | |
07732170 | 12260 | { |
12261 | /* Discourage trying to use fp regs for a pointer. This also | |
12262 | discourages fp regs with SImode because Pmode is an alias | |
12263 | of SImode on this target. See PR target/48596. */ | |
12264 | int addend = (mode == Pmode) ? 40 : 0; | |
12265 | ||
12266 | return (((TARGET_SHMEDIA ? 4 : TARGET_FMOVD ? 8 : 12) + addend) | |
12267 | * ((GET_MODE_SIZE (mode) + 7) / 8U)); | |
12268 | } | |
83b35a61 | 12269 | |
12270 | if ((dstclass == FPUL_REGS | |
12271 | && REGCLASS_HAS_GENERAL_REG (srcclass)) | |
12272 | || (srcclass == FPUL_REGS | |
12273 | && REGCLASS_HAS_GENERAL_REG (dstclass))) | |
12274 | return 5; | |
12275 | ||
12276 | if ((dstclass == FPUL_REGS | |
12277 | && (srcclass == PR_REGS || srcclass == MAC_REGS || srcclass == T_REGS)) | |
9e7454d0 | 12278 | || (srcclass == FPUL_REGS |
83b35a61 | 12279 | && (dstclass == PR_REGS || dstclass == MAC_REGS))) |
12280 | return 7; | |
12281 | ||
12282 | if ((srcclass == TARGET_REGS && ! REGCLASS_HAS_GENERAL_REG (dstclass)) | |
12283 | || ((dstclass) == TARGET_REGS && ! REGCLASS_HAS_GENERAL_REG (srcclass))) | |
12284 | return 20; | |
12285 | ||
59312820 | 12286 | /* ??? ptabs faults on (value & 0x3) == 0x3 */ |
12287 | if (TARGET_SHMEDIA | |
12288 | && ((srcclass) == TARGET_REGS || (srcclass) == SIBCALL_REGS)) | |
12289 | { | |
4906bcbb | 12290 | if (sh_gettrcost >= 0) |
12291 | return sh_gettrcost; | |
59312820 | 12292 | else if (!TARGET_PT_FIXED) |
12293 | return 100; | |
12294 | } | |
12295 | ||
83b35a61 | 12296 | if ((srcclass == FPSCR_REGS && ! REGCLASS_HAS_GENERAL_REG (dstclass)) |
12297 | || (dstclass == FPSCR_REGS && ! REGCLASS_HAS_GENERAL_REG (srcclass))) | |
12298 | return 4; | |
12299 | ||
e04da7b6 | 12300 | if (TARGET_SHMEDIA |
12301 | || (TARGET_FMOVD | |
12302 | && ! REGCLASS_HAS_GENERAL_REG (srcclass) | |
12303 | && ! REGCLASS_HAS_GENERAL_REG (dstclass))) | |
12304 | return 2 * ((GET_MODE_SIZE (mode) + 7) / 8U); | |
12305 | ||
12306 | return 2 * ((GET_MODE_SIZE (mode) + 3) / 4U); | |
83b35a61 | 12307 | } |
12308 | ||
c83ee613 | 12309 | static rtx |
04f04b72 | 12310 | emit_load_ptr (rtx reg, rtx addr) |
c83ee613 | 12311 | { |
aa7e75f2 | 12312 | rtx mem = gen_const_mem (ptr_mode, addr); |
c83ee613 | 12313 | |
12314 | if (Pmode != ptr_mode) | |
12315 | mem = gen_rtx_SIGN_EXTEND (Pmode, mem); | |
12316 | return emit_move_insn (reg, mem); | |
12317 | } | |
12318 | ||
59312820 | 12319 | static void |
04f04b72 | 12320 | sh_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, |
12321 | HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset, | |
12322 | tree function) | |
c83ee613 | 12323 | { |
12324 | CUMULATIVE_ARGS cum; | |
12325 | int structure_value_byref = 0; | |
b82334f7 | 12326 | rtx this_rtx, this_value, sibcall, funexp; |
12327 | rtx_insn *insns; | |
c83ee613 | 12328 | tree funtype = TREE_TYPE (function); |
af2c1324 | 12329 | int simple_add = CONST_OK_FOR_ADD (delta); |
c83ee613 | 12330 | int did_load = 0; |
12331 | rtx scratch0, scratch1, scratch2; | |
59312820 | 12332 | unsigned i; |
c83ee613 | 12333 | |
12334 | reload_completed = 1; | |
8af3db02 | 12335 | epilogue_completed = 1; |
d5bf7b64 | 12336 | crtl->uses_only_leaf_regs = 1; |
c83ee613 | 12337 | |
31b97e8f | 12338 | emit_note (NOTE_INSN_PROLOGUE_END); |
c83ee613 | 12339 | |
12340 | /* Find the "this" pointer. We have such a wide range of ABIs for the | |
12341 | SH that it's best to do this completely machine independently. | |
9e7454d0 | 12342 | "this" is passed as first argument, unless a structure return pointer |
c83ee613 | 12343 | comes first, in which case "this" comes second. */ |
30c70355 | 12344 | INIT_CUMULATIVE_ARGS (cum, funtype, NULL_RTX, 0, 1); |
c83ee613 | 12345 | #ifndef PCC_STATIC_STRUCT_RETURN |
45550790 | 12346 | if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) |
c83ee613 | 12347 | structure_value_byref = 1; |
12348 | #endif /* not PCC_STATIC_STRUCT_RETURN */ | |
45550790 | 12349 | if (structure_value_byref && sh_struct_value_rtx (function, 0) == 0) |
9e7454d0 | 12350 | { |
c83ee613 | 12351 | tree ptype = build_pointer_type (TREE_TYPE (funtype)); |
12352 | ||
39cba157 | 12353 | sh_function_arg_advance (pack_cumulative_args (&cum), Pmode, ptype, true); |
c83ee613 | 12354 | } |
39cba157 | 12355 | this_rtx |
12356 | = sh_function_arg (pack_cumulative_args (&cum), Pmode, ptr_type_node, true); | |
c83ee613 | 12357 | |
12358 | /* For SHcompact, we only have r0 for a scratch register: r1 is the | |
12359 | static chain pointer (even if you can't have nested virtual functions | |
12360 | right now, someone might implement them sometime), and the rest of the | |
12361 | registers are used for argument passing, are callee-saved, or reserved. */ | |
59312820 | 12362 | /* We need to check call_used_regs / fixed_regs in case -fcall_saved-reg / |
12363 | -ffixed-reg has been used. */ | |
12364 | if (! call_used_regs[0] || fixed_regs[0]) | |
12365 | error ("r0 needs to be available as a call-clobbered register"); | |
c83ee613 | 12366 | scratch0 = scratch1 = scratch2 = gen_rtx_REG (Pmode, 0); |
12367 | if (! TARGET_SH5) | |
12368 | { | |
59312820 | 12369 | if (call_used_regs[1] && ! fixed_regs[1]) |
12370 | scratch1 = gen_rtx_REG (ptr_mode, 1); | |
c83ee613 | 12371 | /* N.B., if not TARGET_HITACHI, register 2 is used to pass the pointer |
12372 | pointing where to return struct values. */ | |
59312820 | 12373 | if (call_used_regs[3] && ! fixed_regs[3]) |
12374 | scratch2 = gen_rtx_REG (Pmode, 3); | |
c83ee613 | 12375 | } |
12376 | else if (TARGET_SHMEDIA) | |
12377 | { | |
59312820 | 12378 | for (i = FIRST_GENERAL_REG; i <= LAST_GENERAL_REG; i++) |
12379 | if (i != REGNO (scratch0) && | |
12380 | call_used_regs[i] && ! fixed_regs[i] && ! FUNCTION_ARG_REGNO_P (i)) | |
12381 | { | |
12382 | scratch1 = gen_rtx_REG (ptr_mode, i); | |
12383 | break; | |
12384 | } | |
12385 | if (scratch1 == scratch0) | |
bf776685 | 12386 | error ("need a second call-clobbered general purpose register"); |
59312820 | 12387 | for (i = FIRST_TARGET_REG; i <= LAST_TARGET_REG; i++) |
12388 | if (call_used_regs[i] && ! fixed_regs[i]) | |
12389 | { | |
12390 | scratch2 = gen_rtx_REG (Pmode, i); | |
12391 | break; | |
12392 | } | |
12393 | if (scratch2 == scratch0) | |
bf776685 | 12394 | error ("need a call-clobbered target register"); |
c83ee613 | 12395 | } |
12396 | ||
29c05e22 | 12397 | this_value = plus_constant (Pmode, this_rtx, delta); |
c83ee613 | 12398 | if (vcall_offset |
12399 | && (simple_add || scratch0 != scratch1) | |
12400 | && strict_memory_address_p (ptr_mode, this_value)) | |
12401 | { | |
12402 | emit_load_ptr (scratch0, this_value); | |
12403 | did_load = 1; | |
12404 | } | |
12405 | ||
12406 | if (!delta) | |
12407 | ; /* Do nothing. */ | |
12408 | else if (simple_add) | |
8deb3959 | 12409 | emit_move_insn (this_rtx, this_value); |
c83ee613 | 12410 | else |
12411 | { | |
12412 | emit_move_insn (scratch1, GEN_INT (delta)); | |
8deb3959 | 12413 | emit_insn (gen_add2_insn (this_rtx, scratch1)); |
c83ee613 | 12414 | } |
12415 | ||
12416 | if (vcall_offset) | |
12417 | { | |
12418 | rtx offset_addr; | |
12419 | ||
12420 | if (!did_load) | |
8deb3959 | 12421 | emit_load_ptr (scratch0, this_rtx); |
c83ee613 | 12422 | |
29c05e22 | 12423 | offset_addr = plus_constant (Pmode, scratch0, vcall_offset); |
c83ee613 | 12424 | if (strict_memory_address_p (ptr_mode, offset_addr)) |
12425 | ; /* Do nothing. */ | |
59312820 | 12426 | else if (! TARGET_SH5 && scratch0 != scratch1) |
c83ee613 | 12427 | { |
12428 | /* scratch0 != scratch1, and we have indexed loads. Get better | |
12429 | schedule by loading the offset into r1 and using an indexed | |
12430 | load - then the load of r1 can issue before the load from | |
6c049e03 | 12431 | (this_rtx + delta) finishes. */ |
c83ee613 | 12432 | emit_move_insn (scratch1, GEN_INT (vcall_offset)); |
12433 | offset_addr = gen_rtx_PLUS (Pmode, scratch0, scratch1); | |
12434 | } | |
af2c1324 | 12435 | else if (CONST_OK_FOR_ADD (vcall_offset)) |
c83ee613 | 12436 | { |
12437 | emit_insn (gen_add2_insn (scratch0, GEN_INT (vcall_offset))); | |
12438 | offset_addr = scratch0; | |
12439 | } | |
12440 | else if (scratch0 != scratch1) | |
12441 | { | |
12442 | emit_move_insn (scratch1, GEN_INT (vcall_offset)); | |
12443 | emit_insn (gen_add2_insn (scratch0, scratch1)); | |
12444 | offset_addr = scratch0; | |
12445 | } | |
12446 | else | |
1a6a7a27 | 12447 | gcc_unreachable (); /* FIXME */ |
c83ee613 | 12448 | emit_load_ptr (scratch0, offset_addr); |
12449 | ||
d767e27e | 12450 | if (Pmode != ptr_mode) |
c83ee613 | 12451 | scratch0 = gen_rtx_TRUNCATE (ptr_mode, scratch0); |
8deb3959 | 12452 | emit_insn (gen_add2_insn (this_rtx, scratch0)); |
c83ee613 | 12453 | } |
12454 | ||
12455 | /* Generate a tail call to the target function. */ | |
12456 | if (! TREE_USED (function)) | |
12457 | { | |
12458 | assemble_external (function); | |
12459 | TREE_USED (function) = 1; | |
12460 | } | |
12461 | funexp = XEXP (DECL_RTL (function), 0); | |
59312820 | 12462 | /* If the function is overridden, so is the thunk, hence we don't |
12463 | need GOT addressing even if this is a public symbol. */ | |
12464 | #if 0 | |
12465 | if (TARGET_SH1 && ! flag_weak) | |
12466 | sibcall = gen_sibcalli_thunk (funexp, const0_rtx); | |
12467 | else | |
12468 | #endif | |
12469 | if (TARGET_SH2 && flag_pic) | |
12470 | { | |
12471 | sibcall = gen_sibcall_pcrel (funexp, const0_rtx); | |
12472 | XEXP (XVECEXP (sibcall, 0, 2), 0) = scratch2; | |
12473 | } | |
12474 | else | |
12475 | { | |
12476 | if (TARGET_SHMEDIA && flag_pic) | |
12477 | { | |
12478 | funexp = gen_sym2PIC (funexp); | |
12479 | PUT_MODE (funexp, Pmode); | |
12480 | } | |
12481 | emit_move_insn (scratch2, funexp); | |
12482 | funexp = gen_rtx_MEM (FUNCTION_MODE, scratch2); | |
12483 | sibcall = gen_sibcall (funexp, const0_rtx, NULL_RTX); | |
12484 | } | |
12485 | sibcall = emit_call_insn (sibcall); | |
c83ee613 | 12486 | SIBLING_CALL_P (sibcall) = 1; |
8deb3959 | 12487 | use_reg (&CALL_INSN_FUNCTION_USAGE (sibcall), this_rtx); |
c83ee613 | 12488 | emit_barrier (); |
12489 | ||
50494502 | 12490 | /* Run just enough of rest_of_compilation to do scheduling and get |
c83ee613 | 12491 | the insns emitted. Note that use_thunk calls |
12492 | assemble_start_function and assemble_end_function. */ | |
50494502 | 12493 | |
c83ee613 | 12494 | insns = get_insns (); |
12495 | ||
3072d30e | 12496 | if (optimize > 0) |
12497 | { | |
12498 | if (! cfun->cfg) | |
42073dec | 12499 | init_flow (cfun); |
3072d30e | 12500 | split_all_insns_noflow (); |
12501 | } | |
c83ee613 | 12502 | |
2efea8c0 | 12503 | sh_reorg (); |
c83ee613 | 12504 | shorten_branches (insns); |
12505 | final_start_function (insns, file, 1); | |
4bf029b0 | 12506 | final (insns, file, 1); |
c83ee613 | 12507 | final_end_function (); |
12508 | ||
c83ee613 | 12509 | reload_completed = 0; |
8af3db02 | 12510 | epilogue_completed = 0; |
c83ee613 | 12511 | } |
12512 | ||
45271277 | 12513 | rtx |
59312820 | 12514 | function_symbol (rtx target, const char *name, enum sh_function_kind kind) |
45271277 | 12515 | { |
59312820 | 12516 | rtx sym; |
12517 | ||
12518 | /* If this is not an ordinary function, the name usually comes from a | |
12519 | string literal or an sprintf buffer. Make sure we use the same | |
12520 | string consistently, so that cse will be able to unify address loads. */ | |
12521 | if (kind != FUNCTION_ORDINARY) | |
12522 | name = IDENTIFIER_POINTER (get_identifier (name)); | |
12523 | sym = gen_rtx_SYMBOL_REF (Pmode, name); | |
45271277 | 12524 | SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION; |
59312820 | 12525 | if (flag_pic) |
12526 | switch (kind) | |
12527 | { | |
12528 | case FUNCTION_ORDINARY: | |
12529 | break; | |
12530 | case SFUNC_GOT: | |
12531 | { | |
12532 | rtx reg = target ? target : gen_reg_rtx (Pmode); | |
12533 | ||
12534 | emit_insn (gen_symGOT2reg (reg, sym)); | |
12535 | sym = reg; | |
12536 | break; | |
12537 | } | |
12538 | case SFUNC_STATIC: | |
12539 | { | |
12540 | /* ??? To allow cse to work, we use GOTOFF relocations. | |
6c049e03 | 12541 | We could add combiner patterns to transform this into |
59312820 | 12542 | straight pc-relative calls with sym2PIC / bsrf when |
12543 | label load and function call are still 1:1 and in the | |
12544 | same basic block during combine. */ | |
12545 | rtx reg = target ? target : gen_reg_rtx (Pmode); | |
12546 | ||
12547 | emit_insn (gen_symGOTOFF2reg (reg, sym)); | |
12548 | sym = reg; | |
12549 | break; | |
12550 | } | |
12551 | } | |
12552 | if (target && sym != target) | |
12553 | { | |
12554 | emit_move_insn (target, sym); | |
12555 | return target; | |
12556 | } | |
45271277 | 12557 | return sym; |
12558 | } | |
12559 | ||
41fafa66 | 12560 | /* Find the number of a general purpose register in S. */ |
12561 | static int | |
12562 | scavenge_reg (HARD_REG_SET *s) | |
12563 | { | |
12564 | int r; | |
12565 | for (r = FIRST_GENERAL_REG; r <= LAST_GENERAL_REG; r++) | |
12566 | if (TEST_HARD_REG_BIT (*s, r)) | |
12567 | return r; | |
12568 | return -1; | |
12569 | } | |
12570 | ||
12571 | rtx | |
12572 | sh_get_pr_initial_val (void) | |
12573 | { | |
ca474d26 | 12574 | rtx val; |
12575 | ||
7a1492b5 | 12576 | /* ??? Unfortunately, get_hard_reg_initial_val doesn't always work for the |
12577 | PR register on SHcompact, because it might be clobbered by the prologue. | |
ca474d26 | 12578 | We check first if that is known to be the case. */ |
7a1492b5 | 12579 | if (TARGET_SHCOMPACT |
abe32cce | 12580 | && ((crtl->args.info.call_cookie |
ca474d26 | 12581 | & ~ CALL_COOKIE_RET_TRAMP (1)) |
18d50ae6 | 12582 | || crtl->saves_all_registers)) |
aa7e75f2 | 12583 | return gen_frame_mem (SImode, return_address_pointer_rtx); |
ca474d26 | 12584 | |
12585 | /* If we haven't finished rtl generation, there might be a nonlocal label | |
12586 | that we haven't seen yet. | |
e1ba4a27 | 12587 | ??? get_hard_reg_initial_val fails if it is called after register |
12588 | allocation has started, unless it has been called before for the | |
12589 | same register. And even then, we end in trouble if we didn't use | |
12590 | the register in the same basic block before. So call | |
12591 | get_hard_reg_initial_val now and wrap it in an unspec if we might | |
12592 | need to replace it. */ | |
ce022e7a | 12593 | /* ??? We also must do this for TARGET_SH1 in general, because otherwise |
12594 | combine can put the pseudo returned by get_hard_reg_initial_val into | |
12595 | instructions that need a general purpose registers, which will fail to | |
12596 | be recognized when the pseudo becomes allocated to PR. */ | |
ca474d26 | 12597 | val |
12598 | = get_hard_reg_initial_val (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG); | |
ce022e7a | 12599 | if (TARGET_SH1) |
ca474d26 | 12600 | return gen_rtx_UNSPEC (SImode, gen_rtvec (1, val), UNSPEC_RA); |
12601 | return val; | |
41fafa66 | 12602 | } |
12603 | ||
9db04979 | 12604 | bool |
74f4459c | 12605 | sh_expand_t_scc (rtx operands[]) |
0c3578e6 | 12606 | { |
74f4459c | 12607 | enum rtx_code code = GET_CODE (operands[1]); |
12608 | rtx target = operands[0]; | |
12609 | rtx op0 = operands[2]; | |
12610 | rtx op1 = operands[3]; | |
0c3578e6 | 12611 | rtx result = target; |
12612 | HOST_WIDE_INT val; | |
12613 | ||
cbb16986 | 12614 | if (!REG_P (op0) || REGNO (op0) != T_REG |
12615 | || !CONST_INT_P (op1)) | |
9db04979 | 12616 | return false; |
cbb16986 | 12617 | if (!REG_P (result)) |
0c3578e6 | 12618 | result = gen_reg_rtx (SImode); |
74f4459c | 12619 | val = INTVAL (op1); |
0c3578e6 | 12620 | if ((code == EQ && val == 1) || (code == NE && val == 0)) |
a6be7821 | 12621 | emit_insn (gen_movt (result, get_t_reg_rtx ())); |
0c3578e6 | 12622 | else if ((code == EQ && val == 0) || (code == NE && val == 1)) |
3ba0d068 | 12623 | emit_insn (gen_movnegt (result, get_t_reg_rtx ())); |
0c3578e6 | 12624 | else if (code == EQ || code == NE) |
12625 | emit_insn (gen_move_insn (result, GEN_INT (code == NE))); | |
12626 | else | |
9db04979 | 12627 | return false; |
0c3578e6 | 12628 | if (result != target) |
12629 | emit_move_insn (target, result); | |
9db04979 | 12630 | return true; |
0c3578e6 | 12631 | } |
12632 | ||
05e09565 | 12633 | /* INSN is an sfunc; return the rtx that describes the address used. */ |
12634 | static rtx | |
12635 | extract_sfunc_addr (rtx insn) | |
12636 | { | |
12637 | rtx pattern, part = NULL_RTX; | |
12638 | int len, i; | |
12639 | ||
12640 | pattern = PATTERN (insn); | |
12641 | len = XVECLEN (pattern, 0); | |
12642 | for (i = 0; i < len; i++) | |
12643 | { | |
12644 | part = XVECEXP (pattern, 0, i); | |
12645 | if (GET_CODE (part) == USE && GET_MODE (XEXP (part, 0)) == Pmode | |
12646 | && GENERAL_REGISTER_P (true_regnum (XEXP (part, 0)))) | |
12647 | return XEXP (part, 0); | |
12648 | } | |
1a6a7a27 | 12649 | gcc_assert (GET_CODE (XVECEXP (pattern, 0, 0)) == UNSPEC_VOLATILE); |
12650 | return XVECEXP (XVECEXP (pattern, 0, 0), 0, 1); | |
05e09565 | 12651 | } |
12652 | ||
12653 | /* Verify that the register in use_sfunc_addr still agrees with the address | |
12654 | used in the sfunc. This prevents fill_slots_from_thread from changing | |
12655 | use_sfunc_addr. | |
12656 | INSN is the use_sfunc_addr instruction, and REG is the register it | |
12657 | guards. */ | |
a3b1178e | 12658 | bool |
91a55c11 | 12659 | check_use_sfunc_addr (rtx_insn *insn, rtx reg) |
05e09565 | 12660 | { |
12661 | /* Search for the sfunc. It should really come right after INSN. */ | |
12662 | while ((insn = NEXT_INSN (insn))) | |
12663 | { | |
cbb16986 | 12664 | if (LABEL_P (insn) || JUMP_P (insn)) |
05e09565 | 12665 | break; |
12666 | if (! INSN_P (insn)) | |
12667 | continue; | |
9e7454d0 | 12668 | |
91a55c11 | 12669 | if (rtx_sequence *seq = dyn_cast<rtx_sequence *> (PATTERN (insn))) |
12670 | insn = seq->insn (0); | |
05e09565 | 12671 | if (GET_CODE (PATTERN (insn)) != PARALLEL |
12672 | || get_attr_type (insn) != TYPE_SFUNC) | |
12673 | continue; | |
12674 | return rtx_equal_p (extract_sfunc_addr (insn), reg); | |
12675 | } | |
1a6a7a27 | 12676 | gcc_unreachable (); |
05e09565 | 12677 | } |
12678 | ||
14c9d678 | 12679 | /* This function returns a constant rtx that represents 2**15 / pi in |
12680 | SFmode. It's used to scale a fixed-point signed 16.16-bit fraction | |
12681 | of a full circle back to an SFmode value, i.e. 0x10000 maps to 2*pi. */ | |
9435e831 | 12682 | static GTY(()) rtx sh_fsca_sf2int_rtx; |
12683 | ||
12684 | rtx | |
12685 | sh_fsca_sf2int (void) | |
12686 | { | |
12687 | if (! sh_fsca_sf2int_rtx) | |
12688 | { | |
12689 | REAL_VALUE_TYPE rv; | |
12690 | ||
12691 | real_from_string (&rv, "10430.378350470453"); | |
12692 | sh_fsca_sf2int_rtx = const_double_from_real_value (rv, SFmode); | |
12693 | } | |
12694 | ||
12695 | return sh_fsca_sf2int_rtx; | |
12696 | } | |
9e7454d0 | 12697 | |
14c9d678 | 12698 | /* This function returns a constant rtx that represents pi / 2**15 in |
12699 | SFmode. It's used to scale SFmode angles, in radians, to a | |
12700 | fixed-point signed 16.16-bit fraction of a full circle, i.e. 2*pi | |
12701 | maps to 0x10000. */ | |
9435e831 | 12702 | static GTY(()) rtx sh_fsca_int2sf_rtx; |
12703 | ||
12704 | rtx | |
12705 | sh_fsca_int2sf (void) | |
12706 | { | |
12707 | if (! sh_fsca_int2sf_rtx) | |
12708 | { | |
12709 | REAL_VALUE_TYPE rv; | |
12710 | ||
12711 | real_from_string (&rv, "9.587379924285257e-5"); | |
12712 | sh_fsca_int2sf_rtx = const_double_from_real_value (rv, SFmode); | |
12713 | } | |
12714 | ||
12715 | return sh_fsca_int2sf_rtx; | |
12716 | } | |
43b3dabf | 12717 | |
f8f84db9 | 12718 | /* Initialize the CUMULATIVE_ARGS structure. */ |
43b3dabf | 12719 | void |
12720 | sh_init_cumulative_args (CUMULATIVE_ARGS * pcum, | |
6c049e03 | 12721 | tree fntype, |
43b3dabf | 12722 | rtx libname ATTRIBUTE_UNUSED, |
6c049e03 | 12723 | tree fndecl, |
12724 | signed int n_named_args, | |
3754d046 | 12725 | machine_mode mode) |
43b3dabf | 12726 | { |
12727 | pcum->arg_count [(int) SH_ARG_FLOAT] = 0; | |
12728 | pcum->free_single_fp_reg = 0; | |
12729 | pcum->stack_regs = 0; | |
12730 | pcum->byref_regs = 0; | |
12731 | pcum->byref = 0; | |
12732 | pcum->outgoing = (n_named_args == -1) ? 0 : 1; | |
12733 | ||
12734 | /* XXX - Should we check TARGET_HITACHI here ??? */ | |
12735 | pcum->renesas_abi = sh_attr_renesas_p (fntype) ? 1 : 0; | |
12736 | ||
12737 | if (fntype) | |
12738 | { | |
12739 | pcum->force_mem = ((TARGET_HITACHI || pcum->renesas_abi) | |
12740 | && aggregate_value_p (TREE_TYPE (fntype), fndecl)); | |
a36cf284 | 12741 | pcum->prototype_p = prototype_p (fntype); |
43b3dabf | 12742 | pcum->arg_count [(int) SH_ARG_INT] |
12743 | = TARGET_SH5 && aggregate_value_p (TREE_TYPE (fntype), fndecl); | |
12744 | ||
12745 | pcum->call_cookie | |
12746 | = CALL_COOKIE_RET_TRAMP (TARGET_SHCOMPACT | |
12747 | && pcum->arg_count [(int) SH_ARG_INT] == 0 | |
12748 | && (TYPE_MODE (TREE_TYPE (fntype)) == BLKmode | |
12749 | ? int_size_in_bytes (TREE_TYPE (fntype)) | |
12750 | : GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (fntype)))) > 4 | |
12751 | && (BASE_RETURN_VALUE_REG (TYPE_MODE (TREE_TYPE (fntype))) | |
12752 | == FIRST_RET_REG)); | |
12753 | } | |
12754 | else | |
12755 | { | |
12756 | pcum->arg_count [(int) SH_ARG_INT] = 0; | |
12757 | pcum->prototype_p = FALSE; | |
12758 | if (mode != VOIDmode) | |
12759 | { | |
7126085a | 12760 | pcum->call_cookie = |
43b3dabf | 12761 | CALL_COOKIE_RET_TRAMP (TARGET_SHCOMPACT |
12762 | && GET_MODE_SIZE (mode) > 4 | |
12763 | && BASE_RETURN_VALUE_REG (mode) == FIRST_RET_REG); | |
12764 | ||
12765 | /* If the default ABI is the Renesas ABI then all library | |
12766 | calls must assume that the library will be using the | |
12767 | Renesas ABI. So if the function would return its result | |
12768 | in memory then we must force the address of this memory | |
12769 | block onto the stack. Ideally we would like to call | |
12770 | targetm.calls.return_in_memory() here but we do not have | |
f8f84db9 | 12771 | the TYPE or the FNDECL available so we synthesize the |
43b3dabf | 12772 | contents of that function as best we can. */ |
12773 | pcum->force_mem = | |
156fac8b | 12774 | (TARGET_DEFAULT & MASK_HITACHI) |
43b3dabf | 12775 | && (mode == BLKmode |
12776 | || (GET_MODE_SIZE (mode) > 4 | |
12777 | && !(mode == DFmode | |
12778 | && TARGET_FPU_DOUBLE))); | |
12779 | } | |
12780 | else | |
12781 | { | |
12782 | pcum->call_cookie = 0; | |
12783 | pcum->force_mem = FALSE; | |
12784 | } | |
12785 | } | |
12786 | } | |
12787 | ||
59312820 | 12788 | /* Replace any occurrence of FROM(n) in X with TO(n). The function does |
12789 | not enter into CONST_DOUBLE for the replace. | |
12790 | ||
12791 | Note that copying is not done so X must not be shared unless all copies | |
12792 | are to be modified. | |
12793 | ||
12794 | This is like replace_rtx, except that we operate on N_REPLACEMENTS | |
35fe320d | 12795 | replacements simultaneously - FROM(n) is replacements[n*2] and to(n) is |
59312820 | 12796 | replacements[n*2+1] - and that we take mode changes into account. |
12797 | ||
35fe320d | 12798 | If a replacement is ambiguous, return NULL_RTX. |
59312820 | 12799 | |
12800 | If MODIFY is zero, don't modify any rtl in place, | |
12801 | just return zero or nonzero for failure / success. */ | |
59312820 | 12802 | rtx |
12803 | replace_n_hard_rtx (rtx x, rtx *replacements, int n_replacements, int modify) | |
12804 | { | |
12805 | int i, j; | |
12806 | const char *fmt; | |
12807 | ||
12808 | /* The following prevents loops occurrence when we change MEM in | |
12809 | CONST_DOUBLE onto the same CONST_DOUBLE. */ | |
c3583c9c | 12810 | if (x != NULL_RTX && GET_CODE (x) == CONST_DOUBLE) |
59312820 | 12811 | return x; |
12812 | ||
12813 | for (i = n_replacements - 1; i >= 0 ; i--) | |
12814 | if (x == replacements[i*2] && GET_MODE (x) == GET_MODE (replacements[i*2+1])) | |
12815 | return replacements[i*2+1]; | |
12816 | ||
12817 | /* Allow this function to make replacements in EXPR_LISTs. */ | |
c3583c9c | 12818 | if (x == NULL_RTX) |
12819 | return NULL_RTX; | |
59312820 | 12820 | |
12821 | if (GET_CODE (x) == SUBREG) | |
12822 | { | |
8deb3959 | 12823 | rtx new_rtx = replace_n_hard_rtx (SUBREG_REG (x), replacements, |
59312820 | 12824 | n_replacements, modify); |
12825 | ||
cbb16986 | 12826 | if (CONST_INT_P (new_rtx)) |
59312820 | 12827 | { |
8deb3959 | 12828 | x = simplify_subreg (GET_MODE (x), new_rtx, |
59312820 | 12829 | GET_MODE (SUBREG_REG (x)), |
12830 | SUBREG_BYTE (x)); | |
12831 | if (! x) | |
12832 | abort (); | |
12833 | } | |
12834 | else if (modify) | |
8deb3959 | 12835 | SUBREG_REG (x) = new_rtx; |
59312820 | 12836 | |
12837 | return x; | |
12838 | } | |
cbb16986 | 12839 | else if (REG_P (x)) |
59312820 | 12840 | { |
12841 | unsigned regno = REGNO (x); | |
12842 | unsigned nregs = (regno < FIRST_PSEUDO_REGISTER | |
12843 | ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); | |
12844 | rtx result = NULL_RTX; | |
12845 | ||
12846 | for (i = n_replacements - 1; i >= 0; i--) | |
12847 | { | |
12848 | rtx from = replacements[i*2]; | |
12849 | rtx to = replacements[i*2+1]; | |
12850 | unsigned from_regno, from_nregs, to_regno, new_regno; | |
12851 | ||
cbb16986 | 12852 | if (!REG_P (from)) |
59312820 | 12853 | continue; |
12854 | from_regno = REGNO (from); | |
12855 | from_nregs = (from_regno < FIRST_PSEUDO_REGISTER | |
12856 | ? HARD_REGNO_NREGS (from_regno, GET_MODE (from)) : 1); | |
12857 | if (regno < from_regno + from_nregs && regno + nregs > from_regno) | |
12858 | { | |
12859 | if (regno < from_regno | |
12860 | || regno + nregs > from_regno + nregs | |
cbb16986 | 12861 | || !REG_P (to) |
59312820 | 12862 | || result) |
12863 | return NULL_RTX; | |
12864 | to_regno = REGNO (to); | |
12865 | if (to_regno < FIRST_PSEUDO_REGISTER) | |
12866 | { | |
12867 | new_regno = regno + to_regno - from_regno; | |
12868 | if ((unsigned) HARD_REGNO_NREGS (new_regno, GET_MODE (x)) | |
12869 | != nregs) | |
12870 | return NULL_RTX; | |
12871 | result = gen_rtx_REG (GET_MODE (x), new_regno); | |
12872 | } | |
12873 | else if (GET_MODE (x) <= GET_MODE (to)) | |
12874 | result = gen_lowpart_common (GET_MODE (x), to); | |
12875 | else | |
12876 | result = gen_lowpart_SUBREG (GET_MODE (x), to); | |
12877 | } | |
12878 | } | |
12879 | return result ? result : x; | |
12880 | } | |
12881 | else if (GET_CODE (x) == ZERO_EXTEND) | |
12882 | { | |
8deb3959 | 12883 | rtx new_rtx = replace_n_hard_rtx (XEXP (x, 0), replacements, |
59312820 | 12884 | n_replacements, modify); |
12885 | ||
cbb16986 | 12886 | if (CONST_INT_P (new_rtx)) |
59312820 | 12887 | { |
12888 | x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x), | |
8deb3959 | 12889 | new_rtx, GET_MODE (XEXP (x, 0))); |
59312820 | 12890 | if (! x) |
12891 | abort (); | |
12892 | } | |
12893 | else if (modify) | |
8deb3959 | 12894 | XEXP (x, 0) = new_rtx; |
59312820 | 12895 | |
12896 | return x; | |
12897 | } | |
12898 | ||
12899 | fmt = GET_RTX_FORMAT (GET_CODE (x)); | |
12900 | for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) | |
12901 | { | |
8deb3959 | 12902 | rtx new_rtx; |
59312820 | 12903 | |
12904 | if (fmt[i] == 'e') | |
12905 | { | |
8deb3959 | 12906 | new_rtx = replace_n_hard_rtx (XEXP (x, i), replacements, |
59312820 | 12907 | n_replacements, modify); |
8deb3959 | 12908 | if (!new_rtx) |
59312820 | 12909 | return NULL_RTX; |
12910 | if (modify) | |
8deb3959 | 12911 | XEXP (x, i) = new_rtx; |
59312820 | 12912 | } |
12913 | else if (fmt[i] == 'E') | |
12914 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
12915 | { | |
8deb3959 | 12916 | new_rtx = replace_n_hard_rtx (XVECEXP (x, i, j), replacements, |
59312820 | 12917 | n_replacements, modify); |
8deb3959 | 12918 | if (!new_rtx) |
59312820 | 12919 | return NULL_RTX; |
12920 | if (modify) | |
8deb3959 | 12921 | XVECEXP (x, i, j) = new_rtx; |
59312820 | 12922 | } |
12923 | } | |
12924 | ||
12925 | return x; | |
12926 | } | |
12927 | ||
12928 | rtx | |
3754d046 | 12929 | sh_gen_truncate (machine_mode mode, rtx x, int need_sign_ext) |
59312820 | 12930 | { |
12931 | enum rtx_code code = TRUNCATE; | |
12932 | ||
12933 | if (GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) | |
12934 | { | |
12935 | rtx inner = XEXP (x, 0); | |
3754d046 | 12936 | machine_mode inner_mode = GET_MODE (inner); |
59312820 | 12937 | |
12938 | if (inner_mode == mode) | |
12939 | return inner; | |
12940 | else if (GET_MODE_SIZE (inner_mode) >= GET_MODE_SIZE (mode)) | |
12941 | x = inner; | |
12942 | else if (GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (mode) | |
12943 | && (! need_sign_ext || GET_CODE (x) == SIGN_EXTEND)) | |
12944 | { | |
12945 | code = GET_CODE (x); | |
12946 | x = inner; | |
12947 | } | |
12948 | } | |
12949 | return gen_rtx_fmt_e (code, mode, x); | |
12950 | } | |
12951 | ||
727d658b | 12952 | /* Look through X cleaning up truncates of registers that span multiple |
12953 | actual hard registers. Return the number of changes made. */ | |
59312820 | 12954 | int |
727d658b | 12955 | shmedia_cleanup_truncate (rtx x) |
59312820 | 12956 | { |
727d658b | 12957 | int n_changes = 0; |
12958 | subrtx_var_iterator::array_type array; | |
12959 | FOR_EACH_SUBRTX_VAR (iter, array, x, NONCONST) | |
59312820 | 12960 | { |
727d658b | 12961 | rtx x = *iter; |
12962 | if (GET_CODE (x) == TRUNCATE) | |
12963 | { | |
12964 | rtx reg = XEXP (x, 0); | |
3754d046 | 12965 | machine_mode reg_mode = GET_MODE (reg); |
727d658b | 12966 | if (REG_P (reg) && GET_MODE_SIZE (reg_mode) > 8) |
12967 | { | |
12968 | int offset = subreg_lowpart_offset (DImode, reg_mode); | |
12969 | XEXP (x, 0) = simplify_subreg (DImode, reg, reg_mode, offset); | |
12970 | n_changes += 1; | |
12971 | iter.skip_subrtxes (); | |
12972 | } | |
12973 | } | |
59312820 | 12974 | } |
727d658b | 12975 | return n_changes; |
59312820 | 12976 | } |
12977 | ||
12978 | /* Load and store depend on the highpart of the address. However, | |
12979 | set_attr_alternative does not give well-defined results before reload, | |
12980 | so we must look at the rtl ourselves to see if any of the feeding | |
6c049e03 | 12981 | registers is used in a memref. |
59312820 | 12982 | |
ff2136d4 | 12983 | Return true iff INSN contains a MEM. */ |
a3b1178e | 12984 | bool |
59312820 | 12985 | sh_contains_memref_p (rtx insn) |
12986 | { | |
ff2136d4 | 12987 | subrtx_iterator::array_type array; |
12988 | FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST) | |
12989 | if (MEM_P (*iter)) | |
12990 | return true; | |
12991 | return false; | |
59312820 | 12992 | } |
12993 | ||
a3b1178e | 12994 | /* Return true iff INSN loads a banked register. */ |
12995 | bool | |
2f8b8488 | 12996 | sh_loads_bankedreg_p (rtx insn) |
12997 | { | |
12998 | if (GET_CODE (PATTERN (insn)) == SET) | |
12999 | { | |
13000 | rtx op = SET_DEST (PATTERN(insn)); | |
13001 | if (REG_P (op) && BANKED_REGISTER_P (REGNO (op))) | |
a3b1178e | 13002 | return true; |
2f8b8488 | 13003 | } |
13004 | ||
a3b1178e | 13005 | return false; |
2f8b8488 | 13006 | } |
13007 | ||
59312820 | 13008 | /* FNADDR is the MEM expression from a call expander. Return an address |
13009 | to use in an SHmedia insn pattern. */ | |
13010 | rtx | |
13011 | shmedia_prepare_call_address (rtx fnaddr, int is_sibcall) | |
13012 | { | |
13013 | int is_sym; | |
13014 | ||
13015 | fnaddr = XEXP (fnaddr, 0); | |
13016 | is_sym = GET_CODE (fnaddr) == SYMBOL_REF; | |
13017 | if (flag_pic && is_sym) | |
13018 | { | |
13019 | if (! SYMBOL_REF_LOCAL_P (fnaddr)) | |
13020 | { | |
13021 | rtx reg = gen_reg_rtx (Pmode); | |
13022 | ||
13023 | /* We must not use GOTPLT for sibcalls, because PIC_REG | |
13024 | must be restored before the PLT code gets to run. */ | |
13025 | if (is_sibcall) | |
13026 | emit_insn (gen_symGOT2reg (reg, fnaddr)); | |
13027 | else | |
13028 | emit_insn (gen_symGOTPLT2reg (reg, fnaddr)); | |
13029 | fnaddr = reg; | |
13030 | } | |
13031 | else | |
13032 | { | |
13033 | fnaddr = gen_sym2PIC (fnaddr); | |
13034 | PUT_MODE (fnaddr, Pmode); | |
13035 | } | |
13036 | } | |
13037 | /* If ptabs might trap, make this visible to the rest of the compiler. | |
13038 | We generally assume that symbols pertain to valid locations, but | |
13039 | it is possible to generate invalid symbols with asm or linker tricks. | |
35fe320d | 13040 | In a list of functions where each returns its successor, an invalid |
59312820 | 13041 | symbol might denote an empty list. */ |
13042 | if (!TARGET_PT_FIXED | |
13043 | && (!is_sym || TARGET_INVALID_SYMBOLS) | |
13044 | && (!REG_P (fnaddr) || ! TARGET_REGISTER_P (REGNO (fnaddr)))) | |
13045 | { | |
13046 | rtx tr = gen_reg_rtx (PDImode); | |
13047 | ||
13048 | emit_insn (gen_ptabs (tr, fnaddr)); | |
13049 | fnaddr = tr; | |
13050 | } | |
13051 | else if (! target_reg_operand (fnaddr, Pmode)) | |
13052 | fnaddr = copy_to_mode_reg (Pmode, fnaddr); | |
13053 | return fnaddr; | |
13054 | } | |
13055 | ||
167f2e19 | 13056 | /* Implement TARGET_PREFERRED_RELOAD_CLASS. */ |
167f2e19 | 13057 | static reg_class_t |
13058 | sh_preferred_reload_class (rtx x, reg_class_t rclass) | |
13059 | { | |
13060 | if (rclass == NO_REGS | |
13061 | && TARGET_SHMEDIA | |
13062 | && (CONST_DOUBLE_P (x) | |
13063 | || GET_CODE (x) == SYMBOL_REF | |
13064 | || PIC_ADDR_P (x))) | |
13065 | return GENERAL_REGS; | |
13066 | ||
13067 | return rclass; | |
13068 | } | |
13069 | ||
13070 | /* Implement TARGET_SECONDARY_RELOAD. */ | |
167f2e19 | 13071 | static reg_class_t |
964229b7 | 13072 | sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, |
3754d046 | 13073 | machine_mode mode, secondary_reload_info *sri) |
4d58fa46 | 13074 | { |
964229b7 | 13075 | enum reg_class rclass = (enum reg_class) rclass_i; |
13076 | ||
3ea038fc | 13077 | if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == PLUS |
13078 | && REG_P (XEXP (XEXP (x, 0), 0)) | |
13079 | && REGNO (XEXP (XEXP (x, 0), 0)) == GBR_REG) | |
13080 | return rclass == R0_REGS ? NO_REGS : R0_REGS; | |
13081 | ||
13082 | if (MEM_P (x) && REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) == GBR_REG) | |
13083 | return rclass == R0_REGS ? NO_REGS : R0_REGS; | |
13084 | ||
13085 | if (REG_P (x) && REGNO (x) == GBR_REG) | |
13086 | return NO_REGS; | |
13087 | ||
4d58fa46 | 13088 | if (in_p) |
13089 | { | |
8deb3959 | 13090 | if (REGCLASS_HAS_FP_REG (rclass) |
4d58fa46 | 13091 | && ! TARGET_SHMEDIA |
13092 | && immediate_operand ((x), mode) | |
9cbd1118 | 13093 | && ! ((fp_zero_operand (x) || fp_one_operand (x)) && mode == SFmode)) |
4d58fa46 | 13094 | switch (mode) |
13095 | { | |
13096 | case SFmode: | |
13097 | sri->icode = CODE_FOR_reload_insf__frn; | |
13098 | return NO_REGS; | |
13099 | case DFmode: | |
13100 | sri->icode = CODE_FOR_reload_indf__frn; | |
13101 | return NO_REGS; | |
13102 | case SImode: | |
13103 | /* ??? If we knew that we are in the appropriate mode - | |
13104 | single precision - we could use a reload pattern directly. */ | |
13105 | return FPUL_REGS; | |
13106 | default: | |
13107 | abort (); | |
13108 | } | |
8deb3959 | 13109 | if (rclass == FPUL_REGS |
6c049e03 | 13110 | && ((REG_P (x) && (REGNO (x) == MACL_REG || REGNO (x) == MACH_REG |
13111 | || REGNO (x) == T_REG)) | |
13112 | || GET_CODE (x) == PLUS)) | |
13113 | return GENERAL_REGS; | |
8deb3959 | 13114 | if (rclass == FPUL_REGS && immediate_operand (x, mode)) |
4d58fa46 | 13115 | { |
583c0935 | 13116 | if (satisfies_constraint_I08 (x) || fp_zero_operand (x)) |
4d58fa46 | 13117 | return GENERAL_REGS; |
583c0935 | 13118 | else if (mode == SFmode) |
13119 | return FP_REGS; | |
4d58fa46 | 13120 | sri->icode = CODE_FOR_reload_insi__i_fpul; |
13121 | return NO_REGS; | |
13122 | } | |
8deb3959 | 13123 | if (rclass == FPSCR_REGS |
6c049e03 | 13124 | && ((REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER) |
13125 | || (MEM_P (x) && GET_CODE (XEXP (x, 0)) == PLUS))) | |
4d58fa46 | 13126 | return GENERAL_REGS; |
8deb3959 | 13127 | if (REGCLASS_HAS_FP_REG (rclass) |
6c049e03 | 13128 | && TARGET_SHMEDIA |
13129 | && immediate_operand (x, mode) | |
13130 | && x != CONST0_RTX (GET_MODE (x)) | |
13131 | && GET_MODE (x) != V4SFmode) | |
13132 | return GENERAL_REGS; | |
4d58fa46 | 13133 | if ((mode == QImode || mode == HImode) |
6c049e03 | 13134 | && TARGET_SHMEDIA && inqhi_operand (x, mode)) |
4d58fa46 | 13135 | { |
13136 | sri->icode = ((mode == QImode) | |
13137 | ? CODE_FOR_reload_inqi : CODE_FOR_reload_inhi); | |
13138 | return NO_REGS; | |
13139 | } | |
8deb3959 | 13140 | if (TARGET_SHMEDIA && rclass == GENERAL_REGS |
6c049e03 | 13141 | && (GET_CODE (x) == LABEL_REF || PIC_ADDR_P (x))) |
13142 | return TARGET_REGS; | |
4d58fa46 | 13143 | } /* end of input-only processing. */ |
13144 | ||
8deb3959 | 13145 | if (((REGCLASS_HAS_FP_REG (rclass) |
cbb16986 | 13146 | && (REG_P (x) |
4d58fa46 | 13147 | && (GENERAL_OR_AP_REGISTER_P (REGNO (x)) |
13148 | || (FP_REGISTER_P (REGNO (x)) && mode == SImode | |
13149 | && TARGET_FMOVD)))) | |
8deb3959 | 13150 | || (REGCLASS_HAS_GENERAL_REG (rclass) |
cbb16986 | 13151 | && REG_P (x) |
4d58fa46 | 13152 | && FP_REGISTER_P (REGNO (x)))) |
13153 | && ! TARGET_SHMEDIA | |
13154 | && (mode == SFmode || mode == SImode)) | |
13155 | return FPUL_REGS; | |
8deb3959 | 13156 | if ((rclass == FPUL_REGS |
13157 | || (REGCLASS_HAS_FP_REG (rclass) | |
6c049e03 | 13158 | && ! TARGET_SHMEDIA && mode == SImode)) |
cbb16986 | 13159 | && (MEM_P (x) |
6c049e03 | 13160 | || (REG_P (x) |
13161 | && (REGNO (x) >= FIRST_PSEUDO_REGISTER | |
13162 | || REGNO (x) == T_REG | |
13163 | || system_reg_operand (x, VOIDmode))))) | |
4d58fa46 | 13164 | { |
8deb3959 | 13165 | if (rclass == FPUL_REGS) |
4d58fa46 | 13166 | return GENERAL_REGS; |
13167 | return FPUL_REGS; | |
13168 | } | |
8deb3959 | 13169 | if ((rclass == TARGET_REGS |
13170 | || (TARGET_SHMEDIA && rclass == SIBCALL_REGS)) | |
abff7a2e | 13171 | && !satisfies_constraint_Csy (x) |
cbb16986 | 13172 | && (!REG_P (x) || ! GENERAL_REGISTER_P (REGNO (x)))) |
4d58fa46 | 13173 | return GENERAL_REGS; |
8deb3959 | 13174 | if ((rclass == MAC_REGS || rclass == PR_REGS) |
cbb16986 | 13175 | && REG_P (x) && ! GENERAL_REGISTER_P (REGNO (x)) |
8deb3959 | 13176 | && rclass != REGNO_REG_CLASS (REGNO (x))) |
4d58fa46 | 13177 | return GENERAL_REGS; |
cbb16986 | 13178 | if (rclass != GENERAL_REGS && REG_P (x) |
4d58fa46 | 13179 | && TARGET_REGISTER_P (REGNO (x))) |
13180 | return GENERAL_REGS; | |
836d1cac | 13181 | |
13182 | /* If here fall back to loading FPUL register through general registers. | |
13183 | This case can happen when movsi_ie insn is picked initially to | |
13184 | load/store the FPUL register from/to another register, and then the | |
13185 | other register is allocated on the stack. */ | |
13186 | if (rclass == FPUL_REGS && true_regnum (x) == -1) | |
13187 | return GENERAL_REGS; | |
13188 | ||
51bc6b40 | 13189 | /* Force mov.b / mov.w displacement addressing insn to use R0 as |
13190 | the other operand. | |
89cace00 | 13191 | On SH2A could also just leave it alone here, which would result in a |
13192 | 4 byte move insn being generated instead. However, for this to work | |
13193 | the insns must have the appropriate alternatives. */ | |
51bc6b40 | 13194 | if ((mode == QImode || mode == HImode) && rclass != R0_REGS |
13195 | && satisfies_constraint_Sdd (x) | |
9db63610 | 13196 | && sh_disp_addr_displacement (x) |
13197 | <= sh_max_mov_insn_displacement (mode, false)) | |
89cace00 | 13198 | return R0_REGS; |
13199 | ||
13200 | /* When reload is trying to address a QImode or HImode subreg on the stack, | |
13201 | force any subreg byte into R0_REGS, as this is going to become a | |
13202 | displacement address. | |
13203 | We could restrict this to SUBREG_BYTE (x) > 0, but if the actual reg | |
13204 | is on the stack, the memref to it might already require a displacement | |
13205 | and that has to be added to the final address. At this point we don't | |
13206 | know the cumulative displacement so we assume the worst case. */ | |
13207 | if ((mode == QImode || mode == HImode) && rclass != R0_REGS | |
13208 | && GET_CODE (x) == SUBREG && true_regnum (x) == -1) | |
13209 | return R0_REGS; | |
13210 | ||
4d58fa46 | 13211 | return NO_REGS; |
13212 | } | |
13213 | ||
b2d7ede1 | 13214 | static void |
13215 | sh_conditional_register_usage (void) | |
13216 | { | |
13217 | int regno; | |
13218 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++) | |
13219 | if (! VALID_REGISTER_P (regno)) | |
13220 | fixed_regs[regno] = call_used_regs[regno] = 1; | |
13221 | /* R8 and R9 are call-clobbered on SH5, but not on earlier SH ABIs. */ | |
13222 | if (TARGET_SH5) | |
13223 | { | |
13224 | call_used_regs[FIRST_GENERAL_REG + 8] | |
13225 | = call_used_regs[FIRST_GENERAL_REG + 9] = 1; | |
13226 | call_really_used_regs[FIRST_GENERAL_REG + 8] | |
13227 | = call_really_used_regs[FIRST_GENERAL_REG + 9] = 1; | |
13228 | } | |
13229 | if (TARGET_SHMEDIA) | |
13230 | { | |
13231 | regno_reg_class[FIRST_GENERAL_REG] = GENERAL_REGS; | |
13232 | CLEAR_HARD_REG_SET (reg_class_contents[FP0_REGS]); | |
13233 | regno_reg_class[FIRST_FP_REG] = FP_REGS; | |
13234 | } | |
13235 | if (flag_pic) | |
13236 | { | |
13237 | fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; | |
13238 | call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; | |
13239 | } | |
13240 | /* Renesas saves and restores mac registers on call. */ | |
13241 | if (TARGET_HITACHI && ! TARGET_NOMACSAVE) | |
13242 | { | |
13243 | call_really_used_regs[MACH_REG] = 0; | |
13244 | call_really_used_regs[MACL_REG] = 0; | |
13245 | } | |
ec3c739c | 13246 | |
b2d7ede1 | 13247 | if (TARGET_SHMEDIA) |
13248 | { | |
13249 | for (regno = FIRST_TARGET_REG; regno <= LAST_TARGET_REG; regno ++) | |
13250 | if (! fixed_regs[regno] && call_really_used_regs[regno]) | |
13251 | SET_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno); | |
13252 | } | |
13253 | else | |
13254 | for (regno = FIRST_GENERAL_REG; regno <= LAST_GENERAL_REG; regno++) | |
13255 | if (! fixed_regs[regno] && call_really_used_regs[regno]) | |
13256 | SET_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], regno); | |
b0fa59a9 | 13257 | |
13258 | call_really_used_regs[FPSCR_MODES_REG] = 0; | |
13259 | call_really_used_regs[FPSCR_STAT_REG] = 0; | |
b2d7ede1 | 13260 | } |
13261 | ||
ca316360 | 13262 | /* Implement TARGET_LEGITIMATE_CONSTANT_P |
13263 | ||
13264 | can_store_by_pieces constructs VOIDmode CONST_DOUBLEs. */ | |
ca316360 | 13265 | static bool |
3754d046 | 13266 | sh_legitimate_constant_p (machine_mode mode, rtx x) |
ca316360 | 13267 | { |
13268 | return (TARGET_SHMEDIA | |
13269 | ? ((mode != DFmode && GET_MODE_CLASS (mode) != MODE_VECTOR_FLOAT) | |
13270 | || x == CONST0_RTX (mode) | |
13271 | || !TARGET_SHMEDIA_FPU | |
13272 | || TARGET_SHMEDIA64) | |
13273 | : (GET_CODE (x) != CONST_DOUBLE | |
13274 | || mode == DFmode || mode == SFmode | |
13275 | || mode == DImode || GET_MODE (x) == VOIDmode)); | |
13276 | } | |
b2d7ede1 | 13277 | |
59312820 | 13278 | enum sh_divide_strategy_e sh_div_strategy = SH_DIV_STRATEGY_DEFAULT; |
13279 | ||
a3df8952 | 13280 | static void |
13281 | sh_init_sync_libfuncs (void) | |
13282 | { | |
13283 | init_sync_libfuncs (UNITS_PER_WORD); | |
13284 | } | |
13285 | ||
9579a4b9 | 13286 | /* Return true if it is appropriate to emit `ret' instructions in the |
13287 | body of a function. */ | |
9579a4b9 | 13288 | bool |
13289 | sh_can_use_simple_return_p (void) | |
13290 | { | |
13291 | HARD_REG_SET live_regs_mask; | |
13292 | int d; | |
13293 | ||
9632a01b | 13294 | /* Some targets require special return insns. */ |
13295 | if (TARGET_SHMEDIA | |
13296 | || (TARGET_SHCOMPACT | |
13297 | && (crtl->args.info.call_cookie & CALL_COOKIE_RET_TRAMP (1)))) | |
13298 | return false; | |
13299 | ||
9579a4b9 | 13300 | if (! reload_completed || frame_pointer_needed) |
13301 | return false; | |
13302 | ||
13303 | /* Moving prologue around does't reduce the size. */ | |
13304 | if (optimize_function_for_size_p (cfun)) | |
13305 | return false; | |
13306 | ||
9579a4b9 | 13307 | /* Finally, allow for pr save. */ |
13308 | d = calc_live_regs (&live_regs_mask); | |
13309 | ||
13310 | if (rounded_frame_size (d) > 4) | |
13311 | return false; | |
13312 | ||
13313 | return true; | |
9579a4b9 | 13314 | } |
13315 | ||
3ea038fc | 13316 | /*------------------------------------------------------------------------------ |
13317 | Address mode optimization support code | |
13318 | */ | |
13319 | ||
13320 | typedef HOST_WIDE_INT disp_t; | |
13321 | static const disp_t MIN_DISP = HOST_WIDE_INT_MIN; | |
13322 | static const disp_t MAX_DISP = HOST_WIDE_INT_MAX; | |
13323 | static const disp_t INVALID_DISP = MAX_DISP; | |
13324 | ||
13325 | /* A memory reference which is described by a base register and a | |
13326 | displacement. */ | |
13327 | class base_reg_disp | |
13328 | { | |
13329 | public: | |
13330 | base_reg_disp (rtx br, disp_t d); | |
13331 | ||
13332 | bool is_reg (void) const; | |
13333 | bool is_disp (void) const; | |
13334 | rtx reg (void) const; | |
13335 | disp_t disp (void) const; | |
13336 | ||
13337 | private: | |
13338 | rtx reg_; | |
13339 | disp_t disp_; | |
13340 | }; | |
13341 | ||
13342 | inline | |
13343 | base_reg_disp::base_reg_disp (rtx br, disp_t d) | |
13344 | : reg_ (br), disp_ (d) | |
13345 | { | |
13346 | } | |
13347 | ||
13348 | inline bool | |
13349 | base_reg_disp::is_reg (void) const | |
13350 | { | |
13351 | return reg_ != NULL_RTX && disp_ != INVALID_DISP; | |
13352 | } | |
13353 | ||
13354 | inline bool | |
13355 | base_reg_disp::is_disp (void) const | |
13356 | { | |
13357 | return reg_ == NULL_RTX && disp_ != INVALID_DISP; | |
13358 | } | |
13359 | ||
13360 | inline rtx | |
13361 | base_reg_disp::reg (void) const | |
13362 | { | |
13363 | return reg_; | |
13364 | } | |
13365 | ||
13366 | inline disp_t | |
13367 | base_reg_disp::disp (void) const | |
13368 | { | |
13369 | return disp_; | |
13370 | } | |
13371 | ||
13372 | /* Find the base register and calculate the displacement for a given | |
1c733bf7 | 13373 | address rtx 'x'. */ |
3ea038fc | 13374 | static base_reg_disp |
1c733bf7 | 13375 | sh_find_base_reg_disp (rtx_insn* insn, rtx x, disp_t disp = 0, |
13376 | rtx base_reg = NULL) | |
3ea038fc | 13377 | { |
13378 | if (REG_P (x)) | |
13379 | { | |
13380 | if (REGNO (x) == GBR_REG) | |
13381 | return base_reg_disp (x, disp); | |
13382 | ||
13383 | /* We've reached a hard-reg. This is probably the point where | |
13384 | function args are copied to pseudos. Do not go any further and | |
13385 | stick to the pseudo. If the original mem addr was in a hard reg | |
13386 | from the beginning, it will become the base reg. */ | |
13387 | if (REGNO (x) < FIRST_PSEUDO_REGISTER) | |
13388 | return base_reg_disp (base_reg != NULL ? base_reg : x, disp); | |
13389 | ||
1c733bf7 | 13390 | /* Find the def of the reg and trace it. If there are more than one |
13391 | defs and they are not the same, assume it's not safe to proceed. */ | |
13392 | rtx_insn* last_i = NULL; | |
13393 | rtx last_set = NULL; | |
13394 | for (df_ref d = DF_REG_DEF_CHAIN (REGNO (x)); d != NULL; | |
13395 | d = DF_REF_NEXT_REG (d)) | |
3ea038fc | 13396 | { |
1c733bf7 | 13397 | rtx set = const_cast<rtx> (set_of (x, DF_REF_INSN (d))); |
3ea038fc | 13398 | |
1c733bf7 | 13399 | /* Accept multiple defs, as long as they are equal. */ |
13400 | if (last_set == NULL || rtx_equal_p (last_set, set)) | |
13401 | { | |
13402 | last_i = DF_REF_INSN (d); | |
13403 | last_set = set; | |
13404 | } | |
13405 | else | |
3ea038fc | 13406 | { |
1c733bf7 | 13407 | last_i = NULL; |
13408 | last_set = NULL; | |
13409 | break; | |
3ea038fc | 13410 | } |
13411 | } | |
13412 | ||
1c733bf7 | 13413 | if (last_set != NULL && last_i != NULL) |
13414 | return sh_find_base_reg_disp (last_i, XEXP (last_set, 1), disp, | |
13415 | XEXP (last_set, 0)); | |
13416 | ||
13417 | /* When here, no previous insn was found that sets the reg. | |
13418 | The input reg is already the base reg. */ | |
13419 | return base_reg_disp (x, disp); | |
13420 | } | |
3ea038fc | 13421 | |
13422 | else if (GET_CODE (x) == PLUS) | |
13423 | { | |
13424 | base_reg_disp left_val = sh_find_base_reg_disp (insn, XEXP (x, 0)); | |
13425 | base_reg_disp right_val = sh_find_base_reg_disp (insn, XEXP (x, 1)); | |
13426 | ||
13427 | /* Either left or right val must be a reg. | |
13428 | We don't handle the case of 'reg + reg' here. */ | |
13429 | if (left_val.is_reg () && right_val.is_disp ()) | |
13430 | return base_reg_disp (left_val.reg (), left_val.disp () | |
13431 | + right_val.disp () + disp); | |
13432 | else if (right_val.is_reg () && left_val.is_disp ()) | |
13433 | return base_reg_disp (right_val.reg (), right_val.disp () | |
13434 | + left_val.disp () + disp); | |
13435 | else | |
13436 | return base_reg_disp (base_reg, disp); | |
13437 | } | |
13438 | ||
13439 | else if (CONST_INT_P (x)) | |
13440 | return base_reg_disp (NULL, disp + INTVAL (x)); | |
13441 | ||
13442 | /* Didn't find anything useful. */ | |
13443 | return base_reg_disp (base_reg, disp); | |
13444 | } | |
13445 | ||
13446 | /* Given an insn and a memory operand, try to find an equivalent GBR | |
13447 | based memory address and return the corresponding new memory address. | |
13448 | Return NULL_RTX if not found. */ | |
13449 | rtx | |
1c733bf7 | 13450 | sh_find_equiv_gbr_addr (rtx_insn* insn, rtx mem) |
3ea038fc | 13451 | { |
1c733bf7 | 13452 | if (!MEM_P (mem) || gbr_address_mem (mem, GET_MODE (mem))) |
3ea038fc | 13453 | return NULL_RTX; |
13454 | ||
13455 | /* Leave post/pre inc/dec or any other side effect addresses alone. */ | |
13456 | if (side_effects_p (XEXP (mem, 0))) | |
13457 | return NULL_RTX; | |
13458 | ||
1c733bf7 | 13459 | /* When not optimizing there might be no dataflow available. */ |
13460 | if (df == NULL) | |
13461 | return NULL_RTX; | |
13462 | ||
3ea038fc | 13463 | base_reg_disp gbr_disp = sh_find_base_reg_disp (insn, XEXP (mem, 0)); |
13464 | ||
13465 | if (gbr_disp.is_reg () && REGNO (gbr_disp.reg ()) == GBR_REG) | |
13466 | { | |
1c733bf7 | 13467 | /* If GBR is marked as call clobbered we bail out if we see a call. |
13468 | FIXME: Actually should check if this mem refers to the gbr value | |
13469 | before or after the call. If there is a store_gbr preceeding this | |
13470 | mem, it's safe to use GBR for this mem. | |
13471 | ||
13472 | If GBR is not marked as call clobbered, but there is some other | |
13473 | def than a call, it's probably a load_gbr upon which we also | |
13474 | bail out to be on the safe side. | |
13475 | FIXME: Should check if we have a use-after-def case, such as | |
13476 | the call case above. */ | |
13477 | for (df_ref d = DF_REG_DEF_CHAIN (GBR_REG); d != NULL; | |
13478 | d = DF_REF_NEXT_REG (d)) | |
13479 | { | |
13480 | if (CALL_P (DF_REF_INSN (d))) | |
13481 | { | |
13482 | if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG)) | |
13483 | return NULL_RTX; | |
13484 | else | |
13485 | continue; | |
13486 | } | |
13487 | else | |
13488 | return NULL_RTX; | |
13489 | } | |
13490 | ||
3ea038fc | 13491 | rtx disp = GEN_INT (gbr_disp.disp ()); |
13492 | if (gbr_displacement (disp, GET_MODE (mem))) | |
13493 | return gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, GBR_REG), disp); | |
13494 | } | |
13495 | ||
13496 | return NULL_RTX; | |
13497 | } | |
13498 | ||
99af687a | 13499 | /*------------------------------------------------------------------------------ |
13500 | Manual insn combine support code. | |
13501 | */ | |
13502 | ||
13503 | /* Given a reg rtx and a start insn, try to find the insn that sets the | |
13504 | specified reg by using the specified insn stepping function, such as | |
13505 | 'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx | |
13506 | of the reg set. */ | |
13507 | set_of_reg | |
7bac25b3 | 13508 | sh_find_set_of_reg (rtx reg, rtx insn, rtx_insn *(*stepfunc)(rtx)) |
99af687a | 13509 | { |
13510 | set_of_reg result; | |
13511 | result.insn = insn; | |
13512 | result.set_rtx = NULL_RTX; | |
13513 | result.set_src = NULL_RTX; | |
13514 | ||
13515 | if (!REG_P (reg) || insn == NULL_RTX) | |
13516 | return result; | |
13517 | ||
13518 | for (result.insn = stepfunc (insn); result.insn != NULL_RTX; | |
13519 | result.insn = stepfunc (result.insn)) | |
13520 | { | |
cb71f2c3 | 13521 | if (BARRIER_P (result.insn)) |
99af687a | 13522 | return result; |
13523 | if (!NONJUMP_INSN_P (result.insn)) | |
13524 | continue; | |
13525 | if (reg_set_p (reg, result.insn)) | |
13526 | { | |
13527 | result.set_rtx = set_of (reg, result.insn); | |
13528 | ||
13529 | if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET) | |
13530 | return result; | |
13531 | ||
13532 | result.set_src = XEXP (result.set_rtx, 1); | |
13533 | return result; | |
13534 | } | |
13535 | } | |
13536 | ||
13537 | return result; | |
13538 | } | |
13539 | ||
13540 | /* Given an op rtx and an insn, try to find out whether the result of the | |
13541 | specified op consists only of logical operations on T bit stores. */ | |
13542 | bool | |
13543 | sh_is_logical_t_store_expr (rtx op, rtx insn) | |
13544 | { | |
13545 | if (!logical_operator (op, SImode)) | |
13546 | return false; | |
13547 | ||
13548 | rtx ops[2] = { XEXP (op, 0), XEXP (op, 1) }; | |
13549 | int op_is_t_count = 0; | |
13550 | ||
13551 | for (int i = 0; i < 2; ++i) | |
13552 | { | |
13553 | if (t_reg_operand (ops[i], VOIDmode) | |
13554 | || negt_reg_operand (ops[i], VOIDmode)) | |
13555 | op_is_t_count++; | |
13556 | ||
13557 | else | |
13558 | { | |
13559 | set_of_reg op_set = sh_find_set_of_reg (ops[i], insn, | |
13560 | prev_nonnote_insn_bb); | |
13561 | if (op_set.set_src == NULL_RTX) | |
13562 | continue; | |
13563 | ||
13564 | if (t_reg_operand (op_set.set_src, VOIDmode) | |
13565 | || negt_reg_operand (op_set.set_src, VOIDmode) | |
13566 | || sh_is_logical_t_store_expr (op_set.set_src, op_set.insn)) | |
13567 | op_is_t_count++; | |
13568 | } | |
13569 | } | |
13570 | ||
13571 | return op_is_t_count == 2; | |
13572 | } | |
13573 | ||
13574 | /* Given the operand that is extended in a sign/zero extend insn, and the | |
13575 | insn, try to figure out whether the sign/zero extension can be replaced | |
13576 | by a simple reg-reg copy. If so, the replacement reg rtx is returned, | |
13577 | NULL_RTX otherwise. */ | |
13578 | rtx | |
13579 | sh_try_omit_signzero_extend (rtx extended_op, rtx insn) | |
13580 | { | |
13581 | if (REG_P (extended_op)) | |
13582 | extended_op = extended_op; | |
13583 | else if (GET_CODE (extended_op) == SUBREG && REG_P (SUBREG_REG (extended_op))) | |
13584 | extended_op = SUBREG_REG (extended_op); | |
13585 | else | |
13586 | return NULL_RTX; | |
13587 | ||
13588 | /* Reg moves must be of the same mode. */ | |
13589 | if (GET_MODE (extended_op) != SImode) | |
13590 | return NULL_RTX; | |
13591 | ||
13592 | set_of_reg s = sh_find_set_of_reg (extended_op, insn, prev_nonnote_insn_bb); | |
13593 | if (s.set_src == NULL_RTX) | |
13594 | return NULL_RTX; | |
13595 | ||
13596 | if (t_reg_operand (s.set_src, VOIDmode) | |
13597 | || negt_reg_operand (s.set_src, VOIDmode)) | |
13598 | return extended_op; | |
13599 | ||
13600 | /* If the zero extended reg was formed by a logical operation, check the | |
13601 | operands of the logical operation. If both originated from T bit | |
13602 | stores the zero extension can be eliminated. */ | |
13603 | else if (sh_is_logical_t_store_expr (s.set_src, s.insn)) | |
13604 | return extended_op; | |
13605 | ||
13606 | return NULL_RTX; | |
13607 | } | |
13608 | ||
cea19dab | 13609 | static void |
13610 | sh_emit_mode_set (int entity ATTRIBUTE_UNUSED, int mode, | |
b0fa59a9 | 13611 | int prev_mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED) |
cea19dab | 13612 | { |
7fc0df2f | 13613 | if ((TARGET_SH4A_FP || TARGET_SH4_300) |
13614 | && prev_mode != FP_MODE_NONE && prev_mode != mode) | |
13615 | { | |
13616 | emit_insn (gen_toggle_pr ()); | |
13617 | if (TARGET_FMOVD) | |
13618 | emit_insn (gen_toggle_sz ()); | |
13619 | } | |
b0fa59a9 | 13620 | else if (mode != FP_MODE_NONE) |
13621 | { | |
81298240 | 13622 | rtx tmp = gen_reg_rtx (SImode); |
13623 | emit_insn (gen_sts_fpscr (tmp)); | |
b0fa59a9 | 13624 | rtx i = NULL; |
13625 | ||
13626 | const unsigned HOST_WIDE_INT fpbits = | |
13627 | TARGET_FMOVD ? (FPSCR_PR | FPSCR_SZ) : FPSCR_PR; | |
13628 | ||
13629 | if (prev_mode != FP_MODE_NONE && prev_mode != mode) | |
81298240 | 13630 | i = gen_xorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits))); |
b0fa59a9 | 13631 | else if (mode == FP_MODE_SINGLE) |
81298240 | 13632 | i = gen_andsi3 (tmp, tmp, force_reg (SImode, GEN_INT (~fpbits))); |
b0fa59a9 | 13633 | else if (mode == FP_MODE_DOUBLE) |
81298240 | 13634 | i = gen_iorsi3 (tmp, tmp, force_reg (SImode, GEN_INT (fpbits))); |
b0fa59a9 | 13635 | else |
13636 | gcc_unreachable (); | |
13637 | ||
13638 | emit_insn (i); | |
81298240 | 13639 | emit_insn (gen_lds_fpscr (tmp)); |
b0fa59a9 | 13640 | } |
cea19dab | 13641 | } |
13642 | ||
13643 | static int | |
18282db0 | 13644 | sh_mode_needed (int entity ATTRIBUTE_UNUSED, rtx_insn *insn) |
cea19dab | 13645 | { |
13646 | return recog_memoized (insn) >= 0 ? get_attr_fp_mode (insn) : FP_MODE_NONE; | |
13647 | } | |
13648 | ||
13649 | static int | |
18282db0 | 13650 | sh_mode_after (int entity ATTRIBUTE_UNUSED, int mode, rtx_insn *insn) |
cea19dab | 13651 | { |
13652 | if (TARGET_HITACHI && recog_memoized (insn) >= 0 && | |
13653 | get_attr_fp_set (insn) != FP_SET_NONE) | |
13654 | return (int) get_attr_fp_set (insn); | |
13655 | else | |
13656 | return mode; | |
13657 | } | |
13658 | ||
13659 | static int | |
13660 | sh_mode_entry (int entity ATTRIBUTE_UNUSED) | |
13661 | { | |
13662 | return NORMAL_MODE (entity); | |
13663 | } | |
13664 | ||
13665 | static int | |
13666 | sh_mode_exit (int entity ATTRIBUTE_UNUSED) | |
13667 | { | |
13668 | return sh_cfun_attr_renesas_p () ? FP_MODE_NONE : NORMAL_MODE (entity); | |
13669 | } | |
13670 | ||
13671 | static int | |
13672 | sh_mode_priority (int entity ATTRIBUTE_UNUSED, int n) | |
13673 | { | |
13674 | return ((TARGET_FPU_SINGLE != 0) ^ (n) ? FP_MODE_SINGLE : FP_MODE_DOUBLE); | |
13675 | } | |
13676 | ||
1f3233d1 | 13677 | #include "gt-sh.h" |