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;