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