* config/pa/linux-atomic.c (__kernel_cmpxchg): Reorder arguments to
[official-gcc.git] / gcc / config / epiphany / epiphany.c
blob60000bf3ea855f59a3599519b41ace0f83dcb98e
1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994-2015 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 "alias.h"
26 #include "symtab.h"
27 #include "tree.h"
28 #include "fold-const.h"
29 #include "stor-layout.h"
30 #include "varasm.h"
31 #include "calls.h"
32 #include "stringpool.h"
33 #include "rtl.h"
34 #include "regs.h"
35 #include "hard-reg-set.h"
36 #include "insn-config.h"
37 #include "conditions.h"
38 #include "output.h"
39 #include "insn-attr.h"
40 #include "flags.h"
41 #include "function.h"
42 #include "insn-codes.h"
43 #include "optabs.h"
44 #include "expmed.h"
45 #include "dojump.h"
46 #include "explow.h"
47 #include "emit-rtl.h"
48 #include "stmt.h"
49 #include "expr.h"
50 #include "diagnostic-core.h"
51 #include "recog.h"
52 #include "toplev.h"
53 #include "tm_p.h"
54 #include "target.h"
55 #include "dominance.h"
56 #include "cfg.h"
57 #include "cfgrtl.h"
58 #include "cfganal.h"
59 #include "lcm.h"
60 #include "cfgbuild.h"
61 #include "cfgcleanup.h"
62 #include "predict.h"
63 #include "basic-block.h"
64 #include "df.h"
65 #include "langhooks.h"
66 #include "tm-constrs.h"
67 #include "tree-pass.h" /* for current_pass */
68 #include "context.h"
69 #include "pass_manager.h"
70 #include "builtins.h"
72 /* Which cpu we're compiling for. */
73 int epiphany_cpu_type;
75 /* Name of mangle string to add to symbols to separate code compiled for each
76 cpu (or NULL). */
77 const char *epiphany_mangle_cpu;
79 /* Array of valid operand punctuation characters. */
80 char epiphany_punct_chars[256];
82 /* The rounding mode that we generally use for floating point. */
83 int epiphany_normal_fp_rounding;
85 /* The pass instance, for use in epiphany_optimize_mode_switching. */
86 static opt_pass *pass_mode_switch_use;
88 static void epiphany_init_reg_tables (void);
89 static int get_epiphany_condition_code (rtx);
90 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
91 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
92 bool *);
93 static bool epiphany_pass_by_reference (cumulative_args_t, machine_mode,
94 const_tree, bool);
95 static rtx_insn *frame_insn (rtx);
97 /* defines for the initialization of the GCC target structure. */
98 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
100 #define TARGET_PRINT_OPERAND epiphany_print_operand
101 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
103 #define TARGET_RTX_COSTS epiphany_rtx_costs
104 #define TARGET_ADDRESS_COST epiphany_address_cost
105 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
107 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
108 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
110 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
111 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
112 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
113 #define TARGET_FUNCTION_VALUE epiphany_function_value
114 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
115 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
117 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
119 /* Using the simplistic varags handling forces us to do partial reg/stack
120 argument passing for types with larger size (> 4 bytes) than alignemnt. */
121 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
123 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
125 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
126 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
128 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
130 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
132 #define TARGET_OPTION_OVERRIDE epiphany_override_options
134 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
136 #define TARGET_FUNCTION_ARG epiphany_function_arg
138 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
140 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
142 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
144 /* Nonzero if the constant rtx value is a legitimate general operand.
145 We can handle any 32- or 64-bit constant. */
146 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
148 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
149 epiphany_min_divisions_for_recip_mul
151 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
153 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
155 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
156 epiphany_vector_alignment_reachable
158 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
159 epiphany_support_vector_misalignment
161 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
162 hook_bool_const_tree_hwi_hwi_const_tree_true
163 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
165 /* ??? we can use larger offsets for wider-mode sized accesses, but there
166 is no concept of anchors being dependent on the modes that they are used
167 for, so we can only use an offset range that would suit all modes. */
168 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047)
169 /* We further restrict the minimum to be a multiple of eight. */
170 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040)
172 /* Mode switching hooks. */
174 #define TARGET_MODE_EMIT emit_set_fp_mode
176 #define TARGET_MODE_NEEDED epiphany_mode_needed
178 #define TARGET_MODE_PRIORITY epiphany_mode_priority
180 #define TARGET_MODE_ENTRY epiphany_mode_entry
182 #define TARGET_MODE_EXIT epiphany_mode_exit
184 #define TARGET_MODE_AFTER epiphany_mode_after
186 #include "target-def.h"
188 #undef TARGET_ASM_ALIGNED_HI_OP
189 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
190 #undef TARGET_ASM_ALIGNED_SI_OP
191 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
193 bool
194 epiphany_is_interrupt_p (tree decl)
196 tree attrs;
198 attrs = DECL_ATTRIBUTES (decl);
199 if (lookup_attribute ("interrupt", attrs))
200 return true;
201 else
202 return false;
205 /* Called from epiphany_override_options.
206 We use this to initialize various things. */
208 static void
209 epiphany_init (void)
211 /* N.B. this pass must not run before the first optimize_mode_switching
212 pass because of the side offect of epiphany_mode_needed on
213 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
214 pass_resolve_sw_modes. */
215 pass_mode_switch_use = make_pass_mode_switch_use (g);
216 struct register_pass_info insert_use_info
217 = { pass_mode_switch_use, "mode_sw",
218 1, PASS_POS_INSERT_AFTER
220 opt_pass *mode_sw2
221 = g->get_passes()->get_pass_mode_switching ()->clone ();
222 struct register_pass_info mode_sw2_info
223 = { mode_sw2, "mode_sw",
224 1, PASS_POS_INSERT_AFTER
226 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g);
227 struct register_pass_info mode_sw3_info
228 = { mode_sw3, "mode_sw",
229 1, PASS_POS_INSERT_AFTER
231 opt_pass *mode_sw4
232 = g->get_passes()->get_pass_split_all_insns ()->clone ();
233 struct register_pass_info mode_sw4_info
234 = { mode_sw4, "mode_sw",
235 1, PASS_POS_INSERT_AFTER
237 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
238 #define N_ENTITIES ARRAY_SIZE (num_modes)
240 epiphany_init_reg_tables ();
242 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
243 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
244 epiphany_punct_chars['-'] = 1;
246 epiphany_normal_fp_rounding
247 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
248 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
249 register_pass (&mode_sw4_info);
250 register_pass (&mode_sw2_info);
251 register_pass (&mode_sw3_info);
252 register_pass (&insert_use_info);
253 register_pass (&mode_sw2_info);
254 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
255 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
257 #if 1 /* As long as peep2_rescan is not implemented,
258 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
259 we need a second peephole2 pass to get reasonable code. */
261 opt_pass *extra_peephole2
262 = g->get_passes ()->get_pass_peephole2 ()->clone ();
263 struct register_pass_info peep2_2_info
264 = { extra_peephole2, "peephole2",
265 1, PASS_POS_INSERT_AFTER
268 register_pass (&peep2_2_info);
270 #endif
273 /* The condition codes of the EPIPHANY, and the inverse function. */
274 static const char *const epiphany_condition_codes[] =
275 { /* 0 1 2 3 4 5 6 7 8 9 */
276 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
277 /* 10 11 12 13 */
278 "beq","bne","blt", "blte",
281 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
283 /* Returns the index of the EPIPHANY condition code string in
284 `epiphany_condition_codes'. COMPARISON should be an rtx like
285 `(eq (...) (...))'. */
287 static int
288 get_epiphany_condition_code (rtx comparison)
290 switch (GET_MODE (XEXP (comparison, 0)))
292 case CCmode:
293 switch (GET_CODE (comparison))
295 case EQ : return 0;
296 case NE : return 1;
297 case LTU : return 2;
298 case GEU : return 3;
299 case GT : return 4;
300 case LE : return 5;
301 case GE : return 6;
302 case LT : return 7;
303 case GTU : return 8;
304 case LEU : return 9;
306 default : gcc_unreachable ();
308 case CC_N_NEmode:
309 switch (GET_CODE (comparison))
311 case EQ: return 6;
312 case NE: return 7;
313 default: gcc_unreachable ();
315 case CC_C_LTUmode:
316 switch (GET_CODE (comparison))
318 case GEU: return 2;
319 case LTU: return 3;
320 default: gcc_unreachable ();
322 case CC_C_GTUmode:
323 switch (GET_CODE (comparison))
325 case LEU: return 3;
326 case GTU: return 2;
327 default: gcc_unreachable ();
329 case CC_FPmode:
330 switch (GET_CODE (comparison))
332 case EQ: return 10;
333 case NE: return 11;
334 case LT: return 12;
335 case LE: return 13;
336 default: gcc_unreachable ();
338 case CC_FP_EQmode:
339 switch (GET_CODE (comparison))
341 case EQ: return 0;
342 case NE: return 1;
343 default: gcc_unreachable ();
345 case CC_FP_GTEmode:
346 switch (GET_CODE (comparison))
348 case EQ: return 0;
349 case NE: return 1;
350 case GT : return 4;
351 case GE : return 6;
352 case UNLE : return 5;
353 case UNLT : return 7;
354 default: gcc_unreachable ();
356 case CC_FP_ORDmode:
357 switch (GET_CODE (comparison))
359 case ORDERED: return 9;
360 case UNORDERED: return 8;
361 default: gcc_unreachable ();
363 case CC_FP_UNEQmode:
364 switch (GET_CODE (comparison))
366 case UNEQ: return 9;
367 case LTGT: return 8;
368 default: gcc_unreachable ();
370 default: gcc_unreachable ();
372 /*NOTREACHED*/
373 return (42);
377 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
379 hard_regno_mode_ok (int regno, machine_mode mode)
381 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
382 return (regno & 1) == 0 && GPR_P (regno);
383 else
384 return 1;
387 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
388 return the mode to be used for the comparison. */
390 machine_mode
391 epiphany_select_cc_mode (enum rtx_code op,
392 rtx x ATTRIBUTE_UNUSED,
393 rtx y ATTRIBUTE_UNUSED)
395 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
397 if (TARGET_SOFT_CMPSF
398 || op == ORDERED || op == UNORDERED)
400 if (op == EQ || op == NE)
401 return CC_FP_EQmode;
402 if (op == ORDERED || op == UNORDERED)
403 return CC_FP_ORDmode;
404 if (op == UNEQ || op == LTGT)
405 return CC_FP_UNEQmode;
406 return CC_FP_GTEmode;
408 return CC_FPmode;
410 /* recognize combiner pattern ashlsi_btst:
411 (parallel [
412 (set (reg:N_NE 65 cc1)
413 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
414 (const_int 1 [0x1])
415 (const_int 0 [0x0]))
416 (const_int 0 [0x0])))
417 (clobber (scratch:SI)) */
418 else if ((op == EQ || op == NE)
419 && GET_CODE (x) == ZERO_EXTRACT
420 && XEXP (x, 1) == const1_rtx
421 && CONST_INT_P (XEXP (x, 2)))
422 return CC_N_NEmode;
423 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
424 return CC_C_LTUmode;
425 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
426 return CC_C_GTUmode;
427 else
428 return CCmode;
431 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
433 static void
434 epiphany_init_reg_tables (void)
436 int i;
438 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
440 if (i == GPR_LR)
441 epiphany_regno_reg_class[i] = LR_REGS;
442 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
443 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
444 else if (call_used_regs[i]
445 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
446 epiphany_regno_reg_class[i] = SIBCALL_REGS;
447 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
448 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
449 else if (i < (GPR_LAST+1)
450 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
451 epiphany_regno_reg_class[i] = GENERAL_REGS;
452 else if (i == CC_REGNUM)
453 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
454 else
455 epiphany_regno_reg_class[i] = NO_REGS;
459 /* EPIPHANY specific attribute support.
461 The EPIPHANY has these attributes:
462 interrupt - for interrupt functions.
463 short_call - the function is assumed to be reachable with the b / bl
464 instructions.
465 long_call - the function address is loaded into a register before use.
466 disinterrupt - functions which mask interrupts throughout.
467 They unmask them while calling an interruptible
468 function, though. */
470 static const struct attribute_spec epiphany_attribute_table[] =
472 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
473 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
474 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
475 { "long_call", 0, 0, false, true, true, NULL, false },
476 { "short_call", 0, 0, false, true, true, NULL, false },
477 { "disinterrupt", 0, 0, false, true, true, NULL, true },
478 { NULL, 0, 0, false, false, false, NULL, false }
481 /* Handle an "interrupt" attribute; arguments as in
482 struct attribute_spec.handler. */
483 static tree
484 epiphany_handle_interrupt_attribute (tree *node, tree name, tree args,
485 int flags ATTRIBUTE_UNUSED,
486 bool *no_add_attrs)
488 tree value;
490 if (!args)
492 gcc_assert (DECL_P (*node));
493 tree t = TREE_TYPE (*node);
494 if (TREE_CODE (t) != FUNCTION_TYPE)
495 warning (OPT_Wattributes, "%qE attribute only applies to functions",
496 name);
497 /* Argument handling and the stack layout for interrupt handlers
498 don't mix. It makes no sense in the first place, so emit an
499 error for this. */
500 else if (TYPE_ARG_TYPES (t)
501 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node)
502 error_at (DECL_SOURCE_LOCATION (*node),
503 "interrupt handlers cannot have arguments");
504 return NULL_TREE;
507 value = TREE_VALUE (args);
509 if (TREE_CODE (value) != STRING_CST)
511 warning (OPT_Wattributes,
512 "argument of %qE attribute is not a string constant", name);
513 *no_add_attrs = true;
515 else if (strcmp (TREE_STRING_POINTER (value), "reset")
516 && strcmp (TREE_STRING_POINTER (value), "software_exception")
517 && strcmp (TREE_STRING_POINTER (value), "page_miss")
518 && strcmp (TREE_STRING_POINTER (value), "timer0")
519 && strcmp (TREE_STRING_POINTER (value), "timer1")
520 && strcmp (TREE_STRING_POINTER (value), "message")
521 && strcmp (TREE_STRING_POINTER (value), "dma0")
522 && strcmp (TREE_STRING_POINTER (value), "dma1")
523 && strcmp (TREE_STRING_POINTER (value), "wand")
524 && strcmp (TREE_STRING_POINTER (value), "swi"))
526 warning (OPT_Wattributes,
527 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
528 name);
529 *no_add_attrs = true;
530 return NULL_TREE;
533 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
534 flags, no_add_attrs);
537 /* Handle a "forwarder_section" attribute; arguments as in
538 struct attribute_spec.handler. */
539 static tree
540 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
541 tree name, tree args,
542 int flags ATTRIBUTE_UNUSED,
543 bool *no_add_attrs)
545 tree value;
547 value = TREE_VALUE (args);
549 if (TREE_CODE (value) != STRING_CST)
551 warning (OPT_Wattributes,
552 "argument of %qE attribute is not a string constant", name);
553 *no_add_attrs = true;
555 return NULL_TREE;
559 /* Misc. utilities. */
561 /* Generate a SYMBOL_REF for the special function NAME. When the address
562 can't be placed directly into a call instruction, and if possible, copy
563 it to a register so that cse / code hoisting is possible. */
565 sfunc_symbol (const char *name)
567 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
569 /* These sfuncs should be hidden, and every dso should get a copy. */
570 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
571 if (TARGET_SHORT_CALLS)
572 ; /* Nothing to be done. */
573 else if (can_create_pseudo_p ())
574 sym = copy_to_mode_reg (Pmode, sym);
575 else /* We rely on reload to fix this up. */
576 gcc_assert (!reload_in_progress || reload_completed);
577 return sym;
580 /* X and Y are two things to compare using CODE in IN_MODE.
581 Emit the compare insn, construct the the proper cc reg in the proper
582 mode, and return the rtx for the cc reg comparison in CMODE. */
585 gen_compare_reg (machine_mode cmode, enum rtx_code code,
586 machine_mode in_mode, rtx x, rtx y)
588 machine_mode mode = SELECT_CC_MODE (code, x, y);
589 rtx cc_reg, pat, clob0, clob1, clob2;
591 if (in_mode == VOIDmode)
592 in_mode = GET_MODE (x);
593 if (in_mode == VOIDmode)
594 in_mode = GET_MODE (y);
596 if (mode == CC_FPmode)
598 /* The epiphany has only EQ / NE / LT / LE conditions for
599 hardware floating point. */
600 if (code == GT || code == GE || code == UNLE || code == UNLT)
602 rtx tmp = x; x = y; y = tmp;
603 code = swap_condition (code);
605 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
606 y = force_reg (in_mode, y);
608 else
610 if (mode == CC_FP_GTEmode
611 && (code == LE || code == LT || code == UNGT || code == UNGE))
613 if (flag_finite_math_only
614 && ((REG_P (x) && REGNO (x) == GPR_0)
615 || (REG_P (y) && REGNO (y) == GPR_1)))
616 switch (code)
618 case LE: code = UNLE; break;
619 case LT: code = UNLT; break;
620 case UNGT: code = GT; break;
621 case UNGE: code = GE; break;
622 default: gcc_unreachable ();
624 else
626 rtx tmp = x; x = y; y = tmp;
627 code = swap_condition (code);
630 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
632 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
633 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
634 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
635 && (!REG_P (x) || REGNO (x) != GPR_0
636 || !REG_P (y) || REGNO (y) != GPR_1))
638 rtx reg;
640 #if 0
641 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
642 but just like the flag clobber of movsicc, we have to allow
643 this for ifcvt to work, on the assumption that we'll only want
644 to do this if these registers have been used before by the
645 pre-ifcvt code. */
646 gcc_assert (currently_expanding_to_rtl);
647 #endif
648 reg = gen_rtx_REG (in_mode, GPR_0);
649 if (reg_overlap_mentioned_p (reg, y))
650 return 0;
651 emit_move_insn (reg, x);
652 x = reg;
653 reg = gen_rtx_REG (in_mode, GPR_1);
654 emit_move_insn (reg, y);
655 y = reg;
657 else
658 x = force_reg (in_mode, x);
660 pat = gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y));
661 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
663 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
664 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
666 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
667 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
668 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
670 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
672 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
673 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
675 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
676 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
677 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
678 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
679 clob0, clob1, clob2));
681 else
683 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
684 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
686 emit_insn (pat);
687 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
690 /* The ROUND_ADVANCE* macros are local to this file. */
691 /* Round SIZE up to a word boundary. */
692 #define ROUND_ADVANCE(SIZE) \
693 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
695 /* Round arg MODE/TYPE up to the next word boundary. */
696 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
697 ((MODE) == BLKmode \
698 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
699 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
701 /* Round CUM up to the necessary point for argument MODE/TYPE. */
702 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
703 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
704 ? (((CUM) + 1) & ~1) \
705 : (CUM))
707 static unsigned int
708 epiphany_function_arg_boundary (machine_mode mode, const_tree type)
710 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
711 return PARM_BOUNDARY;
712 return 2 * PARM_BOUNDARY;
715 /* Do any needed setup for a variadic function. For the EPIPHANY, we
716 actually emit the code in epiphany_expand_prologue.
718 CUM has not been updated for the last named argument which has type TYPE
719 and mode MODE, and we rely on this fact. */
722 static void
723 epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
724 tree type, int *pretend_size, int no_rtl)
726 int first_anon_arg;
727 CUMULATIVE_ARGS next_cum;
728 machine_function_t *mf = MACHINE_FUNCTION (cfun);
730 /* All BLKmode values are passed by reference. */
731 gcc_assert (mode != BLKmode);
733 next_cum = *get_cumulative_args (cum);
734 next_cum
735 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
736 first_anon_arg = next_cum;
738 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
740 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
741 int first_reg_offset = first_anon_arg;
743 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
744 * UNITS_PER_WORD);
746 mf->args_parsed = 1;
747 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
750 static int
751 epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
752 tree type, bool named ATTRIBUTE_UNUSED)
754 int words = 0, rounded_cum;
756 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
758 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
759 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
761 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
762 if (words >= ROUND_ADVANCE_ARG (mode, type))
763 words = 0;
765 return words * UNITS_PER_WORD;
768 /* Cost functions. */
770 /* Compute a (partial) cost for rtx X. Return true if the complete
771 cost has been computed, and false if subexpressions should be
772 scanned. In either case, *TOTAL contains the cost result. */
774 static bool
775 epiphany_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
776 int *total, bool speed ATTRIBUTE_UNUSED)
778 switch (code)
780 /* Small integers in the right context are as cheap as registers. */
781 case CONST_INT:
782 if ((outer_code == PLUS || outer_code == MINUS)
783 && SIMM11 (INTVAL (x)))
785 *total = 0;
786 return true;
788 if (IMM16 (INTVAL (x)))
790 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
791 return true;
793 /* FALLTHRU */
795 case CONST:
796 case LABEL_REF:
797 case SYMBOL_REF:
798 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
799 + (outer_code == SET ? 0 : 1));
800 return true;
802 case CONST_DOUBLE:
804 rtx high, low;
805 split_double (x, &high, &low);
806 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
807 + !IMM16 (INTVAL (low)));
808 return true;
811 case ASHIFT:
812 case ASHIFTRT:
813 case LSHIFTRT:
814 *total = COSTS_N_INSNS (1);
815 return true;
817 case COMPARE:
818 switch (GET_MODE (x))
820 /* There are a number of single-insn combiner patterns that use
821 the flag side effects of arithmetic. */
822 case CC_N_NEmode:
823 case CC_C_LTUmode:
824 case CC_C_GTUmode:
825 return true;
826 default:
827 return false;
831 case SET:
833 rtx src = SET_SRC (x);
834 if (BINARY_P (src))
835 *total = 0;
836 return false;
839 default:
840 return false;
845 /* Provide the costs of an addressing mode that contains ADDR.
846 If ADDR is not a valid address, its cost is irrelevant. */
848 static int
849 epiphany_address_cost (rtx addr, machine_mode mode,
850 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
852 rtx reg;
853 rtx off = const0_rtx;
854 int i;
856 if (speed)
857 return 0;
858 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
859 in long insns. */
860 switch (GET_CODE (addr))
862 case PLUS :
863 reg = XEXP (addr, 0);
864 off = XEXP (addr, 1);
865 break;
866 case POST_MODIFY:
867 reg = XEXP (addr, 0);
868 off = XEXP (addr, 1);
869 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
870 off = XEXP (off, 1);
871 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
872 return 0;
873 return 1;
874 case REG:
875 default:
876 reg = addr;
877 break;
879 if (!satisfies_constraint_Rgs (reg))
880 return 1;
881 /* The offset range available for short instructions depends on the mode
882 of the memory access. */
883 /* First, make sure we have a valid integer. */
884 if (!satisfies_constraint_L (off))
885 return 1;
886 i = INTVAL (off);
887 switch (GET_MODE_SIZE (mode))
889 default:
890 case 4:
891 if (i & 1)
892 return 1;
893 i >>= 1;
894 /* Fall through. */
895 case 2:
896 if (i & 1)
897 return 1;
898 i >>= 1;
899 /* Fall through. */
900 case 1:
901 return i < -7 || i > 7;
905 /* Compute the cost of moving data between registers and memory.
906 For integer, load latency is twice as long as register-register moves,
907 but issue pich is the same. For floating point, load latency is three
908 times as much as a reg-reg move. */
909 static int
910 epiphany_memory_move_cost (machine_mode mode,
911 reg_class_t rclass ATTRIBUTE_UNUSED,
912 bool in ATTRIBUTE_UNUSED)
914 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
917 /* Function prologue/epilogue handlers. */
919 /* EPIPHANY stack frames look like:
921 Before call After call
922 +-----------------------+ +-----------------------+
923 | | | |
924 high | local variables, | | local variables, |
925 mem | reg save area, etc. | | reg save area, etc. |
926 | | | |
927 +-----------------------+ +-----------------------+
928 | | | |
929 | arguments on stack. | | arguments on stack. |
930 | | | |
931 SP+8->+-----------------------+FP+8m->+-----------------------+
932 | 2 word save area for | | reg parm save area, |
933 | leaf funcs / flags | | only created for |
934 SP+0->+-----------------------+ | variable argument |
935 | functions |
936 FP+8n->+-----------------------+
938 | register save area |
940 +-----------------------+
942 | local variables |
944 FP+0->+-----------------------+
946 | alloca allocations |
948 +-----------------------+
950 | arguments on stack |
952 SP+8->+-----------------------+
953 low | 2 word save area for |
954 memory | leaf funcs / flags |
955 SP+0->+-----------------------+
957 Notes:
958 1) The "reg parm save area" does not exist for non variable argument fns.
959 The "reg parm save area" could be eliminated if we created our
960 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
961 (so it's not done). */
963 /* Structure to be filled in by epiphany_compute_frame_size with register
964 save masks, and offsets for the current function. */
965 struct epiphany_frame_info
967 unsigned int total_size; /* # bytes that the entire frame takes up. */
968 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
969 unsigned int args_size; /* # bytes that outgoing arguments take up. */
970 unsigned int reg_size; /* # bytes needed to store regs. */
971 unsigned int var_size; /* # bytes that variables take up. */
972 HARD_REG_SET gmask; /* Set of saved gp registers. */
973 int initialized; /* Nonzero if frame size already calculated. */
974 int stld_sz; /* Current load/store data size for offset
975 adjustment. */
976 int need_fp; /* value to override "frame_pointer_needed */
977 /* FIRST_SLOT is the slot that is saved first, at the very start of
978 the frame, with a POST_MODIFY to allocate the frame, if the size fits,
979 or at least the parm and register save areas, otherwise.
980 In the case of a large frame, LAST_SLOT is the slot that is saved last,
981 with a POST_MODIFY to allocate the rest of the frame. */
982 int first_slot, last_slot, first_slot_offset, last_slot_offset;
983 int first_slot_size;
984 int small_threshold;
987 /* Current frame information calculated by epiphany_compute_frame_size. */
988 static struct epiphany_frame_info current_frame_info;
990 /* Zero structure to initialize current_frame_info. */
991 static struct epiphany_frame_info zero_frame_info;
993 /* The usual; we set up our machine_function data. */
994 static struct machine_function *
995 epiphany_init_machine_status (void)
997 struct machine_function *machine;
999 /* Reset state info for each function. */
1000 current_frame_info = zero_frame_info;
1002 machine = ggc_cleared_alloc<machine_function_t> ();
1004 return machine;
1007 /* Implements INIT_EXPANDERS. We just set up to call the above
1008 * function. */
1009 void
1010 epiphany_init_expanders (void)
1012 init_machine_status = epiphany_init_machine_status;
1015 /* Type of function DECL.
1017 The result is cached. To reset the cache at the end of a function,
1018 call with DECL = NULL_TREE. */
1020 static enum epiphany_function_type
1021 epiphany_compute_function_type (tree decl)
1023 tree a;
1024 /* Cached value. */
1025 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1026 /* Last function we were called for. */
1027 static tree last_fn = NULL_TREE;
1029 /* Resetting the cached value? */
1030 if (decl == NULL_TREE)
1032 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1033 last_fn = NULL_TREE;
1034 return fn_type;
1037 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
1038 return fn_type;
1040 /* Assume we have a normal function (not an interrupt handler). */
1041 fn_type = EPIPHANY_FUNCTION_NORMAL;
1043 /* Now see if this is an interrupt handler. */
1044 for (a = DECL_ATTRIBUTES (decl);
1046 a = TREE_CHAIN (a))
1048 tree name = TREE_PURPOSE (a);
1050 if (name == get_identifier ("interrupt"))
1051 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
1054 last_fn = decl;
1055 return fn_type;
1058 #define RETURN_ADDR_REGNUM GPR_LR
1059 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
1060 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
1062 /* Tell prologue and epilogue if register REGNO should be saved / restored.
1063 The return address and frame pointer are treated separately.
1064 Don't consider them here. */
1065 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
1066 ((df_regs_ever_live_p (regno) \
1067 || (interrupt_p && !crtl->is_leaf \
1068 && call_used_regs[regno] && !fixed_regs[regno])) \
1069 && (!call_used_regs[regno] || regno == GPR_LR \
1070 || (interrupt_p && regno != GPR_SP)))
1072 #define MUST_SAVE_RETURN_ADDR 0
1074 /* Return the bytes needed to compute the frame pointer from the current
1075 stack pointer.
1077 SIZE is the size needed for local variables. */
1079 static unsigned int
1080 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
1082 int regno;
1083 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
1084 HARD_REG_SET gmask;
1085 enum epiphany_function_type fn_type;
1086 int interrupt_p;
1087 int first_slot, last_slot, first_slot_offset, last_slot_offset;
1088 int first_slot_size;
1089 int small_slots = 0;
1091 var_size = size;
1092 args_size = crtl->outgoing_args_size;
1093 pretend_size = crtl->args.pretend_args_size;
1094 total_size = args_size + var_size;
1095 reg_size = 0;
1096 CLEAR_HARD_REG_SET (gmask);
1097 first_slot = -1;
1098 first_slot_offset = 0;
1099 last_slot = -1;
1100 last_slot_offset = 0;
1101 first_slot_size = UNITS_PER_WORD;
1103 /* See if this is an interrupt handler. Call used registers must be saved
1104 for them too. */
1105 fn_type = epiphany_compute_function_type (current_function_decl);
1106 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1108 /* Calculate space needed for registers. */
1110 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
1112 reg_size += UNITS_PER_WORD;
1113 SET_HARD_REG_BIT (gmask, regno);
1114 if (epiphany_stack_offset - reg_size == 0)
1115 first_slot = regno;
1118 if (interrupt_p)
1119 reg_size += 2 * UNITS_PER_WORD;
1120 else
1121 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
1123 if (frame_pointer_needed)
1125 current_frame_info.need_fp = 1;
1126 if (!interrupt_p && first_slot < 0)
1127 first_slot = GPR_FP;
1129 else
1130 current_frame_info.need_fp = 0;
1131 for (regno = 0; regno <= GPR_LAST; regno++)
1133 if (MUST_SAVE_REGISTER (regno, interrupt_p))
1135 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1136 reg_size += UNITS_PER_WORD;
1137 SET_HARD_REG_BIT (gmask, regno);
1138 /* FIXME: when optimizing for speed, take schedling into account
1139 when selecting these registers. */
1140 if (regno == first_slot)
1141 gcc_assert (regno == GPR_FP && frame_pointer_needed);
1142 else if (!interrupt_p && first_slot < 0)
1143 first_slot = regno;
1144 else if (last_slot < 0
1145 && (first_slot ^ regno) != 1
1146 && (!interrupt_p || regno > GPR_1))
1147 last_slot = regno;
1150 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1151 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1152 /* ??? Could sometimes do better than that. */
1153 current_frame_info.small_threshold
1154 = (optimize >= 3 || interrupt_p ? 0
1155 : pretend_size ? small_slots
1156 : 4 + small_slots - (first_slot == GPR_FP));
1158 /* If there might be variables with 64-bit alignment requirement, align the
1159 start of the variables. */
1160 if (var_size >= 2 * UNITS_PER_WORD
1161 /* We don't want to split a double reg save/restore across two unpaired
1162 stack slots when optimizing. This rounding could be avoided with
1163 more complex reordering of the register saves, but that would seem
1164 to be a lot of code complexity for little gain. */
1165 || (reg_size > 8 && optimize))
1166 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1167 if (((total_size + reg_size
1168 /* Reserve space for UNKNOWN_REGNUM. */
1169 + EPIPHANY_STACK_ALIGN (4))
1170 <= (unsigned) epiphany_stack_offset)
1171 && !interrupt_p
1172 && crtl->is_leaf && !frame_pointer_needed)
1174 first_slot = -1;
1175 last_slot = -1;
1176 goto alloc_done;
1178 else if (reg_size
1179 && !interrupt_p
1180 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1181 reg_size = epiphany_stack_offset;
1182 if (interrupt_p)
1184 if (total_size + reg_size < 0x3fc)
1186 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1187 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1188 last_slot = -1;
1190 else
1192 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1193 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1194 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1195 if (last_slot >= 0)
1196 CLEAR_HARD_REG_BIT (gmask, last_slot);
1199 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1201 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1202 last_slot = -1;
1204 else
1206 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1208 gcc_assert (first_slot < 0);
1209 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset);
1210 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1212 else
1214 first_slot_offset
1215 = (reg_size
1216 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1217 if (!first_slot_offset)
1219 if (first_slot != GPR_FP || !current_frame_info.need_fp)
1220 last_slot = first_slot;
1221 first_slot = -1;
1223 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1224 if (reg_size)
1225 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1227 if (last_slot >= 0)
1228 CLEAR_HARD_REG_BIT (gmask, last_slot);
1230 alloc_done:
1231 if (first_slot >= 0)
1233 CLEAR_HARD_REG_BIT (gmask, first_slot);
1234 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1235 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1237 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1238 first_slot_size = 2 * UNITS_PER_WORD;
1239 first_slot &= ~1;
1242 total_size = first_slot_offset + last_slot_offset;
1244 /* Save computed information. */
1245 current_frame_info.total_size = total_size;
1246 current_frame_info.pretend_size = pretend_size;
1247 current_frame_info.var_size = var_size;
1248 current_frame_info.args_size = args_size;
1249 current_frame_info.reg_size = reg_size;
1250 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1251 current_frame_info.first_slot = first_slot;
1252 current_frame_info.last_slot = last_slot;
1253 current_frame_info.first_slot_offset = first_slot_offset;
1254 current_frame_info.first_slot_size = first_slot_size;
1255 current_frame_info.last_slot_offset = last_slot_offset;
1257 current_frame_info.initialized = reload_completed;
1259 /* Ok, we're done. */
1260 return total_size;
1263 /* Print operand X (an rtx) in assembler syntax to file FILE.
1264 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1265 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1267 static void
1268 epiphany_print_operand (FILE *file, rtx x, int code)
1270 switch (code)
1272 case 'd':
1273 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1274 return;
1275 case 'D':
1276 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1277 (get_epiphany_condition_code (x))],
1278 file);
1279 return;
1281 case 'X':
1282 current_frame_info.stld_sz = 8;
1283 break;
1285 case 'C' :
1286 current_frame_info.stld_sz = 4;
1287 break;
1289 case 'c' :
1290 current_frame_info.stld_sz = 2;
1291 break;
1293 case 'f':
1294 fputs (REG_P (x) ? "jalr " : "bl ", file);
1295 break;
1297 case '-':
1298 fprintf (file, "r%d", epiphany_m1reg);
1299 return;
1301 case 0 :
1302 /* Do nothing special. */
1303 break;
1304 default :
1305 /* Unknown flag. */
1306 output_operand_lossage ("invalid operand output code");
1309 switch (GET_CODE (x))
1311 rtx addr;
1312 rtx offset;
1314 case REG :
1315 fputs (reg_names[REGNO (x)], file);
1316 break;
1317 case MEM :
1318 if (code == 0)
1319 current_frame_info.stld_sz = 1;
1320 fputc ('[', file);
1321 addr = XEXP (x, 0);
1322 switch (GET_CODE (addr))
1324 case POST_INC:
1325 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1326 addr = XEXP (addr, 0);
1327 break;
1328 case POST_DEC:
1329 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1330 addr = XEXP (addr, 0);
1331 break;
1332 case POST_MODIFY:
1333 offset = XEXP (XEXP (addr, 1), 1);
1334 addr = XEXP (addr, 0);
1335 break;
1336 default:
1337 offset = 0;
1338 break;
1340 output_address (addr);
1341 fputc (']', file);
1342 if (offset)
1344 fputc (',', file);
1345 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1347 default:
1348 gcc_unreachable ();
1349 case 8:
1350 offset = GEN_INT (INTVAL (offset) >> 3);
1351 break;
1352 case 4:
1353 offset = GEN_INT (INTVAL (offset) >> 2);
1354 break;
1355 case 2:
1356 offset = GEN_INT (INTVAL (offset) >> 1);
1357 break;
1358 case 1:
1359 break;
1361 output_address (offset);
1363 break;
1364 case CONST_DOUBLE :
1365 /* We handle SFmode constants here as output_addr_const doesn't. */
1366 if (GET_MODE (x) == SFmode)
1368 REAL_VALUE_TYPE d;
1369 long l;
1371 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
1372 REAL_VALUE_TO_TARGET_SINGLE (d, l);
1373 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1374 break;
1376 /* Fall through. Let output_addr_const deal with it. */
1377 case CONST_INT:
1378 fprintf(file,"%s",IMMEDIATE_PREFIX);
1379 if (code == 'C' || code == 'X')
1381 fprintf (file, "%ld",
1382 (long) (INTVAL (x) / current_frame_info.stld_sz));
1383 break;
1385 /* Fall through */
1386 default :
1387 output_addr_const (file, x);
1388 break;
1392 /* Print a memory address as an operand to reference that memory location. */
1394 static void
1395 epiphany_print_operand_address (FILE *file, rtx addr)
1397 register rtx base, index = 0;
1398 int offset = 0;
1400 switch (GET_CODE (addr))
1402 case REG :
1403 fputs (reg_names[REGNO (addr)], file);
1404 break;
1405 case SYMBOL_REF :
1406 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1408 output_addr_const (file, addr);
1410 else
1412 output_addr_const (file, addr);
1414 break;
1415 case PLUS :
1416 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1417 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1418 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1419 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1420 else
1421 base = XEXP (addr, 0), index = XEXP (addr, 1);
1422 gcc_assert (GET_CODE (base) == REG);
1423 fputs (reg_names[REGNO (base)], file);
1424 if (index == 0)
1427 ** ++rk quirky method to scale offset for ld/str.......
1429 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1430 offset/current_frame_info.stld_sz);
1432 else
1434 switch (GET_CODE (index))
1436 case REG:
1437 fprintf (file, ",%s", reg_names[REGNO (index)]);
1438 break;
1439 case SYMBOL_REF:
1440 fputc (',', file), output_addr_const (file, index);
1441 break;
1442 default:
1443 gcc_unreachable ();
1446 break;
1447 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1448 /* We shouldn't get here as we've lost the mode of the memory object
1449 (which says how much to inc/dec by. */
1450 gcc_unreachable ();
1451 break;
1452 default:
1453 output_addr_const (file, addr);
1454 break;
1458 void
1459 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED,
1460 rtx *opvec ATTRIBUTE_UNUSED,
1461 int noperands ATTRIBUTE_UNUSED)
1463 int i = epiphany_n_nops;
1464 rtx pat ATTRIBUTE_UNUSED;
1466 while (i--)
1467 fputs ("\tnop\n", asm_out_file);
1471 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1473 static bool
1474 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1476 HOST_WIDE_INT size = int_size_in_bytes (type);
1478 if (AGGREGATE_TYPE_P (type)
1479 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1480 return true;
1481 return (size == -1 || size > 8);
1484 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1485 passed by reference. */
1487 static bool
1488 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1489 machine_mode mode, const_tree type,
1490 bool named ATTRIBUTE_UNUSED)
1492 if (type)
1494 if (AGGREGATE_TYPE_P (type)
1495 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1496 return true;
1498 return false;
1502 static rtx
1503 epiphany_function_value (const_tree ret_type,
1504 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1505 bool outgoing ATTRIBUTE_UNUSED)
1507 machine_mode mode;
1509 mode = TYPE_MODE (ret_type);
1510 /* We must change the mode like PROMOTE_MODE does.
1511 ??? PROMOTE_MODE is ignored for non-scalar types.
1512 The set of types tested here has to be kept in sync
1513 with the one in explow.c:promote_mode. */
1514 if (GET_MODE_CLASS (mode) == MODE_INT
1515 && GET_MODE_SIZE (mode) < 4
1516 && (TREE_CODE (ret_type) == INTEGER_TYPE
1517 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1518 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1519 || TREE_CODE (ret_type) == OFFSET_TYPE))
1520 mode = SImode;
1521 return gen_rtx_REG (mode, 0);
1524 static rtx
1525 epiphany_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1527 return gen_rtx_REG (mode, 0);
1530 static bool
1531 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1533 return regno == 0;
1536 /* Fix up invalid option settings. */
1537 static void
1538 epiphany_override_options (void)
1540 if (epiphany_stack_offset < 4)
1541 error ("stack_offset must be at least 4");
1542 if (epiphany_stack_offset & 3)
1543 error ("stack_offset must be a multiple of 4");
1544 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1545 if (!TARGET_SOFT_CMPSF)
1546 flag_finite_math_only = 1;
1548 /* This needs to be done at start up. It's convenient to do it here. */
1549 epiphany_init ();
1552 /* For a DImode load / store SET, make a SImode set for a
1553 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1554 subreg. */
1555 static rtx
1556 frame_subreg_note (rtx set, int offset)
1558 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1559 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1561 set = gen_rtx_SET (dst ,src);
1562 RTX_FRAME_RELATED_P (set) = 1;
1563 return set;
1566 static rtx_insn *
1567 frame_insn (rtx x)
1569 int i;
1570 rtx note = NULL_RTX;
1571 rtx_insn *insn;
1573 if (GET_CODE (x) == PARALLEL)
1575 rtx part = XVECEXP (x, 0, 0);
1577 if (GET_MODE (SET_DEST (part)) == DImode)
1579 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1580 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1581 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1582 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1584 part = copy_rtx (XVECEXP (x, 0, i));
1586 if (GET_CODE (part) == SET)
1587 RTX_FRAME_RELATED_P (part) = 1;
1588 XVECEXP (note, 0, i + 1) = part;
1591 else
1593 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1595 part = XVECEXP (x, 0, i);
1597 if (GET_CODE (part) == SET)
1598 RTX_FRAME_RELATED_P (part) = 1;
1602 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1603 note = gen_rtx_PARALLEL (VOIDmode,
1604 gen_rtvec (2, frame_subreg_note (x, 0),
1605 frame_subreg_note (x, UNITS_PER_WORD)));
1606 insn = emit_insn (x);
1607 RTX_FRAME_RELATED_P (insn) = 1;
1608 if (note)
1609 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1610 return insn;
1613 static rtx_insn *
1614 frame_move_insn (rtx to, rtx from)
1616 return frame_insn (gen_rtx_SET (to, from));
1619 /* Generate a MEM referring to a varargs argument slot. */
1621 static rtx
1622 gen_varargs_mem (machine_mode mode, rtx addr)
1624 rtx mem = gen_rtx_MEM (mode, addr);
1625 MEM_NOTRAP_P (mem) = 1;
1626 set_mem_alias_set (mem, get_varargs_alias_set ());
1627 return mem;
1630 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1631 If EPILOGUE_P is 0, save; if it is one, restore.
1632 ADDR is the stack slot to save the first register to; subsequent
1633 registers are written to lower addresses.
1634 However, the order of register pairs can be reversed in order to
1635 use double-word load-store instructions. Likewise, an unpaired single
1636 word save slot can be skipped while double saves are carried out, and
1637 reused when a single register is to be saved. */
1639 static void
1640 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1642 int i;
1643 int stack_offset
1644 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1645 rtx skipped_mem = NULL_RTX;
1646 int last_saved = limit - 1;
1648 if (!optimize)
1649 while (last_saved >= 0
1650 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1651 last_saved--;
1652 for (i = 0; i < limit; i++)
1654 machine_mode mode = word_mode;
1655 rtx mem, reg;
1656 int n = i;
1657 rtx (*gen_mem) (machine_mode, rtx) = gen_frame_mem;
1659 /* Make sure we push the arguments in the right order. */
1660 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1662 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1663 gen_mem = gen_varargs_mem;
1665 if (stack_offset == current_frame_info.first_slot_size
1666 && current_frame_info.first_slot >= 0)
1668 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1670 mode = DImode;
1671 addr = plus_constant (Pmode, addr,
1672 - (HOST_WIDE_INT) UNITS_PER_WORD);
1674 if (i-- < min || !epilogue_p)
1675 goto next_slot;
1676 n = current_frame_info.first_slot;
1677 gen_mem = gen_frame_mem;
1679 else if (n == UNKNOWN_REGNUM
1680 && stack_offset > current_frame_info.first_slot_size)
1682 i--;
1683 goto next_slot;
1685 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1686 continue;
1687 else if (i < min)
1688 goto next_slot;
1690 /* Check for a register pair to save. */
1691 if (n == i
1692 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1693 && (n & 1) == 0 && n+1 < limit
1694 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1696 /* If it fits in the current stack slot pair, place it there. */
1697 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1698 && stack_offset != 2 * UNITS_PER_WORD
1699 && (current_frame_info.last_slot < 0
1700 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1701 && (n+1 != last_saved || !skipped_mem))
1703 mode = DImode;
1704 i++;
1705 addr = plus_constant (Pmode, addr,
1706 - (HOST_WIDE_INT) UNITS_PER_WORD);
1708 /* If it fits in the following stack slot pair, that's fine, too. */
1709 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1710 && stack_offset != 2 * UNITS_PER_WORD
1711 && stack_offset != 3 * UNITS_PER_WORD
1712 && (current_frame_info.last_slot < 0
1713 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1714 && n + 1 != last_saved)
1716 gcc_assert (!skipped_mem);
1717 stack_offset -= GET_MODE_SIZE (mode);
1718 skipped_mem = gen_mem (mode, addr);
1719 mode = DImode;
1720 i++;
1721 addr = plus_constant (Pmode, addr,
1722 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1725 reg = gen_rtx_REG (mode, n);
1726 if (mode != DImode && skipped_mem)
1727 mem = skipped_mem;
1728 else
1729 mem = gen_mem (mode, addr);
1731 /* If we are loading / storing LR, note the offset that
1732 gen_reload_insi_ra requires. Since GPR_LR is even,
1733 we only need to test n, even if mode is DImode. */
1734 gcc_assert ((GPR_LR & 1) == 0);
1735 if (n == GPR_LR)
1737 long lr_slot_offset = 0;
1738 rtx m_addr = XEXP (mem, 0);
1740 if (GET_CODE (m_addr) == PLUS)
1741 lr_slot_offset = INTVAL (XEXP (m_addr, 1));
1742 if (frame_pointer_needed)
1743 lr_slot_offset += (current_frame_info.first_slot_offset
1744 - current_frame_info.total_size);
1745 if (MACHINE_FUNCTION (cfun)->lr_slot_known)
1746 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset
1747 == lr_slot_offset);
1748 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1749 MACHINE_FUNCTION (cfun)->lr_slot_known = 1;
1752 if (!epilogue_p)
1753 frame_move_insn (mem, reg);
1754 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1755 emit_move_insn (reg, mem);
1756 if (mem == skipped_mem)
1758 skipped_mem = NULL_RTX;
1759 continue;
1761 next_slot:
1762 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
1763 stack_offset -= GET_MODE_SIZE (mode);
1767 void
1768 epiphany_expand_prologue (void)
1770 int interrupt_p;
1771 enum epiphany_function_type fn_type;
1772 rtx addr, mem, off, reg;
1774 if (!current_frame_info.initialized)
1775 epiphany_compute_frame_size (get_frame_size ());
1777 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1778 if (flag_stack_usage_info)
1779 current_function_static_stack_size = current_frame_info.total_size;
1781 fn_type = epiphany_compute_function_type (current_function_decl);
1782 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1784 if (interrupt_p)
1786 addr = plus_constant (Pmode, stack_pointer_rtx,
1787 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1788 if (!lookup_attribute ("forwarder_section",
1789 DECL_ATTRIBUTES (current_function_decl))
1790 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1791 0)))
1792 frame_move_insn (gen_frame_mem (DImode, addr),
1793 gen_rtx_REG (DImode, GPR_0));
1794 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1795 gen_rtx_REG (word_mode, STATUS_REGNUM));
1796 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
1797 gen_rtx_REG (word_mode, IRET_REGNUM));
1798 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1799 off = GEN_INT (-current_frame_info.first_slot_offset);
1800 frame_insn (gen_stack_adjust_add (off, mem));
1801 if (!epiphany_uninterruptible_p (current_function_decl))
1802 emit_insn (gen_gie ());
1803 addr = plus_constant (Pmode, stack_pointer_rtx,
1804 current_frame_info.first_slot_offset
1805 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1807 else
1809 addr = plus_constant (Pmode, stack_pointer_rtx,
1810 epiphany_stack_offset
1811 - (HOST_WIDE_INT) UNITS_PER_WORD);
1812 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1813 addr, 0);
1814 /* Allocate register save area; for small to medium size frames,
1815 allocate the entire frame; this is joint with one register save. */
1816 if (current_frame_info.first_slot >= 0)
1818 machine_mode mode
1819 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1820 ? word_mode : DImode);
1822 off = GEN_INT (-current_frame_info.first_slot_offset);
1823 mem = gen_frame_mem (BLKmode,
1824 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1825 frame_insn (gen_stack_adjust_str
1826 (gen_frame_mem (mode, stack_pointer_rtx),
1827 gen_rtx_REG (mode, current_frame_info.first_slot),
1828 off, mem));
1829 addr = plus_constant (Pmode, addr,
1830 current_frame_info.first_slot_offset);
1833 epiphany_emit_save_restore (current_frame_info.small_threshold,
1834 FIRST_PSEUDO_REGISTER, addr, 0);
1835 if (current_frame_info.need_fp)
1836 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1837 /* For large frames, allocate bulk of frame. This is usually joint with one
1838 register save. */
1839 if (current_frame_info.last_slot >= 0)
1841 rtx ip, mem2, note;
1842 rtx_insn *insn;
1844 gcc_assert (current_frame_info.last_slot != GPR_FP
1845 || (!current_frame_info.need_fp
1846 && current_frame_info.first_slot < 0));
1847 off = GEN_INT (-current_frame_info.last_slot_offset);
1848 mem = gen_frame_mem (BLKmode,
1849 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1850 ip = gen_rtx_REG (Pmode, GPR_IP);
1851 frame_move_insn (ip, off);
1852 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1853 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1854 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1855 /* Instruction scheduling can separate the instruction setting IP from
1856 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1857 temporary register is. Example: _gcov.o */
1858 note = gen_rtx_SET (stack_pointer_rtx,
1859 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1860 note = gen_rtx_PARALLEL (VOIDmode,
1861 gen_rtvec (2, gen_rtx_SET (mem2, reg), note));
1862 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1864 /* If there is only one or no register to save, yet we have a large frame,
1865 use an add. */
1866 else if (current_frame_info.last_slot_offset)
1868 mem = gen_frame_mem (BLKmode,
1869 plus_constant (Pmode, stack_pointer_rtx,
1870 current_frame_info.last_slot_offset));
1871 off = GEN_INT (-current_frame_info.last_slot_offset);
1872 if (!SIMM11 (INTVAL (off)))
1874 reg = gen_rtx_REG (Pmode, GPR_IP);
1875 frame_move_insn (reg, off);
1876 off = reg;
1878 frame_insn (gen_stack_adjust_add (off, mem));
1882 void
1883 epiphany_expand_epilogue (int sibcall_p)
1885 int interrupt_p;
1886 enum epiphany_function_type fn_type;
1887 rtx mem, addr, reg, off;
1888 HOST_WIDE_INT restore_offset;
1890 fn_type = epiphany_compute_function_type( current_function_decl);
1891 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1893 /* For variable frames, deallocate bulk of frame. */
1894 if (current_frame_info.need_fp)
1896 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1897 emit_insn (gen_stack_adjust_mov (mem));
1899 /* Else for large static frames, deallocate bulk of frame. */
1900 else if (current_frame_info.last_slot_offset)
1902 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1903 reg = gen_rtx_REG (Pmode, GPR_IP);
1904 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1905 emit_insn (gen_stack_adjust_add (reg, mem));
1907 restore_offset = (interrupt_p
1908 ? - 3 * UNITS_PER_WORD
1909 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1910 addr = plus_constant (Pmode, stack_pointer_rtx,
1911 (current_frame_info.first_slot_offset
1912 + restore_offset));
1913 epiphany_emit_save_restore (current_frame_info.small_threshold,
1914 FIRST_PSEUDO_REGISTER, addr, 1);
1916 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1917 emit_insn (gen_gid ());
1919 off = GEN_INT (current_frame_info.first_slot_offset);
1920 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1921 /* For large / variable size frames, deallocating the register save area is
1922 joint with one register restore; for medium size frames, we use a
1923 dummy post-increment load to dealloacte the whole frame. */
1924 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1926 emit_insn (gen_stack_adjust_ldr
1927 (gen_rtx_REG (word_mode,
1928 (current_frame_info.last_slot >= 0
1929 ? current_frame_info.last_slot : GPR_IP)),
1930 gen_frame_mem (word_mode, stack_pointer_rtx),
1931 off,
1932 mem));
1934 /* While for small frames, we deallocate the entire frame with one add. */
1935 else if (INTVAL (off))
1937 emit_insn (gen_stack_adjust_add (off, mem));
1939 if (interrupt_p)
1941 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1942 gen_rtx_REG (SImode, GPR_0));
1943 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1944 gen_rtx_REG (SImode, GPR_1));
1945 addr = plus_constant (Pmode, stack_pointer_rtx,
1946 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1947 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1948 gen_frame_mem (DImode, addr));
1950 addr = plus_constant (Pmode, stack_pointer_rtx,
1951 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1952 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1953 if (!sibcall_p)
1955 if (interrupt_p)
1956 emit_jump_insn (gen_return_internal_interrupt());
1957 else
1958 emit_jump_insn (gen_return_i ());
1963 epiphany_initial_elimination_offset (int from, int to)
1965 epiphany_compute_frame_size (get_frame_size ());
1966 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1967 return current_frame_info.total_size - current_frame_info.reg_size;
1968 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1969 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1970 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1971 return (current_frame_info.total_size
1972 - ((current_frame_info.pretend_size + 4) & -8));
1973 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1974 return (current_frame_info.first_slot_offset
1975 - ((current_frame_info.pretend_size + 4) & -8));
1976 gcc_unreachable ();
1979 bool
1980 epiphany_regno_rename_ok (unsigned, unsigned dst)
1982 enum epiphany_function_type fn_type;
1984 fn_type = epiphany_compute_function_type (current_function_decl);
1985 if (!EPIPHANY_INTERRUPT_P (fn_type))
1986 return true;
1987 if (df_regs_ever_live_p (dst))
1988 return true;
1989 return false;
1992 static int
1993 epiphany_issue_rate (void)
1995 return 2;
1998 /* Function to update the integer COST
1999 based on the relationship between INSN that is dependent on
2000 DEP_INSN through the dependence LINK. The default is to make no
2001 adjustment to COST. This can be used for example to specify to
2002 the scheduler that an output- or anti-dependence does not incur
2003 the same cost as a data-dependence. The return value should be
2004 the new value for COST. */
2005 static int
2006 epiphany_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost)
2008 if (REG_NOTE_KIND (link) == 0)
2010 rtx dep_set;
2012 if (recog_memoized (insn) < 0
2013 || recog_memoized (dep_insn) < 0)
2014 return cost;
2016 dep_set = single_set (dep_insn);
2018 /* The latency that we specify in the scheduling description refers
2019 to the actual output, not to an auto-increment register; for that,
2020 the latency is one. */
2021 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
2023 rtx set = single_set (insn);
2025 if (set
2026 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
2027 && (!MEM_P (SET_DEST (set))
2028 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
2029 XEXP (SET_DEST (set), 0))))
2030 cost = 1;
2033 return cost;
2036 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
2038 #define RTX_OK_FOR_BASE_P(X) \
2039 (REG_P (X) && REG_OK_FOR_BASE_P (X))
2041 #define RTX_OK_FOR_INDEX_P(MODE, X) \
2042 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
2043 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
2044 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
2046 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
2047 (GET_CODE (X) == PLUS \
2048 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
2049 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
2050 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
2052 static bool
2053 epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict)
2055 #define REG_OK_FOR_BASE_P(X) \
2056 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
2057 if (RTX_OK_FOR_BASE_P (x))
2058 return true;
2059 if (RTX_FRAME_OFFSET_P (x))
2060 return true;
2061 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
2062 return true;
2063 /* If this is a misaligned stack access, don't force it to reg+index. */
2064 if (GET_MODE_SIZE (mode) == 8
2065 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
2066 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
2067 && !(INTVAL (XEXP (x, 1)) & 3)
2068 && INTVAL (XEXP (x, 1)) >= -2047 * 4
2069 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
2070 return true;
2071 if (TARGET_POST_INC
2072 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
2073 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
2074 return true;
2075 if ((TARGET_POST_MODIFY || reload_completed)
2076 && GET_CODE (x) == POST_MODIFY
2077 && GET_CODE (XEXP ((x), 1)) == PLUS
2078 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
2079 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
2080 return true;
2081 if (mode == BLKmode)
2082 return epiphany_legitimate_address_p (SImode, x, strict);
2083 return false;
2086 static reg_class_t
2087 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
2088 machine_mode mode ATTRIBUTE_UNUSED,
2089 secondary_reload_info *sri)
2091 /* This could give more reload inheritance, but we are missing some
2092 reload infrastructure. */
2093 if (0)
2094 if (in_p && GET_CODE (x) == UNSPEC
2095 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
2097 gcc_assert (rclass == GENERAL_REGS);
2098 sri->icode = CODE_FOR_reload_insi_ra;
2099 return NO_REGS;
2101 return NO_REGS;
2104 bool
2105 epiphany_is_long_call_p (rtx x)
2107 tree decl = SYMBOL_REF_DECL (x);
2108 bool ret_val = !TARGET_SHORT_CALLS;
2109 tree attrs;
2111 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2112 probably encode information via encode_section_info, and also
2113 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2114 into account. */
2115 if (decl)
2117 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
2118 if (lookup_attribute ("long_call", attrs))
2119 ret_val = true;
2120 else if (lookup_attribute ("short_call", attrs))
2121 ret_val = false;
2123 return ret_val;
2126 bool
2127 epiphany_small16 (rtx x)
2129 rtx base = x;
2130 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2132 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2134 base = XEXP (XEXP (x, 0), 0);
2135 offs = XEXP (XEXP (x, 0), 1);
2137 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2138 && epiphany_is_long_call_p (base))
2139 return false;
2140 return TARGET_SMALL16 != 0;
2143 /* Return nonzero if it is ok to make a tail-call to DECL. */
2144 static bool
2145 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2147 bool cfun_interrupt_p, call_interrupt_p;
2149 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2150 (current_function_decl));
2151 if (decl)
2152 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2153 else
2155 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2157 gcc_assert (POINTER_TYPE_P (fn_type));
2158 fn_type = TREE_TYPE (fn_type);
2159 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2160 || TREE_CODE (fn_type) == METHOD_TYPE);
2161 call_interrupt_p
2162 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2165 /* Don't tailcall from or to an ISR routine - although we could in
2166 principle tailcall from one ISR routine to another, we'd need to
2167 handle this in sibcall_epilogue to make it work. */
2168 if (cfun_interrupt_p || call_interrupt_p)
2169 return false;
2171 /* Everything else is ok. */
2172 return true;
2175 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2176 expander.
2177 Return true iff the type of T has the uninterruptible attribute.
2178 If T is NULL, return false. */
2179 bool
2180 epiphany_uninterruptible_p (tree t)
2182 tree attrs;
2184 if (t)
2186 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2187 if (lookup_attribute ("disinterrupt", attrs))
2188 return true;
2190 return false;
2193 bool
2194 epiphany_call_uninterruptible_p (rtx mem)
2196 rtx addr = XEXP (mem, 0);
2197 tree t = NULL_TREE;
2199 if (GET_CODE (addr) == SYMBOL_REF)
2200 t = SYMBOL_REF_DECL (addr);
2201 if (!t)
2202 t = MEM_EXPR (mem);
2203 return epiphany_uninterruptible_p (t);
2206 static machine_mode
2207 epiphany_promote_function_mode (const_tree type, machine_mode mode,
2208 int *punsignedp ATTRIBUTE_UNUSED,
2209 const_tree funtype ATTRIBUTE_UNUSED,
2210 int for_return ATTRIBUTE_UNUSED)
2212 int dummy;
2214 return promote_mode (type, mode, &dummy);
2217 static void
2218 epiphany_conditional_register_usage (void)
2220 int i;
2222 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2224 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2225 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2227 if (TARGET_HALF_REG_FILE)
2229 for (i = 32; i <= 63; i++)
2231 fixed_regs[i] = 1;
2232 call_used_regs[i] = 1;
2235 if (epiphany_m1reg >= 0)
2237 fixed_regs[epiphany_m1reg] = 1;
2238 call_used_regs[epiphany_m1reg] = 1;
2240 if (!TARGET_PREFER_SHORT_INSN_REGS)
2241 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2242 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2243 reg_class_contents[GENERAL_REGS]);
2244 /* It would be simpler and quicker if we could just use
2245 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2246 it is set up later by our caller. */
2247 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2248 if (!call_used_regs[i])
2249 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2252 /* Determine where to put an argument to a function.
2253 Value is zero to push the argument on the stack,
2254 or a hard register in which to store the argument.
2256 MODE is the argument's machine mode.
2257 TYPE is the data type of the argument (as a tree).
2258 This is null for libcalls where that information may
2259 not be available.
2260 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2261 the preceding args and about the function being called.
2262 NAMED is nonzero if this argument is a named parameter
2263 (otherwise it is an extra parameter matching an ellipsis). */
2264 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2265 registers and the rest are pushed. */
2266 static rtx
2267 epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode,
2268 const_tree type, bool named ATTRIBUTE_UNUSED)
2270 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2272 if (PASS_IN_REG_P (cum, mode, type))
2273 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2274 return 0;
2277 /* Update the data in CUM to advance over an argument
2278 of mode MODE and data type TYPE.
2279 (TYPE is null for libcalls where that information may not be available.) */
2280 static void
2281 epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
2282 const_tree type, bool named ATTRIBUTE_UNUSED)
2284 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2286 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2289 /* Nested function support.
2290 An epiphany trampoline looks like this:
2291 mov r16,%low(fnaddr)
2292 movt r16,%high(fnaddr)
2293 mov ip,%low(cxt)
2294 movt ip,%high(cxt)
2295 jr r16 */
2297 #define EPIPHANY_LOW_RTX(X) \
2298 (gen_rtx_IOR (SImode, \
2299 gen_rtx_ASHIFT (SImode, \
2300 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2301 gen_rtx_ASHIFT (SImode, \
2302 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2303 #define EPIPHANY_HIGH_RTX(X) \
2304 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2306 /* Emit RTL insns to initialize the variable parts of a trampoline.
2307 FNADDR is an RTX for the address of the function's pure code.
2308 CXT is an RTX for the static chain value for the function. */
2309 static void
2310 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2312 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2313 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2315 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2316 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2317 EPIPHANY_LOW_RTX (fnaddr)));
2318 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2319 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2320 EPIPHANY_HIGH_RTX (fnaddr)));
2321 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2322 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2323 EPIPHANY_LOW_RTX (cxt)));
2324 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2325 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2326 EPIPHANY_HIGH_RTX (cxt)));
2327 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2328 GEN_INT (0x0802014f));
2331 bool
2332 epiphany_optimize_mode_switching (int entity)
2334 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2335 return false;
2336 switch (entity)
2338 case EPIPHANY_MSW_ENTITY_AND:
2339 case EPIPHANY_MSW_ENTITY_OR:
2340 case EPIPHANY_MSW_ENTITY_CONFIG:
2341 return true;
2342 case EPIPHANY_MSW_ENTITY_NEAREST:
2343 case EPIPHANY_MSW_ENTITY_TRUNC:
2344 return optimize > 0;
2345 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2346 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2347 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2348 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2349 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2350 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2351 return optimize == 0 || current_pass == pass_mode_switch_use;
2353 gcc_unreachable ();
2356 static int
2357 epiphany_mode_priority (int entity, int priority)
2359 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2360 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2361 return priority;
2362 if (priority > 3)
2363 switch (priority)
2365 case 4: return FP_MODE_ROUND_UNKNOWN;
2366 case 5: return FP_MODE_NONE;
2367 default: gcc_unreachable ();
2369 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2371 case FP_MODE_INT:
2372 switch (priority)
2374 case 0: return FP_MODE_INT;
2375 case 1: return epiphany_normal_fp_rounding;
2376 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2377 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2378 case 3: return FP_MODE_CALLER;
2380 case FP_MODE_ROUND_NEAREST:
2381 case FP_MODE_CALLER:
2382 switch (priority)
2384 case 0: return FP_MODE_ROUND_NEAREST;
2385 case 1: return FP_MODE_ROUND_TRUNC;
2386 case 2: return FP_MODE_INT;
2387 case 3: return FP_MODE_CALLER;
2389 case FP_MODE_ROUND_TRUNC:
2390 switch (priority)
2392 case 0: return FP_MODE_ROUND_TRUNC;
2393 case 1: return FP_MODE_ROUND_NEAREST;
2394 case 2: return FP_MODE_INT;
2395 case 3: return FP_MODE_CALLER;
2397 case FP_MODE_ROUND_UNKNOWN:
2398 case FP_MODE_NONE:
2399 gcc_unreachable ();
2401 gcc_unreachable ();
2405 epiphany_mode_needed (int entity, rtx_insn *insn)
2407 enum attr_fp_mode mode;
2409 if (recog_memoized (insn) < 0)
2411 if (entity == EPIPHANY_MSW_ENTITY_AND
2412 || entity == EPIPHANY_MSW_ENTITY_OR
2413 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2414 return 2;
2415 return FP_MODE_NONE;
2417 mode = get_attr_fp_mode (insn);
2419 switch (entity)
2421 case EPIPHANY_MSW_ENTITY_AND:
2422 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
2423 case EPIPHANY_MSW_ENTITY_OR:
2424 return mode == FP_MODE_INT ? 1 : 2;
2425 case EPIPHANY_MSW_ENTITY_CONFIG:
2426 /* We must know/save config before we set it to something else.
2427 Where we need the original value, we are fine with having it
2428 just unchanged from the function start.
2429 Because of the nature of the mode switching optimization,
2430 a restore will be dominated by a clobber. */
2431 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2432 return 1;
2433 /* A cpecial case are abnormal edges, which are deemed to clobber
2434 the mode as well. We need to pin this effect on a actually
2435 dominating insn, and one where the frame can be accessed, too, in
2436 case the pseudo used to save CONFIG doesn't get a hard register. */
2437 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2438 return 1;
2439 return 2;
2440 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2441 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2442 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2443 /* Fall through. */
2444 case EPIPHANY_MSW_ENTITY_NEAREST:
2445 case EPIPHANY_MSW_ENTITY_TRUNC:
2446 if (mode == FP_MODE_ROUND_UNKNOWN)
2448 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2449 return FP_MODE_NONE;
2451 return mode;
2452 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2453 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2454 return FP_MODE_ROUND_UNKNOWN;
2455 return mode;
2456 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2457 if (mode == FP_MODE_ROUND_UNKNOWN)
2458 return epiphany_normal_fp_rounding;
2459 return mode;
2460 default:
2461 gcc_unreachable ();
2465 static int
2466 epiphany_mode_entry_exit (int entity, bool exit)
2468 int normal_mode = epiphany_normal_fp_mode ;
2470 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2471 if (epiphany_is_interrupt_p (current_function_decl))
2472 normal_mode = FP_MODE_CALLER;
2473 switch (entity)
2475 case EPIPHANY_MSW_ENTITY_AND:
2476 if (exit)
2477 return normal_mode != FP_MODE_INT ? 1 : 2;
2478 return 0;
2479 case EPIPHANY_MSW_ENTITY_OR:
2480 if (exit)
2481 return normal_mode == FP_MODE_INT ? 1 : 2;
2482 return 0;
2483 case EPIPHANY_MSW_ENTITY_CONFIG:
2484 if (exit)
2485 return 2;
2486 return normal_mode == FP_MODE_CALLER ? 0 : 1;
2487 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2488 if (normal_mode == FP_MODE_ROUND_NEAREST
2489 || normal_mode == FP_MODE_ROUND_TRUNC)
2490 return FP_MODE_ROUND_UNKNOWN;
2491 /* Fall through. */
2492 case EPIPHANY_MSW_ENTITY_NEAREST:
2493 case EPIPHANY_MSW_ENTITY_TRUNC:
2494 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2495 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2496 return normal_mode;
2497 default:
2498 gcc_unreachable ();
2503 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn)
2505 /* We have too few call-saved registers to hope to keep the masks across
2506 calls. */
2507 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2509 if (CALL_P (insn))
2510 return 0;
2511 return last_mode;
2513 /* If there is an abnormal edge, we don't want the config register to
2514 be 'saved' again at the destination.
2515 The frame pointer adjustment is inside a PARALLEL because of the
2516 flags clobber. */
2517 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2518 && GET_CODE (PATTERN (insn)) == PARALLEL
2519 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2520 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2522 gcc_assert (cfun->has_nonlocal_label);
2523 return 1;
2525 if (recog_memoized (insn) < 0)
2526 return last_mode;
2527 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2528 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2530 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2531 return FP_MODE_ROUND_NEAREST;
2532 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2533 return FP_MODE_ROUND_TRUNC;
2535 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2537 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2538 int fp_mode;
2540 if (REG_P (src))
2541 return FP_MODE_CALLER;
2542 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2543 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2544 && (fp_mode == FP_MODE_ROUND_NEAREST
2545 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2546 return FP_MODE_ROUND_UNKNOWN;
2547 return fp_mode;
2549 return last_mode;
2552 static int
2553 epiphany_mode_entry (int entity)
2555 return epiphany_mode_entry_exit (entity, false);
2558 static int
2559 epiphany_mode_exit (int entity)
2561 return epiphany_mode_entry_exit (entity, true);
2564 void
2565 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
2566 HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2568 rtx save_cc, cc_reg, mask, src, src2;
2569 enum attr_fp_mode fp_mode;
2571 if (!MACHINE_FUNCTION (cfun)->and_mask)
2573 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2574 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2576 if (entity == EPIPHANY_MSW_ENTITY_AND)
2578 gcc_assert (mode >= 0 && mode <= 2);
2579 if (mode == 1)
2580 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2581 gen_int_mode (0xfff1fffe, SImode));
2582 return;
2584 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2586 gcc_assert (mode >= 0 && mode <= 2);
2587 if (mode == 1)
2588 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2589 return;
2591 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2593 /* Mode switching optimization is done after emit_initial_value_sets,
2594 so we have to take care of CONFIG_REGNUM here. */
2595 gcc_assert (mode >= 0 && mode <= 2);
2596 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2597 if (mode == 1)
2598 emit_insn (gen_save_config (save));
2599 return;
2601 fp_mode = (enum attr_fp_mode) mode;
2602 src = NULL_RTX;
2604 switch (fp_mode)
2606 case FP_MODE_CALLER:
2607 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2608 so that the config save gets inserted before the first use. */
2609 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2610 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2611 mask = MACHINE_FUNCTION (cfun)->and_mask;
2612 break;
2613 case FP_MODE_ROUND_UNKNOWN:
2614 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2615 mask = MACHINE_FUNCTION (cfun)->and_mask;
2616 break;
2617 case FP_MODE_ROUND_NEAREST:
2618 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2619 return;
2620 mask = MACHINE_FUNCTION (cfun)->and_mask;
2621 break;
2622 case FP_MODE_ROUND_TRUNC:
2623 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2624 return;
2625 mask = MACHINE_FUNCTION (cfun)->and_mask;
2626 break;
2627 case FP_MODE_INT:
2628 mask = MACHINE_FUNCTION (cfun)->or_mask;
2629 break;
2630 case FP_MODE_NONE:
2631 default:
2632 gcc_unreachable ();
2634 save_cc = gen_reg_rtx (CCmode);
2635 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2636 emit_move_insn (save_cc, cc_reg);
2637 mask = force_reg (SImode, mask);
2638 if (!src)
2640 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2642 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2644 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2645 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2646 src2 = copy_rtx (src);
2647 else
2649 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2651 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2653 emit_insn (gen_set_fp_mode (src, src2, mask));
2654 emit_move_insn (cc_reg, save_cc);
2657 void
2658 epiphany_expand_set_fp_mode (rtx *operands)
2660 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2661 rtx src = operands[0];
2662 rtx mask_reg = operands[2];
2663 rtx scratch = operands[3];
2664 enum attr_fp_mode fp_mode;
2667 gcc_assert (rtx_equal_p (src, operands[1])
2668 /* Sometimes reload gets silly and reloads the same pseudo
2669 into different registers. */
2670 || (REG_P (src) && REG_P (operands[1])));
2672 if (!epiphany_uninterruptible_p (current_function_decl))
2673 emit_insn (gen_gid ());
2674 emit_move_insn (scratch, ctrl);
2676 if (GET_CODE (src) == REG)
2678 /* FP_MODE_CALLER */
2679 emit_insn (gen_xorsi3 (scratch, scratch, src));
2680 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2681 emit_insn (gen_xorsi3 (scratch, scratch, src));
2683 else
2685 gcc_assert (GET_CODE (src) == CONST);
2686 src = XEXP (src, 0);
2687 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2688 switch (fp_mode)
2690 case FP_MODE_ROUND_NEAREST:
2691 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2692 break;
2693 case FP_MODE_ROUND_TRUNC:
2694 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2695 emit_insn (gen_add2_insn (scratch, const1_rtx));
2696 break;
2697 case FP_MODE_INT:
2698 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2699 break;
2700 case FP_MODE_CALLER:
2701 case FP_MODE_ROUND_UNKNOWN:
2702 case FP_MODE_NONE:
2703 gcc_unreachable ();
2706 emit_move_insn (ctrl, scratch);
2707 if (!epiphany_uninterruptible_p (current_function_decl))
2708 emit_insn (gen_gie ());
2711 void
2712 epiphany_insert_mode_switch_use (rtx_insn *insn,
2713 int entity ATTRIBUTE_UNUSED,
2714 int mode ATTRIBUTE_UNUSED)
2716 rtx pat = PATTERN (insn);
2717 rtvec v;
2718 int len, i;
2719 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2720 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2722 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2723 return;
2724 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2726 case FP_MODE_ROUND_NEAREST:
2727 near = gen_rtx_USE (VOIDmode, near);
2728 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2729 break;
2730 case FP_MODE_ROUND_TRUNC:
2731 near = gen_rtx_CLOBBER (VOIDmode, near);
2732 trunc = gen_rtx_USE (VOIDmode, trunc);
2733 break;
2734 case FP_MODE_ROUND_UNKNOWN:
2735 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2736 trunc = copy_rtx (near);
2737 /* Fall through. */
2738 case FP_MODE_INT:
2739 case FP_MODE_CALLER:
2740 near = gen_rtx_USE (VOIDmode, near);
2741 trunc = gen_rtx_USE (VOIDmode, trunc);
2742 break;
2743 case FP_MODE_NONE:
2744 gcc_unreachable ();
2746 gcc_assert (GET_CODE (pat) == PARALLEL);
2747 len = XVECLEN (pat, 0);
2748 v = rtvec_alloc (len + 2);
2749 for (i = 0; i < len; i++)
2750 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2751 RTVEC_ELT (v, len) = near;
2752 RTVEC_ELT (v, len + 1) = trunc;
2753 pat = gen_rtx_PARALLEL (VOIDmode, v);
2754 PATTERN (insn) = pat;
2755 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2758 bool
2759 epiphany_epilogue_uses (int regno)
2761 if (regno == GPR_LR)
2762 return true;
2763 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2765 if (fixed_regs[regno]
2766 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2767 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2768 return false;
2769 return true;
2771 if (regno == FP_NEAREST_REGNUM
2772 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2773 return true;
2774 if (regno == FP_TRUNCATE_REGNUM
2775 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2776 return true;
2777 return false;
2780 static unsigned int
2781 epiphany_min_divisions_for_recip_mul (machine_mode mode)
2783 if (flag_reciprocal_math && mode == SFmode)
2784 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2785 it already at the tree level and expose it to further optimizations. */
2786 return 1;
2787 return default_min_divisions_for_recip_mul (mode);
2790 static machine_mode
2791 epiphany_preferred_simd_mode (machine_mode mode ATTRIBUTE_UNUSED)
2793 return TARGET_VECT_DOUBLE ? DImode : SImode;
2796 static bool
2797 epiphany_vector_mode_supported_p (machine_mode mode)
2799 if (mode == V2SFmode)
2800 return true;
2801 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2802 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2803 return true;
2804 return false;
2807 static bool
2808 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2810 /* Vectors which aren't in packed structures will not be less aligned than
2811 the natural alignment of their element type, so this is safe. */
2812 if (TYPE_ALIGN_UNIT (type) == 4)
2813 return !is_packed;
2815 return default_builtin_vector_alignment_reachable (type, is_packed);
2818 static bool
2819 epiphany_support_vector_misalignment (machine_mode mode, const_tree type,
2820 int misalignment, bool is_packed)
2822 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2823 return true;
2824 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2825 is_packed);
2828 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2829 structs. Make structs double-word-aligned it they are a double word or
2830 (potentially) larger; failing that, do the same for a size of 32 bits. */
2831 unsigned
2832 epiphany_special_round_type_align (tree type, unsigned computed,
2833 unsigned specified)
2835 unsigned align = MAX (computed, specified);
2836 tree field;
2837 HOST_WIDE_INT total, max;
2838 unsigned try_align = FASTEST_ALIGNMENT;
2840 if (maximum_field_alignment && try_align > maximum_field_alignment)
2841 try_align = maximum_field_alignment;
2842 if (align >= try_align)
2843 return align;
2844 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2846 tree offset, size;
2848 if (TREE_CODE (field) != FIELD_DECL
2849 || TREE_TYPE (field) == error_mark_node)
2850 continue;
2851 offset = bit_position (field);
2852 size = DECL_SIZE (field);
2853 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
2854 || tree_to_uhwi (offset) >= try_align
2855 || tree_to_uhwi (size) >= try_align)
2856 return try_align;
2857 total = tree_to_uhwi (offset) + tree_to_uhwi (size);
2858 if (total > max)
2859 max = total;
2861 if (max >= (HOST_WIDE_INT) try_align)
2862 align = try_align;
2863 else if (try_align > 32 && max >= 32)
2864 align = max > 32 ? 64 : 32;
2865 return align;
2868 /* Upping the alignment of arrays in structs is not only a performance
2869 enhancement, it also helps preserve assumptions about how
2870 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2871 libgcov.c . */
2872 unsigned
2873 epiphany_adjust_field_align (tree field, unsigned computed)
2875 if (computed == 32
2876 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
2878 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field)));
2880 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
2881 return 64;
2883 return computed;
2886 /* Output code to add DELTA to the first argument, and then jump
2887 to FUNCTION. Used for C++ multiple inheritance. */
2888 static void
2889 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2890 HOST_WIDE_INT delta,
2891 HOST_WIDE_INT vcall_offset,
2892 tree function)
2894 int this_regno
2895 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2896 const char *this_name = reg_names[this_regno];
2897 const char *fname;
2899 /* We use IP and R16 as a scratch registers. */
2900 gcc_assert (call_used_regs [GPR_IP]);
2901 gcc_assert (call_used_regs [GPR_16]);
2903 /* Add DELTA. When possible use a plain add, otherwise load it into
2904 a register first. */
2905 if (delta == 0)
2906 ; /* Done. */
2907 else if (SIMM11 (delta))
2908 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2909 else if (delta < 0 && delta >= -0xffff)
2911 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2912 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2914 else
2916 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2917 if (delta & ~0xffff)
2918 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2919 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2922 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2923 if (vcall_offset != 0)
2925 /* ldr ip,[this] --> temp = *this
2926 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2927 add this,this,ip --> this+ = *(*this + vcall_offset) */
2928 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2929 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2930 || (vcall_offset & 3) != 0)
2932 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2933 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2934 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2936 else
2937 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2938 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2941 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2942 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2944 fputs ("\tmov\tip,%low(", file);
2945 assemble_name (file, fname);
2946 fputs (")\n\tmovt\tip,%high(", file);
2947 assemble_name (file, fname);
2948 fputs (")\n\tjr ip\n", file);
2950 else
2952 fputs ("\tb\t", file);
2953 assemble_name (file, fname);
2954 fputc ('\n', file);
2958 void
2959 epiphany_start_function (FILE *file, const char *name, tree decl)
2961 /* If the function doesn't fit into the on-chip memory, it will have a
2962 section attribute - or lack of it - that denotes it goes somewhere else.
2963 But the architecture spec says that an interrupt vector still has to
2964 point to on-chip memory. So we must place a jump there to get to the
2965 actual function implementation. The forwarder_section attribute
2966 specifies the section where this jump goes.
2967 This mechanism can also be useful to have a shortcall destination for
2968 a function that is actually placed much farther away. */
2969 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2971 attrs = DECL_ATTRIBUTES (decl);
2972 int_attr = lookup_attribute ("interrupt", attrs);
2973 if (int_attr)
2974 for (int_names = TREE_VALUE (int_attr); int_names;
2975 int_names = TREE_CHAIN (int_names))
2977 char buf[99];
2979 int_name = TREE_VALUE (int_names);
2980 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2981 switch_to_section (get_section (buf, SECTION_CODE, decl));
2982 fputs ("\tb\t", file);
2983 assemble_name (file, name);
2984 fputc ('\n', file);
2986 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2987 if (forwarder_attr)
2989 const char *prefix = "__forwarder_dst_";
2990 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2992 strcpy (dst_name, prefix);
2993 strcat (dst_name, name);
2994 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2995 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2996 SECTION_CODE, decl));
2997 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2998 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
3000 int tmp = GPR_0;
3002 if (int_attr)
3003 fputs ("\tstrd r0,[sp,-1]\n", file);
3004 else
3005 tmp = GPR_16;
3006 gcc_assert (call_used_regs[tmp]);
3007 fprintf (file, "\tmov r%d,%%low(", tmp);
3008 assemble_name (file, dst_name);
3009 fprintf (file, ")\n"
3010 "\tmovt r%d,%%high(", tmp);
3011 assemble_name (file, dst_name);
3012 fprintf (file, ")\n"
3013 "\tjr r%d\n", tmp);
3015 else
3017 fputs ("\tb\t", file);
3018 assemble_name (file, dst_name);
3019 fputc ('\n', file);
3021 name = dst_name;
3023 switch_to_section (function_section (decl));
3024 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
3027 struct gcc_target targetm = TARGET_INITIALIZER;