* doc/invoke.texi (core-avx2): Document.
[official-gcc.git] / gcc / config / epiphany / epiphany.c
blob3b6f63ab975d35f3ccf8108def9570820f013d31
1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994-2013 Free Software Foundation, Inc.
3 Contributed by Embecosm on behalf of Adapteva, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
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 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "rtl.h"
27 #include "regs.h"
28 #include "hard-reg-set.h"
29 #include "real.h"
30 #include "insn-config.h"
31 #include "conditions.h"
32 #include "output.h"
33 #include "insn-attr.h"
34 #include "flags.h"
35 #include "function.h"
36 #include "expr.h"
37 #include "diagnostic-core.h"
38 #include "recog.h"
39 #include "toplev.h"
40 #include "tm_p.h"
41 #include "target.h"
42 #include "df.h"
43 #include "langhooks.h"
44 #include "insn-codes.h"
45 #include "ggc.h"
46 #include "tm-constrs.h"
47 #include "tree-pass.h" /* for current_pass */
49 /* Which cpu we're compiling for. */
50 int epiphany_cpu_type;
52 /* Name of mangle string to add to symbols to separate code compiled for each
53 cpu (or NULL). */
54 const char *epiphany_mangle_cpu;
56 /* Array of valid operand punctuation characters. */
57 char epiphany_punct_chars[256];
59 /* The rounding mode that we generally use for floating point. */
60 int epiphany_normal_fp_rounding;
62 static void epiphany_init_reg_tables (void);
63 static int get_epiphany_condition_code (rtx);
64 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
65 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
66 bool *);
67 static bool epiphany_pass_by_reference (cumulative_args_t, enum machine_mode,
68 const_tree, bool);
69 static rtx frame_insn (rtx);
71 /* defines for the initialization of the GCC target structure. */
72 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
74 #define TARGET_PRINT_OPERAND epiphany_print_operand
75 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
77 #define TARGET_RTX_COSTS epiphany_rtx_costs
78 #define TARGET_ADDRESS_COST epiphany_address_cost
79 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
81 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
82 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
84 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
85 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
86 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
87 #define TARGET_FUNCTION_VALUE epiphany_function_value
88 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
89 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
91 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
93 /* Using the simplistic varags handling forces us to do partial reg/stack
94 argument passing for types with larger size (> 4 bytes) than alignemnt. */
95 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
97 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
99 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
100 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
102 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
104 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
106 #define TARGET_OPTION_OVERRIDE epiphany_override_options
108 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
110 #define TARGET_FUNCTION_ARG epiphany_function_arg
112 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
114 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
116 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
118 /* Nonzero if the constant rtx value is a legitimate general operand.
119 We can handle any 32- or 64-bit constant. */
120 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
122 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
123 epiphany_min_divisions_for_recip_mul
125 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
127 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
129 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
130 epiphany_vector_alignment_reachable
132 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
133 epiphany_support_vector_misalignment
135 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
136 hook_bool_const_tree_hwi_hwi_const_tree_true
137 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
139 #include "target-def.h"
141 #undef TARGET_ASM_ALIGNED_HI_OP
142 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
143 #undef TARGET_ASM_ALIGNED_SI_OP
144 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
146 bool
147 epiphany_is_interrupt_p (tree decl)
149 tree attrs;
151 attrs = DECL_ATTRIBUTES (decl);
152 if (lookup_attribute ("interrupt", attrs))
153 return true;
154 else
155 return false;
158 /* Called from epiphany_override_options.
159 We use this to initialize various things. */
161 static void
162 epiphany_init (void)
164 /* N.B. this pass must not run before the first optimize_mode_switching
165 pass because of the side offect of epiphany_mode_needed on
166 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
167 pass_resolve_sw_modes. */
168 static struct register_pass_info insert_use_info
169 = { &pass_mode_switch_use.pass, "mode_sw",
170 1, PASS_POS_INSERT_AFTER
172 static struct register_pass_info mode_sw2_info
173 = { &pass_mode_switching.pass, "mode_sw",
174 1, PASS_POS_INSERT_AFTER
176 static struct register_pass_info mode_sw3_info
177 = { &pass_resolve_sw_modes.pass, "mode_sw",
178 1, PASS_POS_INSERT_AFTER
180 static struct register_pass_info mode_sw4_info
181 = { &pass_split_all_insns.pass, "mode_sw",
182 1, PASS_POS_INSERT_AFTER
184 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
185 #define N_ENTITIES ARRAY_SIZE (num_modes)
187 epiphany_init_reg_tables ();
189 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
190 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
191 epiphany_punct_chars['-'] = 1;
193 epiphany_normal_fp_rounding
194 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
195 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
196 register_pass (&mode_sw4_info);
197 register_pass (&mode_sw2_info);
198 register_pass (&mode_sw3_info);
199 register_pass (&insert_use_info);
200 register_pass (&mode_sw2_info);
201 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
202 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
204 #if 1 /* As long as peep2_rescan is not implemented,
205 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
206 we need a second peephole2 pass to get reasonable code. */
208 static struct register_pass_info peep2_2_info
209 = { &pass_peephole2.pass, "peephole2",
210 1, PASS_POS_INSERT_AFTER
213 register_pass (&peep2_2_info);
215 #endif
218 /* The condition codes of the EPIPHANY, and the inverse function. */
219 static const char *const epiphany_condition_codes[] =
220 { /* 0 1 2 3 4 5 6 7 8 9 */
221 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
222 /* 10 11 12 13 */
223 "beq","bne","blt", "blte",
226 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
228 /* Returns the index of the EPIPHANY condition code string in
229 `epiphany_condition_codes'. COMPARISON should be an rtx like
230 `(eq (...) (...))'. */
232 static int
233 get_epiphany_condition_code (rtx comparison)
235 switch (GET_MODE (XEXP (comparison, 0)))
237 case CCmode:
238 switch (GET_CODE (comparison))
240 case EQ : return 0;
241 case NE : return 1;
242 case LTU : return 2;
243 case GEU : return 3;
244 case GT : return 4;
245 case LE : return 5;
246 case GE : return 6;
247 case LT : return 7;
248 case GTU : return 8;
249 case LEU : return 9;
251 default : gcc_unreachable ();
253 case CC_N_NEmode:
254 switch (GET_CODE (comparison))
256 case EQ: return 6;
257 case NE: return 7;
258 default: gcc_unreachable ();
260 case CC_C_LTUmode:
261 switch (GET_CODE (comparison))
263 case GEU: return 2;
264 case LTU: return 3;
265 default: gcc_unreachable ();
267 case CC_C_GTUmode:
268 switch (GET_CODE (comparison))
270 case LEU: return 3;
271 case GTU: return 2;
272 default: gcc_unreachable ();
274 case CC_FPmode:
275 switch (GET_CODE (comparison))
277 case EQ: return 10;
278 case NE: return 11;
279 case LT: return 12;
280 case LE: return 13;
281 default: gcc_unreachable ();
283 case CC_FP_EQmode:
284 switch (GET_CODE (comparison))
286 case EQ: return 0;
287 case NE: return 1;
288 default: gcc_unreachable ();
290 case CC_FP_GTEmode:
291 switch (GET_CODE (comparison))
293 case EQ: return 0;
294 case NE: return 1;
295 case GT : return 4;
296 case GE : return 6;
297 case UNLE : return 5;
298 case UNLT : return 7;
299 default: gcc_unreachable ();
301 case CC_FP_ORDmode:
302 switch (GET_CODE (comparison))
304 case ORDERED: return 9;
305 case UNORDERED: return 8;
306 default: gcc_unreachable ();
308 case CC_FP_UNEQmode:
309 switch (GET_CODE (comparison))
311 case UNEQ: return 9;
312 case LTGT: return 8;
313 default: gcc_unreachable ();
315 default: gcc_unreachable ();
317 /*NOTREACHED*/
318 return (42);
322 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
324 hard_regno_mode_ok (int regno, enum machine_mode mode)
326 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
327 return (regno & 1) == 0 && GPR_P (regno);
328 else
329 return 1;
332 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
333 return the mode to be used for the comparison. */
335 enum machine_mode
336 epiphany_select_cc_mode (enum rtx_code op,
337 rtx x ATTRIBUTE_UNUSED,
338 rtx y ATTRIBUTE_UNUSED)
340 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
342 if (TARGET_SOFT_CMPSF
343 || op == ORDERED || op == UNORDERED)
345 if (op == EQ || op == NE)
346 return CC_FP_EQmode;
347 if (op == ORDERED || op == UNORDERED)
348 return CC_FP_ORDmode;
349 if (op == UNEQ || op == LTGT)
350 return CC_FP_UNEQmode;
351 return CC_FP_GTEmode;
353 return CC_FPmode;
355 /* recognize combiner pattern ashlsi_btst:
356 (parallel [
357 (set (reg:N_NE 65 cc1)
358 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
359 (const_int 1 [0x1])
360 (const_int 0 [0x0]))
361 (const_int 0 [0x0])))
362 (clobber (scratch:SI)) */
363 else if ((op == EQ || op == NE)
364 && GET_CODE (x) == ZERO_EXTRACT
365 && XEXP (x, 1) == const1_rtx
366 && CONST_INT_P (XEXP (x, 2)))
367 return CC_N_NEmode;
368 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
369 return CC_C_LTUmode;
370 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
371 return CC_C_GTUmode;
372 else
373 return CCmode;
376 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
378 static void
379 epiphany_init_reg_tables (void)
381 int i;
383 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
385 if (i == GPR_LR)
386 epiphany_regno_reg_class[i] = LR_REGS;
387 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
388 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
389 else if (call_used_regs[i]
390 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
391 epiphany_regno_reg_class[i] = SIBCALL_REGS;
392 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
393 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
394 else if (i < (GPR_LAST+1)
395 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
396 epiphany_regno_reg_class[i] = GENERAL_REGS;
397 else if (i == CC_REGNUM)
398 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
399 else
400 epiphany_regno_reg_class[i] = NO_REGS;
404 /* EPIPHANY specific attribute support.
406 The EPIPHANY has these attributes:
407 interrupt - for interrupt functions.
408 short_call - the function is assumed to be reachable with the b / bl
409 instructions.
410 long_call - the function address is loaded into a register before use.
411 disinterrupt - functions which mask interrupts throughout.
412 They unmask them while calling an interruptible
413 function, though. */
415 static const struct attribute_spec epiphany_attribute_table[] =
417 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
418 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
419 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
420 { "long_call", 0, 0, false, true, true, NULL, false },
421 { "short_call", 0, 0, false, true, true, NULL, false },
422 { "disinterrupt", 0, 0, false, true, true, NULL, true },
423 { NULL, 0, 0, false, false, false, NULL, false }
426 /* Handle an "interrupt" attribute; arguments as in
427 struct attribute_spec.handler. */
428 static tree
429 epiphany_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
430 tree name, tree args,
431 int flags ATTRIBUTE_UNUSED,
432 bool *no_add_attrs)
434 tree value;
436 if (!args)
437 return NULL_TREE;
439 value = TREE_VALUE (args);
441 if (TREE_CODE (value) != STRING_CST)
443 warning (OPT_Wattributes,
444 "argument of %qE attribute is not a string constant", name);
445 *no_add_attrs = true;
447 else if (strcmp (TREE_STRING_POINTER (value), "reset")
448 && strcmp (TREE_STRING_POINTER (value), "software_exception")
449 && strcmp (TREE_STRING_POINTER (value), "page_miss")
450 && strcmp (TREE_STRING_POINTER (value), "timer0")
451 && strcmp (TREE_STRING_POINTER (value), "timer1")
452 && strcmp (TREE_STRING_POINTER (value), "message")
453 && strcmp (TREE_STRING_POINTER (value), "dma0")
454 && strcmp (TREE_STRING_POINTER (value), "dma1")
455 && strcmp (TREE_STRING_POINTER (value), "wand")
456 && strcmp (TREE_STRING_POINTER (value), "swi"))
458 warning (OPT_Wattributes,
459 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
460 name);
461 *no_add_attrs = true;
462 return NULL_TREE;
465 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
466 flags, no_add_attrs);
469 /* Handle a "forwarder_section" attribute; arguments as in
470 struct attribute_spec.handler. */
471 static tree
472 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
473 tree name, tree args,
474 int flags ATTRIBUTE_UNUSED,
475 bool *no_add_attrs)
477 tree value;
479 value = TREE_VALUE (args);
481 if (TREE_CODE (value) != STRING_CST)
483 warning (OPT_Wattributes,
484 "argument of %qE attribute is not a string constant", name);
485 *no_add_attrs = true;
487 return NULL_TREE;
491 /* Misc. utilities. */
493 /* Generate a SYMBOL_REF for the special function NAME. When the address
494 can't be placed directly into a call instruction, and if possible, copy
495 it to a register so that cse / code hoisting is possible. */
497 sfunc_symbol (const char *name)
499 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
501 /* These sfuncs should be hidden, and every dso should get a copy. */
502 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
503 if (TARGET_SHORT_CALLS)
504 ; /* Nothing to be done. */
505 else if (can_create_pseudo_p ())
506 sym = copy_to_mode_reg (Pmode, sym);
507 else /* We rely on reload to fix this up. */
508 gcc_assert (!reload_in_progress || reload_completed);
509 return sym;
512 /* X and Y are two things to compare using CODE in IN_MODE.
513 Emit the compare insn, construct the the proper cc reg in the proper
514 mode, and return the rtx for the cc reg comparison in CMODE. */
517 gen_compare_reg (enum machine_mode cmode, enum rtx_code code,
518 enum machine_mode in_mode, rtx x, rtx y)
520 enum machine_mode mode = SELECT_CC_MODE (code, x, y);
521 rtx cc_reg, pat, clob0, clob1, clob2;
523 if (in_mode == VOIDmode)
524 in_mode = GET_MODE (x);
525 if (in_mode == VOIDmode)
526 in_mode = GET_MODE (y);
528 if (mode == CC_FPmode)
530 /* The epiphany has only EQ / NE / LT / LE conditions for
531 hardware floating point. */
532 if (code == GT || code == GE || code == UNLE || code == UNLT)
534 rtx tmp = x; x = y; y = tmp;
535 code = swap_condition (code);
537 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
538 y = force_reg (in_mode, y);
540 else
542 if (mode == CC_FP_GTEmode
543 && (code == LE || code == LT || code == UNGT || code == UNGE))
545 if (flag_finite_math_only
546 && ((REG_P (x) && REGNO (x) == GPR_0)
547 || (REG_P (y) && REGNO (y) == GPR_1)))
548 switch (code)
550 case LE: code = UNLE; break;
551 case LT: code = UNLT; break;
552 case UNGT: code = GT; break;
553 case UNGE: code = GE; break;
554 default: gcc_unreachable ();
556 else
558 rtx tmp = x; x = y; y = tmp;
559 code = swap_condition (code);
562 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
564 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
565 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
566 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
567 && (!REG_P (x) || REGNO (x) != GPR_0
568 || !REG_P (y) || REGNO (y) != GPR_1))
570 rtx reg;
572 #if 0
573 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
574 but just like the flag clobber of movsicc, we have to allow
575 this for ifcvt to work, on the assumption that we'll only want
576 to do this if these registers have been used before by the
577 pre-ifcvt code. */
578 gcc_assert (currently_expanding_to_rtl);
579 #endif
580 reg = gen_rtx_REG (in_mode, GPR_0);
581 if (reg_overlap_mentioned_p (reg, y))
582 return 0;
583 emit_move_insn (reg, x);
584 x = reg;
585 reg = gen_rtx_REG (in_mode, GPR_1);
586 emit_move_insn (reg, y);
587 y = reg;
589 else
590 x = force_reg (in_mode, x);
592 pat = gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y));
593 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
595 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
596 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
598 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
599 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
600 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
602 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
604 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
605 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
607 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
608 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
609 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
610 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
611 clob0, clob1, clob2));
613 else
615 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
616 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
618 emit_insn (pat);
619 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
622 /* The ROUND_ADVANCE* macros are local to this file. */
623 /* Round SIZE up to a word boundary. */
624 #define ROUND_ADVANCE(SIZE) \
625 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
627 /* Round arg MODE/TYPE up to the next word boundary. */
628 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
629 ((MODE) == BLKmode \
630 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
631 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
633 /* Round CUM up to the necessary point for argument MODE/TYPE. */
634 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
635 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
636 ? (((CUM) + 1) & ~1) \
637 : (CUM))
639 static unsigned int
640 epiphany_function_arg_boundary (enum machine_mode mode, const_tree type)
642 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
643 return PARM_BOUNDARY;
644 return 2 * PARM_BOUNDARY;
647 /* Do any needed setup for a variadic function. For the EPIPHANY, we
648 actually emit the code in epiphany_expand_prologue.
650 CUM has not been updated for the last named argument which has type TYPE
651 and mode MODE, and we rely on this fact. */
654 static void
655 epiphany_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
656 tree type, int *pretend_size, int no_rtl)
658 int first_anon_arg;
659 CUMULATIVE_ARGS next_cum;
660 machine_function_t *mf = MACHINE_FUNCTION (cfun);
662 /* All BLKmode values are passed by reference. */
663 gcc_assert (mode != BLKmode);
665 next_cum = *get_cumulative_args (cum);
666 next_cum
667 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
668 first_anon_arg = next_cum;
670 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
672 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
673 int first_reg_offset = first_anon_arg;
675 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
676 * UNITS_PER_WORD);
678 mf->args_parsed = 1;
679 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
682 static int
683 epiphany_arg_partial_bytes (cumulative_args_t cum, enum machine_mode mode,
684 tree type, bool named ATTRIBUTE_UNUSED)
686 int words = 0, rounded_cum;
688 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
690 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
691 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
693 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
694 if (words >= ROUND_ADVANCE_ARG (mode, type))
695 words = 0;
697 return words * UNITS_PER_WORD;
700 /* Cost functions. */
702 /* Compute a (partial) cost for rtx X. Return true if the complete
703 cost has been computed, and false if subexpressions should be
704 scanned. In either case, *TOTAL contains the cost result. */
706 static bool
707 epiphany_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
708 int *total, bool speed ATTRIBUTE_UNUSED)
710 switch (code)
712 /* Small integers in the right context are as cheap as registers. */
713 case CONST_INT:
714 if ((outer_code == PLUS || outer_code == MINUS)
715 && SIMM11 (INTVAL (x)))
717 *total = 0;
718 return true;
720 if (IMM16 (INTVAL (x)))
722 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
723 return true;
725 /* FALLTHRU */
727 case CONST:
728 case LABEL_REF:
729 case SYMBOL_REF:
730 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
731 + (outer_code == SET ? 0 : 1));
732 return true;
734 case CONST_DOUBLE:
736 rtx high, low;
737 split_double (x, &high, &low);
738 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
739 + !IMM16 (INTVAL (low)));
740 return true;
743 case ASHIFT:
744 case ASHIFTRT:
745 case LSHIFTRT:
746 *total = COSTS_N_INSNS (1);
747 return true;
749 default:
750 return false;
755 /* Provide the costs of an addressing mode that contains ADDR.
756 If ADDR is not a valid address, its cost is irrelevant. */
758 static int
759 epiphany_address_cost (rtx addr, enum machine_mode mode,
760 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
762 rtx reg;
763 rtx off = const0_rtx;
764 int i;
766 if (speed)
767 return 0;
768 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
769 in long insns. */
770 switch (GET_CODE (addr))
772 case PLUS :
773 reg = XEXP (addr, 0);
774 off = XEXP (addr, 1);
775 break;
776 case POST_MODIFY:
777 reg = XEXP (addr, 0);
778 off = XEXP (addr, 1);
779 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
780 off = XEXP (off, 1);
781 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
782 return 0;
783 return 1;
784 case REG:
785 default:
786 reg = addr;
787 break;
789 if (!satisfies_constraint_Rgs (reg))
790 return 1;
791 /* The offset range available for short instructions depends on the mode
792 of the memory access. */
793 /* First, make sure we have a valid integer. */
794 if (!satisfies_constraint_L (off))
795 return 1;
796 i = INTVAL (off);
797 switch (GET_MODE_SIZE (mode))
799 default:
800 case 4:
801 if (i & 1)
802 return 1;
803 i >>= 1;
804 /* Fall through. */
805 case 2:
806 if (i & 1)
807 return 1;
808 i >>= 1;
809 /* Fall through. */
810 case 1:
811 return i < -7 || i > 7;
815 /* Compute the cost of moving data between registers and memory.
816 For integer, load latency is twice as long as register-register moves,
817 but issue pich is the same. For floating point, load latency is three
818 times as much as a reg-reg move. */
819 static int
820 epiphany_memory_move_cost (enum machine_mode mode,
821 reg_class_t rclass ATTRIBUTE_UNUSED,
822 bool in ATTRIBUTE_UNUSED)
824 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
827 /* Function prologue/epilogue handlers. */
829 /* EPIPHANY stack frames look like:
831 Before call After call
832 +-----------------------+ +-----------------------+
833 | | | |
834 high | local variables, | | local variables, |
835 mem | reg save area, etc. | | reg save area, etc. |
836 | | | |
837 +-----------------------+ +-----------------------+
838 | | | |
839 | arguments on stack. | | arguments on stack. |
840 | | | |
841 SP+8->+-----------------------+FP+8m->+-----------------------+
842 | 2 word save area for | | reg parm save area, |
843 | leaf funcs / flags | | only created for |
844 SP+0->+-----------------------+ | variable argument |
845 | functions |
846 FP+8n->+-----------------------+
848 | register save area |
850 +-----------------------+
852 | local variables |
854 FP+0->+-----------------------+
856 | alloca allocations |
858 +-----------------------+
860 | arguments on stack |
862 SP+8->+-----------------------+
863 low | 2 word save area for |
864 memory | leaf funcs / flags |
865 SP+0->+-----------------------+
867 Notes:
868 1) The "reg parm save area" does not exist for non variable argument fns.
869 The "reg parm save area" could be eliminated if we created our
870 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
871 (so it's not done). */
873 /* Structure to be filled in by epiphany_compute_frame_size with register
874 save masks, and offsets for the current function. */
875 struct epiphany_frame_info
877 unsigned int total_size; /* # bytes that the entire frame takes up. */
878 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
879 unsigned int args_size; /* # bytes that outgoing arguments take up. */
880 unsigned int reg_size; /* # bytes needed to store regs. */
881 unsigned int var_size; /* # bytes that variables take up. */
882 HARD_REG_SET gmask; /* Set of saved gp registers. */
883 int initialized; /* Nonzero if frame size already calculated. */
884 int stld_sz; /* Current load/store data size for offset
885 adjustment. */
886 int need_fp; /* value to override "frame_pointer_needed */
887 int first_slot, last_slot, first_slot_offset, last_slot_offset;
888 int first_slot_size;
889 int small_threshold;
892 /* Current frame information calculated by epiphany_compute_frame_size. */
893 static struct epiphany_frame_info current_frame_info;
895 /* Zero structure to initialize current_frame_info. */
896 static struct epiphany_frame_info zero_frame_info;
898 /* The usual; we set up our machine_function data. */
899 static struct machine_function *
900 epiphany_init_machine_status (void)
902 struct machine_function *machine;
904 /* Reset state info for each function. */
905 current_frame_info = zero_frame_info;
907 machine = ggc_alloc_cleared_machine_function_t ();
909 return machine;
912 /* Implements INIT_EXPANDERS. We just set up to call the above
913 * function. */
914 void
915 epiphany_init_expanders (void)
917 init_machine_status = epiphany_init_machine_status;
920 /* Type of function DECL.
922 The result is cached. To reset the cache at the end of a function,
923 call with DECL = NULL_TREE. */
925 static enum epiphany_function_type
926 epiphany_compute_function_type (tree decl)
928 tree a;
929 /* Cached value. */
930 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
931 /* Last function we were called for. */
932 static tree last_fn = NULL_TREE;
934 /* Resetting the cached value? */
935 if (decl == NULL_TREE)
937 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
938 last_fn = NULL_TREE;
939 return fn_type;
942 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
943 return fn_type;
945 /* Assume we have a normal function (not an interrupt handler). */
946 fn_type = EPIPHANY_FUNCTION_NORMAL;
948 /* Now see if this is an interrupt handler. */
949 for (a = DECL_ATTRIBUTES (decl);
951 a = TREE_CHAIN (a))
953 tree name = TREE_PURPOSE (a);
955 if (name == get_identifier ("interrupt"))
956 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
959 last_fn = decl;
960 return fn_type;
963 #define RETURN_ADDR_REGNUM GPR_LR
964 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
965 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
967 /* Tell prologue and epilogue if register REGNO should be saved / restored.
968 The return address and frame pointer are treated separately.
969 Don't consider them here. */
970 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
971 ((df_regs_ever_live_p (regno) \
972 || (interrupt_p && !crtl->is_leaf \
973 && call_used_regs[regno] && !fixed_regs[regno])) \
974 && (!call_used_regs[regno] || regno == GPR_LR \
975 || (interrupt_p && regno != GPR_SP)))
977 #define MUST_SAVE_RETURN_ADDR 0
979 /* Return the bytes needed to compute the frame pointer from the current
980 stack pointer.
982 SIZE is the size needed for local variables. */
984 static unsigned int
985 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
987 int regno;
988 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
989 HARD_REG_SET gmask;
990 enum epiphany_function_type fn_type;
991 int interrupt_p;
992 int first_slot, last_slot, first_slot_offset, last_slot_offset;
993 int first_slot_size;
994 int small_slots = 0;
996 var_size = size;
997 args_size = crtl->outgoing_args_size;
998 pretend_size = crtl->args.pretend_args_size;
999 total_size = args_size + var_size;
1000 reg_size = 0;
1001 CLEAR_HARD_REG_SET (gmask);
1002 first_slot = -1;
1003 first_slot_offset = 0;
1004 last_slot = -1;
1005 last_slot_offset = 0;
1006 first_slot_size = UNITS_PER_WORD;
1008 /* See if this is an interrupt handler. Call used registers must be saved
1009 for them too. */
1010 fn_type = epiphany_compute_function_type (current_function_decl);
1011 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1013 /* Calculate space needed for registers. */
1015 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
1017 reg_size += UNITS_PER_WORD;
1018 SET_HARD_REG_BIT (gmask, regno);
1019 if (epiphany_stack_offset - reg_size == 0)
1020 first_slot = regno;
1023 if (interrupt_p)
1024 reg_size += 2 * UNITS_PER_WORD;
1025 else
1026 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
1028 if (frame_pointer_needed)
1030 current_frame_info.need_fp = 1;
1031 if (!interrupt_p && first_slot < 0)
1032 first_slot = GPR_FP;
1034 else
1035 current_frame_info.need_fp = 0;
1036 for (regno = 0; regno <= GPR_LAST; regno++)
1038 if (MUST_SAVE_REGISTER (regno, interrupt_p))
1040 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1041 reg_size += UNITS_PER_WORD;
1042 SET_HARD_REG_BIT (gmask, regno);
1043 /* FIXME: when optimizing for speed, take schedling into account
1044 when selecting these registers. */
1045 if (regno == first_slot)
1046 gcc_assert (regno == GPR_FP && frame_pointer_needed);
1047 else if (!interrupt_p && first_slot < 0)
1048 first_slot = regno;
1049 else if (last_slot < 0
1050 && (first_slot ^ regno) != 1
1051 && (!interrupt_p || regno > GPR_1))
1052 last_slot = regno;
1055 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1056 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1057 /* ??? Could sometimes do better than that. */
1058 current_frame_info.small_threshold
1059 = (optimize >= 3 || interrupt_p ? 0
1060 : pretend_size ? small_slots
1061 : 4 + small_slots - (first_slot == GPR_FP));
1063 /* If there might be variables with 64-bit alignment requirement, align the
1064 start of the variables. */
1065 if (var_size >= 2 * UNITS_PER_WORD
1066 /* We don't want to split a double reg save/restore across two unpaired
1067 stack slots when optimizing. This rounding could be avoided with
1068 more complex reordering of the register saves, but that would seem
1069 to be a lot of code complexity for little gain. */
1070 || (reg_size > 8 && optimize))
1071 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1072 if (total_size + reg_size <= (unsigned) epiphany_stack_offset
1073 && !interrupt_p
1074 && crtl->is_leaf && !frame_pointer_needed)
1076 first_slot = -1;
1077 last_slot = -1;
1078 goto alloc_done;
1080 else if (reg_size
1081 && !interrupt_p
1082 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1083 reg_size = epiphany_stack_offset;
1084 if (interrupt_p)
1086 if (total_size + reg_size < 0x3fc)
1088 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1089 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1090 last_slot = -1;
1092 else
1094 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1095 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1096 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1097 if (last_slot >= 0)
1098 CLEAR_HARD_REG_BIT (gmask, last_slot);
1101 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1103 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1104 last_slot = -1;
1106 else
1108 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1110 gcc_assert (first_slot < 0);
1111 gcc_assert (reg_size == 0);
1112 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1114 else
1116 first_slot_offset
1117 = (reg_size
1118 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1119 if (!first_slot_offset)
1121 if (first_slot != GPR_FP || !current_frame_info.need_fp)
1122 last_slot = first_slot;
1123 first_slot = -1;
1125 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1126 if (reg_size)
1127 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1129 if (last_slot >= 0)
1130 CLEAR_HARD_REG_BIT (gmask, last_slot);
1132 alloc_done:
1133 if (first_slot >= 0)
1135 CLEAR_HARD_REG_BIT (gmask, first_slot);
1136 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1137 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1139 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1140 first_slot_size = 2 * UNITS_PER_WORD;
1141 first_slot &= ~1;
1144 total_size = first_slot_offset + last_slot_offset;
1146 /* Save computed information. */
1147 current_frame_info.total_size = total_size;
1148 current_frame_info.pretend_size = pretend_size;
1149 current_frame_info.var_size = var_size;
1150 current_frame_info.args_size = args_size;
1151 current_frame_info.reg_size = reg_size;
1152 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1153 current_frame_info.first_slot = first_slot;
1154 current_frame_info.last_slot = last_slot;
1155 current_frame_info.first_slot_offset = first_slot_offset;
1156 current_frame_info.first_slot_size = first_slot_size;
1157 current_frame_info.last_slot_offset = last_slot_offset;
1159 current_frame_info.initialized = reload_completed;
1161 /* Ok, we're done. */
1162 return total_size;
1165 /* Print operand X (an rtx) in assembler syntax to file FILE.
1166 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1167 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1169 static void
1170 epiphany_print_operand (FILE *file, rtx x, int code)
1172 switch (code)
1174 case 'd':
1175 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1176 return;
1177 case 'D':
1178 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1179 (get_epiphany_condition_code (x))],
1180 file);
1181 return;
1183 case 'X':
1184 current_frame_info.stld_sz = 8;
1185 break;
1187 case 'C' :
1188 current_frame_info.stld_sz = 4;
1189 break;
1191 case 'c' :
1192 current_frame_info.stld_sz = 2;
1193 break;
1195 case 'f':
1196 fputs (REG_P (x) ? "jalr " : "bl ", file);
1197 break;
1199 case '-':
1200 fprintf (file, "r%d", epiphany_m1reg);
1201 return;
1203 case 0 :
1204 /* Do nothing special. */
1205 break;
1206 default :
1207 /* Unknown flag. */
1208 output_operand_lossage ("invalid operand output code");
1211 switch (GET_CODE (x))
1213 rtx addr;
1214 rtx offset;
1216 case REG :
1217 fputs (reg_names[REGNO (x)], file);
1218 break;
1219 case MEM :
1220 if (code == 0)
1221 current_frame_info.stld_sz = 1;
1222 fputc ('[', file);
1223 addr = XEXP (x, 0);
1224 switch (GET_CODE (addr))
1226 case POST_INC:
1227 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1228 addr = XEXP (addr, 0);
1229 break;
1230 case POST_DEC:
1231 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1232 addr = XEXP (addr, 0);
1233 break;
1234 case POST_MODIFY:
1235 offset = XEXP (XEXP (addr, 1), 1);
1236 addr = XEXP (addr, 0);
1237 break;
1238 default:
1239 offset = 0;
1240 break;
1242 output_address (addr);
1243 fputc (']', file);
1244 if (offset)
1246 fputc (',', file);
1247 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1249 default:
1250 gcc_unreachable ();
1251 case 8:
1252 offset = GEN_INT (INTVAL (offset) >> 3);
1253 break;
1254 case 4:
1255 offset = GEN_INT (INTVAL (offset) >> 2);
1256 break;
1257 case 2:
1258 offset = GEN_INT (INTVAL (offset) >> 1);
1259 break;
1260 case 1:
1261 break;
1263 output_address (offset);
1265 break;
1266 case CONST_DOUBLE :
1267 /* We handle SFmode constants here as output_addr_const doesn't. */
1268 if (GET_MODE (x) == SFmode)
1270 REAL_VALUE_TYPE d;
1271 long l;
1273 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
1274 REAL_VALUE_TO_TARGET_SINGLE (d, l);
1275 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1276 break;
1278 /* Fall through. Let output_addr_const deal with it. */
1279 case CONST_INT:
1280 fprintf(file,"%s",IMMEDIATE_PREFIX);
1281 if (code == 'C' || code == 'X')
1283 fprintf (file, "%ld",
1284 (long) (INTVAL (x) / current_frame_info.stld_sz));
1285 break;
1287 /* Fall through */
1288 default :
1289 output_addr_const (file, x);
1290 break;
1294 /* Print a memory address as an operand to reference that memory location. */
1296 static void
1297 epiphany_print_operand_address (FILE *file, rtx addr)
1299 register rtx base, index = 0;
1300 int offset = 0;
1302 switch (GET_CODE (addr))
1304 case REG :
1305 fputs (reg_names[REGNO (addr)], file);
1306 break;
1307 case SYMBOL_REF :
1308 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1310 output_addr_const (file, addr);
1312 else
1314 output_addr_const (file, addr);
1316 break;
1317 case PLUS :
1318 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1319 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1320 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1321 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1322 else
1323 base = XEXP (addr, 0), index = XEXP (addr, 1);
1324 gcc_assert (GET_CODE (base) == REG);
1325 fputs (reg_names[REGNO (base)], file);
1326 if (index == 0)
1329 ** ++rk quirky method to scale offset for ld/str.......
1331 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1332 offset/current_frame_info.stld_sz);
1334 else
1336 switch (GET_CODE (index))
1338 case REG:
1339 fprintf (file, ",%s", reg_names[REGNO (index)]);
1340 break;
1341 case SYMBOL_REF:
1342 fputc (',', file), output_addr_const (file, index);
1343 break;
1344 default:
1345 gcc_unreachable ();
1348 break;
1349 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1350 /* We shouldn't get here as we've lost the mode of the memory object
1351 (which says how much to inc/dec by. */
1352 gcc_unreachable ();
1353 break;
1354 default:
1355 output_addr_const (file, addr);
1356 break;
1360 void
1361 epiphany_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED,
1362 rtx *opvec ATTRIBUTE_UNUSED,
1363 int noperands ATTRIBUTE_UNUSED)
1365 int i = epiphany_n_nops;
1366 rtx pat ATTRIBUTE_UNUSED;
1368 while (i--)
1369 fputs ("\tnop\n", asm_out_file);
1373 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1375 static bool
1376 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1378 HOST_WIDE_INT size = int_size_in_bytes (type);
1380 if (AGGREGATE_TYPE_P (type)
1381 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1382 return true;
1383 return (size == -1 || size > 8);
1386 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1387 passed by reference. */
1389 static bool
1390 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1391 enum machine_mode mode, const_tree type,
1392 bool named ATTRIBUTE_UNUSED)
1394 if (type)
1396 if (AGGREGATE_TYPE_P (type)
1397 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1398 return true;
1400 return false;
1404 static rtx
1405 epiphany_function_value (const_tree ret_type,
1406 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1407 bool outgoing ATTRIBUTE_UNUSED)
1409 enum machine_mode mode;
1411 mode = TYPE_MODE (ret_type);
1412 /* We must change the mode like PROMOTE_MODE does.
1413 ??? PROMOTE_MODE is ignored for non-scalar types.
1414 The set of types tested here has to be kept in sync
1415 with the one in explow.c:promote_mode. */
1416 if (GET_MODE_CLASS (mode) == MODE_INT
1417 && GET_MODE_SIZE (mode) < 4
1418 && (TREE_CODE (ret_type) == INTEGER_TYPE
1419 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1420 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1421 || TREE_CODE (ret_type) == OFFSET_TYPE))
1422 mode = SImode;
1423 return gen_rtx_REG (mode, 0);
1426 static rtx
1427 epiphany_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1429 return gen_rtx_REG (mode, 0);
1432 static bool
1433 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1435 return regno == 0;
1438 /* Fix up invalid option settings. */
1439 static void
1440 epiphany_override_options (void)
1442 if (epiphany_stack_offset < 4)
1443 error ("stack_offset must be at least 4");
1444 if (epiphany_stack_offset & 3)
1445 error ("stack_offset must be a multiple of 4");
1446 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1448 /* This needs to be done at start up. It's convenient to do it here. */
1449 epiphany_init ();
1452 /* For a DImode load / store SET, make a SImode set for a
1453 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1454 subreg. */
1455 static rtx
1456 frame_subreg_note (rtx set, int offset)
1458 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1459 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1461 set = gen_rtx_SET (VOIDmode, dst ,src);
1462 RTX_FRAME_RELATED_P (set) = 1;
1463 return set;
1466 static rtx
1467 frame_insn (rtx x)
1469 int i;
1470 rtx note = NULL_RTX;
1472 if (GET_CODE (x) == PARALLEL)
1474 rtx part = XVECEXP (x, 0, 0);
1476 if (GET_MODE (SET_DEST (part)) == DImode)
1478 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1479 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1480 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1481 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1483 part = copy_rtx (XVECEXP (x, 0, i));
1485 if (GET_CODE (part) == SET)
1486 RTX_FRAME_RELATED_P (part) = 1;
1487 XVECEXP (note, 0, i + 1) = part;
1490 else
1492 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1494 part = XVECEXP (x, 0, i);
1496 if (GET_CODE (part) == SET)
1497 RTX_FRAME_RELATED_P (part) = 1;
1501 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1502 note = gen_rtx_PARALLEL (VOIDmode,
1503 gen_rtvec (2, frame_subreg_note (x, 0),
1504 frame_subreg_note (x, UNITS_PER_WORD)));
1505 x = emit_insn (x);
1506 RTX_FRAME_RELATED_P (x) = 1;
1507 if (note)
1508 add_reg_note (x, REG_FRAME_RELATED_EXPR, note);
1509 return x;
1512 static rtx
1513 frame_move_insn (rtx to, rtx from)
1515 return frame_insn (gen_rtx_SET (VOIDmode, to, from));
1518 /* Generate a MEM referring to a varargs argument slot. */
1520 static rtx
1521 gen_varargs_mem (enum machine_mode mode, rtx addr)
1523 rtx mem = gen_rtx_MEM (mode, addr);
1524 MEM_NOTRAP_P (mem) = 1;
1525 set_mem_alias_set (mem, get_varargs_alias_set ());
1526 return mem;
1529 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1530 If EPILOGUE_P is 0, save; if it is one, restore.
1531 ADDR is the stack slot to save the first register to; subsequent
1532 registers are written to lower addresses.
1533 However, the order of register pairs can be reversed in order to
1534 use double-word load-store instructions. Likewise, an unpaired single
1535 word save slot can be skipped while double saves are carried out, and
1536 reused when a single register is to be saved. */
1538 static void
1539 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1541 int i;
1542 int stack_offset
1543 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1544 rtx skipped_mem = NULL_RTX;
1545 int last_saved = limit - 1;
1547 if (!optimize)
1548 while (last_saved >= 0
1549 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1550 last_saved--;
1551 for (i = 0; i < limit; i++)
1553 enum machine_mode mode = word_mode;
1554 rtx mem, reg;
1555 int n = i;
1556 rtx (*gen_mem) (enum machine_mode, rtx) = gen_frame_mem;
1558 /* Make sure we push the arguments in the right order. */
1559 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1561 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1562 gen_mem = gen_varargs_mem;
1564 if (stack_offset == current_frame_info.first_slot_size
1565 && current_frame_info.first_slot >= 0)
1567 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1569 mode = DImode;
1570 addr = plus_constant (Pmode, addr,
1571 - (HOST_WIDE_INT) UNITS_PER_WORD);
1573 if (i-- < min || !epilogue_p)
1574 goto next_slot;
1575 n = current_frame_info.first_slot;
1576 gen_mem = gen_frame_mem;
1578 else if (n == UNKNOWN_REGNUM
1579 && stack_offset > current_frame_info.first_slot_size)
1581 i--;
1582 goto next_slot;
1584 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1585 continue;
1586 else if (i < min)
1587 goto next_slot;
1589 /* Check for a register pair to save. */
1590 if (n == i
1591 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1592 && (n & 1) == 0 && n+1 < limit
1593 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1595 /* If it fits in the current stack slot pair, place it there. */
1596 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1597 && stack_offset != 2 * UNITS_PER_WORD
1598 && (current_frame_info.last_slot < 0
1599 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1600 && (n+1 != last_saved || !skipped_mem))
1602 mode = DImode;
1603 i++;
1604 addr = plus_constant (Pmode, addr,
1605 - (HOST_WIDE_INT) UNITS_PER_WORD);
1607 /* If it fits in the following stack slot pair, that's fine, too. */
1608 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1609 && stack_offset != 2 * UNITS_PER_WORD
1610 && stack_offset != 3 * UNITS_PER_WORD
1611 && (current_frame_info.last_slot < 0
1612 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1613 && n + 1 != last_saved)
1615 gcc_assert (!skipped_mem);
1616 stack_offset -= GET_MODE_SIZE (mode);
1617 skipped_mem = gen_mem (mode, addr);
1618 mode = DImode;
1619 i++;
1620 addr = plus_constant (Pmode, addr,
1621 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1624 reg = gen_rtx_REG (mode, n);
1625 if (mode != DImode && skipped_mem)
1626 mem = skipped_mem;
1627 else
1628 mem = gen_mem (mode, addr);
1630 /* If we are loading / storing LR, note the offset that
1631 gen_reload_insi_ra requires. Since GPR_LR is even,
1632 we only need to test n, even if mode is DImode. */
1633 gcc_assert ((GPR_LR & 1) == 0);
1634 if (n == GPR_LR)
1636 long lr_slot_offset = 0;
1637 rtx m_addr = XEXP (mem, 0);
1639 if (GET_CODE (m_addr) == PLUS)
1640 lr_slot_offset = INTVAL (XEXP (m_addr, 1));
1641 if (frame_pointer_needed)
1642 lr_slot_offset += (current_frame_info.first_slot_offset
1643 - current_frame_info.total_size);
1644 if (MACHINE_FUNCTION (cfun)->lr_slot_known)
1645 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset
1646 == lr_slot_offset);
1647 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1648 MACHINE_FUNCTION (cfun)->lr_slot_known = 1;
1651 if (!epilogue_p)
1652 frame_move_insn (mem, reg);
1653 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1654 emit_move_insn (reg, mem);
1655 if (mem == skipped_mem)
1657 skipped_mem = NULL_RTX;
1658 continue;
1660 next_slot:
1661 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
1662 stack_offset -= GET_MODE_SIZE (mode);
1666 void
1667 epiphany_expand_prologue (void)
1669 int interrupt_p;
1670 enum epiphany_function_type fn_type;
1671 rtx addr, mem, off, reg;
1672 rtx save_config;
1674 if (!current_frame_info.initialized)
1675 epiphany_compute_frame_size (get_frame_size ());
1677 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1678 if (flag_stack_usage_info)
1679 current_function_static_stack_size = current_frame_info.total_size;
1681 fn_type = epiphany_compute_function_type (current_function_decl);
1682 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1684 if (interrupt_p)
1686 addr = plus_constant (Pmode, stack_pointer_rtx,
1687 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1688 if (!lookup_attribute ("forwarder_section",
1689 DECL_ATTRIBUTES (current_function_decl))
1690 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1691 0)))
1692 frame_move_insn (gen_frame_mem (DImode, addr),
1693 gen_rtx_REG (DImode, GPR_0));
1694 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1695 gen_rtx_REG (word_mode, STATUS_REGNUM));
1696 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
1697 gen_rtx_REG (word_mode, IRET_REGNUM));
1698 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1699 off = GEN_INT (-current_frame_info.first_slot_offset);
1700 frame_insn (gen_stack_adjust_add (off, mem));
1701 if (!epiphany_uninterruptible_p (current_function_decl))
1702 emit_insn (gen_gie ());
1703 addr = plus_constant (Pmode, stack_pointer_rtx,
1704 current_frame_info.first_slot_offset
1705 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1707 else
1709 addr = plus_constant (Pmode, stack_pointer_rtx,
1710 epiphany_stack_offset
1711 - (HOST_WIDE_INT) UNITS_PER_WORD);
1712 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1713 addr, 0);
1714 /* Allocate register save area; for small to medium size frames,
1715 allocate the entire frame; this is joint with one register save. */
1716 if (current_frame_info.first_slot >= 0)
1718 enum machine_mode mode
1719 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1720 ? word_mode : DImode);
1722 off = GEN_INT (-current_frame_info.first_slot_offset);
1723 mem = gen_frame_mem (BLKmode,
1724 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1725 frame_insn (gen_stack_adjust_str
1726 (gen_frame_mem (mode, stack_pointer_rtx),
1727 gen_rtx_REG (mode, current_frame_info.first_slot),
1728 off, mem));
1729 addr = plus_constant (Pmode, addr,
1730 current_frame_info.first_slot_offset);
1733 epiphany_emit_save_restore (current_frame_info.small_threshold,
1734 FIRST_PSEUDO_REGISTER, addr, 0);
1735 if (current_frame_info.need_fp)
1736 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1737 /* For large frames, allocate bulk of frame. This is usually joint with one
1738 register save. */
1739 if (current_frame_info.last_slot >= 0)
1741 rtx ip, mem2, insn, note;
1743 gcc_assert (current_frame_info.last_slot != GPR_FP
1744 || (!current_frame_info.need_fp
1745 && current_frame_info.first_slot < 0));
1746 off = GEN_INT (-current_frame_info.last_slot_offset);
1747 mem = gen_frame_mem (BLKmode,
1748 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1749 ip = gen_rtx_REG (Pmode, GPR_IP);
1750 frame_move_insn (ip, off);
1751 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1752 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1753 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1754 /* Instruction scheduling can separate the instruction setting IP from
1755 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1756 temporary register is. Example: _gcov.o */
1757 note = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1758 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1759 note = gen_rtx_PARALLEL (VOIDmode,
1760 gen_rtvec (2, gen_rtx_SET (VOIDmode, mem2, reg),
1761 note));
1762 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1764 /* If there is only one or no register to save, yet we have a large frame,
1765 use an add. */
1766 else if (current_frame_info.last_slot_offset)
1768 mem = gen_frame_mem (BLKmode,
1769 plus_constant (Pmode, stack_pointer_rtx,
1770 current_frame_info.last_slot_offset));
1771 off = GEN_INT (-current_frame_info.last_slot_offset);
1772 if (!SIMM11 (INTVAL (off)))
1774 reg = gen_rtx_REG (Pmode, GPR_IP);
1775 frame_move_insn (reg, off);
1776 off = reg;
1778 frame_insn (gen_stack_adjust_add (off, mem));
1782 void
1783 epiphany_expand_epilogue (int sibcall_p)
1785 int interrupt_p;
1786 enum epiphany_function_type fn_type;
1787 rtx mem, addr, reg, off;
1788 HOST_WIDE_INT restore_offset;
1790 fn_type = epiphany_compute_function_type( current_function_decl);
1791 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1793 /* For variable frames, deallocate bulk of frame. */
1794 if (current_frame_info.need_fp)
1796 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1797 emit_insn (gen_stack_adjust_mov (mem));
1799 /* Else for large static frames, deallocate bulk of frame. */
1800 else if (current_frame_info.last_slot_offset)
1802 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1803 reg = gen_rtx_REG (Pmode, GPR_IP);
1804 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1805 emit_insn (gen_stack_adjust_add (reg, mem));
1807 restore_offset = (interrupt_p
1808 ? - 3 * UNITS_PER_WORD
1809 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1810 addr = plus_constant (Pmode, stack_pointer_rtx,
1811 (current_frame_info.first_slot_offset
1812 + restore_offset));
1813 epiphany_emit_save_restore (current_frame_info.small_threshold,
1814 FIRST_PSEUDO_REGISTER, addr, 1);
1816 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1817 emit_insn (gen_gid ());
1819 off = GEN_INT (current_frame_info.first_slot_offset);
1820 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1821 /* For large / variable size frames, deallocating the register save area is
1822 joint with one register restore; for medium size frames, we use a
1823 dummy post-increment load to dealloacte the whole frame. */
1824 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1826 emit_insn (gen_stack_adjust_ldr
1827 (gen_rtx_REG (word_mode,
1828 (current_frame_info.last_slot >= 0
1829 ? current_frame_info.last_slot : GPR_IP)),
1830 gen_frame_mem (word_mode, stack_pointer_rtx),
1831 off,
1832 mem));
1834 /* While for small frames, we deallocate the entire frame with one add. */
1835 else if (INTVAL (off))
1837 emit_insn (gen_stack_adjust_add (off, mem));
1839 if (interrupt_p)
1841 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1842 gen_rtx_REG (SImode, GPR_0));
1843 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1844 gen_rtx_REG (SImode, GPR_1));
1845 addr = plus_constant (Pmode, stack_pointer_rtx,
1846 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1847 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1848 gen_frame_mem (DImode, addr));
1850 addr = plus_constant (Pmode, stack_pointer_rtx,
1851 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1852 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1853 if (!sibcall_p)
1855 if (interrupt_p)
1856 emit_jump_insn (gen_return_internal_interrupt());
1857 else
1858 emit_jump_insn (gen_return_i ());
1863 epiphany_initial_elimination_offset (int from, int to)
1865 epiphany_compute_frame_size (get_frame_size ());
1866 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1867 return current_frame_info.total_size - current_frame_info.reg_size;
1868 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1869 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1870 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1871 return (current_frame_info.total_size
1872 - ((current_frame_info.pretend_size + 4) & -8));
1873 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1874 return (current_frame_info.first_slot_offset
1875 - ((current_frame_info.pretend_size + 4) & -8));
1876 gcc_unreachable ();
1879 bool
1880 epiphany_regno_rename_ok (unsigned, unsigned dst)
1882 enum epiphany_function_type fn_type;
1884 fn_type = epiphany_compute_function_type (current_function_decl);
1885 if (!EPIPHANY_INTERRUPT_P (fn_type))
1886 return true;
1887 if (df_regs_ever_live_p (dst))
1888 return true;
1889 return false;
1892 static int
1893 epiphany_issue_rate (void)
1895 return 2;
1898 /* Function to update the integer COST
1899 based on the relationship between INSN that is dependent on
1900 DEP_INSN through the dependence LINK. The default is to make no
1901 adjustment to COST. This can be used for example to specify to
1902 the scheduler that an output- or anti-dependence does not incur
1903 the same cost as a data-dependence. The return value should be
1904 the new value for COST. */
1905 static int
1906 epiphany_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1908 if (REG_NOTE_KIND (link) == 0)
1910 rtx dep_set;
1912 if (recog_memoized (insn) < 0
1913 || recog_memoized (dep_insn) < 0)
1914 return cost;
1916 dep_set = single_set (dep_insn);
1918 /* The latency that we specify in the scheduling description refers
1919 to the actual output, not to an auto-increment register; for that,
1920 the latency is one. */
1921 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
1923 rtx set = single_set (insn);
1925 if (set
1926 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
1927 && (!MEM_P (SET_DEST (set))
1928 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
1929 XEXP (SET_DEST (set), 0))))
1930 cost = 1;
1933 return cost;
1936 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
1938 #define RTX_OK_FOR_BASE_P(X) \
1939 (REG_P (X) && REG_OK_FOR_BASE_P (X))
1941 #define RTX_OK_FOR_INDEX_P(MODE, X) \
1942 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
1943 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
1944 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
1946 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
1947 (GET_CODE (X) == PLUS \
1948 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
1949 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
1950 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
1952 static bool
1953 epiphany_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
1955 #define REG_OK_FOR_BASE_P(X) \
1956 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
1957 if (RTX_OK_FOR_BASE_P (x))
1958 return true;
1959 if (RTX_FRAME_OFFSET_P (x))
1960 return true;
1961 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
1962 return true;
1963 /* If this is a misaligned stack access, don't force it to reg+index. */
1964 if (GET_MODE_SIZE (mode) == 8
1965 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
1966 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
1967 && !(INTVAL (XEXP (x, 1)) & 3)
1968 && INTVAL (XEXP (x, 1)) >= -2047 * 4
1969 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
1970 return true;
1971 if (TARGET_POST_INC
1972 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
1973 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
1974 return true;
1975 if ((TARGET_POST_MODIFY || reload_completed)
1976 && GET_CODE (x) == POST_MODIFY
1977 && GET_CODE (XEXP ((x), 1)) == PLUS
1978 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
1979 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
1980 return true;
1981 if (mode == BLKmode)
1982 return true;
1983 return false;
1986 static reg_class_t
1987 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
1988 enum machine_mode mode ATTRIBUTE_UNUSED,
1989 secondary_reload_info *sri)
1991 /* This could give more reload inheritance, but we are missing some
1992 reload infrastructure. */
1993 if (0)
1994 if (in_p && GET_CODE (x) == UNSPEC
1995 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
1997 gcc_assert (rclass == GENERAL_REGS);
1998 sri->icode = CODE_FOR_reload_insi_ra;
1999 return NO_REGS;
2001 return NO_REGS;
2004 bool
2005 epiphany_is_long_call_p (rtx x)
2007 tree decl = SYMBOL_REF_DECL (x);
2008 bool ret_val = !TARGET_SHORT_CALLS;
2009 tree attrs;
2011 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2012 probably encode information via encode_section_info, and also
2013 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2014 into account. */
2015 if (decl)
2017 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
2018 if (lookup_attribute ("long_call", attrs))
2019 ret_val = true;
2020 else if (lookup_attribute ("short_call", attrs))
2021 ret_val = false;
2023 return ret_val;
2026 bool
2027 epiphany_small16 (rtx x)
2029 rtx base = x;
2030 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2032 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2034 base = XEXP (XEXP (x, 0), 0);
2035 offs = XEXP (XEXP (x, 0), 1);
2037 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2038 && epiphany_is_long_call_p (base))
2039 return false;
2040 return TARGET_SMALL16 != 0;
2043 /* Return nonzero if it is ok to make a tail-call to DECL. */
2044 static bool
2045 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2047 bool cfun_interrupt_p, call_interrupt_p;
2049 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2050 (current_function_decl));
2051 if (decl)
2052 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2053 else
2055 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2057 gcc_assert (POINTER_TYPE_P (fn_type));
2058 fn_type = TREE_TYPE (fn_type);
2059 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2060 || TREE_CODE (fn_type) == METHOD_TYPE);
2061 call_interrupt_p
2062 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2065 /* Don't tailcall from or to an ISR routine - although we could in
2066 principle tailcall from one ISR routine to another, we'd need to
2067 handle this in sibcall_epilogue to make it work. */
2068 if (cfun_interrupt_p || call_interrupt_p)
2069 return false;
2071 /* Everything else is ok. */
2072 return true;
2075 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2076 expander.
2077 Return true iff the type of T has the uninterruptible attribute.
2078 If T is NULL, return false. */
2079 bool
2080 epiphany_uninterruptible_p (tree t)
2082 tree attrs;
2084 if (t)
2086 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2087 if (lookup_attribute ("disinterrupt", attrs))
2088 return true;
2090 return false;
2093 bool
2094 epiphany_call_uninterruptible_p (rtx mem)
2096 rtx addr = XEXP (mem, 0);
2097 tree t = NULL_TREE;
2099 if (GET_CODE (addr) == SYMBOL_REF)
2100 t = SYMBOL_REF_DECL (addr);
2101 if (!t)
2102 t = MEM_EXPR (mem);
2103 return epiphany_uninterruptible_p (t);
2106 static enum machine_mode
2107 epiphany_promote_function_mode (const_tree type, enum machine_mode mode,
2108 int *punsignedp ATTRIBUTE_UNUSED,
2109 const_tree funtype ATTRIBUTE_UNUSED,
2110 int for_return ATTRIBUTE_UNUSED)
2112 int dummy;
2114 return promote_mode (type, mode, &dummy);
2117 static void
2118 epiphany_conditional_register_usage (void)
2120 int i;
2122 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2124 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2125 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2127 if (TARGET_HALF_REG_FILE)
2129 for (i = 32; i <= 63; i++)
2131 fixed_regs[i] = 1;
2132 call_used_regs[i] = 1;
2135 if (epiphany_m1reg >= 0)
2137 fixed_regs[epiphany_m1reg] = 1;
2138 call_used_regs[epiphany_m1reg] = 1;
2140 if (!TARGET_PREFER_SHORT_INSN_REGS)
2141 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2142 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2143 reg_class_contents[GENERAL_REGS]);
2144 /* It would be simpler and quicker if we could just use
2145 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2146 it is set up later by our caller. */
2147 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2148 if (!call_used_regs[i])
2149 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2152 /* Determine where to put an argument to a function.
2153 Value is zero to push the argument on the stack,
2154 or a hard register in which to store the argument.
2156 MODE is the argument's machine mode.
2157 TYPE is the data type of the argument (as a tree).
2158 This is null for libcalls where that information may
2159 not be available.
2160 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2161 the preceding args and about the function being called.
2162 NAMED is nonzero if this argument is a named parameter
2163 (otherwise it is an extra parameter matching an ellipsis). */
2164 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2165 registers and the rest are pushed. */
2166 static rtx
2167 epiphany_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
2168 const_tree type, bool named ATTRIBUTE_UNUSED)
2170 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2172 if (PASS_IN_REG_P (cum, mode, type))
2173 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2174 return 0;
2177 /* Update the data in CUM to advance over an argument
2178 of mode MODE and data type TYPE.
2179 (TYPE is null for libcalls where that information may not be available.) */
2180 static void
2181 epiphany_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
2182 const_tree type, bool named ATTRIBUTE_UNUSED)
2184 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2186 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2189 /* Nested function support.
2190 An epiphany trampoline looks like this:
2191 mov r16,%low(fnaddr)
2192 movt r16,%high(fnaddr)
2193 mov ip,%low(cxt)
2194 movt ip,%high(cxt)
2195 jr r16 */
2197 #define EPIPHANY_LOW_RTX(X) \
2198 (gen_rtx_IOR (SImode, \
2199 gen_rtx_ASHIFT (SImode, \
2200 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2201 gen_rtx_ASHIFT (SImode, \
2202 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2203 #define EPIPHANY_HIGH_RTX(X) \
2204 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2206 /* Emit RTL insns to initialize the variable parts of a trampoline.
2207 FNADDR is an RTX for the address of the function's pure code.
2208 CXT is an RTX for the static chain value for the function. */
2209 static void
2210 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2212 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2213 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2215 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2216 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2217 EPIPHANY_LOW_RTX (fnaddr)));
2218 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2219 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2220 EPIPHANY_HIGH_RTX (fnaddr)));
2221 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2222 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2223 EPIPHANY_LOW_RTX (cxt)));
2224 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2225 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2226 EPIPHANY_HIGH_RTX (cxt)));
2227 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2228 GEN_INT (0x0802014f));
2231 bool
2232 epiphany_optimize_mode_switching (int entity)
2234 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2235 return false;
2236 switch (entity)
2238 case EPIPHANY_MSW_ENTITY_AND:
2239 case EPIPHANY_MSW_ENTITY_OR:
2240 case EPIPHANY_MSW_ENTITY_CONFIG:
2241 return true;
2242 case EPIPHANY_MSW_ENTITY_NEAREST:
2243 case EPIPHANY_MSW_ENTITY_TRUNC:
2244 return optimize > 0;
2245 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2246 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2247 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2248 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2249 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2250 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2251 return optimize == 0 || current_pass == &pass_mode_switch_use.pass;
2253 gcc_unreachable ();
2257 epiphany_mode_priority_to_mode (int entity, unsigned priority)
2259 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2260 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2261 return priority;
2262 if (priority > 3)
2263 switch (priority)
2265 case 4: return FP_MODE_ROUND_UNKNOWN;
2266 case 5: return FP_MODE_NONE;
2267 default: gcc_unreachable ();
2269 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2271 case FP_MODE_INT:
2272 switch (priority)
2274 case 0: return FP_MODE_INT;
2275 case 1: return epiphany_normal_fp_rounding;
2276 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2277 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2278 case 3: return FP_MODE_CALLER;
2280 case FP_MODE_ROUND_NEAREST:
2281 case FP_MODE_CALLER:
2282 switch (priority)
2284 case 0: return FP_MODE_ROUND_NEAREST;
2285 case 1: return FP_MODE_ROUND_TRUNC;
2286 case 2: return FP_MODE_INT;
2287 case 3: return FP_MODE_CALLER;
2289 case FP_MODE_ROUND_TRUNC:
2290 switch (priority)
2292 case 0: return FP_MODE_ROUND_TRUNC;
2293 case 1: return FP_MODE_ROUND_NEAREST;
2294 case 2: return FP_MODE_INT;
2295 case 3: return FP_MODE_CALLER;
2297 case FP_MODE_ROUND_UNKNOWN:
2298 case FP_MODE_NONE:
2299 gcc_unreachable ();
2301 gcc_unreachable ();
2305 epiphany_mode_needed (int entity, rtx insn)
2307 enum attr_fp_mode mode;
2309 if (recog_memoized (insn) < 0)
2311 if (entity == EPIPHANY_MSW_ENTITY_AND
2312 || entity == EPIPHANY_MSW_ENTITY_OR
2313 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2314 return 2;
2315 return FP_MODE_NONE;
2317 mode = get_attr_fp_mode (insn);
2319 switch (entity)
2321 case EPIPHANY_MSW_ENTITY_AND:
2322 return mode != FP_MODE_NONE && 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_CONFIG:
2326 /* We must know/save config before we set it to something else.
2327 Where we need the original value, we are fine with having it
2328 just unchanged from the function start.
2329 Because of the nature of the mode switching optimization,
2330 a restore will be dominated by a clobber. */
2331 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2332 return 1;
2333 /* A cpecial case are abnormal edges, which are deemed to clobber
2334 the mode as well. We need to pin this effect on a actually
2335 dominating insn, and one where the frame can be accessed, too, in
2336 case the pseudo used to save CONFIG doesn't get a hard register. */
2337 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2338 return 1;
2339 return 2;
2340 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2341 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2342 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2343 /* Fall through. */
2344 case EPIPHANY_MSW_ENTITY_NEAREST:
2345 case EPIPHANY_MSW_ENTITY_TRUNC:
2346 if (mode == FP_MODE_ROUND_UNKNOWN)
2348 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2349 return FP_MODE_NONE;
2351 return mode;
2352 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2353 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2354 return FP_MODE_ROUND_UNKNOWN;
2355 return mode;
2356 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2357 if (mode == FP_MODE_ROUND_UNKNOWN)
2358 return epiphany_normal_fp_rounding;
2359 return mode;
2360 default:
2361 gcc_unreachable ();
2366 epiphany_mode_entry_exit (int entity, bool exit)
2368 int normal_mode = epiphany_normal_fp_mode ;
2370 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2371 if (epiphany_is_interrupt_p (current_function_decl))
2372 normal_mode = FP_MODE_CALLER;
2373 switch (entity)
2375 case EPIPHANY_MSW_ENTITY_AND:
2376 if (exit)
2377 return normal_mode != FP_MODE_INT ? 1 : 2;
2378 return 0;
2379 case EPIPHANY_MSW_ENTITY_OR:
2380 if (exit)
2381 return normal_mode == FP_MODE_INT ? 1 : 2;
2382 return 0;
2383 case EPIPHANY_MSW_ENTITY_CONFIG:
2384 if (exit)
2385 return 2;
2386 return normal_mode == FP_MODE_CALLER ? 0 : 1;
2387 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2388 if (normal_mode == FP_MODE_ROUND_NEAREST
2389 || normal_mode == FP_MODE_ROUND_TRUNC)
2390 return FP_MODE_ROUND_UNKNOWN;
2391 /* Fall through. */
2392 case EPIPHANY_MSW_ENTITY_NEAREST:
2393 case EPIPHANY_MSW_ENTITY_TRUNC:
2394 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2395 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2396 return normal_mode;
2397 default:
2398 gcc_unreachable ();
2403 epiphany_mode_after (int entity, int last_mode, rtx insn)
2405 /* We have too few call-saved registers to hope to keep the masks across
2406 calls. */
2407 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2409 if (CALL_P (insn))
2410 return 0;
2411 return last_mode;
2413 /* If there is an abnormal edge, we don't want the config register to
2414 be 'saved' again at the destination.
2415 The frame pointer adjustment is inside a PARALLEL because of the
2416 flags clobber. */
2417 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2418 && GET_CODE (PATTERN (insn)) == PARALLEL
2419 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2420 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2422 gcc_assert (cfun->has_nonlocal_label);
2423 return 1;
2425 if (recog_memoized (insn) < 0)
2426 return last_mode;
2427 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2428 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2430 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2431 return FP_MODE_ROUND_NEAREST;
2432 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2433 return FP_MODE_ROUND_TRUNC;
2435 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2437 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2438 int fp_mode;
2440 if (REG_P (src))
2441 return FP_MODE_CALLER;
2442 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2443 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2444 && (fp_mode == FP_MODE_ROUND_NEAREST
2445 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2446 return FP_MODE_ROUND_UNKNOWN;
2447 return fp_mode;
2449 return last_mode;
2452 void
2453 emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2455 rtx save_cc, cc_reg, mask, src, src2;
2456 enum attr_fp_mode fp_mode;
2458 if (!MACHINE_FUNCTION (cfun)->and_mask)
2460 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2461 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2463 if (entity == EPIPHANY_MSW_ENTITY_AND)
2465 gcc_assert (mode >= 0 && mode <= 2);
2466 if (mode == 1)
2467 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2468 gen_int_mode (0xfff1fffe, SImode));
2469 return;
2471 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2473 gcc_assert (mode >= 0 && mode <= 2);
2474 if (mode == 1)
2475 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2476 return;
2478 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2480 /* Mode switching optimization is done after emit_initial_value_sets,
2481 so we have to take care of CONFIG_REGNUM here. */
2482 gcc_assert (mode >= 0 && mode <= 2);
2483 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2484 if (mode == 1)
2485 emit_insn (gen_save_config (save));
2486 return;
2488 fp_mode = (enum attr_fp_mode) mode;
2489 src = NULL_RTX;
2491 switch (fp_mode)
2493 case FP_MODE_CALLER:
2494 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2495 so that the config save gets inserted before the first use. */
2496 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2497 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2498 mask = MACHINE_FUNCTION (cfun)->and_mask;
2499 break;
2500 case FP_MODE_ROUND_UNKNOWN:
2501 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2502 mask = MACHINE_FUNCTION (cfun)->and_mask;
2503 break;
2504 case FP_MODE_ROUND_NEAREST:
2505 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2506 return;
2507 mask = MACHINE_FUNCTION (cfun)->and_mask;
2508 break;
2509 case FP_MODE_ROUND_TRUNC:
2510 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2511 return;
2512 mask = MACHINE_FUNCTION (cfun)->and_mask;
2513 break;
2514 case FP_MODE_INT:
2515 mask = MACHINE_FUNCTION (cfun)->or_mask;
2516 break;
2517 case FP_MODE_NONE:
2518 default:
2519 gcc_unreachable ();
2521 save_cc = gen_reg_rtx (CCmode);
2522 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2523 emit_move_insn (save_cc, cc_reg);
2524 mask = force_reg (SImode, mask);
2525 if (!src)
2527 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2529 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2531 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2532 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2533 src2 = copy_rtx (src);
2534 else
2536 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2538 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2540 emit_insn (gen_set_fp_mode (src, src2, mask));
2541 emit_move_insn (cc_reg, save_cc);
2544 void
2545 epiphany_expand_set_fp_mode (rtx *operands)
2547 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2548 rtx src = operands[0];
2549 rtx mask_reg = operands[2];
2550 rtx scratch = operands[3];
2551 enum attr_fp_mode fp_mode;
2554 gcc_assert (rtx_equal_p (src, operands[1])
2555 /* Sometimes reload gets silly and reloads the same pseudo
2556 into different registers. */
2557 || (REG_P (src) && REG_P (operands[1])));
2559 if (!epiphany_uninterruptible_p (current_function_decl))
2560 emit_insn (gen_gid ());
2561 emit_move_insn (scratch, ctrl);
2563 if (GET_CODE (src) == REG)
2565 /* FP_MODE_CALLER */
2566 emit_insn (gen_xorsi3 (scratch, scratch, src));
2567 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2568 emit_insn (gen_xorsi3 (scratch, scratch, src));
2570 else
2572 gcc_assert (GET_CODE (src) == CONST);
2573 src = XEXP (src, 0);
2574 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2575 switch (fp_mode)
2577 case FP_MODE_ROUND_NEAREST:
2578 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2579 break;
2580 case FP_MODE_ROUND_TRUNC:
2581 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2582 emit_insn (gen_add2_insn (scratch, const1_rtx));
2583 break;
2584 case FP_MODE_INT:
2585 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2586 break;
2587 case FP_MODE_CALLER:
2588 case FP_MODE_ROUND_UNKNOWN:
2589 case FP_MODE_NONE:
2590 gcc_unreachable ();
2593 emit_move_insn (ctrl, scratch);
2594 if (!epiphany_uninterruptible_p (current_function_decl))
2595 emit_insn (gen_gie ());
2598 void
2599 epiphany_insert_mode_switch_use (rtx insn,
2600 int entity ATTRIBUTE_UNUSED,
2601 int mode ATTRIBUTE_UNUSED)
2603 rtx pat = PATTERN (insn);
2604 rtvec v;
2605 int len, i;
2606 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2607 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2609 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2610 return;
2611 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2613 case FP_MODE_ROUND_NEAREST:
2614 near = gen_rtx_USE (VOIDmode, near);
2615 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2616 break;
2617 case FP_MODE_ROUND_TRUNC:
2618 near = gen_rtx_CLOBBER (VOIDmode, near);
2619 trunc = gen_rtx_USE (VOIDmode, trunc);
2620 break;
2621 case FP_MODE_ROUND_UNKNOWN:
2622 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2623 trunc = copy_rtx (near);
2624 /* Fall through. */
2625 case FP_MODE_INT:
2626 case FP_MODE_CALLER:
2627 near = gen_rtx_USE (VOIDmode, near);
2628 trunc = gen_rtx_USE (VOIDmode, trunc);
2629 break;
2630 case FP_MODE_NONE:
2631 gcc_unreachable ();
2633 gcc_assert (GET_CODE (pat) == PARALLEL);
2634 len = XVECLEN (pat, 0);
2635 v = rtvec_alloc (len + 2);
2636 for (i = 0; i < len; i++)
2637 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2638 RTVEC_ELT (v, len) = near;
2639 RTVEC_ELT (v, len + 1) = trunc;
2640 pat = gen_rtx_PARALLEL (VOIDmode, v);
2641 PATTERN (insn) = pat;
2642 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2645 bool
2646 epiphany_epilogue_uses (int regno)
2648 if (regno == GPR_LR)
2649 return true;
2650 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2652 if (fixed_regs[regno]
2653 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2654 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2655 return false;
2656 return true;
2658 if (regno == FP_NEAREST_REGNUM
2659 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2660 return true;
2661 if (regno == FP_TRUNCATE_REGNUM
2662 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2663 return true;
2664 return false;
2667 static unsigned int
2668 epiphany_min_divisions_for_recip_mul (enum machine_mode mode)
2670 if (flag_reciprocal_math && mode == SFmode)
2671 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2672 it already at the tree level and expose it to further optimizations. */
2673 return 1;
2674 return default_min_divisions_for_recip_mul (mode);
2677 static enum machine_mode
2678 epiphany_preferred_simd_mode (enum machine_mode mode ATTRIBUTE_UNUSED)
2680 return TARGET_VECT_DOUBLE ? DImode : SImode;
2683 static bool
2684 epiphany_vector_mode_supported_p (enum machine_mode mode)
2686 if (mode == V2SFmode)
2687 return true;
2688 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2689 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2690 return true;
2691 return false;
2694 static bool
2695 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2697 /* Vectors which aren't in packed structures will not be less aligned than
2698 the natural alignment of their element type, so this is safe. */
2699 if (TYPE_ALIGN_UNIT (type) == 4)
2700 return !is_packed;
2702 return default_builtin_vector_alignment_reachable (type, is_packed);
2705 static bool
2706 epiphany_support_vector_misalignment (enum machine_mode mode, const_tree type,
2707 int misalignment, bool is_packed)
2709 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2710 return true;
2711 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2712 is_packed);
2715 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2716 structs. Make structs double-word-aligned it they are a double word or
2717 (potentially) larger; failing that, do the same for a size of 32 bits. */
2718 unsigned
2719 epiphany_special_round_type_align (tree type, unsigned computed,
2720 unsigned specified)
2722 unsigned align = MAX (computed, specified);
2723 tree field;
2724 HOST_WIDE_INT total, max;
2725 unsigned try_align = FASTEST_ALIGNMENT;
2727 if (maximum_field_alignment && try_align > maximum_field_alignment)
2728 try_align = maximum_field_alignment;
2729 if (align >= try_align)
2730 return align;
2731 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2733 tree offset, size;
2735 if (TREE_CODE (field) != FIELD_DECL
2736 || TREE_TYPE (field) == error_mark_node)
2737 continue;
2738 offset = bit_position (field);
2739 size = DECL_SIZE (field);
2740 if (!host_integerp (offset, 1) || !host_integerp (size, 1)
2741 || TREE_INT_CST_LOW (offset) >= try_align
2742 || TREE_INT_CST_LOW (size) >= try_align)
2743 return try_align;
2744 total = TREE_INT_CST_LOW (offset) + TREE_INT_CST_LOW (size);
2745 if (total > max)
2746 max = total;
2748 if (max >= (HOST_WIDE_INT) try_align)
2749 align = try_align;
2750 else if (try_align > 32 && max >= 32)
2751 align = max > 32 ? 64 : 32;
2752 return align;
2755 /* Upping the alignment of arrays in structs is not only a performance
2756 enhancement, it also helps preserve assumptions about how
2757 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2758 libgcov.c . */
2759 unsigned
2760 epiphany_adjust_field_align (tree field, unsigned computed)
2762 if (computed == 32
2763 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
2765 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field)));
2767 if (!host_integerp (elmsz, 1) || tree_low_cst (elmsz, 1) >= 32)
2768 return 64;
2770 return computed;
2773 /* Output code to add DELTA to the first argument, and then jump
2774 to FUNCTION. Used for C++ multiple inheritance. */
2775 static void
2776 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2777 HOST_WIDE_INT delta,
2778 HOST_WIDE_INT vcall_offset,
2779 tree function)
2781 int this_regno
2782 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2783 const char *this_name = reg_names[this_regno];
2784 const char *fname;
2786 /* We use IP and R16 as a scratch registers. */
2787 gcc_assert (call_used_regs [GPR_IP]);
2788 gcc_assert (call_used_regs [GPR_16]);
2790 /* Add DELTA. When possible use a plain add, otherwise load it into
2791 a register first. */
2792 if (delta == 0)
2793 ; /* Done. */
2794 else if (SIMM11 (delta))
2795 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2796 else if (delta < 0 && delta >= -0xffff)
2798 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2799 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2801 else
2803 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2804 if (delta & ~0xffff)
2805 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2806 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2809 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2810 if (vcall_offset != 0)
2812 /* ldr ip,[this] --> temp = *this
2813 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2814 add this,this,ip --> this+ = *(*this + vcall_offset) */
2815 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2816 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2817 || (vcall_offset & 3) != 0)
2819 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2820 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2821 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2823 else
2824 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2825 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2828 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2829 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2831 fputs ("\tmov\tip,%low(", file);
2832 assemble_name (file, fname);
2833 fputs (")\n\tmovt\tip,%high(", file);
2834 assemble_name (file, fname);
2835 fputs (")\n\tjr ip\n", file);
2837 else
2839 fputs ("\tb\t", file);
2840 assemble_name (file, fname);
2841 fputc ('\n', file);
2845 void
2846 epiphany_start_function (FILE *file, const char *name, tree decl)
2848 /* If the function doesn't fit into the on-chip memory, it will have a
2849 section attribute - or lack of it - that denotes it goes somewhere else.
2850 But the architecture spec says that an interrupt vector still has to
2851 point to on-chip memory. So we must place a jump there to get to the
2852 actual function implementation. The forwarder_section attribute
2853 specifies the section where this jump goes.
2854 This mechanism can also be useful to have a shortcall destination for
2855 a function that is actually placed much farther away. */
2856 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2858 attrs = DECL_ATTRIBUTES (decl);
2859 int_attr = lookup_attribute ("interrupt", attrs);
2860 if (int_attr)
2861 for (int_names = TREE_VALUE (int_attr); int_names;
2862 int_names = TREE_CHAIN (int_names))
2864 char buf[99];
2866 int_name = TREE_VALUE (int_names);
2867 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2868 switch_to_section (get_section (buf, SECTION_CODE, decl));
2869 fputs ("\tb\t", file);
2870 assemble_name (file, name);
2871 fputc ('\n', file);
2873 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2874 if (forwarder_attr)
2876 const char *prefix = "__forwarder_dst_";
2877 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2879 strcpy (dst_name, prefix);
2880 strcat (dst_name, name);
2881 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2882 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2883 SECTION_CODE, decl));
2884 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2885 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2887 int tmp = GPR_0;
2889 if (int_attr)
2890 fputs ("\tstrd r0,[sp,-1]\n", file);
2891 else
2892 tmp = GPR_16;
2893 gcc_assert (call_used_regs[tmp]);
2894 fprintf (file, "\tmov r%d,%%low(", tmp);
2895 assemble_name (file, dst_name);
2896 fprintf (file, ")\n"
2897 "\tmovt r%d,%%high(", tmp);
2898 assemble_name (file, dst_name);
2899 fprintf (file, ")\n"
2900 "\tjr r%d\n", tmp);
2902 else
2904 fputs ("\tb\t", file);
2905 assemble_name (file, dst_name);
2906 fputc ('\n', file);
2908 name = dst_name;
2910 switch_to_section (function_section (decl));
2911 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2914 struct gcc_target targetm = TARGET_INITIALIZER;