1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994-2018 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/>. */
21 #define IN_TARGET_CODE 1
25 #include "coretypes.h"
33 #include "stringpool.h"
38 #include "diagnostic-core.h"
40 #include "stor-layout.h"
44 #include "insn-attr.h"
47 #include "tm-constrs.h"
48 #include "tree-pass.h" /* for current_pass */
50 #include "pass_manager.h"
53 /* Which cpu we're compiling for. */
54 int epiphany_cpu_type
;
56 /* Name of mangle string to add to symbols to separate code compiled for each
58 const char *epiphany_mangle_cpu
;
60 /* Array of valid operand punctuation characters. */
61 char epiphany_punct_chars
[256];
63 /* The rounding mode that we generally use for floating point. */
64 int epiphany_normal_fp_rounding
;
66 /* The pass instance, for use in epiphany_optimize_mode_switching. */
67 static opt_pass
*pass_mode_switch_use
;
69 static void epiphany_init_reg_tables (void);
70 static int get_epiphany_condition_code (rtx
);
71 static tree
epiphany_handle_interrupt_attribute (tree
*, tree
, tree
, int, bool *);
72 static tree
epiphany_handle_forwarder_attribute (tree
*, tree
, tree
, int,
74 static bool epiphany_pass_by_reference (cumulative_args_t
, machine_mode
,
76 static rtx_insn
*frame_insn (rtx
);
78 /* defines for the initialization of the GCC target structure. */
79 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
81 #define TARGET_PRINT_OPERAND epiphany_print_operand
82 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
84 #define TARGET_RTX_COSTS epiphany_rtx_costs
85 #define TARGET_ADDRESS_COST epiphany_address_cost
86 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
88 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
89 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
91 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
92 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
93 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
94 #define TARGET_FUNCTION_VALUE epiphany_function_value
95 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
96 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
98 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
100 /* Using the simplistic varags handling forces us to do partial reg/stack
101 argument passing for types with larger size (> 4 bytes) than alignment. */
102 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
104 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
106 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
107 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
109 #define TARGET_LRA_P hook_bool_void_false
111 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
113 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
115 #define TARGET_OPTION_OVERRIDE epiphany_override_options
117 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
119 #define TARGET_FUNCTION_ARG epiphany_function_arg
121 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
123 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
125 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
127 /* Nonzero if the constant rtx value is a legitimate general operand.
128 We can handle any 32- or 64-bit constant. */
129 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
131 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
132 epiphany_min_divisions_for_recip_mul
134 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
136 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
138 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
139 epiphany_vector_alignment_reachable
141 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
142 epiphany_support_vector_misalignment
144 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
145 hook_bool_const_tree_hwi_hwi_const_tree_true
146 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
148 /* ??? we can use larger offsets for wider-mode sized accesses, but there
149 is no concept of anchors being dependent on the modes that they are used
150 for, so we can only use an offset range that would suit all modes. */
151 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047)
152 /* We further restrict the minimum to be a multiple of eight. */
153 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040)
155 /* Mode switching hooks. */
157 #define TARGET_MODE_EMIT emit_set_fp_mode
159 #define TARGET_MODE_NEEDED epiphany_mode_needed
161 #define TARGET_MODE_PRIORITY epiphany_mode_priority
163 #define TARGET_MODE_ENTRY epiphany_mode_entry
165 #define TARGET_MODE_EXIT epiphany_mode_exit
167 #define TARGET_MODE_AFTER epiphany_mode_after
169 #include "target-def.h"
171 #undef TARGET_ASM_ALIGNED_HI_OP
172 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
173 #undef TARGET_ASM_ALIGNED_SI_OP
174 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
176 #undef TARGET_HARD_REGNO_MODE_OK
177 #define TARGET_HARD_REGNO_MODE_OK epiphany_hard_regno_mode_ok
179 #undef TARGET_CONSTANT_ALIGNMENT
180 #define TARGET_CONSTANT_ALIGNMENT epiphany_constant_alignment
182 #undef TARGET_STARTING_FRAME_OFFSET
183 #define TARGET_STARTING_FRAME_OFFSET epiphany_starting_frame_offset
186 epiphany_is_interrupt_p (tree decl
)
190 attrs
= DECL_ATTRIBUTES (decl
);
191 if (lookup_attribute ("interrupt", attrs
))
197 /* Called from epiphany_override_options.
198 We use this to initialize various things. */
203 /* N.B. this pass must not run before the first optimize_mode_switching
204 pass because of the side offect of epiphany_mode_needed on
205 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
206 pass_resolve_sw_modes. */
207 pass_mode_switch_use
= make_pass_mode_switch_use (g
);
208 struct register_pass_info insert_use_info
209 = { pass_mode_switch_use
, "mode_sw",
210 1, PASS_POS_INSERT_AFTER
213 = g
->get_passes()->get_pass_mode_switching ()->clone ();
214 struct register_pass_info mode_sw2_info
215 = { mode_sw2
, "mode_sw",
216 1, PASS_POS_INSERT_AFTER
218 opt_pass
*mode_sw3
= make_pass_resolve_sw_modes (g
);
219 struct register_pass_info mode_sw3_info
220 = { mode_sw3
, "mode_sw",
221 1, PASS_POS_INSERT_AFTER
224 = g
->get_passes()->get_pass_split_all_insns ()->clone ();
225 struct register_pass_info mode_sw4_info
226 = { mode_sw4
, "mode_sw",
227 1, PASS_POS_INSERT_AFTER
229 static const int num_modes
[] = NUM_MODES_FOR_MODE_SWITCHING
;
230 #define N_ENTITIES ARRAY_SIZE (num_modes)
232 epiphany_init_reg_tables ();
234 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
235 memset (epiphany_punct_chars
, 0, sizeof (epiphany_punct_chars
));
236 epiphany_punct_chars
['-'] = 1;
238 epiphany_normal_fp_rounding
239 = (epiphany_normal_fp_mode
== FP_MODE_ROUND_TRUNC
240 ? FP_MODE_ROUND_TRUNC
: FP_MODE_ROUND_NEAREST
);
241 register_pass (&mode_sw4_info
);
242 register_pass (&mode_sw2_info
);
243 register_pass (&mode_sw3_info
);
244 register_pass (&insert_use_info
);
245 register_pass (&mode_sw2_info
);
246 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
247 gcc_assert (N_ENTITIES
== EPIPHANY_MSW_ENTITY_NUM
);
249 #if 1 /* As long as peep2_rescan is not implemented,
250 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
251 we need a second peephole2 pass to get reasonable code. */
253 opt_pass
*extra_peephole2
254 = g
->get_passes ()->get_pass_peephole2 ()->clone ();
255 struct register_pass_info peep2_2_info
256 = { extra_peephole2
, "peephole2",
257 1, PASS_POS_INSERT_AFTER
260 register_pass (&peep2_2_info
);
265 /* The condition codes of the EPIPHANY, and the inverse function. */
266 static const char *const epiphany_condition_codes
[] =
267 { /* 0 1 2 3 4 5 6 7 8 9 */
268 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
270 "beq","bne","blt", "blte",
273 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
275 /* Returns the index of the EPIPHANY condition code string in
276 `epiphany_condition_codes'. COMPARISON should be an rtx like
277 `(eq (...) (...))'. */
280 get_epiphany_condition_code (rtx comparison
)
282 switch (GET_MODE (XEXP (comparison
, 0)))
285 switch (GET_CODE (comparison
))
298 default : gcc_unreachable ();
301 switch (GET_CODE (comparison
))
305 default: gcc_unreachable ();
308 switch (GET_CODE (comparison
))
312 default: gcc_unreachable ();
315 switch (GET_CODE (comparison
))
319 default: gcc_unreachable ();
322 switch (GET_CODE (comparison
))
328 default: gcc_unreachable ();
331 switch (GET_CODE (comparison
))
335 default: gcc_unreachable ();
337 case E_CC_FP_GTEmode
:
338 switch (GET_CODE (comparison
))
344 case UNLE
: return 5;
345 case UNLT
: return 7;
346 default: gcc_unreachable ();
348 case E_CC_FP_ORDmode
:
349 switch (GET_CODE (comparison
))
351 case ORDERED
: return 9;
352 case UNORDERED
: return 8;
353 default: gcc_unreachable ();
355 case E_CC_FP_UNEQmode
:
356 switch (GET_CODE (comparison
))
360 default: gcc_unreachable ();
362 default: gcc_unreachable ();
369 /* Implement TARGET_HARD_REGNO_MODE_OK. */
372 epiphany_hard_regno_mode_ok (unsigned int regno
, machine_mode mode
)
374 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
375 return (regno
& 1) == 0 && GPR_P (regno
);
380 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
381 return the mode to be used for the comparison. */
384 epiphany_select_cc_mode (enum rtx_code op
,
385 rtx x ATTRIBUTE_UNUSED
,
386 rtx y ATTRIBUTE_UNUSED
)
388 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
390 if (TARGET_SOFT_CMPSF
391 || op
== ORDERED
|| op
== UNORDERED
)
393 if (op
== EQ
|| op
== NE
)
395 if (op
== ORDERED
|| op
== UNORDERED
)
396 return CC_FP_ORDmode
;
397 if (op
== UNEQ
|| op
== LTGT
)
398 return CC_FP_UNEQmode
;
399 return CC_FP_GTEmode
;
403 /* recognize combiner pattern ashlsi_btst:
405 (set (reg:N_NE 65 cc1)
406 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
409 (const_int 0 [0x0])))
410 (clobber (scratch:SI)) */
411 else if ((op
== EQ
|| op
== NE
)
412 && GET_CODE (x
) == ZERO_EXTRACT
413 && XEXP (x
, 1) == const1_rtx
414 && CONST_INT_P (XEXP (x
, 2)))
416 else if ((op
== GEU
|| op
== LTU
) && GET_CODE (x
) == PLUS
)
418 else if ((op
== LEU
|| op
== GTU
) && GET_CODE (x
) == MINUS
)
424 enum reg_class epiphany_regno_reg_class
[FIRST_PSEUDO_REGISTER
];
427 epiphany_init_reg_tables (void)
431 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
434 epiphany_regno_reg_class
[i
] = LR_REGS
;
435 else if (i
<= 7 && TARGET_PREFER_SHORT_INSN_REGS
)
436 epiphany_regno_reg_class
[i
] = SHORT_INSN_REGS
;
437 else if (call_used_regs
[i
]
438 && TEST_HARD_REG_BIT (reg_class_contents
[GENERAL_REGS
], i
))
439 epiphany_regno_reg_class
[i
] = SIBCALL_REGS
;
440 else if (i
>= CORE_CONTROL_FIRST
&& i
<= CORE_CONTROL_LAST
)
441 epiphany_regno_reg_class
[i
] = CORE_CONTROL_REGS
;
442 else if (i
< (GPR_LAST
+1)
443 || i
== ARG_POINTER_REGNUM
|| i
== FRAME_POINTER_REGNUM
)
444 epiphany_regno_reg_class
[i
] = GENERAL_REGS
;
445 else if (i
== CC_REGNUM
)
446 epiphany_regno_reg_class
[i
] = NO_REGS
/* CC_REG: must be NO_REGS */;
448 epiphany_regno_reg_class
[i
] = NO_REGS
;
452 /* EPIPHANY specific attribute support.
454 The EPIPHANY has these attributes:
455 interrupt - for interrupt functions.
456 short_call - the function is assumed to be reachable with the b / bl
458 long_call - the function address is loaded into a register before use.
459 disinterrupt - functions which mask interrupts throughout.
460 They unmask them while calling an interruptible
463 static const struct attribute_spec epiphany_attribute_table
[] =
465 /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
466 affects_type_identity, handler, exclude } */
467 { "interrupt", 0, 9, true, false, false, true,
468 epiphany_handle_interrupt_attribute
, NULL
},
469 { "forwarder_section", 1, 1, true, false, false, false,
470 epiphany_handle_forwarder_attribute
, NULL
},
471 { "long_call", 0, 0, false, true, true, false, NULL
, NULL
},
472 { "short_call", 0, 0, false, true, true, false, NULL
, NULL
},
473 { "disinterrupt", 0, 0, false, true, true, true, NULL
, NULL
},
474 { NULL
, 0, 0, false, false, false, false, NULL
, NULL
}
477 /* Handle an "interrupt" attribute; arguments as in
478 struct attribute_spec.handler. */
480 epiphany_handle_interrupt_attribute (tree
*node
, tree name
, tree args
,
481 int flags ATTRIBUTE_UNUSED
,
488 gcc_assert (DECL_P (*node
));
489 tree t
= TREE_TYPE (*node
);
490 if (TREE_CODE (t
) != FUNCTION_TYPE
)
491 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
493 /* Argument handling and the stack layout for interrupt handlers
494 don't mix. It makes no sense in the first place, so emit an
496 else if (TYPE_ARG_TYPES (t
)
497 && TREE_VALUE (TYPE_ARG_TYPES (t
)) != void_type_node
)
498 error_at (DECL_SOURCE_LOCATION (*node
),
499 "interrupt handlers cannot have arguments");
503 value
= TREE_VALUE (args
);
505 if (TREE_CODE (value
) != STRING_CST
)
507 warning (OPT_Wattributes
,
508 "argument of %qE attribute is not a string constant", name
);
509 *no_add_attrs
= true;
511 else if (strcmp (TREE_STRING_POINTER (value
), "reset")
512 && strcmp (TREE_STRING_POINTER (value
), "software_exception")
513 && strcmp (TREE_STRING_POINTER (value
), "page_miss")
514 && strcmp (TREE_STRING_POINTER (value
), "timer0")
515 && strcmp (TREE_STRING_POINTER (value
), "timer1")
516 && strcmp (TREE_STRING_POINTER (value
), "message")
517 && strcmp (TREE_STRING_POINTER (value
), "dma0")
518 && strcmp (TREE_STRING_POINTER (value
), "dma1")
519 && strcmp (TREE_STRING_POINTER (value
), "wand")
520 && strcmp (TREE_STRING_POINTER (value
), "swi"))
522 warning (OPT_Wattributes
,
523 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
525 *no_add_attrs
= true;
529 return epiphany_handle_interrupt_attribute (node
, name
, TREE_CHAIN (args
),
530 flags
, no_add_attrs
);
533 /* Handle a "forwarder_section" attribute; arguments as in
534 struct attribute_spec.handler. */
536 epiphany_handle_forwarder_attribute (tree
*node ATTRIBUTE_UNUSED
,
537 tree name
, tree args
,
538 int flags ATTRIBUTE_UNUSED
,
543 value
= TREE_VALUE (args
);
545 if (TREE_CODE (value
) != STRING_CST
)
547 warning (OPT_Wattributes
,
548 "argument of %qE attribute is not a string constant", name
);
549 *no_add_attrs
= true;
555 /* Misc. utilities. */
557 /* Generate a SYMBOL_REF for the special function NAME. When the address
558 can't be placed directly into a call instruction, and if possible, copy
559 it to a register so that cse / code hoisting is possible. */
561 sfunc_symbol (const char *name
)
563 rtx sym
= gen_rtx_SYMBOL_REF (Pmode
, name
);
565 /* These sfuncs should be hidden, and every dso should get a copy. */
566 SYMBOL_REF_FLAGS (sym
) = SYMBOL_FLAG_FUNCTION
| SYMBOL_FLAG_LOCAL
;
567 if (TARGET_SHORT_CALLS
)
568 ; /* Nothing to be done. */
569 else if (can_create_pseudo_p ())
570 sym
= copy_to_mode_reg (Pmode
, sym
);
571 else /* We rely on reload to fix this up. */
572 gcc_assert (!reload_in_progress
|| reload_completed
);
576 /* X and Y are two things to compare using CODE in IN_MODE.
577 Emit the compare insn, construct the proper cc reg in the proper
578 mode, and return the rtx for the cc reg comparison in CMODE. */
581 gen_compare_reg (machine_mode cmode
, enum rtx_code code
,
582 machine_mode in_mode
, rtx x
, rtx y
)
584 machine_mode mode
= SELECT_CC_MODE (code
, x
, y
);
585 rtx cc_reg
, pat
, clob0
, clob1
, clob2
;
587 if (in_mode
== VOIDmode
)
588 in_mode
= GET_MODE (x
);
589 if (in_mode
== VOIDmode
)
590 in_mode
= GET_MODE (y
);
592 if (mode
== CC_FPmode
)
594 /* The epiphany has only EQ / NE / LT / LE conditions for
595 hardware floating point. */
596 if (code
== GT
|| code
== GE
|| code
== UNLE
|| code
== UNLT
)
598 rtx tmp
= x
; x
= y
; y
= tmp
;
599 code
= swap_condition (code
);
601 cc_reg
= gen_rtx_REG (mode
, CCFP_REGNUM
);
602 y
= force_reg (in_mode
, y
);
606 if (mode
== CC_FP_GTEmode
607 && (code
== LE
|| code
== LT
|| code
== UNGT
|| code
== UNGE
))
609 if (flag_finite_math_only
610 && ((REG_P (x
) && REGNO (x
) == GPR_0
)
611 || (REG_P (y
) && REGNO (y
) == GPR_1
)))
614 case LE
: code
= UNLE
; break;
615 case LT
: code
= UNLT
; break;
616 case UNGT
: code
= GT
; break;
617 case UNGE
: code
= GE
; break;
618 default: gcc_unreachable ();
622 rtx tmp
= x
; x
= y
; y
= tmp
;
623 code
= swap_condition (code
);
626 cc_reg
= gen_rtx_REG (mode
, CC_REGNUM
);
628 if ((mode
== CC_FP_EQmode
|| mode
== CC_FP_GTEmode
629 || mode
== CC_FP_ORDmode
|| mode
== CC_FP_UNEQmode
)
630 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
631 && (!REG_P (x
) || REGNO (x
) != GPR_0
632 || !REG_P (y
) || REGNO (y
) != GPR_1
))
637 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
638 but just like the flag clobber of movsicc, we have to allow
639 this for ifcvt to work, on the assumption that we'll only want
640 to do this if these registers have been used before by the
642 gcc_assert (currently_expanding_to_rtl
);
644 reg
= gen_rtx_REG (in_mode
, GPR_0
);
645 if (reg_overlap_mentioned_p (reg
, y
))
647 emit_move_insn (reg
, x
);
649 reg
= gen_rtx_REG (in_mode
, GPR_1
);
650 emit_move_insn (reg
, y
);
654 x
= force_reg (in_mode
, x
);
656 pat
= gen_rtx_SET (cc_reg
, gen_rtx_COMPARE (mode
, x
, y
));
657 if (mode
== CC_FP_EQmode
|| mode
== CC_FP_GTEmode
)
659 const char *name
= mode
== CC_FP_EQmode
? "__eqsf2" : "__gtesf2";
660 rtx use
= gen_rtx_USE (VOIDmode
, sfunc_symbol (name
));
662 clob0
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_IP
));
663 clob1
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_LR
));
664 pat
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (4, pat
, use
, clob0
, clob1
));
666 else if (mode
== CC_FP_ORDmode
|| mode
== CC_FP_UNEQmode
)
668 const char *name
= mode
== CC_FP_ORDmode
? "__ordsf2" : "__uneqsf2";
669 rtx use
= gen_rtx_USE (VOIDmode
, sfunc_symbol (name
));
671 clob0
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_IP
));
672 clob1
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_16
));
673 clob2
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_LR
));
674 pat
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (5, pat
, use
,
675 clob0
, clob1
, clob2
));
679 clob0
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (in_mode
));
680 pat
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (2, pat
, clob0
));
683 return gen_rtx_fmt_ee (code
, cmode
, cc_reg
, const0_rtx
);
686 /* The ROUND_ADVANCE* macros are local to this file. */
687 /* Round SIZE up to a word boundary. */
688 #define ROUND_ADVANCE(SIZE) \
689 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
691 /* Round arg MODE/TYPE up to the next word boundary. */
692 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
694 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
695 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
697 /* Round CUM up to the necessary point for argument MODE/TYPE. */
698 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
699 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
700 ? (((CUM) + 1) & ~1) \
704 epiphany_function_arg_boundary (machine_mode mode
, const_tree type
)
706 if ((type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
)) <= PARM_BOUNDARY
)
707 return PARM_BOUNDARY
;
708 return 2 * PARM_BOUNDARY
;
711 /* Do any needed setup for a variadic function. For the EPIPHANY, we
712 actually emit the code in epiphany_expand_prologue.
714 CUM has not been updated for the last named argument which has type TYPE
715 and mode MODE, and we rely on this fact. */
719 epiphany_setup_incoming_varargs (cumulative_args_t cum
, machine_mode mode
,
720 tree type
, int *pretend_size
, int no_rtl
)
723 CUMULATIVE_ARGS next_cum
;
724 machine_function_t
*mf
= MACHINE_FUNCTION (cfun
);
726 /* All BLKmode values are passed by reference. */
727 gcc_assert (mode
!= BLKmode
);
729 next_cum
= *get_cumulative_args (cum
);
731 = ROUND_ADVANCE_CUM (next_cum
, mode
, type
) + ROUND_ADVANCE_ARG (mode
, type
);
732 first_anon_arg
= next_cum
;
734 if (first_anon_arg
< MAX_EPIPHANY_PARM_REGS
&& !no_rtl
)
736 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
737 int first_reg_offset
= first_anon_arg
;
739 *pretend_size
= ((MAX_EPIPHANY_PARM_REGS
- first_reg_offset
)
743 mf
->pretend_args_odd
= ((*pretend_size
& UNITS_PER_WORD
) ? 1 : 0);
747 epiphany_arg_partial_bytes (cumulative_args_t cum
, machine_mode mode
,
748 tree type
, bool named ATTRIBUTE_UNUSED
)
750 int words
= 0, rounded_cum
;
752 gcc_assert (!epiphany_pass_by_reference (cum
, mode
, type
, /* named */ true));
754 rounded_cum
= ROUND_ADVANCE_CUM (*get_cumulative_args (cum
), mode
, type
);
755 if (rounded_cum
< MAX_EPIPHANY_PARM_REGS
)
757 words
= MAX_EPIPHANY_PARM_REGS
- rounded_cum
;
758 if (words
>= ROUND_ADVANCE_ARG (mode
, type
))
761 return words
* UNITS_PER_WORD
;
764 /* Cost functions. */
766 /* Compute a (partial) cost for rtx X. Return true if the complete
767 cost has been computed, and false if subexpressions should be
768 scanned. In either case, *TOTAL contains the cost result. */
771 epiphany_rtx_costs (rtx x
, machine_mode mode
, int outer_code
,
772 int opno ATTRIBUTE_UNUSED
,
773 int *total
, bool speed ATTRIBUTE_UNUSED
)
775 int code
= GET_CODE (x
);
779 /* Small integers in the right context are as cheap as registers. */
781 if ((outer_code
== PLUS
|| outer_code
== MINUS
)
782 && SIMM11 (INTVAL (x
)))
787 if (IMM16 (INTVAL (x
)))
789 *total
= outer_code
== SET
? 0 : COSTS_N_INSNS (1);
797 *total
= COSTS_N_INSNS ((epiphany_small16 (x
) ? 0 : 1)
798 + (outer_code
== SET
? 0 : 1));
804 split_double (x
, &high
, &low
);
805 *total
= COSTS_N_INSNS (!IMM16 (INTVAL (high
))
806 + !IMM16 (INTVAL (low
)));
813 *total
= COSTS_N_INSNS (1);
819 /* There are a number of single-insn combiner patterns that use
820 the flag side effects of arithmetic. */
832 rtx src
= SET_SRC (x
);
844 /* Provide the costs of an addressing mode that contains ADDR.
845 If ADDR is not a valid address, its cost is irrelevant. */
848 epiphany_address_cost (rtx addr
, machine_mode mode
,
849 addr_space_t as ATTRIBUTE_UNUSED
, bool speed
)
852 rtx off
= const0_rtx
;
857 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
859 switch (GET_CODE (addr
))
862 reg
= XEXP (addr
, 0);
863 off
= XEXP (addr
, 1);
866 reg
= XEXP (addr
, 0);
867 off
= XEXP (addr
, 1);
868 gcc_assert (GET_CODE (off
) == PLUS
&& rtx_equal_p (reg
, XEXP (off
, 0)));
870 if (satisfies_constraint_Rgs (reg
) && satisfies_constraint_Rgs (off
))
878 if (!satisfies_constraint_Rgs (reg
))
880 /* The offset range available for short instructions depends on the mode
881 of the memory access. */
882 /* First, make sure we have a valid integer. */
883 if (!satisfies_constraint_L (off
))
886 switch (GET_MODE_SIZE (mode
))
900 return i
< -7 || i
> 7;
904 /* Compute the cost of moving data between registers and memory.
905 For integer, load latency is twice as long as register-register moves,
906 but issue pich is the same. For floating point, load latency is three
907 times as much as a reg-reg move. */
909 epiphany_memory_move_cost (machine_mode mode
,
910 reg_class_t rclass ATTRIBUTE_UNUSED
,
911 bool in ATTRIBUTE_UNUSED
)
913 return GET_MODE_CLASS (mode
) == MODE_INT
? 3 : 4;
916 /* Function prologue/epilogue handlers. */
918 /* EPIPHANY stack frames look like:
920 Before call After call
921 +-----------------------+ +-----------------------+
923 high | local variables, | | local variables, |
924 mem | reg save area, etc. | | reg save area, etc. |
926 +-----------------------+ +-----------------------+
928 | arguments on stack. | | arguments on stack. |
930 SP+8->+-----------------------+FP+8m->+-----------------------+
931 | 2 word save area for | | reg parm save area, |
932 | leaf funcs / flags | | only created for |
933 SP+0->+-----------------------+ | variable argument |
935 FP+8n->+-----------------------+
937 | register save area |
939 +-----------------------+
943 FP+0->+-----------------------+
945 | alloca allocations |
947 +-----------------------+
949 | arguments on stack |
951 SP+8->+-----------------------+
952 low | 2 word save area for |
953 memory | leaf funcs / flags |
954 SP+0->+-----------------------+
957 1) The "reg parm save area" does not exist for non variable argument fns.
958 The "reg parm save area" could be eliminated if we created our
959 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
960 (so it's not done). */
962 /* Structure to be filled in by epiphany_compute_frame_size with register
963 save masks, and offsets for the current function. */
964 struct epiphany_frame_info
966 unsigned int total_size
; /* # bytes that the entire frame takes up. */
967 unsigned int pretend_size
; /* # bytes we push and pretend caller did. */
968 unsigned int args_size
; /* # bytes that outgoing arguments take up. */
969 unsigned int reg_size
; /* # bytes needed to store regs. */
970 unsigned int var_size
; /* # bytes that variables take up. */
971 HARD_REG_SET gmask
; /* Set of saved gp registers. */
972 int initialized
; /* Nonzero if frame size already calculated. */
973 int stld_sz
; /* Current load/store data size for offset
975 int need_fp
; /* value to override "frame_pointer_needed */
976 /* FIRST_SLOT is the slot that is saved first, at the very start of
977 the frame, with a POST_MODIFY to allocate the frame, if the size fits,
978 or at least the parm and register save areas, otherwise.
979 In the case of a large frame, LAST_SLOT is the slot that is saved last,
980 with a POST_MODIFY to allocate the rest of the frame. */
981 int first_slot
, last_slot
, first_slot_offset
, last_slot_offset
;
986 /* Current frame information calculated by epiphany_compute_frame_size. */
987 static struct epiphany_frame_info current_frame_info
;
989 /* Zero structure to initialize current_frame_info. */
990 static struct epiphany_frame_info zero_frame_info
;
992 /* The usual; we set up our machine_function data. */
993 static struct machine_function
*
994 epiphany_init_machine_status (void)
996 struct machine_function
*machine
;
998 /* Reset state info for each function. */
999 current_frame_info
= zero_frame_info
;
1001 machine
= ggc_cleared_alloc
<machine_function_t
> ();
1006 /* Implements INIT_EXPANDERS. We just set up to call the above
1009 epiphany_init_expanders (void)
1011 init_machine_status
= epiphany_init_machine_status
;
1014 /* Type of function DECL.
1016 The result is cached. To reset the cache at the end of a function,
1017 call with DECL = NULL_TREE. */
1019 static enum epiphany_function_type
1020 epiphany_compute_function_type (tree decl
)
1024 static enum epiphany_function_type fn_type
= EPIPHANY_FUNCTION_UNKNOWN
;
1025 /* Last function we were called for. */
1026 static tree last_fn
= NULL_TREE
;
1028 /* Resetting the cached value? */
1029 if (decl
== NULL_TREE
)
1031 fn_type
= EPIPHANY_FUNCTION_UNKNOWN
;
1032 last_fn
= NULL_TREE
;
1036 if (decl
== last_fn
&& fn_type
!= EPIPHANY_FUNCTION_UNKNOWN
)
1039 /* Assume we have a normal function (not an interrupt handler). */
1040 fn_type
= EPIPHANY_FUNCTION_NORMAL
;
1042 /* Now see if this is an interrupt handler. */
1043 for (a
= DECL_ATTRIBUTES (decl
);
1047 tree name
= TREE_PURPOSE (a
);
1049 if (name
== get_identifier ("interrupt"))
1050 fn_type
= EPIPHANY_FUNCTION_INTERRUPT
;
1057 #define RETURN_ADDR_REGNUM GPR_LR
1058 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
1059 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
1061 /* Tell prologue and epilogue if register REGNO should be saved / restored.
1062 The return address and frame pointer are treated separately.
1063 Don't consider them here. */
1064 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
1065 ((df_regs_ever_live_p (regno) \
1066 || (interrupt_p && !crtl->is_leaf \
1067 && call_used_regs[regno] && !fixed_regs[regno])) \
1068 && (!call_used_regs[regno] || regno == GPR_LR \
1069 || (interrupt_p && regno != GPR_SP)))
1071 #define MUST_SAVE_RETURN_ADDR 0
1073 /* Return the bytes needed to compute the frame pointer from the current
1076 SIZE is the size needed for local variables. */
1079 epiphany_compute_frame_size (int size
/* # of var. bytes allocated. */)
1082 unsigned int total_size
, var_size
, args_size
, pretend_size
, reg_size
;
1084 enum epiphany_function_type fn_type
;
1086 int first_slot
, last_slot
, first_slot_offset
, last_slot_offset
;
1087 int first_slot_size
;
1088 int small_slots
= 0;
1091 args_size
= crtl
->outgoing_args_size
;
1092 pretend_size
= crtl
->args
.pretend_args_size
;
1093 total_size
= args_size
+ var_size
;
1095 CLEAR_HARD_REG_SET (gmask
);
1097 first_slot_offset
= 0;
1099 last_slot_offset
= 0;
1100 first_slot_size
= UNITS_PER_WORD
;
1102 /* See if this is an interrupt handler. Call used registers must be saved
1104 fn_type
= epiphany_compute_function_type (current_function_decl
);
1105 interrupt_p
= EPIPHANY_INTERRUPT_P (fn_type
);
1107 /* Calculate space needed for registers. */
1109 for (regno
= MAX_EPIPHANY_PARM_REGS
- 1; pretend_size
> reg_size
; regno
--)
1111 reg_size
+= UNITS_PER_WORD
;
1112 SET_HARD_REG_BIT (gmask
, regno
);
1113 if (epiphany_stack_offset
- reg_size
== 0)
1118 reg_size
+= 2 * UNITS_PER_WORD
;
1120 small_slots
= epiphany_stack_offset
/ UNITS_PER_WORD
;
1122 if (frame_pointer_needed
)
1124 current_frame_info
.need_fp
= 1;
1125 if (!interrupt_p
&& first_slot
< 0)
1126 first_slot
= GPR_FP
;
1129 current_frame_info
.need_fp
= 0;
1130 for (regno
= 0; regno
<= GPR_LAST
; regno
++)
1132 if (MUST_SAVE_REGISTER (regno
, interrupt_p
))
1134 gcc_assert (!TEST_HARD_REG_BIT (gmask
, regno
));
1135 reg_size
+= UNITS_PER_WORD
;
1136 SET_HARD_REG_BIT (gmask
, regno
);
1137 /* FIXME: when optimizing for speed, take schedling into account
1138 when selecting these registers. */
1139 if (regno
== first_slot
)
1140 gcc_assert (regno
== GPR_FP
&& frame_pointer_needed
);
1141 else if (!interrupt_p
&& first_slot
< 0)
1143 else if (last_slot
< 0
1144 && (first_slot
^ regno
) != 1
1145 && (!interrupt_p
|| regno
> GPR_1
))
1149 if (TEST_HARD_REG_BIT (gmask
, GPR_LR
))
1150 MACHINE_FUNCTION (cfun
)->lr_clobbered
= 1;
1151 /* ??? Could sometimes do better than that. */
1152 current_frame_info
.small_threshold
1153 = (optimize
>= 3 || interrupt_p
? 0
1154 : pretend_size
? small_slots
1155 : 4 + small_slots
- (first_slot
== GPR_FP
));
1157 /* If there might be variables with 64-bit alignment requirement, align the
1158 start of the variables. */
1159 if (var_size
>= 2 * UNITS_PER_WORD
1160 /* We don't want to split a double reg save/restore across two unpaired
1161 stack slots when optimizing. This rounding could be avoided with
1162 more complex reordering of the register saves, but that would seem
1163 to be a lot of code complexity for little gain. */
1164 || (reg_size
> 8 && optimize
))
1165 reg_size
= EPIPHANY_STACK_ALIGN (reg_size
);
1166 if (((total_size
+ reg_size
1167 /* Reserve space for UNKNOWN_REGNUM. */
1168 + EPIPHANY_STACK_ALIGN (4))
1169 <= (unsigned) epiphany_stack_offset
)
1171 && crtl
->is_leaf
&& !frame_pointer_needed
)
1179 && reg_size
< (unsigned HOST_WIDE_INT
) epiphany_stack_offset
)
1180 reg_size
= epiphany_stack_offset
;
1183 if (total_size
+ reg_size
< 0x3fc)
1185 first_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
+ reg_size
);
1186 first_slot_offset
+= EPIPHANY_STACK_ALIGN (epiphany_stack_offset
);
1191 first_slot_offset
= EPIPHANY_STACK_ALIGN (reg_size
);
1192 last_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
);
1193 last_slot_offset
+= EPIPHANY_STACK_ALIGN (epiphany_stack_offset
);
1195 CLEAR_HARD_REG_BIT (gmask
, last_slot
);
1198 else if (total_size
+ reg_size
< 0x1ffc && first_slot
>= 0)
1200 first_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
+ reg_size
);
1205 if (total_size
+ reg_size
<= (unsigned) epiphany_stack_offset
)
1207 gcc_assert (first_slot
< 0);
1208 gcc_assert (reg_size
== 0 || (int) reg_size
== epiphany_stack_offset
);
1209 last_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
+ reg_size
);
1215 ? EPIPHANY_STACK_ALIGN (reg_size
- epiphany_stack_offset
) : 0);
1216 if (!first_slot_offset
)
1218 if (first_slot
!= GPR_FP
|| !current_frame_info
.need_fp
)
1219 last_slot
= first_slot
;
1222 last_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
);
1224 last_slot_offset
+= EPIPHANY_STACK_ALIGN (epiphany_stack_offset
);
1227 CLEAR_HARD_REG_BIT (gmask
, last_slot
);
1230 if (first_slot
>= 0)
1232 CLEAR_HARD_REG_BIT (gmask
, first_slot
);
1233 if (TEST_HARD_REG_BIT (gmask
, first_slot
^ 1)
1234 && epiphany_stack_offset
- pretend_size
>= 2 * UNITS_PER_WORD
)
1236 CLEAR_HARD_REG_BIT (gmask
, first_slot
^ 1);
1237 first_slot_size
= 2 * UNITS_PER_WORD
;
1241 total_size
= first_slot_offset
+ last_slot_offset
;
1243 /* Save computed information. */
1244 current_frame_info
.total_size
= total_size
;
1245 current_frame_info
.pretend_size
= pretend_size
;
1246 current_frame_info
.var_size
= var_size
;
1247 current_frame_info
.args_size
= args_size
;
1248 current_frame_info
.reg_size
= reg_size
;
1249 COPY_HARD_REG_SET (current_frame_info
.gmask
, gmask
);
1250 current_frame_info
.first_slot
= first_slot
;
1251 current_frame_info
.last_slot
= last_slot
;
1252 current_frame_info
.first_slot_offset
= first_slot_offset
;
1253 current_frame_info
.first_slot_size
= first_slot_size
;
1254 current_frame_info
.last_slot_offset
= last_slot_offset
;
1256 current_frame_info
.initialized
= reload_completed
;
1258 /* Ok, we're done. */
1262 /* Print operand X (an rtx) in assembler syntax to file FILE.
1263 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1264 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1267 epiphany_print_operand (FILE *file
, rtx x
, int code
)
1272 fputs (epiphany_condition_codes
[get_epiphany_condition_code (x
)], file
);
1275 fputs (epiphany_condition_codes
[EPIPHANY_INVERSE_CONDITION_CODE
1276 (get_epiphany_condition_code (x
))],
1281 current_frame_info
.stld_sz
= 8;
1285 current_frame_info
.stld_sz
= 4;
1289 current_frame_info
.stld_sz
= 2;
1293 fputs (REG_P (x
) ? "jalr " : "bl ", file
);
1297 fprintf (file
, "r%d", epiphany_m1reg
);
1301 /* Do nothing special. */
1305 output_operand_lossage ("invalid operand output code");
1308 switch (GET_CODE (x
))
1314 fputs (reg_names
[REGNO (x
)], file
);
1318 current_frame_info
.stld_sz
= 1;
1321 switch (GET_CODE (addr
))
1324 offset
= GEN_INT (GET_MODE_SIZE (GET_MODE (x
)));
1325 addr
= XEXP (addr
, 0);
1328 offset
= GEN_INT (-GET_MODE_SIZE (GET_MODE (x
)));
1329 addr
= XEXP (addr
, 0);
1332 offset
= XEXP (XEXP (addr
, 1), 1);
1333 addr
= XEXP (addr
, 0);
1339 output_address (GET_MODE (x
), addr
);
1344 if (CONST_INT_P (offset
)) switch (GET_MODE_SIZE (GET_MODE (x
)))
1349 offset
= GEN_INT (INTVAL (offset
) >> 3);
1352 offset
= GEN_INT (INTVAL (offset
) >> 2);
1355 offset
= GEN_INT (INTVAL (offset
) >> 1);
1360 output_address (GET_MODE (x
), offset
);
1364 /* We handle SFmode constants here as output_addr_const doesn't. */
1365 if (GET_MODE (x
) == SFmode
)
1369 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x
), l
);
1370 fprintf (file
, "%s0x%08lx", IMMEDIATE_PREFIX
, l
);
1374 /* Let output_addr_const deal with it. */
1376 fprintf(file
,"%s",IMMEDIATE_PREFIX
);
1377 if (code
== 'C' || code
== 'X')
1379 fprintf (file
, "%ld",
1380 (long) (INTVAL (x
) / current_frame_info
.stld_sz
));
1385 output_addr_const (file
, x
);
1390 /* Print a memory address as an operand to reference that memory location. */
1393 epiphany_print_operand_address (FILE *file
, machine_mode
/*mode*/, rtx addr
)
1395 register rtx base
, index
= 0;
1398 switch (GET_CODE (addr
))
1401 fputs (reg_names
[REGNO (addr
)], file
);
1404 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr
))
1406 output_addr_const (file
, addr
);
1410 output_addr_const (file
, addr
);
1414 if (GET_CODE (XEXP (addr
, 0)) == CONST_INT
)
1415 offset
= INTVAL (XEXP (addr
, 0)), base
= XEXP (addr
, 1);
1416 else if (GET_CODE (XEXP (addr
, 1)) == CONST_INT
)
1417 offset
= INTVAL (XEXP (addr
, 1)), base
= XEXP (addr
, 0);
1419 base
= XEXP (addr
, 0), index
= XEXP (addr
, 1);
1420 gcc_assert (GET_CODE (base
) == REG
);
1421 fputs (reg_names
[REGNO (base
)], file
);
1425 ** ++rk quirky method to scale offset for ld/str.......
1427 fprintf (file
, ",%s%d", IMMEDIATE_PREFIX
,
1428 offset
/current_frame_info
.stld_sz
);
1432 switch (GET_CODE (index
))
1435 fprintf (file
, ",%s", reg_names
[REGNO (index
)]);
1438 fputc (',', file
), output_addr_const (file
, index
);
1445 case PRE_INC
: case PRE_DEC
: case POST_INC
: case POST_DEC
: case POST_MODIFY
:
1446 /* We shouldn't get here as we've lost the mode of the memory object
1447 (which says how much to inc/dec by.
1448 FIXME: We have the mode now, address printing can be moved into this
1453 output_addr_const (file
, addr
);
1459 epiphany_final_prescan_insn (rtx_insn
*insn ATTRIBUTE_UNUSED
,
1460 rtx
*opvec ATTRIBUTE_UNUSED
,
1461 int noperands ATTRIBUTE_UNUSED
)
1463 int i
= epiphany_n_nops
;
1464 rtx pat ATTRIBUTE_UNUSED
;
1467 fputs ("\tnop\n", asm_out_file
);
1471 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1474 epiphany_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
1476 HOST_WIDE_INT size
= int_size_in_bytes (type
);
1478 if (AGGREGATE_TYPE_P (type
)
1479 && (TYPE_MODE (type
) == BLKmode
|| TYPE_NEEDS_CONSTRUCTING (type
)))
1481 return (size
== -1 || size
> 8);
1484 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1485 passed by reference. */
1488 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED
,
1489 machine_mode mode
, const_tree type
,
1490 bool named ATTRIBUTE_UNUSED
)
1494 if (AGGREGATE_TYPE_P (type
)
1495 && (mode
== BLKmode
|| TYPE_NEEDS_CONSTRUCTING (type
)))
1503 epiphany_function_value (const_tree ret_type
,
1504 const_tree fn_decl_or_type ATTRIBUTE_UNUSED
,
1505 bool outgoing ATTRIBUTE_UNUSED
)
1509 mode
= TYPE_MODE (ret_type
);
1510 /* We must change the mode like PROMOTE_MODE does.
1511 ??? PROMOTE_MODE is ignored for non-scalar types.
1512 The set of types tested here has to be kept in sync
1513 with the one in explow.c:promote_mode. */
1514 if (GET_MODE_CLASS (mode
) == MODE_INT
1515 && GET_MODE_SIZE (mode
) < 4
1516 && (TREE_CODE (ret_type
) == INTEGER_TYPE
1517 || TREE_CODE (ret_type
) == ENUMERAL_TYPE
1518 || TREE_CODE (ret_type
) == BOOLEAN_TYPE
1519 || TREE_CODE (ret_type
) == OFFSET_TYPE
))
1521 return gen_rtx_REG (mode
, 0);
1525 epiphany_libcall_value (machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
1527 return gen_rtx_REG (mode
, 0);
1531 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED
)
1536 /* Fix up invalid option settings. */
1538 epiphany_override_options (void)
1540 if (epiphany_stack_offset
< 4)
1541 error ("stack_offset must be at least 4");
1542 if (epiphany_stack_offset
& 3)
1543 error ("stack_offset must be a multiple of 4");
1544 epiphany_stack_offset
= (epiphany_stack_offset
+ 3) & -4;
1545 if (!TARGET_SOFT_CMPSF
)
1546 flag_finite_math_only
= 1;
1548 /* This needs to be done at start up. It's convenient to do it here. */
1552 /* For a DImode load / store SET, make a SImode set for a
1553 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1556 frame_subreg_note (rtx set
, int offset
)
1558 rtx src
= simplify_gen_subreg (SImode
, SET_SRC (set
), DImode
, offset
);
1559 rtx dst
= simplify_gen_subreg (SImode
, SET_DEST (set
), DImode
, offset
);
1561 set
= gen_rtx_SET (dst
,src
);
1562 RTX_FRAME_RELATED_P (set
) = 1;
1570 rtx note
= NULL_RTX
;
1573 if (GET_CODE (x
) == PARALLEL
)
1575 rtx part
= XVECEXP (x
, 0, 0);
1577 if (GET_MODE (SET_DEST (part
)) == DImode
)
1579 note
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (XVECLEN (x
, 0) + 1));
1580 XVECEXP (note
, 0, 0) = frame_subreg_note (part
, 0);
1581 XVECEXP (note
, 0, 1) = frame_subreg_note (part
, UNITS_PER_WORD
);
1582 for (i
= XVECLEN (x
, 0) - 1; i
>= 1; i
--)
1584 part
= copy_rtx (XVECEXP (x
, 0, i
));
1586 if (GET_CODE (part
) == SET
)
1587 RTX_FRAME_RELATED_P (part
) = 1;
1588 XVECEXP (note
, 0, i
+ 1) = part
;
1593 for (i
= XVECLEN (x
, 0) - 1; i
>= 0; i
--)
1595 part
= XVECEXP (x
, 0, i
);
1597 if (GET_CODE (part
) == SET
)
1598 RTX_FRAME_RELATED_P (part
) = 1;
1602 else if (GET_CODE (x
) == SET
&& GET_MODE (SET_DEST (x
)) == DImode
)
1603 note
= gen_rtx_PARALLEL (VOIDmode
,
1604 gen_rtvec (2, frame_subreg_note (x
, 0),
1605 frame_subreg_note (x
, UNITS_PER_WORD
)));
1606 insn
= emit_insn (x
);
1607 RTX_FRAME_RELATED_P (insn
) = 1;
1609 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
, note
);
1614 frame_move_insn (rtx to
, rtx from
)
1616 return frame_insn (gen_rtx_SET (to
, from
));
1619 /* Generate a MEM referring to a varargs argument slot. */
1622 gen_varargs_mem (machine_mode mode
, rtx addr
)
1624 rtx mem
= gen_rtx_MEM (mode
, addr
);
1625 MEM_NOTRAP_P (mem
) = 1;
1626 set_mem_alias_set (mem
, get_varargs_alias_set ());
1630 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1631 If EPILOGUE_P is 0, save; if it is one, restore.
1632 ADDR is the stack slot to save the first register to; subsequent
1633 registers are written to lower addresses.
1634 However, the order of register pairs can be reversed in order to
1635 use double-word load-store instructions. Likewise, an unpaired single
1636 word save slot can be skipped while double saves are carried out, and
1637 reused when a single register is to be saved. */
1640 epiphany_emit_save_restore (int min
, int limit
, rtx addr
, int epilogue_p
)
1644 = current_frame_info
.first_slot
>= 0 ? epiphany_stack_offset
: 0;
1645 rtx skipped_mem
= NULL_RTX
;
1646 int last_saved
= limit
- 1;
1649 while (last_saved
>= 0
1650 && !TEST_HARD_REG_BIT (current_frame_info
.gmask
, last_saved
))
1652 for (i
= 0; i
< limit
; i
++)
1654 machine_mode mode
= word_mode
;
1657 rtx (*gen_mem
) (machine_mode
, rtx
) = gen_frame_mem
;
1659 /* Make sure we push the arguments in the right order. */
1660 if (n
< MAX_EPIPHANY_PARM_REGS
&& crtl
->args
.pretend_args_size
)
1662 n
= MAX_EPIPHANY_PARM_REGS
- 1 - n
;
1663 gen_mem
= gen_varargs_mem
;
1665 if (stack_offset
== current_frame_info
.first_slot_size
1666 && current_frame_info
.first_slot
>= 0)
1668 if (current_frame_info
.first_slot_size
> UNITS_PER_WORD
)
1671 addr
= plus_constant (Pmode
, addr
,
1672 - (HOST_WIDE_INT
) UNITS_PER_WORD
);
1674 if (i
-- < min
|| !epilogue_p
)
1676 n
= current_frame_info
.first_slot
;
1677 gen_mem
= gen_frame_mem
;
1679 else if (n
== UNKNOWN_REGNUM
1680 && stack_offset
> current_frame_info
.first_slot_size
)
1685 else if (!TEST_HARD_REG_BIT (current_frame_info
.gmask
, n
))
1690 /* Check for a register pair to save. */
1692 && (n
>= MAX_EPIPHANY_PARM_REGS
|| crtl
->args
.pretend_args_size
== 0)
1693 && (n
& 1) == 0 && n
+1 < limit
1694 && TEST_HARD_REG_BIT (current_frame_info
.gmask
, n
+1))
1696 /* If it fits in the current stack slot pair, place it there. */
1697 if (GET_CODE (addr
) == PLUS
&& (stack_offset
& 7) == 0
1698 && stack_offset
!= 2 * UNITS_PER_WORD
1699 && (current_frame_info
.last_slot
< 0
1700 || INTVAL (XEXP (addr
, 1)) != UNITS_PER_WORD
)
1701 && (n
+1 != last_saved
|| !skipped_mem
))
1705 addr
= plus_constant (Pmode
, addr
,
1706 - (HOST_WIDE_INT
) UNITS_PER_WORD
);
1708 /* If it fits in the following stack slot pair, that's fine, too. */
1709 else if (GET_CODE (addr
) == PLUS
&& (stack_offset
& 7) == 4
1710 && stack_offset
!= 2 * UNITS_PER_WORD
1711 && stack_offset
!= 3 * UNITS_PER_WORD
1712 && (current_frame_info
.last_slot
< 0
1713 || INTVAL (XEXP (addr
, 1)) != 2 * UNITS_PER_WORD
)
1714 && n
+ 1 != last_saved
)
1716 gcc_assert (!skipped_mem
);
1717 stack_offset
-= GET_MODE_SIZE (mode
);
1718 skipped_mem
= gen_mem (mode
, addr
);
1721 addr
= plus_constant (Pmode
, addr
,
1722 - (HOST_WIDE_INT
) 2 * UNITS_PER_WORD
);
1725 reg
= gen_rtx_REG (mode
, n
);
1726 if (mode
!= DImode
&& skipped_mem
)
1729 mem
= gen_mem (mode
, addr
);
1731 /* If we are loading / storing LR, note the offset that
1732 gen_reload_insi_ra requires. Since GPR_LR is even,
1733 we only need to test n, even if mode is DImode. */
1734 gcc_assert ((GPR_LR
& 1) == 0);
1737 long lr_slot_offset
= 0;
1738 rtx m_addr
= XEXP (mem
, 0);
1740 if (GET_CODE (m_addr
) == PLUS
)
1741 lr_slot_offset
= INTVAL (XEXP (m_addr
, 1));
1742 if (frame_pointer_needed
)
1743 lr_slot_offset
+= (current_frame_info
.first_slot_offset
1744 - current_frame_info
.total_size
);
1745 if (MACHINE_FUNCTION (cfun
)->lr_slot_known
)
1746 gcc_assert (MACHINE_FUNCTION (cfun
)->lr_slot_offset
1748 MACHINE_FUNCTION (cfun
)->lr_slot_offset
= lr_slot_offset
;
1749 MACHINE_FUNCTION (cfun
)->lr_slot_known
= 1;
1753 frame_move_insn (mem
, reg
);
1754 else if (n
>= MAX_EPIPHANY_PARM_REGS
|| !crtl
->args
.pretend_args_size
)
1755 emit_move_insn (reg
, mem
);
1756 if (mem
== skipped_mem
)
1758 skipped_mem
= NULL_RTX
;
1762 addr
= plus_constant (Pmode
, addr
, -(HOST_WIDE_INT
) UNITS_PER_WORD
);
1763 stack_offset
-= GET_MODE_SIZE (mode
);
1768 epiphany_expand_prologue (void)
1771 enum epiphany_function_type fn_type
;
1772 rtx addr
, mem
, off
, reg
;
1774 if (!current_frame_info
.initialized
)
1775 epiphany_compute_frame_size (get_frame_size ());
1777 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1778 if (flag_stack_usage_info
)
1779 current_function_static_stack_size
= current_frame_info
.total_size
;
1781 fn_type
= epiphany_compute_function_type (current_function_decl
);
1782 interrupt_p
= EPIPHANY_INTERRUPT_P (fn_type
);
1786 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1787 - (HOST_WIDE_INT
) 2 * UNITS_PER_WORD
);
1788 if (!lookup_attribute ("forwarder_section",
1789 DECL_ATTRIBUTES (current_function_decl
))
1790 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl
),
1792 frame_move_insn (gen_frame_mem (DImode
, addr
),
1793 gen_rtx_REG (DImode
, GPR_0
));
1794 frame_move_insn (gen_rtx_REG (SImode
, GPR_0
),
1795 gen_rtx_REG (word_mode
, STATUS_REGNUM
));
1796 frame_move_insn (gen_rtx_REG (SImode
, GPR_1
),
1797 gen_rtx_REG (word_mode
, IRET_REGNUM
));
1798 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1799 off
= GEN_INT (-current_frame_info
.first_slot_offset
);
1800 frame_insn (gen_stack_adjust_add (off
, mem
));
1801 if (!epiphany_uninterruptible_p (current_function_decl
))
1802 emit_insn (gen_gie ());
1803 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1804 current_frame_info
.first_slot_offset
1805 - (HOST_WIDE_INT
) 3 * UNITS_PER_WORD
);
1809 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1810 epiphany_stack_offset
1811 - (HOST_WIDE_INT
) UNITS_PER_WORD
);
1812 epiphany_emit_save_restore (0, current_frame_info
.small_threshold
,
1814 /* Allocate register save area; for small to medium size frames,
1815 allocate the entire frame; this is joint with one register save. */
1816 if (current_frame_info
.first_slot
>= 0)
1819 = (current_frame_info
.first_slot_size
== UNITS_PER_WORD
1820 ? word_mode
: DImode
);
1822 off
= GEN_INT (-current_frame_info
.first_slot_offset
);
1823 mem
= gen_frame_mem (BLKmode
,
1824 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, off
));
1825 frame_insn (gen_stack_adjust_str
1826 (gen_frame_mem (mode
, stack_pointer_rtx
),
1827 gen_rtx_REG (mode
, current_frame_info
.first_slot
),
1829 addr
= plus_constant (Pmode
, addr
,
1830 current_frame_info
.first_slot_offset
);
1833 epiphany_emit_save_restore (current_frame_info
.small_threshold
,
1834 FIRST_PSEUDO_REGISTER
, addr
, 0);
1835 if (current_frame_info
.need_fp
)
1836 frame_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
);
1837 /* For large frames, allocate bulk of frame. This is usually joint with one
1839 if (current_frame_info
.last_slot
>= 0)
1844 gcc_assert (current_frame_info
.last_slot
!= GPR_FP
1845 || (!current_frame_info
.need_fp
1846 && current_frame_info
.first_slot
< 0));
1847 off
= GEN_INT (-current_frame_info
.last_slot_offset
);
1848 mem
= gen_frame_mem (BLKmode
,
1849 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, off
));
1850 ip
= gen_rtx_REG (Pmode
, GPR_IP
);
1851 frame_move_insn (ip
, off
);
1852 reg
= gen_rtx_REG (word_mode
, current_frame_info
.last_slot
),
1853 mem2
= gen_frame_mem (word_mode
, stack_pointer_rtx
),
1854 insn
= frame_insn (gen_stack_adjust_str (mem2
, reg
, ip
, mem
));
1855 /* Instruction scheduling can separate the instruction setting IP from
1856 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1857 temporary register is. Example: _gcov.o */
1858 note
= gen_rtx_SET (stack_pointer_rtx
,
1859 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, off
));
1860 note
= gen_rtx_PARALLEL (VOIDmode
,
1861 gen_rtvec (2, gen_rtx_SET (mem2
, reg
), note
));
1862 add_reg_note (insn
, REG_FRAME_RELATED_EXPR
, note
);
1864 /* If there is only one or no register to save, yet we have a large frame,
1866 else if (current_frame_info
.last_slot_offset
)
1868 mem
= gen_frame_mem (BLKmode
,
1869 plus_constant (Pmode
, stack_pointer_rtx
,
1870 current_frame_info
.last_slot_offset
));
1871 off
= GEN_INT (-current_frame_info
.last_slot_offset
);
1872 if (!SIMM11 (INTVAL (off
)))
1874 reg
= gen_rtx_REG (Pmode
, GPR_IP
);
1875 frame_move_insn (reg
, off
);
1878 frame_insn (gen_stack_adjust_add (off
, mem
));
1883 epiphany_expand_epilogue (int sibcall_p
)
1886 enum epiphany_function_type fn_type
;
1887 rtx mem
, addr
, reg
, off
;
1888 HOST_WIDE_INT restore_offset
;
1890 fn_type
= epiphany_compute_function_type( current_function_decl
);
1891 interrupt_p
= EPIPHANY_INTERRUPT_P (fn_type
);
1893 /* For variable frames, deallocate bulk of frame. */
1894 if (current_frame_info
.need_fp
)
1896 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1897 emit_insn (gen_stack_adjust_mov (mem
));
1899 /* Else for large static frames, deallocate bulk of frame. */
1900 else if (current_frame_info
.last_slot_offset
)
1902 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1903 reg
= gen_rtx_REG (Pmode
, GPR_IP
);
1904 emit_move_insn (reg
, GEN_INT (current_frame_info
.last_slot_offset
));
1905 emit_insn (gen_stack_adjust_add (reg
, mem
));
1907 restore_offset
= (interrupt_p
1908 ? - 3 * UNITS_PER_WORD
1909 : epiphany_stack_offset
- (HOST_WIDE_INT
) UNITS_PER_WORD
);
1910 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1911 (current_frame_info
.first_slot_offset
1913 epiphany_emit_save_restore (current_frame_info
.small_threshold
,
1914 FIRST_PSEUDO_REGISTER
, addr
, 1);
1916 if (interrupt_p
&& !epiphany_uninterruptible_p (current_function_decl
))
1917 emit_insn (gen_gid ());
1919 off
= GEN_INT (current_frame_info
.first_slot_offset
);
1920 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1921 /* For large / variable size frames, deallocating the register save area is
1922 joint with one register restore; for medium size frames, we use a
1923 dummy post-increment load to dealloacte the whole frame. */
1924 if (!SIMM11 (INTVAL (off
)) || current_frame_info
.last_slot
>= 0)
1926 emit_insn (gen_stack_adjust_ldr
1927 (gen_rtx_REG (word_mode
,
1928 (current_frame_info
.last_slot
>= 0
1929 ? current_frame_info
.last_slot
: GPR_IP
)),
1930 gen_frame_mem (word_mode
, stack_pointer_rtx
),
1934 /* While for small frames, we deallocate the entire frame with one add. */
1935 else if (INTVAL (off
))
1937 emit_insn (gen_stack_adjust_add (off
, mem
));
1941 emit_move_insn (gen_rtx_REG (word_mode
, STATUS_REGNUM
),
1942 gen_rtx_REG (SImode
, GPR_0
));
1943 emit_move_insn (gen_rtx_REG (word_mode
, IRET_REGNUM
),
1944 gen_rtx_REG (SImode
, GPR_1
));
1945 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1946 - (HOST_WIDE_INT
) 2 * UNITS_PER_WORD
);
1947 emit_move_insn (gen_rtx_REG (DImode
, GPR_0
),
1948 gen_frame_mem (DImode
, addr
));
1950 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1951 epiphany_stack_offset
- (HOST_WIDE_INT
) UNITS_PER_WORD
);
1952 epiphany_emit_save_restore (0, current_frame_info
.small_threshold
, addr
, 1);
1956 emit_jump_insn (gen_return_internal_interrupt());
1958 emit_jump_insn (gen_return_i ());
1963 epiphany_initial_elimination_offset (int from
, int to
)
1965 epiphany_compute_frame_size (get_frame_size ());
1966 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
1967 return current_frame_info
.total_size
- current_frame_info
.reg_size
;
1968 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1969 return current_frame_info
.first_slot_offset
- current_frame_info
.reg_size
;
1970 if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
1971 return (current_frame_info
.total_size
1972 - ((current_frame_info
.pretend_size
+ 4) & -8));
1973 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1974 return (current_frame_info
.first_slot_offset
1975 - ((current_frame_info
.pretend_size
+ 4) & -8));
1980 epiphany_regno_rename_ok (unsigned, unsigned dst
)
1982 enum epiphany_function_type fn_type
;
1984 fn_type
= epiphany_compute_function_type (current_function_decl
);
1985 if (!EPIPHANY_INTERRUPT_P (fn_type
))
1987 if (df_regs_ever_live_p (dst
))
1993 epiphany_issue_rate (void)
1998 /* Function to update the integer COST
1999 based on the relationship between INSN that is dependent on
2000 DEP_INSN through the dependence LINK. The default is to make no
2001 adjustment to COST. This can be used for example to specify to
2002 the scheduler that an output- or anti-dependence does not incur
2003 the same cost as a data-dependence. The return value should be
2004 the new value for COST. */
2006 epiphany_adjust_cost (rtx_insn
*insn
, int dep_type
, rtx_insn
*dep_insn
,
2007 int cost
, unsigned int)
2013 if (recog_memoized (insn
) < 0
2014 || recog_memoized (dep_insn
) < 0)
2017 dep_set
= single_set (dep_insn
);
2019 /* The latency that we specify in the scheduling description refers
2020 to the actual output, not to an auto-increment register; for that,
2021 the latency is one. */
2022 if (dep_set
&& MEM_P (SET_SRC (dep_set
)) && cost
> 1)
2024 rtx set
= single_set (insn
);
2027 && !reg_overlap_mentioned_p (SET_DEST (dep_set
), SET_SRC (set
))
2028 && (!MEM_P (SET_DEST (set
))
2029 || !reg_overlap_mentioned_p (SET_DEST (dep_set
),
2030 XEXP (SET_DEST (set
), 0))))
2037 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
2039 #define RTX_OK_FOR_BASE_P(X) \
2040 (REG_P (X) && REG_OK_FOR_BASE_P (X))
2042 #define RTX_OK_FOR_INDEX_P(MODE, X) \
2043 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
2044 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
2045 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
2047 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
2048 (GET_CODE (X) == PLUS \
2049 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
2050 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
2051 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
2054 epiphany_legitimate_address_p (machine_mode mode
, rtx x
, bool strict
)
2056 #define REG_OK_FOR_BASE_P(X) \
2057 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
2058 if (RTX_OK_FOR_BASE_P (x
))
2060 if (RTX_FRAME_OFFSET_P (x
))
2062 if (LEGITIMATE_OFFSET_ADDRESS_P (mode
, x
))
2064 /* If this is a misaligned stack access, don't force it to reg+index. */
2065 if (GET_MODE_SIZE (mode
) == 8
2066 && GET_CODE (x
) == PLUS
&& XEXP (x
, 0) == stack_pointer_rtx
2067 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
2068 && !(INTVAL (XEXP (x
, 1)) & 3)
2069 && INTVAL (XEXP (x
, 1)) >= -2047 * 4
2070 && INTVAL (XEXP (x
, 1)) <= 2046 * 4)
2073 && (GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == POST_INC
)
2074 && RTX_OK_FOR_BASE_P (XEXP ((x
), 0)))
2076 if ((TARGET_POST_MODIFY
|| reload_completed
)
2077 && GET_CODE (x
) == POST_MODIFY
2078 && GET_CODE (XEXP ((x
), 1)) == PLUS
2079 && rtx_equal_p (XEXP ((x
), 0), XEXP (XEXP ((x
), 1), 0))
2080 && LEGITIMATE_OFFSET_ADDRESS_P (mode
, XEXP ((x
), 1)))
2082 if (mode
== BLKmode
)
2083 return epiphany_legitimate_address_p (SImode
, x
, strict
);
2088 epiphany_secondary_reload (bool in_p
, rtx x
, reg_class_t rclass
,
2089 machine_mode mode ATTRIBUTE_UNUSED
,
2090 secondary_reload_info
*sri
)
2092 /* This could give more reload inheritance, but we are missing some
2093 reload infrastructure. */
2095 if (in_p
&& GET_CODE (x
) == UNSPEC
2096 && satisfies_constraint_Sra (x
) && !satisfies_constraint_Rra (x
))
2098 gcc_assert (rclass
== GENERAL_REGS
);
2099 sri
->icode
= CODE_FOR_reload_insi_ra
;
2106 epiphany_is_long_call_p (rtx x
)
2108 tree decl
= SYMBOL_REF_DECL (x
);
2109 bool ret_val
= !TARGET_SHORT_CALLS
;
2112 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2113 probably encode information via encode_section_info, and also
2114 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2118 attrs
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
2119 if (lookup_attribute ("long_call", attrs
))
2121 else if (lookup_attribute ("short_call", attrs
))
2128 epiphany_small16 (rtx x
)
2131 rtx offs ATTRIBUTE_UNUSED
= const0_rtx
;
2133 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
2135 base
= XEXP (XEXP (x
, 0), 0);
2136 offs
= XEXP (XEXP (x
, 0), 1);
2138 if (GET_CODE (base
) == SYMBOL_REF
&& SYMBOL_REF_FUNCTION_P (base
)
2139 && epiphany_is_long_call_p (base
))
2141 return TARGET_SMALL16
!= 0;
2144 /* Return nonzero if it is ok to make a tail-call to DECL. */
2146 epiphany_function_ok_for_sibcall (tree decl
, tree exp
)
2148 bool cfun_interrupt_p
, call_interrupt_p
;
2150 cfun_interrupt_p
= EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2151 (current_function_decl
));
2153 call_interrupt_p
= EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl
));
2156 tree fn_type
= TREE_TYPE (CALL_EXPR_FN (exp
));
2158 gcc_assert (POINTER_TYPE_P (fn_type
));
2159 fn_type
= TREE_TYPE (fn_type
);
2160 gcc_assert (TREE_CODE (fn_type
) == FUNCTION_TYPE
2161 || TREE_CODE (fn_type
) == METHOD_TYPE
);
2163 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type
)) != NULL
;
2166 /* Don't tailcall from or to an ISR routine - although we could in
2167 principle tailcall from one ISR routine to another, we'd need to
2168 handle this in sibcall_epilogue to make it work. */
2169 if (cfun_interrupt_p
|| call_interrupt_p
)
2172 /* Everything else is ok. */
2176 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2178 Return true iff the type of T has the uninterruptible attribute.
2179 If T is NULL, return false. */
2181 epiphany_uninterruptible_p (tree t
)
2187 attrs
= TYPE_ATTRIBUTES (TREE_TYPE (t
));
2188 if (lookup_attribute ("disinterrupt", attrs
))
2195 epiphany_call_uninterruptible_p (rtx mem
)
2197 rtx addr
= XEXP (mem
, 0);
2200 if (GET_CODE (addr
) == SYMBOL_REF
)
2201 t
= SYMBOL_REF_DECL (addr
);
2204 return epiphany_uninterruptible_p (t
);
2208 epiphany_promote_function_mode (const_tree type
, machine_mode mode
,
2209 int *punsignedp ATTRIBUTE_UNUSED
,
2210 const_tree funtype ATTRIBUTE_UNUSED
,
2211 int for_return ATTRIBUTE_UNUSED
)
2215 return promote_mode (type
, mode
, &dummy
);
2219 epiphany_conditional_register_usage (void)
2223 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
2225 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
2226 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
2228 if (TARGET_HALF_REG_FILE
)
2230 for (i
= 32; i
<= 63; i
++)
2233 call_used_regs
[i
] = 1;
2236 if (epiphany_m1reg
>= 0)
2238 fixed_regs
[epiphany_m1reg
] = 1;
2239 call_used_regs
[epiphany_m1reg
] = 1;
2241 if (!TARGET_PREFER_SHORT_INSN_REGS
)
2242 CLEAR_HARD_REG_SET (reg_class_contents
[SHORT_INSN_REGS
]);
2243 COPY_HARD_REG_SET (reg_class_contents
[SIBCALL_REGS
],
2244 reg_class_contents
[GENERAL_REGS
]);
2245 /* It would be simpler and quicker if we could just use
2246 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2247 it is set up later by our caller. */
2248 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
2249 if (!call_used_regs
[i
])
2250 CLEAR_HARD_REG_BIT (reg_class_contents
[SIBCALL_REGS
], i
);
2253 /* Determine where to put an argument to a function.
2254 Value is zero to push the argument on the stack,
2255 or a hard register in which to store the argument.
2257 MODE is the argument's machine mode.
2258 TYPE is the data type of the argument (as a tree).
2259 This is null for libcalls where that information may
2261 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2262 the preceding args and about the function being called.
2263 NAMED is nonzero if this argument is a named parameter
2264 (otherwise it is an extra parameter matching an ellipsis). */
2265 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2266 registers and the rest are pushed. */
2268 epiphany_function_arg (cumulative_args_t cum_v
, machine_mode mode
,
2269 const_tree type
, bool named ATTRIBUTE_UNUSED
)
2271 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
2273 if (PASS_IN_REG_P (cum
, mode
, type
))
2274 return gen_rtx_REG (mode
, ROUND_ADVANCE_CUM (cum
, mode
, type
));
2278 /* Update the data in CUM to advance over an argument
2279 of mode MODE and data type TYPE.
2280 (TYPE is null for libcalls where that information may not be available.) */
2282 epiphany_function_arg_advance (cumulative_args_t cum_v
, machine_mode mode
,
2283 const_tree type
, bool named ATTRIBUTE_UNUSED
)
2285 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2287 *cum
= ROUND_ADVANCE_CUM (*cum
, mode
, type
) + ROUND_ADVANCE_ARG (mode
, type
);
2290 /* Nested function support.
2291 An epiphany trampoline looks like this:
2292 mov r16,%low(fnaddr)
2293 movt r16,%high(fnaddr)
2298 #define EPIPHANY_LOW_RTX(X) \
2299 (gen_rtx_IOR (SImode, \
2300 gen_rtx_ASHIFT (SImode, \
2301 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2302 gen_rtx_ASHIFT (SImode, \
2303 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2304 #define EPIPHANY_HIGH_RTX(X) \
2305 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2307 /* Emit RTL insns to initialize the variable parts of a trampoline.
2308 FNADDR is an RTX for the address of the function's pure code.
2309 CXT is an RTX for the static chain value for the function. */
2311 epiphany_trampoline_init (rtx tramp_mem
, tree fndecl
, rtx cxt
)
2313 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
2314 rtx tramp
= force_reg (Pmode
, XEXP (tramp_mem
, 0));
2316 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 0)),
2317 gen_rtx_IOR (SImode
, GEN_INT (0x4002000b),
2318 EPIPHANY_LOW_RTX (fnaddr
)));
2319 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 4)),
2320 gen_rtx_IOR (SImode
, GEN_INT (0x5002000b),
2321 EPIPHANY_HIGH_RTX (fnaddr
)));
2322 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 8)),
2323 gen_rtx_IOR (SImode
, GEN_INT (0x2002800b),
2324 EPIPHANY_LOW_RTX (cxt
)));
2325 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 12)),
2326 gen_rtx_IOR (SImode
, GEN_INT (0x3002800b),
2327 EPIPHANY_HIGH_RTX (cxt
)));
2328 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 16)),
2329 GEN_INT (0x0802014f));
2333 epiphany_optimize_mode_switching (int entity
)
2335 if (MACHINE_FUNCTION (cfun
)->sw_entities_processed
& (1 << entity
))
2339 case EPIPHANY_MSW_ENTITY_AND
:
2340 case EPIPHANY_MSW_ENTITY_OR
:
2341 case EPIPHANY_MSW_ENTITY_CONFIG
:
2343 case EPIPHANY_MSW_ENTITY_NEAREST
:
2344 case EPIPHANY_MSW_ENTITY_TRUNC
:
2345 return optimize
> 0;
2346 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
:
2347 return MACHINE_FUNCTION (cfun
)->unknown_mode_uses
!= 0;
2348 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN
:
2349 return (MACHINE_FUNCTION (cfun
)->sw_entities_processed
2350 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
)) != 0;
2351 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
:
2352 return optimize
== 0 || current_pass
== pass_mode_switch_use
;
2358 epiphany_mode_priority (int entity
, int priority
)
2360 if (entity
== EPIPHANY_MSW_ENTITY_AND
|| entity
== EPIPHANY_MSW_ENTITY_OR
2361 || entity
== EPIPHANY_MSW_ENTITY_CONFIG
)
2366 case 4: return FP_MODE_ROUND_UNKNOWN
;
2367 case 5: return FP_MODE_NONE
;
2368 default: gcc_unreachable ();
2370 switch ((enum attr_fp_mode
) epiphany_normal_fp_mode
)
2375 case 0: return FP_MODE_INT
;
2376 case 1: return epiphany_normal_fp_rounding
;
2377 case 2: return (epiphany_normal_fp_rounding
== FP_MODE_ROUND_NEAREST
2378 ? FP_MODE_ROUND_TRUNC
: FP_MODE_ROUND_NEAREST
);
2379 case 3: return FP_MODE_CALLER
;
2381 case FP_MODE_ROUND_NEAREST
:
2382 case FP_MODE_CALLER
:
2385 case 0: return FP_MODE_ROUND_NEAREST
;
2386 case 1: return FP_MODE_ROUND_TRUNC
;
2387 case 2: return FP_MODE_INT
;
2388 case 3: return FP_MODE_CALLER
;
2390 case FP_MODE_ROUND_TRUNC
:
2393 case 0: return FP_MODE_ROUND_TRUNC
;
2394 case 1: return FP_MODE_ROUND_NEAREST
;
2395 case 2: return FP_MODE_INT
;
2396 case 3: return FP_MODE_CALLER
;
2398 case FP_MODE_ROUND_UNKNOWN
:
2406 epiphany_mode_needed (int entity
, rtx_insn
*insn
)
2408 enum attr_fp_mode mode
;
2410 if (recog_memoized (insn
) < 0)
2412 if (entity
== EPIPHANY_MSW_ENTITY_AND
2413 || entity
== EPIPHANY_MSW_ENTITY_OR
2414 || entity
== EPIPHANY_MSW_ENTITY_CONFIG
)
2416 return FP_MODE_NONE
;
2418 mode
= get_attr_fp_mode (insn
);
2422 case EPIPHANY_MSW_ENTITY_AND
:
2423 return mode
!= FP_MODE_NONE
&& mode
!= FP_MODE_INT
? 1 : 2;
2424 case EPIPHANY_MSW_ENTITY_OR
:
2425 return mode
== FP_MODE_INT
? 1 : 2;
2426 case EPIPHANY_MSW_ENTITY_CONFIG
:
2427 /* We must know/save config before we set it to something else.
2428 Where we need the original value, we are fine with having it
2429 just unchanged from the function start.
2430 Because of the nature of the mode switching optimization,
2431 a restore will be dominated by a clobber. */
2432 if (mode
!= FP_MODE_NONE
&& mode
!= FP_MODE_CALLER
)
2434 /* A cpecial case are abnormal edges, which are deemed to clobber
2435 the mode as well. We need to pin this effect on a actually
2436 dominating insn, and one where the frame can be accessed, too, in
2437 case the pseudo used to save CONFIG doesn't get a hard register. */
2438 if (CALL_P (insn
) && find_reg_note (insn
, REG_EH_REGION
, NULL_RTX
))
2441 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN
:
2442 if (recog_memoized (insn
) == CODE_FOR_set_fp_mode
)
2443 mode
= (enum attr_fp_mode
) epiphany_mode_after (entity
, mode
, insn
);
2445 case EPIPHANY_MSW_ENTITY_NEAREST
:
2446 case EPIPHANY_MSW_ENTITY_TRUNC
:
2447 if (mode
== FP_MODE_ROUND_UNKNOWN
)
2449 MACHINE_FUNCTION (cfun
)->unknown_mode_uses
++;
2450 return FP_MODE_NONE
;
2453 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
:
2454 if (mode
== FP_MODE_ROUND_NEAREST
|| mode
== FP_MODE_ROUND_TRUNC
)
2455 return FP_MODE_ROUND_UNKNOWN
;
2457 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
:
2458 if (mode
== FP_MODE_ROUND_UNKNOWN
)
2459 return epiphany_normal_fp_rounding
;
2467 epiphany_mode_entry_exit (int entity
, bool exit
)
2469 int normal_mode
= epiphany_normal_fp_mode
;
2471 MACHINE_FUNCTION (cfun
)->sw_entities_processed
|= (1 << entity
);
2472 if (epiphany_is_interrupt_p (current_function_decl
))
2473 normal_mode
= FP_MODE_CALLER
;
2476 case EPIPHANY_MSW_ENTITY_AND
:
2478 return normal_mode
!= FP_MODE_INT
? 1 : 2;
2480 case EPIPHANY_MSW_ENTITY_OR
:
2482 return normal_mode
== FP_MODE_INT
? 1 : 2;
2484 case EPIPHANY_MSW_ENTITY_CONFIG
:
2487 return normal_mode
== FP_MODE_CALLER
? 0 : 1;
2488 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
:
2489 if (normal_mode
== FP_MODE_ROUND_NEAREST
2490 || normal_mode
== FP_MODE_ROUND_TRUNC
)
2491 return FP_MODE_ROUND_UNKNOWN
;
2493 case EPIPHANY_MSW_ENTITY_NEAREST
:
2494 case EPIPHANY_MSW_ENTITY_TRUNC
:
2495 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN
:
2496 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
:
2504 epiphany_mode_after (int entity
, int last_mode
, rtx_insn
*insn
)
2506 /* We have too few call-saved registers to hope to keep the masks across
2508 if (entity
== EPIPHANY_MSW_ENTITY_AND
|| entity
== EPIPHANY_MSW_ENTITY_OR
)
2514 /* If there is an abnormal edge, we don't want the config register to
2515 be 'saved' again at the destination.
2516 The frame pointer adjustment is inside a PARALLEL because of the
2518 if (entity
== EPIPHANY_MSW_ENTITY_CONFIG
&& NONJUMP_INSN_P (insn
)
2519 && GET_CODE (PATTERN (insn
)) == PARALLEL
2520 && GET_CODE (XVECEXP (PATTERN (insn
), 0, 0)) == SET
2521 && SET_DEST (XVECEXP (PATTERN (insn
), 0, 0)) == frame_pointer_rtx
)
2523 gcc_assert (cfun
->has_nonlocal_label
);
2526 if (recog_memoized (insn
) < 0)
2528 if (get_attr_fp_mode (insn
) == FP_MODE_ROUND_UNKNOWN
2529 && last_mode
!= FP_MODE_ROUND_NEAREST
&& last_mode
!= FP_MODE_ROUND_TRUNC
)
2531 if (entity
== EPIPHANY_MSW_ENTITY_NEAREST
)
2532 return FP_MODE_ROUND_NEAREST
;
2533 if (entity
== EPIPHANY_MSW_ENTITY_TRUNC
)
2534 return FP_MODE_ROUND_TRUNC
;
2536 if (recog_memoized (insn
) == CODE_FOR_set_fp_mode
)
2538 rtx src
= SET_SRC (XVECEXP (PATTERN (insn
), 0, 0));
2542 return FP_MODE_CALLER
;
2543 fp_mode
= INTVAL (XVECEXP (XEXP (src
, 0), 0, 0));
2544 if (entity
== EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2545 && (fp_mode
== FP_MODE_ROUND_NEAREST
2546 || fp_mode
== EPIPHANY_MSW_ENTITY_TRUNC
))
2547 return FP_MODE_ROUND_UNKNOWN
;
2554 epiphany_mode_entry (int entity
)
2556 return epiphany_mode_entry_exit (entity
, false);
2560 epiphany_mode_exit (int entity
)
2562 return epiphany_mode_entry_exit (entity
, true);
2566 emit_set_fp_mode (int entity
, int mode
, int prev_mode ATTRIBUTE_UNUSED
,
2567 HARD_REG_SET regs_live ATTRIBUTE_UNUSED
)
2569 rtx save_cc
, cc_reg
, mask
, src
, src2
;
2570 enum attr_fp_mode fp_mode
;
2572 if (!MACHINE_FUNCTION (cfun
)->and_mask
)
2574 MACHINE_FUNCTION (cfun
)->and_mask
= gen_reg_rtx (SImode
);
2575 MACHINE_FUNCTION (cfun
)->or_mask
= gen_reg_rtx (SImode
);
2577 if (entity
== EPIPHANY_MSW_ENTITY_AND
)
2579 gcc_assert (mode
>= 0 && mode
<= 2);
2581 emit_move_insn (MACHINE_FUNCTION (cfun
)->and_mask
,
2582 gen_int_mode (0xfff1fffe, SImode
));
2585 else if (entity
== EPIPHANY_MSW_ENTITY_OR
)
2587 gcc_assert (mode
>= 0 && mode
<= 2);
2589 emit_move_insn (MACHINE_FUNCTION (cfun
)->or_mask
, GEN_INT(0x00080000));
2592 else if (entity
== EPIPHANY_MSW_ENTITY_CONFIG
)
2594 /* Mode switching optimization is done after emit_initial_value_sets,
2595 so we have to take care of CONFIG_REGNUM here. */
2596 gcc_assert (mode
>= 0 && mode
<= 2);
2597 rtx save
= get_hard_reg_initial_val (SImode
, CONFIG_REGNUM
);
2599 emit_insn (gen_save_config (save
));
2602 fp_mode
= (enum attr_fp_mode
) mode
;
2607 case FP_MODE_CALLER
:
2608 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2609 so that the config save gets inserted before the first use. */
2610 gcc_assert (entity
> EPIPHANY_MSW_ENTITY_CONFIG
);
2611 src
= get_hard_reg_initial_val (SImode
, CONFIG_REGNUM
);
2612 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2614 case FP_MODE_ROUND_UNKNOWN
:
2615 MACHINE_FUNCTION (cfun
)->unknown_mode_sets
++;
2616 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2618 case FP_MODE_ROUND_NEAREST
:
2619 if (entity
== EPIPHANY_MSW_ENTITY_TRUNC
)
2621 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2623 case FP_MODE_ROUND_TRUNC
:
2624 if (entity
== EPIPHANY_MSW_ENTITY_NEAREST
)
2626 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2629 mask
= MACHINE_FUNCTION (cfun
)->or_mask
;
2635 save_cc
= gen_reg_rtx (CCmode
);
2636 cc_reg
= gen_rtx_REG (CCmode
, CC_REGNUM
);
2637 emit_move_insn (save_cc
, cc_reg
);
2638 mask
= force_reg (SImode
, mask
);
2641 rtvec v
= gen_rtvec (1, GEN_INT (fp_mode
));
2643 src
= gen_rtx_CONST (SImode
, gen_rtx_UNSPEC (SImode
, v
, UNSPEC_FP_MODE
));
2645 if (entity
== EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2646 || entity
== EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
)
2647 src2
= copy_rtx (src
);
2650 rtvec v
= gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN
));
2652 src2
= gen_rtx_CONST (SImode
, gen_rtx_UNSPEC (SImode
, v
, UNSPEC_FP_MODE
));
2654 emit_insn (gen_set_fp_mode (src
, src2
, mask
));
2655 emit_move_insn (cc_reg
, save_cc
);
2659 epiphany_expand_set_fp_mode (rtx
*operands
)
2661 rtx ctrl
= gen_rtx_REG (SImode
, CONFIG_REGNUM
);
2662 rtx src
= operands
[0];
2663 rtx mask_reg
= operands
[2];
2664 rtx scratch
= operands
[3];
2665 enum attr_fp_mode fp_mode
;
2668 gcc_assert (rtx_equal_p (src
, operands
[1])
2669 /* Sometimes reload gets silly and reloads the same pseudo
2670 into different registers. */
2671 || (REG_P (src
) && REG_P (operands
[1])));
2673 if (!epiphany_uninterruptible_p (current_function_decl
))
2674 emit_insn (gen_gid ());
2675 emit_move_insn (scratch
, ctrl
);
2677 if (GET_CODE (src
) == REG
)
2679 /* FP_MODE_CALLER */
2680 emit_insn (gen_xorsi3 (scratch
, scratch
, src
));
2681 emit_insn (gen_andsi3 (scratch
, scratch
, mask_reg
));
2682 emit_insn (gen_xorsi3 (scratch
, scratch
, src
));
2686 gcc_assert (GET_CODE (src
) == CONST
);
2687 src
= XEXP (src
, 0);
2688 fp_mode
= (enum attr_fp_mode
) INTVAL (XVECEXP (src
, 0, 0));
2691 case FP_MODE_ROUND_NEAREST
:
2692 emit_insn (gen_andsi3 (scratch
, scratch
, mask_reg
));
2694 case FP_MODE_ROUND_TRUNC
:
2695 emit_insn (gen_andsi3 (scratch
, scratch
, mask_reg
));
2696 emit_insn (gen_add2_insn (scratch
, const1_rtx
));
2699 emit_insn (gen_iorsi3 (scratch
, scratch
, mask_reg
));
2701 case FP_MODE_CALLER
:
2702 case FP_MODE_ROUND_UNKNOWN
:
2707 emit_move_insn (ctrl
, scratch
);
2708 if (!epiphany_uninterruptible_p (current_function_decl
))
2709 emit_insn (gen_gie ());
2713 epiphany_insert_mode_switch_use (rtx_insn
*insn
,
2714 int entity ATTRIBUTE_UNUSED
,
2715 int mode ATTRIBUTE_UNUSED
)
2717 rtx pat
= PATTERN (insn
);
2720 rtx near
= gen_rtx_REG (SImode
, FP_NEAREST_REGNUM
);
2721 rtx trunc
= gen_rtx_REG (SImode
, FP_TRUNCATE_REGNUM
);
2723 if (entity
!= EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
)
2725 switch ((enum attr_fp_mode
) get_attr_fp_mode (insn
))
2727 case FP_MODE_ROUND_NEAREST
:
2728 near
= gen_rtx_USE (VOIDmode
, near
);
2729 trunc
= gen_rtx_CLOBBER (VOIDmode
, trunc
);
2731 case FP_MODE_ROUND_TRUNC
:
2732 near
= gen_rtx_CLOBBER (VOIDmode
, near
);
2733 trunc
= gen_rtx_USE (VOIDmode
, trunc
);
2735 case FP_MODE_ROUND_UNKNOWN
:
2736 near
= gen_rtx_USE (VOIDmode
, gen_rtx_REG (SImode
, FP_ANYFP_REGNUM
));
2737 trunc
= copy_rtx (near
);
2740 case FP_MODE_CALLER
:
2741 near
= gen_rtx_USE (VOIDmode
, near
);
2742 trunc
= gen_rtx_USE (VOIDmode
, trunc
);
2747 gcc_assert (GET_CODE (pat
) == PARALLEL
);
2748 len
= XVECLEN (pat
, 0);
2749 v
= rtvec_alloc (len
+ 2);
2750 for (i
= 0; i
< len
; i
++)
2751 RTVEC_ELT (v
, i
) = XVECEXP (pat
, 0, i
);
2752 RTVEC_ELT (v
, len
) = near
;
2753 RTVEC_ELT (v
, len
+ 1) = trunc
;
2754 pat
= gen_rtx_PARALLEL (VOIDmode
, v
);
2755 PATTERN (insn
) = pat
;
2756 MACHINE_FUNCTION (cfun
)->control_use_inserted
= true;
2760 epiphany_epilogue_uses (int regno
)
2762 if (regno
== GPR_LR
)
2764 if (reload_completed
&& epiphany_is_interrupt_p (current_function_decl
))
2766 if (fixed_regs
[regno
]
2767 && regno
!= STATUS_REGNUM
&& regno
!= IRET_REGNUM
2768 && regno
!= FP_NEAREST_REGNUM
&& regno
!= FP_TRUNCATE_REGNUM
)
2772 if (regno
== FP_NEAREST_REGNUM
2773 && epiphany_normal_fp_mode
!= FP_MODE_ROUND_TRUNC
)
2775 if (regno
== FP_TRUNCATE_REGNUM
2776 && epiphany_normal_fp_mode
!= FP_MODE_ROUND_NEAREST
)
2782 epiphany_min_divisions_for_recip_mul (machine_mode mode
)
2784 if (flag_reciprocal_math
&& mode
== SFmode
)
2785 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2786 it already at the tree level and expose it to further optimizations. */
2788 return default_min_divisions_for_recip_mul (mode
);
2792 epiphany_preferred_simd_mode (scalar_mode mode ATTRIBUTE_UNUSED
)
2794 return TARGET_VECT_DOUBLE
? DImode
: SImode
;
2798 epiphany_vector_mode_supported_p (machine_mode mode
)
2800 if (mode
== V2SFmode
)
2802 if (GET_MODE_CLASS (mode
) == MODE_VECTOR_INT
2803 && (GET_MODE_SIZE (mode
) == 4 || GET_MODE_SIZE (mode
) == 8))
2809 epiphany_vector_alignment_reachable (const_tree type
, bool is_packed
)
2811 /* Vectors which aren't in packed structures will not be less aligned than
2812 the natural alignment of their element type, so this is safe. */
2813 if (TYPE_ALIGN_UNIT (type
) == 4)
2816 return default_builtin_vector_alignment_reachable (type
, is_packed
);
2820 epiphany_support_vector_misalignment (machine_mode mode
, const_tree type
,
2821 int misalignment
, bool is_packed
)
2823 if (GET_MODE_SIZE (mode
) == 8 && misalignment
% 4 == 0)
2825 return default_builtin_support_vector_misalignment (mode
, type
, misalignment
,
2829 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2830 structs. Make structs double-word-aligned it they are a double word or
2831 (potentially) larger; failing that, do the same for a size of 32 bits. */
2833 epiphany_special_round_type_align (tree type
, unsigned computed
,
2836 unsigned align
= MAX (computed
, specified
);
2838 HOST_WIDE_INT total
, max
;
2839 unsigned try_align
= FASTEST_ALIGNMENT
;
2841 if (maximum_field_alignment
&& try_align
> maximum_field_alignment
)
2842 try_align
= maximum_field_alignment
;
2843 if (align
>= try_align
)
2845 for (max
= 0, field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
2849 if (TREE_CODE (field
) != FIELD_DECL
2850 || TREE_TYPE (field
) == error_mark_node
)
2852 offset
= bit_position (field
);
2853 size
= DECL_SIZE (field
);
2854 if (!tree_fits_uhwi_p (offset
) || !tree_fits_uhwi_p (size
)
2855 || tree_to_uhwi (offset
) >= try_align
2856 || tree_to_uhwi (size
) >= try_align
)
2858 total
= tree_to_uhwi (offset
) + tree_to_uhwi (size
);
2862 if (max
>= (HOST_WIDE_INT
) try_align
)
2864 else if (try_align
> 32 && max
>= 32)
2865 align
= max
> 32 ? 64 : 32;
2869 /* Upping the alignment of arrays in structs is not only a performance
2870 enhancement, it also helps preserve assumptions about how
2871 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2874 epiphany_adjust_field_align (tree type
, unsigned computed
)
2877 && TREE_CODE (type
) == ARRAY_TYPE
)
2879 tree elmsz
= TYPE_SIZE (TREE_TYPE (type
));
2881 if (!tree_fits_uhwi_p (elmsz
) || tree_to_uhwi (elmsz
) >= 32)
2887 /* Output code to add DELTA to the first argument, and then jump
2888 to FUNCTION. Used for C++ multiple inheritance. */
2890 epiphany_output_mi_thunk (FILE *file
, tree thunk ATTRIBUTE_UNUSED
,
2891 HOST_WIDE_INT delta
,
2892 HOST_WIDE_INT vcall_offset
,
2896 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
) ? 1 : 0;
2897 const char *this_name
= reg_names
[this_regno
];
2900 /* We use IP and R16 as a scratch registers. */
2901 gcc_assert (call_used_regs
[GPR_IP
]);
2902 gcc_assert (call_used_regs
[GPR_16
]);
2904 /* Add DELTA. When possible use a plain add, otherwise load it into
2905 a register first. */
2908 else if (SIMM11 (delta
))
2909 asm_fprintf (file
, "\tadd\t%s,%s,%d\n", this_name
, this_name
, (int) delta
);
2910 else if (delta
< 0 && delta
>= -0xffff)
2912 asm_fprintf (file
, "\tmov\tip,%d\n", (int) -delta
);
2913 asm_fprintf (file
, "\tsub\t%s,%s,ip\n", this_name
, this_name
);
2917 asm_fprintf (file
, "\tmov\tip,%%low(%ld)\n", (long) delta
);
2918 if (delta
& ~0xffff)
2919 asm_fprintf (file
, "\tmovt\tip,%%high(%ld)\n", (long) delta
);
2920 asm_fprintf (file
, "\tadd\t%s,%s,ip\n", this_name
, this_name
);
2923 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2924 if (vcall_offset
!= 0)
2926 /* ldr ip,[this] --> temp = *this
2927 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2928 add this,this,ip --> this+ = *(*this + vcall_offset) */
2929 asm_fprintf (file
, "\tldr\tip, [%s]\n", this_name
);
2930 if (vcall_offset
< -0x7ff * 4 || vcall_offset
> 0x7ff * 4
2931 || (vcall_offset
& 3) != 0)
2933 asm_fprintf (file
, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset
);
2934 asm_fprintf (file
, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset
);
2935 asm_fprintf (file
, "\tldr\tip, [ip,r16]\n");
2938 asm_fprintf (file
, "\tldr\tip, [ip,%d]\n", (int) vcall_offset
/ 4);
2939 asm_fprintf (file
, "\tadd\t%s, %s, ip\n", this_name
, this_name
);
2942 fname
= XSTR (XEXP (DECL_RTL (function
), 0), 0);
2943 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function
), 0)))
2945 fputs ("\tmov\tip,%low(", file
);
2946 assemble_name (file
, fname
);
2947 fputs (")\n\tmovt\tip,%high(", file
);
2948 assemble_name (file
, fname
);
2949 fputs (")\n\tjr ip\n", file
);
2953 fputs ("\tb\t", file
);
2954 assemble_name (file
, fname
);
2960 epiphany_start_function (FILE *file
, const char *name
, tree decl
)
2962 /* If the function doesn't fit into the on-chip memory, it will have a
2963 section attribute - or lack of it - that denotes it goes somewhere else.
2964 But the architecture spec says that an interrupt vector still has to
2965 point to on-chip memory. So we must place a jump there to get to the
2966 actual function implementation. The forwarder_section attribute
2967 specifies the section where this jump goes.
2968 This mechanism can also be useful to have a shortcall destination for
2969 a function that is actually placed much farther away. */
2970 tree attrs
, int_attr
, int_names
, int_name
, forwarder_attr
;
2972 attrs
= DECL_ATTRIBUTES (decl
);
2973 int_attr
= lookup_attribute ("interrupt", attrs
);
2975 for (int_names
= TREE_VALUE (int_attr
); int_names
;
2976 int_names
= TREE_CHAIN (int_names
))
2980 int_name
= TREE_VALUE (int_names
);
2981 sprintf (buf
, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name
));
2982 switch_to_section (get_section (buf
, SECTION_CODE
, decl
));
2983 fputs ("\tb\t", file
);
2984 assemble_name (file
, name
);
2987 forwarder_attr
= lookup_attribute ("forwarder_section", attrs
);
2990 const char *prefix
= "__forwarder_dst_";
2991 char *dst_name
= (char *) alloca (strlen (prefix
) + strlen (name
) + 1);
2993 strcpy (dst_name
, prefix
);
2994 strcat (dst_name
, name
);
2995 forwarder_attr
= TREE_VALUE (TREE_VALUE (forwarder_attr
));
2996 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr
),
2997 SECTION_CODE
, decl
));
2998 ASM_OUTPUT_FUNCTION_LABEL (file
, name
, decl
);
2999 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl
), 0)))
3004 fputs ("\tstrd r0,[sp,-1]\n", file
);
3007 gcc_assert (call_used_regs
[tmp
]);
3008 fprintf (file
, "\tmov r%d,%%low(", tmp
);
3009 assemble_name (file
, dst_name
);
3010 fprintf (file
, ")\n"
3011 "\tmovt r%d,%%high(", tmp
);
3012 assemble_name (file
, dst_name
);
3013 fprintf (file
, ")\n"
3018 fputs ("\tb\t", file
);
3019 assemble_name (file
, dst_name
);
3024 switch_to_section (function_section (decl
));
3025 ASM_OUTPUT_FUNCTION_LABEL (file
, name
, decl
);
3029 /* Implement TARGET_CONSTANT_ALIGNMENT. */
3031 static HOST_WIDE_INT
3032 epiphany_constant_alignment (const_tree exp
, HOST_WIDE_INT align
)
3034 if (TREE_CODE (exp
) == STRING_CST
)
3035 return MAX (align
, FASTEST_ALIGNMENT
);
3039 /* Implement TARGET_STARTING_FRAME_OFFSET. */
3041 static HOST_WIDE_INT
3042 epiphany_starting_frame_offset (void)
3044 return epiphany_stack_offset
;
3047 struct gcc_target targetm
= TARGET_INITIALIZER
;