Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/epiphany/epiphany.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Subroutines used for code generation on the EPIPHANY cpu. | |
2 Copyright (C) 1994-2017 Free Software Foundation, Inc. | |
3 Contributed by Embecosm on behalf of Adapteva, Inc. | |
4 | |
5 This file is part of GCC. | |
6 | |
7 GCC is free software; you can redistribute it and/or modify | |
8 it under the terms of the GNU General Public License as published by | |
9 the Free Software Foundation; either version 3, or (at your option) | |
10 any later version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 #include "config.h" | |
22 #include "system.h" | |
23 #include "coretypes.h" | |
24 #include "backend.h" | |
25 #include "target.h" | |
26 #include "rtl.h" | |
27 #include "tree.h" | |
28 #include "df.h" | |
29 #include "memmodel.h" | |
30 #include "tm_p.h" | |
31 #include "stringpool.h" | |
32 #include "attribs.h" | |
33 #include "optabs.h" | |
34 #include "emit-rtl.h" | |
35 #include "recog.h" | |
36 #include "diagnostic-core.h" | |
37 #include "alias.h" | |
38 #include "stor-layout.h" | |
39 #include "varasm.h" | |
40 #include "calls.h" | |
41 #include "output.h" | |
42 #include "insn-attr.h" | |
43 #include "explow.h" | |
44 #include "expr.h" | |
45 #include "tm-constrs.h" | |
46 #include "tree-pass.h" /* for current_pass */ | |
47 #include "context.h" | |
48 #include "pass_manager.h" | |
49 #include "builtins.h" | |
50 | |
51 /* Which cpu we're compiling for. */ | |
52 int epiphany_cpu_type; | |
53 | |
54 /* Name of mangle string to add to symbols to separate code compiled for each | |
55 cpu (or NULL). */ | |
56 const char *epiphany_mangle_cpu; | |
57 | |
58 /* Array of valid operand punctuation characters. */ | |
59 char epiphany_punct_chars[256]; | |
60 | |
61 /* The rounding mode that we generally use for floating point. */ | |
62 int epiphany_normal_fp_rounding; | |
63 | |
64 /* The pass instance, for use in epiphany_optimize_mode_switching. */ | |
65 static opt_pass *pass_mode_switch_use; | |
66 | |
67 static void epiphany_init_reg_tables (void); | |
68 static int get_epiphany_condition_code (rtx); | |
69 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *); | |
70 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int, | |
71 bool *); | |
72 static bool epiphany_pass_by_reference (cumulative_args_t, machine_mode, | |
73 const_tree, bool); | |
74 static rtx_insn *frame_insn (rtx); | |
75 | |
76 /* defines for the initialization of the GCC target structure. */ | |
77 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table | |
78 | |
79 #define TARGET_PRINT_OPERAND epiphany_print_operand | |
80 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address | |
81 | |
82 #define TARGET_RTX_COSTS epiphany_rtx_costs | |
83 #define TARGET_ADDRESS_COST epiphany_address_cost | |
84 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost | |
85 | |
86 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode | |
87 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true | |
88 | |
89 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory | |
90 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference | |
91 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true | |
92 #define TARGET_FUNCTION_VALUE epiphany_function_value | |
93 #define TARGET_LIBCALL_VALUE epiphany_libcall_value | |
94 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p | |
95 | |
96 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs | |
97 | |
98 /* Using the simplistic varags handling forces us to do partial reg/stack | |
99 argument passing for types with larger size (> 4 bytes) than alignment. */ | |
100 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes | |
101 | |
102 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall | |
103 | |
104 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate | |
105 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost | |
106 | |
107 #define TARGET_LRA_P hook_bool_void_false | |
108 | |
109 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p | |
110 | |
111 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload | |
112 | |
113 #define TARGET_OPTION_OVERRIDE epiphany_override_options | |
114 | |
115 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage | |
116 | |
117 #define TARGET_FUNCTION_ARG epiphany_function_arg | |
118 | |
119 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance | |
120 | |
121 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary | |
122 | |
123 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init | |
124 | |
125 /* Nonzero if the constant rtx value is a legitimate general operand. | |
126 We can handle any 32- or 64-bit constant. */ | |
127 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true | |
128 | |
129 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \ | |
130 epiphany_min_divisions_for_recip_mul | |
131 | |
132 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode | |
133 | |
134 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p | |
135 | |
136 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \ | |
137 epiphany_vector_alignment_reachable | |
138 | |
139 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \ | |
140 epiphany_support_vector_misalignment | |
141 | |
142 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ | |
143 hook_bool_const_tree_hwi_hwi_const_tree_true | |
144 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk | |
145 | |
146 /* ??? we can use larger offsets for wider-mode sized accesses, but there | |
147 is no concept of anchors being dependent on the modes that they are used | |
148 for, so we can only use an offset range that would suit all modes. */ | |
149 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047) | |
150 /* We further restrict the minimum to be a multiple of eight. */ | |
151 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040) | |
152 | |
153 /* Mode switching hooks. */ | |
154 | |
155 #define TARGET_MODE_EMIT emit_set_fp_mode | |
156 | |
157 #define TARGET_MODE_NEEDED epiphany_mode_needed | |
158 | |
159 #define TARGET_MODE_PRIORITY epiphany_mode_priority | |
160 | |
161 #define TARGET_MODE_ENTRY epiphany_mode_entry | |
162 | |
163 #define TARGET_MODE_EXIT epiphany_mode_exit | |
164 | |
165 #define TARGET_MODE_AFTER epiphany_mode_after | |
166 | |
167 #include "target-def.h" | |
168 | |
169 #undef TARGET_ASM_ALIGNED_HI_OP | |
170 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" | |
171 #undef TARGET_ASM_ALIGNED_SI_OP | |
172 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" | |
173 | |
174 #undef TARGET_HARD_REGNO_MODE_OK | |
175 #define TARGET_HARD_REGNO_MODE_OK epiphany_hard_regno_mode_ok | |
176 | |
177 #undef TARGET_CONSTANT_ALIGNMENT | |
178 #define TARGET_CONSTANT_ALIGNMENT epiphany_constant_alignment | |
179 | |
180 #undef TARGET_STARTING_FRAME_OFFSET | |
181 #define TARGET_STARTING_FRAME_OFFSET epiphany_starting_frame_offset | |
182 | |
183 bool | |
184 epiphany_is_interrupt_p (tree decl) | |
185 { | |
186 tree attrs; | |
187 | |
188 attrs = DECL_ATTRIBUTES (decl); | |
189 if (lookup_attribute ("interrupt", attrs)) | |
190 return true; | |
191 else | |
192 return false; | |
193 } | |
194 | |
195 /* Called from epiphany_override_options. | |
196 We use this to initialize various things. */ | |
197 | |
198 static void | |
199 epiphany_init (void) | |
200 { | |
201 /* N.B. this pass must not run before the first optimize_mode_switching | |
202 pass because of the side offect of epiphany_mode_needed on | |
203 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before | |
204 pass_resolve_sw_modes. */ | |
205 pass_mode_switch_use = make_pass_mode_switch_use (g); | |
206 struct register_pass_info insert_use_info | |
207 = { pass_mode_switch_use, "mode_sw", | |
208 1, PASS_POS_INSERT_AFTER | |
209 }; | |
210 opt_pass *mode_sw2 | |
211 = g->get_passes()->get_pass_mode_switching ()->clone (); | |
212 struct register_pass_info mode_sw2_info | |
213 = { mode_sw2, "mode_sw", | |
214 1, PASS_POS_INSERT_AFTER | |
215 }; | |
216 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g); | |
217 struct register_pass_info mode_sw3_info | |
218 = { mode_sw3, "mode_sw", | |
219 1, PASS_POS_INSERT_AFTER | |
220 }; | |
221 opt_pass *mode_sw4 | |
222 = g->get_passes()->get_pass_split_all_insns ()->clone (); | |
223 struct register_pass_info mode_sw4_info | |
224 = { mode_sw4, "mode_sw", | |
225 1, PASS_POS_INSERT_AFTER | |
226 }; | |
227 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING; | |
228 #define N_ENTITIES ARRAY_SIZE (num_modes) | |
229 | |
230 epiphany_init_reg_tables (); | |
231 | |
232 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ | |
233 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars)); | |
234 epiphany_punct_chars['-'] = 1; | |
235 | |
236 epiphany_normal_fp_rounding | |
237 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC | |
238 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST); | |
239 register_pass (&mode_sw4_info); | |
240 register_pass (&mode_sw2_info); | |
241 register_pass (&mode_sw3_info); | |
242 register_pass (&insert_use_info); | |
243 register_pass (&mode_sw2_info); | |
244 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */ | |
245 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM); | |
246 | |
247 #if 1 /* As long as peep2_rescan is not implemented, | |
248 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,) | |
249 we need a second peephole2 pass to get reasonable code. */ | |
250 { | |
251 opt_pass *extra_peephole2 | |
252 = g->get_passes ()->get_pass_peephole2 ()->clone (); | |
253 struct register_pass_info peep2_2_info | |
254 = { extra_peephole2, "peephole2", | |
255 1, PASS_POS_INSERT_AFTER | |
256 }; | |
257 | |
258 register_pass (&peep2_2_info); | |
259 } | |
260 #endif | |
261 } | |
262 | |
263 /* The condition codes of the EPIPHANY, and the inverse function. */ | |
264 static const char *const epiphany_condition_codes[] = | |
265 { /* 0 1 2 3 4 5 6 7 8 9 */ | |
266 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu", | |
267 /* 10 11 12 13 */ | |
268 "beq","bne","blt", "blte", | |
269 }; | |
270 | |
271 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1) | |
272 | |
273 /* Returns the index of the EPIPHANY condition code string in | |
274 `epiphany_condition_codes'. COMPARISON should be an rtx like | |
275 `(eq (...) (...))'. */ | |
276 | |
277 static int | |
278 get_epiphany_condition_code (rtx comparison) | |
279 { | |
280 switch (GET_MODE (XEXP (comparison, 0))) | |
281 { | |
282 case E_CCmode: | |
283 switch (GET_CODE (comparison)) | |
284 { | |
285 case EQ : return 0; | |
286 case NE : return 1; | |
287 case LTU : return 2; | |
288 case GEU : return 3; | |
289 case GT : return 4; | |
290 case LE : return 5; | |
291 case GE : return 6; | |
292 case LT : return 7; | |
293 case GTU : return 8; | |
294 case LEU : return 9; | |
295 | |
296 default : gcc_unreachable (); | |
297 } | |
298 case E_CC_N_NEmode: | |
299 switch (GET_CODE (comparison)) | |
300 { | |
301 case EQ: return 6; | |
302 case NE: return 7; | |
303 default: gcc_unreachable (); | |
304 } | |
305 case E_CC_C_LTUmode: | |
306 switch (GET_CODE (comparison)) | |
307 { | |
308 case GEU: return 2; | |
309 case LTU: return 3; | |
310 default: gcc_unreachable (); | |
311 } | |
312 case E_CC_C_GTUmode: | |
313 switch (GET_CODE (comparison)) | |
314 { | |
315 case LEU: return 3; | |
316 case GTU: return 2; | |
317 default: gcc_unreachable (); | |
318 } | |
319 case E_CC_FPmode: | |
320 switch (GET_CODE (comparison)) | |
321 { | |
322 case EQ: return 10; | |
323 case NE: return 11; | |
324 case LT: return 12; | |
325 case LE: return 13; | |
326 default: gcc_unreachable (); | |
327 } | |
328 case E_CC_FP_EQmode: | |
329 switch (GET_CODE (comparison)) | |
330 { | |
331 case EQ: return 0; | |
332 case NE: return 1; | |
333 default: gcc_unreachable (); | |
334 } | |
335 case E_CC_FP_GTEmode: | |
336 switch (GET_CODE (comparison)) | |
337 { | |
338 case EQ: return 0; | |
339 case NE: return 1; | |
340 case GT : return 4; | |
341 case GE : return 6; | |
342 case UNLE : return 5; | |
343 case UNLT : return 7; | |
344 default: gcc_unreachable (); | |
345 } | |
346 case E_CC_FP_ORDmode: | |
347 switch (GET_CODE (comparison)) | |
348 { | |
349 case ORDERED: return 9; | |
350 case UNORDERED: return 8; | |
351 default: gcc_unreachable (); | |
352 } | |
353 case E_CC_FP_UNEQmode: | |
354 switch (GET_CODE (comparison)) | |
355 { | |
356 case UNEQ: return 9; | |
357 case LTGT: return 8; | |
358 default: gcc_unreachable (); | |
359 } | |
360 default: gcc_unreachable (); | |
361 } | |
362 /*NOTREACHED*/ | |
363 return (42); | |
364 } | |
365 | |
366 | |
367 /* Implement TARGET_HARD_REGNO_MODE_OK. */ | |
368 | |
369 static bool | |
370 epiphany_hard_regno_mode_ok (unsigned int regno, machine_mode mode) | |
371 { | |
372 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) | |
373 return (regno & 1) == 0 && GPR_P (regno); | |
374 else | |
375 return true; | |
376 } | |
377 | |
378 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, | |
379 return the mode to be used for the comparison. */ | |
380 | |
381 machine_mode | |
382 epiphany_select_cc_mode (enum rtx_code op, | |
383 rtx x ATTRIBUTE_UNUSED, | |
384 rtx y ATTRIBUTE_UNUSED) | |
385 { | |
386 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) | |
387 { | |
388 if (TARGET_SOFT_CMPSF | |
389 || op == ORDERED || op == UNORDERED) | |
390 { | |
391 if (op == EQ || op == NE) | |
392 return CC_FP_EQmode; | |
393 if (op == ORDERED || op == UNORDERED) | |
394 return CC_FP_ORDmode; | |
395 if (op == UNEQ || op == LTGT) | |
396 return CC_FP_UNEQmode; | |
397 return CC_FP_GTEmode; | |
398 } | |
399 return CC_FPmode; | |
400 } | |
401 /* recognize combiner pattern ashlsi_btst: | |
402 (parallel [ | |
403 (set (reg:N_NE 65 cc1) | |
404 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ]) | |
405 (const_int 1 [0x1]) | |
406 (const_int 0 [0x0])) | |
407 (const_int 0 [0x0]))) | |
408 (clobber (scratch:SI)) */ | |
409 else if ((op == EQ || op == NE) | |
410 && GET_CODE (x) == ZERO_EXTRACT | |
411 && XEXP (x, 1) == const1_rtx | |
412 && CONST_INT_P (XEXP (x, 2))) | |
413 return CC_N_NEmode; | |
414 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS) | |
415 return CC_C_LTUmode; | |
416 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS) | |
417 return CC_C_GTUmode; | |
418 else | |
419 return CCmode; | |
420 } | |
421 | |
422 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER]; | |
423 | |
424 static void | |
425 epiphany_init_reg_tables (void) | |
426 { | |
427 int i; | |
428 | |
429 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
430 { | |
431 if (i == GPR_LR) | |
432 epiphany_regno_reg_class[i] = LR_REGS; | |
433 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS) | |
434 epiphany_regno_reg_class[i] = SHORT_INSN_REGS; | |
435 else if (call_used_regs[i] | |
436 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i)) | |
437 epiphany_regno_reg_class[i] = SIBCALL_REGS; | |
438 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST) | |
439 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS; | |
440 else if (i < (GPR_LAST+1) | |
441 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM) | |
442 epiphany_regno_reg_class[i] = GENERAL_REGS; | |
443 else if (i == CC_REGNUM) | |
444 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */; | |
445 else | |
446 epiphany_regno_reg_class[i] = NO_REGS; | |
447 } | |
448 } | |
449 | |
450 /* EPIPHANY specific attribute support. | |
451 | |
452 The EPIPHANY has these attributes: | |
453 interrupt - for interrupt functions. | |
454 short_call - the function is assumed to be reachable with the b / bl | |
455 instructions. | |
456 long_call - the function address is loaded into a register before use. | |
457 disinterrupt - functions which mask interrupts throughout. | |
458 They unmask them while calling an interruptible | |
459 function, though. */ | |
460 | |
461 static const struct attribute_spec epiphany_attribute_table[] = | |
462 { | |
463 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ | |
464 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true }, | |
465 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false }, | |
466 { "long_call", 0, 0, false, true, true, NULL, false }, | |
467 { "short_call", 0, 0, false, true, true, NULL, false }, | |
468 { "disinterrupt", 0, 0, false, true, true, NULL, true }, | |
469 { NULL, 0, 0, false, false, false, NULL, false } | |
470 }; | |
471 | |
472 /* Handle an "interrupt" attribute; arguments as in | |
473 struct attribute_spec.handler. */ | |
474 static tree | |
475 epiphany_handle_interrupt_attribute (tree *node, tree name, tree args, | |
476 int flags ATTRIBUTE_UNUSED, | |
477 bool *no_add_attrs) | |
478 { | |
479 tree value; | |
480 | |
481 if (!args) | |
482 { | |
483 gcc_assert (DECL_P (*node)); | |
484 tree t = TREE_TYPE (*node); | |
485 if (TREE_CODE (t) != FUNCTION_TYPE) | |
486 warning (OPT_Wattributes, "%qE attribute only applies to functions", | |
487 name); | |
488 /* Argument handling and the stack layout for interrupt handlers | |
489 don't mix. It makes no sense in the first place, so emit an | |
490 error for this. */ | |
491 else if (TYPE_ARG_TYPES (t) | |
492 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node) | |
493 error_at (DECL_SOURCE_LOCATION (*node), | |
494 "interrupt handlers cannot have arguments"); | |
495 return NULL_TREE; | |
496 } | |
497 | |
498 value = TREE_VALUE (args); | |
499 | |
500 if (TREE_CODE (value) != STRING_CST) | |
501 { | |
502 warning (OPT_Wattributes, | |
503 "argument of %qE attribute is not a string constant", name); | |
504 *no_add_attrs = true; | |
505 } | |
506 else if (strcmp (TREE_STRING_POINTER (value), "reset") | |
507 && strcmp (TREE_STRING_POINTER (value), "software_exception") | |
508 && strcmp (TREE_STRING_POINTER (value), "page_miss") | |
509 && strcmp (TREE_STRING_POINTER (value), "timer0") | |
510 && strcmp (TREE_STRING_POINTER (value), "timer1") | |
511 && strcmp (TREE_STRING_POINTER (value), "message") | |
512 && strcmp (TREE_STRING_POINTER (value), "dma0") | |
513 && strcmp (TREE_STRING_POINTER (value), "dma1") | |
514 && strcmp (TREE_STRING_POINTER (value), "wand") | |
515 && strcmp (TREE_STRING_POINTER (value), "swi")) | |
516 { | |
517 warning (OPT_Wattributes, | |
518 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"", | |
519 name); | |
520 *no_add_attrs = true; | |
521 return NULL_TREE; | |
522 } | |
523 | |
524 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args), | |
525 flags, no_add_attrs); | |
526 } | |
527 | |
528 /* Handle a "forwarder_section" attribute; arguments as in | |
529 struct attribute_spec.handler. */ | |
530 static tree | |
531 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED, | |
532 tree name, tree args, | |
533 int flags ATTRIBUTE_UNUSED, | |
534 bool *no_add_attrs) | |
535 { | |
536 tree value; | |
537 | |
538 value = TREE_VALUE (args); | |
539 | |
540 if (TREE_CODE (value) != STRING_CST) | |
541 { | |
542 warning (OPT_Wattributes, | |
543 "argument of %qE attribute is not a string constant", name); | |
544 *no_add_attrs = true; | |
545 } | |
546 return NULL_TREE; | |
547 } | |
548 | |
549 | |
550 /* Misc. utilities. */ | |
551 | |
552 /* Generate a SYMBOL_REF for the special function NAME. When the address | |
553 can't be placed directly into a call instruction, and if possible, copy | |
554 it to a register so that cse / code hoisting is possible. */ | |
555 rtx | |
556 sfunc_symbol (const char *name) | |
557 { | |
558 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name); | |
559 | |
560 /* These sfuncs should be hidden, and every dso should get a copy. */ | |
561 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL; | |
562 if (TARGET_SHORT_CALLS) | |
563 ; /* Nothing to be done. */ | |
564 else if (can_create_pseudo_p ()) | |
565 sym = copy_to_mode_reg (Pmode, sym); | |
566 else /* We rely on reload to fix this up. */ | |
567 gcc_assert (!reload_in_progress || reload_completed); | |
568 return sym; | |
569 } | |
570 | |
571 /* X and Y are two things to compare using CODE in IN_MODE. | |
572 Emit the compare insn, construct the proper cc reg in the proper | |
573 mode, and return the rtx for the cc reg comparison in CMODE. */ | |
574 | |
575 rtx | |
576 gen_compare_reg (machine_mode cmode, enum rtx_code code, | |
577 machine_mode in_mode, rtx x, rtx y) | |
578 { | |
579 machine_mode mode = SELECT_CC_MODE (code, x, y); | |
580 rtx cc_reg, pat, clob0, clob1, clob2; | |
581 | |
582 if (in_mode == VOIDmode) | |
583 in_mode = GET_MODE (x); | |
584 if (in_mode == VOIDmode) | |
585 in_mode = GET_MODE (y); | |
586 | |
587 if (mode == CC_FPmode) | |
588 { | |
589 /* The epiphany has only EQ / NE / LT / LE conditions for | |
590 hardware floating point. */ | |
591 if (code == GT || code == GE || code == UNLE || code == UNLT) | |
592 { | |
593 rtx tmp = x; x = y; y = tmp; | |
594 code = swap_condition (code); | |
595 } | |
596 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM); | |
597 y = force_reg (in_mode, y); | |
598 } | |
599 else | |
600 { | |
601 if (mode == CC_FP_GTEmode | |
602 && (code == LE || code == LT || code == UNGT || code == UNGE)) | |
603 { | |
604 if (flag_finite_math_only | |
605 && ((REG_P (x) && REGNO (x) == GPR_0) | |
606 || (REG_P (y) && REGNO (y) == GPR_1))) | |
607 switch (code) | |
608 { | |
609 case LE: code = UNLE; break; | |
610 case LT: code = UNLT; break; | |
611 case UNGT: code = GT; break; | |
612 case UNGE: code = GE; break; | |
613 default: gcc_unreachable (); | |
614 } | |
615 else | |
616 { | |
617 rtx tmp = x; x = y; y = tmp; | |
618 code = swap_condition (code); | |
619 } | |
620 } | |
621 cc_reg = gen_rtx_REG (mode, CC_REGNUM); | |
622 } | |
623 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode | |
624 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode) | |
625 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */ | |
626 && (!REG_P (x) || REGNO (x) != GPR_0 | |
627 || !REG_P (y) || REGNO (y) != GPR_1)) | |
628 { | |
629 rtx reg; | |
630 | |
631 #if 0 | |
632 /* ??? We should really do the r0/r1 clobber only during rtl expansion, | |
633 but just like the flag clobber of movsicc, we have to allow | |
634 this for ifcvt to work, on the assumption that we'll only want | |
635 to do this if these registers have been used before by the | |
636 pre-ifcvt code. */ | |
637 gcc_assert (currently_expanding_to_rtl); | |
638 #endif | |
639 reg = gen_rtx_REG (in_mode, GPR_0); | |
640 if (reg_overlap_mentioned_p (reg, y)) | |
641 return 0; | |
642 emit_move_insn (reg, x); | |
643 x = reg; | |
644 reg = gen_rtx_REG (in_mode, GPR_1); | |
645 emit_move_insn (reg, y); | |
646 y = reg; | |
647 } | |
648 else | |
649 x = force_reg (in_mode, x); | |
650 | |
651 pat = gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y)); | |
652 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode) | |
653 { | |
654 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2"; | |
655 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name)); | |
656 | |
657 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP)); | |
658 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR)); | |
659 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1)); | |
660 } | |
661 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode) | |
662 { | |
663 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2"; | |
664 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name)); | |
665 | |
666 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP)); | |
667 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16)); | |
668 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR)); | |
669 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use, | |
670 clob0, clob1, clob2)); | |
671 } | |
672 else | |
673 { | |
674 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode)); | |
675 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0)); | |
676 } | |
677 emit_insn (pat); | |
678 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx); | |
679 } | |
680 | |
681 /* The ROUND_ADVANCE* macros are local to this file. */ | |
682 /* Round SIZE up to a word boundary. */ | |
683 #define ROUND_ADVANCE(SIZE) \ | |
684 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) | |
685 | |
686 /* Round arg MODE/TYPE up to the next word boundary. */ | |
687 #define ROUND_ADVANCE_ARG(MODE, TYPE) \ | |
688 ((MODE) == BLKmode \ | |
689 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \ | |
690 : ROUND_ADVANCE (GET_MODE_SIZE (MODE))) | |
691 | |
692 /* Round CUM up to the necessary point for argument MODE/TYPE. */ | |
693 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \ | |
694 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \ | |
695 ? (((CUM) + 1) & ~1) \ | |
696 : (CUM)) | |
697 | |
698 static unsigned int | |
699 epiphany_function_arg_boundary (machine_mode mode, const_tree type) | |
700 { | |
701 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY) | |
702 return PARM_BOUNDARY; | |
703 return 2 * PARM_BOUNDARY; | |
704 } | |
705 | |
706 /* Do any needed setup for a variadic function. For the EPIPHANY, we | |
707 actually emit the code in epiphany_expand_prologue. | |
708 | |
709 CUM has not been updated for the last named argument which has type TYPE | |
710 and mode MODE, and we rely on this fact. */ | |
711 | |
712 | |
713 static void | |
714 epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode, | |
715 tree type, int *pretend_size, int no_rtl) | |
716 { | |
717 int first_anon_arg; | |
718 CUMULATIVE_ARGS next_cum; | |
719 machine_function_t *mf = MACHINE_FUNCTION (cfun); | |
720 | |
721 /* All BLKmode values are passed by reference. */ | |
722 gcc_assert (mode != BLKmode); | |
723 | |
724 next_cum = *get_cumulative_args (cum); | |
725 next_cum | |
726 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type); | |
727 first_anon_arg = next_cum; | |
728 | |
729 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl) | |
730 { | |
731 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */ | |
732 int first_reg_offset = first_anon_arg; | |
733 | |
734 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset) | |
735 * UNITS_PER_WORD); | |
736 } | |
737 mf->args_parsed = 1; | |
738 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0); | |
739 } | |
740 | |
741 static int | |
742 epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode, | |
743 tree type, bool named ATTRIBUTE_UNUSED) | |
744 { | |
745 int words = 0, rounded_cum; | |
746 | |
747 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true)); | |
748 | |
749 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type); | |
750 if (rounded_cum < MAX_EPIPHANY_PARM_REGS) | |
751 { | |
752 words = MAX_EPIPHANY_PARM_REGS - rounded_cum; | |
753 if (words >= ROUND_ADVANCE_ARG (mode, type)) | |
754 words = 0; | |
755 } | |
756 return words * UNITS_PER_WORD; | |
757 } | |
758 | |
759 /* Cost functions. */ | |
760 | |
761 /* Compute a (partial) cost for rtx X. Return true if the complete | |
762 cost has been computed, and false if subexpressions should be | |
763 scanned. In either case, *TOTAL contains the cost result. */ | |
764 | |
765 static bool | |
766 epiphany_rtx_costs (rtx x, machine_mode mode, int outer_code, | |
767 int opno ATTRIBUTE_UNUSED, | |
768 int *total, bool speed ATTRIBUTE_UNUSED) | |
769 { | |
770 int code = GET_CODE (x); | |
771 | |
772 switch (code) | |
773 { | |
774 /* Small integers in the right context are as cheap as registers. */ | |
775 case CONST_INT: | |
776 if ((outer_code == PLUS || outer_code == MINUS) | |
777 && SIMM11 (INTVAL (x))) | |
778 { | |
779 *total = 0; | |
780 return true; | |
781 } | |
782 if (IMM16 (INTVAL (x))) | |
783 { | |
784 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1); | |
785 return true; | |
786 } | |
787 /* FALLTHRU */ | |
788 | |
789 case CONST: | |
790 case LABEL_REF: | |
791 case SYMBOL_REF: | |
792 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1) | |
793 + (outer_code == SET ? 0 : 1)); | |
794 return true; | |
795 | |
796 case CONST_DOUBLE: | |
797 { | |
798 rtx high, low; | |
799 split_double (x, &high, &low); | |
800 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high)) | |
801 + !IMM16 (INTVAL (low))); | |
802 return true; | |
803 } | |
804 | |
805 case ASHIFT: | |
806 case ASHIFTRT: | |
807 case LSHIFTRT: | |
808 *total = COSTS_N_INSNS (1); | |
809 return true; | |
810 | |
811 case COMPARE: | |
812 switch (mode) | |
813 { | |
814 /* There are a number of single-insn combiner patterns that use | |
815 the flag side effects of arithmetic. */ | |
816 case E_CC_N_NEmode: | |
817 case E_CC_C_LTUmode: | |
818 case E_CC_C_GTUmode: | |
819 return true; | |
820 default: | |
821 return false; | |
822 } | |
823 | |
824 | |
825 case SET: | |
826 { | |
827 rtx src = SET_SRC (x); | |
828 if (BINARY_P (src)) | |
829 *total = 0; | |
830 return false; | |
831 } | |
832 | |
833 default: | |
834 return false; | |
835 } | |
836 } | |
837 | |
838 | |
839 /* Provide the costs of an addressing mode that contains ADDR. | |
840 If ADDR is not a valid address, its cost is irrelevant. */ | |
841 | |
842 static int | |
843 epiphany_address_cost (rtx addr, machine_mode mode, | |
844 addr_space_t as ATTRIBUTE_UNUSED, bool speed) | |
845 { | |
846 rtx reg; | |
847 rtx off = const0_rtx; | |
848 int i; | |
849 | |
850 if (speed) | |
851 return 0; | |
852 /* Return 0 for addresses valid in short insns, 1 for addresses only valid | |
853 in long insns. */ | |
854 switch (GET_CODE (addr)) | |
855 { | |
856 case PLUS : | |
857 reg = XEXP (addr, 0); | |
858 off = XEXP (addr, 1); | |
859 break; | |
860 case POST_MODIFY: | |
861 reg = XEXP (addr, 0); | |
862 off = XEXP (addr, 1); | |
863 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0))); | |
864 off = XEXP (off, 1); | |
865 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off)) | |
866 return 0; | |
867 return 1; | |
868 case REG: | |
869 default: | |
870 reg = addr; | |
871 break; | |
872 } | |
873 if (!satisfies_constraint_Rgs (reg)) | |
874 return 1; | |
875 /* The offset range available for short instructions depends on the mode | |
876 of the memory access. */ | |
877 /* First, make sure we have a valid integer. */ | |
878 if (!satisfies_constraint_L (off)) | |
879 return 1; | |
880 i = INTVAL (off); | |
881 switch (GET_MODE_SIZE (mode)) | |
882 { | |
883 default: | |
884 case 4: | |
885 if (i & 1) | |
886 return 1; | |
887 i >>= 1; | |
888 /* Fall through. */ | |
889 case 2: | |
890 if (i & 1) | |
891 return 1; | |
892 i >>= 1; | |
893 /* Fall through. */ | |
894 case 1: | |
895 return i < -7 || i > 7; | |
896 } | |
897 } | |
898 | |
899 /* Compute the cost of moving data between registers and memory. | |
900 For integer, load latency is twice as long as register-register moves, | |
901 but issue pich is the same. For floating point, load latency is three | |
902 times as much as a reg-reg move. */ | |
903 static int | |
904 epiphany_memory_move_cost (machine_mode mode, | |
905 reg_class_t rclass ATTRIBUTE_UNUSED, | |
906 bool in ATTRIBUTE_UNUSED) | |
907 { | |
908 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4; | |
909 } | |
910 | |
911 /* Function prologue/epilogue handlers. */ | |
912 | |
913 /* EPIPHANY stack frames look like: | |
914 | |
915 Before call After call | |
916 +-----------------------+ +-----------------------+ | |
917 | | | | | |
918 high | local variables, | | local variables, | | |
919 mem | reg save area, etc. | | reg save area, etc. | | |
920 | | | | | |
921 +-----------------------+ +-----------------------+ | |
922 | | | | | |
923 | arguments on stack. | | arguments on stack. | | |
924 | | | | | |
925 SP+8->+-----------------------+FP+8m->+-----------------------+ | |
926 | 2 word save area for | | reg parm save area, | | |
927 | leaf funcs / flags | | only created for | | |
928 SP+0->+-----------------------+ | variable argument | | |
929 | functions | | |
930 FP+8n->+-----------------------+ | |
931 | | | |
932 | register save area | | |
933 | | | |
934 +-----------------------+ | |
935 | | | |
936 | local variables | | |
937 | | | |
938 FP+0->+-----------------------+ | |
939 | | | |
940 | alloca allocations | | |
941 | | | |
942 +-----------------------+ | |
943 | | | |
944 | arguments on stack | | |
945 | | | |
946 SP+8->+-----------------------+ | |
947 low | 2 word save area for | | |
948 memory | leaf funcs / flags | | |
949 SP+0->+-----------------------+ | |
950 | |
951 Notes: | |
952 1) The "reg parm save area" does not exist for non variable argument fns. | |
953 The "reg parm save area" could be eliminated if we created our | |
954 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well | |
955 (so it's not done). */ | |
956 | |
957 /* Structure to be filled in by epiphany_compute_frame_size with register | |
958 save masks, and offsets for the current function. */ | |
959 struct epiphany_frame_info | |
960 { | |
961 unsigned int total_size; /* # bytes that the entire frame takes up. */ | |
962 unsigned int pretend_size; /* # bytes we push and pretend caller did. */ | |
963 unsigned int args_size; /* # bytes that outgoing arguments take up. */ | |
964 unsigned int reg_size; /* # bytes needed to store regs. */ | |
965 unsigned int var_size; /* # bytes that variables take up. */ | |
966 HARD_REG_SET gmask; /* Set of saved gp registers. */ | |
967 int initialized; /* Nonzero if frame size already calculated. */ | |
968 int stld_sz; /* Current load/store data size for offset | |
969 adjustment. */ | |
970 int need_fp; /* value to override "frame_pointer_needed */ | |
971 /* FIRST_SLOT is the slot that is saved first, at the very start of | |
972 the frame, with a POST_MODIFY to allocate the frame, if the size fits, | |
973 or at least the parm and register save areas, otherwise. | |
974 In the case of a large frame, LAST_SLOT is the slot that is saved last, | |
975 with a POST_MODIFY to allocate the rest of the frame. */ | |
976 int first_slot, last_slot, first_slot_offset, last_slot_offset; | |
977 int first_slot_size; | |
978 int small_threshold; | |
979 }; | |
980 | |
981 /* Current frame information calculated by epiphany_compute_frame_size. */ | |
982 static struct epiphany_frame_info current_frame_info; | |
983 | |
984 /* Zero structure to initialize current_frame_info. */ | |
985 static struct epiphany_frame_info zero_frame_info; | |
986 | |
987 /* The usual; we set up our machine_function data. */ | |
988 static struct machine_function * | |
989 epiphany_init_machine_status (void) | |
990 { | |
991 struct machine_function *machine; | |
992 | |
993 /* Reset state info for each function. */ | |
994 current_frame_info = zero_frame_info; | |
995 | |
996 machine = ggc_cleared_alloc<machine_function_t> (); | |
997 | |
998 return machine; | |
999 } | |
1000 | |
1001 /* Implements INIT_EXPANDERS. We just set up to call the above | |
1002 * function. */ | |
1003 void | |
1004 epiphany_init_expanders (void) | |
1005 { | |
1006 init_machine_status = epiphany_init_machine_status; | |
1007 } | |
1008 | |
1009 /* Type of function DECL. | |
1010 | |
1011 The result is cached. To reset the cache at the end of a function, | |
1012 call with DECL = NULL_TREE. */ | |
1013 | |
1014 static enum epiphany_function_type | |
1015 epiphany_compute_function_type (tree decl) | |
1016 { | |
1017 tree a; | |
1018 /* Cached value. */ | |
1019 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN; | |
1020 /* Last function we were called for. */ | |
1021 static tree last_fn = NULL_TREE; | |
1022 | |
1023 /* Resetting the cached value? */ | |
1024 if (decl == NULL_TREE) | |
1025 { | |
1026 fn_type = EPIPHANY_FUNCTION_UNKNOWN; | |
1027 last_fn = NULL_TREE; | |
1028 return fn_type; | |
1029 } | |
1030 | |
1031 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN) | |
1032 return fn_type; | |
1033 | |
1034 /* Assume we have a normal function (not an interrupt handler). */ | |
1035 fn_type = EPIPHANY_FUNCTION_NORMAL; | |
1036 | |
1037 /* Now see if this is an interrupt handler. */ | |
1038 for (a = DECL_ATTRIBUTES (decl); | |
1039 a; | |
1040 a = TREE_CHAIN (a)) | |
1041 { | |
1042 tree name = TREE_PURPOSE (a); | |
1043 | |
1044 if (name == get_identifier ("interrupt")) | |
1045 fn_type = EPIPHANY_FUNCTION_INTERRUPT; | |
1046 } | |
1047 | |
1048 last_fn = decl; | |
1049 return fn_type; | |
1050 } | |
1051 | |
1052 #define RETURN_ADDR_REGNUM GPR_LR | |
1053 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM)) | |
1054 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM)) | |
1055 | |
1056 /* Tell prologue and epilogue if register REGNO should be saved / restored. | |
1057 The return address and frame pointer are treated separately. | |
1058 Don't consider them here. */ | |
1059 #define MUST_SAVE_REGISTER(regno, interrupt_p) \ | |
1060 ((df_regs_ever_live_p (regno) \ | |
1061 || (interrupt_p && !crtl->is_leaf \ | |
1062 && call_used_regs[regno] && !fixed_regs[regno])) \ | |
1063 && (!call_used_regs[regno] || regno == GPR_LR \ | |
1064 || (interrupt_p && regno != GPR_SP))) | |
1065 | |
1066 #define MUST_SAVE_RETURN_ADDR 0 | |
1067 | |
1068 /* Return the bytes needed to compute the frame pointer from the current | |
1069 stack pointer. | |
1070 | |
1071 SIZE is the size needed for local variables. */ | |
1072 | |
1073 static unsigned int | |
1074 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */) | |
1075 { | |
1076 int regno; | |
1077 unsigned int total_size, var_size, args_size, pretend_size, reg_size; | |
1078 HARD_REG_SET gmask; | |
1079 enum epiphany_function_type fn_type; | |
1080 int interrupt_p; | |
1081 int first_slot, last_slot, first_slot_offset, last_slot_offset; | |
1082 int first_slot_size; | |
1083 int small_slots = 0; | |
1084 | |
1085 var_size = size; | |
1086 args_size = crtl->outgoing_args_size; | |
1087 pretend_size = crtl->args.pretend_args_size; | |
1088 total_size = args_size + var_size; | |
1089 reg_size = 0; | |
1090 CLEAR_HARD_REG_SET (gmask); | |
1091 first_slot = -1; | |
1092 first_slot_offset = 0; | |
1093 last_slot = -1; | |
1094 last_slot_offset = 0; | |
1095 first_slot_size = UNITS_PER_WORD; | |
1096 | |
1097 /* See if this is an interrupt handler. Call used registers must be saved | |
1098 for them too. */ | |
1099 fn_type = epiphany_compute_function_type (current_function_decl); | |
1100 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type); | |
1101 | |
1102 /* Calculate space needed for registers. */ | |
1103 | |
1104 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--) | |
1105 { | |
1106 reg_size += UNITS_PER_WORD; | |
1107 SET_HARD_REG_BIT (gmask, regno); | |
1108 if (epiphany_stack_offset - reg_size == 0) | |
1109 first_slot = regno; | |
1110 } | |
1111 | |
1112 if (interrupt_p) | |
1113 reg_size += 2 * UNITS_PER_WORD; | |
1114 else | |
1115 small_slots = epiphany_stack_offset / UNITS_PER_WORD; | |
1116 | |
1117 if (frame_pointer_needed) | |
1118 { | |
1119 current_frame_info.need_fp = 1; | |
1120 if (!interrupt_p && first_slot < 0) | |
1121 first_slot = GPR_FP; | |
1122 } | |
1123 else | |
1124 current_frame_info.need_fp = 0; | |
1125 for (regno = 0; regno <= GPR_LAST; regno++) | |
1126 { | |
1127 if (MUST_SAVE_REGISTER (regno, interrupt_p)) | |
1128 { | |
1129 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno)); | |
1130 reg_size += UNITS_PER_WORD; | |
1131 SET_HARD_REG_BIT (gmask, regno); | |
1132 /* FIXME: when optimizing for speed, take schedling into account | |
1133 when selecting these registers. */ | |
1134 if (regno == first_slot) | |
1135 gcc_assert (regno == GPR_FP && frame_pointer_needed); | |
1136 else if (!interrupt_p && first_slot < 0) | |
1137 first_slot = regno; | |
1138 else if (last_slot < 0 | |
1139 && (first_slot ^ regno) != 1 | |
1140 && (!interrupt_p || regno > GPR_1)) | |
1141 last_slot = regno; | |
1142 } | |
1143 } | |
1144 if (TEST_HARD_REG_BIT (gmask, GPR_LR)) | |
1145 MACHINE_FUNCTION (cfun)->lr_clobbered = 1; | |
1146 /* ??? Could sometimes do better than that. */ | |
1147 current_frame_info.small_threshold | |
1148 = (optimize >= 3 || interrupt_p ? 0 | |
1149 : pretend_size ? small_slots | |
1150 : 4 + small_slots - (first_slot == GPR_FP)); | |
1151 | |
1152 /* If there might be variables with 64-bit alignment requirement, align the | |
1153 start of the variables. */ | |
1154 if (var_size >= 2 * UNITS_PER_WORD | |
1155 /* We don't want to split a double reg save/restore across two unpaired | |
1156 stack slots when optimizing. This rounding could be avoided with | |
1157 more complex reordering of the register saves, but that would seem | |
1158 to be a lot of code complexity for little gain. */ | |
1159 || (reg_size > 8 && optimize)) | |
1160 reg_size = EPIPHANY_STACK_ALIGN (reg_size); | |
1161 if (((total_size + reg_size | |
1162 /* Reserve space for UNKNOWN_REGNUM. */ | |
1163 + EPIPHANY_STACK_ALIGN (4)) | |
1164 <= (unsigned) epiphany_stack_offset) | |
1165 && !interrupt_p | |
1166 && crtl->is_leaf && !frame_pointer_needed) | |
1167 { | |
1168 first_slot = -1; | |
1169 last_slot = -1; | |
1170 goto alloc_done; | |
1171 } | |
1172 else if (reg_size | |
1173 && !interrupt_p | |
1174 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset) | |
1175 reg_size = epiphany_stack_offset; | |
1176 if (interrupt_p) | |
1177 { | |
1178 if (total_size + reg_size < 0x3fc) | |
1179 { | |
1180 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size); | |
1181 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset); | |
1182 last_slot = -1; | |
1183 } | |
1184 else | |
1185 { | |
1186 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size); | |
1187 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size); | |
1188 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset); | |
1189 if (last_slot >= 0) | |
1190 CLEAR_HARD_REG_BIT (gmask, last_slot); | |
1191 } | |
1192 } | |
1193 else if (total_size + reg_size < 0x1ffc && first_slot >= 0) | |
1194 { | |
1195 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size); | |
1196 last_slot = -1; | |
1197 } | |
1198 else | |
1199 { | |
1200 if (total_size + reg_size <= (unsigned) epiphany_stack_offset) | |
1201 { | |
1202 gcc_assert (first_slot < 0); | |
1203 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset); | |
1204 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size); | |
1205 } | |
1206 else | |
1207 { | |
1208 first_slot_offset | |
1209 = (reg_size | |
1210 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0); | |
1211 if (!first_slot_offset) | |
1212 { | |
1213 if (first_slot != GPR_FP || !current_frame_info.need_fp) | |
1214 last_slot = first_slot; | |
1215 first_slot = -1; | |
1216 } | |
1217 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size); | |
1218 if (reg_size) | |
1219 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset); | |
1220 } | |
1221 if (last_slot >= 0) | |
1222 CLEAR_HARD_REG_BIT (gmask, last_slot); | |
1223 } | |
1224 alloc_done: | |
1225 if (first_slot >= 0) | |
1226 { | |
1227 CLEAR_HARD_REG_BIT (gmask, first_slot); | |
1228 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1) | |
1229 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD) | |
1230 { | |
1231 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1); | |
1232 first_slot_size = 2 * UNITS_PER_WORD; | |
1233 first_slot &= ~1; | |
1234 } | |
1235 } | |
1236 total_size = first_slot_offset + last_slot_offset; | |
1237 | |
1238 /* Save computed information. */ | |
1239 current_frame_info.total_size = total_size; | |
1240 current_frame_info.pretend_size = pretend_size; | |
1241 current_frame_info.var_size = var_size; | |
1242 current_frame_info.args_size = args_size; | |
1243 current_frame_info.reg_size = reg_size; | |
1244 COPY_HARD_REG_SET (current_frame_info.gmask, gmask); | |
1245 current_frame_info.first_slot = first_slot; | |
1246 current_frame_info.last_slot = last_slot; | |
1247 current_frame_info.first_slot_offset = first_slot_offset; | |
1248 current_frame_info.first_slot_size = first_slot_size; | |
1249 current_frame_info.last_slot_offset = last_slot_offset; | |
1250 | |
1251 current_frame_info.initialized = reload_completed; | |
1252 | |
1253 /* Ok, we're done. */ | |
1254 return total_size; | |
1255 } | |
1256 | |
1257 /* Print operand X (an rtx) in assembler syntax to file FILE. | |
1258 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified. | |
1259 For `%' followed by punctuation, CODE is the punctuation and X is null. */ | |
1260 | |
1261 static void | |
1262 epiphany_print_operand (FILE *file, rtx x, int code) | |
1263 { | |
1264 switch (code) | |
1265 { | |
1266 case 'd': | |
1267 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file); | |
1268 return; | |
1269 case 'D': | |
1270 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE | |
1271 (get_epiphany_condition_code (x))], | |
1272 file); | |
1273 return; | |
1274 | |
1275 case 'X': | |
1276 current_frame_info.stld_sz = 8; | |
1277 break; | |
1278 | |
1279 case 'C' : | |
1280 current_frame_info.stld_sz = 4; | |
1281 break; | |
1282 | |
1283 case 'c' : | |
1284 current_frame_info.stld_sz = 2; | |
1285 break; | |
1286 | |
1287 case 'f': | |
1288 fputs (REG_P (x) ? "jalr " : "bl ", file); | |
1289 break; | |
1290 | |
1291 case '-': | |
1292 fprintf (file, "r%d", epiphany_m1reg); | |
1293 return; | |
1294 | |
1295 case 0 : | |
1296 /* Do nothing special. */ | |
1297 break; | |
1298 default : | |
1299 /* Unknown flag. */ | |
1300 output_operand_lossage ("invalid operand output code"); | |
1301 } | |
1302 | |
1303 switch (GET_CODE (x)) | |
1304 { | |
1305 rtx addr; | |
1306 rtx offset; | |
1307 | |
1308 case REG : | |
1309 fputs (reg_names[REGNO (x)], file); | |
1310 break; | |
1311 case MEM : | |
1312 if (code == 0) | |
1313 current_frame_info.stld_sz = 1; | |
1314 fputc ('[', file); | |
1315 addr = XEXP (x, 0); | |
1316 switch (GET_CODE (addr)) | |
1317 { | |
1318 case POST_INC: | |
1319 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x))); | |
1320 addr = XEXP (addr, 0); | |
1321 break; | |
1322 case POST_DEC: | |
1323 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x))); | |
1324 addr = XEXP (addr, 0); | |
1325 break; | |
1326 case POST_MODIFY: | |
1327 offset = XEXP (XEXP (addr, 1), 1); | |
1328 addr = XEXP (addr, 0); | |
1329 break; | |
1330 default: | |
1331 offset = 0; | |
1332 break; | |
1333 } | |
1334 output_address (GET_MODE (x), addr); | |
1335 fputc (']', file); | |
1336 if (offset) | |
1337 { | |
1338 fputc (',', file); | |
1339 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x))) | |
1340 { | |
1341 default: | |
1342 gcc_unreachable (); | |
1343 case 8: | |
1344 offset = GEN_INT (INTVAL (offset) >> 3); | |
1345 break; | |
1346 case 4: | |
1347 offset = GEN_INT (INTVAL (offset) >> 2); | |
1348 break; | |
1349 case 2: | |
1350 offset = GEN_INT (INTVAL (offset) >> 1); | |
1351 break; | |
1352 case 1: | |
1353 break; | |
1354 } | |
1355 output_address (GET_MODE (x), offset); | |
1356 } | |
1357 break; | |
1358 case CONST_DOUBLE : | |
1359 /* We handle SFmode constants here as output_addr_const doesn't. */ | |
1360 if (GET_MODE (x) == SFmode) | |
1361 { | |
1362 long l; | |
1363 | |
1364 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l); | |
1365 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l); | |
1366 break; | |
1367 } | |
1368 /* FALLTHRU */ | |
1369 /* Let output_addr_const deal with it. */ | |
1370 case CONST_INT: | |
1371 fprintf(file,"%s",IMMEDIATE_PREFIX); | |
1372 if (code == 'C' || code == 'X') | |
1373 { | |
1374 fprintf (file, "%ld", | |
1375 (long) (INTVAL (x) / current_frame_info.stld_sz)); | |
1376 break; | |
1377 } | |
1378 /* Fall through */ | |
1379 default : | |
1380 output_addr_const (file, x); | |
1381 break; | |
1382 } | |
1383 } | |
1384 | |
1385 /* Print a memory address as an operand to reference that memory location. */ | |
1386 | |
1387 static void | |
1388 epiphany_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr) | |
1389 { | |
1390 register rtx base, index = 0; | |
1391 int offset = 0; | |
1392 | |
1393 switch (GET_CODE (addr)) | |
1394 { | |
1395 case REG : | |
1396 fputs (reg_names[REGNO (addr)], file); | |
1397 break; | |
1398 case SYMBOL_REF : | |
1399 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr)) | |
1400 { | |
1401 output_addr_const (file, addr); | |
1402 } | |
1403 else | |
1404 { | |
1405 output_addr_const (file, addr); | |
1406 } | |
1407 break; | |
1408 case PLUS : | |
1409 if (GET_CODE (XEXP (addr, 0)) == CONST_INT) | |
1410 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1); | |
1411 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) | |
1412 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0); | |
1413 else | |
1414 base = XEXP (addr, 0), index = XEXP (addr, 1); | |
1415 gcc_assert (GET_CODE (base) == REG); | |
1416 fputs (reg_names[REGNO (base)], file); | |
1417 if (index == 0) | |
1418 { | |
1419 /* | |
1420 ** ++rk quirky method to scale offset for ld/str....... | |
1421 */ | |
1422 fprintf (file, ",%s%d", IMMEDIATE_PREFIX, | |
1423 offset/current_frame_info.stld_sz); | |
1424 } | |
1425 else | |
1426 { | |
1427 switch (GET_CODE (index)) | |
1428 { | |
1429 case REG: | |
1430 fprintf (file, ",%s", reg_names[REGNO (index)]); | |
1431 break; | |
1432 case SYMBOL_REF: | |
1433 fputc (',', file), output_addr_const (file, index); | |
1434 break; | |
1435 default: | |
1436 gcc_unreachable (); | |
1437 } | |
1438 } | |
1439 break; | |
1440 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY: | |
1441 /* We shouldn't get here as we've lost the mode of the memory object | |
1442 (which says how much to inc/dec by. | |
1443 FIXME: We have the mode now, address printing can be moved into this | |
1444 function. */ | |
1445 gcc_unreachable (); | |
1446 break; | |
1447 default: | |
1448 output_addr_const (file, addr); | |
1449 break; | |
1450 } | |
1451 } | |
1452 | |
1453 void | |
1454 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED, | |
1455 rtx *opvec ATTRIBUTE_UNUSED, | |
1456 int noperands ATTRIBUTE_UNUSED) | |
1457 { | |
1458 int i = epiphany_n_nops; | |
1459 rtx pat ATTRIBUTE_UNUSED; | |
1460 | |
1461 while (i--) | |
1462 fputs ("\tnop\n", asm_out_file); | |
1463 } | |
1464 | |
1465 | |
1466 /* Worker function for TARGET_RETURN_IN_MEMORY. */ | |
1467 | |
1468 static bool | |
1469 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) | |
1470 { | |
1471 HOST_WIDE_INT size = int_size_in_bytes (type); | |
1472 | |
1473 if (AGGREGATE_TYPE_P (type) | |
1474 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type))) | |
1475 return true; | |
1476 return (size == -1 || size > 8); | |
1477 } | |
1478 | |
1479 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are | |
1480 passed by reference. */ | |
1481 | |
1482 static bool | |
1483 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED, | |
1484 machine_mode mode, const_tree type, | |
1485 bool named ATTRIBUTE_UNUSED) | |
1486 { | |
1487 if (type) | |
1488 { | |
1489 if (AGGREGATE_TYPE_P (type) | |
1490 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type))) | |
1491 return true; | |
1492 } | |
1493 return false; | |
1494 } | |
1495 | |
1496 | |
1497 static rtx | |
1498 epiphany_function_value (const_tree ret_type, | |
1499 const_tree fn_decl_or_type ATTRIBUTE_UNUSED, | |
1500 bool outgoing ATTRIBUTE_UNUSED) | |
1501 { | |
1502 machine_mode mode; | |
1503 | |
1504 mode = TYPE_MODE (ret_type); | |
1505 /* We must change the mode like PROMOTE_MODE does. | |
1506 ??? PROMOTE_MODE is ignored for non-scalar types. | |
1507 The set of types tested here has to be kept in sync | |
1508 with the one in explow.c:promote_mode. */ | |
1509 if (GET_MODE_CLASS (mode) == MODE_INT | |
1510 && GET_MODE_SIZE (mode) < 4 | |
1511 && (TREE_CODE (ret_type) == INTEGER_TYPE | |
1512 || TREE_CODE (ret_type) == ENUMERAL_TYPE | |
1513 || TREE_CODE (ret_type) == BOOLEAN_TYPE | |
1514 || TREE_CODE (ret_type) == OFFSET_TYPE)) | |
1515 mode = SImode; | |
1516 return gen_rtx_REG (mode, 0); | |
1517 } | |
1518 | |
1519 static rtx | |
1520 epiphany_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) | |
1521 { | |
1522 return gen_rtx_REG (mode, 0); | |
1523 } | |
1524 | |
1525 static bool | |
1526 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED) | |
1527 { | |
1528 return regno == 0; | |
1529 } | |
1530 | |
1531 /* Fix up invalid option settings. */ | |
1532 static void | |
1533 epiphany_override_options (void) | |
1534 { | |
1535 if (epiphany_stack_offset < 4) | |
1536 error ("stack_offset must be at least 4"); | |
1537 if (epiphany_stack_offset & 3) | |
1538 error ("stack_offset must be a multiple of 4"); | |
1539 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4; | |
1540 if (!TARGET_SOFT_CMPSF) | |
1541 flag_finite_math_only = 1; | |
1542 | |
1543 /* This needs to be done at start up. It's convenient to do it here. */ | |
1544 epiphany_init (); | |
1545 } | |
1546 | |
1547 /* For a DImode load / store SET, make a SImode set for a | |
1548 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart | |
1549 subreg. */ | |
1550 static rtx | |
1551 frame_subreg_note (rtx set, int offset) | |
1552 { | |
1553 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset); | |
1554 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset); | |
1555 | |
1556 set = gen_rtx_SET (dst ,src); | |
1557 RTX_FRAME_RELATED_P (set) = 1; | |
1558 return set; | |
1559 } | |
1560 | |
1561 static rtx_insn * | |
1562 frame_insn (rtx x) | |
1563 { | |
1564 int i; | |
1565 rtx note = NULL_RTX; | |
1566 rtx_insn *insn; | |
1567 | |
1568 if (GET_CODE (x) == PARALLEL) | |
1569 { | |
1570 rtx part = XVECEXP (x, 0, 0); | |
1571 | |
1572 if (GET_MODE (SET_DEST (part)) == DImode) | |
1573 { | |
1574 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1)); | |
1575 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0); | |
1576 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD); | |
1577 for (i = XVECLEN (x, 0) - 1; i >= 1; i--) | |
1578 { | |
1579 part = copy_rtx (XVECEXP (x, 0, i)); | |
1580 | |
1581 if (GET_CODE (part) == SET) | |
1582 RTX_FRAME_RELATED_P (part) = 1; | |
1583 XVECEXP (note, 0, i + 1) = part; | |
1584 } | |
1585 } | |
1586 else | |
1587 { | |
1588 for (i = XVECLEN (x, 0) - 1; i >= 0; i--) | |
1589 { | |
1590 part = XVECEXP (x, 0, i); | |
1591 | |
1592 if (GET_CODE (part) == SET) | |
1593 RTX_FRAME_RELATED_P (part) = 1; | |
1594 } | |
1595 } | |
1596 } | |
1597 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode) | |
1598 note = gen_rtx_PARALLEL (VOIDmode, | |
1599 gen_rtvec (2, frame_subreg_note (x, 0), | |
1600 frame_subreg_note (x, UNITS_PER_WORD))); | |
1601 insn = emit_insn (x); | |
1602 RTX_FRAME_RELATED_P (insn) = 1; | |
1603 if (note) | |
1604 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); | |
1605 return insn; | |
1606 } | |
1607 | |
1608 static rtx_insn * | |
1609 frame_move_insn (rtx to, rtx from) | |
1610 { | |
1611 return frame_insn (gen_rtx_SET (to, from)); | |
1612 } | |
1613 | |
1614 /* Generate a MEM referring to a varargs argument slot. */ | |
1615 | |
1616 static rtx | |
1617 gen_varargs_mem (machine_mode mode, rtx addr) | |
1618 { | |
1619 rtx mem = gen_rtx_MEM (mode, addr); | |
1620 MEM_NOTRAP_P (mem) = 1; | |
1621 set_mem_alias_set (mem, get_varargs_alias_set ()); | |
1622 return mem; | |
1623 } | |
1624 | |
1625 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) . | |
1626 If EPILOGUE_P is 0, save; if it is one, restore. | |
1627 ADDR is the stack slot to save the first register to; subsequent | |
1628 registers are written to lower addresses. | |
1629 However, the order of register pairs can be reversed in order to | |
1630 use double-word load-store instructions. Likewise, an unpaired single | |
1631 word save slot can be skipped while double saves are carried out, and | |
1632 reused when a single register is to be saved. */ | |
1633 | |
1634 static void | |
1635 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p) | |
1636 { | |
1637 int i; | |
1638 int stack_offset | |
1639 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0; | |
1640 rtx skipped_mem = NULL_RTX; | |
1641 int last_saved = limit - 1; | |
1642 | |
1643 if (!optimize) | |
1644 while (last_saved >= 0 | |
1645 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved)) | |
1646 last_saved--; | |
1647 for (i = 0; i < limit; i++) | |
1648 { | |
1649 machine_mode mode = word_mode; | |
1650 rtx mem, reg; | |
1651 int n = i; | |
1652 rtx (*gen_mem) (machine_mode, rtx) = gen_frame_mem; | |
1653 | |
1654 /* Make sure we push the arguments in the right order. */ | |
1655 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size) | |
1656 { | |
1657 n = MAX_EPIPHANY_PARM_REGS - 1 - n; | |
1658 gen_mem = gen_varargs_mem; | |
1659 } | |
1660 if (stack_offset == current_frame_info.first_slot_size | |
1661 && current_frame_info.first_slot >= 0) | |
1662 { | |
1663 if (current_frame_info.first_slot_size > UNITS_PER_WORD) | |
1664 { | |
1665 mode = DImode; | |
1666 addr = plus_constant (Pmode, addr, | |
1667 - (HOST_WIDE_INT) UNITS_PER_WORD); | |
1668 } | |
1669 if (i-- < min || !epilogue_p) | |
1670 goto next_slot; | |
1671 n = current_frame_info.first_slot; | |
1672 gen_mem = gen_frame_mem; | |
1673 } | |
1674 else if (n == UNKNOWN_REGNUM | |
1675 && stack_offset > current_frame_info.first_slot_size) | |
1676 { | |
1677 i--; | |
1678 goto next_slot; | |
1679 } | |
1680 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n)) | |
1681 continue; | |
1682 else if (i < min) | |
1683 goto next_slot; | |
1684 | |
1685 /* Check for a register pair to save. */ | |
1686 if (n == i | |
1687 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0) | |
1688 && (n & 1) == 0 && n+1 < limit | |
1689 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1)) | |
1690 { | |
1691 /* If it fits in the current stack slot pair, place it there. */ | |
1692 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0 | |
1693 && stack_offset != 2 * UNITS_PER_WORD | |
1694 && (current_frame_info.last_slot < 0 | |
1695 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD) | |
1696 && (n+1 != last_saved || !skipped_mem)) | |
1697 { | |
1698 mode = DImode; | |
1699 i++; | |
1700 addr = plus_constant (Pmode, addr, | |
1701 - (HOST_WIDE_INT) UNITS_PER_WORD); | |
1702 } | |
1703 /* If it fits in the following stack slot pair, that's fine, too. */ | |
1704 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4 | |
1705 && stack_offset != 2 * UNITS_PER_WORD | |
1706 && stack_offset != 3 * UNITS_PER_WORD | |
1707 && (current_frame_info.last_slot < 0 | |
1708 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD) | |
1709 && n + 1 != last_saved) | |
1710 { | |
1711 gcc_assert (!skipped_mem); | |
1712 stack_offset -= GET_MODE_SIZE (mode); | |
1713 skipped_mem = gen_mem (mode, addr); | |
1714 mode = DImode; | |
1715 i++; | |
1716 addr = plus_constant (Pmode, addr, | |
1717 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); | |
1718 } | |
1719 } | |
1720 reg = gen_rtx_REG (mode, n); | |
1721 if (mode != DImode && skipped_mem) | |
1722 mem = skipped_mem; | |
1723 else | |
1724 mem = gen_mem (mode, addr); | |
1725 | |
1726 /* If we are loading / storing LR, note the offset that | |
1727 gen_reload_insi_ra requires. Since GPR_LR is even, | |
1728 we only need to test n, even if mode is DImode. */ | |
1729 gcc_assert ((GPR_LR & 1) == 0); | |
1730 if (n == GPR_LR) | |
1731 { | |
1732 long lr_slot_offset = 0; | |
1733 rtx m_addr = XEXP (mem, 0); | |
1734 | |
1735 if (GET_CODE (m_addr) == PLUS) | |
1736 lr_slot_offset = INTVAL (XEXP (m_addr, 1)); | |
1737 if (frame_pointer_needed) | |
1738 lr_slot_offset += (current_frame_info.first_slot_offset | |
1739 - current_frame_info.total_size); | |
1740 if (MACHINE_FUNCTION (cfun)->lr_slot_known) | |
1741 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset | |
1742 == lr_slot_offset); | |
1743 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset; | |
1744 MACHINE_FUNCTION (cfun)->lr_slot_known = 1; | |
1745 } | |
1746 | |
1747 if (!epilogue_p) | |
1748 frame_move_insn (mem, reg); | |
1749 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size) | |
1750 emit_move_insn (reg, mem); | |
1751 if (mem == skipped_mem) | |
1752 { | |
1753 skipped_mem = NULL_RTX; | |
1754 continue; | |
1755 } | |
1756 next_slot: | |
1757 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD); | |
1758 stack_offset -= GET_MODE_SIZE (mode); | |
1759 } | |
1760 } | |
1761 | |
1762 void | |
1763 epiphany_expand_prologue (void) | |
1764 { | |
1765 int interrupt_p; | |
1766 enum epiphany_function_type fn_type; | |
1767 rtx addr, mem, off, reg; | |
1768 | |
1769 if (!current_frame_info.initialized) | |
1770 epiphany_compute_frame_size (get_frame_size ()); | |
1771 | |
1772 /* It is debatable if we should adjust this by epiphany_stack_offset. */ | |
1773 if (flag_stack_usage_info) | |
1774 current_function_static_stack_size = current_frame_info.total_size; | |
1775 | |
1776 fn_type = epiphany_compute_function_type (current_function_decl); | |
1777 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type); | |
1778 | |
1779 if (interrupt_p) | |
1780 { | |
1781 addr = plus_constant (Pmode, stack_pointer_rtx, | |
1782 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); | |
1783 if (!lookup_attribute ("forwarder_section", | |
1784 DECL_ATTRIBUTES (current_function_decl)) | |
1785 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl), | |
1786 0))) | |
1787 frame_move_insn (gen_frame_mem (DImode, addr), | |
1788 gen_rtx_REG (DImode, GPR_0)); | |
1789 frame_move_insn (gen_rtx_REG (SImode, GPR_0), | |
1790 gen_rtx_REG (word_mode, STATUS_REGNUM)); | |
1791 frame_move_insn (gen_rtx_REG (SImode, GPR_1), | |
1792 gen_rtx_REG (word_mode, IRET_REGNUM)); | |
1793 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); | |
1794 off = GEN_INT (-current_frame_info.first_slot_offset); | |
1795 frame_insn (gen_stack_adjust_add (off, mem)); | |
1796 if (!epiphany_uninterruptible_p (current_function_decl)) | |
1797 emit_insn (gen_gie ()); | |
1798 addr = plus_constant (Pmode, stack_pointer_rtx, | |
1799 current_frame_info.first_slot_offset | |
1800 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD); | |
1801 } | |
1802 else | |
1803 { | |
1804 addr = plus_constant (Pmode, stack_pointer_rtx, | |
1805 epiphany_stack_offset | |
1806 - (HOST_WIDE_INT) UNITS_PER_WORD); | |
1807 epiphany_emit_save_restore (0, current_frame_info.small_threshold, | |
1808 addr, 0); | |
1809 /* Allocate register save area; for small to medium size frames, | |
1810 allocate the entire frame; this is joint with one register save. */ | |
1811 if (current_frame_info.first_slot >= 0) | |
1812 { | |
1813 machine_mode mode | |
1814 = (current_frame_info.first_slot_size == UNITS_PER_WORD | |
1815 ? word_mode : DImode); | |
1816 | |
1817 off = GEN_INT (-current_frame_info.first_slot_offset); | |
1818 mem = gen_frame_mem (BLKmode, | |
1819 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); | |
1820 frame_insn (gen_stack_adjust_str | |
1821 (gen_frame_mem (mode, stack_pointer_rtx), | |
1822 gen_rtx_REG (mode, current_frame_info.first_slot), | |
1823 off, mem)); | |
1824 addr = plus_constant (Pmode, addr, | |
1825 current_frame_info.first_slot_offset); | |
1826 } | |
1827 } | |
1828 epiphany_emit_save_restore (current_frame_info.small_threshold, | |
1829 FIRST_PSEUDO_REGISTER, addr, 0); | |
1830 if (current_frame_info.need_fp) | |
1831 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); | |
1832 /* For large frames, allocate bulk of frame. This is usually joint with one | |
1833 register save. */ | |
1834 if (current_frame_info.last_slot >= 0) | |
1835 { | |
1836 rtx ip, mem2, note; | |
1837 rtx_insn *insn; | |
1838 | |
1839 gcc_assert (current_frame_info.last_slot != GPR_FP | |
1840 || (!current_frame_info.need_fp | |
1841 && current_frame_info.first_slot < 0)); | |
1842 off = GEN_INT (-current_frame_info.last_slot_offset); | |
1843 mem = gen_frame_mem (BLKmode, | |
1844 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); | |
1845 ip = gen_rtx_REG (Pmode, GPR_IP); | |
1846 frame_move_insn (ip, off); | |
1847 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot), | |
1848 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx), | |
1849 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem)); | |
1850 /* Instruction scheduling can separate the instruction setting IP from | |
1851 INSN so that dwarf2out_frame_debug_expr becomes confused what the | |
1852 temporary register is. Example: _gcov.o */ | |
1853 note = gen_rtx_SET (stack_pointer_rtx, | |
1854 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off)); | |
1855 note = gen_rtx_PARALLEL (VOIDmode, | |
1856 gen_rtvec (2, gen_rtx_SET (mem2, reg), note)); | |
1857 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note); | |
1858 } | |
1859 /* If there is only one or no register to save, yet we have a large frame, | |
1860 use an add. */ | |
1861 else if (current_frame_info.last_slot_offset) | |
1862 { | |
1863 mem = gen_frame_mem (BLKmode, | |
1864 plus_constant (Pmode, stack_pointer_rtx, | |
1865 current_frame_info.last_slot_offset)); | |
1866 off = GEN_INT (-current_frame_info.last_slot_offset); | |
1867 if (!SIMM11 (INTVAL (off))) | |
1868 { | |
1869 reg = gen_rtx_REG (Pmode, GPR_IP); | |
1870 frame_move_insn (reg, off); | |
1871 off = reg; | |
1872 } | |
1873 frame_insn (gen_stack_adjust_add (off, mem)); | |
1874 } | |
1875 } | |
1876 | |
1877 void | |
1878 epiphany_expand_epilogue (int sibcall_p) | |
1879 { | |
1880 int interrupt_p; | |
1881 enum epiphany_function_type fn_type; | |
1882 rtx mem, addr, reg, off; | |
1883 HOST_WIDE_INT restore_offset; | |
1884 | |
1885 fn_type = epiphany_compute_function_type( current_function_decl); | |
1886 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type); | |
1887 | |
1888 /* For variable frames, deallocate bulk of frame. */ | |
1889 if (current_frame_info.need_fp) | |
1890 { | |
1891 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); | |
1892 emit_insn (gen_stack_adjust_mov (mem)); | |
1893 } | |
1894 /* Else for large static frames, deallocate bulk of frame. */ | |
1895 else if (current_frame_info.last_slot_offset) | |
1896 { | |
1897 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); | |
1898 reg = gen_rtx_REG (Pmode, GPR_IP); | |
1899 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset)); | |
1900 emit_insn (gen_stack_adjust_add (reg, mem)); | |
1901 } | |
1902 restore_offset = (interrupt_p | |
1903 ? - 3 * UNITS_PER_WORD | |
1904 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD); | |
1905 addr = plus_constant (Pmode, stack_pointer_rtx, | |
1906 (current_frame_info.first_slot_offset | |
1907 + restore_offset)); | |
1908 epiphany_emit_save_restore (current_frame_info.small_threshold, | |
1909 FIRST_PSEUDO_REGISTER, addr, 1); | |
1910 | |
1911 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl)) | |
1912 emit_insn (gen_gid ()); | |
1913 | |
1914 off = GEN_INT (current_frame_info.first_slot_offset); | |
1915 mem = gen_frame_mem (BLKmode, stack_pointer_rtx); | |
1916 /* For large / variable size frames, deallocating the register save area is | |
1917 joint with one register restore; for medium size frames, we use a | |
1918 dummy post-increment load to dealloacte the whole frame. */ | |
1919 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0) | |
1920 { | |
1921 emit_insn (gen_stack_adjust_ldr | |
1922 (gen_rtx_REG (word_mode, | |
1923 (current_frame_info.last_slot >= 0 | |
1924 ? current_frame_info.last_slot : GPR_IP)), | |
1925 gen_frame_mem (word_mode, stack_pointer_rtx), | |
1926 off, | |
1927 mem)); | |
1928 } | |
1929 /* While for small frames, we deallocate the entire frame with one add. */ | |
1930 else if (INTVAL (off)) | |
1931 { | |
1932 emit_insn (gen_stack_adjust_add (off, mem)); | |
1933 } | |
1934 if (interrupt_p) | |
1935 { | |
1936 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM), | |
1937 gen_rtx_REG (SImode, GPR_0)); | |
1938 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM), | |
1939 gen_rtx_REG (SImode, GPR_1)); | |
1940 addr = plus_constant (Pmode, stack_pointer_rtx, | |
1941 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD); | |
1942 emit_move_insn (gen_rtx_REG (DImode, GPR_0), | |
1943 gen_frame_mem (DImode, addr)); | |
1944 } | |
1945 addr = plus_constant (Pmode, stack_pointer_rtx, | |
1946 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD); | |
1947 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1); | |
1948 if (!sibcall_p) | |
1949 { | |
1950 if (interrupt_p) | |
1951 emit_jump_insn (gen_return_internal_interrupt()); | |
1952 else | |
1953 emit_jump_insn (gen_return_i ()); | |
1954 } | |
1955 } | |
1956 | |
1957 int | |
1958 epiphany_initial_elimination_offset (int from, int to) | |
1959 { | |
1960 epiphany_compute_frame_size (get_frame_size ()); | |
1961 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM) | |
1962 return current_frame_info.total_size - current_frame_info.reg_size; | |
1963 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) | |
1964 return current_frame_info.first_slot_offset - current_frame_info.reg_size; | |
1965 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM) | |
1966 return (current_frame_info.total_size | |
1967 - ((current_frame_info.pretend_size + 4) & -8)); | |
1968 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) | |
1969 return (current_frame_info.first_slot_offset | |
1970 - ((current_frame_info.pretend_size + 4) & -8)); | |
1971 gcc_unreachable (); | |
1972 } | |
1973 | |
1974 bool | |
1975 epiphany_regno_rename_ok (unsigned, unsigned dst) | |
1976 { | |
1977 enum epiphany_function_type fn_type; | |
1978 | |
1979 fn_type = epiphany_compute_function_type (current_function_decl); | |
1980 if (!EPIPHANY_INTERRUPT_P (fn_type)) | |
1981 return true; | |
1982 if (df_regs_ever_live_p (dst)) | |
1983 return true; | |
1984 return false; | |
1985 } | |
1986 | |
1987 static int | |
1988 epiphany_issue_rate (void) | |
1989 { | |
1990 return 2; | |
1991 } | |
1992 | |
1993 /* Function to update the integer COST | |
1994 based on the relationship between INSN that is dependent on | |
1995 DEP_INSN through the dependence LINK. The default is to make no | |
1996 adjustment to COST. This can be used for example to specify to | |
1997 the scheduler that an output- or anti-dependence does not incur | |
1998 the same cost as a data-dependence. The return value should be | |
1999 the new value for COST. */ | |
2000 static int | |
2001 epiphany_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, | |
2002 int cost, unsigned int) | |
2003 { | |
2004 if (dep_type == 0) | |
2005 { | |
2006 rtx dep_set; | |
2007 | |
2008 if (recog_memoized (insn) < 0 | |
2009 || recog_memoized (dep_insn) < 0) | |
2010 return cost; | |
2011 | |
2012 dep_set = single_set (dep_insn); | |
2013 | |
2014 /* The latency that we specify in the scheduling description refers | |
2015 to the actual output, not to an auto-increment register; for that, | |
2016 the latency is one. */ | |
2017 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1) | |
2018 { | |
2019 rtx set = single_set (insn); | |
2020 | |
2021 if (set | |
2022 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set)) | |
2023 && (!MEM_P (SET_DEST (set)) | |
2024 || !reg_overlap_mentioned_p (SET_DEST (dep_set), | |
2025 XEXP (SET_DEST (set), 0)))) | |
2026 cost = 1; | |
2027 } | |
2028 } | |
2029 return cost; | |
2030 } | |
2031 | |
2032 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X) | |
2033 | |
2034 #define RTX_OK_FOR_BASE_P(X) \ | |
2035 (REG_P (X) && REG_OK_FOR_BASE_P (X)) | |
2036 | |
2037 #define RTX_OK_FOR_INDEX_P(MODE, X) \ | |
2038 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \ | |
2039 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \ | |
2040 && (REG_P (X) && REG_OK_FOR_INDEX_P (X))) | |
2041 | |
2042 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \ | |
2043 (GET_CODE (X) == PLUS \ | |
2044 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \ | |
2045 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \ | |
2046 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1)))) | |
2047 | |
2048 static bool | |
2049 epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict) | |
2050 { | |
2051 #define REG_OK_FOR_BASE_P(X) \ | |
2052 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X))) | |
2053 if (RTX_OK_FOR_BASE_P (x)) | |
2054 return true; | |
2055 if (RTX_FRAME_OFFSET_P (x)) | |
2056 return true; | |
2057 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x)) | |
2058 return true; | |
2059 /* If this is a misaligned stack access, don't force it to reg+index. */ | |
2060 if (GET_MODE_SIZE (mode) == 8 | |
2061 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx | |
2062 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */ | |
2063 && !(INTVAL (XEXP (x, 1)) & 3) | |
2064 && INTVAL (XEXP (x, 1)) >= -2047 * 4 | |
2065 && INTVAL (XEXP (x, 1)) <= 2046 * 4) | |
2066 return true; | |
2067 if (TARGET_POST_INC | |
2068 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC) | |
2069 && RTX_OK_FOR_BASE_P (XEXP ((x), 0))) | |
2070 return true; | |
2071 if ((TARGET_POST_MODIFY || reload_completed) | |
2072 && GET_CODE (x) == POST_MODIFY | |
2073 && GET_CODE (XEXP ((x), 1)) == PLUS | |
2074 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0)) | |
2075 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1))) | |
2076 return true; | |
2077 if (mode == BLKmode) | |
2078 return epiphany_legitimate_address_p (SImode, x, strict); | |
2079 return false; | |
2080 } | |
2081 | |
2082 static reg_class_t | |
2083 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass, | |
2084 machine_mode mode ATTRIBUTE_UNUSED, | |
2085 secondary_reload_info *sri) | |
2086 { | |
2087 /* This could give more reload inheritance, but we are missing some | |
2088 reload infrastructure. */ | |
2089 if (0) | |
2090 if (in_p && GET_CODE (x) == UNSPEC | |
2091 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x)) | |
2092 { | |
2093 gcc_assert (rclass == GENERAL_REGS); | |
2094 sri->icode = CODE_FOR_reload_insi_ra; | |
2095 return NO_REGS; | |
2096 } | |
2097 return NO_REGS; | |
2098 } | |
2099 | |
2100 bool | |
2101 epiphany_is_long_call_p (rtx x) | |
2102 { | |
2103 tree decl = SYMBOL_REF_DECL (x); | |
2104 bool ret_val = !TARGET_SHORT_CALLS; | |
2105 tree attrs; | |
2106 | |
2107 /* ??? Is it safe to default to ret_val if decl is NULL? We should | |
2108 probably encode information via encode_section_info, and also | |
2109 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL | |
2110 into account. */ | |
2111 if (decl) | |
2112 { | |
2113 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); | |
2114 if (lookup_attribute ("long_call", attrs)) | |
2115 ret_val = true; | |
2116 else if (lookup_attribute ("short_call", attrs)) | |
2117 ret_val = false; | |
2118 } | |
2119 return ret_val; | |
2120 } | |
2121 | |
2122 bool | |
2123 epiphany_small16 (rtx x) | |
2124 { | |
2125 rtx base = x; | |
2126 rtx offs ATTRIBUTE_UNUSED = const0_rtx; | |
2127 | |
2128 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) | |
2129 { | |
2130 base = XEXP (XEXP (x, 0), 0); | |
2131 offs = XEXP (XEXP (x, 0), 1); | |
2132 } | |
2133 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base) | |
2134 && epiphany_is_long_call_p (base)) | |
2135 return false; | |
2136 return TARGET_SMALL16 != 0; | |
2137 } | |
2138 | |
2139 /* Return nonzero if it is ok to make a tail-call to DECL. */ | |
2140 static bool | |
2141 epiphany_function_ok_for_sibcall (tree decl, tree exp) | |
2142 { | |
2143 bool cfun_interrupt_p, call_interrupt_p; | |
2144 | |
2145 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type | |
2146 (current_function_decl)); | |
2147 if (decl) | |
2148 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl)); | |
2149 else | |
2150 { | |
2151 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp)); | |
2152 | |
2153 gcc_assert (POINTER_TYPE_P (fn_type)); | |
2154 fn_type = TREE_TYPE (fn_type); | |
2155 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE | |
2156 || TREE_CODE (fn_type) == METHOD_TYPE); | |
2157 call_interrupt_p | |
2158 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL; | |
2159 } | |
2160 | |
2161 /* Don't tailcall from or to an ISR routine - although we could in | |
2162 principle tailcall from one ISR routine to another, we'd need to | |
2163 handle this in sibcall_epilogue to make it work. */ | |
2164 if (cfun_interrupt_p || call_interrupt_p) | |
2165 return false; | |
2166 | |
2167 /* Everything else is ok. */ | |
2168 return true; | |
2169 } | |
2170 | |
2171 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call | |
2172 expander. | |
2173 Return true iff the type of T has the uninterruptible attribute. | |
2174 If T is NULL, return false. */ | |
2175 bool | |
2176 epiphany_uninterruptible_p (tree t) | |
2177 { | |
2178 tree attrs; | |
2179 | |
2180 if (t) | |
2181 { | |
2182 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t)); | |
2183 if (lookup_attribute ("disinterrupt", attrs)) | |
2184 return true; | |
2185 } | |
2186 return false; | |
2187 } | |
2188 | |
2189 bool | |
2190 epiphany_call_uninterruptible_p (rtx mem) | |
2191 { | |
2192 rtx addr = XEXP (mem, 0); | |
2193 tree t = NULL_TREE; | |
2194 | |
2195 if (GET_CODE (addr) == SYMBOL_REF) | |
2196 t = SYMBOL_REF_DECL (addr); | |
2197 if (!t) | |
2198 t = MEM_EXPR (mem); | |
2199 return epiphany_uninterruptible_p (t); | |
2200 } | |
2201 | |
2202 static machine_mode | |
2203 epiphany_promote_function_mode (const_tree type, machine_mode mode, | |
2204 int *punsignedp ATTRIBUTE_UNUSED, | |
2205 const_tree funtype ATTRIBUTE_UNUSED, | |
2206 int for_return ATTRIBUTE_UNUSED) | |
2207 { | |
2208 int dummy; | |
2209 | |
2210 return promote_mode (type, mode, &dummy); | |
2211 } | |
2212 | |
2213 static void | |
2214 epiphany_conditional_register_usage (void) | |
2215 { | |
2216 int i; | |
2217 | |
2218 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) | |
2219 { | |
2220 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; | |
2221 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; | |
2222 } | |
2223 if (TARGET_HALF_REG_FILE) | |
2224 { | |
2225 for (i = 32; i <= 63; i++) | |
2226 { | |
2227 fixed_regs[i] = 1; | |
2228 call_used_regs[i] = 1; | |
2229 } | |
2230 } | |
2231 if (epiphany_m1reg >= 0) | |
2232 { | |
2233 fixed_regs[epiphany_m1reg] = 1; | |
2234 call_used_regs[epiphany_m1reg] = 1; | |
2235 } | |
2236 if (!TARGET_PREFER_SHORT_INSN_REGS) | |
2237 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]); | |
2238 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS], | |
2239 reg_class_contents[GENERAL_REGS]); | |
2240 /* It would be simpler and quicker if we could just use | |
2241 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized; | |
2242 it is set up later by our caller. */ | |
2243 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) | |
2244 if (!call_used_regs[i]) | |
2245 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i); | |
2246 } | |
2247 | |
2248 /* Determine where to put an argument to a function. | |
2249 Value is zero to push the argument on the stack, | |
2250 or a hard register in which to store the argument. | |
2251 | |
2252 MODE is the argument's machine mode. | |
2253 TYPE is the data type of the argument (as a tree). | |
2254 This is null for libcalls where that information may | |
2255 not be available. | |
2256 CUM is a variable of type CUMULATIVE_ARGS which gives info about | |
2257 the preceding args and about the function being called. | |
2258 NAMED is nonzero if this argument is a named parameter | |
2259 (otherwise it is an extra parameter matching an ellipsis). */ | |
2260 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in | |
2261 registers and the rest are pushed. */ | |
2262 static rtx | |
2263 epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode, | |
2264 const_tree type, bool named ATTRIBUTE_UNUSED) | |
2265 { | |
2266 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v); | |
2267 | |
2268 if (PASS_IN_REG_P (cum, mode, type)) | |
2269 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type)); | |
2270 return 0; | |
2271 } | |
2272 | |
2273 /* Update the data in CUM to advance over an argument | |
2274 of mode MODE and data type TYPE. | |
2275 (TYPE is null for libcalls where that information may not be available.) */ | |
2276 static void | |
2277 epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, | |
2278 const_tree type, bool named ATTRIBUTE_UNUSED) | |
2279 { | |
2280 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); | |
2281 | |
2282 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type); | |
2283 } | |
2284 | |
2285 /* Nested function support. | |
2286 An epiphany trampoline looks like this: | |
2287 mov r16,%low(fnaddr) | |
2288 movt r16,%high(fnaddr) | |
2289 mov ip,%low(cxt) | |
2290 movt ip,%high(cxt) | |
2291 jr r16 */ | |
2292 | |
2293 #define EPIPHANY_LOW_RTX(X) \ | |
2294 (gen_rtx_IOR (SImode, \ | |
2295 gen_rtx_ASHIFT (SImode, \ | |
2296 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \ | |
2297 gen_rtx_ASHIFT (SImode, \ | |
2298 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12)))) | |
2299 #define EPIPHANY_HIGH_RTX(X) \ | |
2300 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16))) | |
2301 | |
2302 /* Emit RTL insns to initialize the variable parts of a trampoline. | |
2303 FNADDR is an RTX for the address of the function's pure code. | |
2304 CXT is an RTX for the static chain value for the function. */ | |
2305 static void | |
2306 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt) | |
2307 { | |
2308 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); | |
2309 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0)); | |
2310 | |
2311 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)), | |
2312 gen_rtx_IOR (SImode, GEN_INT (0x4002000b), | |
2313 EPIPHANY_LOW_RTX (fnaddr))); | |
2314 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)), | |
2315 gen_rtx_IOR (SImode, GEN_INT (0x5002000b), | |
2316 EPIPHANY_HIGH_RTX (fnaddr))); | |
2317 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)), | |
2318 gen_rtx_IOR (SImode, GEN_INT (0x2002800b), | |
2319 EPIPHANY_LOW_RTX (cxt))); | |
2320 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)), | |
2321 gen_rtx_IOR (SImode, GEN_INT (0x3002800b), | |
2322 EPIPHANY_HIGH_RTX (cxt))); | |
2323 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)), | |
2324 GEN_INT (0x0802014f)); | |
2325 } | |
2326 | |
2327 bool | |
2328 epiphany_optimize_mode_switching (int entity) | |
2329 { | |
2330 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity)) | |
2331 return false; | |
2332 switch (entity) | |
2333 { | |
2334 case EPIPHANY_MSW_ENTITY_AND: | |
2335 case EPIPHANY_MSW_ENTITY_OR: | |
2336 case EPIPHANY_MSW_ENTITY_CONFIG: | |
2337 return true; | |
2338 case EPIPHANY_MSW_ENTITY_NEAREST: | |
2339 case EPIPHANY_MSW_ENTITY_TRUNC: | |
2340 return optimize > 0; | |
2341 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: | |
2342 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0; | |
2343 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: | |
2344 return (MACHINE_FUNCTION (cfun)->sw_entities_processed | |
2345 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0; | |
2346 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS: | |
2347 return optimize == 0 || current_pass == pass_mode_switch_use; | |
2348 } | |
2349 gcc_unreachable (); | |
2350 } | |
2351 | |
2352 static int | |
2353 epiphany_mode_priority (int entity, int priority) | |
2354 { | |
2355 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR | |
2356 || entity== EPIPHANY_MSW_ENTITY_CONFIG) | |
2357 return priority; | |
2358 if (priority > 3) | |
2359 switch (priority) | |
2360 { | |
2361 case 4: return FP_MODE_ROUND_UNKNOWN; | |
2362 case 5: return FP_MODE_NONE; | |
2363 default: gcc_unreachable (); | |
2364 } | |
2365 switch ((enum attr_fp_mode) epiphany_normal_fp_mode) | |
2366 { | |
2367 case FP_MODE_INT: | |
2368 switch (priority) | |
2369 { | |
2370 case 0: return FP_MODE_INT; | |
2371 case 1: return epiphany_normal_fp_rounding; | |
2372 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST | |
2373 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST); | |
2374 case 3: return FP_MODE_CALLER; | |
2375 } | |
2376 case FP_MODE_ROUND_NEAREST: | |
2377 case FP_MODE_CALLER: | |
2378 switch (priority) | |
2379 { | |
2380 case 0: return FP_MODE_ROUND_NEAREST; | |
2381 case 1: return FP_MODE_ROUND_TRUNC; | |
2382 case 2: return FP_MODE_INT; | |
2383 case 3: return FP_MODE_CALLER; | |
2384 } | |
2385 case FP_MODE_ROUND_TRUNC: | |
2386 switch (priority) | |
2387 { | |
2388 case 0: return FP_MODE_ROUND_TRUNC; | |
2389 case 1: return FP_MODE_ROUND_NEAREST; | |
2390 case 2: return FP_MODE_INT; | |
2391 case 3: return FP_MODE_CALLER; | |
2392 } | |
2393 case FP_MODE_ROUND_UNKNOWN: | |
2394 case FP_MODE_NONE: | |
2395 gcc_unreachable (); | |
2396 } | |
2397 gcc_unreachable (); | |
2398 } | |
2399 | |
2400 int | |
2401 epiphany_mode_needed (int entity, rtx_insn *insn) | |
2402 { | |
2403 enum attr_fp_mode mode; | |
2404 | |
2405 if (recog_memoized (insn) < 0) | |
2406 { | |
2407 if (entity == EPIPHANY_MSW_ENTITY_AND | |
2408 || entity == EPIPHANY_MSW_ENTITY_OR | |
2409 || entity == EPIPHANY_MSW_ENTITY_CONFIG) | |
2410 return 2; | |
2411 return FP_MODE_NONE; | |
2412 } | |
2413 mode = get_attr_fp_mode (insn); | |
2414 | |
2415 switch (entity) | |
2416 { | |
2417 case EPIPHANY_MSW_ENTITY_AND: | |
2418 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2; | |
2419 case EPIPHANY_MSW_ENTITY_OR: | |
2420 return mode == FP_MODE_INT ? 1 : 2; | |
2421 case EPIPHANY_MSW_ENTITY_CONFIG: | |
2422 /* We must know/save config before we set it to something else. | |
2423 Where we need the original value, we are fine with having it | |
2424 just unchanged from the function start. | |
2425 Because of the nature of the mode switching optimization, | |
2426 a restore will be dominated by a clobber. */ | |
2427 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER) | |
2428 return 1; | |
2429 /* A cpecial case are abnormal edges, which are deemed to clobber | |
2430 the mode as well. We need to pin this effect on a actually | |
2431 dominating insn, and one where the frame can be accessed, too, in | |
2432 case the pseudo used to save CONFIG doesn't get a hard register. */ | |
2433 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX)) | |
2434 return 1; | |
2435 return 2; | |
2436 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: | |
2437 if (recog_memoized (insn) == CODE_FOR_set_fp_mode) | |
2438 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn); | |
2439 /* Fall through. */ | |
2440 case EPIPHANY_MSW_ENTITY_NEAREST: | |
2441 case EPIPHANY_MSW_ENTITY_TRUNC: | |
2442 if (mode == FP_MODE_ROUND_UNKNOWN) | |
2443 { | |
2444 MACHINE_FUNCTION (cfun)->unknown_mode_uses++; | |
2445 return FP_MODE_NONE; | |
2446 } | |
2447 return mode; | |
2448 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: | |
2449 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC) | |
2450 return FP_MODE_ROUND_UNKNOWN; | |
2451 return mode; | |
2452 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS: | |
2453 if (mode == FP_MODE_ROUND_UNKNOWN) | |
2454 return epiphany_normal_fp_rounding; | |
2455 return mode; | |
2456 default: | |
2457 gcc_unreachable (); | |
2458 } | |
2459 } | |
2460 | |
2461 static int | |
2462 epiphany_mode_entry_exit (int entity, bool exit) | |
2463 { | |
2464 int normal_mode = epiphany_normal_fp_mode ; | |
2465 | |
2466 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity); | |
2467 if (epiphany_is_interrupt_p (current_function_decl)) | |
2468 normal_mode = FP_MODE_CALLER; | |
2469 switch (entity) | |
2470 { | |
2471 case EPIPHANY_MSW_ENTITY_AND: | |
2472 if (exit) | |
2473 return normal_mode != FP_MODE_INT ? 1 : 2; | |
2474 return 0; | |
2475 case EPIPHANY_MSW_ENTITY_OR: | |
2476 if (exit) | |
2477 return normal_mode == FP_MODE_INT ? 1 : 2; | |
2478 return 0; | |
2479 case EPIPHANY_MSW_ENTITY_CONFIG: | |
2480 if (exit) | |
2481 return 2; | |
2482 return normal_mode == FP_MODE_CALLER ? 0 : 1; | |
2483 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN: | |
2484 if (normal_mode == FP_MODE_ROUND_NEAREST | |
2485 || normal_mode == FP_MODE_ROUND_TRUNC) | |
2486 return FP_MODE_ROUND_UNKNOWN; | |
2487 /* Fall through. */ | |
2488 case EPIPHANY_MSW_ENTITY_NEAREST: | |
2489 case EPIPHANY_MSW_ENTITY_TRUNC: | |
2490 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN: | |
2491 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS: | |
2492 return normal_mode; | |
2493 default: | |
2494 gcc_unreachable (); | |
2495 } | |
2496 } | |
2497 | |
2498 int | |
2499 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn) | |
2500 { | |
2501 /* We have too few call-saved registers to hope to keep the masks across | |
2502 calls. */ | |
2503 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR) | |
2504 { | |
2505 if (CALL_P (insn)) | |
2506 return 0; | |
2507 return last_mode; | |
2508 } | |
2509 /* If there is an abnormal edge, we don't want the config register to | |
2510 be 'saved' again at the destination. | |
2511 The frame pointer adjustment is inside a PARALLEL because of the | |
2512 flags clobber. */ | |
2513 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn) | |
2514 && GET_CODE (PATTERN (insn)) == PARALLEL | |
2515 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET | |
2516 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx) | |
2517 { | |
2518 gcc_assert (cfun->has_nonlocal_label); | |
2519 return 1; | |
2520 } | |
2521 if (recog_memoized (insn) < 0) | |
2522 return last_mode; | |
2523 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN | |
2524 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC) | |
2525 { | |
2526 if (entity == EPIPHANY_MSW_ENTITY_NEAREST) | |
2527 return FP_MODE_ROUND_NEAREST; | |
2528 if (entity == EPIPHANY_MSW_ENTITY_TRUNC) | |
2529 return FP_MODE_ROUND_TRUNC; | |
2530 } | |
2531 if (recog_memoized (insn) == CODE_FOR_set_fp_mode) | |
2532 { | |
2533 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); | |
2534 int fp_mode; | |
2535 | |
2536 if (REG_P (src)) | |
2537 return FP_MODE_CALLER; | |
2538 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0)); | |
2539 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN | |
2540 && (fp_mode == FP_MODE_ROUND_NEAREST | |
2541 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC)) | |
2542 return FP_MODE_ROUND_UNKNOWN; | |
2543 return fp_mode; | |
2544 } | |
2545 return last_mode; | |
2546 } | |
2547 | |
2548 static int | |
2549 epiphany_mode_entry (int entity) | |
2550 { | |
2551 return epiphany_mode_entry_exit (entity, false); | |
2552 } | |
2553 | |
2554 static int | |
2555 epiphany_mode_exit (int entity) | |
2556 { | |
2557 return epiphany_mode_entry_exit (entity, true); | |
2558 } | |
2559 | |
2560 void | |
2561 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED, | |
2562 HARD_REG_SET regs_live ATTRIBUTE_UNUSED) | |
2563 { | |
2564 rtx save_cc, cc_reg, mask, src, src2; | |
2565 enum attr_fp_mode fp_mode; | |
2566 | |
2567 if (!MACHINE_FUNCTION (cfun)->and_mask) | |
2568 { | |
2569 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode); | |
2570 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode); | |
2571 } | |
2572 if (entity == EPIPHANY_MSW_ENTITY_AND) | |
2573 { | |
2574 gcc_assert (mode >= 0 && mode <= 2); | |
2575 if (mode == 1) | |
2576 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask, | |
2577 gen_int_mode (0xfff1fffe, SImode)); | |
2578 return; | |
2579 } | |
2580 else if (entity == EPIPHANY_MSW_ENTITY_OR) | |
2581 { | |
2582 gcc_assert (mode >= 0 && mode <= 2); | |
2583 if (mode == 1) | |
2584 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000)); | |
2585 return; | |
2586 } | |
2587 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG) | |
2588 { | |
2589 /* Mode switching optimization is done after emit_initial_value_sets, | |
2590 so we have to take care of CONFIG_REGNUM here. */ | |
2591 gcc_assert (mode >= 0 && mode <= 2); | |
2592 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM); | |
2593 if (mode == 1) | |
2594 emit_insn (gen_save_config (save)); | |
2595 return; | |
2596 } | |
2597 fp_mode = (enum attr_fp_mode) mode; | |
2598 src = NULL_RTX; | |
2599 | |
2600 switch (fp_mode) | |
2601 { | |
2602 case FP_MODE_CALLER: | |
2603 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later | |
2604 so that the config save gets inserted before the first use. */ | |
2605 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG); | |
2606 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM); | |
2607 mask = MACHINE_FUNCTION (cfun)->and_mask; | |
2608 break; | |
2609 case FP_MODE_ROUND_UNKNOWN: | |
2610 MACHINE_FUNCTION (cfun)->unknown_mode_sets++; | |
2611 mask = MACHINE_FUNCTION (cfun)->and_mask; | |
2612 break; | |
2613 case FP_MODE_ROUND_NEAREST: | |
2614 if (entity == EPIPHANY_MSW_ENTITY_TRUNC) | |
2615 return; | |
2616 mask = MACHINE_FUNCTION (cfun)->and_mask; | |
2617 break; | |
2618 case FP_MODE_ROUND_TRUNC: | |
2619 if (entity == EPIPHANY_MSW_ENTITY_NEAREST) | |
2620 return; | |
2621 mask = MACHINE_FUNCTION (cfun)->and_mask; | |
2622 break; | |
2623 case FP_MODE_INT: | |
2624 mask = MACHINE_FUNCTION (cfun)->or_mask; | |
2625 break; | |
2626 case FP_MODE_NONE: | |
2627 default: | |
2628 gcc_unreachable (); | |
2629 } | |
2630 save_cc = gen_reg_rtx (CCmode); | |
2631 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM); | |
2632 emit_move_insn (save_cc, cc_reg); | |
2633 mask = force_reg (SImode, mask); | |
2634 if (!src) | |
2635 { | |
2636 rtvec v = gen_rtvec (1, GEN_INT (fp_mode)); | |
2637 | |
2638 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE)); | |
2639 } | |
2640 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN | |
2641 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS) | |
2642 src2 = copy_rtx (src); | |
2643 else | |
2644 { | |
2645 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN)); | |
2646 | |
2647 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE)); | |
2648 } | |
2649 emit_insn (gen_set_fp_mode (src, src2, mask)); | |
2650 emit_move_insn (cc_reg, save_cc); | |
2651 } | |
2652 | |
2653 void | |
2654 epiphany_expand_set_fp_mode (rtx *operands) | |
2655 { | |
2656 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM); | |
2657 rtx src = operands[0]; | |
2658 rtx mask_reg = operands[2]; | |
2659 rtx scratch = operands[3]; | |
2660 enum attr_fp_mode fp_mode; | |
2661 | |
2662 | |
2663 gcc_assert (rtx_equal_p (src, operands[1]) | |
2664 /* Sometimes reload gets silly and reloads the same pseudo | |
2665 into different registers. */ | |
2666 || (REG_P (src) && REG_P (operands[1]))); | |
2667 | |
2668 if (!epiphany_uninterruptible_p (current_function_decl)) | |
2669 emit_insn (gen_gid ()); | |
2670 emit_move_insn (scratch, ctrl); | |
2671 | |
2672 if (GET_CODE (src) == REG) | |
2673 { | |
2674 /* FP_MODE_CALLER */ | |
2675 emit_insn (gen_xorsi3 (scratch, scratch, src)); | |
2676 emit_insn (gen_andsi3 (scratch, scratch, mask_reg)); | |
2677 emit_insn (gen_xorsi3 (scratch, scratch, src)); | |
2678 } | |
2679 else | |
2680 { | |
2681 gcc_assert (GET_CODE (src) == CONST); | |
2682 src = XEXP (src, 0); | |
2683 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0)); | |
2684 switch (fp_mode) | |
2685 { | |
2686 case FP_MODE_ROUND_NEAREST: | |
2687 emit_insn (gen_andsi3 (scratch, scratch, mask_reg)); | |
2688 break; | |
2689 case FP_MODE_ROUND_TRUNC: | |
2690 emit_insn (gen_andsi3 (scratch, scratch, mask_reg)); | |
2691 emit_insn (gen_add2_insn (scratch, const1_rtx)); | |
2692 break; | |
2693 case FP_MODE_INT: | |
2694 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg)); | |
2695 break; | |
2696 case FP_MODE_CALLER: | |
2697 case FP_MODE_ROUND_UNKNOWN: | |
2698 case FP_MODE_NONE: | |
2699 gcc_unreachable (); | |
2700 } | |
2701 } | |
2702 emit_move_insn (ctrl, scratch); | |
2703 if (!epiphany_uninterruptible_p (current_function_decl)) | |
2704 emit_insn (gen_gie ()); | |
2705 } | |
2706 | |
2707 void | |
2708 epiphany_insert_mode_switch_use (rtx_insn *insn, | |
2709 int entity ATTRIBUTE_UNUSED, | |
2710 int mode ATTRIBUTE_UNUSED) | |
2711 { | |
2712 rtx pat = PATTERN (insn); | |
2713 rtvec v; | |
2714 int len, i; | |
2715 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM); | |
2716 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM); | |
2717 | |
2718 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS) | |
2719 return; | |
2720 switch ((enum attr_fp_mode) get_attr_fp_mode (insn)) | |
2721 { | |
2722 case FP_MODE_ROUND_NEAREST: | |
2723 near = gen_rtx_USE (VOIDmode, near); | |
2724 trunc = gen_rtx_CLOBBER (VOIDmode, trunc); | |
2725 break; | |
2726 case FP_MODE_ROUND_TRUNC: | |
2727 near = gen_rtx_CLOBBER (VOIDmode, near); | |
2728 trunc = gen_rtx_USE (VOIDmode, trunc); | |
2729 break; | |
2730 case FP_MODE_ROUND_UNKNOWN: | |
2731 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM)); | |
2732 trunc = copy_rtx (near); | |
2733 /* Fall through. */ | |
2734 case FP_MODE_INT: | |
2735 case FP_MODE_CALLER: | |
2736 near = gen_rtx_USE (VOIDmode, near); | |
2737 trunc = gen_rtx_USE (VOIDmode, trunc); | |
2738 break; | |
2739 case FP_MODE_NONE: | |
2740 gcc_unreachable (); | |
2741 } | |
2742 gcc_assert (GET_CODE (pat) == PARALLEL); | |
2743 len = XVECLEN (pat, 0); | |
2744 v = rtvec_alloc (len + 2); | |
2745 for (i = 0; i < len; i++) | |
2746 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i); | |
2747 RTVEC_ELT (v, len) = near; | |
2748 RTVEC_ELT (v, len + 1) = trunc; | |
2749 pat = gen_rtx_PARALLEL (VOIDmode, v); | |
2750 PATTERN (insn) = pat; | |
2751 MACHINE_FUNCTION (cfun)->control_use_inserted = true; | |
2752 } | |
2753 | |
2754 bool | |
2755 epiphany_epilogue_uses (int regno) | |
2756 { | |
2757 if (regno == GPR_LR) | |
2758 return true; | |
2759 if (reload_completed && epiphany_is_interrupt_p (current_function_decl)) | |
2760 { | |
2761 if (fixed_regs[regno] | |
2762 && regno != STATUS_REGNUM && regno != IRET_REGNUM | |
2763 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM) | |
2764 return false; | |
2765 return true; | |
2766 } | |
2767 if (regno == FP_NEAREST_REGNUM | |
2768 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC) | |
2769 return true; | |
2770 if (regno == FP_TRUNCATE_REGNUM | |
2771 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST) | |
2772 return true; | |
2773 return false; | |
2774 } | |
2775 | |
2776 static unsigned int | |
2777 epiphany_min_divisions_for_recip_mul (machine_mode mode) | |
2778 { | |
2779 if (flag_reciprocal_math && mode == SFmode) | |
2780 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do | |
2781 it already at the tree level and expose it to further optimizations. */ | |
2782 return 1; | |
2783 return default_min_divisions_for_recip_mul (mode); | |
2784 } | |
2785 | |
2786 static machine_mode | |
2787 epiphany_preferred_simd_mode (scalar_mode mode ATTRIBUTE_UNUSED) | |
2788 { | |
2789 return TARGET_VECT_DOUBLE ? DImode : SImode; | |
2790 } | |
2791 | |
2792 static bool | |
2793 epiphany_vector_mode_supported_p (machine_mode mode) | |
2794 { | |
2795 if (mode == V2SFmode) | |
2796 return true; | |
2797 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT | |
2798 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)) | |
2799 return true; | |
2800 return false; | |
2801 } | |
2802 | |
2803 static bool | |
2804 epiphany_vector_alignment_reachable (const_tree type, bool is_packed) | |
2805 { | |
2806 /* Vectors which aren't in packed structures will not be less aligned than | |
2807 the natural alignment of their element type, so this is safe. */ | |
2808 if (TYPE_ALIGN_UNIT (type) == 4) | |
2809 return !is_packed; | |
2810 | |
2811 return default_builtin_vector_alignment_reachable (type, is_packed); | |
2812 } | |
2813 | |
2814 static bool | |
2815 epiphany_support_vector_misalignment (machine_mode mode, const_tree type, | |
2816 int misalignment, bool is_packed) | |
2817 { | |
2818 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0) | |
2819 return true; | |
2820 return default_builtin_support_vector_misalignment (mode, type, misalignment, | |
2821 is_packed); | |
2822 } | |
2823 | |
2824 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small | |
2825 structs. Make structs double-word-aligned it they are a double word or | |
2826 (potentially) larger; failing that, do the same for a size of 32 bits. */ | |
2827 unsigned | |
2828 epiphany_special_round_type_align (tree type, unsigned computed, | |
2829 unsigned specified) | |
2830 { | |
2831 unsigned align = MAX (computed, specified); | |
2832 tree field; | |
2833 HOST_WIDE_INT total, max; | |
2834 unsigned try_align = FASTEST_ALIGNMENT; | |
2835 | |
2836 if (maximum_field_alignment && try_align > maximum_field_alignment) | |
2837 try_align = maximum_field_alignment; | |
2838 if (align >= try_align) | |
2839 return align; | |
2840 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) | |
2841 { | |
2842 tree offset, size; | |
2843 | |
2844 if (TREE_CODE (field) != FIELD_DECL | |
2845 || TREE_TYPE (field) == error_mark_node) | |
2846 continue; | |
2847 offset = bit_position (field); | |
2848 size = DECL_SIZE (field); | |
2849 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size) | |
2850 || tree_to_uhwi (offset) >= try_align | |
2851 || tree_to_uhwi (size) >= try_align) | |
2852 return try_align; | |
2853 total = tree_to_uhwi (offset) + tree_to_uhwi (size); | |
2854 if (total > max) | |
2855 max = total; | |
2856 } | |
2857 if (max >= (HOST_WIDE_INT) try_align) | |
2858 align = try_align; | |
2859 else if (try_align > 32 && max >= 32) | |
2860 align = max > 32 ? 64 : 32; | |
2861 return align; | |
2862 } | |
2863 | |
2864 /* Upping the alignment of arrays in structs is not only a performance | |
2865 enhancement, it also helps preserve assumptions about how | |
2866 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in | |
2867 libgcov.c . */ | |
2868 unsigned | |
2869 epiphany_adjust_field_align (tree type, unsigned computed) | |
2870 { | |
2871 if (computed == 32 | |
2872 && TREE_CODE (type) == ARRAY_TYPE) | |
2873 { | |
2874 tree elmsz = TYPE_SIZE (TREE_TYPE (type)); | |
2875 | |
2876 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32) | |
2877 return 64; | |
2878 } | |
2879 return computed; | |
2880 } | |
2881 | |
2882 /* Output code to add DELTA to the first argument, and then jump | |
2883 to FUNCTION. Used for C++ multiple inheritance. */ | |
2884 static void | |
2885 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, | |
2886 HOST_WIDE_INT delta, | |
2887 HOST_WIDE_INT vcall_offset, | |
2888 tree function) | |
2889 { | |
2890 int this_regno | |
2891 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0; | |
2892 const char *this_name = reg_names[this_regno]; | |
2893 const char *fname; | |
2894 | |
2895 /* We use IP and R16 as a scratch registers. */ | |
2896 gcc_assert (call_used_regs [GPR_IP]); | |
2897 gcc_assert (call_used_regs [GPR_16]); | |
2898 | |
2899 /* Add DELTA. When possible use a plain add, otherwise load it into | |
2900 a register first. */ | |
2901 if (delta == 0) | |
2902 ; /* Done. */ | |
2903 else if (SIMM11 (delta)) | |
2904 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta); | |
2905 else if (delta < 0 && delta >= -0xffff) | |
2906 { | |
2907 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta); | |
2908 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name); | |
2909 } | |
2910 else | |
2911 { | |
2912 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta); | |
2913 if (delta & ~0xffff) | |
2914 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta); | |
2915 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name); | |
2916 } | |
2917 | |
2918 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ | |
2919 if (vcall_offset != 0) | |
2920 { | |
2921 /* ldr ip,[this] --> temp = *this | |
2922 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset) | |
2923 add this,this,ip --> this+ = *(*this + vcall_offset) */ | |
2924 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name); | |
2925 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4 | |
2926 || (vcall_offset & 3) != 0) | |
2927 { | |
2928 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset); | |
2929 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset); | |
2930 asm_fprintf (file, "\tldr\tip, [ip,r16]\n"); | |
2931 } | |
2932 else | |
2933 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4); | |
2934 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name); | |
2935 } | |
2936 | |
2937 fname = XSTR (XEXP (DECL_RTL (function), 0), 0); | |
2938 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0))) | |
2939 { | |
2940 fputs ("\tmov\tip,%low(", file); | |
2941 assemble_name (file, fname); | |
2942 fputs (")\n\tmovt\tip,%high(", file); | |
2943 assemble_name (file, fname); | |
2944 fputs (")\n\tjr ip\n", file); | |
2945 } | |
2946 else | |
2947 { | |
2948 fputs ("\tb\t", file); | |
2949 assemble_name (file, fname); | |
2950 fputc ('\n', file); | |
2951 } | |
2952 } | |
2953 | |
2954 void | |
2955 epiphany_start_function (FILE *file, const char *name, tree decl) | |
2956 { | |
2957 /* If the function doesn't fit into the on-chip memory, it will have a | |
2958 section attribute - or lack of it - that denotes it goes somewhere else. | |
2959 But the architecture spec says that an interrupt vector still has to | |
2960 point to on-chip memory. So we must place a jump there to get to the | |
2961 actual function implementation. The forwarder_section attribute | |
2962 specifies the section where this jump goes. | |
2963 This mechanism can also be useful to have a shortcall destination for | |
2964 a function that is actually placed much farther away. */ | |
2965 tree attrs, int_attr, int_names, int_name, forwarder_attr; | |
2966 | |
2967 attrs = DECL_ATTRIBUTES (decl); | |
2968 int_attr = lookup_attribute ("interrupt", attrs); | |
2969 if (int_attr) | |
2970 for (int_names = TREE_VALUE (int_attr); int_names; | |
2971 int_names = TREE_CHAIN (int_names)) | |
2972 { | |
2973 char buf[99]; | |
2974 | |
2975 int_name = TREE_VALUE (int_names); | |
2976 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name)); | |
2977 switch_to_section (get_section (buf, SECTION_CODE, decl)); | |
2978 fputs ("\tb\t", file); | |
2979 assemble_name (file, name); | |
2980 fputc ('\n', file); | |
2981 } | |
2982 forwarder_attr = lookup_attribute ("forwarder_section", attrs); | |
2983 if (forwarder_attr) | |
2984 { | |
2985 const char *prefix = "__forwarder_dst_"; | |
2986 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1); | |
2987 | |
2988 strcpy (dst_name, prefix); | |
2989 strcat (dst_name, name); | |
2990 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr)); | |
2991 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr), | |
2992 SECTION_CODE, decl)); | |
2993 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); | |
2994 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0))) | |
2995 { | |
2996 int tmp = GPR_0; | |
2997 | |
2998 if (int_attr) | |
2999 fputs ("\tstrd r0,[sp,-1]\n", file); | |
3000 else | |
3001 tmp = GPR_16; | |
3002 gcc_assert (call_used_regs[tmp]); | |
3003 fprintf (file, "\tmov r%d,%%low(", tmp); | |
3004 assemble_name (file, dst_name); | |
3005 fprintf (file, ")\n" | |
3006 "\tmovt r%d,%%high(", tmp); | |
3007 assemble_name (file, dst_name); | |
3008 fprintf (file, ")\n" | |
3009 "\tjr r%d\n", tmp); | |
3010 } | |
3011 else | |
3012 { | |
3013 fputs ("\tb\t", file); | |
3014 assemble_name (file, dst_name); | |
3015 fputc ('\n', file); | |
3016 } | |
3017 name = dst_name; | |
3018 } | |
3019 switch_to_section (function_section (decl)); | |
3020 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); | |
3021 } | |
3022 | |
3023 | |
3024 /* Implement TARGET_CONSTANT_ALIGNMENT. */ | |
3025 | |
3026 static HOST_WIDE_INT | |
3027 epiphany_constant_alignment (const_tree exp, HOST_WIDE_INT align) | |
3028 { | |
3029 if (TREE_CODE (exp) == STRING_CST) | |
3030 return MAX (align, FASTEST_ALIGNMENT); | |
3031 return align; | |
3032 } | |
3033 | |
3034 /* Implement TARGET_STARTING_FRAME_OFFSET. */ | |
3035 | |
3036 static HOST_WIDE_INT | |
3037 epiphany_starting_frame_offset (void) | |
3038 { | |
3039 return epiphany_stack_offset; | |
3040 } | |
3041 | |
3042 struct gcc_target targetm = TARGET_INITIALIZER; |