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-2012 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" /* for current_pass */
50 /* Which cpu we're compiling for. */
51 int epiphany_cpu_type
;
53 /* Name of mangle string to add to symbols to separate code compiled for each
55 const char *epiphany_mangle_cpu
;
57 /* Array of valid operand punctuation characters. */
58 char epiphany_punct_chars
[256];
60 /* The rounding mode that we generally use for floating point. */
61 int epiphany_normal_fp_rounding
;
63 static void epiphany_init_reg_tables (void);
64 static int get_epiphany_condition_code (rtx
);
65 static tree
epiphany_handle_interrupt_attribute (tree
*, tree
, tree
, int, bool *);
66 static tree
epiphany_handle_forwarder_attribute (tree
*, tree
, tree
, int,
68 static bool epiphany_pass_by_reference (cumulative_args_t
, enum machine_mode
,
70 static rtx
frame_insn (rtx
);
72 /* defines for the initialization of the GCC target structure. */
73 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
75 #define TARGET_PRINT_OPERAND epiphany_print_operand
76 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
78 #define TARGET_RTX_COSTS epiphany_rtx_costs
79 #define TARGET_ADDRESS_COST epiphany_address_cost
80 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
82 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
83 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
85 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
86 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
87 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
88 #define TARGET_FUNCTION_VALUE epiphany_function_value
89 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
90 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
92 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
94 /* Using the simplistic varags handling forces us to do partial reg/stack
95 argument passing for types with larger size (> 4 bytes) than alignemnt. */
96 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
98 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
100 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
101 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
103 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
105 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
107 #define TARGET_OPTION_OVERRIDE epiphany_override_options
109 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
111 #define TARGET_FUNCTION_ARG epiphany_function_arg
113 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
115 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
117 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
119 /* Nonzero if the constant rtx value is a legitimate general operand.
120 We can handle any 32- or 64-bit constant. */
121 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
123 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
124 epiphany_min_divisions_for_recip_mul
126 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
128 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
130 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
131 epiphany_vector_alignment_reachable
133 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
134 epiphany_support_vector_misalignment
136 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
137 hook_bool_const_tree_hwi_hwi_const_tree_true
138 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
140 #include "target-def.h"
142 #undef TARGET_ASM_ALIGNED_HI_OP
143 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
144 #undef TARGET_ASM_ALIGNED_SI_OP
145 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
148 epiphany_is_interrupt_p (tree decl
)
152 attrs
= DECL_ATTRIBUTES (decl
);
153 if (lookup_attribute ("interrupt", attrs
))
159 /* Called from epiphany_override_options.
160 We use this to initialize various things. */
165 /* N.B. this pass must not run before the first optimize_mode_switching
166 pass because of the side offect of epiphany_mode_needed on
167 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
168 pass_resolve_sw_modes. */
169 static struct register_pass_info insert_use_info
170 = { &pass_mode_switch_use
.pass
, "mode_sw",
171 1, PASS_POS_INSERT_AFTER
173 static struct register_pass_info mode_sw2_info
174 = { &pass_mode_switching
.pass
, "mode_sw",
175 1, PASS_POS_INSERT_AFTER
177 static struct register_pass_info mode_sw3_info
178 = { &pass_resolve_sw_modes
.pass
, "mode_sw",
179 1, PASS_POS_INSERT_AFTER
181 static struct register_pass_info mode_sw4_info
182 = { &pass_split_all_insns
.pass
, "mode_sw",
183 1, PASS_POS_INSERT_AFTER
186 epiphany_init_reg_tables ();
188 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
189 memset (epiphany_punct_chars
, 0, sizeof (epiphany_punct_chars
));
190 epiphany_punct_chars
['-'] = 1;
192 epiphany_normal_fp_rounding
193 = (epiphany_normal_fp_mode
== FP_MODE_ROUND_TRUNC
194 ? FP_MODE_ROUND_TRUNC
: FP_MODE_ROUND_NEAREST
);
195 register_pass (&mode_sw4_info
);
196 register_pass (&mode_sw2_info
);
197 register_pass (&mode_sw3_info
);
198 register_pass (&insert_use_info
);
199 register_pass (&mode_sw2_info
);
201 #if 1 /* As long as peep2_rescan is not implemented,
202 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
203 we need a second peephole2 pass to get reasonable code. */
205 static struct register_pass_info peep2_2_info
206 = { &pass_peephole2
.pass
, "peephole2",
207 1, PASS_POS_INSERT_AFTER
210 register_pass (&peep2_2_info
);
215 /* The condition codes of the EPIPHANY, and the inverse function. */
216 static const char *const epiphany_condition_codes
[] =
217 { /* 0 1 2 3 4 5 6 7 8 9 */
218 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
220 "beq","bne","blt", "blte",
223 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
225 /* Returns the index of the EPIPHANY condition code string in
226 `epiphany_condition_codes'. COMPARISON should be an rtx like
227 `(eq (...) (...))'. */
230 get_epiphany_condition_code (rtx comparison
)
232 switch (GET_MODE (XEXP (comparison
, 0)))
235 switch (GET_CODE (comparison
))
248 default : gcc_unreachable ();
251 switch (GET_CODE (comparison
))
255 default: gcc_unreachable ();
258 switch (GET_CODE (comparison
))
262 default: gcc_unreachable ();
265 switch (GET_CODE (comparison
))
269 default: gcc_unreachable ();
272 switch (GET_CODE (comparison
))
278 default: gcc_unreachable ();
281 switch (GET_CODE (comparison
))
285 default: gcc_unreachable ();
288 switch (GET_CODE (comparison
))
294 case UNLE
: return 5;
295 case UNLT
: return 7;
296 default: gcc_unreachable ();
299 switch (GET_CODE (comparison
))
301 case ORDERED
: return 9;
302 case UNORDERED
: return 8;
303 default: gcc_unreachable ();
306 switch (GET_CODE (comparison
))
310 default: gcc_unreachable ();
312 default: gcc_unreachable ();
319 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
321 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
323 if (GET_MODE_SIZE (mode
) > UNITS_PER_WORD
)
324 return (regno
& 1) == 0 && GPR_P (regno
);
329 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
330 return the mode to be used for the comparison. */
333 epiphany_select_cc_mode (enum rtx_code op
,
334 rtx x ATTRIBUTE_UNUSED
,
335 rtx y ATTRIBUTE_UNUSED
)
337 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
339 if (TARGET_SOFT_CMPSF
)
341 if (op
== EQ
|| op
== NE
)
343 if (op
== ORDERED
|| op
== UNORDERED
)
344 return CC_FP_ORDmode
;
345 if (op
== UNEQ
|| op
== LTGT
)
346 return CC_FP_UNEQmode
;
347 return CC_FP_GTEmode
;
351 /* recognize combiner pattern ashlsi_btst:
353 (set (reg:N_NE 65 cc1)
354 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
357 (const_int 0 [0x0])))
358 (clobber (scratch:SI)) */
359 else if ((op
== EQ
|| op
== NE
)
360 && GET_CODE (x
) == ZERO_EXTRACT
361 && XEXP (x
, 1) == const1_rtx
362 && CONST_INT_P (XEXP (x
, 2)))
364 else if ((op
== GEU
|| op
== LTU
) && GET_CODE (x
) == PLUS
)
366 else if ((op
== LEU
|| op
== GTU
) && GET_CODE (x
) == MINUS
)
372 enum reg_class epiphany_regno_reg_class
[FIRST_PSEUDO_REGISTER
];
375 epiphany_init_reg_tables (void)
379 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
382 epiphany_regno_reg_class
[i
] = LR_REGS
;
383 else if (i
<= 7 && TARGET_PREFER_SHORT_INSN_REGS
)
384 epiphany_regno_reg_class
[i
] = SHORT_INSN_REGS
;
385 else if (call_used_regs
[i
]
386 && TEST_HARD_REG_BIT (reg_class_contents
[GENERAL_REGS
], i
))
387 epiphany_regno_reg_class
[i
] = SIBCALL_REGS
;
388 else if (i
>= CORE_CONTROL_FIRST
&& i
<= CORE_CONTROL_LAST
)
389 epiphany_regno_reg_class
[i
] = CORE_CONTROL_REGS
;
390 else if (i
< (GPR_LAST
+1)
391 || i
== ARG_POINTER_REGNUM
|| i
== FRAME_POINTER_REGNUM
)
392 epiphany_regno_reg_class
[i
] = GENERAL_REGS
;
393 else if (i
== CC_REGNUM
)
394 epiphany_regno_reg_class
[i
] = NO_REGS
/* CC_REG: must be NO_REGS */;
396 epiphany_regno_reg_class
[i
] = NO_REGS
;
400 /* EPIPHANY specific attribute support.
402 The EPIPHANY has these attributes:
403 interrupt - for interrupt functions.
404 short_call - the function is assumed to be reachable with the b / bl
406 long_call - the function address is loaded into a register before use.
407 disinterrupt - functions which mask interrupts throughout.
408 They unmask them while calling an interruptible
411 static const struct attribute_spec epiphany_attribute_table
[] =
413 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
414 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute
, true },
415 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute
, false },
416 { "long_call", 0, 0, false, true, true, NULL
, false },
417 { "short_call", 0, 0, false, true, true, NULL
, false },
418 { "disinterrupt", 0, 0, false, true, true, NULL
, true },
419 { NULL
, 0, 0, false, false, false, NULL
, false }
422 /* Handle an "interrupt" attribute; arguments as in
423 struct attribute_spec.handler. */
425 epiphany_handle_interrupt_attribute (tree
*node ATTRIBUTE_UNUSED
,
426 tree name
, tree args
,
427 int flags ATTRIBUTE_UNUSED
,
435 value
= TREE_VALUE (args
);
437 if (TREE_CODE (value
) != STRING_CST
)
439 warning (OPT_Wattributes
,
440 "argument of %qE attribute is not a string constant", name
);
441 *no_add_attrs
= true;
443 else if (strcmp (TREE_STRING_POINTER (value
), "reset")
444 && strcmp (TREE_STRING_POINTER (value
), "software_exception")
445 && strcmp (TREE_STRING_POINTER (value
), "page_miss")
446 && strcmp (TREE_STRING_POINTER (value
), "timer0")
447 && strcmp (TREE_STRING_POINTER (value
), "timer1")
448 && strcmp (TREE_STRING_POINTER (value
), "message")
449 && strcmp (TREE_STRING_POINTER (value
), "dma0")
450 && strcmp (TREE_STRING_POINTER (value
), "dma1")
451 && strcmp (TREE_STRING_POINTER (value
), "wand")
452 && strcmp (TREE_STRING_POINTER (value
), "swi"))
454 warning (OPT_Wattributes
,
455 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
457 *no_add_attrs
= true;
461 return epiphany_handle_interrupt_attribute (node
, name
, TREE_CHAIN (args
),
462 flags
, no_add_attrs
);
465 /* Handle a "forwarder_section" attribute; arguments as in
466 struct attribute_spec.handler. */
468 epiphany_handle_forwarder_attribute (tree
*node ATTRIBUTE_UNUSED
,
469 tree name
, tree args
,
470 int flags ATTRIBUTE_UNUSED
,
475 value
= TREE_VALUE (args
);
477 if (TREE_CODE (value
) != STRING_CST
)
479 warning (OPT_Wattributes
,
480 "argument of %qE attribute is not a string constant", name
);
481 *no_add_attrs
= true;
487 /* Misc. utilities. */
489 /* Generate a SYMBOL_REF for the special function NAME. When the address
490 can't be placed directly into a call instruction, and if possible, copy
491 it to a register so that cse / code hoisting is possible. */
493 sfunc_symbol (const char *name
)
495 rtx sym
= gen_rtx_SYMBOL_REF (Pmode
, name
);
497 /* These sfuncs should be hidden, and every dso should get a copy. */
498 SYMBOL_REF_FLAGS (sym
) = SYMBOL_FLAG_FUNCTION
| SYMBOL_FLAG_LOCAL
;
499 if (TARGET_SHORT_CALLS
)
500 ; /* Nothing to be done. */
501 else if (can_create_pseudo_p ())
502 sym
= copy_to_mode_reg (Pmode
, sym
);
503 else /* We rely on reload to fix this up. */
504 gcc_assert (!reload_in_progress
|| reload_completed
);
508 /* X and Y are two things to compare using CODE in IN_MODE.
509 Emit the compare insn, construct the the proper cc reg in the proper
510 mode, and return the rtx for the cc reg comparison in CMODE. */
513 gen_compare_reg (enum machine_mode cmode
, enum rtx_code code
,
514 enum machine_mode in_mode
, rtx x
, rtx y
)
516 enum machine_mode mode
= SELECT_CC_MODE (code
, x
, y
);
517 rtx cc_reg
, pat
, clob0
, clob1
, clob2
;
519 if (in_mode
== VOIDmode
)
520 in_mode
= GET_MODE (x
);
521 if (in_mode
== VOIDmode
)
522 in_mode
= GET_MODE (y
);
524 if (mode
== CC_FPmode
)
526 /* The epiphany has only EQ / NE / LT / LE conditions for
527 hardware floating point. */
528 if (code
== GT
|| code
== GE
|| code
== UNLE
|| code
== UNLT
)
530 rtx tmp
= x
; x
= y
; y
= tmp
;
531 code
= swap_condition (code
);
533 cc_reg
= gen_rtx_REG (mode
, CCFP_REGNUM
);
534 y
= force_reg (in_mode
, y
);
538 if (mode
== CC_FP_GTEmode
539 && (code
== LE
|| code
== LT
|| code
== UNGT
|| code
== UNGE
))
541 rtx tmp
= x
; x
= y
; y
= tmp
;
542 code
= swap_condition (code
);
544 cc_reg
= gen_rtx_REG (mode
, CC_REGNUM
);
546 if ((mode
== CC_FP_EQmode
|| mode
== CC_FP_GTEmode
547 || mode
== CC_FP_ORDmode
|| mode
== CC_FP_UNEQmode
)
548 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
549 && (!REG_P (x
) || REGNO (x
) != 0 || !REG_P (y
) || REGNO (y
) != 1))
553 gcc_assert (currently_expanding_to_rtl
);
554 reg
= gen_rtx_REG (in_mode
, 0);
555 gcc_assert (!reg_overlap_mentioned_p (reg
, y
));
556 emit_move_insn (reg
, x
);
558 reg
= gen_rtx_REG (in_mode
, 1);
559 emit_move_insn (reg
, y
);
563 x
= force_reg (in_mode
, x
);
565 pat
= gen_rtx_SET (VOIDmode
, cc_reg
, gen_rtx_COMPARE (mode
, x
, y
));
566 if (mode
== CC_FP_EQmode
|| mode
== CC_FP_GTEmode
)
568 const char *name
= mode
== CC_FP_EQmode
? "__eqsf2" : "__gtesf2";
569 rtx use
= gen_rtx_USE (VOIDmode
, sfunc_symbol (name
));
571 clob0
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_IP
));
572 clob1
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_LR
));
573 pat
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (4, pat
, use
, clob0
, clob1
));
575 else if (mode
== CC_FP_ORDmode
|| mode
== CC_FP_UNEQmode
)
577 const char *name
= mode
== CC_FP_ORDmode
? "__ordsf2" : "__uneqsf2";
578 rtx use
= gen_rtx_USE (VOIDmode
, sfunc_symbol (name
));
580 clob0
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_IP
));
581 clob1
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_16
));
582 clob2
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (SImode
, GPR_LR
));
583 pat
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (5, pat
, use
,
584 clob0
, clob1
, clob2
));
588 clob0
= gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (in_mode
));
589 pat
= gen_rtx_PARALLEL (VOIDmode
, gen_rtvec (2, pat
, clob0
));
592 return gen_rtx_fmt_ee (code
, cmode
, cc_reg
, const0_rtx
);
595 /* The ROUND_ADVANCE* macros are local to this file. */
596 /* Round SIZE up to a word boundary. */
597 #define ROUND_ADVANCE(SIZE) \
598 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
600 /* Round arg MODE/TYPE up to the next word boundary. */
601 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
603 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
604 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
606 /* Round CUM up to the necessary point for argument MODE/TYPE. */
607 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
608 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
609 ? (((CUM) + 1) & ~1) \
613 epiphany_function_arg_boundary (enum machine_mode mode
, const_tree type
)
615 if ((type
? TYPE_ALIGN (type
) : GET_MODE_BITSIZE (mode
)) <= PARM_BOUNDARY
)
616 return PARM_BOUNDARY
;
617 return 2 * PARM_BOUNDARY
;
620 /* Do any needed setup for a variadic function. For the EPIPHANY, we
621 actually emit the code in epiphany_expand_prologue.
623 CUM has not been updated for the last named argument which has type TYPE
624 and mode MODE, and we rely on this fact. */
628 epiphany_setup_incoming_varargs (cumulative_args_t cum
, enum machine_mode mode
,
629 tree type
, int *pretend_size
, int no_rtl
)
632 CUMULATIVE_ARGS next_cum
;
633 machine_function_t
*mf
= MACHINE_FUNCTION (cfun
);
635 /* All BLKmode values are passed by reference. */
636 gcc_assert (mode
!= BLKmode
);
638 next_cum
= *get_cumulative_args (cum
);
640 = ROUND_ADVANCE_CUM (next_cum
, mode
, type
) + ROUND_ADVANCE_ARG (mode
, type
);
641 first_anon_arg
= next_cum
;
643 if (first_anon_arg
< MAX_EPIPHANY_PARM_REGS
&& !no_rtl
)
645 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
646 int first_reg_offset
= first_anon_arg
;
648 *pretend_size
= ((MAX_EPIPHANY_PARM_REGS
- first_reg_offset
)
652 mf
->pretend_args_odd
= ((*pretend_size
& UNITS_PER_WORD
) ? 1 : 0);
656 epiphany_arg_partial_bytes (cumulative_args_t cum
, enum machine_mode mode
,
657 tree type
, bool named ATTRIBUTE_UNUSED
)
659 int words
= 0, rounded_cum
;
661 gcc_assert (!epiphany_pass_by_reference (cum
, mode
, type
, /* named */ true));
663 rounded_cum
= ROUND_ADVANCE_CUM (*get_cumulative_args (cum
), mode
, type
);
664 if (rounded_cum
< MAX_EPIPHANY_PARM_REGS
)
666 words
= MAX_EPIPHANY_PARM_REGS
- rounded_cum
;
667 if (words
>= ROUND_ADVANCE_ARG (mode
, type
))
670 return words
* UNITS_PER_WORD
;
673 /* Cost functions. */
675 /* Compute a (partial) cost for rtx X. Return true if the complete
676 cost has been computed, and false if subexpressions should be
677 scanned. In either case, *TOTAL contains the cost result. */
680 epiphany_rtx_costs (rtx x
, int code
, int outer_code
, int opno ATTRIBUTE_UNUSED
,
681 int *total
, bool speed ATTRIBUTE_UNUSED
)
685 /* Small integers in the right context are as cheap as registers. */
687 if ((outer_code
== PLUS
|| outer_code
== MINUS
)
688 && SIMM11 (INTVAL (x
)))
693 if (IMM16 (INTVAL (x
)))
695 *total
= outer_code
== SET
? 0 : COSTS_N_INSNS (1);
703 *total
= COSTS_N_INSNS ((epiphany_small16 (x
) ? 0 : 1)
704 + (outer_code
== SET
? 0 : 1));
710 split_double (x
, &high
, &low
);
711 *total
= COSTS_N_INSNS (!IMM16 (INTVAL (high
))
712 + !IMM16 (INTVAL (low
)));
719 *total
= COSTS_N_INSNS (1);
728 /* Provide the costs of an addressing mode that contains ADDR.
729 If ADDR is not a valid address, its cost is irrelevant. */
732 epiphany_address_cost (rtx addr
, enum machine_mode mode
,
733 addr_space_t as ATTRIBUTE_UNUSED
, 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 /* The offset range available for short instructions depends on the mode
765 of the memory access. */
766 /* First, make sure we have a valid integer. */
767 if (!satisfies_constraint_L (off
))
770 switch (GET_MODE_SIZE (mode
))
784 return i
< -7 || i
> 7;
788 /* Compute the cost of moving data between registers and memory.
789 For integer, load latency is twice as long as register-register moves,
790 but issue pich is the same. For floating point, load latency is three
791 times as much as a reg-reg move. */
793 epiphany_memory_move_cost (enum machine_mode mode
,
794 reg_class_t rclass ATTRIBUTE_UNUSED
,
795 bool in ATTRIBUTE_UNUSED
)
797 return GET_MODE_CLASS (mode
) == MODE_INT
? 3 : 4;
800 /* Function prologue/epilogue handlers. */
802 /* EPIPHANY stack frames look like:
804 Before call After call
805 +-----------------------+ +-----------------------+
807 high | local variables, | | local variables, |
808 mem | reg save area, etc. | | reg save area, etc. |
810 +-----------------------+ +-----------------------+
812 | arguments on stack. | | arguments on stack. |
814 SP+8->+-----------------------+FP+8m->+-----------------------+
815 | 2 word save area for | | reg parm save area, |
816 | leaf funcs / flags | | only created for |
817 SP+0->+-----------------------+ | variable argument |
819 FP+8n->+-----------------------+
821 | register save area |
823 +-----------------------+
827 FP+0->+-----------------------+
829 | alloca allocations |
831 +-----------------------+
833 | arguments on stack |
835 SP+8->+-----------------------+
836 low | 2 word save area for |
837 memory | leaf funcs / flags |
838 SP+0->+-----------------------+
841 1) The "reg parm save area" does not exist for non variable argument fns.
842 The "reg parm save area" could be eliminated if we created our
843 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
844 (so it's not done). */
846 /* Structure to be filled in by epiphany_compute_frame_size with register
847 save masks, and offsets for the current function. */
848 struct epiphany_frame_info
850 unsigned int total_size
; /* # bytes that the entire frame takes up. */
851 unsigned int pretend_size
; /* # bytes we push and pretend caller did. */
852 unsigned int args_size
; /* # bytes that outgoing arguments take up. */
853 unsigned int reg_size
; /* # bytes needed to store regs. */
854 unsigned int var_size
; /* # bytes that variables take up. */
855 HARD_REG_SET gmask
; /* Set of saved gp registers. */
856 int initialized
; /* Nonzero if frame size already calculated. */
857 int stld_sz
; /* Current load/store data size for offset
859 int need_fp
; /* value to override "frame_pointer_needed */
860 int first_slot
, last_slot
, first_slot_offset
, last_slot_offset
;
865 /* Current frame information calculated by epiphany_compute_frame_size. */
866 static struct epiphany_frame_info current_frame_info
;
868 /* Zero structure to initialize current_frame_info. */
869 static struct epiphany_frame_info zero_frame_info
;
871 /* The usual; we set up our machine_function data. */
872 static struct machine_function
*
873 epiphany_init_machine_status (void)
875 struct machine_function
*machine
;
877 /* Reset state info for each function. */
878 current_frame_info
= zero_frame_info
;
880 machine
= ggc_alloc_cleared_machine_function_t ();
885 /* Implements INIT_EXPANDERS. We just set up to call the above
888 epiphany_init_expanders (void)
890 init_machine_status
= epiphany_init_machine_status
;
893 /* Type of function DECL.
895 The result is cached. To reset the cache at the end of a function,
896 call with DECL = NULL_TREE. */
898 static enum epiphany_function_type
899 epiphany_compute_function_type (tree decl
)
903 static enum epiphany_function_type fn_type
= EPIPHANY_FUNCTION_UNKNOWN
;
904 /* Last function we were called for. */
905 static tree last_fn
= NULL_TREE
;
907 /* Resetting the cached value? */
908 if (decl
== NULL_TREE
)
910 fn_type
= EPIPHANY_FUNCTION_UNKNOWN
;
915 if (decl
== last_fn
&& fn_type
!= EPIPHANY_FUNCTION_UNKNOWN
)
918 /* Assume we have a normal function (not an interrupt handler). */
919 fn_type
= EPIPHANY_FUNCTION_NORMAL
;
921 /* Now see if this is an interrupt handler. */
922 for (a
= DECL_ATTRIBUTES (decl
);
926 tree name
= TREE_PURPOSE (a
);
928 if (name
== get_identifier ("interrupt"))
929 fn_type
= EPIPHANY_FUNCTION_INTERRUPT
;
936 #define RETURN_ADDR_REGNUM GPR_LR
937 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
938 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
940 /* Tell prologue and epilogue if register REGNO should be saved / restored.
941 The return address and frame pointer are treated separately.
942 Don't consider them here. */
943 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
944 ((df_regs_ever_live_p (regno) \
945 || (interrupt_p && !crtl->is_leaf \
946 && call_used_regs[regno] && !fixed_regs[regno])) \
947 && (!call_used_regs[regno] || regno == GPR_LR \
948 || (interrupt_p && regno != GPR_SP)))
950 #define MUST_SAVE_RETURN_ADDR 0
952 /* Return the bytes needed to compute the frame pointer from the current
955 SIZE is the size needed for local variables. */
958 epiphany_compute_frame_size (int size
/* # of var. bytes allocated. */)
961 unsigned int total_size
, var_size
, args_size
, pretend_size
, reg_size
;
963 enum epiphany_function_type fn_type
;
965 int first_slot
, last_slot
, first_slot_offset
, last_slot_offset
;
971 args_size
= crtl
->outgoing_args_size
;
972 pretend_size
= crtl
->args
.pretend_args_size
;
973 total_size
= args_size
+ var_size
;
975 CLEAR_HARD_REG_SET (gmask
);
977 first_slot_offset
= 0;
979 last_slot_offset
= 0;
980 first_slot_size
= UNITS_PER_WORD
;
982 /* See if this is an interrupt handler. Call used registers must be saved
984 fn_type
= epiphany_compute_function_type (current_function_decl
);
985 interrupt_p
= EPIPHANY_INTERRUPT_P (fn_type
);
987 /* Calculate space needed for registers. */
989 for (regno
= MAX_EPIPHANY_PARM_REGS
- 1; pretend_size
> reg_size
; regno
--)
991 reg_size
+= UNITS_PER_WORD
;
992 SET_HARD_REG_BIT (gmask
, regno
);
993 if (epiphany_stack_offset
- reg_size
== 0)
998 reg_size
+= 2 * UNITS_PER_WORD
;
1000 small_slots
= epiphany_stack_offset
/ UNITS_PER_WORD
;
1002 if (frame_pointer_needed
)
1004 current_frame_info
.need_fp
= 1;
1005 if (!interrupt_p
&& first_slot
< 0)
1006 first_slot
= GPR_FP
;
1009 current_frame_info
.need_fp
= 0;
1010 for (regno
= 0; regno
<= GPR_LAST
; regno
++)
1012 if (MUST_SAVE_REGISTER (regno
, interrupt_p
))
1014 gcc_assert (!TEST_HARD_REG_BIT (gmask
, regno
));
1015 reg_size
+= UNITS_PER_WORD
;
1016 SET_HARD_REG_BIT (gmask
, regno
);
1017 /* FIXME: when optimizing for speed, take schedling into account
1018 when selecting these registers. */
1019 if (regno
== first_slot
)
1020 gcc_assert (regno
== GPR_FP
&& frame_pointer_needed
);
1021 else if (!interrupt_p
&& first_slot
< 0)
1023 else if (last_slot
< 0
1024 && (first_slot
^ regno
) != 1
1025 && (!interrupt_p
|| regno
> GPR_0
+ 1))
1029 if (TEST_HARD_REG_BIT (gmask
, GPR_LR
))
1030 MACHINE_FUNCTION (cfun
)->lr_clobbered
= 1;
1031 /* ??? Could sometimes do better than that. */
1032 current_frame_info
.small_threshold
1033 = (optimize
>= 3 || interrupt_p
? 0
1034 : pretend_size
? small_slots
1035 : 4 + small_slots
- (first_slot
== GPR_FP
));
1037 /* If there might be variables with 64-bit alignment requirement, align the
1038 start of the variables. */
1039 if (var_size
>= 2 * UNITS_PER_WORD
1040 /* We don't want to split a double reg save/restore across two unpaired
1041 stack slots when optimizing. This rounding could be avoided with
1042 more complex reordering of the register saves, but that would seem
1043 to be a lot of code complexity for little gain. */
1044 || (reg_size
> 8 && optimize
))
1045 reg_size
= EPIPHANY_STACK_ALIGN (reg_size
);
1046 if (total_size
+ reg_size
<= (unsigned) epiphany_stack_offset
1048 && crtl
->is_leaf
&& !frame_pointer_needed
)
1056 && reg_size
< (unsigned HOST_WIDE_INT
) epiphany_stack_offset
)
1057 reg_size
= epiphany_stack_offset
;
1060 if (total_size
+ reg_size
< 0x3fc)
1062 first_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
+ reg_size
);
1063 first_slot_offset
+= EPIPHANY_STACK_ALIGN (epiphany_stack_offset
);
1068 first_slot_offset
= EPIPHANY_STACK_ALIGN (reg_size
);
1069 last_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
);
1070 last_slot_offset
+= EPIPHANY_STACK_ALIGN (epiphany_stack_offset
);
1072 CLEAR_HARD_REG_BIT (gmask
, last_slot
);
1075 else if (total_size
+ reg_size
< 0x1ffc && first_slot
>= 0)
1077 first_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
+ reg_size
);
1082 if (total_size
+ reg_size
<= (unsigned) epiphany_stack_offset
)
1084 gcc_assert (first_slot
< 0);
1085 gcc_assert (reg_size
== 0);
1086 last_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
+ reg_size
);
1092 ? EPIPHANY_STACK_ALIGN (reg_size
- epiphany_stack_offset
) : 0);
1093 if (!first_slot_offset
)
1095 if (first_slot
!= GPR_FP
|| !current_frame_info
.need_fp
)
1096 last_slot
= first_slot
;
1099 last_slot_offset
= EPIPHANY_STACK_ALIGN (total_size
);
1101 last_slot_offset
+= EPIPHANY_STACK_ALIGN (epiphany_stack_offset
);
1104 CLEAR_HARD_REG_BIT (gmask
, last_slot
);
1107 if (first_slot
>= 0)
1109 CLEAR_HARD_REG_BIT (gmask
, first_slot
);
1110 if (TEST_HARD_REG_BIT (gmask
, first_slot
^ 1)
1111 && epiphany_stack_offset
- pretend_size
>= 2 * UNITS_PER_WORD
)
1113 CLEAR_HARD_REG_BIT (gmask
, first_slot
^ 1);
1114 first_slot_size
= 2 * UNITS_PER_WORD
;
1118 total_size
= first_slot_offset
+ last_slot_offset
;
1121 = (frame_pointer_needed
? first_slot_offset
: (long) total_size
);
1122 if (first_slot
!= GPR_LR
)
1124 int stack_offset
= epiphany_stack_offset
- UNITS_PER_WORD
;
1126 for (regno
= 0; ; regno
++)
1128 if (stack_offset
+ UNITS_PER_WORD
- first_slot_size
== 0
1131 stack_offset
-= first_slot_size
;
1134 else if (regno
== GPR_LR
)
1136 else if TEST_HARD_REG_BIT (gmask
, regno
)
1137 stack_offset
-= UNITS_PER_WORD
;
1139 lr_slot_offset
+= stack_offset
;
1142 /* Save computed information. */
1143 current_frame_info
.total_size
= total_size
;
1144 current_frame_info
.pretend_size
= pretend_size
;
1145 current_frame_info
.var_size
= var_size
;
1146 current_frame_info
.args_size
= args_size
;
1147 current_frame_info
.reg_size
= reg_size
;
1148 COPY_HARD_REG_SET (current_frame_info
.gmask
, gmask
);
1149 current_frame_info
.first_slot
= first_slot
;
1150 current_frame_info
.last_slot
= last_slot
;
1151 current_frame_info
.first_slot_offset
= first_slot_offset
;
1152 current_frame_info
.first_slot_size
= first_slot_size
;
1153 current_frame_info
.last_slot_offset
= last_slot_offset
;
1154 MACHINE_FUNCTION (cfun
)->lr_slot_offset
= lr_slot_offset
;
1156 current_frame_info
.initialized
= reload_completed
;
1158 /* Ok, we're done. */
1162 /* Print operand X (an rtx) in assembler syntax to file FILE.
1163 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1164 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1167 epiphany_print_operand (FILE *file
, rtx x
, int code
)
1172 fputs (epiphany_condition_codes
[get_epiphany_condition_code (x
)], file
);
1175 fputs (epiphany_condition_codes
[EPIPHANY_INVERSE_CONDITION_CODE
1176 (get_epiphany_condition_code (x
))],
1181 current_frame_info
.stld_sz
= 8;
1185 current_frame_info
.stld_sz
= 4;
1189 current_frame_info
.stld_sz
= 2;
1193 fputs (REG_P (x
) ? "jalr " : "bl ", file
);
1197 fprintf (file
, "r%d", epiphany_m1reg
);
1201 /* Do nothing special. */
1205 output_operand_lossage ("invalid operand output code");
1208 switch (GET_CODE (x
))
1214 fputs (reg_names
[REGNO (x
)], file
);
1218 current_frame_info
.stld_sz
= 1;
1221 switch (GET_CODE (addr
))
1224 offset
= GEN_INT (GET_MODE_SIZE (GET_MODE (x
)));
1225 addr
= XEXP (addr
, 0);
1228 offset
= GEN_INT (-GET_MODE_SIZE (GET_MODE (x
)));
1229 addr
= XEXP (addr
, 0);
1232 offset
= XEXP (XEXP (addr
, 1), 1);
1233 addr
= XEXP (addr
, 0);
1239 output_address (addr
);
1244 if (CONST_INT_P (offset
)) switch (GET_MODE_SIZE (GET_MODE (x
)))
1249 offset
= GEN_INT (INTVAL (offset
) >> 3);
1252 offset
= GEN_INT (INTVAL (offset
) >> 2);
1255 offset
= GEN_INT (INTVAL (offset
) >> 1);
1260 output_address (offset
);
1264 /* We handle SFmode constants here as output_addr_const doesn't. */
1265 if (GET_MODE (x
) == SFmode
)
1270 REAL_VALUE_FROM_CONST_DOUBLE (d
, x
);
1271 REAL_VALUE_TO_TARGET_SINGLE (d
, l
);
1272 fprintf (file
, "%s0x%08lx", IMMEDIATE_PREFIX
, l
);
1275 /* Fall through. Let output_addr_const deal with it. */
1277 fprintf(file
,"%s",IMMEDIATE_PREFIX
);
1278 if (code
== 'C' || code
== 'X')
1280 fprintf (file
, "%ld",
1281 (long) (INTVAL (x
) / current_frame_info
.stld_sz
));
1286 output_addr_const (file
, x
);
1291 /* Print a memory address as an operand to reference that memory location. */
1294 epiphany_print_operand_address (FILE *file
, rtx addr
)
1296 register rtx base
, index
= 0;
1299 switch (GET_CODE (addr
))
1302 fputs (reg_names
[REGNO (addr
)], file
);
1305 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr
))
1307 output_addr_const (file
, addr
);
1311 output_addr_const (file
, addr
);
1315 if (GET_CODE (XEXP (addr
, 0)) == CONST_INT
)
1316 offset
= INTVAL (XEXP (addr
, 0)), base
= XEXP (addr
, 1);
1317 else if (GET_CODE (XEXP (addr
, 1)) == CONST_INT
)
1318 offset
= INTVAL (XEXP (addr
, 1)), base
= XEXP (addr
, 0);
1320 base
= XEXP (addr
, 0), index
= XEXP (addr
, 1);
1321 gcc_assert (GET_CODE (base
) == REG
);
1322 fputs (reg_names
[REGNO (base
)], file
);
1326 ** ++rk quirky method to scale offset for ld/str.......
1328 fprintf (file
, ",%s%d", IMMEDIATE_PREFIX
,
1329 offset
/current_frame_info
.stld_sz
);
1333 switch (GET_CODE (index
))
1336 fprintf (file
, ",%s", reg_names
[REGNO (index
)]);
1339 fputc (',', file
), output_addr_const (file
, index
);
1346 case PRE_INC
: case PRE_DEC
: case POST_INC
: case POST_DEC
: case POST_MODIFY
:
1347 /* We shouldn't get here as we've lost the mode of the memory object
1348 (which says how much to inc/dec by. */
1352 output_addr_const (file
, addr
);
1358 epiphany_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED
,
1359 rtx
*opvec ATTRIBUTE_UNUSED
,
1360 int noperands ATTRIBUTE_UNUSED
)
1362 int i
= epiphany_n_nops
;
1363 rtx pat ATTRIBUTE_UNUSED
;
1366 fputs ("\tnop\n", asm_out_file
);
1370 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1373 epiphany_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
1375 HOST_WIDE_INT size
= int_size_in_bytes (type
);
1377 if (AGGREGATE_TYPE_P (type
)
1378 && (TYPE_MODE (type
) == BLKmode
|| TYPE_NEEDS_CONSTRUCTING (type
)))
1380 return (size
== -1 || size
> 8);
1383 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1384 passed by reference. */
1387 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED
,
1388 enum machine_mode mode
, const_tree type
,
1389 bool named ATTRIBUTE_UNUSED
)
1393 if (AGGREGATE_TYPE_P (type
)
1394 && (mode
== BLKmode
|| TYPE_NEEDS_CONSTRUCTING (type
)))
1402 epiphany_function_value (const_tree ret_type
,
1403 const_tree fn_decl_or_type ATTRIBUTE_UNUSED
,
1404 bool outgoing ATTRIBUTE_UNUSED
)
1406 enum machine_mode mode
;
1408 mode
= TYPE_MODE (ret_type
);
1409 /* We must change the mode like PROMOTE_MODE does.
1410 ??? PROMOTE_MODE is ignored for non-scalar types.
1411 The set of types tested here has to be kept in sync
1412 with the one in explow.c:promote_mode. */
1413 if (GET_MODE_CLASS (mode
) == MODE_INT
1414 && GET_MODE_SIZE (mode
) < 4
1415 && (TREE_CODE (ret_type
) == INTEGER_TYPE
1416 || TREE_CODE (ret_type
) == ENUMERAL_TYPE
1417 || TREE_CODE (ret_type
) == BOOLEAN_TYPE
1418 || TREE_CODE (ret_type
) == OFFSET_TYPE
))
1420 return gen_rtx_REG (mode
, 0);
1424 epiphany_libcall_value (enum machine_mode mode
, const_rtx fun ATTRIBUTE_UNUSED
)
1426 return gen_rtx_REG (mode
, 0);
1430 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED
)
1435 /* Fix up invalid option settings. */
1437 epiphany_override_options (void)
1439 if (epiphany_stack_offset
< 4)
1440 error ("stack_offset must be at least 4");
1441 if (epiphany_stack_offset
& 3)
1442 error ("stack_offset must be a multiple of 4");
1443 epiphany_stack_offset
= (epiphany_stack_offset
+ 3) & -4;
1445 /* This needs to be done at start up. It's convenient to do it here. */
1449 /* For a DImode load / store SET, make a SImode set for a
1450 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1453 frame_subreg_note (rtx set
, int offset
)
1455 rtx src
= simplify_gen_subreg (SImode
, SET_SRC (set
), DImode
, offset
);
1456 rtx dst
= simplify_gen_subreg (SImode
, SET_DEST (set
), DImode
, offset
);
1458 set
= gen_rtx_SET (VOIDmode
, dst
,src
);
1459 RTX_FRAME_RELATED_P (set
) = 1;
1467 rtx note
= NULL_RTX
;
1469 if (GET_CODE (x
) == PARALLEL
)
1471 rtx part
= XVECEXP (x
, 0, 0);
1473 if (GET_MODE (SET_DEST (part
)) == DImode
)
1475 note
= gen_rtx_PARALLEL (VOIDmode
, rtvec_alloc (XVECLEN (x
, 0) + 1));
1476 XVECEXP (note
, 0, 0) = frame_subreg_note (part
, 0);
1477 XVECEXP (note
, 0, 1) = frame_subreg_note (part
, UNITS_PER_WORD
);
1478 for (i
= XVECLEN (x
, 0) - 1; i
>= 1; i
--)
1480 part
= copy_rtx (XVECEXP (x
, 0, i
));
1482 if (GET_CODE (part
) == SET
)
1483 RTX_FRAME_RELATED_P (part
) = 1;
1484 XVECEXP (note
, 0, i
+ 1) = part
;
1489 for (i
= XVECLEN (x
, 0) - 1; i
>= 0; i
--)
1491 part
= XVECEXP (x
, 0, i
);
1493 if (GET_CODE (part
) == SET
)
1494 RTX_FRAME_RELATED_P (part
) = 1;
1498 else if (GET_CODE (x
) == SET
&& GET_MODE (SET_DEST (x
)) == DImode
)
1499 note
= gen_rtx_PARALLEL (VOIDmode
,
1500 gen_rtvec (2, frame_subreg_note (x
, 0),
1501 frame_subreg_note (x
, UNITS_PER_WORD
)));
1503 RTX_FRAME_RELATED_P (x
) = 1;
1505 add_reg_note (x
, REG_FRAME_RELATED_EXPR
, note
);
1510 frame_move_insn (rtx to
, rtx from
)
1512 return frame_insn (gen_rtx_SET (VOIDmode
, to
, from
));
1515 /* Generate a MEM referring to a varargs argument slot. */
1518 gen_varargs_mem (enum machine_mode mode
, rtx addr
)
1520 rtx mem
= gen_rtx_MEM (mode
, addr
);
1521 MEM_NOTRAP_P (mem
) = 1;
1522 set_mem_alias_set (mem
, get_varargs_alias_set ());
1526 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1527 If EPILOGUE_P is 0, save; if it is one, restore.
1528 ADDR is the stack slot to save the first register to; subsequent
1529 registers are written to lower addresses.
1530 However, the order of register pairs can be reversed in order to
1531 use double-word load-store instructions. Likewise, an unpaired single
1532 word save slot can be skipped while double saves are carried out, and
1533 reused when a single register is to be saved. */
1536 epiphany_emit_save_restore (int min
, int limit
, rtx addr
, int epilogue_p
)
1540 = current_frame_info
.first_slot
>= 0 ? epiphany_stack_offset
: 0;
1541 rtx skipped_mem
= NULL_RTX
;
1542 int last_saved
= limit
- 1;
1545 while (last_saved
>= 0
1546 && !TEST_HARD_REG_BIT (current_frame_info
.gmask
, last_saved
))
1548 for (i
= 0; i
< limit
; i
++)
1550 enum machine_mode mode
= word_mode
;
1553 rtx (*gen_mem
) (enum machine_mode
, rtx
) = gen_frame_mem
;
1555 /* Make sure we push the arguments in the right order. */
1556 if (n
< MAX_EPIPHANY_PARM_REGS
&& crtl
->args
.pretend_args_size
)
1558 n
= MAX_EPIPHANY_PARM_REGS
- 1 - n
;
1559 gen_mem
= gen_varargs_mem
;
1561 if (stack_offset
== current_frame_info
.first_slot_size
1562 && current_frame_info
.first_slot
>= 0)
1564 if (current_frame_info
.first_slot_size
> UNITS_PER_WORD
)
1567 addr
= plus_constant (Pmode
, addr
,
1568 - (HOST_WIDE_INT
) UNITS_PER_WORD
);
1570 if (i
-- < min
|| !epilogue_p
)
1572 n
= current_frame_info
.first_slot
;
1573 gen_mem
= gen_frame_mem
;
1575 else if (n
== UNKNOWN_REGNUM
1576 && stack_offset
> current_frame_info
.first_slot_size
)
1581 else if (!TEST_HARD_REG_BIT (current_frame_info
.gmask
, n
))
1586 /* Check for a register pair to save. */
1588 && (n
>= MAX_EPIPHANY_PARM_REGS
|| crtl
->args
.pretend_args_size
== 0)
1589 && (n
& 1) == 0 && n
+1 < limit
1590 && TEST_HARD_REG_BIT (current_frame_info
.gmask
, n
+1))
1592 /* If it fits in the current stack slot pair, place it there. */
1593 if (GET_CODE (addr
) == PLUS
&& (stack_offset
& 7) == 0
1594 && stack_offset
!= 2 * UNITS_PER_WORD
1595 && (current_frame_info
.last_slot
< 0
1596 || INTVAL (XEXP (addr
, 1)) != UNITS_PER_WORD
)
1597 && (n
+1 != last_saved
|| !skipped_mem
))
1601 addr
= plus_constant (Pmode
, addr
,
1602 - (HOST_WIDE_INT
) UNITS_PER_WORD
);
1604 /* If it fits in the following stack slot pair, that's fine, too. */
1605 else if (GET_CODE (addr
) == PLUS
&& (stack_offset
& 7) == 4
1606 && stack_offset
!= 2 * UNITS_PER_WORD
1607 && stack_offset
!= 3 * UNITS_PER_WORD
1608 && (current_frame_info
.last_slot
< 0
1609 || INTVAL (XEXP (addr
, 1)) != 2 * UNITS_PER_WORD
)
1610 && n
+ 1 != last_saved
)
1612 gcc_assert (!skipped_mem
);
1613 stack_offset
-= GET_MODE_SIZE (mode
);
1614 skipped_mem
= gen_mem (mode
, addr
);
1617 addr
= plus_constant (Pmode
, addr
,
1618 - (HOST_WIDE_INT
) 2 * UNITS_PER_WORD
);
1621 reg
= gen_rtx_REG (mode
, n
);
1622 if (mode
!= DImode
&& skipped_mem
)
1625 mem
= gen_mem (mode
, addr
);
1627 frame_move_insn (mem
, reg
);
1628 else if (n
>= MAX_EPIPHANY_PARM_REGS
|| !crtl
->args
.pretend_args_size
)
1629 emit_move_insn (reg
, mem
);
1630 if (mem
== skipped_mem
)
1632 skipped_mem
= NULL_RTX
;
1636 addr
= plus_constant (Pmode
, addr
, -(HOST_WIDE_INT
) UNITS_PER_WORD
);
1637 stack_offset
-= GET_MODE_SIZE (mode
);
1642 epiphany_expand_prologue (void)
1645 enum epiphany_function_type fn_type
;
1646 rtx addr
, mem
, off
, reg
;
1649 if (!current_frame_info
.initialized
)
1650 epiphany_compute_frame_size (get_frame_size ());
1652 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1653 if (flag_stack_usage_info
)
1654 current_function_static_stack_size
= current_frame_info
.total_size
;
1656 fn_type
= epiphany_compute_function_type (current_function_decl
);
1657 interrupt_p
= EPIPHANY_INTERRUPT_P (fn_type
);
1661 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1662 - (HOST_WIDE_INT
) 2 * UNITS_PER_WORD
);
1663 if (!lookup_attribute ("forwarder_section",
1664 DECL_ATTRIBUTES (current_function_decl
))
1665 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl
),
1667 frame_move_insn (gen_frame_mem (DImode
, addr
),
1668 gen_rtx_REG (DImode
, GPR_0
));
1669 frame_move_insn (gen_rtx_REG (SImode
, GPR_0
),
1670 gen_rtx_REG (word_mode
, STATUS_REGNUM
));
1671 frame_move_insn (gen_rtx_REG (SImode
, GPR_0
+1),
1672 gen_rtx_REG (word_mode
, IRET_REGNUM
));
1673 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1674 off
= GEN_INT (-current_frame_info
.first_slot_offset
);
1675 frame_insn (gen_stack_adjust_add (off
, mem
));
1676 if (!epiphany_uninterruptible_p (current_function_decl
))
1677 emit_insn (gen_gie ());
1678 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1679 current_frame_info
.first_slot_offset
1680 - (HOST_WIDE_INT
) 3 * UNITS_PER_WORD
);
1684 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1685 epiphany_stack_offset
1686 - (HOST_WIDE_INT
) UNITS_PER_WORD
);
1687 epiphany_emit_save_restore (0, current_frame_info
.small_threshold
,
1689 /* Allocate register save area; for small to medium size frames,
1690 allocate the entire frame; this is joint with one register save. */
1691 if (current_frame_info
.first_slot
>= 0)
1693 enum machine_mode mode
1694 = (current_frame_info
.first_slot_size
== UNITS_PER_WORD
1695 ? word_mode
: DImode
);
1697 off
= GEN_INT (-current_frame_info
.first_slot_offset
);
1698 mem
= gen_frame_mem (BLKmode
,
1699 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, off
));
1700 frame_insn (gen_stack_adjust_str
1701 (gen_frame_mem (mode
, stack_pointer_rtx
),
1702 gen_rtx_REG (mode
, current_frame_info
.first_slot
),
1704 addr
= plus_constant (Pmode
, addr
,
1705 current_frame_info
.first_slot_offset
);
1708 epiphany_emit_save_restore (current_frame_info
.small_threshold
,
1709 FIRST_PSEUDO_REGISTER
, addr
, 0);
1710 if (current_frame_info
.need_fp
)
1711 frame_move_insn (hard_frame_pointer_rtx
, stack_pointer_rtx
);
1712 /* For large frames, allocate bulk of frame. This is usually joint with one
1714 if (current_frame_info
.last_slot
>= 0)
1716 gcc_assert (current_frame_info
.last_slot
!= GPR_FP
1717 || (!current_frame_info
.need_fp
1718 && current_frame_info
.first_slot
< 0));
1719 off
= GEN_INT (-current_frame_info
.last_slot_offset
);
1720 mem
= gen_frame_mem (BLKmode
,
1721 gen_rtx_PLUS (Pmode
, stack_pointer_rtx
, off
));
1722 reg
= gen_rtx_REG (Pmode
, GPR_IP
);
1723 frame_move_insn (reg
, off
);
1724 frame_insn (gen_stack_adjust_str
1725 (gen_frame_mem (word_mode
, stack_pointer_rtx
),
1726 gen_rtx_REG (word_mode
, current_frame_info
.last_slot
),
1729 /* If there is only one or no register to save, yet we have a large frame,
1731 else if (current_frame_info
.last_slot_offset
)
1733 mem
= gen_frame_mem (BLKmode
,
1734 plus_constant (Pmode
, stack_pointer_rtx
,
1735 current_frame_info
.last_slot_offset
));
1736 off
= GEN_INT (-current_frame_info
.last_slot_offset
);
1737 if (!SIMM11 (INTVAL (off
)))
1739 reg
= gen_rtx_REG (Pmode
, GPR_IP
);
1740 frame_move_insn (reg
, off
);
1743 frame_insn (gen_stack_adjust_add (off
, mem
));
1746 /* Mode switching uses get_hard_reg_initial_val after
1747 emit_initial_value_sets, so we have to fix this up now. */
1748 save_config
= has_hard_reg_initial_val (SImode
, CONFIG_REGNUM
);
1751 if (REG_P (save_config
))
1753 if (REGNO (save_config
) >= FIRST_PSEUDO_REGISTER
)
1754 gcc_assert (!df_regs_ever_live_p (REGNO (save_config
)));
1756 frame_move_insn (save_config
,
1757 get_hard_reg_initial_reg (save_config
));
1761 rtx save_dst
= save_config
;
1763 reg
= gen_rtx_REG (SImode
, GPR_IP
);
1764 gcc_assert (MEM_P (save_dst
));
1765 if (!memory_operand (save_dst
, SImode
))
1767 rtx addr
= XEXP (save_dst
, 0);
1768 rtx reg2
= gen_rtx_REG (SImode
, GPR_16
);
1770 gcc_assert (GET_CODE (addr
) == PLUS
);
1771 gcc_assert (XEXP (addr
, 0) == hard_frame_pointer_rtx
1772 || XEXP (addr
, 0) == stack_pointer_rtx
);
1773 emit_move_insn (reg2
, XEXP (addr
, 1));
1775 = replace_equiv_address (save_dst
,
1776 gen_rtx_PLUS (Pmode
, XEXP (addr
, 0),
1779 emit_move_insn (reg
, get_hard_reg_initial_reg (save_config
));
1780 emit_move_insn (save_dst
, reg
);
1786 epiphany_expand_epilogue (int sibcall_p
)
1789 enum epiphany_function_type fn_type
;
1790 rtx mem
, addr
, reg
, off
;
1791 HOST_WIDE_INT restore_offset
;
1793 fn_type
= epiphany_compute_function_type( current_function_decl
);
1794 interrupt_p
= EPIPHANY_INTERRUPT_P (fn_type
);
1796 /* For variable frames, deallocate bulk of frame. */
1797 if (current_frame_info
.need_fp
)
1799 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1800 emit_insn (gen_stack_adjust_mov (mem
));
1802 /* Else for large static frames, deallocate bulk of frame. */
1803 else if (current_frame_info
.last_slot_offset
)
1805 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1806 reg
= gen_rtx_REG (Pmode
, GPR_IP
);
1807 emit_move_insn (reg
, GEN_INT (current_frame_info
.last_slot_offset
));
1808 emit_insn (gen_stack_adjust_add (reg
, mem
));
1810 restore_offset
= (interrupt_p
1811 ? - 3 * UNITS_PER_WORD
1812 : epiphany_stack_offset
- (HOST_WIDE_INT
) UNITS_PER_WORD
);
1813 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1814 (current_frame_info
.first_slot_offset
1816 epiphany_emit_save_restore (current_frame_info
.small_threshold
,
1817 FIRST_PSEUDO_REGISTER
, addr
, 1);
1819 if (interrupt_p
&& !epiphany_uninterruptible_p (current_function_decl
))
1820 emit_insn (gen_gid ());
1822 off
= GEN_INT (current_frame_info
.first_slot_offset
);
1823 mem
= gen_frame_mem (BLKmode
, stack_pointer_rtx
);
1824 /* For large / variable size frames, deallocating the register save area is
1825 joint with one register restore; for medium size frames, we use a
1826 dummy post-increment load to dealloacte the whole frame. */
1827 if (!SIMM11 (INTVAL (off
)) || current_frame_info
.last_slot
>= 0)
1829 emit_insn (gen_stack_adjust_ldr
1830 (gen_rtx_REG (word_mode
,
1831 (current_frame_info
.last_slot
>= 0
1832 ? current_frame_info
.last_slot
: GPR_IP
)),
1833 gen_frame_mem (word_mode
, stack_pointer_rtx
),
1837 /* While for small frames, we deallocate the entire frame with one add. */
1838 else if (INTVAL (off
))
1840 emit_insn (gen_stack_adjust_add (off
, mem
));
1844 emit_move_insn (gen_rtx_REG (word_mode
, STATUS_REGNUM
),
1845 gen_rtx_REG (SImode
, GPR_0
));
1846 emit_move_insn (gen_rtx_REG (word_mode
, IRET_REGNUM
),
1847 gen_rtx_REG (SImode
, GPR_0
+1));
1848 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1849 - (HOST_WIDE_INT
) 2 * UNITS_PER_WORD
);
1850 emit_move_insn (gen_rtx_REG (DImode
, GPR_0
),
1851 gen_frame_mem (DImode
, addr
));
1853 addr
= plus_constant (Pmode
, stack_pointer_rtx
,
1854 epiphany_stack_offset
- (HOST_WIDE_INT
) UNITS_PER_WORD
);
1855 epiphany_emit_save_restore (0, current_frame_info
.small_threshold
, addr
, 1);
1859 emit_jump_insn (gen_return_internal_interrupt());
1861 emit_jump_insn (gen_return_i ());
1866 epiphany_initial_elimination_offset (int from
, int to
)
1868 epiphany_compute_frame_size (get_frame_size ());
1869 if (from
== FRAME_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
1870 return current_frame_info
.total_size
- current_frame_info
.reg_size
;
1871 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1872 return current_frame_info
.first_slot_offset
- current_frame_info
.reg_size
;
1873 if (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
)
1874 return (current_frame_info
.total_size
1875 - ((current_frame_info
.pretend_size
+ 4) & -8));
1876 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1877 return (current_frame_info
.first_slot_offset
1878 - ((current_frame_info
.pretend_size
+ 4) & -8));
1883 epiphany_regno_rename_ok (unsigned, unsigned dst
)
1885 enum epiphany_function_type fn_type
;
1887 fn_type
= epiphany_compute_function_type (current_function_decl
);
1888 if (!EPIPHANY_INTERRUPT_P (fn_type
))
1890 if (df_regs_ever_live_p (dst
))
1896 epiphany_issue_rate (void)
1901 /* Function to update the integer COST
1902 based on the relationship between INSN that is dependent on
1903 DEP_INSN through the dependence LINK. The default is to make no
1904 adjustment to COST. This can be used for example to specify to
1905 the scheduler that an output- or anti-dependence does not incur
1906 the same cost as a data-dependence. The return value should be
1907 the new value for COST. */
1909 epiphany_adjust_cost (rtx insn
, rtx link
, rtx dep_insn
, int cost
)
1911 if (REG_NOTE_KIND (link
) == 0)
1915 if (recog_memoized (insn
) < 0
1916 || recog_memoized (dep_insn
) < 0)
1919 dep_set
= single_set (dep_insn
);
1921 /* The latency that we specify in the scheduling description refers
1922 to the actual output, not to an auto-increment register; for that,
1923 the latency is one. */
1924 if (dep_set
&& MEM_P (SET_SRC (dep_set
)) && cost
> 1)
1926 rtx set
= single_set (insn
);
1929 && !reg_mentioned_p (SET_DEST (dep_set
), SET_SRC (set
))
1930 && (!MEM_P (SET_DEST (set
))
1931 || !reg_mentioned_p (SET_DEST (dep_set
),
1932 XEXP (SET_DEST (set
), 0))))
1939 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
1941 #define RTX_OK_FOR_BASE_P(X) \
1942 (REG_P (X) && REG_OK_FOR_BASE_P (X))
1944 #define RTX_OK_FOR_INDEX_P(MODE, X) \
1945 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
1946 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
1947 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
1949 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
1950 (GET_CODE (X) == PLUS \
1951 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
1952 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
1953 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
1956 epiphany_legitimate_address_p (enum machine_mode mode
, rtx x
, bool strict
)
1958 #define REG_OK_FOR_BASE_P(X) \
1959 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
1960 if (RTX_OK_FOR_BASE_P (x
))
1962 if (RTX_FRAME_OFFSET_P (x
))
1964 if (LEGITIMATE_OFFSET_ADDRESS_P (mode
, x
))
1966 /* If this is a misaligned stack access, don't force it to reg+index. */
1967 if (GET_MODE_SIZE (mode
) == 8
1968 && GET_CODE (x
) == PLUS
&& XEXP (x
, 0) == stack_pointer_rtx
1969 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
1970 && !(INTVAL (XEXP (x
, 1)) & 3)
1971 && INTVAL (XEXP (x
, 1)) >= -2047 * 4
1972 && INTVAL (XEXP (x
, 1)) <= 2046 * 4)
1975 && (GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == POST_INC
)
1976 && RTX_OK_FOR_BASE_P (XEXP ((x
), 0)))
1978 if ((TARGET_POST_MODIFY
|| reload_completed
)
1979 && GET_CODE (x
) == POST_MODIFY
1980 && GET_CODE (XEXP ((x
), 1)) == PLUS
1981 && rtx_equal_p (XEXP ((x
), 0), XEXP (XEXP ((x
), 1), 0))
1982 && LEGITIMATE_OFFSET_ADDRESS_P (mode
, XEXP ((x
), 1)))
1984 if (mode
== BLKmode
)
1990 epiphany_secondary_reload (bool in_p
, rtx x
, reg_class_t rclass
,
1991 enum machine_mode mode ATTRIBUTE_UNUSED
,
1992 secondary_reload_info
*sri
)
1994 /* This could give more reload inheritance, but we are missing some
1995 reload infrastructure. */
1997 if (in_p
&& GET_CODE (x
) == UNSPEC
1998 && satisfies_constraint_Sra (x
) && !satisfies_constraint_Rra (x
))
2000 gcc_assert (rclass
== GENERAL_REGS
);
2001 sri
->icode
= CODE_FOR_reload_insi_ra
;
2008 epiphany_is_long_call_p (rtx x
)
2010 tree decl
= SYMBOL_REF_DECL (x
);
2011 bool ret_val
= !TARGET_SHORT_CALLS
;
2014 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2015 probably encode information via encode_section_info, and also
2016 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2020 attrs
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
2021 if (lookup_attribute ("long_call", attrs
))
2023 else if (lookup_attribute ("short_call", attrs
))
2030 epiphany_small16 (rtx x
)
2033 rtx offs ATTRIBUTE_UNUSED
= const0_rtx
;
2035 if (GET_CODE (x
) == CONST
&& GET_CODE (XEXP (x
, 0)) == PLUS
)
2037 base
= XEXP (XEXP (x
, 0), 0);
2038 offs
= XEXP (XEXP (x
, 0), 1);
2040 if (GET_CODE (base
) == SYMBOL_REF
&& SYMBOL_REF_FUNCTION_P (base
)
2041 && epiphany_is_long_call_p (base
))
2043 return TARGET_SMALL16
!= 0;
2046 /* Return nonzero if it is ok to make a tail-call to DECL. */
2048 epiphany_function_ok_for_sibcall (tree decl
, tree exp
)
2050 bool cfun_interrupt_p
, call_interrupt_p
;
2052 cfun_interrupt_p
= EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2053 (current_function_decl
));
2055 call_interrupt_p
= EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl
));
2058 tree fn_type
= TREE_TYPE (CALL_EXPR_FN (exp
));
2060 gcc_assert (POINTER_TYPE_P (fn_type
));
2061 fn_type
= TREE_TYPE (fn_type
);
2062 gcc_assert (TREE_CODE (fn_type
) == FUNCTION_TYPE
2063 || TREE_CODE (fn_type
) == METHOD_TYPE
);
2065 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type
)) != NULL
;
2068 /* Don't tailcall from or to an ISR routine - although we could in
2069 principle tailcall from one ISR routine to another, we'd need to
2070 handle this in sibcall_epilogue to make it work. */
2071 if (cfun_interrupt_p
|| call_interrupt_p
)
2074 /* Everything else is ok. */
2078 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2080 Return true iff the type of T has the uninterruptible attribute.
2081 If T is NULL, return false. */
2083 epiphany_uninterruptible_p (tree t
)
2089 attrs
= TYPE_ATTRIBUTES (TREE_TYPE (t
));
2090 if (lookup_attribute ("disinterrupt", attrs
))
2097 epiphany_call_uninterruptible_p (rtx mem
)
2099 rtx addr
= XEXP (mem
, 0);
2102 if (GET_CODE (addr
) == SYMBOL_REF
)
2103 t
= SYMBOL_REF_DECL (addr
);
2106 return epiphany_uninterruptible_p (t
);
2109 static enum machine_mode
2110 epiphany_promote_function_mode (const_tree type
, enum machine_mode mode
,
2111 int *punsignedp ATTRIBUTE_UNUSED
,
2112 const_tree funtype ATTRIBUTE_UNUSED
,
2113 int for_return ATTRIBUTE_UNUSED
)
2117 return promote_mode (type
, mode
, &dummy
);
2121 epiphany_conditional_register_usage (void)
2125 if (PIC_OFFSET_TABLE_REGNUM
!= INVALID_REGNUM
)
2127 fixed_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
2128 call_used_regs
[PIC_OFFSET_TABLE_REGNUM
] = 1;
2130 if (TARGET_HALF_REG_FILE
)
2132 for (i
= 32; i
<= 63; i
++)
2135 call_used_regs
[i
] = 1;
2138 if (epiphany_m1reg
>= 0)
2140 fixed_regs
[epiphany_m1reg
] = 1;
2141 call_used_regs
[epiphany_m1reg
] = 1;
2143 if (!TARGET_PREFER_SHORT_INSN_REGS
)
2144 CLEAR_HARD_REG_SET (reg_class_contents
[SHORT_INSN_REGS
]);
2145 COPY_HARD_REG_SET (reg_class_contents
[SIBCALL_REGS
],
2146 reg_class_contents
[GENERAL_REGS
]);
2147 /* It would be simpler and quicker if we could just use
2148 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2149 it is set up later by our caller. */
2150 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
2151 if (!call_used_regs
[i
])
2152 CLEAR_HARD_REG_BIT (reg_class_contents
[SIBCALL_REGS
], i
);
2155 /* Determine where to put an argument to a function.
2156 Value is zero to push the argument on the stack,
2157 or a hard register in which to store the argument.
2159 MODE is the argument's machine mode.
2160 TYPE is the data type of the argument (as a tree).
2161 This is null for libcalls where that information may
2163 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2164 the preceding args and about the function being called.
2165 NAMED is nonzero if this argument is a named parameter
2166 (otherwise it is an extra parameter matching an ellipsis). */
2167 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2168 registers and the rest are pushed. */
2170 epiphany_function_arg (cumulative_args_t cum_v
, enum machine_mode mode
,
2171 const_tree type
, bool named ATTRIBUTE_UNUSED
)
2173 CUMULATIVE_ARGS cum
= *get_cumulative_args (cum_v
);
2175 if (PASS_IN_REG_P (cum
, mode
, type
))
2176 return gen_rtx_REG (mode
, ROUND_ADVANCE_CUM (cum
, mode
, type
));
2180 /* Update the data in CUM to advance over an argument
2181 of mode MODE and data type TYPE.
2182 (TYPE is null for libcalls where that information may not be available.) */
2184 epiphany_function_arg_advance (cumulative_args_t cum_v
, enum machine_mode mode
,
2185 const_tree type
, bool named ATTRIBUTE_UNUSED
)
2187 CUMULATIVE_ARGS
*cum
= get_cumulative_args (cum_v
);
2189 *cum
= ROUND_ADVANCE_CUM (*cum
, mode
, type
) + ROUND_ADVANCE_ARG (mode
, type
);
2192 /* Nested function support.
2193 An epiphany trampoline looks like this:
2194 mov r16,%low(fnaddr)
2195 movt r16,%high(fnaddr)
2200 #define EPIPHANY_LOW_RTX(X) \
2201 (gen_rtx_IOR (SImode, \
2202 gen_rtx_ASHIFT (SImode, \
2203 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2204 gen_rtx_ASHIFT (SImode, \
2205 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2206 #define EPIPHANY_HIGH_RTX(X) \
2207 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2209 /* Emit RTL insns to initialize the variable parts of a trampoline.
2210 FNADDR is an RTX for the address of the function's pure code.
2211 CXT is an RTX for the static chain value for the function. */
2213 epiphany_trampoline_init (rtx tramp_mem
, tree fndecl
, rtx cxt
)
2215 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
2216 rtx tramp
= force_reg (Pmode
, XEXP (tramp_mem
, 0));
2218 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 0)),
2219 gen_rtx_IOR (SImode
, GEN_INT (0x4002000b),
2220 EPIPHANY_LOW_RTX (fnaddr
)));
2221 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 4)),
2222 gen_rtx_IOR (SImode
, GEN_INT (0x5002000b),
2223 EPIPHANY_HIGH_RTX (fnaddr
)));
2224 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 8)),
2225 gen_rtx_IOR (SImode
, GEN_INT (0x2002800b),
2226 EPIPHANY_LOW_RTX (cxt
)));
2227 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 12)),
2228 gen_rtx_IOR (SImode
, GEN_INT (0x3002800b),
2229 EPIPHANY_HIGH_RTX (cxt
)));
2230 emit_move_insn (gen_rtx_MEM (SImode
, plus_constant (Pmode
, tramp
, 16)),
2231 GEN_INT (0x0802014f));
2235 epiphany_optimize_mode_switching (int entity
)
2237 if (MACHINE_FUNCTION (cfun
)->sw_entities_processed
& (1 << entity
))
2241 case EPIPHANY_MSW_ENTITY_AND
:
2242 case EPIPHANY_MSW_ENTITY_OR
:
2244 case EPIPHANY_MSW_ENTITY_NEAREST
:
2245 case EPIPHANY_MSW_ENTITY_TRUNC
:
2246 return optimize
> 0;
2247 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
:
2248 return MACHINE_FUNCTION (cfun
)->unknown_mode_uses
!= 0;
2249 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN
:
2250 return (MACHINE_FUNCTION (cfun
)->sw_entities_processed
2251 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
)) != 0;
2252 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
:
2253 return optimize
== 0 || current_pass
== &pass_mode_switch_use
.pass
;
2259 epiphany_mode_priority_to_mode (int entity
, unsigned priority
)
2261 if (entity
== EPIPHANY_MSW_ENTITY_AND
|| entity
== EPIPHANY_MSW_ENTITY_OR
)
2266 case 4: return FP_MODE_ROUND_UNKNOWN
;
2267 case 5: return FP_MODE_NONE
;
2268 default: gcc_unreachable ();
2270 switch ((enum attr_fp_mode
) epiphany_normal_fp_mode
)
2275 case 0: return FP_MODE_INT
;
2276 case 1: return epiphany_normal_fp_rounding
;
2277 case 2: return (epiphany_normal_fp_rounding
== FP_MODE_ROUND_NEAREST
2278 ? FP_MODE_ROUND_TRUNC
: FP_MODE_ROUND_NEAREST
);
2279 case 3: return FP_MODE_CALLER
;
2281 case FP_MODE_ROUND_NEAREST
:
2282 case FP_MODE_CALLER
:
2285 case 0: return FP_MODE_ROUND_NEAREST
;
2286 case 1: return FP_MODE_ROUND_TRUNC
;
2287 case 2: return FP_MODE_INT
;
2288 case 3: return FP_MODE_CALLER
;
2290 case FP_MODE_ROUND_TRUNC
:
2293 case 0: return FP_MODE_ROUND_TRUNC
;
2294 case 1: return FP_MODE_ROUND_NEAREST
;
2295 case 2: return FP_MODE_INT
;
2296 case 3: return FP_MODE_CALLER
;
2298 case FP_MODE_ROUND_UNKNOWN
:
2306 epiphany_mode_needed (int entity
, rtx insn
)
2308 enum attr_fp_mode mode
;
2310 if (recog_memoized (insn
) < 0)
2312 if (entity
== EPIPHANY_MSW_ENTITY_AND
2313 || entity
== EPIPHANY_MSW_ENTITY_OR
)
2315 return FP_MODE_NONE
;
2317 mode
= get_attr_fp_mode (insn
);
2321 case EPIPHANY_MSW_ENTITY_AND
:
2322 return mode
!= FP_MODE_INT
? 1 : 2;
2323 case EPIPHANY_MSW_ENTITY_OR
:
2324 return mode
== FP_MODE_INT
? 1 : 2;
2325 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN
:
2326 if (recog_memoized (insn
) == CODE_FOR_set_fp_mode
)
2327 mode
= (enum attr_fp_mode
) epiphany_mode_after (entity
, mode
, insn
);
2329 case EPIPHANY_MSW_ENTITY_NEAREST
:
2330 case EPIPHANY_MSW_ENTITY_TRUNC
:
2331 if (mode
== FP_MODE_ROUND_UNKNOWN
)
2333 MACHINE_FUNCTION (cfun
)->unknown_mode_uses
++;
2334 return FP_MODE_NONE
;
2337 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
:
2338 if (mode
== FP_MODE_ROUND_NEAREST
|| mode
== FP_MODE_ROUND_TRUNC
)
2339 return FP_MODE_ROUND_UNKNOWN
;
2341 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
:
2342 if (mode
== FP_MODE_ROUND_UNKNOWN
)
2343 return epiphany_normal_fp_rounding
;
2351 epiphany_mode_entry_exit (int entity
, bool exit
)
2353 int normal_mode
= epiphany_normal_fp_mode
;
2355 MACHINE_FUNCTION (cfun
)->sw_entities_processed
|= (1 << entity
);
2356 if (epiphany_is_interrupt_p (current_function_decl
))
2357 normal_mode
= FP_MODE_CALLER
;
2360 case EPIPHANY_MSW_ENTITY_AND
:
2362 return normal_mode
!= FP_MODE_INT
? 1 : 2;
2364 case EPIPHANY_MSW_ENTITY_OR
:
2366 return normal_mode
== FP_MODE_INT
? 1 : 2;
2368 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
:
2369 if (normal_mode
== FP_MODE_ROUND_NEAREST
2370 || normal_mode
== FP_MODE_ROUND_TRUNC
)
2371 return FP_MODE_ROUND_UNKNOWN
;
2373 case EPIPHANY_MSW_ENTITY_NEAREST
:
2374 case EPIPHANY_MSW_ENTITY_TRUNC
:
2375 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN
:
2376 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
:
2384 epiphany_mode_after (int entity
, int last_mode
, rtx insn
)
2386 /* We have too few call-saved registers to hope to keep the masks across
2388 if (entity
== EPIPHANY_MSW_ENTITY_AND
|| entity
== EPIPHANY_MSW_ENTITY_OR
)
2390 if (GET_CODE (insn
) == CALL_INSN
)
2394 if (recog_memoized (insn
) < 0)
2396 if (get_attr_fp_mode (insn
) == FP_MODE_ROUND_UNKNOWN
2397 && last_mode
!= FP_MODE_ROUND_NEAREST
&& last_mode
!= FP_MODE_ROUND_TRUNC
)
2399 if (entity
== EPIPHANY_MSW_ENTITY_NEAREST
)
2400 return FP_MODE_ROUND_NEAREST
;
2401 if (entity
== EPIPHANY_MSW_ENTITY_TRUNC
)
2402 return FP_MODE_ROUND_TRUNC
;
2404 if (recog_memoized (insn
) == CODE_FOR_set_fp_mode
)
2406 rtx src
= SET_SRC (XVECEXP (PATTERN (insn
), 0, 0));
2410 return FP_MODE_CALLER
;
2411 fp_mode
= INTVAL (XVECEXP (XEXP (src
, 0), 0, 0));
2412 if (entity
== EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2413 && (fp_mode
== FP_MODE_ROUND_NEAREST
2414 || fp_mode
== EPIPHANY_MSW_ENTITY_TRUNC
))
2415 return FP_MODE_ROUND_UNKNOWN
;
2422 emit_set_fp_mode (int entity
, int mode
, HARD_REG_SET regs_live ATTRIBUTE_UNUSED
)
2424 rtx save_cc
, cc_reg
, mask
, src
, src2
;
2425 enum attr_fp_mode fp_mode
;
2427 if (!MACHINE_FUNCTION (cfun
)->and_mask
)
2429 MACHINE_FUNCTION (cfun
)->and_mask
= gen_reg_rtx (SImode
);
2430 MACHINE_FUNCTION (cfun
)->or_mask
= gen_reg_rtx (SImode
);
2432 if (entity
== EPIPHANY_MSW_ENTITY_AND
)
2434 gcc_assert (mode
>= 0 && mode
<= 2);
2436 emit_move_insn (MACHINE_FUNCTION (cfun
)->and_mask
,
2437 gen_int_mode (0xfff1fffe, SImode
));
2440 else if (entity
== EPIPHANY_MSW_ENTITY_OR
)
2442 gcc_assert (mode
>= 0 && mode
<= 2);
2444 emit_move_insn (MACHINE_FUNCTION (cfun
)->or_mask
, GEN_INT(0x00080000));
2447 fp_mode
= (enum attr_fp_mode
) mode
;
2452 case FP_MODE_CALLER
:
2453 src
= get_hard_reg_initial_val (SImode
, CONFIG_REGNUM
);
2454 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2456 case FP_MODE_ROUND_UNKNOWN
:
2457 MACHINE_FUNCTION (cfun
)->unknown_mode_sets
++;
2458 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2460 case FP_MODE_ROUND_NEAREST
:
2461 if (entity
== EPIPHANY_MSW_ENTITY_TRUNC
)
2463 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2465 case FP_MODE_ROUND_TRUNC
:
2466 if (entity
== EPIPHANY_MSW_ENTITY_NEAREST
)
2468 mask
= MACHINE_FUNCTION (cfun
)->and_mask
;
2471 mask
= MACHINE_FUNCTION (cfun
)->or_mask
;
2477 save_cc
= gen_reg_rtx (CCmode
);
2478 cc_reg
= gen_rtx_REG (CCmode
, CC_REGNUM
);
2479 emit_move_insn (save_cc
, cc_reg
);
2480 mask
= force_reg (SImode
, mask
);
2483 rtvec v
= gen_rtvec (1, GEN_INT (fp_mode
));
2485 src
= gen_rtx_CONST (SImode
, gen_rtx_UNSPEC (SImode
, v
, UNSPEC_FP_MODE
));
2487 if (entity
== EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2488 || entity
== EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
)
2489 src2
= copy_rtx (src
);
2492 rtvec v
= gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN
));
2494 src2
= gen_rtx_CONST (SImode
, gen_rtx_UNSPEC (SImode
, v
, UNSPEC_FP_MODE
));
2496 emit_insn (gen_set_fp_mode (src
, src2
, mask
));
2497 emit_move_insn (cc_reg
, save_cc
);
2501 epiphany_expand_set_fp_mode (rtx
*operands
)
2503 rtx ctrl
= gen_rtx_REG (SImode
, CONFIG_REGNUM
);
2504 rtx src
= operands
[0];
2505 rtx mask_reg
= operands
[2];
2506 rtx scratch
= operands
[3];
2507 enum attr_fp_mode fp_mode
;
2510 gcc_assert (rtx_equal_p (src
, operands
[1])
2511 /* Sometimes reload gets silly and reloads the same pseudo
2512 into different registers. */
2513 || (REG_P (src
) && REG_P (operands
[1])));
2515 if (!epiphany_uninterruptible_p (current_function_decl
))
2516 emit_insn (gen_gid ());
2517 emit_move_insn (scratch
, ctrl
);
2519 if (GET_CODE (src
) == REG
)
2521 /* FP_MODE_CALLER */
2522 emit_insn (gen_xorsi3 (scratch
, scratch
, src
));
2523 emit_insn (gen_andsi3 (scratch
, scratch
, mask_reg
));
2524 emit_insn (gen_xorsi3 (scratch
, scratch
, src
));
2528 gcc_assert (GET_CODE (src
) == CONST
);
2529 src
= XEXP (src
, 0);
2530 fp_mode
= (enum attr_fp_mode
) INTVAL (XVECEXP (src
, 0, 0));
2533 case FP_MODE_ROUND_NEAREST
:
2534 emit_insn (gen_andsi3 (scratch
, scratch
, mask_reg
));
2536 case FP_MODE_ROUND_TRUNC
:
2537 emit_insn (gen_andsi3 (scratch
, scratch
, mask_reg
));
2538 emit_insn (gen_add2_insn (scratch
, const1_rtx
));
2541 emit_insn (gen_iorsi3 (scratch
, scratch
, mask_reg
));
2543 case FP_MODE_CALLER
:
2544 case FP_MODE_ROUND_UNKNOWN
:
2549 emit_move_insn (ctrl
, scratch
);
2550 if (!epiphany_uninterruptible_p (current_function_decl
))
2551 emit_insn (gen_gie ());
2555 epiphany_insert_mode_switch_use (rtx insn
,
2556 int entity ATTRIBUTE_UNUSED
,
2557 int mode ATTRIBUTE_UNUSED
)
2559 rtx pat
= PATTERN (insn
);
2562 rtx near
= gen_rtx_REG (SImode
, FP_NEAREST_REGNUM
);
2563 rtx trunc
= gen_rtx_REG (SImode
, FP_TRUNCATE_REGNUM
);
2565 if (entity
!= EPIPHANY_MSW_ENTITY_FPU_OMNIBUS
)
2567 switch ((enum attr_fp_mode
) get_attr_fp_mode (insn
))
2569 case FP_MODE_ROUND_NEAREST
:
2570 near
= gen_rtx_USE (VOIDmode
, near
);
2571 trunc
= gen_rtx_CLOBBER (VOIDmode
, trunc
);
2573 case FP_MODE_ROUND_TRUNC
:
2574 near
= gen_rtx_CLOBBER (VOIDmode
, near
);
2575 trunc
= gen_rtx_USE (VOIDmode
, trunc
);
2577 case FP_MODE_ROUND_UNKNOWN
:
2578 near
= gen_rtx_USE (VOIDmode
, gen_rtx_REG (SImode
, FP_ANYFP_REGNUM
));
2579 trunc
= copy_rtx (near
);
2582 case FP_MODE_CALLER
:
2583 near
= gen_rtx_USE (VOIDmode
, near
);
2584 trunc
= gen_rtx_USE (VOIDmode
, trunc
);
2589 gcc_assert (GET_CODE (pat
) == PARALLEL
);
2590 len
= XVECLEN (pat
, 0);
2591 v
= rtvec_alloc (len
+ 2);
2592 for (i
= 0; i
< len
; i
++)
2593 RTVEC_ELT (v
, i
) = XVECEXP (pat
, 0, i
);
2594 RTVEC_ELT (v
, len
) = near
;
2595 RTVEC_ELT (v
, len
+ 1) = trunc
;
2596 pat
= gen_rtx_PARALLEL (VOIDmode
, v
);
2597 PATTERN (insn
) = pat
;
2598 MACHINE_FUNCTION (cfun
)->control_use_inserted
= true;
2602 epiphany_epilogue_uses (int regno
)
2604 if (regno
== GPR_LR
)
2606 if (reload_completed
&& epiphany_is_interrupt_p (current_function_decl
))
2608 if (fixed_regs
[regno
]
2609 && regno
!= STATUS_REGNUM
&& regno
!= IRET_REGNUM
2610 && regno
!= FP_NEAREST_REGNUM
&& regno
!= FP_TRUNCATE_REGNUM
)
2614 if (regno
== FP_NEAREST_REGNUM
2615 && epiphany_normal_fp_mode
!= FP_MODE_ROUND_TRUNC
)
2617 if (regno
== FP_TRUNCATE_REGNUM
2618 && epiphany_normal_fp_mode
!= FP_MODE_ROUND_NEAREST
)
2624 epiphany_min_divisions_for_recip_mul (enum machine_mode mode
)
2626 if (flag_reciprocal_math
&& mode
== SFmode
)
2627 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2628 it already at the tree level and expose it to further optimizations. */
2630 return default_min_divisions_for_recip_mul (mode
);
2633 static enum machine_mode
2634 epiphany_preferred_simd_mode (enum machine_mode mode ATTRIBUTE_UNUSED
)
2636 return TARGET_VECT_DOUBLE
? DImode
: SImode
;
2640 epiphany_vector_mode_supported_p (enum machine_mode mode
)
2642 if (mode
== V2SFmode
)
2644 if (GET_MODE_CLASS (mode
) == MODE_VECTOR_INT
2645 && (GET_MODE_SIZE (mode
) == 4 || GET_MODE_SIZE (mode
) == 8))
2651 epiphany_vector_alignment_reachable (const_tree type
, bool is_packed
)
2653 /* Vectors which aren't in packed structures will not be less aligned than
2654 the natural alignment of their element type, so this is safe. */
2655 if (TYPE_ALIGN_UNIT (type
) == 4)
2658 return default_builtin_vector_alignment_reachable (type
, is_packed
);
2662 epiphany_support_vector_misalignment (enum machine_mode mode
, const_tree type
,
2663 int misalignment
, bool is_packed
)
2665 if (GET_MODE_SIZE (mode
) == 8 && misalignment
% 4 == 0)
2667 return default_builtin_support_vector_misalignment (mode
, type
, misalignment
,
2671 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2672 structs. Make structs double-word-aligned it they are a double word or
2673 (potentially) larger; failing that, do the same for a size of 32 bits. */
2675 epiphany_special_round_type_align (tree type
, unsigned computed
,
2678 unsigned align
= MAX (computed
, specified
);
2680 HOST_WIDE_INT total
, max
;
2681 unsigned try_align
= FASTEST_ALIGNMENT
;
2683 if (maximum_field_alignment
&& try_align
> maximum_field_alignment
)
2684 try_align
= maximum_field_alignment
;
2685 if (align
>= try_align
)
2687 for (max
= 0, field
= TYPE_FIELDS (type
); field
; field
= DECL_CHAIN (field
))
2691 if (TREE_CODE (field
) != FIELD_DECL
2692 || TREE_TYPE (field
) == error_mark_node
)
2694 offset
= bit_position (field
);
2695 size
= DECL_SIZE (field
);
2696 if (!host_integerp (offset
, 1) || !host_integerp (size
, 1)
2697 || TREE_INT_CST_LOW (offset
) >= try_align
2698 || TREE_INT_CST_LOW (size
) >= try_align
)
2700 total
= TREE_INT_CST_LOW (offset
) + TREE_INT_CST_LOW (size
);
2704 if (max
>= (HOST_WIDE_INT
) try_align
)
2706 else if (try_align
> 32 && max
>= 32)
2707 align
= max
> 32 ? 64 : 32;
2711 /* Upping the alignment of arrays in structs is not only a performance
2712 enhancement, it also helps preserve assumptions about how
2713 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2716 epiphany_adjust_field_align (tree field
, unsigned computed
)
2719 && TREE_CODE (TREE_TYPE (field
)) == ARRAY_TYPE
)
2721 tree elmsz
= TYPE_SIZE (TREE_TYPE (TREE_TYPE (field
)));
2723 if (!host_integerp (elmsz
, 1) || tree_low_cst (elmsz
, 1) >= 32)
2729 /* Output code to add DELTA to the first argument, and then jump
2730 to FUNCTION. Used for C++ multiple inheritance. */
2732 epiphany_output_mi_thunk (FILE *file
, tree thunk ATTRIBUTE_UNUSED
,
2733 HOST_WIDE_INT delta
,
2734 HOST_WIDE_INT vcall_offset
,
2738 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function
)), function
) ? 1 : 0;
2739 const char *this_name
= reg_names
[this_regno
];
2742 /* We use IP and R16 as a scratch registers. */
2743 gcc_assert (call_used_regs
[GPR_IP
]);
2744 gcc_assert (call_used_regs
[GPR_16
]);
2746 /* Add DELTA. When possible use a plain add, otherwise load it into
2747 a register first. */
2750 else if (SIMM11 (delta
))
2751 asm_fprintf (file
, "\tadd\t%s,%s,%d\n", this_name
, this_name
, (int) delta
);
2752 else if (delta
< 0 && delta
>= -0xffff)
2754 asm_fprintf (file
, "\tmov\tip,%d\n", (int) -delta
);
2755 asm_fprintf (file
, "\tsub\t%s,%s,ip\n", this_name
, this_name
);
2759 asm_fprintf (file
, "\tmov\tip,%%low(%ld)\n", (long) delta
);
2760 if (delta
& ~0xffff)
2761 asm_fprintf (file
, "\tmovt\tip,%%high(%ld)\n", (long) delta
);
2762 asm_fprintf (file
, "\tadd\t%s,%s,ip\n", this_name
, this_name
);
2765 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2766 if (vcall_offset
!= 0)
2768 /* ldr ip,[this] --> temp = *this
2769 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2770 add this,this,ip --> this+ = *(*this + vcall_offset) */
2771 asm_fprintf (file
, "\tldr\tip, [%s]\n", this_name
);
2772 if (vcall_offset
< -0x7ff * 4 || vcall_offset
> 0x7ff * 4
2773 || (vcall_offset
& 3) != 0)
2775 asm_fprintf (file
, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset
);
2776 asm_fprintf (file
, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset
);
2777 asm_fprintf (file
, "\tldr\tip, [ip,r16]\n");
2780 asm_fprintf (file
, "\tldr\tip, [ip,%d]\n", (int) vcall_offset
/ 4);
2781 asm_fprintf (file
, "\tadd\t%s, %s, ip\n", this_name
, this_name
);
2784 fname
= XSTR (XEXP (DECL_RTL (function
), 0), 0);
2785 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function
), 0)))
2787 fputs ("\tmov\tip,%low(", file
);
2788 assemble_name (file
, fname
);
2789 fputs (")\n\tmovt\tip,%high(", file
);
2790 assemble_name (file
, fname
);
2791 fputs (")\n\tjr ip\n", file
);
2795 fputs ("\tb\t", file
);
2796 assemble_name (file
, fname
);
2802 epiphany_start_function (FILE *file
, const char *name
, tree decl
)
2804 /* If the function doesn't fit into the on-chip memory, it will have a
2805 section attribute - or lack of it - that denotes it goes somewhere else.
2806 But the architecture spec says that an interrupt vector still has to
2807 point to on-chip memory. So we must place a jump there to get to the
2808 actual function implementation. The forwarder_section attribute
2809 specifies the section where this jump goes.
2810 This mechanism can also be useful to have a shortcall destination for
2811 a function that is actually placed much farther away. */
2812 tree attrs
, int_attr
, int_names
, int_name
, forwarder_attr
;
2814 attrs
= DECL_ATTRIBUTES (decl
);
2815 int_attr
= lookup_attribute ("interrupt", attrs
);
2817 for (int_names
= TREE_VALUE (int_attr
); int_names
;
2818 int_names
= TREE_CHAIN (int_names
))
2822 int_name
= TREE_VALUE (int_names
);
2823 sprintf (buf
, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name
));
2824 switch_to_section (get_section (buf
, SECTION_CODE
, decl
));
2825 fputs ("\tb\t", file
);
2826 assemble_name (file
, name
);
2829 forwarder_attr
= lookup_attribute ("forwarder_section", attrs
);
2832 const char *prefix
= "__forwarder_dst_";
2833 char *dst_name
= (char *) alloca (strlen (prefix
) + strlen (name
) + 1);
2835 strcpy (dst_name
, prefix
);
2836 strcat (dst_name
, name
);
2837 forwarder_attr
= TREE_VALUE (TREE_VALUE (forwarder_attr
));
2838 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr
),
2839 SECTION_CODE
, decl
));
2840 ASM_OUTPUT_FUNCTION_LABEL (file
, name
, decl
);
2841 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl
), 0)))
2846 fputs ("\tstrd r0,[sp,-1]\n", file
);
2849 gcc_assert (call_used_regs
[tmp
]);
2850 fprintf (file
, "\tmov r%d,%%low(", tmp
);
2851 assemble_name (file
, dst_name
);
2852 fprintf (file
, ")\n"
2853 "\tmovt r%d,%%high(", tmp
);
2854 assemble_name (file
, dst_name
);
2855 fprintf (file
, ")\n"
2860 fputs ("\tb\t", file
);
2861 assemble_name (file
, dst_name
);
2866 switch_to_section (function_section (decl
));
2867 ASM_OUTPUT_FUNCTION_LABEL (file
, name
, decl
);
2870 struct gcc_target targetm
= TARGET_INITIALIZER
;