1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
4 Contributed by Embecosm on behalf of Adapteva, Inc.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
29 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "conditions.h"
34 #include "insn-attr.h"
38 #include "diagnostic-core.h"
44 #include "langhooks.h"
45 #include "insn-codes.h"
47 #include "tm-constrs.h"
48 #include "tree-pass.h"
49 #include "integrate.h"
51 /* Which cpu we're compiling for. */
52 int epiphany_cpu_type;
54 /* Name of mangle string to add to symbols to separate code compiled for each
56 const char *epiphany_mangle_cpu;
58 /* Array of valid operand punctuation characters. */
59 char epiphany_punct_chars[256];
61 /* The rounding mode that we generally use for floating point. */
62 int epiphany_normal_fp_rounding;
64 static void epiphany_init_reg_tables (void);
65 static int get_epiphany_condition_code (rtx);
66 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
67 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
69 static bool epiphany_pass_by_reference (cumulative_args_t, enum machine_mode,
71 static rtx frame_insn (rtx);
73 /* defines for the initialization of the GCC target structure. */
74 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
76 #define TARGET_PRINT_OPERAND epiphany_print_operand
77 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
79 #define TARGET_RTX_COSTS epiphany_rtx_costs
80 #define TARGET_ADDRESS_COST epiphany_address_cost
81 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
83 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
84 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
86 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
87 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
88 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
89 #define TARGET_FUNCTION_VALUE epiphany_function_value
90 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
91 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
93 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
95 /* Using the simplistic varags handling forces us to do partial reg/stack
96 argument passing for types with larger size (> 4 bytes) than alignemnt. */
97 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
99 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
101 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
102 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
104 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
106 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
108 #define TARGET_OPTION_OVERRIDE epiphany_override_options
110 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
112 #define TARGET_FUNCTION_ARG epiphany_function_arg
114 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
116 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
118 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
120 /* Nonzero if the constant rtx value is a legitimate general operand.
121 We can handle any 32- or 64-bit constant. */
122 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
124 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
125 epiphany_min_divisions_for_recip_mul
127 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
129 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
131 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
132 epiphany_vector_alignment_reachable
134 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
135 epiphany_support_vector_misalignment
137 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
138 hook_bool_const_tree_hwi_hwi_const_tree_true
139 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
141 #include "target-def.h"
143 #undef TARGET_ASM_ALIGNED_HI_OP
144 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
145 #undef TARGET_ASM_ALIGNED_SI_OP
146 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
149 epiphany_is_interrupt_p (tree decl)
153 attrs = DECL_ATTRIBUTES (decl);
154 if (lookup_attribute ("interrupt", attrs))
160 /* Called from epiphany_override_options.
161 We use this to initialize various things. */
166 /* N.B. this pass must not run before the first optimize_mode_switching
167 pass because of the side offect of epiphany_mode_needed on
168 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
169 pass_resolve_sw_modes. */
170 static struct register_pass_info insert_use_info
171 = { &pass_mode_switch_use.pass, "mode_sw",
172 1, PASS_POS_INSERT_AFTER
174 static struct register_pass_info mode_sw2_info
175 = { &pass_mode_switching.pass, "mode_sw",
176 1, PASS_POS_INSERT_AFTER
178 static struct register_pass_info mode_sw3_info
179 = { &pass_resolve_sw_modes.pass, "mode_sw",
180 1, PASS_POS_INSERT_AFTER
182 static struct register_pass_info mode_sw4_info
183 = { &pass_split_all_insns.pass, "mode_sw",
184 1, PASS_POS_INSERT_AFTER
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);
202 #if 1 /* As long as peep2_rescan is not implemented,
203 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
204 we need a second peephole2 pass to get reasonable code. */
206 static struct register_pass_info peep2_2_info
207 = { &pass_peephole2.pass, "peephole2",
208 1, PASS_POS_INSERT_AFTER
211 register_pass (&peep2_2_info);
216 /* The condition codes of the EPIPHANY, and the inverse function. */
217 static const char *const epiphany_condition_codes[] =
218 { /* 0 1 2 3 4 5 6 7 8 9 */
219 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
221 "beq","bne","blt", "blte",
224 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
226 /* Returns the index of the EPIPHANY condition code string in
227 `epiphany_condition_codes'. COMPARISON should be an rtx like
228 `(eq (...) (...))'. */
231 get_epiphany_condition_code (rtx comparison)
233 switch (GET_MODE (XEXP (comparison, 0)))
236 switch (GET_CODE (comparison))
249 default : gcc_unreachable ();
252 switch (GET_CODE (comparison))
256 default: gcc_unreachable ();
259 switch (GET_CODE (comparison))
263 default: gcc_unreachable ();
266 switch (GET_CODE (comparison))
270 default: gcc_unreachable ();
273 switch (GET_CODE (comparison))
279 default: gcc_unreachable ();
282 switch (GET_CODE (comparison))
286 default: gcc_unreachable ();
289 switch (GET_CODE (comparison))
295 case UNLE : return 5;
296 case UNLT : return 7;
297 default: gcc_unreachable ();
300 switch (GET_CODE (comparison))
302 case ORDERED: return 9;
303 case UNORDERED: return 8;
304 default: gcc_unreachable ();
307 switch (GET_CODE (comparison))
311 default: gcc_unreachable ();
313 default: gcc_unreachable ();
320 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
322 hard_regno_mode_ok (int regno, enum machine_mode mode)
324 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
325 return (regno & 1) == 0 && GPR_P (regno);
330 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
331 return the mode to be used for the comparison. */
334 epiphany_select_cc_mode (enum rtx_code op,
335 rtx x ATTRIBUTE_UNUSED,
336 rtx y ATTRIBUTE_UNUSED)
338 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
340 if (TARGET_SOFT_CMPSF)
342 if (op == EQ || op == NE)
344 if (op == ORDERED || op == UNORDERED)
345 return CC_FP_ORDmode;
346 if (op == UNEQ || op == LTGT)
347 return CC_FP_UNEQmode;
348 return CC_FP_GTEmode;
352 /* recognize combiner pattern ashlsi_btst:
354 (set (reg:N_NE 65 cc1)
355 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
358 (const_int 0 [0x0])))
359 (clobber (scratch:SI)) */
360 else if ((op == EQ || op == NE)
361 && GET_CODE (x) == ZERO_EXTRACT
362 && XEXP (x, 1) == const1_rtx
363 && CONST_INT_P (XEXP (x, 2)))
365 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
367 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
373 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
376 epiphany_init_reg_tables (void)
380 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
383 epiphany_regno_reg_class[i] = LR_REGS;
384 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
385 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
386 else if (call_used_regs[i]
387 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
388 epiphany_regno_reg_class[i] = SIBCALL_REGS;
389 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
390 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
391 else if (i < (GPR_LAST+1)
392 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
393 epiphany_regno_reg_class[i] = GENERAL_REGS;
394 else if (i == CC_REGNUM)
395 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
397 epiphany_regno_reg_class[i] = NO_REGS;
401 /* EPIPHANY specific attribute support.
403 The EPIPHANY has these attributes:
404 interrupt - for interrupt functions.
405 short_call - the function is assumed to be reachable with the b / bl
407 long_call - the function address is loaded into a register before use.
408 disinterrupt - functions which mask interrupts throughout.
409 They unmask them while calling an interruptible
412 static const struct attribute_spec epiphany_attribute_table[] =
414 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
415 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
416 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
417 { "long_call", 0, 0, false, true, true, NULL, false },
418 { "short_call", 0, 0, false, true, true, NULL, false },
419 { "disinterrupt", 0, 0, false, true, true, NULL, true },
420 { NULL, 0, 0, false, false, false, NULL, false }
423 /* Handle an "interrupt" attribute; arguments as in
424 struct attribute_spec.handler. */
426 epiphany_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
427 tree name, tree args,
428 int flags ATTRIBUTE_UNUSED,
436 value = TREE_VALUE (args);
438 if (TREE_CODE (value) != STRING_CST)
440 warning (OPT_Wattributes,
441 "argument of %qE attribute is not a string constant", name);
442 *no_add_attrs = true;
444 else if (strcmp (TREE_STRING_POINTER (value), "reset")
445 && strcmp (TREE_STRING_POINTER (value), "software_exception")
446 && strcmp (TREE_STRING_POINTER (value), "page_miss")
447 && strcmp (TREE_STRING_POINTER (value), "timer0")
448 && strcmp (TREE_STRING_POINTER (value), "timer1")
449 && strcmp (TREE_STRING_POINTER (value), "message")
450 && strcmp (TREE_STRING_POINTER (value), "dma0")
451 && strcmp (TREE_STRING_POINTER (value), "dma1")
452 && strcmp (TREE_STRING_POINTER (value), "wand")
453 && strcmp (TREE_STRING_POINTER (value), "swi"))
455 warning (OPT_Wattributes,
456 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
458 *no_add_attrs = true;
462 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
463 flags, no_add_attrs);
466 /* Handle a "forwarder_section" attribute; arguments as in
467 struct attribute_spec.handler. */
469 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
470 tree name, tree args,
471 int flags ATTRIBUTE_UNUSED,
476 value = TREE_VALUE (args);
478 if (TREE_CODE (value) != STRING_CST)
480 warning (OPT_Wattributes,
481 "argument of %qE attribute is not a string constant", name);
482 *no_add_attrs = true;
488 /* Misc. utilities. */
490 /* Generate a SYMBOL_REF for the special function NAME. When the address
491 can't be placed directly into a call instruction, and if possible, copy
492 it to a register so that cse / code hoisting is possible. */
494 sfunc_symbol (const char *name)
496 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
498 /* These sfuncs should be hidden, and every dso should get a copy. */
499 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
500 if (TARGET_SHORT_CALLS)
501 ; /* Nothing to be done. */
502 else if (can_create_pseudo_p ())
503 sym = copy_to_mode_reg (Pmode, sym);
504 else /* We rely on reload to fix this up. */
505 gcc_assert (!reload_in_progress || reload_completed);
509 /* X and Y are two things to compare using CODE in IN_MODE.
510 Emit the compare insn, construct the the proper cc reg in the proper
511 mode, and return the rtx for the cc reg comparison in CMODE. */
514 gen_compare_reg (enum machine_mode cmode, enum rtx_code code,
515 enum machine_mode in_mode, rtx x, rtx y)
517 enum machine_mode mode = SELECT_CC_MODE (code, x, y);
518 rtx cc_reg, pat, clob0, clob1, clob2;
520 if (in_mode == VOIDmode)
521 in_mode = GET_MODE (x);
522 if (in_mode == VOIDmode)
523 in_mode = GET_MODE (y);
525 if (mode == CC_FPmode)
527 /* The epiphany has only EQ / NE / LT / LE conditions for
528 hardware floating point. */
529 if (code == GT || code == GE || code == UNLE || code == UNLT)
531 rtx tmp = x; x = y; y = tmp;
532 code = swap_condition (code);
534 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
535 y = force_reg (in_mode, y);
539 if (mode == CC_FP_GTEmode
540 && (code == LE || code == LT || code == UNGT || code == UNGE))
542 rtx tmp = x; x = y; y = tmp;
543 code = swap_condition (code);
545 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
547 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
548 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
549 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
550 && (!REG_P (x) || REGNO (x) != 0 || !REG_P (y) || REGNO (y) != 1))
554 gcc_assert (currently_expanding_to_rtl);
555 reg = gen_rtx_REG (in_mode, 0);
556 gcc_assert (!reg_overlap_mentioned_p (reg, y));
557 emit_move_insn (reg, x);
559 reg = gen_rtx_REG (in_mode, 1);
560 emit_move_insn (reg, y);
564 x = force_reg (in_mode, x);
566 pat = gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y));
567 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
569 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
570 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
572 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
573 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
574 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
576 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
578 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
579 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
581 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
582 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
583 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
584 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
585 clob0, clob1, clob2));
589 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
590 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
593 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
596 /* The ROUND_ADVANCE* macros are local to this file. */
597 /* Round SIZE up to a word boundary. */
598 #define ROUND_ADVANCE(SIZE) \
599 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
601 /* Round arg MODE/TYPE up to the next word boundary. */
602 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
604 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
605 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
607 /* Round CUM up to the necessary point for argument MODE/TYPE. */
608 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
609 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
610 ? (((CUM) + 1) & ~1) \
614 epiphany_function_arg_boundary (enum machine_mode mode, const_tree type)
616 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
617 return PARM_BOUNDARY;
618 return 2 * PARM_BOUNDARY;
621 /* Do any needed setup for a variadic function. For the EPIPHANY, we
622 actually emit the code in epiphany_expand_prologue.
624 CUM has not been updated for the last named argument which has type TYPE
625 and mode MODE, and we rely on this fact. */
629 epiphany_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
630 tree type, int *pretend_size, int no_rtl)
633 CUMULATIVE_ARGS next_cum;
634 machine_function_t *mf = MACHINE_FUNCTION (cfun);
636 /* All BLKmode values are passed by reference. */
637 gcc_assert (mode != BLKmode);
639 next_cum = *get_cumulative_args (cum);
641 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
642 first_anon_arg = next_cum;
644 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
646 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
647 int first_reg_offset = first_anon_arg;
649 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
653 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
657 epiphany_arg_partial_bytes (cumulative_args_t cum, enum machine_mode mode,
658 tree type, bool named ATTRIBUTE_UNUSED)
660 int words = 0, rounded_cum;
662 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
664 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
665 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
667 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
668 if (words >= ROUND_ADVANCE_ARG (mode, type))
671 return words * UNITS_PER_WORD;
674 /* Cost functions. */
676 /* Compute a (partial) cost for rtx X. Return true if the complete
677 cost has been computed, and false if subexpressions should be
678 scanned. In either case, *TOTAL contains the cost result. */
681 epiphany_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
682 int *total, bool speed ATTRIBUTE_UNUSED)
686 /* Small integers in the right context are as cheap as registers. */
688 if ((outer_code == PLUS || outer_code == MINUS)
689 && SIMM11 (INTVAL (x)))
694 if (IMM16 (INTVAL (x)))
696 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
704 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
705 + (outer_code == SET ? 0 : 1));
711 split_double (x, &high, &low);
712 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
713 + !IMM16 (INTVAL (low)));
720 *total = COSTS_N_INSNS (1);
729 /* Provide the costs of an addressing mode that contains ADDR.
730 If ADDR is not a valid address, its cost is irrelevant. */
733 epiphany_address_cost (rtx addr, bool speed)
736 rtx off = const0_rtx;
741 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
743 switch (GET_CODE (addr))
746 reg = XEXP (addr, 0);
747 off = XEXP (addr, 1);
750 reg = XEXP (addr, 0);
751 off = XEXP (addr, 1);
752 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
754 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
762 if (!satisfies_constraint_Rgs (reg))
764 /* ??? We don't know the mode of the memory access. We are going to assume
765 SImode, unless lack of offset alignment indicates a smaller access. */
766 /* First, make sure we have a valid integer. */
767 if (!satisfies_constraint_L (off))
779 /* Compute the cost of moving data between registers and memory.
780 For integer, load latency is twice as long as register-register moves,
781 but issue pich is the same. For floating point, load latency is three
782 times as much as a reg-reg move. */
784 epiphany_memory_move_cost (enum machine_mode mode,
785 reg_class_t rclass ATTRIBUTE_UNUSED,
786 bool in ATTRIBUTE_UNUSED)
788 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
791 /* Function prologue/epilogue handlers. */
793 /* EPIPHANY stack frames look like:
795 Before call After call
796 +-----------------------+ +-----------------------+
798 high | local variables, | | local variables, |
799 mem | reg save area, etc. | | reg save area, etc. |
801 +-----------------------+ +-----------------------+
803 | arguments on stack. | | arguments on stack. |
805 SP+8->+-----------------------+FP+8m->+-----------------------+
806 | 2 word save area for | | reg parm save area, |
807 | leaf funcs / flags | | only created for |
808 SP+0->+-----------------------+ | variable argument |
810 FP+8n->+-----------------------+
812 | register save area |
814 +-----------------------+
818 FP+0->+-----------------------+
820 | alloca allocations |
822 +-----------------------+
824 | arguments on stack |
826 SP+8->+-----------------------+
827 low | 2 word save area for |
828 memory | leaf funcs / flags |
829 SP+0->+-----------------------+
832 1) The "reg parm save area" does not exist for non variable argument fns.
833 The "reg parm save area" could be eliminated if we created our
834 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
835 (so it's not done). */
837 /* Structure to be filled in by epiphany_compute_frame_size with register
838 save masks, and offsets for the current function. */
839 struct epiphany_frame_info
841 unsigned int total_size; /* # bytes that the entire frame takes up. */
842 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
843 unsigned int args_size; /* # bytes that outgoing arguments take up. */
844 unsigned int reg_size; /* # bytes needed to store regs. */
845 unsigned int var_size; /* # bytes that variables take up. */
846 HARD_REG_SET gmask; /* Set of saved gp registers. */
847 int initialized; /* Nonzero if frame size already calculated. */
848 int stld_sz; /* Current load/store data size for offset
850 int need_fp; /* value to override "frame_pointer_needed */
851 int first_slot, last_slot, first_slot_offset, last_slot_offset;
856 /* Current frame information calculated by epiphany_compute_frame_size. */
857 static struct epiphany_frame_info current_frame_info;
859 /* Zero structure to initialize current_frame_info. */
860 static struct epiphany_frame_info zero_frame_info;
862 /* The usual; we set up our machine_function data. */
863 static struct machine_function *
864 epiphany_init_machine_status (void)
866 struct machine_function *machine;
868 /* Reset state info for each function. */
869 current_frame_info = zero_frame_info;
871 machine = ggc_alloc_cleared_machine_function_t ();
876 /* Implements INIT_EXPANDERS. We just set up to call the above
879 epiphany_init_expanders (void)
881 init_machine_status = epiphany_init_machine_status;
884 /* Type of function DECL.
886 The result is cached. To reset the cache at the end of a function,
887 call with DECL = NULL_TREE. */
889 static enum epiphany_function_type
890 epiphany_compute_function_type (tree decl)
894 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
895 /* Last function we were called for. */
896 static tree last_fn = NULL_TREE;
898 /* Resetting the cached value? */
899 if (decl == NULL_TREE)
901 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
906 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
909 /* Assume we have a normal function (not an interrupt handler). */
910 fn_type = EPIPHANY_FUNCTION_NORMAL;
912 /* Now see if this is an interrupt handler. */
913 for (a = DECL_ATTRIBUTES (decl);
917 tree name = TREE_PURPOSE (a);
919 if (name == get_identifier ("interrupt"))
920 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
927 #define RETURN_ADDR_REGNUM GPR_LR
928 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
929 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
931 /* Tell prologue and epilogue if register REGNO should be saved / restored.
932 The return address and frame pointer are treated separately.
933 Don't consider them here. */
934 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
935 ((df_regs_ever_live_p (regno) \
936 || (interrupt_p && !current_function_is_leaf \
937 && call_used_regs[regno] && !fixed_regs[regno])) \
938 && (!call_used_regs[regno] || regno == GPR_LR \
939 || (interrupt_p && regno != GPR_SP)))
941 #define MUST_SAVE_RETURN_ADDR 0
943 /* Return the bytes needed to compute the frame pointer from the current
946 SIZE is the size needed for local variables. */
949 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
952 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
954 enum epiphany_function_type fn_type;
956 int first_slot, last_slot, first_slot_offset, last_slot_offset;
962 args_size = crtl->outgoing_args_size;
963 pretend_size = crtl->args.pretend_args_size;
964 total_size = args_size + var_size;
966 CLEAR_HARD_REG_SET (gmask);
968 first_slot_offset = 0;
970 last_slot_offset = 0;
971 first_slot_size = UNITS_PER_WORD;
973 /* See if this is an interrupt handler. Call used registers must be saved
975 fn_type = epiphany_compute_function_type (current_function_decl);
976 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
978 /* Calculate space needed for registers. */
980 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
982 reg_size += UNITS_PER_WORD;
983 SET_HARD_REG_BIT (gmask, regno);
984 if (epiphany_stack_offset - reg_size == 0)
989 reg_size += 2 * UNITS_PER_WORD;
991 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
993 if (frame_pointer_needed)
995 current_frame_info.need_fp = 1;
996 if (!interrupt_p && first_slot < 0)
1000 current_frame_info.need_fp = 0;
1001 for (regno = 0; regno <= GPR_LAST; regno++)
1003 if (MUST_SAVE_REGISTER (regno, interrupt_p))
1005 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1006 reg_size += UNITS_PER_WORD;
1007 SET_HARD_REG_BIT (gmask, regno);
1008 /* FIXME: when optimizing for speed, take schedling into account
1009 when selecting these registers. */
1010 if (regno == first_slot)
1011 gcc_assert (regno == GPR_FP && frame_pointer_needed);
1012 else if (!interrupt_p && first_slot < 0)
1014 else if (last_slot < 0
1015 && (first_slot ^ regno) != 1
1016 && (!interrupt_p || regno > GPR_0 + 1))
1020 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1021 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1022 /* ??? Could sometimes do better than that. */
1023 current_frame_info.small_threshold
1024 = (optimize >= 3 || interrupt_p ? 0
1025 : pretend_size ? small_slots
1026 : 4 + small_slots - (first_slot == GPR_FP));
1028 /* If there might be variables with 64-bit alignment requirement, align the
1029 start of the variables. */
1030 if (var_size >= 2 * UNITS_PER_WORD
1031 /* We don't want to split a double reg save/restore across two unpaired
1032 stack slots when optimizing. This rounding could be avoided with
1033 more complex reordering of the register saves, but that would seem
1034 to be a lot of code complexity for little gain. */
1035 || (reg_size > 8 && optimize))
1036 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1037 if (total_size + reg_size <= (unsigned) epiphany_stack_offset
1039 && current_function_is_leaf && !frame_pointer_needed)
1047 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1048 reg_size = epiphany_stack_offset;
1051 if (total_size + reg_size < 0x3fc)
1053 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1054 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1059 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1060 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1061 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1063 CLEAR_HARD_REG_BIT (gmask, last_slot);
1066 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1068 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1073 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1075 gcc_assert (first_slot < 0);
1076 gcc_assert (reg_size == 0);
1077 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1083 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1084 if (!first_slot_offset)
1086 if (first_slot != GPR_FP || !current_frame_info.need_fp)
1087 last_slot = first_slot;
1090 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1092 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1095 CLEAR_HARD_REG_BIT (gmask, last_slot);
1098 if (first_slot >= 0)
1100 CLEAR_HARD_REG_BIT (gmask, first_slot);
1101 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1102 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1104 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1105 first_slot_size = 2 * UNITS_PER_WORD;
1109 total_size = first_slot_offset + last_slot_offset;
1112 = (frame_pointer_needed ? first_slot_offset : (long) total_size);
1113 if (first_slot != GPR_LR)
1115 int stack_offset = epiphany_stack_offset - UNITS_PER_WORD;
1117 for (regno = 0; ; regno++)
1119 if (stack_offset + UNITS_PER_WORD - first_slot_size == 0
1122 stack_offset -= first_slot_size;
1125 else if (regno == GPR_LR)
1127 else if TEST_HARD_REG_BIT (gmask, regno)
1128 stack_offset -= UNITS_PER_WORD;
1130 lr_slot_offset += stack_offset;
1133 /* Save computed information. */
1134 current_frame_info.total_size = total_size;
1135 current_frame_info.pretend_size = pretend_size;
1136 current_frame_info.var_size = var_size;
1137 current_frame_info.args_size = args_size;
1138 current_frame_info.reg_size = reg_size;
1139 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1140 current_frame_info.first_slot = first_slot;
1141 current_frame_info.last_slot = last_slot;
1142 current_frame_info.first_slot_offset = first_slot_offset;
1143 current_frame_info.first_slot_size = first_slot_size;
1144 current_frame_info.last_slot_offset = last_slot_offset;
1145 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1147 current_frame_info.initialized = reload_completed;
1149 /* Ok, we're done. */
1153 /* Print operand X (an rtx) in assembler syntax to file FILE.
1154 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1155 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1158 epiphany_print_operand (FILE *file, rtx x, int code)
1163 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1166 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1167 (get_epiphany_condition_code (x))],
1172 current_frame_info.stld_sz = 8;
1176 current_frame_info.stld_sz = 4;
1180 current_frame_info.stld_sz = 2;
1184 fputs (REG_P (x) ? "jalr " : "bl ", file);
1188 fprintf (file, "r%d", epiphany_m1reg);
1192 /* Do nothing special. */
1196 output_operand_lossage ("invalid operand output code");
1199 switch (GET_CODE (x))
1205 fputs (reg_names[REGNO (x)], file);
1209 current_frame_info.stld_sz = 1;
1212 switch (GET_CODE (addr))
1215 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1216 addr = XEXP (addr, 0);
1219 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1220 addr = XEXP (addr, 0);
1223 offset = XEXP (XEXP (addr, 1), 1);
1224 addr = XEXP (addr, 0);
1230 output_address (addr);
1235 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1240 offset = GEN_INT (INTVAL (offset) >> 3);
1243 offset = GEN_INT (INTVAL (offset) >> 2);
1246 offset = GEN_INT (INTVAL (offset) >> 1);
1251 output_address (offset);
1255 /* We handle SFmode constants here as output_addr_const doesn't. */
1256 if (GET_MODE (x) == SFmode)
1261 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
1262 REAL_VALUE_TO_TARGET_SINGLE (d, l);
1263 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1266 /* Fall through. Let output_addr_const deal with it. */
1268 fprintf(file,"%s",IMMEDIATE_PREFIX);
1269 if (code == 'C' || code == 'X')
1271 fprintf (file, "%ld",
1272 (long) (INTVAL (x) / current_frame_info.stld_sz));
1277 output_addr_const (file, x);
1282 /* Print a memory address as an operand to reference that memory location. */
1285 epiphany_print_operand_address (FILE *file, rtx addr)
1287 register rtx base, index = 0;
1290 switch (GET_CODE (addr))
1293 fputs (reg_names[REGNO (addr)], file);
1296 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1298 output_addr_const (file, addr);
1302 output_addr_const (file, addr);
1306 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1307 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1308 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1309 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1311 base = XEXP (addr, 0), index = XEXP (addr, 1);
1312 gcc_assert (GET_CODE (base) == REG);
1313 fputs (reg_names[REGNO (base)], file);
1317 ** ++rk quirky method to scale offset for ld/str.......
1319 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1320 offset/current_frame_info.stld_sz);
1324 switch (GET_CODE (index))
1327 fprintf (file, ",%s", reg_names[REGNO (index)]);
1330 fputc (',', file), output_addr_const (file, index);
1337 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1338 /* We shouldn't get here as we've lost the mode of the memory object
1339 (which says how much to inc/dec by. */
1343 output_addr_const (file, addr);
1349 epiphany_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED,
1350 rtx *opvec ATTRIBUTE_UNUSED,
1351 int noperands ATTRIBUTE_UNUSED)
1353 int i = epiphany_n_nops;
1354 rtx pat ATTRIBUTE_UNUSED;
1357 fputs ("\tnop\n", asm_out_file);
1361 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1364 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1366 HOST_WIDE_INT size = int_size_in_bytes (type);
1368 if (AGGREGATE_TYPE_P (type)
1369 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1371 return (size == -1 || size > 8);
1374 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1375 passed by reference. */
1378 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1379 enum machine_mode mode, const_tree type,
1380 bool named ATTRIBUTE_UNUSED)
1384 if (AGGREGATE_TYPE_P (type)
1385 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1393 epiphany_function_value (const_tree ret_type,
1394 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1395 bool outgoing ATTRIBUTE_UNUSED)
1397 enum machine_mode mode;
1399 mode = TYPE_MODE (ret_type);
1400 /* We must change the mode like PROMOTE_MODE does.
1401 ??? PROMOTE_MODE is ignored for non-scalar types.
1402 The set of types tested here has to be kept in sync
1403 with the one in explow.c:promote_mode. */
1404 if (GET_MODE_CLASS (mode) == MODE_INT
1405 && GET_MODE_SIZE (mode) < 4
1406 && (TREE_CODE (ret_type) == INTEGER_TYPE
1407 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1408 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1409 || TREE_CODE (ret_type) == OFFSET_TYPE))
1411 return gen_rtx_REG (mode, 0);
1415 epiphany_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1417 return gen_rtx_REG (mode, 0);
1421 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1426 /* Fix up invalid option settings. */
1428 epiphany_override_options (void)
1430 if (epiphany_stack_offset < 4)
1431 error ("stack_offset must be at least 4");
1432 if (epiphany_stack_offset & 3)
1433 error ("stack_offset must be a multiple of 4");
1434 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1436 /* This needs to be done at start up. It's convenient to do it here. */
1440 /* For a DImode load / store SET, make a SImode set for a
1441 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1444 frame_subreg_note (rtx set, int offset)
1446 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1447 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1449 set = gen_rtx_SET (VOIDmode, dst ,src);
1450 RTX_FRAME_RELATED_P (set) = 1;
1458 rtx note = NULL_RTX;
1460 if (GET_CODE (x) == PARALLEL)
1462 rtx part = XVECEXP (x, 0, 0);
1464 if (GET_MODE (SET_DEST (part)) == DImode)
1466 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1467 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1468 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1469 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1471 part = copy_rtx (XVECEXP (x, 0, i));
1473 if (GET_CODE (part) == SET)
1474 RTX_FRAME_RELATED_P (part) = 1;
1475 XVECEXP (note, 0, i + 1) = part;
1480 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1482 part = XVECEXP (x, 0, i);
1484 if (GET_CODE (part) == SET)
1485 RTX_FRAME_RELATED_P (part) = 1;
1489 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1490 note = gen_rtx_PARALLEL (VOIDmode,
1491 gen_rtvec (2, frame_subreg_note (x, 0),
1492 frame_subreg_note (x, UNITS_PER_WORD)));
1494 RTX_FRAME_RELATED_P (x) = 1;
1496 add_reg_note (x, REG_FRAME_RELATED_EXPR, note);
1501 frame_move_insn (rtx to, rtx from)
1503 return frame_insn (gen_rtx_SET (VOIDmode, to, from));
1506 /* Generate a MEM referring to a varargs argument slot. */
1509 gen_varargs_mem (enum machine_mode mode, rtx addr)
1511 rtx mem = gen_rtx_MEM (mode, addr);
1512 MEM_NOTRAP_P (mem) = 1;
1513 set_mem_alias_set (mem, get_varargs_alias_set ());
1517 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1518 If EPILOGUE_P is 0, save; if it is one, restore.
1519 ADDR is the stack slot to save the first register to; subsequent
1520 registers are written to lower addresses.
1521 However, the order of register pairs can be reversed in order to
1522 use double-word load-store instructions. Likewise, an unpaired single
1523 word save slot can be skipped while double saves are carried out, and
1524 reused when a single register is to be saved. */
1527 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1531 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1532 rtx skipped_mem = NULL_RTX;
1533 int last_saved = limit - 1;
1536 while (last_saved >= 0
1537 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1539 for (i = 0; i < limit; i++)
1541 enum machine_mode mode = word_mode;
1544 rtx (*gen_mem) (enum machine_mode, rtx) = gen_frame_mem;
1546 /* Make sure we push the arguments in the right order. */
1547 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1549 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1550 gen_mem = gen_varargs_mem;
1552 if (stack_offset == current_frame_info.first_slot_size
1553 && current_frame_info.first_slot >= 0)
1555 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1558 addr = plus_constant (addr, - (HOST_WIDE_INT) UNITS_PER_WORD);
1560 if (i-- < min || !epilogue_p)
1562 n = current_frame_info.first_slot;
1563 gen_mem = gen_frame_mem;
1565 else if (n == UNKNOWN_REGNUM
1566 && stack_offset > current_frame_info.first_slot_size)
1571 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1576 /* Check for a register pair to save. */
1578 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1579 && (n & 1) == 0 && n+1 < limit
1580 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1582 /* If it fits in the current stack slot pair, place it there. */
1583 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1584 && stack_offset != 2 * UNITS_PER_WORD
1585 && (current_frame_info.last_slot < 0
1586 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1587 && (n+1 != last_saved || !skipped_mem))
1591 addr = plus_constant (addr, - (HOST_WIDE_INT) UNITS_PER_WORD);
1593 /* If it fits in the following stack slot pair, that's fine, too. */
1594 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1595 && stack_offset != 2 * UNITS_PER_WORD
1596 && stack_offset != 3 * UNITS_PER_WORD
1597 && (current_frame_info.last_slot < 0
1598 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1599 && n + 1 != last_saved)
1601 gcc_assert (!skipped_mem);
1602 stack_offset -= GET_MODE_SIZE (mode);
1603 skipped_mem = gen_mem (mode, addr);
1606 addr = plus_constant (addr, - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1609 reg = gen_rtx_REG (mode, n);
1610 if (mode != DImode && skipped_mem)
1613 mem = gen_mem (mode, addr);
1615 frame_move_insn (mem, reg);
1616 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1617 emit_move_insn (reg, mem);
1618 if (mem == skipped_mem)
1620 skipped_mem = NULL_RTX;
1624 addr = plus_constant (addr, - (HOST_WIDE_INT) UNITS_PER_WORD);
1625 stack_offset -= GET_MODE_SIZE (mode);
1630 epiphany_expand_prologue (void)
1633 enum epiphany_function_type fn_type;
1634 rtx addr, mem, off, reg;
1637 if (!current_frame_info.initialized)
1638 epiphany_compute_frame_size (get_frame_size ());
1640 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1641 if (flag_stack_usage_info)
1642 current_function_static_stack_size = current_frame_info.total_size;
1644 fn_type = epiphany_compute_function_type (current_function_decl);
1645 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1649 addr = plus_constant (stack_pointer_rtx,
1650 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1651 if (!lookup_attribute ("forwarder_section",
1652 DECL_ATTRIBUTES (current_function_decl))
1653 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1655 frame_move_insn (gen_frame_mem (DImode, addr),
1656 gen_rtx_REG (DImode, GPR_0));
1657 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1658 gen_rtx_REG (word_mode, STATUS_REGNUM));
1659 frame_move_insn (gen_rtx_REG (SImode, GPR_0+1),
1660 gen_rtx_REG (word_mode, IRET_REGNUM));
1661 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1662 off = GEN_INT (-current_frame_info.first_slot_offset);
1663 frame_insn (gen_stack_adjust_add (off, mem));
1664 if (!epiphany_uninterruptible_p (current_function_decl))
1665 emit_insn (gen_gie ());
1666 addr = plus_constant (stack_pointer_rtx,
1667 current_frame_info.first_slot_offset
1668 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1672 addr = plus_constant (stack_pointer_rtx,
1673 epiphany_stack_offset
1674 - (HOST_WIDE_INT) UNITS_PER_WORD);
1675 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1677 /* Allocate register save area; for small to medium size frames,
1678 allocate the entire frame; this is joint with one register save. */
1679 if (current_frame_info.first_slot >= 0)
1681 enum machine_mode mode
1682 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1683 ? word_mode : DImode);
1685 off = GEN_INT (-current_frame_info.first_slot_offset);
1686 mem = gen_frame_mem (BLKmode,
1687 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1688 frame_insn (gen_stack_adjust_str
1689 (gen_frame_mem (mode, stack_pointer_rtx),
1690 gen_rtx_REG (mode, current_frame_info.first_slot),
1692 addr = plus_constant (addr, current_frame_info.first_slot_offset);
1695 epiphany_emit_save_restore (current_frame_info.small_threshold,
1696 FIRST_PSEUDO_REGISTER, addr, 0);
1697 if (current_frame_info.need_fp)
1698 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1699 /* For large frames, allocate bulk of frame. This is usually joint with one
1701 if (current_frame_info.last_slot >= 0)
1703 gcc_assert (current_frame_info.last_slot != GPR_FP
1704 || (!current_frame_info.need_fp
1705 && current_frame_info.first_slot < 0));
1706 off = GEN_INT (-current_frame_info.last_slot_offset);
1707 mem = gen_frame_mem (BLKmode,
1708 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1709 reg = gen_rtx_REG (Pmode, GPR_IP);
1710 frame_move_insn (reg, off);
1711 frame_insn (gen_stack_adjust_str
1712 (gen_frame_mem (word_mode, stack_pointer_rtx),
1713 gen_rtx_REG (word_mode, current_frame_info.last_slot),
1716 /* If there is only one or no register to save, yet we have a large frame,
1718 else if (current_frame_info.last_slot_offset)
1720 mem = gen_frame_mem (BLKmode,
1721 plus_constant (stack_pointer_rtx,
1722 current_frame_info.last_slot_offset));
1723 off = GEN_INT (-current_frame_info.last_slot_offset);
1724 if (!SIMM11 (INTVAL (off)))
1726 reg = gen_rtx_REG (Pmode, GPR_IP);
1727 frame_move_insn (reg, off);
1730 frame_insn (gen_stack_adjust_add (off, mem));
1733 /* Mode switching uses get_hard_reg_initial_val after
1734 emit_initial_value_sets, so we have to fix this up now. */
1735 save_config = has_hard_reg_initial_val (SImode, CONFIG_REGNUM);
1738 if (REG_P (save_config))
1740 if (REGNO (save_config) >= FIRST_PSEUDO_REGISTER)
1741 gcc_assert (!df_regs_ever_live_p (REGNO (save_config)));
1743 frame_move_insn (save_config,
1744 get_hard_reg_initial_reg (save_config));
1748 rtx save_dst = save_config;
1750 reg = gen_rtx_REG (SImode, GPR_IP);
1751 gcc_assert (MEM_P (save_dst));
1752 if (!memory_operand (save_dst, SImode))
1754 rtx addr = XEXP (save_dst, 0);
1755 rtx reg2 = gen_rtx_REG (SImode, GPR_16);
1757 gcc_assert (GET_CODE (addr) == PLUS);
1758 gcc_assert (XEXP (addr, 0) == hard_frame_pointer_rtx
1759 || XEXP (addr, 0) == stack_pointer_rtx);
1760 emit_move_insn (reg2, XEXP (addr, 1));
1762 = replace_equiv_address (save_dst,
1763 gen_rtx_PLUS (Pmode, XEXP (addr, 0),
1766 emit_move_insn (reg, get_hard_reg_initial_reg (save_config));
1767 emit_move_insn (save_dst, reg);
1773 epiphany_expand_epilogue (int sibcall_p)
1776 enum epiphany_function_type fn_type;
1777 rtx mem, addr, reg, off;
1778 HOST_WIDE_INT restore_offset;
1780 fn_type = epiphany_compute_function_type( current_function_decl);
1781 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1783 /* For variable frames, deallocate bulk of frame. */
1784 if (current_frame_info.need_fp)
1786 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1787 emit_insn (gen_stack_adjust_mov (mem));
1789 /* Else for large static frames, deallocate bulk of frame. */
1790 else if (current_frame_info.last_slot_offset)
1792 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1793 reg = gen_rtx_REG (Pmode, GPR_IP);
1794 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1795 emit_insn (gen_stack_adjust_add (reg, mem));
1797 restore_offset = (interrupt_p
1798 ? - 3 * UNITS_PER_WORD
1799 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1800 addr = plus_constant (stack_pointer_rtx,
1801 (current_frame_info.first_slot_offset
1803 epiphany_emit_save_restore (current_frame_info.small_threshold,
1804 FIRST_PSEUDO_REGISTER, addr, 1);
1806 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1807 emit_insn (gen_gid ());
1809 off = GEN_INT (current_frame_info.first_slot_offset);
1810 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1811 /* For large / variable size frames, deallocating the register save area is
1812 joint with one register restore; for medium size frames, we use a
1813 dummy post-increment load to dealloacte the whole frame. */
1814 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1816 emit_insn (gen_stack_adjust_ldr
1817 (gen_rtx_REG (word_mode,
1818 (current_frame_info.last_slot >= 0
1819 ? current_frame_info.last_slot : GPR_IP)),
1820 gen_frame_mem (word_mode, stack_pointer_rtx),
1824 /* While for small frames, we deallocate the entire frame with one add. */
1825 else if (INTVAL (off))
1827 emit_insn (gen_stack_adjust_add (off, mem));
1831 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1832 gen_rtx_REG (SImode, GPR_0));
1833 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1834 gen_rtx_REG (SImode, GPR_0+1));
1835 addr = plus_constant (stack_pointer_rtx,
1836 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1837 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1838 gen_frame_mem (DImode, addr));
1840 addr = plus_constant (stack_pointer_rtx,
1841 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1842 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1846 emit_jump_insn (gen_return_internal_interrupt());
1848 emit_jump_insn (gen_return_i ());
1853 epiphany_initial_elimination_offset (int from, int to)
1855 epiphany_compute_frame_size (get_frame_size ());
1856 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1857 return current_frame_info.total_size - current_frame_info.reg_size;
1858 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1859 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1860 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1861 return (current_frame_info.total_size
1862 - ((current_frame_info.pretend_size + 4) & -8));
1863 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1864 return (current_frame_info.first_slot_offset
1865 - ((current_frame_info.pretend_size + 4) & -8));
1870 epiphany_issue_rate (void)
1875 /* Function to update the integer COST
1876 based on the relationship between INSN that is dependent on
1877 DEP_INSN through the dependence LINK. The default is to make no
1878 adjustment to COST. This can be used for example to specify to
1879 the scheduler that an output- or anti-dependence does not incur
1880 the same cost as a data-dependence. The return value should be
1881 the new value for COST. */
1883 epiphany_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1885 if (REG_NOTE_KIND (link) == 0)
1889 if (recog_memoized (insn) < 0
1890 || recog_memoized (dep_insn) < 0)
1893 dep_set = single_set (dep_insn);
1895 /* The latency that we specify in the scheduling description refers
1896 to the actual output, not to an auto-increment register; for that,
1897 the latency is one. */
1898 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
1900 rtx set = single_set (insn);
1903 && !reg_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
1904 && (!MEM_P (SET_DEST (set))
1905 || !reg_mentioned_p (SET_DEST (dep_set),
1906 XEXP (SET_DEST (set), 0))))
1913 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
1915 #define RTX_OK_FOR_BASE_P(X) \
1916 (REG_P (X) && REG_OK_FOR_BASE_P (X))
1918 #define RTX_OK_FOR_INDEX_P(MODE, X) \
1919 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
1920 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
1921 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
1923 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
1924 (GET_CODE (X) == PLUS \
1925 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
1926 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
1927 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
1930 epiphany_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
1932 #define REG_OK_FOR_BASE_P(X) \
1933 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
1934 if (RTX_OK_FOR_BASE_P (x))
1936 if (RTX_FRAME_OFFSET_P (x))
1938 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
1941 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
1942 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
1944 if ((TARGET_POST_MODIFY || reload_completed)
1945 && GET_CODE (x) == POST_MODIFY
1946 && GET_CODE (XEXP ((x), 1)) == PLUS
1947 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
1948 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
1950 if (mode == BLKmode)
1956 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
1957 enum machine_mode mode ATTRIBUTE_UNUSED,
1958 secondary_reload_info *sri)
1960 /* This could give more reload inheritance, but we are missing some
1961 reload infrastructure. */
1963 if (in_p && GET_CODE (x) == UNSPEC
1964 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
1966 gcc_assert (rclass == GENERAL_REGS);
1967 sri->icode = CODE_FOR_reload_insi_ra;
1974 epiphany_is_long_call_p (rtx x)
1976 tree decl = SYMBOL_REF_DECL (x);
1977 bool ret_val = !TARGET_SHORT_CALLS;
1980 /* ??? Is it safe to default to ret_val if decl is NULL? We should
1981 probably encode information via encode_section_info, and also
1982 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
1986 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1987 if (lookup_attribute ("long_call", attrs))
1989 else if (lookup_attribute ("short_call", attrs))
1996 epiphany_small16 (rtx x)
1999 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2001 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2003 base = XEXP (XEXP (x, 0), 0);
2004 offs = XEXP (XEXP (x, 0), 1);
2006 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2007 && epiphany_is_long_call_p (base))
2009 return TARGET_SMALL16 != 0;
2012 /* Return nonzero if it is ok to make a tail-call to DECL. */
2014 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2016 bool cfun_interrupt_p, call_interrupt_p;
2018 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2019 (current_function_decl));
2021 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2024 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2026 gcc_assert (POINTER_TYPE_P (fn_type));
2027 fn_type = TREE_TYPE (fn_type);
2028 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2029 || TREE_CODE (fn_type) == METHOD_TYPE);
2031 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2034 /* Don't tailcall from or to an ISR routine - although we could in
2035 principle tailcall from one ISR routine to another, we'd need to
2036 handle this in sibcall_epilogue to make it work. */
2037 if (cfun_interrupt_p || call_interrupt_p)
2040 /* Everything else is ok. */
2044 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2046 Return true iff the type of T has the uninterruptible attribute.
2047 If T is NULL, return false. */
2049 epiphany_uninterruptible_p (tree t)
2055 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2056 if (lookup_attribute ("disinterrupt", attrs))
2063 epiphany_call_uninterruptible_p (rtx mem)
2065 rtx addr = XEXP (mem, 0);
2068 if (GET_CODE (addr) == SYMBOL_REF)
2069 t = SYMBOL_REF_DECL (addr);
2072 return epiphany_uninterruptible_p (t);
2075 static enum machine_mode
2076 epiphany_promote_function_mode (const_tree type, enum machine_mode mode,
2077 int *punsignedp ATTRIBUTE_UNUSED,
2078 const_tree funtype ATTRIBUTE_UNUSED,
2079 int for_return ATTRIBUTE_UNUSED)
2083 return promote_mode (type, mode, &dummy);
2087 epiphany_conditional_register_usage (void)
2091 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2093 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2094 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2096 if (TARGET_HALF_REG_FILE)
2098 for (i = 32; i <= 63; i++)
2101 call_used_regs[i] = 1;
2104 if (epiphany_m1reg >= 0)
2106 fixed_regs[epiphany_m1reg] = 1;
2107 call_used_regs[epiphany_m1reg] = 1;
2109 if (!TARGET_PREFER_SHORT_INSN_REGS)
2110 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2111 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2112 reg_class_contents[GENERAL_REGS]);
2113 /* It would be simpler and quicker if we could just use
2114 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2115 it is set up later by our caller. */
2116 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2117 if (!call_used_regs[i])
2118 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2121 /* Determine where to put an argument to a function.
2122 Value is zero to push the argument on the stack,
2123 or a hard register in which to store the argument.
2125 MODE is the argument's machine mode.
2126 TYPE is the data type of the argument (as a tree).
2127 This is null for libcalls where that information may
2129 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2130 the preceding args and about the function being called.
2131 NAMED is nonzero if this argument is a named parameter
2132 (otherwise it is an extra parameter matching an ellipsis). */
2133 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2134 registers and the rest are pushed. */
2136 epiphany_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
2137 const_tree type, bool named ATTRIBUTE_UNUSED)
2139 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2141 if (PASS_IN_REG_P (cum, mode, type))
2142 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2146 /* Update the data in CUM to advance over an argument
2147 of mode MODE and data type TYPE.
2148 (TYPE is null for libcalls where that information may not be available.) */
2150 epiphany_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
2151 const_tree type, bool named ATTRIBUTE_UNUSED)
2153 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2155 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2158 /* Nested function support.
2159 An epiphany trampoline looks like this:
2160 mov r16,%low(fnaddr)
2161 movt r16,%high(fnaddr)
2166 #define EPIPHANY_LOW_RTX(X) \
2167 (gen_rtx_IOR (SImode, \
2168 gen_rtx_ASHIFT (SImode, \
2169 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2170 gen_rtx_ASHIFT (SImode, \
2171 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2172 #define EPIPHANY_HIGH_RTX(X) \
2173 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2175 /* Emit RTL insns to initialize the variable parts of a trampoline.
2176 FNADDR is an RTX for the address of the function's pure code.
2177 CXT is an RTX for the static chain value for the function. */
2179 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2181 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2182 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2184 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 0)),
2185 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2186 EPIPHANY_LOW_RTX (fnaddr)));
2187 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
2188 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2189 EPIPHANY_HIGH_RTX (fnaddr)));
2190 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
2191 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2192 EPIPHANY_LOW_RTX (cxt)));
2193 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
2194 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2195 EPIPHANY_HIGH_RTX (cxt)));
2196 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 16)),
2197 GEN_INT (0x0802014f));
2201 epiphany_optimize_mode_switching (int entity)
2203 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2207 case EPIPHANY_MSW_ENTITY_AND:
2208 case EPIPHANY_MSW_ENTITY_OR:
2210 case EPIPHANY_MSW_ENTITY_NEAREST:
2211 case EPIPHANY_MSW_ENTITY_TRUNC:
2212 return optimize > 0;
2213 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2214 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2215 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2216 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2217 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2218 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2219 return optimize == 0 || current_pass == &pass_mode_switch_use.pass;
2225 epiphany_mode_priority_to_mode (int entity, unsigned priority)
2227 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2232 case 4: return FP_MODE_ROUND_UNKNOWN;
2233 case 5: return FP_MODE_NONE;
2234 default: gcc_unreachable ();
2236 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2241 case 0: return FP_MODE_INT;
2242 case 1: return epiphany_normal_fp_rounding;
2243 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2244 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2245 case 3: return FP_MODE_CALLER;
2247 case FP_MODE_ROUND_NEAREST:
2248 case FP_MODE_CALLER:
2251 case 0: return FP_MODE_ROUND_NEAREST;
2252 case 1: return FP_MODE_ROUND_TRUNC;
2253 case 2: return FP_MODE_INT;
2254 case 3: return FP_MODE_CALLER;
2256 case FP_MODE_ROUND_TRUNC:
2259 case 0: return FP_MODE_ROUND_TRUNC;
2260 case 1: return FP_MODE_ROUND_NEAREST;
2261 case 2: return FP_MODE_INT;
2262 case 3: return FP_MODE_CALLER;
2264 case FP_MODE_ROUND_UNKNOWN:
2272 epiphany_mode_needed (int entity, rtx insn)
2274 enum attr_fp_mode mode;
2276 if (recog_memoized (insn) < 0)
2278 if (entity == EPIPHANY_MSW_ENTITY_AND
2279 || entity == EPIPHANY_MSW_ENTITY_OR)
2281 return FP_MODE_NONE;
2283 mode = get_attr_fp_mode (insn);
2287 case EPIPHANY_MSW_ENTITY_AND:
2288 return mode != FP_MODE_INT ? 1 : 2;
2289 case EPIPHANY_MSW_ENTITY_OR:
2290 return mode == FP_MODE_INT ? 1 : 2;
2291 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2292 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2293 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2295 case EPIPHANY_MSW_ENTITY_NEAREST:
2296 case EPIPHANY_MSW_ENTITY_TRUNC:
2297 if (mode == FP_MODE_ROUND_UNKNOWN)
2299 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2300 return FP_MODE_NONE;
2303 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2304 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2305 return FP_MODE_ROUND_UNKNOWN;
2307 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2308 if (mode == FP_MODE_ROUND_UNKNOWN)
2309 return epiphany_normal_fp_rounding;
2317 epiphany_mode_entry_exit (int entity, bool exit)
2319 int normal_mode = epiphany_normal_fp_mode ;
2321 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2322 if (epiphany_is_interrupt_p (current_function_decl))
2323 normal_mode = FP_MODE_CALLER;
2326 case EPIPHANY_MSW_ENTITY_AND:
2328 return normal_mode != FP_MODE_INT ? 1 : 2;
2330 case EPIPHANY_MSW_ENTITY_OR:
2332 return normal_mode == FP_MODE_INT ? 1 : 2;
2334 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2335 if (normal_mode == FP_MODE_ROUND_NEAREST
2336 || normal_mode == FP_MODE_ROUND_TRUNC)
2337 return FP_MODE_ROUND_UNKNOWN;
2339 case EPIPHANY_MSW_ENTITY_NEAREST:
2340 case EPIPHANY_MSW_ENTITY_TRUNC:
2341 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2342 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2350 epiphany_mode_after (int entity, int last_mode, rtx insn)
2352 /* We have too few call-saved registers to hope to keep the masks across
2354 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2356 if (GET_CODE (insn) == CALL_INSN)
2360 if (recog_memoized (insn) < 0)
2362 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2363 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2365 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2366 return FP_MODE_ROUND_NEAREST;
2367 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2368 return FP_MODE_ROUND_TRUNC;
2370 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2372 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2376 return FP_MODE_CALLER;
2377 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2378 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2379 && (fp_mode == FP_MODE_ROUND_NEAREST
2380 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2381 return FP_MODE_ROUND_UNKNOWN;
2388 emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2390 rtx save_cc, cc_reg, mask, src, src2;
2391 enum attr_fp_mode fp_mode;
2393 if (!MACHINE_FUNCTION (cfun)->and_mask)
2395 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2396 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2398 if (entity == EPIPHANY_MSW_ENTITY_AND)
2400 gcc_assert (mode >= 0 && mode <= 2);
2402 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2403 gen_int_mode (0xfff1fffe, SImode));
2406 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2408 gcc_assert (mode >= 0 && mode <= 2);
2410 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2413 fp_mode = (enum attr_fp_mode) mode;
2418 case FP_MODE_CALLER:
2419 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2420 mask = MACHINE_FUNCTION (cfun)->and_mask;
2422 case FP_MODE_ROUND_UNKNOWN:
2423 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2424 mask = MACHINE_FUNCTION (cfun)->and_mask;
2426 case FP_MODE_ROUND_NEAREST:
2427 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2429 mask = MACHINE_FUNCTION (cfun)->and_mask;
2431 case FP_MODE_ROUND_TRUNC:
2432 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2434 mask = MACHINE_FUNCTION (cfun)->and_mask;
2437 mask = MACHINE_FUNCTION (cfun)->or_mask;
2443 save_cc = gen_reg_rtx (CCmode);
2444 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2445 emit_move_insn (save_cc, cc_reg);
2446 mask = force_reg (SImode, mask);
2449 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2451 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2453 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2454 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2455 src2 = copy_rtx (src);
2458 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2460 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2462 emit_insn (gen_set_fp_mode (src, src2, mask));
2463 emit_move_insn (cc_reg, save_cc);
2467 epiphany_expand_set_fp_mode (rtx *operands)
2469 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2470 rtx src = operands[0];
2471 rtx mask_reg = operands[2];
2472 rtx scratch = operands[3];
2473 enum attr_fp_mode fp_mode;
2476 gcc_assert (rtx_equal_p (src, operands[1])
2477 /* Sometimes reload gets silly and reloads the same pseudo
2478 into different registers. */
2479 || (REG_P (src) && REG_P (operands[1])));
2481 if (!epiphany_uninterruptible_p (current_function_decl))
2482 emit_insn (gen_gid ());
2483 emit_move_insn (scratch, ctrl);
2485 if (GET_CODE (src) == REG)
2487 /* FP_MODE_CALLER */
2488 emit_insn (gen_xorsi3 (scratch, scratch, src));
2489 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2490 emit_insn (gen_xorsi3 (scratch, scratch, src));
2494 gcc_assert (GET_CODE (src) == CONST);
2495 src = XEXP (src, 0);
2496 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2499 case FP_MODE_ROUND_NEAREST:
2500 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2502 case FP_MODE_ROUND_TRUNC:
2503 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2504 emit_insn (gen_add2_insn (scratch, const1_rtx));
2507 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2509 case FP_MODE_CALLER:
2510 case FP_MODE_ROUND_UNKNOWN:
2515 emit_move_insn (ctrl, scratch);
2516 if (!epiphany_uninterruptible_p (current_function_decl))
2517 emit_insn (gen_gie ());
2521 epiphany_insert_mode_switch_use (rtx insn,
2522 int entity ATTRIBUTE_UNUSED,
2523 int mode ATTRIBUTE_UNUSED)
2525 rtx pat = PATTERN (insn);
2528 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2529 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2531 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2533 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2535 case FP_MODE_ROUND_NEAREST:
2536 near = gen_rtx_USE (VOIDmode, near);
2537 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2539 case FP_MODE_ROUND_TRUNC:
2540 near = gen_rtx_CLOBBER (VOIDmode, near);
2541 trunc = gen_rtx_USE (VOIDmode, trunc);
2543 case FP_MODE_ROUND_UNKNOWN:
2544 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2545 trunc = copy_rtx (near);
2548 case FP_MODE_CALLER:
2549 near = gen_rtx_USE (VOIDmode, near);
2550 trunc = gen_rtx_USE (VOIDmode, trunc);
2555 gcc_assert (GET_CODE (pat) == PARALLEL);
2556 len = XVECLEN (pat, 0);
2557 v = rtvec_alloc (len + 2);
2558 for (i = 0; i < len; i++)
2559 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2560 RTVEC_ELT (v, len) = near;
2561 RTVEC_ELT (v, len + 1) = trunc;
2562 pat = gen_rtx_PARALLEL (VOIDmode, v);
2563 PATTERN (insn) = pat;
2564 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2568 epiphany_epilogue_uses (int regno)
2570 if (regno == GPR_LR)
2572 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2574 if (fixed_regs[regno]
2575 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2576 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2580 if (regno == FP_NEAREST_REGNUM
2581 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2583 if (regno == FP_TRUNCATE_REGNUM
2584 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2590 epiphany_min_divisions_for_recip_mul (enum machine_mode mode)
2592 if (flag_reciprocal_math && mode == SFmode)
2593 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2594 it already at the tree level and expose it to further optimizations. */
2596 return default_min_divisions_for_recip_mul (mode);
2599 static enum machine_mode
2600 epiphany_preferred_simd_mode (enum machine_mode mode ATTRIBUTE_UNUSED)
2602 return TARGET_VECT_DOUBLE ? DImode : SImode;
2606 epiphany_vector_mode_supported_p (enum machine_mode mode)
2608 if (mode == V2SFmode)
2610 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2611 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2617 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2619 /* Vectors which aren't in packed structures will not be less aligned than
2620 the natural alignment of their element type, so this is safe. */
2621 if (TYPE_ALIGN_UNIT (type) == 4)
2624 return default_builtin_vector_alignment_reachable (type, is_packed);
2628 epiphany_support_vector_misalignment (enum machine_mode mode, const_tree type,
2629 int misalignment, bool is_packed)
2631 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2633 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2637 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2638 structs. Make structs double-word-aligned it they are a double word or
2639 (potentially) larger; failing that, do the same for a size of 32 bits. */
2641 epiphany_special_round_type_align (tree type, unsigned computed,
2644 unsigned align = MAX (computed, specified);
2646 HOST_WIDE_INT total, max;
2647 unsigned try_align = FASTEST_ALIGNMENT;
2649 if (maximum_field_alignment && try_align > maximum_field_alignment)
2650 try_align = maximum_field_alignment;
2651 if (align >= try_align)
2653 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2657 if (TREE_CODE (field) != FIELD_DECL
2658 || TREE_TYPE (field) == error_mark_node)
2660 offset = bit_position (field);
2661 size = DECL_SIZE (field);
2662 if (!host_integerp (offset, 1) || !host_integerp (size, 1)
2663 || TREE_INT_CST_LOW (offset) >= try_align
2664 || TREE_INT_CST_LOW (size) >= try_align)
2666 total = TREE_INT_CST_LOW (offset) + TREE_INT_CST_LOW (size);
2670 if (max >= (HOST_WIDE_INT) try_align)
2672 else if (try_align > 32 && max >= 32)
2673 align = max > 32 ? 64 : 32;
2677 /* Upping the alignment of arrays in structs is not only a performance
2678 enhancement, it also helps preserve assumptions about how
2679 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2682 epiphany_adjust_field_align (tree field, unsigned computed)
2685 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
2687 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field)));
2689 if (!host_integerp (elmsz, 1) || tree_low_cst (elmsz, 1) >= 32)
2695 /* Output code to add DELTA to the first argument, and then jump
2696 to FUNCTION. Used for C++ multiple inheritance. */
2698 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2699 HOST_WIDE_INT delta,
2700 HOST_WIDE_INT vcall_offset,
2704 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2705 const char *this_name = reg_names[this_regno];
2708 /* We use IP and R16 as a scratch registers. */
2709 gcc_assert (call_used_regs [GPR_IP]);
2710 gcc_assert (call_used_regs [GPR_16]);
2712 /* Add DELTA. When possible use a plain add, otherwise load it into
2713 a register first. */
2716 else if (SIMM11 (delta))
2717 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2718 else if (delta < 0 && delta >= -0xffff)
2720 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2721 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2725 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2726 if (delta & ~0xffff)
2727 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2728 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2731 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2732 if (vcall_offset != 0)
2734 /* ldr ip,[this] --> temp = *this
2735 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2736 add this,this,ip --> this+ = *(*this + vcall_offset) */
2737 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2738 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2739 || (vcall_offset & 3) != 0)
2741 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2742 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2743 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2746 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2747 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2750 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2751 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2753 fputs ("\tmov\tip,%low(", file);
2754 assemble_name (file, fname);
2755 fputs (")\n\tmovt\tip,%high(", file);
2756 assemble_name (file, fname);
2757 fputs (")\n\tjr ip\n", file);
2761 fputs ("\tb\t", file);
2762 assemble_name (file, fname);
2768 epiphany_start_function (FILE *file, const char *name, tree decl)
2770 /* If the function doesn't fit into the on-chip memory, it will have a
2771 section attribute - or lack of it - that denotes it goes somewhere else.
2772 But the architecture spec says that an interrupt vector still has to
2773 point to on-chip memory. So we must place a jump there to get to the
2774 actual function implementation. The forwarder_section attribute
2775 specifies the section where this jump goes.
2776 This mechanism can also be useful to have a shortcall destination for
2777 a function that is actually placed much farther away. */
2778 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2780 attrs = DECL_ATTRIBUTES (decl);
2781 int_attr = lookup_attribute ("interrupt", attrs);
2783 for (int_names = TREE_VALUE (int_attr); int_names;
2784 int_names = TREE_CHAIN (int_names))
2788 int_name = TREE_VALUE (int_names);
2789 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2790 switch_to_section (get_section (buf, SECTION_CODE, decl));
2791 fputs ("\tb\t", file);
2792 assemble_name (file, name);
2795 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2798 const char *prefix = "__forwarder_dst_";
2799 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2801 strcpy (dst_name, prefix);
2802 strcat (dst_name, name);
2803 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2804 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2805 SECTION_CODE, decl));
2806 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2807 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2812 fputs ("\tstrd r0,[sp,-1]\n", file);
2815 gcc_assert (call_used_regs[tmp]);
2816 fprintf (file, "\tmov r%d,%%low(", tmp);
2817 assemble_name (file, dst_name);
2818 fprintf (file, ")\n"
2819 "\tmovt r%d,%%high(", tmp);
2820 assemble_name (file, dst_name);
2821 fprintf (file, ")\n"
2826 fputs ("\tb\t", file);
2827 assemble_name (file, dst_name);
2832 switch_to_section (function_section (decl));
2833 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2836 struct gcc_target targetm = TARGET_INITIALIZER;