Use rtx_insn for various target.def hooks
[official-gcc.git] / gcc / config / epiphany / epiphany.c
blob93030e5dc469444262ce47779c21c5bbb1c1be46
1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994-2014 Free Software Foundation, Inc.
3 Contributed by Embecosm on behalf of Adapteva, Inc.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "stor-layout.h"
27 #include "varasm.h"
28 #include "calls.h"
29 #include "stringpool.h"
30 #include "rtl.h"
31 #include "regs.h"
32 #include "hard-reg-set.h"
33 #include "real.h"
34 #include "insn-config.h"
35 #include "conditions.h"
36 #include "output.h"
37 #include "insn-attr.h"
38 #include "flags.h"
39 #include "function.h"
40 #include "expr.h"
41 #include "diagnostic-core.h"
42 #include "recog.h"
43 #include "toplev.h"
44 #include "tm_p.h"
45 #include "target.h"
46 #include "df.h"
47 #include "langhooks.h"
48 #include "insn-codes.h"
49 #include "ggc.h"
50 #include "tm-constrs.h"
51 #include "tree-pass.h" /* for current_pass */
52 #include "context.h"
53 #include "pass_manager.h"
54 #include "builtins.h"
56 /* Which cpu we're compiling for. */
57 int epiphany_cpu_type;
59 /* Name of mangle string to add to symbols to separate code compiled for each
60 cpu (or NULL). */
61 const char *epiphany_mangle_cpu;
63 /* Array of valid operand punctuation characters. */
64 char epiphany_punct_chars[256];
66 /* The rounding mode that we generally use for floating point. */
67 int epiphany_normal_fp_rounding;
69 /* The pass instance, for use in epiphany_optimize_mode_switching. */
70 static opt_pass *pass_mode_switch_use;
72 static void epiphany_init_reg_tables (void);
73 static int get_epiphany_condition_code (rtx);
74 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
75 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
76 bool *);
77 static bool epiphany_pass_by_reference (cumulative_args_t, enum machine_mode,
78 const_tree, bool);
79 static rtx_insn *frame_insn (rtx);
81 /* defines for the initialization of the GCC target structure. */
82 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
84 #define TARGET_PRINT_OPERAND epiphany_print_operand
85 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
87 #define TARGET_RTX_COSTS epiphany_rtx_costs
88 #define TARGET_ADDRESS_COST epiphany_address_cost
89 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
91 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
92 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
94 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
95 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
96 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
97 #define TARGET_FUNCTION_VALUE epiphany_function_value
98 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
99 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
101 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
103 /* Using the simplistic varags handling forces us to do partial reg/stack
104 argument passing for types with larger size (> 4 bytes) than alignemnt. */
105 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
107 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
109 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
110 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
112 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
114 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
116 #define TARGET_OPTION_OVERRIDE epiphany_override_options
118 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
120 #define TARGET_FUNCTION_ARG epiphany_function_arg
122 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
124 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
126 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
128 /* Nonzero if the constant rtx value is a legitimate general operand.
129 We can handle any 32- or 64-bit constant. */
130 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
132 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
133 epiphany_min_divisions_for_recip_mul
135 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
137 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
139 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
140 epiphany_vector_alignment_reachable
142 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
143 epiphany_support_vector_misalignment
145 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
146 hook_bool_const_tree_hwi_hwi_const_tree_true
147 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
149 /* ??? we can use larger offsets for wider-mode sized accesses, but there
150 is no concept of anchors being dependent on the modes that they are used
151 for, so we can only use an offset range that would suit all modes. */
152 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047)
153 /* We further restrict the minimum to be a multiple of eight. */
154 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040)
156 /* Mode switching hooks. */
158 #define TARGET_MODE_EMIT emit_set_fp_mode
160 #define TARGET_MODE_NEEDED epiphany_mode_needed
162 #define TARGET_MODE_PRIORITY epiphany_mode_priority
164 #define TARGET_MODE_ENTRY epiphany_mode_entry
166 #define TARGET_MODE_EXIT epiphany_mode_exit
168 #define TARGET_MODE_AFTER epiphany_mode_after
170 #include "target-def.h"
172 #undef TARGET_ASM_ALIGNED_HI_OP
173 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
174 #undef TARGET_ASM_ALIGNED_SI_OP
175 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
177 bool
178 epiphany_is_interrupt_p (tree decl)
180 tree attrs;
182 attrs = DECL_ATTRIBUTES (decl);
183 if (lookup_attribute ("interrupt", attrs))
184 return true;
185 else
186 return false;
189 /* Called from epiphany_override_options.
190 We use this to initialize various things. */
192 static void
193 epiphany_init (void)
195 /* N.B. this pass must not run before the first optimize_mode_switching
196 pass because of the side offect of epiphany_mode_needed on
197 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
198 pass_resolve_sw_modes. */
199 pass_mode_switch_use = make_pass_mode_switch_use (g);
200 struct register_pass_info insert_use_info
201 = { pass_mode_switch_use, "mode_sw",
202 1, PASS_POS_INSERT_AFTER
204 opt_pass *mode_sw2
205 = g->get_passes()->get_pass_mode_switching ()->clone ();
206 struct register_pass_info mode_sw2_info
207 = { mode_sw2, "mode_sw",
208 1, PASS_POS_INSERT_AFTER
210 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g);
211 struct register_pass_info mode_sw3_info
212 = { mode_sw3, "mode_sw",
213 1, PASS_POS_INSERT_AFTER
215 opt_pass *mode_sw4
216 = g->get_passes()->get_pass_split_all_insns ()->clone ();
217 struct register_pass_info mode_sw4_info
218 = { mode_sw4, "mode_sw",
219 1, PASS_POS_INSERT_AFTER
221 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
222 #define N_ENTITIES ARRAY_SIZE (num_modes)
224 epiphany_init_reg_tables ();
226 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
227 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
228 epiphany_punct_chars['-'] = 1;
230 epiphany_normal_fp_rounding
231 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
232 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
233 register_pass (&mode_sw4_info);
234 register_pass (&mode_sw2_info);
235 register_pass (&mode_sw3_info);
236 register_pass (&insert_use_info);
237 register_pass (&mode_sw2_info);
238 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
239 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
241 #if 1 /* As long as peep2_rescan is not implemented,
242 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
243 we need a second peephole2 pass to get reasonable code. */
245 opt_pass *extra_peephole2
246 = g->get_passes ()->get_pass_peephole2 ()->clone ();
247 struct register_pass_info peep2_2_info
248 = { extra_peephole2, "peephole2",
249 1, PASS_POS_INSERT_AFTER
252 register_pass (&peep2_2_info);
254 #endif
257 /* The condition codes of the EPIPHANY, and the inverse function. */
258 static const char *const epiphany_condition_codes[] =
259 { /* 0 1 2 3 4 5 6 7 8 9 */
260 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
261 /* 10 11 12 13 */
262 "beq","bne","blt", "blte",
265 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
267 /* Returns the index of the EPIPHANY condition code string in
268 `epiphany_condition_codes'. COMPARISON should be an rtx like
269 `(eq (...) (...))'. */
271 static int
272 get_epiphany_condition_code (rtx comparison)
274 switch (GET_MODE (XEXP (comparison, 0)))
276 case CCmode:
277 switch (GET_CODE (comparison))
279 case EQ : return 0;
280 case NE : return 1;
281 case LTU : return 2;
282 case GEU : return 3;
283 case GT : return 4;
284 case LE : return 5;
285 case GE : return 6;
286 case LT : return 7;
287 case GTU : return 8;
288 case LEU : return 9;
290 default : gcc_unreachable ();
292 case CC_N_NEmode:
293 switch (GET_CODE (comparison))
295 case EQ: return 6;
296 case NE: return 7;
297 default: gcc_unreachable ();
299 case CC_C_LTUmode:
300 switch (GET_CODE (comparison))
302 case GEU: return 2;
303 case LTU: return 3;
304 default: gcc_unreachable ();
306 case CC_C_GTUmode:
307 switch (GET_CODE (comparison))
309 case LEU: return 3;
310 case GTU: return 2;
311 default: gcc_unreachable ();
313 case CC_FPmode:
314 switch (GET_CODE (comparison))
316 case EQ: return 10;
317 case NE: return 11;
318 case LT: return 12;
319 case LE: return 13;
320 default: gcc_unreachable ();
322 case CC_FP_EQmode:
323 switch (GET_CODE (comparison))
325 case EQ: return 0;
326 case NE: return 1;
327 default: gcc_unreachable ();
329 case CC_FP_GTEmode:
330 switch (GET_CODE (comparison))
332 case EQ: return 0;
333 case NE: return 1;
334 case GT : return 4;
335 case GE : return 6;
336 case UNLE : return 5;
337 case UNLT : return 7;
338 default: gcc_unreachable ();
340 case CC_FP_ORDmode:
341 switch (GET_CODE (comparison))
343 case ORDERED: return 9;
344 case UNORDERED: return 8;
345 default: gcc_unreachable ();
347 case CC_FP_UNEQmode:
348 switch (GET_CODE (comparison))
350 case UNEQ: return 9;
351 case LTGT: return 8;
352 default: gcc_unreachable ();
354 default: gcc_unreachable ();
356 /*NOTREACHED*/
357 return (42);
361 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
363 hard_regno_mode_ok (int regno, enum machine_mode mode)
365 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
366 return (regno & 1) == 0 && GPR_P (regno);
367 else
368 return 1;
371 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
372 return the mode to be used for the comparison. */
374 enum machine_mode
375 epiphany_select_cc_mode (enum rtx_code op,
376 rtx x ATTRIBUTE_UNUSED,
377 rtx y ATTRIBUTE_UNUSED)
379 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
381 if (TARGET_SOFT_CMPSF
382 || op == ORDERED || op == UNORDERED)
384 if (op == EQ || op == NE)
385 return CC_FP_EQmode;
386 if (op == ORDERED || op == UNORDERED)
387 return CC_FP_ORDmode;
388 if (op == UNEQ || op == LTGT)
389 return CC_FP_UNEQmode;
390 return CC_FP_GTEmode;
392 return CC_FPmode;
394 /* recognize combiner pattern ashlsi_btst:
395 (parallel [
396 (set (reg:N_NE 65 cc1)
397 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
398 (const_int 1 [0x1])
399 (const_int 0 [0x0]))
400 (const_int 0 [0x0])))
401 (clobber (scratch:SI)) */
402 else if ((op == EQ || op == NE)
403 && GET_CODE (x) == ZERO_EXTRACT
404 && XEXP (x, 1) == const1_rtx
405 && CONST_INT_P (XEXP (x, 2)))
406 return CC_N_NEmode;
407 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
408 return CC_C_LTUmode;
409 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
410 return CC_C_GTUmode;
411 else
412 return CCmode;
415 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
417 static void
418 epiphany_init_reg_tables (void)
420 int i;
422 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
424 if (i == GPR_LR)
425 epiphany_regno_reg_class[i] = LR_REGS;
426 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
427 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
428 else if (call_used_regs[i]
429 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
430 epiphany_regno_reg_class[i] = SIBCALL_REGS;
431 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
432 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
433 else if (i < (GPR_LAST+1)
434 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
435 epiphany_regno_reg_class[i] = GENERAL_REGS;
436 else if (i == CC_REGNUM)
437 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
438 else
439 epiphany_regno_reg_class[i] = NO_REGS;
443 /* EPIPHANY specific attribute support.
445 The EPIPHANY has these attributes:
446 interrupt - for interrupt functions.
447 short_call - the function is assumed to be reachable with the b / bl
448 instructions.
449 long_call - the function address is loaded into a register before use.
450 disinterrupt - functions which mask interrupts throughout.
451 They unmask them while calling an interruptible
452 function, though. */
454 static const struct attribute_spec epiphany_attribute_table[] =
456 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
457 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
458 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
459 { "long_call", 0, 0, false, true, true, NULL, false },
460 { "short_call", 0, 0, false, true, true, NULL, false },
461 { "disinterrupt", 0, 0, false, true, true, NULL, true },
462 { NULL, 0, 0, false, false, false, NULL, false }
465 /* Handle an "interrupt" attribute; arguments as in
466 struct attribute_spec.handler. */
467 static tree
468 epiphany_handle_interrupt_attribute (tree *node, tree name, tree args,
469 int flags ATTRIBUTE_UNUSED,
470 bool *no_add_attrs)
472 tree value;
474 if (!args)
476 gcc_assert (DECL_P (*node));
477 tree t = TREE_TYPE (*node);
478 if (TREE_CODE (t) != FUNCTION_TYPE)
479 warning (OPT_Wattributes, "%qE attribute only applies to functions",
480 name);
481 /* Argument handling and the stack layout for interrupt handlers
482 don't mix. It makes no sense in the first place, so emit an
483 error for this. */
484 else if (TYPE_ARG_TYPES (t)
485 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node)
486 error_at (DECL_SOURCE_LOCATION (*node),
487 "interrupt handlers cannot have arguments");
488 return NULL_TREE;
491 value = TREE_VALUE (args);
493 if (TREE_CODE (value) != STRING_CST)
495 warning (OPT_Wattributes,
496 "argument of %qE attribute is not a string constant", name);
497 *no_add_attrs = true;
499 else if (strcmp (TREE_STRING_POINTER (value), "reset")
500 && strcmp (TREE_STRING_POINTER (value), "software_exception")
501 && strcmp (TREE_STRING_POINTER (value), "page_miss")
502 && strcmp (TREE_STRING_POINTER (value), "timer0")
503 && strcmp (TREE_STRING_POINTER (value), "timer1")
504 && strcmp (TREE_STRING_POINTER (value), "message")
505 && strcmp (TREE_STRING_POINTER (value), "dma0")
506 && strcmp (TREE_STRING_POINTER (value), "dma1")
507 && strcmp (TREE_STRING_POINTER (value), "wand")
508 && strcmp (TREE_STRING_POINTER (value), "swi"))
510 warning (OPT_Wattributes,
511 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
512 name);
513 *no_add_attrs = true;
514 return NULL_TREE;
517 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
518 flags, no_add_attrs);
521 /* Handle a "forwarder_section" attribute; arguments as in
522 struct attribute_spec.handler. */
523 static tree
524 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
525 tree name, tree args,
526 int flags ATTRIBUTE_UNUSED,
527 bool *no_add_attrs)
529 tree value;
531 value = TREE_VALUE (args);
533 if (TREE_CODE (value) != STRING_CST)
535 warning (OPT_Wattributes,
536 "argument of %qE attribute is not a string constant", name);
537 *no_add_attrs = true;
539 return NULL_TREE;
543 /* Misc. utilities. */
545 /* Generate a SYMBOL_REF for the special function NAME. When the address
546 can't be placed directly into a call instruction, and if possible, copy
547 it to a register so that cse / code hoisting is possible. */
549 sfunc_symbol (const char *name)
551 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
553 /* These sfuncs should be hidden, and every dso should get a copy. */
554 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
555 if (TARGET_SHORT_CALLS)
556 ; /* Nothing to be done. */
557 else if (can_create_pseudo_p ())
558 sym = copy_to_mode_reg (Pmode, sym);
559 else /* We rely on reload to fix this up. */
560 gcc_assert (!reload_in_progress || reload_completed);
561 return sym;
564 /* X and Y are two things to compare using CODE in IN_MODE.
565 Emit the compare insn, construct the the proper cc reg in the proper
566 mode, and return the rtx for the cc reg comparison in CMODE. */
569 gen_compare_reg (enum machine_mode cmode, enum rtx_code code,
570 enum machine_mode in_mode, rtx x, rtx y)
572 enum machine_mode mode = SELECT_CC_MODE (code, x, y);
573 rtx cc_reg, pat, clob0, clob1, clob2;
575 if (in_mode == VOIDmode)
576 in_mode = GET_MODE (x);
577 if (in_mode == VOIDmode)
578 in_mode = GET_MODE (y);
580 if (mode == CC_FPmode)
582 /* The epiphany has only EQ / NE / LT / LE conditions for
583 hardware floating point. */
584 if (code == GT || code == GE || code == UNLE || code == UNLT)
586 rtx tmp = x; x = y; y = tmp;
587 code = swap_condition (code);
589 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
590 y = force_reg (in_mode, y);
592 else
594 if (mode == CC_FP_GTEmode
595 && (code == LE || code == LT || code == UNGT || code == UNGE))
597 if (flag_finite_math_only
598 && ((REG_P (x) && REGNO (x) == GPR_0)
599 || (REG_P (y) && REGNO (y) == GPR_1)))
600 switch (code)
602 case LE: code = UNLE; break;
603 case LT: code = UNLT; break;
604 case UNGT: code = GT; break;
605 case UNGE: code = GE; break;
606 default: gcc_unreachable ();
608 else
610 rtx tmp = x; x = y; y = tmp;
611 code = swap_condition (code);
614 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
616 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
617 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
618 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
619 && (!REG_P (x) || REGNO (x) != GPR_0
620 || !REG_P (y) || REGNO (y) != GPR_1))
622 rtx reg;
624 #if 0
625 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
626 but just like the flag clobber of movsicc, we have to allow
627 this for ifcvt to work, on the assumption that we'll only want
628 to do this if these registers have been used before by the
629 pre-ifcvt code. */
630 gcc_assert (currently_expanding_to_rtl);
631 #endif
632 reg = gen_rtx_REG (in_mode, GPR_0);
633 if (reg_overlap_mentioned_p (reg, y))
634 return 0;
635 emit_move_insn (reg, x);
636 x = reg;
637 reg = gen_rtx_REG (in_mode, GPR_1);
638 emit_move_insn (reg, y);
639 y = reg;
641 else
642 x = force_reg (in_mode, x);
644 pat = gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y));
645 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
647 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
648 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
650 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
651 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
652 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
654 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
656 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
657 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
659 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
660 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
661 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
662 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
663 clob0, clob1, clob2));
665 else
667 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
668 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
670 emit_insn (pat);
671 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
674 /* The ROUND_ADVANCE* macros are local to this file. */
675 /* Round SIZE up to a word boundary. */
676 #define ROUND_ADVANCE(SIZE) \
677 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
679 /* Round arg MODE/TYPE up to the next word boundary. */
680 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
681 ((MODE) == BLKmode \
682 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
683 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
685 /* Round CUM up to the necessary point for argument MODE/TYPE. */
686 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
687 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
688 ? (((CUM) + 1) & ~1) \
689 : (CUM))
691 static unsigned int
692 epiphany_function_arg_boundary (enum machine_mode mode, const_tree type)
694 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
695 return PARM_BOUNDARY;
696 return 2 * PARM_BOUNDARY;
699 /* Do any needed setup for a variadic function. For the EPIPHANY, we
700 actually emit the code in epiphany_expand_prologue.
702 CUM has not been updated for the last named argument which has type TYPE
703 and mode MODE, and we rely on this fact. */
706 static void
707 epiphany_setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
708 tree type, int *pretend_size, int no_rtl)
710 int first_anon_arg;
711 CUMULATIVE_ARGS next_cum;
712 machine_function_t *mf = MACHINE_FUNCTION (cfun);
714 /* All BLKmode values are passed by reference. */
715 gcc_assert (mode != BLKmode);
717 next_cum = *get_cumulative_args (cum);
718 next_cum
719 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
720 first_anon_arg = next_cum;
722 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
724 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
725 int first_reg_offset = first_anon_arg;
727 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
728 * UNITS_PER_WORD);
730 mf->args_parsed = 1;
731 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
734 static int
735 epiphany_arg_partial_bytes (cumulative_args_t cum, enum machine_mode mode,
736 tree type, bool named ATTRIBUTE_UNUSED)
738 int words = 0, rounded_cum;
740 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
742 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
743 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
745 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
746 if (words >= ROUND_ADVANCE_ARG (mode, type))
747 words = 0;
749 return words * UNITS_PER_WORD;
752 /* Cost functions. */
754 /* Compute a (partial) cost for rtx X. Return true if the complete
755 cost has been computed, and false if subexpressions should be
756 scanned. In either case, *TOTAL contains the cost result. */
758 static bool
759 epiphany_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
760 int *total, bool speed ATTRIBUTE_UNUSED)
762 switch (code)
764 /* Small integers in the right context are as cheap as registers. */
765 case CONST_INT:
766 if ((outer_code == PLUS || outer_code == MINUS)
767 && SIMM11 (INTVAL (x)))
769 *total = 0;
770 return true;
772 if (IMM16 (INTVAL (x)))
774 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
775 return true;
777 /* FALLTHRU */
779 case CONST:
780 case LABEL_REF:
781 case SYMBOL_REF:
782 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
783 + (outer_code == SET ? 0 : 1));
784 return true;
786 case CONST_DOUBLE:
788 rtx high, low;
789 split_double (x, &high, &low);
790 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
791 + !IMM16 (INTVAL (low)));
792 return true;
795 case ASHIFT:
796 case ASHIFTRT:
797 case LSHIFTRT:
798 *total = COSTS_N_INSNS (1);
799 return true;
801 case COMPARE:
802 switch (GET_MODE (x))
804 /* There are a number of single-insn combiner patterns that use
805 the flag side effects of arithmetic. */
806 case CC_N_NEmode:
807 case CC_C_LTUmode:
808 case CC_C_GTUmode:
809 return true;
810 default:
811 return false;
815 case SET:
817 rtx src = SET_SRC (x);
818 if (BINARY_P (src))
819 *total = 0;
820 return false;
823 default:
824 return false;
829 /* Provide the costs of an addressing mode that contains ADDR.
830 If ADDR is not a valid address, its cost is irrelevant. */
832 static int
833 epiphany_address_cost (rtx addr, enum machine_mode mode,
834 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
836 rtx reg;
837 rtx off = const0_rtx;
838 int i;
840 if (speed)
841 return 0;
842 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
843 in long insns. */
844 switch (GET_CODE (addr))
846 case PLUS :
847 reg = XEXP (addr, 0);
848 off = XEXP (addr, 1);
849 break;
850 case POST_MODIFY:
851 reg = XEXP (addr, 0);
852 off = XEXP (addr, 1);
853 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
854 off = XEXP (off, 1);
855 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
856 return 0;
857 return 1;
858 case REG:
859 default:
860 reg = addr;
861 break;
863 if (!satisfies_constraint_Rgs (reg))
864 return 1;
865 /* The offset range available for short instructions depends on the mode
866 of the memory access. */
867 /* First, make sure we have a valid integer. */
868 if (!satisfies_constraint_L (off))
869 return 1;
870 i = INTVAL (off);
871 switch (GET_MODE_SIZE (mode))
873 default:
874 case 4:
875 if (i & 1)
876 return 1;
877 i >>= 1;
878 /* Fall through. */
879 case 2:
880 if (i & 1)
881 return 1;
882 i >>= 1;
883 /* Fall through. */
884 case 1:
885 return i < -7 || i > 7;
889 /* Compute the cost of moving data between registers and memory.
890 For integer, load latency is twice as long as register-register moves,
891 but issue pich is the same. For floating point, load latency is three
892 times as much as a reg-reg move. */
893 static int
894 epiphany_memory_move_cost (enum machine_mode mode,
895 reg_class_t rclass ATTRIBUTE_UNUSED,
896 bool in ATTRIBUTE_UNUSED)
898 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
901 /* Function prologue/epilogue handlers. */
903 /* EPIPHANY stack frames look like:
905 Before call After call
906 +-----------------------+ +-----------------------+
907 | | | |
908 high | local variables, | | local variables, |
909 mem | reg save area, etc. | | reg save area, etc. |
910 | | | |
911 +-----------------------+ +-----------------------+
912 | | | |
913 | arguments on stack. | | arguments on stack. |
914 | | | |
915 SP+8->+-----------------------+FP+8m->+-----------------------+
916 | 2 word save area for | | reg parm save area, |
917 | leaf funcs / flags | | only created for |
918 SP+0->+-----------------------+ | variable argument |
919 | functions |
920 FP+8n->+-----------------------+
922 | register save area |
924 +-----------------------+
926 | local variables |
928 FP+0->+-----------------------+
930 | alloca allocations |
932 +-----------------------+
934 | arguments on stack |
936 SP+8->+-----------------------+
937 low | 2 word save area for |
938 memory | leaf funcs / flags |
939 SP+0->+-----------------------+
941 Notes:
942 1) The "reg parm save area" does not exist for non variable argument fns.
943 The "reg parm save area" could be eliminated if we created our
944 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
945 (so it's not done). */
947 /* Structure to be filled in by epiphany_compute_frame_size with register
948 save masks, and offsets for the current function. */
949 struct epiphany_frame_info
951 unsigned int total_size; /* # bytes that the entire frame takes up. */
952 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
953 unsigned int args_size; /* # bytes that outgoing arguments take up. */
954 unsigned int reg_size; /* # bytes needed to store regs. */
955 unsigned int var_size; /* # bytes that variables take up. */
956 HARD_REG_SET gmask; /* Set of saved gp registers. */
957 int initialized; /* Nonzero if frame size already calculated. */
958 int stld_sz; /* Current load/store data size for offset
959 adjustment. */
960 int need_fp; /* value to override "frame_pointer_needed */
961 /* FIRST_SLOT is the slot that is saved first, at the very start of
962 the frame, with a POST_MODIFY to allocate the frame, if the size fits,
963 or at least the parm and register save areas, otherwise.
964 In the case of a large frame, LAST_SLOT is the slot that is saved last,
965 with a POST_MODIFY to allocate the rest of the frame. */
966 int first_slot, last_slot, first_slot_offset, last_slot_offset;
967 int first_slot_size;
968 int small_threshold;
971 /* Current frame information calculated by epiphany_compute_frame_size. */
972 static struct epiphany_frame_info current_frame_info;
974 /* Zero structure to initialize current_frame_info. */
975 static struct epiphany_frame_info zero_frame_info;
977 /* The usual; we set up our machine_function data. */
978 static struct machine_function *
979 epiphany_init_machine_status (void)
981 struct machine_function *machine;
983 /* Reset state info for each function. */
984 current_frame_info = zero_frame_info;
986 machine = ggc_cleared_alloc<machine_function_t> ();
988 return machine;
991 /* Implements INIT_EXPANDERS. We just set up to call the above
992 * function. */
993 void
994 epiphany_init_expanders (void)
996 init_machine_status = epiphany_init_machine_status;
999 /* Type of function DECL.
1001 The result is cached. To reset the cache at the end of a function,
1002 call with DECL = NULL_TREE. */
1004 static enum epiphany_function_type
1005 epiphany_compute_function_type (tree decl)
1007 tree a;
1008 /* Cached value. */
1009 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1010 /* Last function we were called for. */
1011 static tree last_fn = NULL_TREE;
1013 /* Resetting the cached value? */
1014 if (decl == NULL_TREE)
1016 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1017 last_fn = NULL_TREE;
1018 return fn_type;
1021 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
1022 return fn_type;
1024 /* Assume we have a normal function (not an interrupt handler). */
1025 fn_type = EPIPHANY_FUNCTION_NORMAL;
1027 /* Now see if this is an interrupt handler. */
1028 for (a = DECL_ATTRIBUTES (decl);
1030 a = TREE_CHAIN (a))
1032 tree name = TREE_PURPOSE (a);
1034 if (name == get_identifier ("interrupt"))
1035 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
1038 last_fn = decl;
1039 return fn_type;
1042 #define RETURN_ADDR_REGNUM GPR_LR
1043 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
1044 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
1046 /* Tell prologue and epilogue if register REGNO should be saved / restored.
1047 The return address and frame pointer are treated separately.
1048 Don't consider them here. */
1049 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
1050 ((df_regs_ever_live_p (regno) \
1051 || (interrupt_p && !crtl->is_leaf \
1052 && call_used_regs[regno] && !fixed_regs[regno])) \
1053 && (!call_used_regs[regno] || regno == GPR_LR \
1054 || (interrupt_p && regno != GPR_SP)))
1056 #define MUST_SAVE_RETURN_ADDR 0
1058 /* Return the bytes needed to compute the frame pointer from the current
1059 stack pointer.
1061 SIZE is the size needed for local variables. */
1063 static unsigned int
1064 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
1066 int regno;
1067 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
1068 HARD_REG_SET gmask;
1069 enum epiphany_function_type fn_type;
1070 int interrupt_p;
1071 int first_slot, last_slot, first_slot_offset, last_slot_offset;
1072 int first_slot_size;
1073 int small_slots = 0;
1075 var_size = size;
1076 args_size = crtl->outgoing_args_size;
1077 pretend_size = crtl->args.pretend_args_size;
1078 total_size = args_size + var_size;
1079 reg_size = 0;
1080 CLEAR_HARD_REG_SET (gmask);
1081 first_slot = -1;
1082 first_slot_offset = 0;
1083 last_slot = -1;
1084 last_slot_offset = 0;
1085 first_slot_size = UNITS_PER_WORD;
1087 /* See if this is an interrupt handler. Call used registers must be saved
1088 for them too. */
1089 fn_type = epiphany_compute_function_type (current_function_decl);
1090 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1092 /* Calculate space needed for registers. */
1094 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
1096 reg_size += UNITS_PER_WORD;
1097 SET_HARD_REG_BIT (gmask, regno);
1098 if (epiphany_stack_offset - reg_size == 0)
1099 first_slot = regno;
1102 if (interrupt_p)
1103 reg_size += 2 * UNITS_PER_WORD;
1104 else
1105 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
1107 if (frame_pointer_needed)
1109 current_frame_info.need_fp = 1;
1110 if (!interrupt_p && first_slot < 0)
1111 first_slot = GPR_FP;
1113 else
1114 current_frame_info.need_fp = 0;
1115 for (regno = 0; regno <= GPR_LAST; regno++)
1117 if (MUST_SAVE_REGISTER (regno, interrupt_p))
1119 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1120 reg_size += UNITS_PER_WORD;
1121 SET_HARD_REG_BIT (gmask, regno);
1122 /* FIXME: when optimizing for speed, take schedling into account
1123 when selecting these registers. */
1124 if (regno == first_slot)
1125 gcc_assert (regno == GPR_FP && frame_pointer_needed);
1126 else if (!interrupt_p && first_slot < 0)
1127 first_slot = regno;
1128 else if (last_slot < 0
1129 && (first_slot ^ regno) != 1
1130 && (!interrupt_p || regno > GPR_1))
1131 last_slot = regno;
1134 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1135 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1136 /* ??? Could sometimes do better than that. */
1137 current_frame_info.small_threshold
1138 = (optimize >= 3 || interrupt_p ? 0
1139 : pretend_size ? small_slots
1140 : 4 + small_slots - (first_slot == GPR_FP));
1142 /* If there might be variables with 64-bit alignment requirement, align the
1143 start of the variables. */
1144 if (var_size >= 2 * UNITS_PER_WORD
1145 /* We don't want to split a double reg save/restore across two unpaired
1146 stack slots when optimizing. This rounding could be avoided with
1147 more complex reordering of the register saves, but that would seem
1148 to be a lot of code complexity for little gain. */
1149 || (reg_size > 8 && optimize))
1150 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1151 if (((total_size + reg_size
1152 /* Reserve space for UNKNOWN_REGNUM. */
1153 + EPIPHANY_STACK_ALIGN (4))
1154 <= (unsigned) epiphany_stack_offset)
1155 && !interrupt_p
1156 && crtl->is_leaf && !frame_pointer_needed)
1158 first_slot = -1;
1159 last_slot = -1;
1160 goto alloc_done;
1162 else if (reg_size
1163 && !interrupt_p
1164 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1165 reg_size = epiphany_stack_offset;
1166 if (interrupt_p)
1168 if (total_size + reg_size < 0x3fc)
1170 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1171 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1172 last_slot = -1;
1174 else
1176 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1177 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1178 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1179 if (last_slot >= 0)
1180 CLEAR_HARD_REG_BIT (gmask, last_slot);
1183 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1185 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1186 last_slot = -1;
1188 else
1190 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1192 gcc_assert (first_slot < 0);
1193 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset);
1194 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1196 else
1198 first_slot_offset
1199 = (reg_size
1200 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1201 if (!first_slot_offset)
1203 if (first_slot != GPR_FP || !current_frame_info.need_fp)
1204 last_slot = first_slot;
1205 first_slot = -1;
1207 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1208 if (reg_size)
1209 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1211 if (last_slot >= 0)
1212 CLEAR_HARD_REG_BIT (gmask, last_slot);
1214 alloc_done:
1215 if (first_slot >= 0)
1217 CLEAR_HARD_REG_BIT (gmask, first_slot);
1218 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1219 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1221 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1222 first_slot_size = 2 * UNITS_PER_WORD;
1223 first_slot &= ~1;
1226 total_size = first_slot_offset + last_slot_offset;
1228 /* Save computed information. */
1229 current_frame_info.total_size = total_size;
1230 current_frame_info.pretend_size = pretend_size;
1231 current_frame_info.var_size = var_size;
1232 current_frame_info.args_size = args_size;
1233 current_frame_info.reg_size = reg_size;
1234 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1235 current_frame_info.first_slot = first_slot;
1236 current_frame_info.last_slot = last_slot;
1237 current_frame_info.first_slot_offset = first_slot_offset;
1238 current_frame_info.first_slot_size = first_slot_size;
1239 current_frame_info.last_slot_offset = last_slot_offset;
1241 current_frame_info.initialized = reload_completed;
1243 /* Ok, we're done. */
1244 return total_size;
1247 /* Print operand X (an rtx) in assembler syntax to file FILE.
1248 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1249 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1251 static void
1252 epiphany_print_operand (FILE *file, rtx x, int code)
1254 switch (code)
1256 case 'd':
1257 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1258 return;
1259 case 'D':
1260 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1261 (get_epiphany_condition_code (x))],
1262 file);
1263 return;
1265 case 'X':
1266 current_frame_info.stld_sz = 8;
1267 break;
1269 case 'C' :
1270 current_frame_info.stld_sz = 4;
1271 break;
1273 case 'c' :
1274 current_frame_info.stld_sz = 2;
1275 break;
1277 case 'f':
1278 fputs (REG_P (x) ? "jalr " : "bl ", file);
1279 break;
1281 case '-':
1282 fprintf (file, "r%d", epiphany_m1reg);
1283 return;
1285 case 0 :
1286 /* Do nothing special. */
1287 break;
1288 default :
1289 /* Unknown flag. */
1290 output_operand_lossage ("invalid operand output code");
1293 switch (GET_CODE (x))
1295 rtx addr;
1296 rtx offset;
1298 case REG :
1299 fputs (reg_names[REGNO (x)], file);
1300 break;
1301 case MEM :
1302 if (code == 0)
1303 current_frame_info.stld_sz = 1;
1304 fputc ('[', file);
1305 addr = XEXP (x, 0);
1306 switch (GET_CODE (addr))
1308 case POST_INC:
1309 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1310 addr = XEXP (addr, 0);
1311 break;
1312 case POST_DEC:
1313 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1314 addr = XEXP (addr, 0);
1315 break;
1316 case POST_MODIFY:
1317 offset = XEXP (XEXP (addr, 1), 1);
1318 addr = XEXP (addr, 0);
1319 break;
1320 default:
1321 offset = 0;
1322 break;
1324 output_address (addr);
1325 fputc (']', file);
1326 if (offset)
1328 fputc (',', file);
1329 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1331 default:
1332 gcc_unreachable ();
1333 case 8:
1334 offset = GEN_INT (INTVAL (offset) >> 3);
1335 break;
1336 case 4:
1337 offset = GEN_INT (INTVAL (offset) >> 2);
1338 break;
1339 case 2:
1340 offset = GEN_INT (INTVAL (offset) >> 1);
1341 break;
1342 case 1:
1343 break;
1345 output_address (offset);
1347 break;
1348 case CONST_DOUBLE :
1349 /* We handle SFmode constants here as output_addr_const doesn't. */
1350 if (GET_MODE (x) == SFmode)
1352 REAL_VALUE_TYPE d;
1353 long l;
1355 REAL_VALUE_FROM_CONST_DOUBLE (d, x);
1356 REAL_VALUE_TO_TARGET_SINGLE (d, l);
1357 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1358 break;
1360 /* Fall through. Let output_addr_const deal with it. */
1361 case CONST_INT:
1362 fprintf(file,"%s",IMMEDIATE_PREFIX);
1363 if (code == 'C' || code == 'X')
1365 fprintf (file, "%ld",
1366 (long) (INTVAL (x) / current_frame_info.stld_sz));
1367 break;
1369 /* Fall through */
1370 default :
1371 output_addr_const (file, x);
1372 break;
1376 /* Print a memory address as an operand to reference that memory location. */
1378 static void
1379 epiphany_print_operand_address (FILE *file, rtx addr)
1381 register rtx base, index = 0;
1382 int offset = 0;
1384 switch (GET_CODE (addr))
1386 case REG :
1387 fputs (reg_names[REGNO (addr)], file);
1388 break;
1389 case SYMBOL_REF :
1390 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1392 output_addr_const (file, addr);
1394 else
1396 output_addr_const (file, addr);
1398 break;
1399 case PLUS :
1400 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1401 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1402 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1403 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1404 else
1405 base = XEXP (addr, 0), index = XEXP (addr, 1);
1406 gcc_assert (GET_CODE (base) == REG);
1407 fputs (reg_names[REGNO (base)], file);
1408 if (index == 0)
1411 ** ++rk quirky method to scale offset for ld/str.......
1413 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1414 offset/current_frame_info.stld_sz);
1416 else
1418 switch (GET_CODE (index))
1420 case REG:
1421 fprintf (file, ",%s", reg_names[REGNO (index)]);
1422 break;
1423 case SYMBOL_REF:
1424 fputc (',', file), output_addr_const (file, index);
1425 break;
1426 default:
1427 gcc_unreachable ();
1430 break;
1431 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1432 /* We shouldn't get here as we've lost the mode of the memory object
1433 (which says how much to inc/dec by. */
1434 gcc_unreachable ();
1435 break;
1436 default:
1437 output_addr_const (file, addr);
1438 break;
1442 void
1443 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED,
1444 rtx *opvec ATTRIBUTE_UNUSED,
1445 int noperands ATTRIBUTE_UNUSED)
1447 int i = epiphany_n_nops;
1448 rtx pat ATTRIBUTE_UNUSED;
1450 while (i--)
1451 fputs ("\tnop\n", asm_out_file);
1455 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1457 static bool
1458 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1460 HOST_WIDE_INT size = int_size_in_bytes (type);
1462 if (AGGREGATE_TYPE_P (type)
1463 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1464 return true;
1465 return (size == -1 || size > 8);
1468 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1469 passed by reference. */
1471 static bool
1472 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1473 enum machine_mode mode, const_tree type,
1474 bool named ATTRIBUTE_UNUSED)
1476 if (type)
1478 if (AGGREGATE_TYPE_P (type)
1479 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1480 return true;
1482 return false;
1486 static rtx
1487 epiphany_function_value (const_tree ret_type,
1488 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1489 bool outgoing ATTRIBUTE_UNUSED)
1491 enum machine_mode mode;
1493 mode = TYPE_MODE (ret_type);
1494 /* We must change the mode like PROMOTE_MODE does.
1495 ??? PROMOTE_MODE is ignored for non-scalar types.
1496 The set of types tested here has to be kept in sync
1497 with the one in explow.c:promote_mode. */
1498 if (GET_MODE_CLASS (mode) == MODE_INT
1499 && GET_MODE_SIZE (mode) < 4
1500 && (TREE_CODE (ret_type) == INTEGER_TYPE
1501 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1502 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1503 || TREE_CODE (ret_type) == OFFSET_TYPE))
1504 mode = SImode;
1505 return gen_rtx_REG (mode, 0);
1508 static rtx
1509 epiphany_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1511 return gen_rtx_REG (mode, 0);
1514 static bool
1515 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1517 return regno == 0;
1520 /* Fix up invalid option settings. */
1521 static void
1522 epiphany_override_options (void)
1524 if (epiphany_stack_offset < 4)
1525 error ("stack_offset must be at least 4");
1526 if (epiphany_stack_offset & 3)
1527 error ("stack_offset must be a multiple of 4");
1528 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1530 /* This needs to be done at start up. It's convenient to do it here. */
1531 epiphany_init ();
1534 /* For a DImode load / store SET, make a SImode set for a
1535 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1536 subreg. */
1537 static rtx
1538 frame_subreg_note (rtx set, int offset)
1540 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1541 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1543 set = gen_rtx_SET (VOIDmode, dst ,src);
1544 RTX_FRAME_RELATED_P (set) = 1;
1545 return set;
1548 static rtx_insn *
1549 frame_insn (rtx x)
1551 int i;
1552 rtx note = NULL_RTX;
1553 rtx_insn *insn;
1555 if (GET_CODE (x) == PARALLEL)
1557 rtx part = XVECEXP (x, 0, 0);
1559 if (GET_MODE (SET_DEST (part)) == DImode)
1561 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1562 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1563 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1564 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1566 part = copy_rtx (XVECEXP (x, 0, i));
1568 if (GET_CODE (part) == SET)
1569 RTX_FRAME_RELATED_P (part) = 1;
1570 XVECEXP (note, 0, i + 1) = part;
1573 else
1575 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1577 part = XVECEXP (x, 0, i);
1579 if (GET_CODE (part) == SET)
1580 RTX_FRAME_RELATED_P (part) = 1;
1584 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1585 note = gen_rtx_PARALLEL (VOIDmode,
1586 gen_rtvec (2, frame_subreg_note (x, 0),
1587 frame_subreg_note (x, UNITS_PER_WORD)));
1588 insn = emit_insn (x);
1589 RTX_FRAME_RELATED_P (insn) = 1;
1590 if (note)
1591 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1592 return insn;
1595 static rtx_insn *
1596 frame_move_insn (rtx to, rtx from)
1598 return frame_insn (gen_rtx_SET (VOIDmode, to, from));
1601 /* Generate a MEM referring to a varargs argument slot. */
1603 static rtx
1604 gen_varargs_mem (enum machine_mode mode, rtx addr)
1606 rtx mem = gen_rtx_MEM (mode, addr);
1607 MEM_NOTRAP_P (mem) = 1;
1608 set_mem_alias_set (mem, get_varargs_alias_set ());
1609 return mem;
1612 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1613 If EPILOGUE_P is 0, save; if it is one, restore.
1614 ADDR is the stack slot to save the first register to; subsequent
1615 registers are written to lower addresses.
1616 However, the order of register pairs can be reversed in order to
1617 use double-word load-store instructions. Likewise, an unpaired single
1618 word save slot can be skipped while double saves are carried out, and
1619 reused when a single register is to be saved. */
1621 static void
1622 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1624 int i;
1625 int stack_offset
1626 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1627 rtx skipped_mem = NULL_RTX;
1628 int last_saved = limit - 1;
1630 if (!optimize)
1631 while (last_saved >= 0
1632 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1633 last_saved--;
1634 for (i = 0; i < limit; i++)
1636 enum machine_mode mode = word_mode;
1637 rtx mem, reg;
1638 int n = i;
1639 rtx (*gen_mem) (enum machine_mode, rtx) = gen_frame_mem;
1641 /* Make sure we push the arguments in the right order. */
1642 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1644 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1645 gen_mem = gen_varargs_mem;
1647 if (stack_offset == current_frame_info.first_slot_size
1648 && current_frame_info.first_slot >= 0)
1650 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1652 mode = DImode;
1653 addr = plus_constant (Pmode, addr,
1654 - (HOST_WIDE_INT) UNITS_PER_WORD);
1656 if (i-- < min || !epilogue_p)
1657 goto next_slot;
1658 n = current_frame_info.first_slot;
1659 gen_mem = gen_frame_mem;
1661 else if (n == UNKNOWN_REGNUM
1662 && stack_offset > current_frame_info.first_slot_size)
1664 i--;
1665 goto next_slot;
1667 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1668 continue;
1669 else if (i < min)
1670 goto next_slot;
1672 /* Check for a register pair to save. */
1673 if (n == i
1674 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1675 && (n & 1) == 0 && n+1 < limit
1676 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1678 /* If it fits in the current stack slot pair, place it there. */
1679 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1680 && stack_offset != 2 * UNITS_PER_WORD
1681 && (current_frame_info.last_slot < 0
1682 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1683 && (n+1 != last_saved || !skipped_mem))
1685 mode = DImode;
1686 i++;
1687 addr = plus_constant (Pmode, addr,
1688 - (HOST_WIDE_INT) UNITS_PER_WORD);
1690 /* If it fits in the following stack slot pair, that's fine, too. */
1691 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1692 && stack_offset != 2 * UNITS_PER_WORD
1693 && stack_offset != 3 * UNITS_PER_WORD
1694 && (current_frame_info.last_slot < 0
1695 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1696 && n + 1 != last_saved)
1698 gcc_assert (!skipped_mem);
1699 stack_offset -= GET_MODE_SIZE (mode);
1700 skipped_mem = gen_mem (mode, addr);
1701 mode = DImode;
1702 i++;
1703 addr = plus_constant (Pmode, addr,
1704 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1707 reg = gen_rtx_REG (mode, n);
1708 if (mode != DImode && skipped_mem)
1709 mem = skipped_mem;
1710 else
1711 mem = gen_mem (mode, addr);
1713 /* If we are loading / storing LR, note the offset that
1714 gen_reload_insi_ra requires. Since GPR_LR is even,
1715 we only need to test n, even if mode is DImode. */
1716 gcc_assert ((GPR_LR & 1) == 0);
1717 if (n == GPR_LR)
1719 long lr_slot_offset = 0;
1720 rtx m_addr = XEXP (mem, 0);
1722 if (GET_CODE (m_addr) == PLUS)
1723 lr_slot_offset = INTVAL (XEXP (m_addr, 1));
1724 if (frame_pointer_needed)
1725 lr_slot_offset += (current_frame_info.first_slot_offset
1726 - current_frame_info.total_size);
1727 if (MACHINE_FUNCTION (cfun)->lr_slot_known)
1728 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset
1729 == lr_slot_offset);
1730 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1731 MACHINE_FUNCTION (cfun)->lr_slot_known = 1;
1734 if (!epilogue_p)
1735 frame_move_insn (mem, reg);
1736 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1737 emit_move_insn (reg, mem);
1738 if (mem == skipped_mem)
1740 skipped_mem = NULL_RTX;
1741 continue;
1743 next_slot:
1744 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
1745 stack_offset -= GET_MODE_SIZE (mode);
1749 void
1750 epiphany_expand_prologue (void)
1752 int interrupt_p;
1753 enum epiphany_function_type fn_type;
1754 rtx addr, mem, off, reg;
1756 if (!current_frame_info.initialized)
1757 epiphany_compute_frame_size (get_frame_size ());
1759 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1760 if (flag_stack_usage_info)
1761 current_function_static_stack_size = current_frame_info.total_size;
1763 fn_type = epiphany_compute_function_type (current_function_decl);
1764 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1766 if (interrupt_p)
1768 addr = plus_constant (Pmode, stack_pointer_rtx,
1769 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1770 if (!lookup_attribute ("forwarder_section",
1771 DECL_ATTRIBUTES (current_function_decl))
1772 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1773 0)))
1774 frame_move_insn (gen_frame_mem (DImode, addr),
1775 gen_rtx_REG (DImode, GPR_0));
1776 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1777 gen_rtx_REG (word_mode, STATUS_REGNUM));
1778 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
1779 gen_rtx_REG (word_mode, IRET_REGNUM));
1780 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1781 off = GEN_INT (-current_frame_info.first_slot_offset);
1782 frame_insn (gen_stack_adjust_add (off, mem));
1783 if (!epiphany_uninterruptible_p (current_function_decl))
1784 emit_insn (gen_gie ());
1785 addr = plus_constant (Pmode, stack_pointer_rtx,
1786 current_frame_info.first_slot_offset
1787 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1789 else
1791 addr = plus_constant (Pmode, stack_pointer_rtx,
1792 epiphany_stack_offset
1793 - (HOST_WIDE_INT) UNITS_PER_WORD);
1794 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1795 addr, 0);
1796 /* Allocate register save area; for small to medium size frames,
1797 allocate the entire frame; this is joint with one register save. */
1798 if (current_frame_info.first_slot >= 0)
1800 enum machine_mode mode
1801 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1802 ? word_mode : DImode);
1804 off = GEN_INT (-current_frame_info.first_slot_offset);
1805 mem = gen_frame_mem (BLKmode,
1806 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1807 frame_insn (gen_stack_adjust_str
1808 (gen_frame_mem (mode, stack_pointer_rtx),
1809 gen_rtx_REG (mode, current_frame_info.first_slot),
1810 off, mem));
1811 addr = plus_constant (Pmode, addr,
1812 current_frame_info.first_slot_offset);
1815 epiphany_emit_save_restore (current_frame_info.small_threshold,
1816 FIRST_PSEUDO_REGISTER, addr, 0);
1817 if (current_frame_info.need_fp)
1818 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1819 /* For large frames, allocate bulk of frame. This is usually joint with one
1820 register save. */
1821 if (current_frame_info.last_slot >= 0)
1823 rtx ip, mem2, note;
1824 rtx_insn *insn;
1826 gcc_assert (current_frame_info.last_slot != GPR_FP
1827 || (!current_frame_info.need_fp
1828 && current_frame_info.first_slot < 0));
1829 off = GEN_INT (-current_frame_info.last_slot_offset);
1830 mem = gen_frame_mem (BLKmode,
1831 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1832 ip = gen_rtx_REG (Pmode, GPR_IP);
1833 frame_move_insn (ip, off);
1834 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1835 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1836 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1837 /* Instruction scheduling can separate the instruction setting IP from
1838 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1839 temporary register is. Example: _gcov.o */
1840 note = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1841 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1842 note = gen_rtx_PARALLEL (VOIDmode,
1843 gen_rtvec (2, gen_rtx_SET (VOIDmode, mem2, reg),
1844 note));
1845 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1847 /* If there is only one or no register to save, yet we have a large frame,
1848 use an add. */
1849 else if (current_frame_info.last_slot_offset)
1851 mem = gen_frame_mem (BLKmode,
1852 plus_constant (Pmode, stack_pointer_rtx,
1853 current_frame_info.last_slot_offset));
1854 off = GEN_INT (-current_frame_info.last_slot_offset);
1855 if (!SIMM11 (INTVAL (off)))
1857 reg = gen_rtx_REG (Pmode, GPR_IP);
1858 frame_move_insn (reg, off);
1859 off = reg;
1861 frame_insn (gen_stack_adjust_add (off, mem));
1865 void
1866 epiphany_expand_epilogue (int sibcall_p)
1868 int interrupt_p;
1869 enum epiphany_function_type fn_type;
1870 rtx mem, addr, reg, off;
1871 HOST_WIDE_INT restore_offset;
1873 fn_type = epiphany_compute_function_type( current_function_decl);
1874 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1876 /* For variable frames, deallocate bulk of frame. */
1877 if (current_frame_info.need_fp)
1879 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1880 emit_insn (gen_stack_adjust_mov (mem));
1882 /* Else for large static frames, deallocate bulk of frame. */
1883 else if (current_frame_info.last_slot_offset)
1885 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1886 reg = gen_rtx_REG (Pmode, GPR_IP);
1887 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1888 emit_insn (gen_stack_adjust_add (reg, mem));
1890 restore_offset = (interrupt_p
1891 ? - 3 * UNITS_PER_WORD
1892 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1893 addr = plus_constant (Pmode, stack_pointer_rtx,
1894 (current_frame_info.first_slot_offset
1895 + restore_offset));
1896 epiphany_emit_save_restore (current_frame_info.small_threshold,
1897 FIRST_PSEUDO_REGISTER, addr, 1);
1899 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1900 emit_insn (gen_gid ());
1902 off = GEN_INT (current_frame_info.first_slot_offset);
1903 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1904 /* For large / variable size frames, deallocating the register save area is
1905 joint with one register restore; for medium size frames, we use a
1906 dummy post-increment load to dealloacte the whole frame. */
1907 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1909 emit_insn (gen_stack_adjust_ldr
1910 (gen_rtx_REG (word_mode,
1911 (current_frame_info.last_slot >= 0
1912 ? current_frame_info.last_slot : GPR_IP)),
1913 gen_frame_mem (word_mode, stack_pointer_rtx),
1914 off,
1915 mem));
1917 /* While for small frames, we deallocate the entire frame with one add. */
1918 else if (INTVAL (off))
1920 emit_insn (gen_stack_adjust_add (off, mem));
1922 if (interrupt_p)
1924 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1925 gen_rtx_REG (SImode, GPR_0));
1926 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1927 gen_rtx_REG (SImode, GPR_1));
1928 addr = plus_constant (Pmode, stack_pointer_rtx,
1929 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1930 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1931 gen_frame_mem (DImode, addr));
1933 addr = plus_constant (Pmode, stack_pointer_rtx,
1934 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1935 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1936 if (!sibcall_p)
1938 if (interrupt_p)
1939 emit_jump_insn (gen_return_internal_interrupt());
1940 else
1941 emit_jump_insn (gen_return_i ());
1946 epiphany_initial_elimination_offset (int from, int to)
1948 epiphany_compute_frame_size (get_frame_size ());
1949 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1950 return current_frame_info.total_size - current_frame_info.reg_size;
1951 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1952 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1953 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1954 return (current_frame_info.total_size
1955 - ((current_frame_info.pretend_size + 4) & -8));
1956 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1957 return (current_frame_info.first_slot_offset
1958 - ((current_frame_info.pretend_size + 4) & -8));
1959 gcc_unreachable ();
1962 bool
1963 epiphany_regno_rename_ok (unsigned, unsigned dst)
1965 enum epiphany_function_type fn_type;
1967 fn_type = epiphany_compute_function_type (current_function_decl);
1968 if (!EPIPHANY_INTERRUPT_P (fn_type))
1969 return true;
1970 if (df_regs_ever_live_p (dst))
1971 return true;
1972 return false;
1975 static int
1976 epiphany_issue_rate (void)
1978 return 2;
1981 /* Function to update the integer COST
1982 based on the relationship between INSN that is dependent on
1983 DEP_INSN through the dependence LINK. The default is to make no
1984 adjustment to COST. This can be used for example to specify to
1985 the scheduler that an output- or anti-dependence does not incur
1986 the same cost as a data-dependence. The return value should be
1987 the new value for COST. */
1988 static int
1989 epiphany_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost)
1991 if (REG_NOTE_KIND (link) == 0)
1993 rtx dep_set;
1995 if (recog_memoized (insn) < 0
1996 || recog_memoized (dep_insn) < 0)
1997 return cost;
1999 dep_set = single_set (dep_insn);
2001 /* The latency that we specify in the scheduling description refers
2002 to the actual output, not to an auto-increment register; for that,
2003 the latency is one. */
2004 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
2006 rtx set = single_set (insn);
2008 if (set
2009 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
2010 && (!MEM_P (SET_DEST (set))
2011 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
2012 XEXP (SET_DEST (set), 0))))
2013 cost = 1;
2016 return cost;
2019 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
2021 #define RTX_OK_FOR_BASE_P(X) \
2022 (REG_P (X) && REG_OK_FOR_BASE_P (X))
2024 #define RTX_OK_FOR_INDEX_P(MODE, X) \
2025 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
2026 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
2027 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
2029 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
2030 (GET_CODE (X) == PLUS \
2031 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
2032 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
2033 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
2035 static bool
2036 epiphany_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
2038 #define REG_OK_FOR_BASE_P(X) \
2039 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
2040 if (RTX_OK_FOR_BASE_P (x))
2041 return true;
2042 if (RTX_FRAME_OFFSET_P (x))
2043 return true;
2044 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
2045 return true;
2046 /* If this is a misaligned stack access, don't force it to reg+index. */
2047 if (GET_MODE_SIZE (mode) == 8
2048 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
2049 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
2050 && !(INTVAL (XEXP (x, 1)) & 3)
2051 && INTVAL (XEXP (x, 1)) >= -2047 * 4
2052 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
2053 return true;
2054 if (TARGET_POST_INC
2055 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
2056 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
2057 return true;
2058 if ((TARGET_POST_MODIFY || reload_completed)
2059 && GET_CODE (x) == POST_MODIFY
2060 && GET_CODE (XEXP ((x), 1)) == PLUS
2061 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
2062 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
2063 return true;
2064 if (mode == BLKmode)
2065 return epiphany_legitimate_address_p (SImode, x, strict);
2066 return false;
2069 static reg_class_t
2070 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
2071 enum machine_mode mode ATTRIBUTE_UNUSED,
2072 secondary_reload_info *sri)
2074 /* This could give more reload inheritance, but we are missing some
2075 reload infrastructure. */
2076 if (0)
2077 if (in_p && GET_CODE (x) == UNSPEC
2078 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
2080 gcc_assert (rclass == GENERAL_REGS);
2081 sri->icode = CODE_FOR_reload_insi_ra;
2082 return NO_REGS;
2084 return NO_REGS;
2087 bool
2088 epiphany_is_long_call_p (rtx x)
2090 tree decl = SYMBOL_REF_DECL (x);
2091 bool ret_val = !TARGET_SHORT_CALLS;
2092 tree attrs;
2094 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2095 probably encode information via encode_section_info, and also
2096 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2097 into account. */
2098 if (decl)
2100 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
2101 if (lookup_attribute ("long_call", attrs))
2102 ret_val = true;
2103 else if (lookup_attribute ("short_call", attrs))
2104 ret_val = false;
2106 return ret_val;
2109 bool
2110 epiphany_small16 (rtx x)
2112 rtx base = x;
2113 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2115 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2117 base = XEXP (XEXP (x, 0), 0);
2118 offs = XEXP (XEXP (x, 0), 1);
2120 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2121 && epiphany_is_long_call_p (base))
2122 return false;
2123 return TARGET_SMALL16 != 0;
2126 /* Return nonzero if it is ok to make a tail-call to DECL. */
2127 static bool
2128 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2130 bool cfun_interrupt_p, call_interrupt_p;
2132 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2133 (current_function_decl));
2134 if (decl)
2135 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2136 else
2138 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2140 gcc_assert (POINTER_TYPE_P (fn_type));
2141 fn_type = TREE_TYPE (fn_type);
2142 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2143 || TREE_CODE (fn_type) == METHOD_TYPE);
2144 call_interrupt_p
2145 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2148 /* Don't tailcall from or to an ISR routine - although we could in
2149 principle tailcall from one ISR routine to another, we'd need to
2150 handle this in sibcall_epilogue to make it work. */
2151 if (cfun_interrupt_p || call_interrupt_p)
2152 return false;
2154 /* Everything else is ok. */
2155 return true;
2158 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2159 expander.
2160 Return true iff the type of T has the uninterruptible attribute.
2161 If T is NULL, return false. */
2162 bool
2163 epiphany_uninterruptible_p (tree t)
2165 tree attrs;
2167 if (t)
2169 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2170 if (lookup_attribute ("disinterrupt", attrs))
2171 return true;
2173 return false;
2176 bool
2177 epiphany_call_uninterruptible_p (rtx mem)
2179 rtx addr = XEXP (mem, 0);
2180 tree t = NULL_TREE;
2182 if (GET_CODE (addr) == SYMBOL_REF)
2183 t = SYMBOL_REF_DECL (addr);
2184 if (!t)
2185 t = MEM_EXPR (mem);
2186 return epiphany_uninterruptible_p (t);
2189 static enum machine_mode
2190 epiphany_promote_function_mode (const_tree type, enum machine_mode mode,
2191 int *punsignedp ATTRIBUTE_UNUSED,
2192 const_tree funtype ATTRIBUTE_UNUSED,
2193 int for_return ATTRIBUTE_UNUSED)
2195 int dummy;
2197 return promote_mode (type, mode, &dummy);
2200 static void
2201 epiphany_conditional_register_usage (void)
2203 int i;
2205 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2207 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2208 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2210 if (TARGET_HALF_REG_FILE)
2212 for (i = 32; i <= 63; i++)
2214 fixed_regs[i] = 1;
2215 call_used_regs[i] = 1;
2218 if (epiphany_m1reg >= 0)
2220 fixed_regs[epiphany_m1reg] = 1;
2221 call_used_regs[epiphany_m1reg] = 1;
2223 if (!TARGET_PREFER_SHORT_INSN_REGS)
2224 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2225 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2226 reg_class_contents[GENERAL_REGS]);
2227 /* It would be simpler and quicker if we could just use
2228 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2229 it is set up later by our caller. */
2230 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2231 if (!call_used_regs[i])
2232 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2235 /* Determine where to put an argument to a function.
2236 Value is zero to push the argument on the stack,
2237 or a hard register in which to store the argument.
2239 MODE is the argument's machine mode.
2240 TYPE is the data type of the argument (as a tree).
2241 This is null for libcalls where that information may
2242 not be available.
2243 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2244 the preceding args and about the function being called.
2245 NAMED is nonzero if this argument is a named parameter
2246 (otherwise it is an extra parameter matching an ellipsis). */
2247 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2248 registers and the rest are pushed. */
2249 static rtx
2250 epiphany_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
2251 const_tree type, bool named ATTRIBUTE_UNUSED)
2253 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2255 if (PASS_IN_REG_P (cum, mode, type))
2256 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2257 return 0;
2260 /* Update the data in CUM to advance over an argument
2261 of mode MODE and data type TYPE.
2262 (TYPE is null for libcalls where that information may not be available.) */
2263 static void
2264 epiphany_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
2265 const_tree type, bool named ATTRIBUTE_UNUSED)
2267 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2269 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2272 /* Nested function support.
2273 An epiphany trampoline looks like this:
2274 mov r16,%low(fnaddr)
2275 movt r16,%high(fnaddr)
2276 mov ip,%low(cxt)
2277 movt ip,%high(cxt)
2278 jr r16 */
2280 #define EPIPHANY_LOW_RTX(X) \
2281 (gen_rtx_IOR (SImode, \
2282 gen_rtx_ASHIFT (SImode, \
2283 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2284 gen_rtx_ASHIFT (SImode, \
2285 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2286 #define EPIPHANY_HIGH_RTX(X) \
2287 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2289 /* Emit RTL insns to initialize the variable parts of a trampoline.
2290 FNADDR is an RTX for the address of the function's pure code.
2291 CXT is an RTX for the static chain value for the function. */
2292 static void
2293 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2295 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2296 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2298 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2299 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2300 EPIPHANY_LOW_RTX (fnaddr)));
2301 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2302 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2303 EPIPHANY_HIGH_RTX (fnaddr)));
2304 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2305 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2306 EPIPHANY_LOW_RTX (cxt)));
2307 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2308 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2309 EPIPHANY_HIGH_RTX (cxt)));
2310 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2311 GEN_INT (0x0802014f));
2314 bool
2315 epiphany_optimize_mode_switching (int entity)
2317 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2318 return false;
2319 switch (entity)
2321 case EPIPHANY_MSW_ENTITY_AND:
2322 case EPIPHANY_MSW_ENTITY_OR:
2323 case EPIPHANY_MSW_ENTITY_CONFIG:
2324 return true;
2325 case EPIPHANY_MSW_ENTITY_NEAREST:
2326 case EPIPHANY_MSW_ENTITY_TRUNC:
2327 return optimize > 0;
2328 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2329 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2330 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2331 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2332 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2333 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2334 return optimize == 0 || current_pass == pass_mode_switch_use;
2336 gcc_unreachable ();
2339 static int
2340 epiphany_mode_priority (int entity, int priority)
2342 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2343 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2344 return priority;
2345 if (priority > 3)
2346 switch (priority)
2348 case 4: return FP_MODE_ROUND_UNKNOWN;
2349 case 5: return FP_MODE_NONE;
2350 default: gcc_unreachable ();
2352 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2354 case FP_MODE_INT:
2355 switch (priority)
2357 case 0: return FP_MODE_INT;
2358 case 1: return epiphany_normal_fp_rounding;
2359 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2360 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2361 case 3: return FP_MODE_CALLER;
2363 case FP_MODE_ROUND_NEAREST:
2364 case FP_MODE_CALLER:
2365 switch (priority)
2367 case 0: return FP_MODE_ROUND_NEAREST;
2368 case 1: return FP_MODE_ROUND_TRUNC;
2369 case 2: return FP_MODE_INT;
2370 case 3: return FP_MODE_CALLER;
2372 case FP_MODE_ROUND_TRUNC:
2373 switch (priority)
2375 case 0: return FP_MODE_ROUND_TRUNC;
2376 case 1: return FP_MODE_ROUND_NEAREST;
2377 case 2: return FP_MODE_INT;
2378 case 3: return FP_MODE_CALLER;
2380 case FP_MODE_ROUND_UNKNOWN:
2381 case FP_MODE_NONE:
2382 gcc_unreachable ();
2384 gcc_unreachable ();
2388 epiphany_mode_needed (int entity, rtx_insn *insn)
2390 enum attr_fp_mode mode;
2392 if (recog_memoized (insn) < 0)
2394 if (entity == EPIPHANY_MSW_ENTITY_AND
2395 || entity == EPIPHANY_MSW_ENTITY_OR
2396 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2397 return 2;
2398 return FP_MODE_NONE;
2400 mode = get_attr_fp_mode (insn);
2402 switch (entity)
2404 case EPIPHANY_MSW_ENTITY_AND:
2405 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
2406 case EPIPHANY_MSW_ENTITY_OR:
2407 return mode == FP_MODE_INT ? 1 : 2;
2408 case EPIPHANY_MSW_ENTITY_CONFIG:
2409 /* We must know/save config before we set it to something else.
2410 Where we need the original value, we are fine with having it
2411 just unchanged from the function start.
2412 Because of the nature of the mode switching optimization,
2413 a restore will be dominated by a clobber. */
2414 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2415 return 1;
2416 /* A cpecial case are abnormal edges, which are deemed to clobber
2417 the mode as well. We need to pin this effect on a actually
2418 dominating insn, and one where the frame can be accessed, too, in
2419 case the pseudo used to save CONFIG doesn't get a hard register. */
2420 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2421 return 1;
2422 return 2;
2423 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2424 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2425 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2426 /* Fall through. */
2427 case EPIPHANY_MSW_ENTITY_NEAREST:
2428 case EPIPHANY_MSW_ENTITY_TRUNC:
2429 if (mode == FP_MODE_ROUND_UNKNOWN)
2431 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2432 return FP_MODE_NONE;
2434 return mode;
2435 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2436 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2437 return FP_MODE_ROUND_UNKNOWN;
2438 return mode;
2439 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2440 if (mode == FP_MODE_ROUND_UNKNOWN)
2441 return epiphany_normal_fp_rounding;
2442 return mode;
2443 default:
2444 gcc_unreachable ();
2448 static int
2449 epiphany_mode_entry_exit (int entity, bool exit)
2451 int normal_mode = epiphany_normal_fp_mode ;
2453 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2454 if (epiphany_is_interrupt_p (current_function_decl))
2455 normal_mode = FP_MODE_CALLER;
2456 switch (entity)
2458 case EPIPHANY_MSW_ENTITY_AND:
2459 if (exit)
2460 return normal_mode != FP_MODE_INT ? 1 : 2;
2461 return 0;
2462 case EPIPHANY_MSW_ENTITY_OR:
2463 if (exit)
2464 return normal_mode == FP_MODE_INT ? 1 : 2;
2465 return 0;
2466 case EPIPHANY_MSW_ENTITY_CONFIG:
2467 if (exit)
2468 return 2;
2469 return normal_mode == FP_MODE_CALLER ? 0 : 1;
2470 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2471 if (normal_mode == FP_MODE_ROUND_NEAREST
2472 || normal_mode == FP_MODE_ROUND_TRUNC)
2473 return FP_MODE_ROUND_UNKNOWN;
2474 /* Fall through. */
2475 case EPIPHANY_MSW_ENTITY_NEAREST:
2476 case EPIPHANY_MSW_ENTITY_TRUNC:
2477 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2478 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2479 return normal_mode;
2480 default:
2481 gcc_unreachable ();
2486 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn)
2488 /* We have too few call-saved registers to hope to keep the masks across
2489 calls. */
2490 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2492 if (CALL_P (insn))
2493 return 0;
2494 return last_mode;
2496 /* If there is an abnormal edge, we don't want the config register to
2497 be 'saved' again at the destination.
2498 The frame pointer adjustment is inside a PARALLEL because of the
2499 flags clobber. */
2500 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2501 && GET_CODE (PATTERN (insn)) == PARALLEL
2502 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2503 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2505 gcc_assert (cfun->has_nonlocal_label);
2506 return 1;
2508 if (recog_memoized (insn) < 0)
2509 return last_mode;
2510 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2511 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2513 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2514 return FP_MODE_ROUND_NEAREST;
2515 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2516 return FP_MODE_ROUND_TRUNC;
2518 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2520 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2521 int fp_mode;
2523 if (REG_P (src))
2524 return FP_MODE_CALLER;
2525 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2526 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2527 && (fp_mode == FP_MODE_ROUND_NEAREST
2528 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2529 return FP_MODE_ROUND_UNKNOWN;
2530 return fp_mode;
2532 return last_mode;
2535 static int
2536 epiphany_mode_entry (int entity)
2538 return epiphany_mode_entry_exit (entity, false);
2541 static int
2542 epiphany_mode_exit (int entity)
2544 return epiphany_mode_entry_exit (entity, true);
2547 void
2548 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
2549 HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2551 rtx save_cc, cc_reg, mask, src, src2;
2552 enum attr_fp_mode fp_mode;
2554 if (!MACHINE_FUNCTION (cfun)->and_mask)
2556 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2557 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2559 if (entity == EPIPHANY_MSW_ENTITY_AND)
2561 gcc_assert (mode >= 0 && mode <= 2);
2562 if (mode == 1)
2563 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2564 gen_int_mode (0xfff1fffe, SImode));
2565 return;
2567 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2569 gcc_assert (mode >= 0 && mode <= 2);
2570 if (mode == 1)
2571 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2572 return;
2574 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2576 /* Mode switching optimization is done after emit_initial_value_sets,
2577 so we have to take care of CONFIG_REGNUM here. */
2578 gcc_assert (mode >= 0 && mode <= 2);
2579 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2580 if (mode == 1)
2581 emit_insn (gen_save_config (save));
2582 return;
2584 fp_mode = (enum attr_fp_mode) mode;
2585 src = NULL_RTX;
2587 switch (fp_mode)
2589 case FP_MODE_CALLER:
2590 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2591 so that the config save gets inserted before the first use. */
2592 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2593 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2594 mask = MACHINE_FUNCTION (cfun)->and_mask;
2595 break;
2596 case FP_MODE_ROUND_UNKNOWN:
2597 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2598 mask = MACHINE_FUNCTION (cfun)->and_mask;
2599 break;
2600 case FP_MODE_ROUND_NEAREST:
2601 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2602 return;
2603 mask = MACHINE_FUNCTION (cfun)->and_mask;
2604 break;
2605 case FP_MODE_ROUND_TRUNC:
2606 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2607 return;
2608 mask = MACHINE_FUNCTION (cfun)->and_mask;
2609 break;
2610 case FP_MODE_INT:
2611 mask = MACHINE_FUNCTION (cfun)->or_mask;
2612 break;
2613 case FP_MODE_NONE:
2614 default:
2615 gcc_unreachable ();
2617 save_cc = gen_reg_rtx (CCmode);
2618 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2619 emit_move_insn (save_cc, cc_reg);
2620 mask = force_reg (SImode, mask);
2621 if (!src)
2623 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2625 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2627 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2628 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2629 src2 = copy_rtx (src);
2630 else
2632 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2634 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2636 emit_insn (gen_set_fp_mode (src, src2, mask));
2637 emit_move_insn (cc_reg, save_cc);
2640 void
2641 epiphany_expand_set_fp_mode (rtx *operands)
2643 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2644 rtx src = operands[0];
2645 rtx mask_reg = operands[2];
2646 rtx scratch = operands[3];
2647 enum attr_fp_mode fp_mode;
2650 gcc_assert (rtx_equal_p (src, operands[1])
2651 /* Sometimes reload gets silly and reloads the same pseudo
2652 into different registers. */
2653 || (REG_P (src) && REG_P (operands[1])));
2655 if (!epiphany_uninterruptible_p (current_function_decl))
2656 emit_insn (gen_gid ());
2657 emit_move_insn (scratch, ctrl);
2659 if (GET_CODE (src) == REG)
2661 /* FP_MODE_CALLER */
2662 emit_insn (gen_xorsi3 (scratch, scratch, src));
2663 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2664 emit_insn (gen_xorsi3 (scratch, scratch, src));
2666 else
2668 gcc_assert (GET_CODE (src) == CONST);
2669 src = XEXP (src, 0);
2670 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2671 switch (fp_mode)
2673 case FP_MODE_ROUND_NEAREST:
2674 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2675 break;
2676 case FP_MODE_ROUND_TRUNC:
2677 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2678 emit_insn (gen_add2_insn (scratch, const1_rtx));
2679 break;
2680 case FP_MODE_INT:
2681 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2682 break;
2683 case FP_MODE_CALLER:
2684 case FP_MODE_ROUND_UNKNOWN:
2685 case FP_MODE_NONE:
2686 gcc_unreachable ();
2689 emit_move_insn (ctrl, scratch);
2690 if (!epiphany_uninterruptible_p (current_function_decl))
2691 emit_insn (gen_gie ());
2694 void
2695 epiphany_insert_mode_switch_use (rtx insn,
2696 int entity ATTRIBUTE_UNUSED,
2697 int mode ATTRIBUTE_UNUSED)
2699 rtx pat = PATTERN (insn);
2700 rtvec v;
2701 int len, i;
2702 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2703 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2705 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2706 return;
2707 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2709 case FP_MODE_ROUND_NEAREST:
2710 near = gen_rtx_USE (VOIDmode, near);
2711 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2712 break;
2713 case FP_MODE_ROUND_TRUNC:
2714 near = gen_rtx_CLOBBER (VOIDmode, near);
2715 trunc = gen_rtx_USE (VOIDmode, trunc);
2716 break;
2717 case FP_MODE_ROUND_UNKNOWN:
2718 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2719 trunc = copy_rtx (near);
2720 /* Fall through. */
2721 case FP_MODE_INT:
2722 case FP_MODE_CALLER:
2723 near = gen_rtx_USE (VOIDmode, near);
2724 trunc = gen_rtx_USE (VOIDmode, trunc);
2725 break;
2726 case FP_MODE_NONE:
2727 gcc_unreachable ();
2729 gcc_assert (GET_CODE (pat) == PARALLEL);
2730 len = XVECLEN (pat, 0);
2731 v = rtvec_alloc (len + 2);
2732 for (i = 0; i < len; i++)
2733 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2734 RTVEC_ELT (v, len) = near;
2735 RTVEC_ELT (v, len + 1) = trunc;
2736 pat = gen_rtx_PARALLEL (VOIDmode, v);
2737 PATTERN (insn) = pat;
2738 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2741 bool
2742 epiphany_epilogue_uses (int regno)
2744 if (regno == GPR_LR)
2745 return true;
2746 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2748 if (fixed_regs[regno]
2749 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2750 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2751 return false;
2752 return true;
2754 if (regno == FP_NEAREST_REGNUM
2755 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2756 return true;
2757 if (regno == FP_TRUNCATE_REGNUM
2758 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2759 return true;
2760 return false;
2763 static unsigned int
2764 epiphany_min_divisions_for_recip_mul (enum machine_mode mode)
2766 if (flag_reciprocal_math && mode == SFmode)
2767 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2768 it already at the tree level and expose it to further optimizations. */
2769 return 1;
2770 return default_min_divisions_for_recip_mul (mode);
2773 static enum machine_mode
2774 epiphany_preferred_simd_mode (enum machine_mode mode ATTRIBUTE_UNUSED)
2776 return TARGET_VECT_DOUBLE ? DImode : SImode;
2779 static bool
2780 epiphany_vector_mode_supported_p (enum machine_mode mode)
2782 if (mode == V2SFmode)
2783 return true;
2784 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2785 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2786 return true;
2787 return false;
2790 static bool
2791 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2793 /* Vectors which aren't in packed structures will not be less aligned than
2794 the natural alignment of their element type, so this is safe. */
2795 if (TYPE_ALIGN_UNIT (type) == 4)
2796 return !is_packed;
2798 return default_builtin_vector_alignment_reachable (type, is_packed);
2801 static bool
2802 epiphany_support_vector_misalignment (enum machine_mode mode, const_tree type,
2803 int misalignment, bool is_packed)
2805 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2806 return true;
2807 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2808 is_packed);
2811 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2812 structs. Make structs double-word-aligned it they are a double word or
2813 (potentially) larger; failing that, do the same for a size of 32 bits. */
2814 unsigned
2815 epiphany_special_round_type_align (tree type, unsigned computed,
2816 unsigned specified)
2818 unsigned align = MAX (computed, specified);
2819 tree field;
2820 HOST_WIDE_INT total, max;
2821 unsigned try_align = FASTEST_ALIGNMENT;
2823 if (maximum_field_alignment && try_align > maximum_field_alignment)
2824 try_align = maximum_field_alignment;
2825 if (align >= try_align)
2826 return align;
2827 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2829 tree offset, size;
2831 if (TREE_CODE (field) != FIELD_DECL
2832 || TREE_TYPE (field) == error_mark_node)
2833 continue;
2834 offset = bit_position (field);
2835 size = DECL_SIZE (field);
2836 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
2837 || tree_to_uhwi (offset) >= try_align
2838 || tree_to_uhwi (size) >= try_align)
2839 return try_align;
2840 total = tree_to_uhwi (offset) + tree_to_uhwi (size);
2841 if (total > max)
2842 max = total;
2844 if (max >= (HOST_WIDE_INT) try_align)
2845 align = try_align;
2846 else if (try_align > 32 && max >= 32)
2847 align = max > 32 ? 64 : 32;
2848 return align;
2851 /* Upping the alignment of arrays in structs is not only a performance
2852 enhancement, it also helps preserve assumptions about how
2853 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2854 libgcov.c . */
2855 unsigned
2856 epiphany_adjust_field_align (tree field, unsigned computed)
2858 if (computed == 32
2859 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
2861 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field)));
2863 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
2864 return 64;
2866 return computed;
2869 /* Output code to add DELTA to the first argument, and then jump
2870 to FUNCTION. Used for C++ multiple inheritance. */
2871 static void
2872 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2873 HOST_WIDE_INT delta,
2874 HOST_WIDE_INT vcall_offset,
2875 tree function)
2877 int this_regno
2878 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2879 const char *this_name = reg_names[this_regno];
2880 const char *fname;
2882 /* We use IP and R16 as a scratch registers. */
2883 gcc_assert (call_used_regs [GPR_IP]);
2884 gcc_assert (call_used_regs [GPR_16]);
2886 /* Add DELTA. When possible use a plain add, otherwise load it into
2887 a register first. */
2888 if (delta == 0)
2889 ; /* Done. */
2890 else if (SIMM11 (delta))
2891 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2892 else if (delta < 0 && delta >= -0xffff)
2894 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2895 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2897 else
2899 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2900 if (delta & ~0xffff)
2901 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2902 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2905 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2906 if (vcall_offset != 0)
2908 /* ldr ip,[this] --> temp = *this
2909 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2910 add this,this,ip --> this+ = *(*this + vcall_offset) */
2911 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2912 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2913 || (vcall_offset & 3) != 0)
2915 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2916 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2917 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2919 else
2920 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2921 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2924 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2925 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2927 fputs ("\tmov\tip,%low(", file);
2928 assemble_name (file, fname);
2929 fputs (")\n\tmovt\tip,%high(", file);
2930 assemble_name (file, fname);
2931 fputs (")\n\tjr ip\n", file);
2933 else
2935 fputs ("\tb\t", file);
2936 assemble_name (file, fname);
2937 fputc ('\n', file);
2941 void
2942 epiphany_start_function (FILE *file, const char *name, tree decl)
2944 /* If the function doesn't fit into the on-chip memory, it will have a
2945 section attribute - or lack of it - that denotes it goes somewhere else.
2946 But the architecture spec says that an interrupt vector still has to
2947 point to on-chip memory. So we must place a jump there to get to the
2948 actual function implementation. The forwarder_section attribute
2949 specifies the section where this jump goes.
2950 This mechanism can also be useful to have a shortcall destination for
2951 a function that is actually placed much farther away. */
2952 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2954 attrs = DECL_ATTRIBUTES (decl);
2955 int_attr = lookup_attribute ("interrupt", attrs);
2956 if (int_attr)
2957 for (int_names = TREE_VALUE (int_attr); int_names;
2958 int_names = TREE_CHAIN (int_names))
2960 char buf[99];
2962 int_name = TREE_VALUE (int_names);
2963 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2964 switch_to_section (get_section (buf, SECTION_CODE, decl));
2965 fputs ("\tb\t", file);
2966 assemble_name (file, name);
2967 fputc ('\n', file);
2969 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2970 if (forwarder_attr)
2972 const char *prefix = "__forwarder_dst_";
2973 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2975 strcpy (dst_name, prefix);
2976 strcat (dst_name, name);
2977 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2978 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2979 SECTION_CODE, decl));
2980 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2981 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2983 int tmp = GPR_0;
2985 if (int_attr)
2986 fputs ("\tstrd r0,[sp,-1]\n", file);
2987 else
2988 tmp = GPR_16;
2989 gcc_assert (call_used_regs[tmp]);
2990 fprintf (file, "\tmov r%d,%%low(", tmp);
2991 assemble_name (file, dst_name);
2992 fprintf (file, ")\n"
2993 "\tmovt r%d,%%high(", tmp);
2994 assemble_name (file, dst_name);
2995 fprintf (file, ")\n"
2996 "\tjr r%d\n", tmp);
2998 else
3000 fputs ("\tb\t", file);
3001 assemble_name (file, dst_name);
3002 fputc ('\n', file);
3004 name = dst_name;
3006 switch_to_section (function_section (decl));
3007 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
3010 struct gcc_target targetm = TARGET_INITIALIZER;