]>
Commit | Line | Data |
---|---|---|
7b23765d | 1 | /* Definitions of target machine for GNU compiler for Renesas / SuperH SH. |
f1717362 | 2 | Copyright (C) 1993-2016 Free Software Foundation, Inc. |
b7dbbdb2 | 3 | Contributed by Steve Chamberlain (sac@cygnus.com). |
4 | Improved by Jim Wilson (wilson@cygnus.com). | |
5 | ||
187b36cf | 6 | This file is part of GCC. |
b7dbbdb2 | 7 | |
187b36cf | 8 | GCC is free software; you can redistribute it and/or modify |
b7dbbdb2 | 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) |
b7dbbdb2 | 11 | any later version. |
12 | ||
187b36cf | 13 | GCC is distributed in the hope that it will be useful, |
b7dbbdb2 | 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/>. */ | |
b7dbbdb2 | 21 | |
1fcd08b1 | 22 | #ifndef GCC_SH_PROTOS_H |
23 | #define GCC_SH_PROTOS_H | |
24 | ||
59312820 | 25 | enum sh_function_kind { |
26 | /* A function with normal C ABI */ | |
27 | FUNCTION_ORDINARY, | |
28 | /* A special function that guarantees that some otherwise call-clobbered | |
29 | registers are not clobbered. These can't go through the SH5 resolver, | |
30 | because it only saves argument passing registers. */ | |
31 | SFUNC_GOT, | |
32 | /* A special function that should be linked statically. These are typically | |
33 | smaller or not much larger than a PLT entry. | |
34 | Some also have a non-standard ABI which precludes dynamic linking. */ | |
35 | SFUNC_STATIC | |
36 | }; | |
37 | ||
7928e854 | 38 | /* Atomic model. */ |
39 | struct sh_atomic_model | |
40 | { | |
41 | enum enum_type | |
42 | { | |
43 | none = 0, | |
44 | soft_gusa, | |
45 | hard_llcs, | |
46 | soft_tcb, | |
47 | soft_imask, | |
48 | ||
49 | num_models | |
50 | }; | |
51 | ||
52 | /* If strict is set, disallow mixing of different models, as it would | |
53 | happen on SH4A. */ | |
54 | bool strict; | |
55 | enum_type type; | |
cfaba078 | 56 | |
57 | /* Name string as it was specified on the command line. */ | |
58 | const char* name; | |
59 | ||
60 | /* Name string as it is used in C/C++ defines. */ | |
61 | const char* cdef_name; | |
62 | ||
63 | /* GBR offset variable for TCB model. */ | |
7928e854 | 64 | int tcb_gbr_offset; |
65 | }; | |
66 | ||
67 | extern const sh_atomic_model& selected_atomic_model (void); | |
68 | ||
69 | /* Shortcuts to check the currently selected atomic model. */ | |
70 | #define TARGET_ATOMIC_ANY \ | |
6cf92cc1 | 71 | (selected_atomic_model ().type != sh_atomic_model::none) |
7928e854 | 72 | |
73 | #define TARGET_ATOMIC_STRICT \ | |
6cf92cc1 | 74 | (selected_atomic_model ().strict) |
7928e854 | 75 | |
76 | #define TARGET_ATOMIC_SOFT_GUSA \ | |
6cf92cc1 | 77 | (selected_atomic_model ().type == sh_atomic_model::soft_gusa) |
7928e854 | 78 | |
79 | #define TARGET_ATOMIC_HARD_LLCS \ | |
6cf92cc1 | 80 | (selected_atomic_model ().type == sh_atomic_model::hard_llcs) |
7928e854 | 81 | |
82 | #define TARGET_ATOMIC_SOFT_TCB \ | |
6cf92cc1 | 83 | (selected_atomic_model ().type == sh_atomic_model::soft_tcb) |
7928e854 | 84 | |
85 | #define TARGET_ATOMIC_SOFT_TCB_GBR_OFFSET_RTX \ | |
86 | GEN_INT (selected_atomic_model ().tcb_gbr_offset) | |
87 | ||
88 | #define TARGET_ATOMIC_SOFT_IMASK \ | |
6cf92cc1 | 89 | (selected_atomic_model ().type == sh_atomic_model::soft_imask) |
7928e854 | 90 | |
b7dbbdb2 | 91 | #ifdef RTX_CODE |
9435e831 | 92 | extern rtx sh_fsca_sf2int (void); |
9435e831 | 93 | extern rtx sh_fsca_int2sf (void); |
b7dbbdb2 | 94 | |
95 | /* Declare functions defined in sh.c and used in templates. */ | |
2dd4467f | 96 | extern bool sh_lra_p (void); |
b7dbbdb2 | 97 | |
d3ffa7b4 | 98 | extern const char *output_branch (int, rtx_insn *, rtx *); |
b82334f7 | 99 | extern const char *output_ieee_ccmpeq (rtx_insn *, rtx *); |
100 | extern const char *output_branchy_insn (enum rtx_code, const char *, | |
101 | rtx_insn *, rtx *); | |
3754d046 | 102 | extern const char *output_movedouble (rtx, rtx[], machine_mode); |
103 | extern const char *output_movepcrel (rtx, rtx[], machine_mode); | |
b82334f7 | 104 | extern const char *output_far_jump (rtx_insn *, rtx); |
b7dbbdb2 | 105 | |
d3ffa7b4 | 106 | extern rtx sfunc_uses_reg (rtx_insn *); |
91a55c11 | 107 | extern int barrier_align (rtx_insn *); |
ed3e6e5d | 108 | extern int sh_loop_align (rtx_insn *); |
a3b1178e | 109 | extern bool fp_zero_operand (rtx); |
110 | extern bool fp_one_operand (rtx); | |
3754d046 | 111 | extern bool sh_legitimate_index_p (machine_mode, rtx, bool, bool); |
112 | extern bool sh_legitimize_reload_address (rtx *, machine_mode, int, int); | |
113 | extern rtx legitimize_pic_address (rtx, machine_mode, rtx); | |
a3b1178e | 114 | extern bool nonpic_symbol_mentioned_p (rtx); |
04f04b72 | 115 | extern void output_pic_addr_const (FILE *, rtx); |
a3b1178e | 116 | extern bool expand_block_move (rtx *); |
3754d046 | 117 | extern void prepare_move_operands (rtx[], machine_mode mode); |
ccd57e8a | 118 | extern bool sh_expand_cmpstr (rtx *); |
b421555d | 119 | extern bool sh_expand_cmpnstr (rtx *); |
c2daae6e | 120 | extern bool sh_expand_strlen (rtx *); |
1878fb5b | 121 | extern void sh_expand_setmem (rtx *); |
3754d046 | 122 | extern enum rtx_code prepare_cbranch_operands (rtx *, machine_mode mode, |
5be30882 | 123 | enum rtx_code comparison); |
124 | extern void expand_cbranchsi4 (rtx *operands, enum rtx_code comparison, int); | |
125 | extern bool expand_cbranchdi4 (rtx *operands, enum rtx_code comparison); | |
74f4459c | 126 | extern void sh_emit_scc_to_t (enum rtx_code, rtx, rtx); |
3754d046 | 127 | extern rtx sh_emit_cheap_store_flag (machine_mode, enum rtx_code, rtx, rtx); |
128 | extern void sh_emit_compare_and_branch (rtx *, machine_mode); | |
129 | extern void sh_emit_compare_and_set (rtx *, machine_mode); | |
55c71520 | 130 | extern bool sh_ashlsi_clobbers_t_reg_p (rtx); |
8cec7a6e | 131 | extern bool sh_lshrsi_clobbers_t_reg_p (rtx); |
04f04b72 | 132 | extern void gen_shifty_op (int, rtx *); |
133 | extern void gen_shifty_hi_op (int, rtx *); | |
a3b1178e | 134 | extern bool expand_ashiftrt (rtx *); |
135 | extern bool sh_dynamicalize_shift_p (rtx); | |
04f04b72 | 136 | extern int shl_and_kind (rtx, rtx, int *); |
137 | extern int shl_and_length (rtx); | |
138 | extern int shl_and_scr_length (rtx); | |
a3b1178e | 139 | extern bool gen_shl_and (rtx, rtx, rtx, rtx); |
04f04b72 | 140 | extern int shl_sext_kind (rtx, rtx, int *); |
141 | extern int shl_sext_length (rtx); | |
a3b1178e | 142 | extern bool gen_shl_sext (rtx, rtx, rtx, rtx); |
04f04b72 | 143 | extern rtx gen_datalabel_ref (rtx); |
144 | extern int regs_used (rtx, int); | |
91a55c11 | 145 | extern void fixup_addr_diff_vecs (rtx_insn *); |
04f04b72 | 146 | extern int get_dest_uid (rtx, int); |
b82334f7 | 147 | extern void final_prescan_insn (rtx_insn *, rtx *, int); |
3754d046 | 148 | extern enum tls_model tls_symbolic_operand (rtx, machine_mode); |
149 | extern bool system_reg_operand (rtx, machine_mode); | |
91a55c11 | 150 | extern bool reg_unused_after (rtx, rtx_insn *); |
b82334f7 | 151 | extern int sh_insn_length_adjustment (rtx_insn *); |
04f04b72 | 152 | extern void sh_expand_unop_v2sf (enum rtx_code, rtx, rtx); |
153 | extern void sh_expand_binop_v2sf (enum rtx_code, rtx, rtx, rtx); | |
9db04979 | 154 | extern bool sh_expand_t_scc (rtx *); |
3754d046 | 155 | extern rtx sh_gen_truncate (machine_mode, rtx, int); |
156 | extern bool sh_vector_mode_supported_p (machine_mode); | |
c8378feb | 157 | extern bool sh_cfun_trap_exit_p (void); |
1c733bf7 | 158 | extern rtx sh_find_equiv_gbr_addr (rtx_insn* cur_insn, rtx mem); |
21910658 | 159 | extern int sh_eval_treg_value (rtx op); |
9db63610 | 160 | extern HOST_WIDE_INT sh_disp_addr_displacement (rtx mem_op); |
161 | extern int sh_max_mov_insn_displacement (machine_mode mode, bool consider_sh2a); | |
90e650e5 | 162 | extern bool sh_movsf_ie_ra_split_p (rtx, rtx, rtx); |
ec0e49e4 | 163 | extern void sh_expand_sym_label2reg (rtx, rtx, rtx, bool); |
99af687a | 164 | |
165 | /* Result value of sh_find_set_of_reg. */ | |
166 | struct set_of_reg | |
167 | { | |
168 | /* The insn where sh_find_set_of_reg stopped looking. | |
169 | Can be NULL_RTX if the end of the insn list was reached. */ | |
33f075ea | 170 | rtx_insn* insn; |
99af687a | 171 | |
172 | /* The set rtx of the specified reg if found, NULL_RTX otherwise. */ | |
173 | const_rtx set_rtx; | |
174 | ||
175 | /* The set source rtx of the specified reg if found, NULL_RTX otherwise. | |
176 | Usually, this is the most interesting return value. */ | |
177 | rtx set_src; | |
178 | }; | |
179 | ||
33f075ea | 180 | /* Given a reg rtx and a start insn, try to find the insn that sets the |
181 | specified reg by using the specified insn stepping function, such as | |
182 | 'prev_nonnote_insn_bb'. When the insn is found, try to extract the rtx | |
183 | of the reg set. */ | |
184 | template <typename F> inline set_of_reg | |
394e78ee | 185 | sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc, |
186 | bool ignore_reg_reg_copies = false) | |
33f075ea | 187 | { |
188 | set_of_reg result; | |
189 | result.insn = insn; | |
190 | result.set_rtx = NULL_RTX; | |
191 | result.set_src = NULL_RTX; | |
192 | ||
193 | if (!REG_P (reg) || insn == NULL_RTX) | |
194 | return result; | |
195 | ||
9971a66b | 196 | for (rtx_insn* i = stepfunc (insn); i != NULL_RTX; i = stepfunc (i)) |
33f075ea | 197 | { |
9971a66b | 198 | if (BARRIER_P (i)) |
4a03e703 | 199 | break; |
9971a66b | 200 | if (!INSN_P (i) || DEBUG_INSN_P (i)) |
201 | continue; | |
202 | if (reg_set_p (reg, i)) | |
33f075ea | 203 | { |
9971a66b | 204 | if (CALL_P (i)) |
205 | break; | |
206 | ||
207 | result.insn = i; | |
208 | result.set_rtx = set_of (reg, i); | |
33f075ea | 209 | |
210 | if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET) | |
4a03e703 | 211 | break; |
33f075ea | 212 | |
213 | result.set_src = XEXP (result.set_rtx, 1); | |
394e78ee | 214 | |
215 | if (ignore_reg_reg_copies && REG_P (result.set_src)) | |
216 | { | |
217 | reg = result.set_src; | |
218 | continue; | |
219 | } | |
220 | if (ignore_reg_reg_copies && SUBREG_P (result.set_src) | |
221 | && REG_P (SUBREG_REG (result.set_src))) | |
222 | { | |
223 | reg = SUBREG_REG (result.set_src); | |
224 | continue; | |
225 | } | |
226 | ||
4a03e703 | 227 | break; |
33f075ea | 228 | } |
229 | } | |
230 | ||
4a03e703 | 231 | if (result.set_src != NULL) |
232 | gcc_assert (result.insn != NULL && result.set_rtx != NULL); | |
233 | ||
33f075ea | 234 | return result; |
235 | } | |
236 | ||
394e78ee | 237 | /* Result value of sh_find_extending_set_of_reg. */ |
238 | struct sh_extending_set_of_reg : public set_of_reg | |
239 | { | |
240 | /* The mode the set is extending from (QImode or HImode), or VOIDmode if | |
241 | this is not a zero/sign extending set. */ | |
242 | machine_mode from_mode; | |
243 | ||
244 | /* ZERO_EXTEND, SIGN_EXTEND or UNKNOWN. */ | |
245 | rtx_code ext_code; | |
246 | ||
247 | sh_extending_set_of_reg (rtx_insn* i) | |
248 | { | |
249 | insn = i; | |
250 | set_rtx = NULL; | |
251 | set_src = NULL; | |
252 | from_mode = VOIDmode; | |
253 | ext_code = UNKNOWN; | |
254 | } | |
255 | ||
256 | sh_extending_set_of_reg (const set_of_reg& rhs) | |
257 | { | |
258 | *((set_of_reg*)this) = rhs; | |
259 | from_mode = VOIDmode; | |
260 | ext_code = UNKNOWN; | |
261 | } | |
262 | ||
6c97af1b | 263 | /* Returns true if it's possible to use the source reg of the sign |
264 | or zero extending set directly, bypassing the extension. */ | |
265 | bool can_use_as_unextended_reg (void) const; | |
266 | ||
267 | /* Returns the reg rtx of the sign or zero extending set source, that can | |
268 | be safely used at the specified insn in SImode. */ | |
269 | rtx use_as_unextended_reg (rtx_insn* use_at_insn) const; | |
270 | ||
394e78ee | 271 | /* Returns the reg rtx of the sign or zero extending result, that can be |
272 | safely used at the specified insn in SImode. If the set source is an | |
273 | implicitly sign extending mem load, the mem load is converted into an | |
274 | explicitly sign extending mem load. */ | |
275 | rtx use_as_extended_reg (rtx_insn* use_at_insn) const; | |
276 | }; | |
277 | ||
278 | extern sh_extending_set_of_reg sh_find_extending_set_of_reg (rtx reg, | |
279 | rtx_insn* insn); | |
280 | ||
33f075ea | 281 | extern bool sh_is_logical_t_store_expr (rtx op, rtx_insn* insn); |
282 | extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn); | |
283 | extern bool sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, | |
284 | rtx operands[]); | |
394e78ee | 285 | extern void sh_split_tst_subregs (rtx_insn* curr_insn, |
286 | machine_mode subreg_mode, int subreg_offset, | |
287 | rtx operands[]); | |
6c97af1b | 288 | |
289 | extern bool sh_is_nott_insn (const rtx_insn* i); | |
290 | extern rtx sh_movt_set_dest (const rtx_insn* i); | |
291 | extern rtx sh_movrt_set_dest (const rtx_insn* i); | |
292 | ||
293 | inline bool sh_is_movt_insn (const rtx_insn* i) | |
294 | { | |
295 | return sh_movt_set_dest (i) != NULL; | |
296 | } | |
297 | ||
298 | inline bool sh_is_movrt_insn (const rtx_insn* i) | |
299 | { | |
300 | return sh_movrt_set_dest (i) != NULL; | |
301 | } | |
302 | ||
303 | extern bool sh_insn_operands_modified_between_p (rtx_insn* operands_insn, | |
304 | const rtx_insn* from, | |
305 | const rtx_insn* to); | |
306 | ||
307 | extern bool sh_reg_dead_or_unused_after_insn (const rtx_insn* i, int regno); | |
394e78ee | 308 | extern void sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno); |
e13062e7 | 309 | extern rtx_insn* sh_check_add_incdec_notes (rtx_insn* i); |
0394e184 | 310 | extern rtx sh_remove_overlapping_post_inc (rtx dst, rtx src); |
311 | extern rtx_insn* sh_peephole_emit_move_insn (rtx dst, rtx src); | |
6c97af1b | 312 | |
313 | extern bool sh_in_recog_treg_set_expr (void); | |
314 | extern bool sh_recog_treg_set_expr (rtx op, machine_mode mode); | |
315 | ||
316 | /* Result value of sh_split_treg_set_expr. Contains the first insn emitted | |
317 | and the optional trailing nott insn. */ | |
318 | class sh_treg_insns | |
319 | { | |
320 | public: | |
321 | sh_treg_insns (void) : m_first_insn (NULL), m_trailing_nott_insn (NULL) { } | |
322 | sh_treg_insns (rtx_insn* first_insn, rtx_insn* nott_insn) | |
323 | : m_first_insn (first_insn), | |
324 | m_trailing_nott_insn (nott_insn) | |
325 | { } | |
326 | ||
327 | bool was_treg_operand (void) const { return m_first_insn == NULL; } | |
328 | bool has_trailing_nott (void) const { return m_trailing_nott_insn != NULL; } | |
329 | rtx_insn* trailing_nott (void) const { return m_trailing_nott_insn; } | |
330 | rtx_insn* first_insn (void) const { return m_first_insn; } | |
331 | ||
332 | /* If there is a trailing nott, remove it from the emitted insns and | |
333 | return true. Return false otherwise. */ | |
334 | bool | |
335 | remove_trailing_nott (void) | |
336 | { | |
337 | if (!has_trailing_nott ()) | |
338 | return false; | |
339 | ||
340 | remove_insn (trailing_nott ()); | |
341 | return true; | |
342 | } | |
343 | ||
344 | private: | |
345 | rtx_insn* m_first_insn; | |
346 | rtx_insn* m_trailing_nott_insn; | |
347 | }; | |
348 | ||
349 | extern sh_treg_insns sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn); | |
350 | ||
b7dbbdb2 | 351 | #endif /* RTX_CODE */ |
352 | ||
cfaba078 | 353 | extern void sh_cpu_cpp_builtins (cpp_reader* pfile); |
354 | ||
04f04b72 | 355 | extern const char *output_jump_label_table (void); |
a6be7821 | 356 | extern rtx get_t_reg_rtx (void); |
04f04b72 | 357 | extern int sh_media_register_for_return (void); |
358 | extern void sh_expand_prologue (void); | |
66209063 | 359 | extern void sh_expand_epilogue (bool); |
04f04b72 | 360 | extern void sh_set_return_address (rtx, rtx); |
361 | extern int initial_elimination_offset (int, int); | |
a3b1178e | 362 | extern bool sh_hard_regno_rename_ok (unsigned int, unsigned int); |
363 | extern bool sh_cfun_interrupt_handler_p (void); | |
364 | extern bool sh_cfun_resbank_handler_p (void); | |
365 | extern bool sh_attr_renesas_p (const_tree); | |
366 | extern bool sh_cfun_attr_renesas_p (void); | |
22aae821 | 367 | extern bool sh_cannot_change_mode_class |
3754d046 | 368 | (machine_mode, machine_mode, enum reg_class); |
369 | extern bool sh_small_register_classes_for_mode_p (machine_mode); | |
04f04b72 | 370 | extern void sh_mark_label (rtx, int); |
91a55c11 | 371 | extern bool check_use_sfunc_addr (rtx_insn *, rtx); |
18862b5a | 372 | |
373 | #ifdef HARD_CONST | |
04f04b72 | 374 | extern void fpscr_set_from_mem (int, HARD_REG_SET); |
18862b5a | 375 | #endif |
1fcd08b1 | 376 | |
04f04b72 | 377 | extern void sh_pr_interrupt (struct cpp_reader *); |
378 | extern void sh_pr_trapa (struct cpp_reader *); | |
379 | extern void sh_pr_nosave_low_regs (struct cpp_reader *); | |
bcc58dc6 | 380 | |
381 | struct function_symbol_result | |
382 | { | |
383 | function_symbol_result (void) : sym (NULL), lab (NULL) { } | |
384 | function_symbol_result (rtx s, rtx l) : sym (s), lab (l) { } | |
385 | ||
386 | rtx sym; | |
387 | rtx lab; | |
388 | }; | |
389 | ||
390 | extern function_symbol_result function_symbol (rtx, const char *, | |
391 | sh_function_kind); | |
392 | extern rtx sh_get_fdpic_reg_initial_val (void); | |
41fafa66 | 393 | extern rtx sh_get_pr_initial_val (void); |
1fcd08b1 | 394 | |
6c049e03 | 395 | extern void sh_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, |
3754d046 | 396 | signed int, machine_mode); |
e1190e3a | 397 | extern rtx sh_dwarf_register_span (rtx); |
45550790 | 398 | |
727d658b | 399 | extern int shmedia_cleanup_truncate (rtx); |
59312820 | 400 | |
a3b1178e | 401 | extern bool sh_contains_memref_p (rtx); |
402 | extern bool sh_loads_bankedreg_p (rtx); | |
59312820 | 403 | extern rtx shmedia_prepare_call_address (rtx fnaddr, int is_sibcall); |
5241f4ad | 404 | extern int sh2a_get_function_vector_number (rtx); |
a3b1178e | 405 | extern bool sh2a_is_function_vector_call (rtx); |
d47be40b | 406 | extern void sh_fix_range (const char *); |
3754d046 | 407 | extern bool sh_hard_regno_mode_ok (unsigned int, machine_mode); |
ea68d4ba | 408 | extern machine_mode sh_hard_regno_caller_save_mode (unsigned int, unsigned int, |
409 | machine_mode); | |
9579a4b9 | 410 | extern bool sh_can_use_simple_return_p (void); |
bcc58dc6 | 411 | extern rtx sh_load_function_descriptor (rtx); |
2a281353 | 412 | #endif /* ! GCC_SH_PROTOS_H */ |