1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994-2013 Free Software Foundation, Inc.
3 Contributed by Embecosm on behalf of Adapteva, Inc.
5 This file is part of GCC.
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)
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.
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/>. */
23 #include "coretypes.h"
28 #include "hard-reg-set.h"
30 #include "insn-config.h"
31 #include "conditions.h"
33 #include "insn-attr.h"
37 #include "diagnostic-core.h"
43 #include "langhooks.h"
44 #include "insn-codes.h"
46 #include "tm-constrs.h"
47 #include "tree-pass.h" /* for current_pass */
49 /* Which cpu we're compiling for. */
50 int epiphany_cpu_type;
52 /* Name of mangle string to add to symbols to separate code compiled for each
54 const char *epiphany_mangle_cpu;
56 /* Array of valid operand punctuation characters. */
57 char epiphany_punct_chars[256];
59 /* The rounding mode that we generally use for floating point. */
60 int epiphany_normal_fp_rounding;
62 static void epiphany_init_reg_tables (void);
63 static int get_epiphany_condition_code (rtx);
64 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
65 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
67 static bool epiphany_pass_by_reference (cumulative_args_t, enum machine_mode,
69 static rtx frame_insn (rtx);
71 /* defines for the initialization of the GCC target structure. */
72 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
74 #define TARGET_PRINT_OPERAND epiphany_print_operand
75 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
77 #define TARGET_RTX_COSTS epiphany_rtx_costs
78 #define TARGET_ADDRESS_COST epiphany_address_cost
79 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
81 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
82 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
84 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
85 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
86 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
87 #define TARGET_FUNCTION_VALUE epiphany_function_value
88 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
89 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
91 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
93 /* Using the simplistic varags handling forces us to do partial reg/stack
94 argument passing for types with larger size (> 4 bytes) than alignemnt. */
95 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
97 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
99 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
100 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
102 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
104 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
106 #define TARGET_OPTION_OVERRIDE epiphany_override_options
108 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
110 #define TARGET_FUNCTION_ARG epiphany_function_arg
112 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
114 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
116 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
118 /* Nonzero if the constant rtx value is a legitimate general operand.
119 We can handle any 32- or 64-bit constant. */
120 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
122 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
123 epiphany_min_divisions_for_recip_mul
125 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
127 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
129 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
130 epiphany_vector_alignment_reachable
132 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
133 epiphany_support_vector_misalignment
135 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
136 hook_bool_const_tree_hwi_hwi_const_tree_true
137 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
139 #include "target-def.h"
141 #undef TARGET_ASM_ALIGNED_HI_OP
142 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
143 #undef TARGET_ASM_ALIGNED_SI_OP
144 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
147 epiphany_is_interrupt_p (tree decl)
151 attrs = DECL_ATTRIBUTES (decl);
152 if (lookup_attribute ("interrupt", attrs))
158 /* Called from epiphany_override_options.
159 We use this to initialize various things. */
164 /* N.B. this pass must not run before the first optimize_mode_switching
165 pass because of the side offect of epiphany_mode_needed on
166 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
167 pass_resolve_sw_modes. */
168 static struct register_pass_info insert_use_info
169 = { &pass_mode_switch_use.pass, "mode_sw",
170 1, PASS_POS_INSERT_AFTER
172 static struct register_pass_info mode_sw2_info
173 = { &pass_mode_switching.pass, "mode_sw",
174 1, PASS_POS_INSERT_AFTER
176 static struct register_pass_info mode_sw3_info
177 = { &pass_resolve_sw_modes.pass, "mode_sw",
178 1, PASS_POS_INSERT_AFTER
180 static struct register_pass_info mode_sw4_info
181 = { &pass_split_all_insns.pass, "mode_sw",
182 1, PASS_POS_INSERT_AFTER
184 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
185 #define N_ENTITIES ARRAY_SIZE (num_modes)
187 epiphany_init_reg_tables ();
189 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
190 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
191 epiphany_punct_chars['-'] = 1;
193 epiphany_normal_fp_rounding
194 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
195 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
196 register_pass (&mode_sw4_info);
197 register_pass (&mode_sw2_info);
198 register_pass (&mode_sw3_info);
199 register_pass (&insert_use_info);
200 register_pass (&mode_sw2_info);
201 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
202 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
204 #if 1 /* As long as peep2_rescan is not implemented,
205 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
206 we need a second peephole2 pass to get reasonable code. */
208 static struct register_pass_info peep2_2_info
209 = { &pass_peephole2.pass, "peephole2",
210 1, PASS_POS_INSERT_AFTER
213 register_pass (&peep2_2_info);
218 /* The condition codes of the EPIPHANY, and the inverse function. */
219 static const char *const epiphany_condition_codes[] =
220 { /* 0 1 2 3 4 5 6 7 8 9 */
221 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
223 "beq","bne","blt", "blte",
226 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
228 /* Returns the index of the EPIPHANY condition code string in
229 `epiphany_condition_codes'. COMPARISON should be an rtx like
230 `(eq (...) (...))'. */
233 get_epiphany_condition_code (rtx comparison)
235 switch (GET_MODE (XEXP (comparison, 0)))
238 switch (GET_CODE (comparison))
251 default : gcc_unreachable ();
254 switch (GET_CODE (comparison))
258 default: gcc_unreachable ();
261 switch (GET_CODE (comparison))
265 default: gcc_unreachable ();
268 switch (GET_CODE (comparison))
272 default: gcc_unreachable ();
275 switch (GET_CODE (comparison))
281 default: gcc_unreachable ();
284 switch (GET_CODE (comparison))
288 default: gcc_unreachable ();
291 switch (GET_CODE (comparison))
297 case UNLE : return 5;
298 case UNLT : return 7;
299 default: gcc_unreachable ();
302 switch (GET_CODE (comparison))
304 case ORDERED: return 9;
305 case UNORDERED: return 8;
306 default: gcc_unreachable ();
309 switch (GET_CODE (comparison))
313 default: gcc_unreachable ();
315 default: gcc_unreachable ();
322 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
324 hard_regno_mode_ok (int regno, enum machine_mode mode)
326 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
327 return (regno & 1) == 0 && GPR_P (regno);
332 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
333 return the mode to be used for the comparison. */
336 epiphany_select_cc_mode (enum rtx_code op,
337 rtx x ATTRIBUTE_UNUSED,
338 rtx y ATTRIBUTE_UNUSED)
340 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
342 if (TARGET_SOFT_CMPSF)
344 if (op == EQ || op == NE)
346 if (op == ORDERED || op == UNORDERED)
347 return CC_FP_ORDmode;
348 if (op == UNEQ || op == LTGT)
349 return CC_FP_UNEQmode;
350 return CC_FP_GTEmode;
354 /* recognize combiner pattern ashlsi_btst:
356 (set (reg:N_NE 65 cc1)
357 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
360 (const_int 0 [0x0])))
361 (clobber (scratch:SI)) */
362 else if ((op == EQ || op == NE)
363 && GET_CODE (x) == ZERO_EXTRACT
364 && XEXP (x, 1) == const1_rtx
365 && CONST_INT_P (XEXP (x, 2)))
367 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
369 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
375 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
378 epiphany_init_reg_tables (void)
382 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
385 epiphany_regno_reg_class[i] = LR_REGS;
386 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
387 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
388 else if (call_used_regs[i]
389 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
390 epiphany_regno_reg_class[i] = SIBCALL_REGS;
391 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
392 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
393 else if (i < (GPR_LAST+1)
394 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
395 epiphany_regno_reg_class[i] = GENERAL_REGS;
396 else if (i == CC_REGNUM)
397 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
399 epiphany_regno_reg_class[i] = NO_REGS;
403 /* EPIPHANY specific attribute support.
405 The EPIPHANY has these attributes:
406 interrupt - for interrupt functions.
407 short_call - the function is assumed to be reachable with the b / bl
409 long_call - the function address is loaded into a register before use.
410 disinterrupt - functions which mask interrupts throughout.
411 They unmask them while calling an interruptible
414 static const struct attribute_spec epiphany_attribute_table[] =
416 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
417 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
418 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
419 { "long_call", 0, 0, false, true, true, NULL, false },
420 { "short_call", 0, 0, false, true, true, NULL, false },
421 { "disinterrupt", 0, 0, false, true, true, NULL, true },
422 { NULL, 0, 0, false, false, false, NULL, false }
425 /* Handle an "interrupt" attribute; arguments as in
426 struct attribute_spec.handler. */
428 epiphany_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
429 tree name, tree args,
430 int flags ATTRIBUTE_UNUSED,
438 value = TREE_VALUE (args);
440 if (TREE_CODE (value) != STRING_CST)
442 warning (OPT_Wattributes,
443 "argument of %qE attribute is not a string constant", name);
444 *no_add_attrs = true;
446 else if (strcmp (TREE_STRING_POINTER (value), "reset")
447 && strcmp (TREE_STRING_POINTER (value), "software_exception")
448 && strcmp (TREE_STRING_POINTER (value), "page_miss")
449 && strcmp (TREE_STRING_POINTER (value), "timer0")
450 && strcmp (TREE_STRING_POINTER (value), "timer1")
451 && strcmp (TREE_STRING_POINTER (value), "message")
452 && strcmp (TREE_STRING_POINTER (value), "dma0")
453 && strcmp (TREE_STRING_POINTER (value), "dma1")
454 && strcmp (TREE_STRING_POINTER (value), "wand")
455 && strcmp (TREE_STRING_POINTER (value), "swi"))
457 warning (OPT_Wattributes,
458 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
460 *no_add_attrs = true;
464 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
465 flags, no_add_attrs);
468 /* Handle a "forwarder_section" attribute; arguments as in
469 struct attribute_spec.handler. */
471 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
472 tree name, tree args,
473 int flags ATTRIBUTE_UNUSED,
478 value = TREE_VALUE (args);
480 if (TREE_CODE (value) != STRING_CST)
482 warning (OPT_Wattributes,
483 "argument of %qE attribute is not a string constant", name);
484 *no_add_attrs = true;
490 /* Misc. utilities. */
492 /* Generate a SYMBOL_REF for the special function NAME. When the address
493 can't be placed directly into a call instruction, and if possible, copy
494 it to a register so that cse / code hoisting is possible. */
496 sfunc_symbol (const char *name)
498 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
500 /* These sfuncs should be hidden, and every dso should get a copy. */
501 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
502 if (TARGET_SHORT_CALLS)
503 ; /* Nothing to be done. */
504 else if (can_create_pseudo_p ())
505 sym = copy_to_mode_reg (Pmode, sym);
506 else /* We rely on reload to fix this up. */
507 gcc_assert (!reload_in_progress || reload_completed);
511 /* X and Y are two things to compare using CODE in IN_MODE.
512 Emit the compare insn, construct the the proper cc reg in the proper
513 mode, and return the rtx for the cc reg comparison in CMODE. */
516 gen_compare_reg (enum machine_mode cmode, enum rtx_code code,
517 enum machine_mode in_mode, rtx x, rtx y)
519 enum machine_mode mode = SELECT_CC_MODE (code, x, y);
520 rtx cc_reg, pat, clob0, clob1, clob2;
522 if (in_mode == VOIDmode)
523 in_mode = GET_MODE (x);
524 if (in_mode == VOIDmode)
525 in_mode = GET_MODE (y);
527 if (mode == CC_FPmode)
529 /* The epiphany has only EQ / NE / LT / LE conditions for
530 hardware floating point. */
531 if (code == GT || code == GE || code == UNLE || code == UNLT)
533 rtx tmp = x; x = y; y = tmp;
534 code = swap_condition (code);
536 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
537 y = force_reg (in_mode, y);
541 if (mode == CC_FP_GTEmode
542 && (code == LE || code == LT || code == UNGT || code == UNGE))
544 rtx tmp = x; x = y; y = tmp;
545 code = swap_condition (code);
547 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
549 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
550 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
551 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
552 && (!REG_P (x) || REGNO (x) != 0 || !REG_P (y) || REGNO (y) != 1))
556 gcc_assert (currently_expanding_to_rtl);
557 reg = gen_rtx_REG (in_mode, 0);
558 gcc_assert (!reg_overlap_mentioned_p (reg, y));
559 emit_move_insn (reg, x);
561 reg = gen_rtx_REG (in_mode, 1);
562 emit_move_insn (reg, y);
566 x = force_reg (in_mode, x);
568 pat = gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y));
569 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
571 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
572 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
574 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
575 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
576 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
578 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
580 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
581 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
583 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
584 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
585 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
586 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
587 clob0, clob1, clob2));
591 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
592 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
595 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
598 /* The ROUND_ADVANCE* macros are local to this file. */
599 /* Round SIZE up to a word boundary. */
600 #define ROUND_ADVANCE(SIZE) \
601 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
603 /* Round arg MODE/TYPE up to the next word boundary. */
604 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
606 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
607 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
609 /* Round CUM up to the necessary point for argument MODE/TYPE. */
610 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
611 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
612 ? (((CUM) + 1) & ~1) \
616 epiphany_function_arg_boundary (enum machine_mode mode, const_tree type)
618 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
619 return PARM_BOUNDARY;
620 return 2 * PARM_BOUNDARY;
623 /* Do any needed setup for a variadic function. For the EPIPHANY, we
624 actually emit the code in epiphany_expand_prologue.
626 CUM has not been updated for the last named argument which has type TYPE
627 and mode MODE, and we rely on this fact. */
631 epiphany_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
632 tree type, int *pretend_size, int no_rtl)
635 CUMULATIVE_ARGS next_cum;
636 machine_function_t *mf = MACHINE_FUNCTION (cfun);
638 /* All BLKmode values are passed by reference. */
639 gcc_assert (mode != BLKmode);
641 next_cum = *get_cumulative_args (cum);
643 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
644 first_anon_arg = next_cum;
646 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
648 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
649 int first_reg_offset = first_anon_arg;
651 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
655 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
659 epiphany_arg_partial_bytes (cumulative_args_t cum, enum machine_mode mode,
660 tree type, bool named ATTRIBUTE_UNUSED)
662 int words = 0, rounded_cum;
664 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
666 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
667 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
669 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
670 if (words >= ROUND_ADVANCE_ARG (mode, type))
673 return words * UNITS_PER_WORD;
676 /* Cost functions. */
678 /* Compute a (partial) cost for rtx X. Return true if the complete
679 cost has been computed, and false if subexpressions should be
680 scanned. In either case, *TOTAL contains the cost result. */
683 epiphany_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
684 int *total, bool speed ATTRIBUTE_UNUSED)
688 /* Small integers in the right context are as cheap as registers. */
690 if ((outer_code == PLUS || outer_code == MINUS)
691 && SIMM11 (INTVAL (x)))
696 if (IMM16 (INTVAL (x)))
698 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
706 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
707 + (outer_code == SET ? 0 : 1));
713 split_double (x, &high, &low);
714 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
715 + !IMM16 (INTVAL (low)));
722 *total = COSTS_N_INSNS (1);
731 /* Provide the costs of an addressing mode that contains ADDR.
732 If ADDR is not a valid address, its cost is irrelevant. */
735 epiphany_address_cost (rtx addr, enum machine_mode mode,
736 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
739 rtx off = const0_rtx;
744 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
746 switch (GET_CODE (addr))
749 reg = XEXP (addr, 0);
750 off = XEXP (addr, 1);
753 reg = XEXP (addr, 0);
754 off = XEXP (addr, 1);
755 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
757 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
765 if (!satisfies_constraint_Rgs (reg))
767 /* The offset range available for short instructions depends on the mode
768 of the memory access. */
769 /* First, make sure we have a valid integer. */
770 if (!satisfies_constraint_L (off))
773 switch (GET_MODE_SIZE (mode))
787 return i < -7 || i > 7;
791 /* Compute the cost of moving data between registers and memory.
792 For integer, load latency is twice as long as register-register moves,
793 but issue pich is the same. For floating point, load latency is three
794 times as much as a reg-reg move. */
796 epiphany_memory_move_cost (enum machine_mode mode,
797 reg_class_t rclass ATTRIBUTE_UNUSED,
798 bool in ATTRIBUTE_UNUSED)
800 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
803 /* Function prologue/epilogue handlers. */
805 /* EPIPHANY stack frames look like:
807 Before call After call
808 +-----------------------+ +-----------------------+
810 high | local variables, | | local variables, |
811 mem | reg save area, etc. | | reg save area, etc. |
813 +-----------------------+ +-----------------------+
815 | arguments on stack. | | arguments on stack. |
817 SP+8->+-----------------------+FP+8m->+-----------------------+
818 | 2 word save area for | | reg parm save area, |
819 | leaf funcs / flags | | only created for |
820 SP+0->+-----------------------+ | variable argument |
822 FP+8n->+-----------------------+
824 | register save area |
826 +-----------------------+
830 FP+0->+-----------------------+
832 | alloca allocations |
834 +-----------------------+
836 | arguments on stack |
838 SP+8->+-----------------------+
839 low | 2 word save area for |
840 memory | leaf funcs / flags |
841 SP+0->+-----------------------+
844 1) The "reg parm save area" does not exist for non variable argument fns.
845 The "reg parm save area" could be eliminated if we created our
846 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
847 (so it's not done). */
849 /* Structure to be filled in by epiphany_compute_frame_size with register
850 save masks, and offsets for the current function. */
851 struct epiphany_frame_info
853 unsigned int total_size; /* # bytes that the entire frame takes up. */
854 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
855 unsigned int args_size; /* # bytes that outgoing arguments take up. */
856 unsigned int reg_size; /* # bytes needed to store regs. */
857 unsigned int var_size; /* # bytes that variables take up. */
858 HARD_REG_SET gmask; /* Set of saved gp registers. */
859 int initialized; /* Nonzero if frame size already calculated. */
860 int stld_sz; /* Current load/store data size for offset
862 int need_fp; /* value to override "frame_pointer_needed */
863 int first_slot, last_slot, first_slot_offset, last_slot_offset;
868 /* Current frame information calculated by epiphany_compute_frame_size. */
869 static struct epiphany_frame_info current_frame_info;
871 /* Zero structure to initialize current_frame_info. */
872 static struct epiphany_frame_info zero_frame_info;
874 /* The usual; we set up our machine_function data. */
875 static struct machine_function *
876 epiphany_init_machine_status (void)
878 struct machine_function *machine;
880 /* Reset state info for each function. */
881 current_frame_info = zero_frame_info;
883 machine = ggc_alloc_cleared_machine_function_t ();
888 /* Implements INIT_EXPANDERS. We just set up to call the above
891 epiphany_init_expanders (void)
893 init_machine_status = epiphany_init_machine_status;
896 /* Type of function DECL.
898 The result is cached. To reset the cache at the end of a function,
899 call with DECL = NULL_TREE. */
901 static enum epiphany_function_type
902 epiphany_compute_function_type (tree decl)
906 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
907 /* Last function we were called for. */
908 static tree last_fn = NULL_TREE;
910 /* Resetting the cached value? */
911 if (decl == NULL_TREE)
913 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
918 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
921 /* Assume we have a normal function (not an interrupt handler). */
922 fn_type = EPIPHANY_FUNCTION_NORMAL;
924 /* Now see if this is an interrupt handler. */
925 for (a = DECL_ATTRIBUTES (decl);
929 tree name = TREE_PURPOSE (a);
931 if (name == get_identifier ("interrupt"))
932 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
939 #define RETURN_ADDR_REGNUM GPR_LR
940 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
941 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
943 /* Tell prologue and epilogue if register REGNO should be saved / restored.
944 The return address and frame pointer are treated separately.
945 Don't consider them here. */
946 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
947 ((df_regs_ever_live_p (regno) \
948 || (interrupt_p && !crtl->is_leaf \
949 && call_used_regs[regno] && !fixed_regs[regno])) \
950 && (!call_used_regs[regno] || regno == GPR_LR \
951 || (interrupt_p && regno != GPR_SP)))
953 #define MUST_SAVE_RETURN_ADDR 0
955 /* Return the bytes needed to compute the frame pointer from the current
958 SIZE is the size needed for local variables. */
961 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
964 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
966 enum epiphany_function_type fn_type;
968 int first_slot, last_slot, first_slot_offset, last_slot_offset;
974 args_size = crtl->outgoing_args_size;
975 pretend_size = crtl->args.pretend_args_size;
976 total_size = args_size + var_size;
978 CLEAR_HARD_REG_SET (gmask);
980 first_slot_offset = 0;
982 last_slot_offset = 0;
983 first_slot_size = UNITS_PER_WORD;
985 /* See if this is an interrupt handler. Call used registers must be saved
987 fn_type = epiphany_compute_function_type (current_function_decl);
988 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
990 /* Calculate space needed for registers. */
992 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
994 reg_size += UNITS_PER_WORD;
995 SET_HARD_REG_BIT (gmask, regno);
996 if (epiphany_stack_offset - reg_size == 0)
1001 reg_size += 2 * UNITS_PER_WORD;
1003 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
1005 if (frame_pointer_needed)
1007 current_frame_info.need_fp = 1;
1008 if (!interrupt_p && first_slot < 0)
1009 first_slot = GPR_FP;
1012 current_frame_info.need_fp = 0;
1013 for (regno = 0; regno <= GPR_LAST; regno++)
1015 if (MUST_SAVE_REGISTER (regno, interrupt_p))
1017 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1018 reg_size += UNITS_PER_WORD;
1019 SET_HARD_REG_BIT (gmask, regno);
1020 /* FIXME: when optimizing for speed, take schedling into account
1021 when selecting these registers. */
1022 if (regno == first_slot)
1023 gcc_assert (regno == GPR_FP && frame_pointer_needed);
1024 else if (!interrupt_p && first_slot < 0)
1026 else if (last_slot < 0
1027 && (first_slot ^ regno) != 1
1028 && (!interrupt_p || regno > GPR_0 + 1))
1032 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1033 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1034 /* ??? Could sometimes do better than that. */
1035 current_frame_info.small_threshold
1036 = (optimize >= 3 || interrupt_p ? 0
1037 : pretend_size ? small_slots
1038 : 4 + small_slots - (first_slot == GPR_FP));
1040 /* If there might be variables with 64-bit alignment requirement, align the
1041 start of the variables. */
1042 if (var_size >= 2 * UNITS_PER_WORD
1043 /* We don't want to split a double reg save/restore across two unpaired
1044 stack slots when optimizing. This rounding could be avoided with
1045 more complex reordering of the register saves, but that would seem
1046 to be a lot of code complexity for little gain. */
1047 || (reg_size > 8 && optimize))
1048 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1049 if (total_size + reg_size <= (unsigned) epiphany_stack_offset
1051 && crtl->is_leaf && !frame_pointer_needed)
1059 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1060 reg_size = epiphany_stack_offset;
1063 if (total_size + reg_size < 0x3fc)
1065 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1066 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1071 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1072 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1073 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1075 CLEAR_HARD_REG_BIT (gmask, last_slot);
1078 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1080 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1085 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1087 gcc_assert (first_slot < 0);
1088 gcc_assert (reg_size == 0);
1089 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1095 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1096 if (!first_slot_offset)
1098 if (first_slot != GPR_FP || !current_frame_info.need_fp)
1099 last_slot = first_slot;
1102 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1104 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1107 CLEAR_HARD_REG_BIT (gmask, last_slot);
1110 if (first_slot >= 0)
1112 CLEAR_HARD_REG_BIT (gmask, first_slot);
1113 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1114 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1116 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1117 first_slot_size = 2 * UNITS_PER_WORD;
1121 total_size = first_slot_offset + last_slot_offset;
1124 = (frame_pointer_needed ? first_slot_offset : (long) total_size);
1125 if (first_slot != GPR_LR)
1127 int stack_offset = epiphany_stack_offset - UNITS_PER_WORD;
1129 for (regno = 0; ; regno++)
1131 if (stack_offset + UNITS_PER_WORD - first_slot_size == 0
1134 stack_offset -= first_slot_size;
1137 else if (regno == GPR_LR)
1139 else if TEST_HARD_REG_BIT (gmask, regno)
1140 stack_offset -= UNITS_PER_WORD;
1142 lr_slot_offset += stack_offset;
1145 /* Save computed information. */
1146 current_frame_info.total_size = total_size;
1147 current_frame_info.pretend_size = pretend_size;
1148 current_frame_info.var_size = var_size;
1149 current_frame_info.args_size = args_size;
1150 current_frame_info.reg_size = reg_size;
1151 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1152 current_frame_info.first_slot = first_slot;
1153 current_frame_info.last_slot = last_slot;
1154 current_frame_info.first_slot_offset = first_slot_offset;
1155 current_frame_info.first_slot_size = first_slot_size;
1156 current_frame_info.last_slot_offset = last_slot_offset;
1157 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1159 current_frame_info.initialized = reload_completed;
1161 /* Ok, we're done. */
1165 /* Print operand X (an rtx) in assembler syntax to file FILE.
1166 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1167 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1170 epiphany_print_operand (FILE *file, rtx x, int code)
1175 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1178 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1179 (get_epiphany_condition_code (x))],
1184 current_frame_info.stld_sz = 8;
1188 current_frame_info.stld_sz = 4;
1192 current_frame_info.stld_sz = 2;
1196 fputs (REG_P (x) ? "jalr " : "bl ", file);
1200 fprintf (file, "r%d", epiphany_m1reg);
1204 /* Do nothing special. */
1208 output_operand_lossage ("invalid operand output code");
1211 switch (GET_CODE (x))
1217 fputs (reg_names[REGNO (x)], file);
1221 current_frame_info.stld_sz = 1;
1224 switch (GET_CODE (addr))
1227 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1228 addr = XEXP (addr, 0);
1231 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1232 addr = XEXP (addr, 0);
1235 offset = XEXP (XEXP (addr, 1), 1);
1236 addr = XEXP (addr, 0);
1242 output_address (addr);
1247 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1252 offset = GEN_INT (INTVAL (offset) >> 3);
1255 offset = GEN_INT (INTVAL (offset) >> 2);
1258 offset = GEN_INT (INTVAL (offset) >> 1);
1263 output_address (offset);
1267 /* We handle SFmode constants here as output_addr_const doesn't. */
1268 if (GET_MODE (x) == SFmode)
1273 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
1274 REAL_VALUE_TO_TARGET_SINGLE (d, l);
1275 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1278 /* Fall through. Let output_addr_const deal with it. */
1280 fprintf(file,"%s",IMMEDIATE_PREFIX);
1281 if (code == 'C' || code == 'X')
1283 fprintf (file, "%ld",
1284 (long) (INTVAL (x) / current_frame_info.stld_sz));
1289 output_addr_const (file, x);
1294 /* Print a memory address as an operand to reference that memory location. */
1297 epiphany_print_operand_address (FILE *file, rtx addr)
1299 register rtx base, index = 0;
1302 switch (GET_CODE (addr))
1305 fputs (reg_names[REGNO (addr)], file);
1308 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1310 output_addr_const (file, addr);
1314 output_addr_const (file, addr);
1318 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1319 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1320 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1321 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1323 base = XEXP (addr, 0), index = XEXP (addr, 1);
1324 gcc_assert (GET_CODE (base) == REG);
1325 fputs (reg_names[REGNO (base)], file);
1329 ** ++rk quirky method to scale offset for ld/str.......
1331 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1332 offset/current_frame_info.stld_sz);
1336 switch (GET_CODE (index))
1339 fprintf (file, ",%s", reg_names[REGNO (index)]);
1342 fputc (',', file), output_addr_const (file, index);
1349 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1350 /* We shouldn't get here as we've lost the mode of the memory object
1351 (which says how much to inc/dec by. */
1355 output_addr_const (file, addr);
1361 epiphany_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED,
1362 rtx *opvec ATTRIBUTE_UNUSED,
1363 int noperands ATTRIBUTE_UNUSED)
1365 int i = epiphany_n_nops;
1366 rtx pat ATTRIBUTE_UNUSED;
1369 fputs ("\tnop\n", asm_out_file);
1373 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1376 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1378 HOST_WIDE_INT size = int_size_in_bytes (type);
1380 if (AGGREGATE_TYPE_P (type)
1381 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1383 return (size == -1 || size > 8);
1386 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1387 passed by reference. */
1390 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1391 enum machine_mode mode, const_tree type,
1392 bool named ATTRIBUTE_UNUSED)
1396 if (AGGREGATE_TYPE_P (type)
1397 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1405 epiphany_function_value (const_tree ret_type,
1406 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1407 bool outgoing ATTRIBUTE_UNUSED)
1409 enum machine_mode mode;
1411 mode = TYPE_MODE (ret_type);
1412 /* We must change the mode like PROMOTE_MODE does.
1413 ??? PROMOTE_MODE is ignored for non-scalar types.
1414 The set of types tested here has to be kept in sync
1415 with the one in explow.c:promote_mode. */
1416 if (GET_MODE_CLASS (mode) == MODE_INT
1417 && GET_MODE_SIZE (mode) < 4
1418 && (TREE_CODE (ret_type) == INTEGER_TYPE
1419 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1420 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1421 || TREE_CODE (ret_type) == OFFSET_TYPE))
1423 return gen_rtx_REG (mode, 0);
1427 epiphany_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1429 return gen_rtx_REG (mode, 0);
1433 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1438 /* Fix up invalid option settings. */
1440 epiphany_override_options (void)
1442 if (epiphany_stack_offset < 4)
1443 error ("stack_offset must be at least 4");
1444 if (epiphany_stack_offset & 3)
1445 error ("stack_offset must be a multiple of 4");
1446 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1448 /* This needs to be done at start up. It's convenient to do it here. */
1452 /* For a DImode load / store SET, make a SImode set for a
1453 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1456 frame_subreg_note (rtx set, int offset)
1458 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1459 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1461 set = gen_rtx_SET (VOIDmode, dst ,src);
1462 RTX_FRAME_RELATED_P (set) = 1;
1470 rtx note = NULL_RTX;
1472 if (GET_CODE (x) == PARALLEL)
1474 rtx part = XVECEXP (x, 0, 0);
1476 if (GET_MODE (SET_DEST (part)) == DImode)
1478 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1479 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1480 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1481 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1483 part = copy_rtx (XVECEXP (x, 0, i));
1485 if (GET_CODE (part) == SET)
1486 RTX_FRAME_RELATED_P (part) = 1;
1487 XVECEXP (note, 0, i + 1) = part;
1492 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1494 part = XVECEXP (x, 0, i);
1496 if (GET_CODE (part) == SET)
1497 RTX_FRAME_RELATED_P (part) = 1;
1501 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1502 note = gen_rtx_PARALLEL (VOIDmode,
1503 gen_rtvec (2, frame_subreg_note (x, 0),
1504 frame_subreg_note (x, UNITS_PER_WORD)));
1506 RTX_FRAME_RELATED_P (x) = 1;
1508 add_reg_note (x, REG_FRAME_RELATED_EXPR, note);
1513 frame_move_insn (rtx to, rtx from)
1515 return frame_insn (gen_rtx_SET (VOIDmode, to, from));
1518 /* Generate a MEM referring to a varargs argument slot. */
1521 gen_varargs_mem (enum machine_mode mode, rtx addr)
1523 rtx mem = gen_rtx_MEM (mode, addr);
1524 MEM_NOTRAP_P (mem) = 1;
1525 set_mem_alias_set (mem, get_varargs_alias_set ());
1529 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1530 If EPILOGUE_P is 0, save; if it is one, restore.
1531 ADDR is the stack slot to save the first register to; subsequent
1532 registers are written to lower addresses.
1533 However, the order of register pairs can be reversed in order to
1534 use double-word load-store instructions. Likewise, an unpaired single
1535 word save slot can be skipped while double saves are carried out, and
1536 reused when a single register is to be saved. */
1539 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1543 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1544 rtx skipped_mem = NULL_RTX;
1545 int last_saved = limit - 1;
1548 while (last_saved >= 0
1549 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1551 for (i = 0; i < limit; i++)
1553 enum machine_mode mode = word_mode;
1556 rtx (*gen_mem) (enum machine_mode, rtx) = gen_frame_mem;
1558 /* Make sure we push the arguments in the right order. */
1559 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1561 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1562 gen_mem = gen_varargs_mem;
1564 if (stack_offset == current_frame_info.first_slot_size
1565 && current_frame_info.first_slot >= 0)
1567 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1570 addr = plus_constant (Pmode, addr,
1571 - (HOST_WIDE_INT) UNITS_PER_WORD);
1573 if (i-- < min || !epilogue_p)
1575 n = current_frame_info.first_slot;
1576 gen_mem = gen_frame_mem;
1578 else if (n == UNKNOWN_REGNUM
1579 && stack_offset > current_frame_info.first_slot_size)
1584 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1589 /* Check for a register pair to save. */
1591 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1592 && (n & 1) == 0 && n+1 < limit
1593 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1595 /* If it fits in the current stack slot pair, place it there. */
1596 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1597 && stack_offset != 2 * UNITS_PER_WORD
1598 && (current_frame_info.last_slot < 0
1599 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1600 && (n+1 != last_saved || !skipped_mem))
1604 addr = plus_constant (Pmode, addr,
1605 - (HOST_WIDE_INT) UNITS_PER_WORD);
1607 /* If it fits in the following stack slot pair, that's fine, too. */
1608 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1609 && stack_offset != 2 * UNITS_PER_WORD
1610 && stack_offset != 3 * UNITS_PER_WORD
1611 && (current_frame_info.last_slot < 0
1612 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1613 && n + 1 != last_saved)
1615 gcc_assert (!skipped_mem);
1616 stack_offset -= GET_MODE_SIZE (mode);
1617 skipped_mem = gen_mem (mode, addr);
1620 addr = plus_constant (Pmode, addr,
1621 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1624 reg = gen_rtx_REG (mode, n);
1625 if (mode != DImode && skipped_mem)
1628 mem = gen_mem (mode, addr);
1630 frame_move_insn (mem, reg);
1631 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1632 emit_move_insn (reg, mem);
1633 if (mem == skipped_mem)
1635 skipped_mem = NULL_RTX;
1639 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
1640 stack_offset -= GET_MODE_SIZE (mode);
1645 epiphany_expand_prologue (void)
1648 enum epiphany_function_type fn_type;
1649 rtx addr, mem, off, reg;
1652 if (!current_frame_info.initialized)
1653 epiphany_compute_frame_size (get_frame_size ());
1655 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1656 if (flag_stack_usage_info)
1657 current_function_static_stack_size = current_frame_info.total_size;
1659 fn_type = epiphany_compute_function_type (current_function_decl);
1660 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1664 addr = plus_constant (Pmode, stack_pointer_rtx,
1665 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1666 if (!lookup_attribute ("forwarder_section",
1667 DECL_ATTRIBUTES (current_function_decl))
1668 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1670 frame_move_insn (gen_frame_mem (DImode, addr),
1671 gen_rtx_REG (DImode, GPR_0));
1672 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1673 gen_rtx_REG (word_mode, STATUS_REGNUM));
1674 frame_move_insn (gen_rtx_REG (SImode, GPR_0+1),
1675 gen_rtx_REG (word_mode, IRET_REGNUM));
1676 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1677 off = GEN_INT (-current_frame_info.first_slot_offset);
1678 frame_insn (gen_stack_adjust_add (off, mem));
1679 if (!epiphany_uninterruptible_p (current_function_decl))
1680 emit_insn (gen_gie ());
1681 addr = plus_constant (Pmode, stack_pointer_rtx,
1682 current_frame_info.first_slot_offset
1683 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1687 addr = plus_constant (Pmode, stack_pointer_rtx,
1688 epiphany_stack_offset
1689 - (HOST_WIDE_INT) UNITS_PER_WORD);
1690 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1692 /* Allocate register save area; for small to medium size frames,
1693 allocate the entire frame; this is joint with one register save. */
1694 if (current_frame_info.first_slot >= 0)
1696 enum machine_mode mode
1697 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1698 ? word_mode : DImode);
1700 off = GEN_INT (-current_frame_info.first_slot_offset);
1701 mem = gen_frame_mem (BLKmode,
1702 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1703 frame_insn (gen_stack_adjust_str
1704 (gen_frame_mem (mode, stack_pointer_rtx),
1705 gen_rtx_REG (mode, current_frame_info.first_slot),
1707 addr = plus_constant (Pmode, addr,
1708 current_frame_info.first_slot_offset);
1711 epiphany_emit_save_restore (current_frame_info.small_threshold,
1712 FIRST_PSEUDO_REGISTER, addr, 0);
1713 if (current_frame_info.need_fp)
1714 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1715 /* For large frames, allocate bulk of frame. This is usually joint with one
1717 if (current_frame_info.last_slot >= 0)
1719 rtx ip, mem2, insn, note;
1721 gcc_assert (current_frame_info.last_slot != GPR_FP
1722 || (!current_frame_info.need_fp
1723 && current_frame_info.first_slot < 0));
1724 off = GEN_INT (-current_frame_info.last_slot_offset);
1725 mem = gen_frame_mem (BLKmode,
1726 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1727 ip = gen_rtx_REG (Pmode, GPR_IP);
1728 frame_move_insn (ip, off);
1729 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1730 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1731 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1732 /* Instruction scheduling can separate the instruction setting IP from
1733 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1734 temporary register is. Example: _gcov.o */
1735 note = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1736 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1737 note = gen_rtx_PARALLEL (VOIDmode,
1738 gen_rtvec (2, gen_rtx_SET (VOIDmode, mem2, reg),
1740 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1742 /* If there is only one or no register to save, yet we have a large frame,
1744 else if (current_frame_info.last_slot_offset)
1746 mem = gen_frame_mem (BLKmode,
1747 plus_constant (Pmode, stack_pointer_rtx,
1748 current_frame_info.last_slot_offset));
1749 off = GEN_INT (-current_frame_info.last_slot_offset);
1750 if (!SIMM11 (INTVAL (off)))
1752 reg = gen_rtx_REG (Pmode, GPR_IP);
1753 frame_move_insn (reg, off);
1756 frame_insn (gen_stack_adjust_add (off, mem));
1761 epiphany_expand_epilogue (int sibcall_p)
1764 enum epiphany_function_type fn_type;
1765 rtx mem, addr, reg, off;
1766 HOST_WIDE_INT restore_offset;
1768 fn_type = epiphany_compute_function_type( current_function_decl);
1769 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1771 /* For variable frames, deallocate bulk of frame. */
1772 if (current_frame_info.need_fp)
1774 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1775 emit_insn (gen_stack_adjust_mov (mem));
1777 /* Else for large static frames, deallocate bulk of frame. */
1778 else if (current_frame_info.last_slot_offset)
1780 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1781 reg = gen_rtx_REG (Pmode, GPR_IP);
1782 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1783 emit_insn (gen_stack_adjust_add (reg, mem));
1785 restore_offset = (interrupt_p
1786 ? - 3 * UNITS_PER_WORD
1787 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1788 addr = plus_constant (Pmode, stack_pointer_rtx,
1789 (current_frame_info.first_slot_offset
1791 epiphany_emit_save_restore (current_frame_info.small_threshold,
1792 FIRST_PSEUDO_REGISTER, addr, 1);
1794 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1795 emit_insn (gen_gid ());
1797 off = GEN_INT (current_frame_info.first_slot_offset);
1798 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1799 /* For large / variable size frames, deallocating the register save area is
1800 joint with one register restore; for medium size frames, we use a
1801 dummy post-increment load to dealloacte the whole frame. */
1802 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1804 emit_insn (gen_stack_adjust_ldr
1805 (gen_rtx_REG (word_mode,
1806 (current_frame_info.last_slot >= 0
1807 ? current_frame_info.last_slot : GPR_IP)),
1808 gen_frame_mem (word_mode, stack_pointer_rtx),
1812 /* While for small frames, we deallocate the entire frame with one add. */
1813 else if (INTVAL (off))
1815 emit_insn (gen_stack_adjust_add (off, mem));
1819 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1820 gen_rtx_REG (SImode, GPR_0));
1821 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1822 gen_rtx_REG (SImode, GPR_0+1));
1823 addr = plus_constant (Pmode, stack_pointer_rtx,
1824 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1825 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1826 gen_frame_mem (DImode, addr));
1828 addr = plus_constant (Pmode, stack_pointer_rtx,
1829 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1830 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1834 emit_jump_insn (gen_return_internal_interrupt());
1836 emit_jump_insn (gen_return_i ());
1841 epiphany_initial_elimination_offset (int from, int to)
1843 epiphany_compute_frame_size (get_frame_size ());
1844 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1845 return current_frame_info.total_size - current_frame_info.reg_size;
1846 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1847 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1848 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1849 return (current_frame_info.total_size
1850 - ((current_frame_info.pretend_size + 4) & -8));
1851 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1852 return (current_frame_info.first_slot_offset
1853 - ((current_frame_info.pretend_size + 4) & -8));
1858 epiphany_regno_rename_ok (unsigned, unsigned dst)
1860 enum epiphany_function_type fn_type;
1862 fn_type = epiphany_compute_function_type (current_function_decl);
1863 if (!EPIPHANY_INTERRUPT_P (fn_type))
1865 if (df_regs_ever_live_p (dst))
1871 epiphany_issue_rate (void)
1876 /* Function to update the integer COST
1877 based on the relationship between INSN that is dependent on
1878 DEP_INSN through the dependence LINK. The default is to make no
1879 adjustment to COST. This can be used for example to specify to
1880 the scheduler that an output- or anti-dependence does not incur
1881 the same cost as a data-dependence. The return value should be
1882 the new value for COST. */
1884 epiphany_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1886 if (REG_NOTE_KIND (link) == 0)
1890 if (recog_memoized (insn) < 0
1891 || recog_memoized (dep_insn) < 0)
1894 dep_set = single_set (dep_insn);
1896 /* The latency that we specify in the scheduling description refers
1897 to the actual output, not to an auto-increment register; for that,
1898 the latency is one. */
1899 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
1901 rtx set = single_set (insn);
1904 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
1905 && (!MEM_P (SET_DEST (set))
1906 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
1907 XEXP (SET_DEST (set), 0))))
1914 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
1916 #define RTX_OK_FOR_BASE_P(X) \
1917 (REG_P (X) && REG_OK_FOR_BASE_P (X))
1919 #define RTX_OK_FOR_INDEX_P(MODE, X) \
1920 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
1921 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
1922 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
1924 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
1925 (GET_CODE (X) == PLUS \
1926 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
1927 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
1928 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
1931 epiphany_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
1933 #define REG_OK_FOR_BASE_P(X) \
1934 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
1935 if (RTX_OK_FOR_BASE_P (x))
1937 if (RTX_FRAME_OFFSET_P (x))
1939 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
1941 /* If this is a misaligned stack access, don't force it to reg+index. */
1942 if (GET_MODE_SIZE (mode) == 8
1943 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
1944 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
1945 && !(INTVAL (XEXP (x, 1)) & 3)
1946 && INTVAL (XEXP (x, 1)) >= -2047 * 4
1947 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
1950 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
1951 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
1953 if ((TARGET_POST_MODIFY || reload_completed)
1954 && GET_CODE (x) == POST_MODIFY
1955 && GET_CODE (XEXP ((x), 1)) == PLUS
1956 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
1957 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
1959 if (mode == BLKmode)
1965 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
1966 enum machine_mode mode ATTRIBUTE_UNUSED,
1967 secondary_reload_info *sri)
1969 /* This could give more reload inheritance, but we are missing some
1970 reload infrastructure. */
1972 if (in_p && GET_CODE (x) == UNSPEC
1973 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
1975 gcc_assert (rclass == GENERAL_REGS);
1976 sri->icode = CODE_FOR_reload_insi_ra;
1983 epiphany_is_long_call_p (rtx x)
1985 tree decl = SYMBOL_REF_DECL (x);
1986 bool ret_val = !TARGET_SHORT_CALLS;
1989 /* ??? Is it safe to default to ret_val if decl is NULL? We should
1990 probably encode information via encode_section_info, and also
1991 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
1995 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1996 if (lookup_attribute ("long_call", attrs))
1998 else if (lookup_attribute ("short_call", attrs))
2005 epiphany_small16 (rtx x)
2008 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2010 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2012 base = XEXP (XEXP (x, 0), 0);
2013 offs = XEXP (XEXP (x, 0), 1);
2015 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2016 && epiphany_is_long_call_p (base))
2018 return TARGET_SMALL16 != 0;
2021 /* Return nonzero if it is ok to make a tail-call to DECL. */
2023 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2025 bool cfun_interrupt_p, call_interrupt_p;
2027 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2028 (current_function_decl));
2030 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2033 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2035 gcc_assert (POINTER_TYPE_P (fn_type));
2036 fn_type = TREE_TYPE (fn_type);
2037 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2038 || TREE_CODE (fn_type) == METHOD_TYPE);
2040 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2043 /* Don't tailcall from or to an ISR routine - although we could in
2044 principle tailcall from one ISR routine to another, we'd need to
2045 handle this in sibcall_epilogue to make it work. */
2046 if (cfun_interrupt_p || call_interrupt_p)
2049 /* Everything else is ok. */
2053 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2055 Return true iff the type of T has the uninterruptible attribute.
2056 If T is NULL, return false. */
2058 epiphany_uninterruptible_p (tree t)
2064 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2065 if (lookup_attribute ("disinterrupt", attrs))
2072 epiphany_call_uninterruptible_p (rtx mem)
2074 rtx addr = XEXP (mem, 0);
2077 if (GET_CODE (addr) == SYMBOL_REF)
2078 t = SYMBOL_REF_DECL (addr);
2081 return epiphany_uninterruptible_p (t);
2084 static enum machine_mode
2085 epiphany_promote_function_mode (const_tree type, enum machine_mode mode,
2086 int *punsignedp ATTRIBUTE_UNUSED,
2087 const_tree funtype ATTRIBUTE_UNUSED,
2088 int for_return ATTRIBUTE_UNUSED)
2092 return promote_mode (type, mode, &dummy);
2096 epiphany_conditional_register_usage (void)
2100 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2102 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2103 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2105 if (TARGET_HALF_REG_FILE)
2107 for (i = 32; i <= 63; i++)
2110 call_used_regs[i] = 1;
2113 if (epiphany_m1reg >= 0)
2115 fixed_regs[epiphany_m1reg] = 1;
2116 call_used_regs[epiphany_m1reg] = 1;
2118 if (!TARGET_PREFER_SHORT_INSN_REGS)
2119 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2120 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2121 reg_class_contents[GENERAL_REGS]);
2122 /* It would be simpler and quicker if we could just use
2123 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2124 it is set up later by our caller. */
2125 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2126 if (!call_used_regs[i])
2127 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2130 /* Determine where to put an argument to a function.
2131 Value is zero to push the argument on the stack,
2132 or a hard register in which to store the argument.
2134 MODE is the argument's machine mode.
2135 TYPE is the data type of the argument (as a tree).
2136 This is null for libcalls where that information may
2138 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2139 the preceding args and about the function being called.
2140 NAMED is nonzero if this argument is a named parameter
2141 (otherwise it is an extra parameter matching an ellipsis). */
2142 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2143 registers and the rest are pushed. */
2145 epiphany_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
2146 const_tree type, bool named ATTRIBUTE_UNUSED)
2148 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2150 if (PASS_IN_REG_P (cum, mode, type))
2151 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2155 /* Update the data in CUM to advance over an argument
2156 of mode MODE and data type TYPE.
2157 (TYPE is null for libcalls where that information may not be available.) */
2159 epiphany_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
2160 const_tree type, bool named ATTRIBUTE_UNUSED)
2162 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2164 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2167 /* Nested function support.
2168 An epiphany trampoline looks like this:
2169 mov r16,%low(fnaddr)
2170 movt r16,%high(fnaddr)
2175 #define EPIPHANY_LOW_RTX(X) \
2176 (gen_rtx_IOR (SImode, \
2177 gen_rtx_ASHIFT (SImode, \
2178 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2179 gen_rtx_ASHIFT (SImode, \
2180 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2181 #define EPIPHANY_HIGH_RTX(X) \
2182 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2184 /* Emit RTL insns to initialize the variable parts of a trampoline.
2185 FNADDR is an RTX for the address of the function's pure code.
2186 CXT is an RTX for the static chain value for the function. */
2188 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2190 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2191 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2193 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2194 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2195 EPIPHANY_LOW_RTX (fnaddr)));
2196 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2197 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2198 EPIPHANY_HIGH_RTX (fnaddr)));
2199 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2200 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2201 EPIPHANY_LOW_RTX (cxt)));
2202 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2203 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2204 EPIPHANY_HIGH_RTX (cxt)));
2205 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2206 GEN_INT (0x0802014f));
2210 epiphany_optimize_mode_switching (int entity)
2212 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2216 case EPIPHANY_MSW_ENTITY_AND:
2217 case EPIPHANY_MSW_ENTITY_OR:
2218 case EPIPHANY_MSW_ENTITY_CONFIG:
2220 case EPIPHANY_MSW_ENTITY_NEAREST:
2221 case EPIPHANY_MSW_ENTITY_TRUNC:
2222 return optimize > 0;
2223 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2224 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2225 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2226 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2227 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2228 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2229 return optimize == 0 || current_pass == &pass_mode_switch_use.pass;
2235 epiphany_mode_priority_to_mode (int entity, unsigned priority)
2237 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2238 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2243 case 4: return FP_MODE_ROUND_UNKNOWN;
2244 case 5: return FP_MODE_NONE;
2245 default: gcc_unreachable ();
2247 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2252 case 0: return FP_MODE_INT;
2253 case 1: return epiphany_normal_fp_rounding;
2254 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2255 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2256 case 3: return FP_MODE_CALLER;
2258 case FP_MODE_ROUND_NEAREST:
2259 case FP_MODE_CALLER:
2262 case 0: return FP_MODE_ROUND_NEAREST;
2263 case 1: return FP_MODE_ROUND_TRUNC;
2264 case 2: return FP_MODE_INT;
2265 case 3: return FP_MODE_CALLER;
2267 case FP_MODE_ROUND_TRUNC:
2270 case 0: return FP_MODE_ROUND_TRUNC;
2271 case 1: return FP_MODE_ROUND_NEAREST;
2272 case 2: return FP_MODE_INT;
2273 case 3: return FP_MODE_CALLER;
2275 case FP_MODE_ROUND_UNKNOWN:
2283 epiphany_mode_needed (int entity, rtx insn)
2285 enum attr_fp_mode mode;
2287 if (recog_memoized (insn) < 0)
2289 if (entity == EPIPHANY_MSW_ENTITY_AND
2290 || entity == EPIPHANY_MSW_ENTITY_OR
2291 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2293 return FP_MODE_NONE;
2295 mode = get_attr_fp_mode (insn);
2299 case EPIPHANY_MSW_ENTITY_AND:
2300 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
2301 case EPIPHANY_MSW_ENTITY_OR:
2302 return mode == FP_MODE_INT ? 1 : 2;
2303 case EPIPHANY_MSW_ENTITY_CONFIG:
2304 /* We must know/save config before we set it to something else.
2305 Where we need the original value, we are fine with having it
2306 just unchanged from the function start.
2307 Because of the nature of the mode switching optimization,
2308 a restore will be dominated by a clobber. */
2309 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2311 /* A cpecial case are abnormal edges, which are deemed to clobber
2312 the mode as well. We need to pin this effect on a actually
2313 dominating insn, and one where the frame can be accessed, too, in
2314 case the pseudo used to save CONFIG doesn't get a hard register. */
2315 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2318 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2319 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2320 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2322 case EPIPHANY_MSW_ENTITY_NEAREST:
2323 case EPIPHANY_MSW_ENTITY_TRUNC:
2324 if (mode == FP_MODE_ROUND_UNKNOWN)
2326 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2327 return FP_MODE_NONE;
2330 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2331 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2332 return FP_MODE_ROUND_UNKNOWN;
2334 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2335 if (mode == FP_MODE_ROUND_UNKNOWN)
2336 return epiphany_normal_fp_rounding;
2344 epiphany_mode_entry_exit (int entity, bool exit)
2346 int normal_mode = epiphany_normal_fp_mode ;
2348 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2349 if (epiphany_is_interrupt_p (current_function_decl))
2350 normal_mode = FP_MODE_CALLER;
2353 case EPIPHANY_MSW_ENTITY_AND:
2355 return normal_mode != FP_MODE_INT ? 1 : 2;
2357 case EPIPHANY_MSW_ENTITY_OR:
2359 return normal_mode == FP_MODE_INT ? 1 : 2;
2361 case EPIPHANY_MSW_ENTITY_CONFIG:
2364 return normal_mode == FP_MODE_CALLER ? 0 : 1;
2365 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2366 if (normal_mode == FP_MODE_ROUND_NEAREST
2367 || normal_mode == FP_MODE_ROUND_TRUNC)
2368 return FP_MODE_ROUND_UNKNOWN;
2370 case EPIPHANY_MSW_ENTITY_NEAREST:
2371 case EPIPHANY_MSW_ENTITY_TRUNC:
2372 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2373 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2381 epiphany_mode_after (int entity, int last_mode, rtx insn)
2383 /* We have too few call-saved registers to hope to keep the masks across
2385 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2387 if (GET_CODE (insn) == CALL_INSN)
2391 /* If there is an abnormal edge, we don't want the config register to
2392 be 'saved' again at the destination.
2393 The frame pointer adjustment is inside a PARALLEL because of the
2395 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2396 && GET_CODE (PATTERN (insn)) == PARALLEL
2397 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2398 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2400 gcc_assert (cfun->has_nonlocal_label);
2403 if (recog_memoized (insn) < 0)
2405 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2406 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2408 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2409 return FP_MODE_ROUND_NEAREST;
2410 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2411 return FP_MODE_ROUND_TRUNC;
2413 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2415 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2419 return FP_MODE_CALLER;
2420 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2421 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2422 && (fp_mode == FP_MODE_ROUND_NEAREST
2423 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2424 return FP_MODE_ROUND_UNKNOWN;
2431 emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2433 rtx save_cc, cc_reg, mask, src, src2;
2434 enum attr_fp_mode fp_mode;
2436 if (!MACHINE_FUNCTION (cfun)->and_mask)
2438 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2439 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2441 if (entity == EPIPHANY_MSW_ENTITY_AND)
2443 gcc_assert (mode >= 0 && mode <= 2);
2445 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2446 gen_int_mode (0xfff1fffe, SImode));
2449 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2451 gcc_assert (mode >= 0 && mode <= 2);
2453 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2456 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2458 /* Mode switching optimization is done after emit_initial_value_sets,
2459 so we have to take care of CONFIG_REGNUM here. */
2460 gcc_assert (mode >= 0 && mode <= 2);
2461 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2463 emit_insn (gen_save_config (save));
2466 fp_mode = (enum attr_fp_mode) mode;
2471 case FP_MODE_CALLER:
2472 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2473 so that the config save gets inserted before the first use. */
2474 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2475 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2476 mask = MACHINE_FUNCTION (cfun)->and_mask;
2478 case FP_MODE_ROUND_UNKNOWN:
2479 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2480 mask = MACHINE_FUNCTION (cfun)->and_mask;
2482 case FP_MODE_ROUND_NEAREST:
2483 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2485 mask = MACHINE_FUNCTION (cfun)->and_mask;
2487 case FP_MODE_ROUND_TRUNC:
2488 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2490 mask = MACHINE_FUNCTION (cfun)->and_mask;
2493 mask = MACHINE_FUNCTION (cfun)->or_mask;
2499 save_cc = gen_reg_rtx (CCmode);
2500 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2501 emit_move_insn (save_cc, cc_reg);
2502 mask = force_reg (SImode, mask);
2505 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2507 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2509 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2510 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2511 src2 = copy_rtx (src);
2514 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2516 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2518 emit_insn (gen_set_fp_mode (src, src2, mask));
2519 emit_move_insn (cc_reg, save_cc);
2523 epiphany_expand_set_fp_mode (rtx *operands)
2525 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2526 rtx src = operands[0];
2527 rtx mask_reg = operands[2];
2528 rtx scratch = operands[3];
2529 enum attr_fp_mode fp_mode;
2532 gcc_assert (rtx_equal_p (src, operands[1])
2533 /* Sometimes reload gets silly and reloads the same pseudo
2534 into different registers. */
2535 || (REG_P (src) && REG_P (operands[1])));
2537 if (!epiphany_uninterruptible_p (current_function_decl))
2538 emit_insn (gen_gid ());
2539 emit_move_insn (scratch, ctrl);
2541 if (GET_CODE (src) == REG)
2543 /* FP_MODE_CALLER */
2544 emit_insn (gen_xorsi3 (scratch, scratch, src));
2545 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2546 emit_insn (gen_xorsi3 (scratch, scratch, src));
2550 gcc_assert (GET_CODE (src) == CONST);
2551 src = XEXP (src, 0);
2552 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2555 case FP_MODE_ROUND_NEAREST:
2556 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2558 case FP_MODE_ROUND_TRUNC:
2559 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2560 emit_insn (gen_add2_insn (scratch, const1_rtx));
2563 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2565 case FP_MODE_CALLER:
2566 case FP_MODE_ROUND_UNKNOWN:
2571 emit_move_insn (ctrl, scratch);
2572 if (!epiphany_uninterruptible_p (current_function_decl))
2573 emit_insn (gen_gie ());
2577 epiphany_insert_mode_switch_use (rtx insn,
2578 int entity ATTRIBUTE_UNUSED,
2579 int mode ATTRIBUTE_UNUSED)
2581 rtx pat = PATTERN (insn);
2584 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2585 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2587 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2589 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2591 case FP_MODE_ROUND_NEAREST:
2592 near = gen_rtx_USE (VOIDmode, near);
2593 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2595 case FP_MODE_ROUND_TRUNC:
2596 near = gen_rtx_CLOBBER (VOIDmode, near);
2597 trunc = gen_rtx_USE (VOIDmode, trunc);
2599 case FP_MODE_ROUND_UNKNOWN:
2600 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2601 trunc = copy_rtx (near);
2604 case FP_MODE_CALLER:
2605 near = gen_rtx_USE (VOIDmode, near);
2606 trunc = gen_rtx_USE (VOIDmode, trunc);
2611 gcc_assert (GET_CODE (pat) == PARALLEL);
2612 len = XVECLEN (pat, 0);
2613 v = rtvec_alloc (len + 2);
2614 for (i = 0; i < len; i++)
2615 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2616 RTVEC_ELT (v, len) = near;
2617 RTVEC_ELT (v, len + 1) = trunc;
2618 pat = gen_rtx_PARALLEL (VOIDmode, v);
2619 PATTERN (insn) = pat;
2620 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2624 epiphany_epilogue_uses (int regno)
2626 if (regno == GPR_LR)
2628 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2630 if (fixed_regs[regno]
2631 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2632 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2636 if (regno == FP_NEAREST_REGNUM
2637 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2639 if (regno == FP_TRUNCATE_REGNUM
2640 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2646 epiphany_min_divisions_for_recip_mul (enum machine_mode mode)
2648 if (flag_reciprocal_math && mode == SFmode)
2649 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2650 it already at the tree level and expose it to further optimizations. */
2652 return default_min_divisions_for_recip_mul (mode);
2655 static enum machine_mode
2656 epiphany_preferred_simd_mode (enum machine_mode mode ATTRIBUTE_UNUSED)
2658 return TARGET_VECT_DOUBLE ? DImode : SImode;
2662 epiphany_vector_mode_supported_p (enum machine_mode mode)
2664 if (mode == V2SFmode)
2666 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2667 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2673 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2675 /* Vectors which aren't in packed structures will not be less aligned than
2676 the natural alignment of their element type, so this is safe. */
2677 if (TYPE_ALIGN_UNIT (type) == 4)
2680 return default_builtin_vector_alignment_reachable (type, is_packed);
2684 epiphany_support_vector_misalignment (enum machine_mode mode, const_tree type,
2685 int misalignment, bool is_packed)
2687 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2689 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2693 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2694 structs. Make structs double-word-aligned it they are a double word or
2695 (potentially) larger; failing that, do the same for a size of 32 bits. */
2697 epiphany_special_round_type_align (tree type, unsigned computed,
2700 unsigned align = MAX (computed, specified);
2702 HOST_WIDE_INT total, max;
2703 unsigned try_align = FASTEST_ALIGNMENT;
2705 if (maximum_field_alignment && try_align > maximum_field_alignment)
2706 try_align = maximum_field_alignment;
2707 if (align >= try_align)
2709 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2713 if (TREE_CODE (field) != FIELD_DECL
2714 || TREE_TYPE (field) == error_mark_node)
2716 offset = bit_position (field);
2717 size = DECL_SIZE (field);
2718 if (!host_integerp (offset, 1) || !host_integerp (size, 1)
2719 || TREE_INT_CST_LOW (offset) >= try_align
2720 || TREE_INT_CST_LOW (size) >= try_align)
2722 total = TREE_INT_CST_LOW (offset) + TREE_INT_CST_LOW (size);
2726 if (max >= (HOST_WIDE_INT) try_align)
2728 else if (try_align > 32 && max >= 32)
2729 align = max > 32 ? 64 : 32;
2733 /* Upping the alignment of arrays in structs is not only a performance
2734 enhancement, it also helps preserve assumptions about how
2735 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2738 epiphany_adjust_field_align (tree field, unsigned computed)
2741 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
2743 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field)));
2745 if (!host_integerp (elmsz, 1) || tree_low_cst (elmsz, 1) >= 32)
2751 /* Output code to add DELTA to the first argument, and then jump
2752 to FUNCTION. Used for C++ multiple inheritance. */
2754 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2755 HOST_WIDE_INT delta,
2756 HOST_WIDE_INT vcall_offset,
2760 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2761 const char *this_name = reg_names[this_regno];
2764 /* We use IP and R16 as a scratch registers. */
2765 gcc_assert (call_used_regs [GPR_IP]);
2766 gcc_assert (call_used_regs [GPR_16]);
2768 /* Add DELTA. When possible use a plain add, otherwise load it into
2769 a register first. */
2772 else if (SIMM11 (delta))
2773 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2774 else if (delta < 0 && delta >= -0xffff)
2776 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2777 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2781 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2782 if (delta & ~0xffff)
2783 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2784 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2787 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2788 if (vcall_offset != 0)
2790 /* ldr ip,[this] --> temp = *this
2791 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2792 add this,this,ip --> this+ = *(*this + vcall_offset) */
2793 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2794 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2795 || (vcall_offset & 3) != 0)
2797 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2798 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2799 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2802 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2803 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2806 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2807 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2809 fputs ("\tmov\tip,%low(", file);
2810 assemble_name (file, fname);
2811 fputs (")\n\tmovt\tip,%high(", file);
2812 assemble_name (file, fname);
2813 fputs (")\n\tjr ip\n", file);
2817 fputs ("\tb\t", file);
2818 assemble_name (file, fname);
2824 epiphany_start_function (FILE *file, const char *name, tree decl)
2826 /* If the function doesn't fit into the on-chip memory, it will have a
2827 section attribute - or lack of it - that denotes it goes somewhere else.
2828 But the architecture spec says that an interrupt vector still has to
2829 point to on-chip memory. So we must place a jump there to get to the
2830 actual function implementation. The forwarder_section attribute
2831 specifies the section where this jump goes.
2832 This mechanism can also be useful to have a shortcall destination for
2833 a function that is actually placed much farther away. */
2834 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2836 attrs = DECL_ATTRIBUTES (decl);
2837 int_attr = lookup_attribute ("interrupt", attrs);
2839 for (int_names = TREE_VALUE (int_attr); int_names;
2840 int_names = TREE_CHAIN (int_names))
2844 int_name = TREE_VALUE (int_names);
2845 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2846 switch_to_section (get_section (buf, SECTION_CODE, decl));
2847 fputs ("\tb\t", file);
2848 assemble_name (file, name);
2851 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2854 const char *prefix = "__forwarder_dst_";
2855 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2857 strcpy (dst_name, prefix);
2858 strcat (dst_name, name);
2859 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2860 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2861 SECTION_CODE, decl));
2862 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2863 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2868 fputs ("\tstrd r0,[sp,-1]\n", file);
2871 gcc_assert (call_used_regs[tmp]);
2872 fprintf (file, "\tmov r%d,%%low(", tmp);
2873 assemble_name (file, dst_name);
2874 fprintf (file, ")\n"
2875 "\tmovt r%d,%%high(", tmp);
2876 assemble_name (file, dst_name);
2877 fprintf (file, ")\n"
2882 fputs ("\tb\t", file);
2883 assemble_name (file, dst_name);
2888 switch_to_section (function_section (decl));
2889 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2892 struct gcc_target targetm = TARGET_INITIALIZER;