]>
Commit | Line | Data |
---|---|---|
c8f0269d | 1 | /* Definitions of target machine for GNU compiler for Renesas / SuperH SH. |
a5544970 | 2 | Copyright (C) 1993-2019 Free Software Foundation, Inc. |
318881c0 KG |
3 | Contributed by Steve Chamberlain (sac@cygnus.com). |
4 | Improved by Jim Wilson (wilson@cygnus.com). | |
5 | ||
7ec022b2 | 6 | This file is part of GCC. |
318881c0 | 7 | |
7ec022b2 | 8 | GCC is free software; you can redistribute it and/or modify |
318881c0 | 9 | it under the terms of the GNU General Public License as published by |
2f83c7d6 | 10 | the Free Software Foundation; either version 3, or (at your option) |
318881c0 KG |
11 | any later version. |
12 | ||
7ec022b2 | 13 | GCC is distributed in the hope that it will be useful, |
318881c0 KG |
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 | |
2f83c7d6 NC |
19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ | |
318881c0 | 21 | |
8b97c5f8 ZW |
22 | #ifndef GCC_SH_PROTOS_H |
23 | #define GCC_SH_PROTOS_H | |
24 | ||
73a4d10b R |
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 | ||
318881c0 | 38 | #ifdef RTX_CODE |
312209c6 | 39 | extern rtx sh_fsca_sf2int (void); |
312209c6 | 40 | extern rtx sh_fsca_int2sf (void); |
318881c0 KG |
41 | |
42 | /* Declare functions defined in sh.c and used in templates. */ | |
a981b743 | 43 | extern bool sh_lra_p (void); |
318881c0 | 44 | |
84034c69 | 45 | extern const char *output_branch (int, rtx_insn *, rtx *); |
6cb7eb41 DM |
46 | extern const char *output_ieee_ccmpeq (rtx_insn *, rtx *); |
47 | extern const char *output_branchy_insn (enum rtx_code, const char *, | |
48 | rtx_insn *, rtx *); | |
ef4bddc2 RS |
49 | extern const char *output_movedouble (rtx, rtx[], machine_mode); |
50 | extern const char *output_movepcrel (rtx, rtx[], machine_mode); | |
6cb7eb41 | 51 | extern const char *output_far_jump (rtx_insn *, rtx); |
318881c0 | 52 | |
84034c69 | 53 | extern rtx sfunc_uses_reg (rtx_insn *); |
b32d5189 | 54 | extern int barrier_align (rtx_insn *); |
647d790d | 55 | extern int sh_loop_align (rtx_insn *); |
aaf701c5 OE |
56 | extern bool fp_zero_operand (rtx); |
57 | extern bool fp_one_operand (rtx); | |
ef4bddc2 RS |
58 | extern bool sh_legitimate_index_p (machine_mode, rtx, bool, bool); |
59 | extern bool sh_legitimize_reload_address (rtx *, machine_mode, int, int); | |
60 | extern rtx legitimize_pic_address (rtx, machine_mode, rtx); | |
aaf701c5 | 61 | extern bool nonpic_symbol_mentioned_p (rtx); |
cf277499 | 62 | extern void output_pic_addr_const (FILE *, rtx); |
aaf701c5 | 63 | extern bool expand_block_move (rtx *); |
ef4bddc2 | 64 | extern void prepare_move_operands (rtx[], machine_mode mode); |
8e701300 | 65 | extern bool sh_expand_cmpstr (rtx *); |
ca494b8d | 66 | extern bool sh_expand_cmpnstr (rtx *); |
3a1a7897 | 67 | extern bool sh_expand_strlen (rtx *); |
fa1aecc1 | 68 | extern void sh_expand_setmem (rtx *); |
ef4bddc2 | 69 | extern enum rtx_code prepare_cbranch_operands (rtx *, machine_mode mode, |
78d310c2 | 70 | enum rtx_code comparison); |
5fa396ad | 71 | extern void expand_cbranchsi4 (rtx *operands, enum rtx_code comparison); |
78d310c2 | 72 | extern bool expand_cbranchdi4 (rtx *operands, enum rtx_code comparison); |
f90b7a5a | 73 | extern void sh_emit_scc_to_t (enum rtx_code, rtx, rtx); |
ef4bddc2 RS |
74 | extern void sh_emit_compare_and_branch (rtx *, machine_mode); |
75 | extern void sh_emit_compare_and_set (rtx *, machine_mode); | |
70d4736c | 76 | extern bool sh_ashlsi_clobbers_t_reg_p (rtx); |
5592815a | 77 | extern bool sh_lshrsi_clobbers_t_reg_p (rtx); |
cf277499 SB |
78 | extern void gen_shifty_op (int, rtx *); |
79 | extern void gen_shifty_hi_op (int, rtx *); | |
aaf701c5 OE |
80 | extern bool expand_ashiftrt (rtx *); |
81 | extern bool sh_dynamicalize_shift_p (rtx); | |
cf277499 SB |
82 | extern int shl_and_kind (rtx, rtx, int *); |
83 | extern int shl_and_length (rtx); | |
84 | extern int shl_and_scr_length (rtx); | |
aaf701c5 | 85 | extern bool gen_shl_and (rtx, rtx, rtx, rtx); |
cf277499 SB |
86 | extern int shl_sext_kind (rtx, rtx, int *); |
87 | extern int shl_sext_length (rtx); | |
aaf701c5 | 88 | extern bool gen_shl_sext (rtx, rtx, rtx, rtx); |
cf277499 | 89 | extern int regs_used (rtx, int); |
b32d5189 | 90 | extern void fixup_addr_diff_vecs (rtx_insn *); |
4dea3bff | 91 | extern int get_dest_uid (rtx_insn *, int); |
6cb7eb41 | 92 | extern void final_prescan_insn (rtx_insn *, rtx *, int); |
ef4bddc2 RS |
93 | extern enum tls_model tls_symbolic_operand (rtx, machine_mode); |
94 | extern bool system_reg_operand (rtx, machine_mode); | |
b32d5189 | 95 | extern bool reg_unused_after (rtx, rtx_insn *); |
6cb7eb41 | 96 | extern int sh_insn_length_adjustment (rtx_insn *); |
10c17a58 | 97 | extern bool sh_expand_t_scc (rtx *); |
ef4bddc2 RS |
98 | extern rtx sh_gen_truncate (machine_mode, rtx, int); |
99 | extern bool sh_vector_mode_supported_p (machine_mode); | |
d16202ba | 100 | extern bool sh_cfun_trap_exit_p (void); |
4eac9c2b | 101 | extern rtx sh_find_equiv_gbr_addr (rtx_insn* cur_insn, rtx mem); |
b4eca9c8 | 102 | extern int sh_eval_treg_value (rtx op); |
91f65b12 OE |
103 | extern HOST_WIDE_INT sh_disp_addr_displacement (rtx mem_op); |
104 | extern int sh_max_mov_insn_displacement (machine_mode mode, bool consider_sh2a); | |
6efc6b7f | 105 | extern bool sh_movsf_ie_ra_split_p (rtx, rtx, rtx); |
fbce972a | 106 | extern void sh_expand_sym_label2reg (rtx, rtx, rtx, bool); |
26943929 OE |
107 | |
108 | /* Result value of sh_find_set_of_reg. */ | |
109 | struct set_of_reg | |
110 | { | |
111 | /* The insn where sh_find_set_of_reg stopped looking. | |
112 | Can be NULL_RTX if the end of the insn list was reached. */ | |
355e9975 | 113 | rtx_insn* insn; |
26943929 OE |
114 | |
115 | /* The set rtx of the specified reg if found, NULL_RTX otherwise. */ | |
116 | const_rtx set_rtx; | |
117 | ||
118 | /* The set source rtx of the specified reg if found, NULL_RTX otherwise. | |
119 | Usually, this is the most interesting return value. */ | |
120 | rtx set_src; | |
121 | }; | |
122 | ||
c483db37 AO |
123 | /* Given a reg rtx and a start insn, try to find the insn that sets |
124 | the specified reg by using the specified insn stepping function, | |
125 | such as 'prev_nonnote_nondebug_insn_bb'. When the insn is found, | |
126 | try to extract the rtx of the reg set. */ | |
355e9975 | 127 | template <typename F> inline set_of_reg |
83e3f98b OE |
128 | sh_find_set_of_reg (rtx reg, rtx_insn* insn, F stepfunc, |
129 | bool ignore_reg_reg_copies = false) | |
355e9975 OE |
130 | { |
131 | set_of_reg result; | |
132 | result.insn = insn; | |
133 | result.set_rtx = NULL_RTX; | |
134 | result.set_src = NULL_RTX; | |
135 | ||
136 | if (!REG_P (reg) || insn == NULL_RTX) | |
137 | return result; | |
138 | ||
f6ba5bb2 | 139 | for (rtx_insn* i = stepfunc (insn); i != NULL_RTX; i = stepfunc (i)) |
355e9975 | 140 | { |
f6ba5bb2 | 141 | if (BARRIER_P (i)) |
b151091d | 142 | break; |
f6ba5bb2 OE |
143 | if (!INSN_P (i) || DEBUG_INSN_P (i)) |
144 | continue; | |
145 | if (reg_set_p (reg, i)) | |
355e9975 | 146 | { |
f6ba5bb2 OE |
147 | if (CALL_P (i)) |
148 | break; | |
149 | ||
150 | result.insn = i; | |
151 | result.set_rtx = set_of (reg, i); | |
355e9975 OE |
152 | |
153 | if (result.set_rtx == NULL_RTX || GET_CODE (result.set_rtx) != SET) | |
b151091d | 154 | break; |
355e9975 OE |
155 | |
156 | result.set_src = XEXP (result.set_rtx, 1); | |
83e3f98b OE |
157 | |
158 | if (ignore_reg_reg_copies && REG_P (result.set_src)) | |
159 | { | |
160 | reg = result.set_src; | |
161 | continue; | |
162 | } | |
163 | if (ignore_reg_reg_copies && SUBREG_P (result.set_src) | |
164 | && REG_P (SUBREG_REG (result.set_src))) | |
165 | { | |
166 | reg = SUBREG_REG (result.set_src); | |
167 | continue; | |
168 | } | |
169 | ||
b151091d | 170 | break; |
355e9975 OE |
171 | } |
172 | } | |
173 | ||
da5b1ec1 OE |
174 | /* If the searched reg is found inside a (mem (post_inc:SI (reg))), set_of |
175 | will return NULL and set_rtx will be NULL. | |
176 | In this case report a 'not found'. result.insn will always be non-null | |
177 | at this point, so no need to check it. */ | |
178 | if (result.set_src != NULL && result.set_rtx == NULL) | |
179 | result.set_src = NULL; | |
b151091d | 180 | |
355e9975 OE |
181 | return result; |
182 | } | |
183 | ||
83e3f98b OE |
184 | /* Result value of sh_find_extending_set_of_reg. */ |
185 | struct sh_extending_set_of_reg : public set_of_reg | |
186 | { | |
187 | /* The mode the set is extending from (QImode or HImode), or VOIDmode if | |
188 | this is not a zero/sign extending set. */ | |
189 | machine_mode from_mode; | |
190 | ||
191 | /* ZERO_EXTEND, SIGN_EXTEND or UNKNOWN. */ | |
192 | rtx_code ext_code; | |
193 | ||
194 | sh_extending_set_of_reg (rtx_insn* i) | |
195 | { | |
196 | insn = i; | |
197 | set_rtx = NULL; | |
198 | set_src = NULL; | |
199 | from_mode = VOIDmode; | |
200 | ext_code = UNKNOWN; | |
201 | } | |
202 | ||
203 | sh_extending_set_of_reg (const set_of_reg& rhs) | |
204 | { | |
205 | *((set_of_reg*)this) = rhs; | |
206 | from_mode = VOIDmode; | |
207 | ext_code = UNKNOWN; | |
208 | } | |
209 | ||
841dbf80 OE |
210 | /* Returns true if it's possible to use the source reg of the sign |
211 | or zero extending set directly, bypassing the extension. */ | |
212 | bool can_use_as_unextended_reg (void) const; | |
213 | ||
214 | /* Returns the reg rtx of the sign or zero extending set source, that can | |
215 | be safely used at the specified insn in SImode. */ | |
216 | rtx use_as_unextended_reg (rtx_insn* use_at_insn) const; | |
217 | ||
83e3f98b OE |
218 | /* Returns the reg rtx of the sign or zero extending result, that can be |
219 | safely used at the specified insn in SImode. If the set source is an | |
220 | implicitly sign extending mem load, the mem load is converted into an | |
221 | explicitly sign extending mem load. */ | |
222 | rtx use_as_extended_reg (rtx_insn* use_at_insn) const; | |
223 | }; | |
224 | ||
225 | extern sh_extending_set_of_reg sh_find_extending_set_of_reg (rtx reg, | |
226 | rtx_insn* insn); | |
227 | ||
355e9975 OE |
228 | extern bool sh_is_logical_t_store_expr (rtx op, rtx_insn* insn); |
229 | extern rtx sh_try_omit_signzero_extend (rtx extended_op, rtx_insn* insn); | |
230 | extern bool sh_split_movrt_negc_to_movt_xor (rtx_insn* curr_insn, | |
231 | rtx operands[]); | |
83e3f98b OE |
232 | extern void sh_split_tst_subregs (rtx_insn* curr_insn, |
233 | machine_mode subreg_mode, int subreg_offset, | |
234 | rtx operands[]); | |
841dbf80 OE |
235 | |
236 | extern bool sh_is_nott_insn (const rtx_insn* i); | |
237 | extern rtx sh_movt_set_dest (const rtx_insn* i); | |
50c6dd20 | 238 | extern rtx sh_movt_set_dest (const_rtx i); |
841dbf80 | 239 | extern rtx sh_movrt_set_dest (const rtx_insn* i); |
50c6dd20 | 240 | extern rtx sh_movrt_set_dest (const_rtx i); |
841dbf80 OE |
241 | |
242 | inline bool sh_is_movt_insn (const rtx_insn* i) | |
243 | { | |
244 | return sh_movt_set_dest (i) != NULL; | |
245 | } | |
246 | ||
247 | inline bool sh_is_movrt_insn (const rtx_insn* i) | |
248 | { | |
249 | return sh_movrt_set_dest (i) != NULL; | |
250 | } | |
251 | ||
252 | extern bool sh_insn_operands_modified_between_p (rtx_insn* operands_insn, | |
253 | const rtx_insn* from, | |
254 | const rtx_insn* to); | |
255 | ||
256 | extern bool sh_reg_dead_or_unused_after_insn (const rtx_insn* i, int regno); | |
83e3f98b | 257 | extern void sh_remove_reg_dead_or_unused_notes (rtx_insn* i, int regno); |
dac2637b | 258 | extern rtx_insn* sh_check_add_incdec_notes (rtx_insn* i); |
7dc5a9bb OE |
259 | extern rtx sh_remove_overlapping_post_inc (rtx dst, rtx src); |
260 | extern rtx_insn* sh_peephole_emit_move_insn (rtx dst, rtx src); | |
841dbf80 OE |
261 | |
262 | extern bool sh_in_recog_treg_set_expr (void); | |
263 | extern bool sh_recog_treg_set_expr (rtx op, machine_mode mode); | |
264 | ||
265 | /* Result value of sh_split_treg_set_expr. Contains the first insn emitted | |
266 | and the optional trailing nott insn. */ | |
267 | class sh_treg_insns | |
268 | { | |
269 | public: | |
270 | sh_treg_insns (void) : m_first_insn (NULL), m_trailing_nott_insn (NULL) { } | |
271 | sh_treg_insns (rtx_insn* first_insn, rtx_insn* nott_insn) | |
272 | : m_first_insn (first_insn), | |
273 | m_trailing_nott_insn (nott_insn) | |
274 | { } | |
275 | ||
276 | bool was_treg_operand (void) const { return m_first_insn == NULL; } | |
277 | bool has_trailing_nott (void) const { return m_trailing_nott_insn != NULL; } | |
278 | rtx_insn* trailing_nott (void) const { return m_trailing_nott_insn; } | |
279 | rtx_insn* first_insn (void) const { return m_first_insn; } | |
280 | ||
281 | /* If there is a trailing nott, remove it from the emitted insns and | |
282 | return true. Return false otherwise. */ | |
283 | bool | |
284 | remove_trailing_nott (void) | |
285 | { | |
286 | if (!has_trailing_nott ()) | |
287 | return false; | |
288 | ||
289 | remove_insn (trailing_nott ()); | |
290 | return true; | |
291 | } | |
292 | ||
293 | private: | |
294 | rtx_insn* m_first_insn; | |
295 | rtx_insn* m_trailing_nott_insn; | |
296 | }; | |
297 | ||
298 | extern sh_treg_insns sh_split_treg_set_expr (rtx x, rtx_insn* curr_insn); | |
299 | ||
e22daa4b OE |
300 | enum |
301 | { | |
302 | /* An effective conditional branch distance of zero bytes is impossible. | |
303 | Hence we can use it to designate an unknown value. */ | |
304 | unknown_cbranch_distance = 0u, | |
305 | infinite_cbranch_distance = ~0u | |
306 | }; | |
307 | ||
308 | unsigned int | |
309 | sh_cbranch_distance (rtx_insn* cbranch_insn, | |
310 | unsigned int max_dist = infinite_cbranch_distance); | |
311 | ||
318881c0 KG |
312 | #endif /* RTX_CODE */ |
313 | ||
9597375a OE |
314 | extern void sh_cpu_cpp_builtins (cpp_reader* pfile); |
315 | ||
cf277499 | 316 | extern const char *output_jump_label_table (void); |
f031c344 | 317 | extern rtx get_t_reg_rtx (void); |
cf277499 | 318 | extern void sh_expand_prologue (void); |
726d4cb7 | 319 | extern void sh_expand_epilogue (bool); |
cf277499 SB |
320 | extern void sh_set_return_address (rtx, rtx); |
321 | extern int initial_elimination_offset (int, int); | |
aaf701c5 OE |
322 | extern bool sh_hard_regno_rename_ok (unsigned int, unsigned int); |
323 | extern bool sh_cfun_interrupt_handler_p (void); | |
324 | extern bool sh_cfun_resbank_handler_p (void); | |
325 | extern bool sh_attr_renesas_p (const_tree); | |
326 | extern bool sh_cfun_attr_renesas_p (void); | |
ef4bddc2 | 327 | extern bool sh_small_register_classes_for_mode_p (machine_mode); |
cf277499 | 328 | extern void sh_mark_label (rtx, int); |
b32d5189 | 329 | extern bool check_use_sfunc_addr (rtx_insn *, rtx); |
9f09b1f2 R |
330 | |
331 | #ifdef HARD_CONST | |
cf277499 | 332 | extern void fpscr_set_from_mem (int, HARD_REG_SET); |
9f09b1f2 | 333 | #endif |
8b97c5f8 | 334 | |
cf277499 SB |
335 | extern void sh_pr_interrupt (struct cpp_reader *); |
336 | extern void sh_pr_trapa (struct cpp_reader *); | |
337 | extern void sh_pr_nosave_low_regs (struct cpp_reader *); | |
1e44e857 DJ |
338 | |
339 | struct function_symbol_result | |
340 | { | |
341 | function_symbol_result (void) : sym (NULL), lab (NULL) { } | |
342 | function_symbol_result (rtx s, rtx l) : sym (s), lab (l) { } | |
343 | ||
344 | rtx sym; | |
345 | rtx lab; | |
346 | }; | |
347 | ||
348 | extern function_symbol_result function_symbol (rtx, const char *, | |
349 | sh_function_kind); | |
350 | extern rtx sh_get_fdpic_reg_initial_val (void); | |
fada1961 | 351 | extern rtx sh_get_pr_initial_val (void); |
8b97c5f8 | 352 | |
50fe8924 | 353 | extern void sh_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, |
ef4bddc2 | 354 | signed int, machine_mode); |
63a9de54 | 355 | extern rtx sh_dwarf_register_span (rtx); |
61f71b34 | 356 | |
aaf701c5 OE |
357 | extern bool sh_contains_memref_p (rtx); |
358 | extern bool sh_loads_bankedreg_p (rtx); | |
561642fa | 359 | extern int sh2a_get_function_vector_number (rtx); |
aaf701c5 | 360 | extern bool sh2a_is_function_vector_call (rtx); |
3217af3e | 361 | extern void sh_fix_range (const char *); |
fc1fcfa0 KK |
362 | extern machine_mode sh_hard_regno_caller_save_mode (unsigned int, unsigned int, |
363 | machine_mode); | |
fcf8632e | 364 | extern bool sh_can_use_simple_return_p (void); |
1e44e857 | 365 | extern rtx sh_load_function_descriptor (rtx); |
88657302 | 366 | #endif /* ! GCC_SH_PROTOS_H */ |