[2/77] Add an E_ prefix to case statements
[official-gcc.git] / gcc / config / epiphany / epiphany.c
bloba35c00173961c85463bfd66e135f27b495c36075
1 /* Subroutines used for code generation on the EPIPHANY cpu.
2 Copyright (C) 1994-2017 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 "backend.h"
25 #include "target.h"
26 #include "rtl.h"
27 #include "tree.h"
28 #include "df.h"
29 #include "memmodel.h"
30 #include "tm_p.h"
31 #include "stringpool.h"
32 #include "attribs.h"
33 #include "optabs.h"
34 #include "emit-rtl.h"
35 #include "recog.h"
36 #include "diagnostic-core.h"
37 #include "alias.h"
38 #include "stor-layout.h"
39 #include "varasm.h"
40 #include "calls.h"
41 #include "output.h"
42 #include "insn-attr.h"
43 #include "explow.h"
44 #include "expr.h"
45 #include "tm-constrs.h"
46 #include "tree-pass.h" /* for current_pass */
47 #include "context.h"
48 #include "pass_manager.h"
49 #include "builtins.h"
51 /* Which cpu we're compiling for. */
52 int epiphany_cpu_type;
54 /* Name of mangle string to add to symbols to separate code compiled for each
55 cpu (or NULL). */
56 const char *epiphany_mangle_cpu;
58 /* Array of valid operand punctuation characters. */
59 char epiphany_punct_chars[256];
61 /* The rounding mode that we generally use for floating point. */
62 int epiphany_normal_fp_rounding;
64 /* The pass instance, for use in epiphany_optimize_mode_switching. */
65 static opt_pass *pass_mode_switch_use;
67 static void epiphany_init_reg_tables (void);
68 static int get_epiphany_condition_code (rtx);
69 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
70 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
71 bool *);
72 static bool epiphany_pass_by_reference (cumulative_args_t, machine_mode,
73 const_tree, bool);
74 static rtx_insn *frame_insn (rtx);
76 /* defines for the initialization of the GCC target structure. */
77 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
79 #define TARGET_PRINT_OPERAND epiphany_print_operand
80 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
82 #define TARGET_RTX_COSTS epiphany_rtx_costs
83 #define TARGET_ADDRESS_COST epiphany_address_cost
84 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
86 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
87 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
89 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
90 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
91 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
92 #define TARGET_FUNCTION_VALUE epiphany_function_value
93 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
94 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
96 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
98 /* Using the simplistic varags handling forces us to do partial reg/stack
99 argument passing for types with larger size (> 4 bytes) than alignment. */
100 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
102 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
104 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
105 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
107 #define TARGET_LRA_P hook_bool_void_false
109 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
111 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
113 #define TARGET_OPTION_OVERRIDE epiphany_override_options
115 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
117 #define TARGET_FUNCTION_ARG epiphany_function_arg
119 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
121 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
123 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
125 /* Nonzero if the constant rtx value is a legitimate general operand.
126 We can handle any 32- or 64-bit constant. */
127 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
129 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
130 epiphany_min_divisions_for_recip_mul
132 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
134 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
136 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
137 epiphany_vector_alignment_reachable
139 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
140 epiphany_support_vector_misalignment
142 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
143 hook_bool_const_tree_hwi_hwi_const_tree_true
144 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
146 /* ??? we can use larger offsets for wider-mode sized accesses, but there
147 is no concept of anchors being dependent on the modes that they are used
148 for, so we can only use an offset range that would suit all modes. */
149 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047)
150 /* We further restrict the minimum to be a multiple of eight. */
151 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040)
153 /* Mode switching hooks. */
155 #define TARGET_MODE_EMIT emit_set_fp_mode
157 #define TARGET_MODE_NEEDED epiphany_mode_needed
159 #define TARGET_MODE_PRIORITY epiphany_mode_priority
161 #define TARGET_MODE_ENTRY epiphany_mode_entry
163 #define TARGET_MODE_EXIT epiphany_mode_exit
165 #define TARGET_MODE_AFTER epiphany_mode_after
167 #include "target-def.h"
169 #undef TARGET_ASM_ALIGNED_HI_OP
170 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
171 #undef TARGET_ASM_ALIGNED_SI_OP
172 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
174 bool
175 epiphany_is_interrupt_p (tree decl)
177 tree attrs;
179 attrs = DECL_ATTRIBUTES (decl);
180 if (lookup_attribute ("interrupt", attrs))
181 return true;
182 else
183 return false;
186 /* Called from epiphany_override_options.
187 We use this to initialize various things. */
189 static void
190 epiphany_init (void)
192 /* N.B. this pass must not run before the first optimize_mode_switching
193 pass because of the side offect of epiphany_mode_needed on
194 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
195 pass_resolve_sw_modes. */
196 pass_mode_switch_use = make_pass_mode_switch_use (g);
197 struct register_pass_info insert_use_info
198 = { pass_mode_switch_use, "mode_sw",
199 1, PASS_POS_INSERT_AFTER
201 opt_pass *mode_sw2
202 = g->get_passes()->get_pass_mode_switching ()->clone ();
203 struct register_pass_info mode_sw2_info
204 = { mode_sw2, "mode_sw",
205 1, PASS_POS_INSERT_AFTER
207 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g);
208 struct register_pass_info mode_sw3_info
209 = { mode_sw3, "mode_sw",
210 1, PASS_POS_INSERT_AFTER
212 opt_pass *mode_sw4
213 = g->get_passes()->get_pass_split_all_insns ()->clone ();
214 struct register_pass_info mode_sw4_info
215 = { mode_sw4, "mode_sw",
216 1, PASS_POS_INSERT_AFTER
218 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
219 #define N_ENTITIES ARRAY_SIZE (num_modes)
221 epiphany_init_reg_tables ();
223 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
224 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
225 epiphany_punct_chars['-'] = 1;
227 epiphany_normal_fp_rounding
228 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
229 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
230 register_pass (&mode_sw4_info);
231 register_pass (&mode_sw2_info);
232 register_pass (&mode_sw3_info);
233 register_pass (&insert_use_info);
234 register_pass (&mode_sw2_info);
235 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
236 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
238 #if 1 /* As long as peep2_rescan is not implemented,
239 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
240 we need a second peephole2 pass to get reasonable code. */
242 opt_pass *extra_peephole2
243 = g->get_passes ()->get_pass_peephole2 ()->clone ();
244 struct register_pass_info peep2_2_info
245 = { extra_peephole2, "peephole2",
246 1, PASS_POS_INSERT_AFTER
249 register_pass (&peep2_2_info);
251 #endif
254 /* The condition codes of the EPIPHANY, and the inverse function. */
255 static const char *const epiphany_condition_codes[] =
256 { /* 0 1 2 3 4 5 6 7 8 9 */
257 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
258 /* 10 11 12 13 */
259 "beq","bne","blt", "blte",
262 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
264 /* Returns the index of the EPIPHANY condition code string in
265 `epiphany_condition_codes'. COMPARISON should be an rtx like
266 `(eq (...) (...))'. */
268 static int
269 get_epiphany_condition_code (rtx comparison)
271 switch (GET_MODE (XEXP (comparison, 0)))
273 case E_CCmode:
274 switch (GET_CODE (comparison))
276 case EQ : return 0;
277 case NE : return 1;
278 case LTU : return 2;
279 case GEU : return 3;
280 case GT : return 4;
281 case LE : return 5;
282 case GE : return 6;
283 case LT : return 7;
284 case GTU : return 8;
285 case LEU : return 9;
287 default : gcc_unreachable ();
289 case E_CC_N_NEmode:
290 switch (GET_CODE (comparison))
292 case EQ: return 6;
293 case NE: return 7;
294 default: gcc_unreachable ();
296 case E_CC_C_LTUmode:
297 switch (GET_CODE (comparison))
299 case GEU: return 2;
300 case LTU: return 3;
301 default: gcc_unreachable ();
303 case E_CC_C_GTUmode:
304 switch (GET_CODE (comparison))
306 case LEU: return 3;
307 case GTU: return 2;
308 default: gcc_unreachable ();
310 case E_CC_FPmode:
311 switch (GET_CODE (comparison))
313 case EQ: return 10;
314 case NE: return 11;
315 case LT: return 12;
316 case LE: return 13;
317 default: gcc_unreachable ();
319 case E_CC_FP_EQmode:
320 switch (GET_CODE (comparison))
322 case EQ: return 0;
323 case NE: return 1;
324 default: gcc_unreachable ();
326 case E_CC_FP_GTEmode:
327 switch (GET_CODE (comparison))
329 case EQ: return 0;
330 case NE: return 1;
331 case GT : return 4;
332 case GE : return 6;
333 case UNLE : return 5;
334 case UNLT : return 7;
335 default: gcc_unreachable ();
337 case E_CC_FP_ORDmode:
338 switch (GET_CODE (comparison))
340 case ORDERED: return 9;
341 case UNORDERED: return 8;
342 default: gcc_unreachable ();
344 case E_CC_FP_UNEQmode:
345 switch (GET_CODE (comparison))
347 case UNEQ: return 9;
348 case LTGT: return 8;
349 default: gcc_unreachable ();
351 default: gcc_unreachable ();
353 /*NOTREACHED*/
354 return (42);
358 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
360 hard_regno_mode_ok (int regno, machine_mode mode)
362 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
363 return (regno & 1) == 0 && GPR_P (regno);
364 else
365 return 1;
368 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
369 return the mode to be used for the comparison. */
371 machine_mode
372 epiphany_select_cc_mode (enum rtx_code op,
373 rtx x ATTRIBUTE_UNUSED,
374 rtx y ATTRIBUTE_UNUSED)
376 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
378 if (TARGET_SOFT_CMPSF
379 || op == ORDERED || op == UNORDERED)
381 if (op == EQ || op == NE)
382 return CC_FP_EQmode;
383 if (op == ORDERED || op == UNORDERED)
384 return CC_FP_ORDmode;
385 if (op == UNEQ || op == LTGT)
386 return CC_FP_UNEQmode;
387 return CC_FP_GTEmode;
389 return CC_FPmode;
391 /* recognize combiner pattern ashlsi_btst:
392 (parallel [
393 (set (reg:N_NE 65 cc1)
394 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
395 (const_int 1 [0x1])
396 (const_int 0 [0x0]))
397 (const_int 0 [0x0])))
398 (clobber (scratch:SI)) */
399 else if ((op == EQ || op == NE)
400 && GET_CODE (x) == ZERO_EXTRACT
401 && XEXP (x, 1) == const1_rtx
402 && CONST_INT_P (XEXP (x, 2)))
403 return CC_N_NEmode;
404 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
405 return CC_C_LTUmode;
406 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
407 return CC_C_GTUmode;
408 else
409 return CCmode;
412 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
414 static void
415 epiphany_init_reg_tables (void)
417 int i;
419 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
421 if (i == GPR_LR)
422 epiphany_regno_reg_class[i] = LR_REGS;
423 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
424 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
425 else if (call_used_regs[i]
426 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
427 epiphany_regno_reg_class[i] = SIBCALL_REGS;
428 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
429 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
430 else if (i < (GPR_LAST+1)
431 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
432 epiphany_regno_reg_class[i] = GENERAL_REGS;
433 else if (i == CC_REGNUM)
434 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
435 else
436 epiphany_regno_reg_class[i] = NO_REGS;
440 /* EPIPHANY specific attribute support.
442 The EPIPHANY has these attributes:
443 interrupt - for interrupt functions.
444 short_call - the function is assumed to be reachable with the b / bl
445 instructions.
446 long_call - the function address is loaded into a register before use.
447 disinterrupt - functions which mask interrupts throughout.
448 They unmask them while calling an interruptible
449 function, though. */
451 static const struct attribute_spec epiphany_attribute_table[] =
453 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
454 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
455 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
456 { "long_call", 0, 0, false, true, true, NULL, false },
457 { "short_call", 0, 0, false, true, true, NULL, false },
458 { "disinterrupt", 0, 0, false, true, true, NULL, true },
459 { NULL, 0, 0, false, false, false, NULL, false }
462 /* Handle an "interrupt" attribute; arguments as in
463 struct attribute_spec.handler. */
464 static tree
465 epiphany_handle_interrupt_attribute (tree *node, tree name, tree args,
466 int flags ATTRIBUTE_UNUSED,
467 bool *no_add_attrs)
469 tree value;
471 if (!args)
473 gcc_assert (DECL_P (*node));
474 tree t = TREE_TYPE (*node);
475 if (TREE_CODE (t) != FUNCTION_TYPE)
476 warning (OPT_Wattributes, "%qE attribute only applies to functions",
477 name);
478 /* Argument handling and the stack layout for interrupt handlers
479 don't mix. It makes no sense in the first place, so emit an
480 error for this. */
481 else if (TYPE_ARG_TYPES (t)
482 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node)
483 error_at (DECL_SOURCE_LOCATION (*node),
484 "interrupt handlers cannot have arguments");
485 return NULL_TREE;
488 value = TREE_VALUE (args);
490 if (TREE_CODE (value) != STRING_CST)
492 warning (OPT_Wattributes,
493 "argument of %qE attribute is not a string constant", name);
494 *no_add_attrs = true;
496 else if (strcmp (TREE_STRING_POINTER (value), "reset")
497 && strcmp (TREE_STRING_POINTER (value), "software_exception")
498 && strcmp (TREE_STRING_POINTER (value), "page_miss")
499 && strcmp (TREE_STRING_POINTER (value), "timer0")
500 && strcmp (TREE_STRING_POINTER (value), "timer1")
501 && strcmp (TREE_STRING_POINTER (value), "message")
502 && strcmp (TREE_STRING_POINTER (value), "dma0")
503 && strcmp (TREE_STRING_POINTER (value), "dma1")
504 && strcmp (TREE_STRING_POINTER (value), "wand")
505 && strcmp (TREE_STRING_POINTER (value), "swi"))
507 warning (OPT_Wattributes,
508 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
509 name);
510 *no_add_attrs = true;
511 return NULL_TREE;
514 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
515 flags, no_add_attrs);
518 /* Handle a "forwarder_section" attribute; arguments as in
519 struct attribute_spec.handler. */
520 static tree
521 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
522 tree name, tree args,
523 int flags ATTRIBUTE_UNUSED,
524 bool *no_add_attrs)
526 tree value;
528 value = TREE_VALUE (args);
530 if (TREE_CODE (value) != STRING_CST)
532 warning (OPT_Wattributes,
533 "argument of %qE attribute is not a string constant", name);
534 *no_add_attrs = true;
536 return NULL_TREE;
540 /* Misc. utilities. */
542 /* Generate a SYMBOL_REF for the special function NAME. When the address
543 can't be placed directly into a call instruction, and if possible, copy
544 it to a register so that cse / code hoisting is possible. */
546 sfunc_symbol (const char *name)
548 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
550 /* These sfuncs should be hidden, and every dso should get a copy. */
551 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
552 if (TARGET_SHORT_CALLS)
553 ; /* Nothing to be done. */
554 else if (can_create_pseudo_p ())
555 sym = copy_to_mode_reg (Pmode, sym);
556 else /* We rely on reload to fix this up. */
557 gcc_assert (!reload_in_progress || reload_completed);
558 return sym;
561 /* X and Y are two things to compare using CODE in IN_MODE.
562 Emit the compare insn, construct the proper cc reg in the proper
563 mode, and return the rtx for the cc reg comparison in CMODE. */
566 gen_compare_reg (machine_mode cmode, enum rtx_code code,
567 machine_mode in_mode, rtx x, rtx y)
569 machine_mode mode = SELECT_CC_MODE (code, x, y);
570 rtx cc_reg, pat, clob0, clob1, clob2;
572 if (in_mode == VOIDmode)
573 in_mode = GET_MODE (x);
574 if (in_mode == VOIDmode)
575 in_mode = GET_MODE (y);
577 if (mode == CC_FPmode)
579 /* The epiphany has only EQ / NE / LT / LE conditions for
580 hardware floating point. */
581 if (code == GT || code == GE || code == UNLE || code == UNLT)
583 rtx tmp = x; x = y; y = tmp;
584 code = swap_condition (code);
586 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
587 y = force_reg (in_mode, y);
589 else
591 if (mode == CC_FP_GTEmode
592 && (code == LE || code == LT || code == UNGT || code == UNGE))
594 if (flag_finite_math_only
595 && ((REG_P (x) && REGNO (x) == GPR_0)
596 || (REG_P (y) && REGNO (y) == GPR_1)))
597 switch (code)
599 case LE: code = UNLE; break;
600 case LT: code = UNLT; break;
601 case UNGT: code = GT; break;
602 case UNGE: code = GE; break;
603 default: gcc_unreachable ();
605 else
607 rtx tmp = x; x = y; y = tmp;
608 code = swap_condition (code);
611 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
613 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
614 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
615 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
616 && (!REG_P (x) || REGNO (x) != GPR_0
617 || !REG_P (y) || REGNO (y) != GPR_1))
619 rtx reg;
621 #if 0
622 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
623 but just like the flag clobber of movsicc, we have to allow
624 this for ifcvt to work, on the assumption that we'll only want
625 to do this if these registers have been used before by the
626 pre-ifcvt code. */
627 gcc_assert (currently_expanding_to_rtl);
628 #endif
629 reg = gen_rtx_REG (in_mode, GPR_0);
630 if (reg_overlap_mentioned_p (reg, y))
631 return 0;
632 emit_move_insn (reg, x);
633 x = reg;
634 reg = gen_rtx_REG (in_mode, GPR_1);
635 emit_move_insn (reg, y);
636 y = reg;
638 else
639 x = force_reg (in_mode, x);
641 pat = gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y));
642 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
644 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
645 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
647 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
648 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
649 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
651 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
653 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
654 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
656 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
657 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
658 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
659 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
660 clob0, clob1, clob2));
662 else
664 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
665 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
667 emit_insn (pat);
668 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
671 /* The ROUND_ADVANCE* macros are local to this file. */
672 /* Round SIZE up to a word boundary. */
673 #define ROUND_ADVANCE(SIZE) \
674 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
676 /* Round arg MODE/TYPE up to the next word boundary. */
677 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
678 ((MODE) == BLKmode \
679 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
680 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
682 /* Round CUM up to the necessary point for argument MODE/TYPE. */
683 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
684 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
685 ? (((CUM) + 1) & ~1) \
686 : (CUM))
688 static unsigned int
689 epiphany_function_arg_boundary (machine_mode mode, const_tree type)
691 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
692 return PARM_BOUNDARY;
693 return 2 * PARM_BOUNDARY;
696 /* Do any needed setup for a variadic function. For the EPIPHANY, we
697 actually emit the code in epiphany_expand_prologue.
699 CUM has not been updated for the last named argument which has type TYPE
700 and mode MODE, and we rely on this fact. */
703 static void
704 epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
705 tree type, int *pretend_size, int no_rtl)
707 int first_anon_arg;
708 CUMULATIVE_ARGS next_cum;
709 machine_function_t *mf = MACHINE_FUNCTION (cfun);
711 /* All BLKmode values are passed by reference. */
712 gcc_assert (mode != BLKmode);
714 next_cum = *get_cumulative_args (cum);
715 next_cum
716 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
717 first_anon_arg = next_cum;
719 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
721 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
722 int first_reg_offset = first_anon_arg;
724 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
725 * UNITS_PER_WORD);
727 mf->args_parsed = 1;
728 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
731 static int
732 epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
733 tree type, bool named ATTRIBUTE_UNUSED)
735 int words = 0, rounded_cum;
737 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
739 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
740 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
742 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
743 if (words >= ROUND_ADVANCE_ARG (mode, type))
744 words = 0;
746 return words * UNITS_PER_WORD;
749 /* Cost functions. */
751 /* Compute a (partial) cost for rtx X. Return true if the complete
752 cost has been computed, and false if subexpressions should be
753 scanned. In either case, *TOTAL contains the cost result. */
755 static bool
756 epiphany_rtx_costs (rtx x, machine_mode mode, int outer_code,
757 int opno ATTRIBUTE_UNUSED,
758 int *total, bool speed ATTRIBUTE_UNUSED)
760 int code = GET_CODE (x);
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 (mode)
804 /* There are a number of single-insn combiner patterns that use
805 the flag side effects of arithmetic. */
806 case E_CC_N_NEmode:
807 case E_CC_C_LTUmode:
808 case E_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, 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 (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 (GET_MODE (x), 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 (GET_MODE (x), 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 long l;
1354 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l);
1355 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1356 break;
1358 /* FALLTHRU */
1359 /* Let output_addr_const deal with it. */
1360 case CONST_INT:
1361 fprintf(file,"%s",IMMEDIATE_PREFIX);
1362 if (code == 'C' || code == 'X')
1364 fprintf (file, "%ld",
1365 (long) (INTVAL (x) / current_frame_info.stld_sz));
1366 break;
1368 /* Fall through */
1369 default :
1370 output_addr_const (file, x);
1371 break;
1375 /* Print a memory address as an operand to reference that memory location. */
1377 static void
1378 epiphany_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr)
1380 register rtx base, index = 0;
1381 int offset = 0;
1383 switch (GET_CODE (addr))
1385 case REG :
1386 fputs (reg_names[REGNO (addr)], file);
1387 break;
1388 case SYMBOL_REF :
1389 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1391 output_addr_const (file, addr);
1393 else
1395 output_addr_const (file, addr);
1397 break;
1398 case PLUS :
1399 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1400 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1401 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1402 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1403 else
1404 base = XEXP (addr, 0), index = XEXP (addr, 1);
1405 gcc_assert (GET_CODE (base) == REG);
1406 fputs (reg_names[REGNO (base)], file);
1407 if (index == 0)
1410 ** ++rk quirky method to scale offset for ld/str.......
1412 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1413 offset/current_frame_info.stld_sz);
1415 else
1417 switch (GET_CODE (index))
1419 case REG:
1420 fprintf (file, ",%s", reg_names[REGNO (index)]);
1421 break;
1422 case SYMBOL_REF:
1423 fputc (',', file), output_addr_const (file, index);
1424 break;
1425 default:
1426 gcc_unreachable ();
1429 break;
1430 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1431 /* We shouldn't get here as we've lost the mode of the memory object
1432 (which says how much to inc/dec by.
1433 FIXME: We have the mode now, address printing can be moved into this
1434 function. */
1435 gcc_unreachable ();
1436 break;
1437 default:
1438 output_addr_const (file, addr);
1439 break;
1443 void
1444 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED,
1445 rtx *opvec ATTRIBUTE_UNUSED,
1446 int noperands ATTRIBUTE_UNUSED)
1448 int i = epiphany_n_nops;
1449 rtx pat ATTRIBUTE_UNUSED;
1451 while (i--)
1452 fputs ("\tnop\n", asm_out_file);
1456 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1458 static bool
1459 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1461 HOST_WIDE_INT size = int_size_in_bytes (type);
1463 if (AGGREGATE_TYPE_P (type)
1464 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1465 return true;
1466 return (size == -1 || size > 8);
1469 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1470 passed by reference. */
1472 static bool
1473 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1474 machine_mode mode, const_tree type,
1475 bool named ATTRIBUTE_UNUSED)
1477 if (type)
1479 if (AGGREGATE_TYPE_P (type)
1480 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1481 return true;
1483 return false;
1487 static rtx
1488 epiphany_function_value (const_tree ret_type,
1489 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1490 bool outgoing ATTRIBUTE_UNUSED)
1492 machine_mode mode;
1494 mode = TYPE_MODE (ret_type);
1495 /* We must change the mode like PROMOTE_MODE does.
1496 ??? PROMOTE_MODE is ignored for non-scalar types.
1497 The set of types tested here has to be kept in sync
1498 with the one in explow.c:promote_mode. */
1499 if (GET_MODE_CLASS (mode) == MODE_INT
1500 && GET_MODE_SIZE (mode) < 4
1501 && (TREE_CODE (ret_type) == INTEGER_TYPE
1502 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1503 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1504 || TREE_CODE (ret_type) == OFFSET_TYPE))
1505 mode = SImode;
1506 return gen_rtx_REG (mode, 0);
1509 static rtx
1510 epiphany_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1512 return gen_rtx_REG (mode, 0);
1515 static bool
1516 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1518 return regno == 0;
1521 /* Fix up invalid option settings. */
1522 static void
1523 epiphany_override_options (void)
1525 if (epiphany_stack_offset < 4)
1526 error ("stack_offset must be at least 4");
1527 if (epiphany_stack_offset & 3)
1528 error ("stack_offset must be a multiple of 4");
1529 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1530 if (!TARGET_SOFT_CMPSF)
1531 flag_finite_math_only = 1;
1533 /* This needs to be done at start up. It's convenient to do it here. */
1534 epiphany_init ();
1537 /* For a DImode load / store SET, make a SImode set for a
1538 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1539 subreg. */
1540 static rtx
1541 frame_subreg_note (rtx set, int offset)
1543 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1544 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1546 set = gen_rtx_SET (dst ,src);
1547 RTX_FRAME_RELATED_P (set) = 1;
1548 return set;
1551 static rtx_insn *
1552 frame_insn (rtx x)
1554 int i;
1555 rtx note = NULL_RTX;
1556 rtx_insn *insn;
1558 if (GET_CODE (x) == PARALLEL)
1560 rtx part = XVECEXP (x, 0, 0);
1562 if (GET_MODE (SET_DEST (part)) == DImode)
1564 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1565 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1566 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1567 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1569 part = copy_rtx (XVECEXP (x, 0, i));
1571 if (GET_CODE (part) == SET)
1572 RTX_FRAME_RELATED_P (part) = 1;
1573 XVECEXP (note, 0, i + 1) = part;
1576 else
1578 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1580 part = XVECEXP (x, 0, i);
1582 if (GET_CODE (part) == SET)
1583 RTX_FRAME_RELATED_P (part) = 1;
1587 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1588 note = gen_rtx_PARALLEL (VOIDmode,
1589 gen_rtvec (2, frame_subreg_note (x, 0),
1590 frame_subreg_note (x, UNITS_PER_WORD)));
1591 insn = emit_insn (x);
1592 RTX_FRAME_RELATED_P (insn) = 1;
1593 if (note)
1594 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1595 return insn;
1598 static rtx_insn *
1599 frame_move_insn (rtx to, rtx from)
1601 return frame_insn (gen_rtx_SET (to, from));
1604 /* Generate a MEM referring to a varargs argument slot. */
1606 static rtx
1607 gen_varargs_mem (machine_mode mode, rtx addr)
1609 rtx mem = gen_rtx_MEM (mode, addr);
1610 MEM_NOTRAP_P (mem) = 1;
1611 set_mem_alias_set (mem, get_varargs_alias_set ());
1612 return mem;
1615 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1616 If EPILOGUE_P is 0, save; if it is one, restore.
1617 ADDR is the stack slot to save the first register to; subsequent
1618 registers are written to lower addresses.
1619 However, the order of register pairs can be reversed in order to
1620 use double-word load-store instructions. Likewise, an unpaired single
1621 word save slot can be skipped while double saves are carried out, and
1622 reused when a single register is to be saved. */
1624 static void
1625 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1627 int i;
1628 int stack_offset
1629 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1630 rtx skipped_mem = NULL_RTX;
1631 int last_saved = limit - 1;
1633 if (!optimize)
1634 while (last_saved >= 0
1635 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1636 last_saved--;
1637 for (i = 0; i < limit; i++)
1639 machine_mode mode = word_mode;
1640 rtx mem, reg;
1641 int n = i;
1642 rtx (*gen_mem) (machine_mode, rtx) = gen_frame_mem;
1644 /* Make sure we push the arguments in the right order. */
1645 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1647 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1648 gen_mem = gen_varargs_mem;
1650 if (stack_offset == current_frame_info.first_slot_size
1651 && current_frame_info.first_slot >= 0)
1653 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1655 mode = DImode;
1656 addr = plus_constant (Pmode, addr,
1657 - (HOST_WIDE_INT) UNITS_PER_WORD);
1659 if (i-- < min || !epilogue_p)
1660 goto next_slot;
1661 n = current_frame_info.first_slot;
1662 gen_mem = gen_frame_mem;
1664 else if (n == UNKNOWN_REGNUM
1665 && stack_offset > current_frame_info.first_slot_size)
1667 i--;
1668 goto next_slot;
1670 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1671 continue;
1672 else if (i < min)
1673 goto next_slot;
1675 /* Check for a register pair to save. */
1676 if (n == i
1677 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1678 && (n & 1) == 0 && n+1 < limit
1679 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1681 /* If it fits in the current stack slot pair, place it there. */
1682 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1683 && stack_offset != 2 * UNITS_PER_WORD
1684 && (current_frame_info.last_slot < 0
1685 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1686 && (n+1 != last_saved || !skipped_mem))
1688 mode = DImode;
1689 i++;
1690 addr = plus_constant (Pmode, addr,
1691 - (HOST_WIDE_INT) UNITS_PER_WORD);
1693 /* If it fits in the following stack slot pair, that's fine, too. */
1694 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1695 && stack_offset != 2 * UNITS_PER_WORD
1696 && stack_offset != 3 * UNITS_PER_WORD
1697 && (current_frame_info.last_slot < 0
1698 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1699 && n + 1 != last_saved)
1701 gcc_assert (!skipped_mem);
1702 stack_offset -= GET_MODE_SIZE (mode);
1703 skipped_mem = gen_mem (mode, addr);
1704 mode = DImode;
1705 i++;
1706 addr = plus_constant (Pmode, addr,
1707 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1710 reg = gen_rtx_REG (mode, n);
1711 if (mode != DImode && skipped_mem)
1712 mem = skipped_mem;
1713 else
1714 mem = gen_mem (mode, addr);
1716 /* If we are loading / storing LR, note the offset that
1717 gen_reload_insi_ra requires. Since GPR_LR is even,
1718 we only need to test n, even if mode is DImode. */
1719 gcc_assert ((GPR_LR & 1) == 0);
1720 if (n == GPR_LR)
1722 long lr_slot_offset = 0;
1723 rtx m_addr = XEXP (mem, 0);
1725 if (GET_CODE (m_addr) == PLUS)
1726 lr_slot_offset = INTVAL (XEXP (m_addr, 1));
1727 if (frame_pointer_needed)
1728 lr_slot_offset += (current_frame_info.first_slot_offset
1729 - current_frame_info.total_size);
1730 if (MACHINE_FUNCTION (cfun)->lr_slot_known)
1731 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset
1732 == lr_slot_offset);
1733 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1734 MACHINE_FUNCTION (cfun)->lr_slot_known = 1;
1737 if (!epilogue_p)
1738 frame_move_insn (mem, reg);
1739 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1740 emit_move_insn (reg, mem);
1741 if (mem == skipped_mem)
1743 skipped_mem = NULL_RTX;
1744 continue;
1746 next_slot:
1747 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
1748 stack_offset -= GET_MODE_SIZE (mode);
1752 void
1753 epiphany_expand_prologue (void)
1755 int interrupt_p;
1756 enum epiphany_function_type fn_type;
1757 rtx addr, mem, off, reg;
1759 if (!current_frame_info.initialized)
1760 epiphany_compute_frame_size (get_frame_size ());
1762 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1763 if (flag_stack_usage_info)
1764 current_function_static_stack_size = current_frame_info.total_size;
1766 fn_type = epiphany_compute_function_type (current_function_decl);
1767 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1769 if (interrupt_p)
1771 addr = plus_constant (Pmode, stack_pointer_rtx,
1772 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1773 if (!lookup_attribute ("forwarder_section",
1774 DECL_ATTRIBUTES (current_function_decl))
1775 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1776 0)))
1777 frame_move_insn (gen_frame_mem (DImode, addr),
1778 gen_rtx_REG (DImode, GPR_0));
1779 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1780 gen_rtx_REG (word_mode, STATUS_REGNUM));
1781 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
1782 gen_rtx_REG (word_mode, IRET_REGNUM));
1783 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1784 off = GEN_INT (-current_frame_info.first_slot_offset);
1785 frame_insn (gen_stack_adjust_add (off, mem));
1786 if (!epiphany_uninterruptible_p (current_function_decl))
1787 emit_insn (gen_gie ());
1788 addr = plus_constant (Pmode, stack_pointer_rtx,
1789 current_frame_info.first_slot_offset
1790 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1792 else
1794 addr = plus_constant (Pmode, stack_pointer_rtx,
1795 epiphany_stack_offset
1796 - (HOST_WIDE_INT) UNITS_PER_WORD);
1797 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1798 addr, 0);
1799 /* Allocate register save area; for small to medium size frames,
1800 allocate the entire frame; this is joint with one register save. */
1801 if (current_frame_info.first_slot >= 0)
1803 machine_mode mode
1804 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1805 ? word_mode : DImode);
1807 off = GEN_INT (-current_frame_info.first_slot_offset);
1808 mem = gen_frame_mem (BLKmode,
1809 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1810 frame_insn (gen_stack_adjust_str
1811 (gen_frame_mem (mode, stack_pointer_rtx),
1812 gen_rtx_REG (mode, current_frame_info.first_slot),
1813 off, mem));
1814 addr = plus_constant (Pmode, addr,
1815 current_frame_info.first_slot_offset);
1818 epiphany_emit_save_restore (current_frame_info.small_threshold,
1819 FIRST_PSEUDO_REGISTER, addr, 0);
1820 if (current_frame_info.need_fp)
1821 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1822 /* For large frames, allocate bulk of frame. This is usually joint with one
1823 register save. */
1824 if (current_frame_info.last_slot >= 0)
1826 rtx ip, mem2, note;
1827 rtx_insn *insn;
1829 gcc_assert (current_frame_info.last_slot != GPR_FP
1830 || (!current_frame_info.need_fp
1831 && current_frame_info.first_slot < 0));
1832 off = GEN_INT (-current_frame_info.last_slot_offset);
1833 mem = gen_frame_mem (BLKmode,
1834 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1835 ip = gen_rtx_REG (Pmode, GPR_IP);
1836 frame_move_insn (ip, off);
1837 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1838 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1839 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1840 /* Instruction scheduling can separate the instruction setting IP from
1841 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1842 temporary register is. Example: _gcov.o */
1843 note = gen_rtx_SET (stack_pointer_rtx,
1844 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1845 note = gen_rtx_PARALLEL (VOIDmode,
1846 gen_rtvec (2, gen_rtx_SET (mem2, reg), note));
1847 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1849 /* If there is only one or no register to save, yet we have a large frame,
1850 use an add. */
1851 else if (current_frame_info.last_slot_offset)
1853 mem = gen_frame_mem (BLKmode,
1854 plus_constant (Pmode, stack_pointer_rtx,
1855 current_frame_info.last_slot_offset));
1856 off = GEN_INT (-current_frame_info.last_slot_offset);
1857 if (!SIMM11 (INTVAL (off)))
1859 reg = gen_rtx_REG (Pmode, GPR_IP);
1860 frame_move_insn (reg, off);
1861 off = reg;
1863 frame_insn (gen_stack_adjust_add (off, mem));
1867 void
1868 epiphany_expand_epilogue (int sibcall_p)
1870 int interrupt_p;
1871 enum epiphany_function_type fn_type;
1872 rtx mem, addr, reg, off;
1873 HOST_WIDE_INT restore_offset;
1875 fn_type = epiphany_compute_function_type( current_function_decl);
1876 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1878 /* For variable frames, deallocate bulk of frame. */
1879 if (current_frame_info.need_fp)
1881 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1882 emit_insn (gen_stack_adjust_mov (mem));
1884 /* Else for large static frames, deallocate bulk of frame. */
1885 else if (current_frame_info.last_slot_offset)
1887 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1888 reg = gen_rtx_REG (Pmode, GPR_IP);
1889 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1890 emit_insn (gen_stack_adjust_add (reg, mem));
1892 restore_offset = (interrupt_p
1893 ? - 3 * UNITS_PER_WORD
1894 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1895 addr = plus_constant (Pmode, stack_pointer_rtx,
1896 (current_frame_info.first_slot_offset
1897 + restore_offset));
1898 epiphany_emit_save_restore (current_frame_info.small_threshold,
1899 FIRST_PSEUDO_REGISTER, addr, 1);
1901 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1902 emit_insn (gen_gid ());
1904 off = GEN_INT (current_frame_info.first_slot_offset);
1905 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1906 /* For large / variable size frames, deallocating the register save area is
1907 joint with one register restore; for medium size frames, we use a
1908 dummy post-increment load to dealloacte the whole frame. */
1909 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1911 emit_insn (gen_stack_adjust_ldr
1912 (gen_rtx_REG (word_mode,
1913 (current_frame_info.last_slot >= 0
1914 ? current_frame_info.last_slot : GPR_IP)),
1915 gen_frame_mem (word_mode, stack_pointer_rtx),
1916 off,
1917 mem));
1919 /* While for small frames, we deallocate the entire frame with one add. */
1920 else if (INTVAL (off))
1922 emit_insn (gen_stack_adjust_add (off, mem));
1924 if (interrupt_p)
1926 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1927 gen_rtx_REG (SImode, GPR_0));
1928 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1929 gen_rtx_REG (SImode, GPR_1));
1930 addr = plus_constant (Pmode, stack_pointer_rtx,
1931 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1932 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1933 gen_frame_mem (DImode, addr));
1935 addr = plus_constant (Pmode, stack_pointer_rtx,
1936 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1937 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1938 if (!sibcall_p)
1940 if (interrupt_p)
1941 emit_jump_insn (gen_return_internal_interrupt());
1942 else
1943 emit_jump_insn (gen_return_i ());
1948 epiphany_initial_elimination_offset (int from, int to)
1950 epiphany_compute_frame_size (get_frame_size ());
1951 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1952 return current_frame_info.total_size - current_frame_info.reg_size;
1953 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1954 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1955 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1956 return (current_frame_info.total_size
1957 - ((current_frame_info.pretend_size + 4) & -8));
1958 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1959 return (current_frame_info.first_slot_offset
1960 - ((current_frame_info.pretend_size + 4) & -8));
1961 gcc_unreachable ();
1964 bool
1965 epiphany_regno_rename_ok (unsigned, unsigned dst)
1967 enum epiphany_function_type fn_type;
1969 fn_type = epiphany_compute_function_type (current_function_decl);
1970 if (!EPIPHANY_INTERRUPT_P (fn_type))
1971 return true;
1972 if (df_regs_ever_live_p (dst))
1973 return true;
1974 return false;
1977 static int
1978 epiphany_issue_rate (void)
1980 return 2;
1983 /* Function to update the integer COST
1984 based on the relationship between INSN that is dependent on
1985 DEP_INSN through the dependence LINK. The default is to make no
1986 adjustment to COST. This can be used for example to specify to
1987 the scheduler that an output- or anti-dependence does not incur
1988 the same cost as a data-dependence. The return value should be
1989 the new value for COST. */
1990 static int
1991 epiphany_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
1992 int cost, unsigned int)
1994 if (dep_type == 0)
1996 rtx dep_set;
1998 if (recog_memoized (insn) < 0
1999 || recog_memoized (dep_insn) < 0)
2000 return cost;
2002 dep_set = single_set (dep_insn);
2004 /* The latency that we specify in the scheduling description refers
2005 to the actual output, not to an auto-increment register; for that,
2006 the latency is one. */
2007 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
2009 rtx set = single_set (insn);
2011 if (set
2012 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
2013 && (!MEM_P (SET_DEST (set))
2014 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
2015 XEXP (SET_DEST (set), 0))))
2016 cost = 1;
2019 return cost;
2022 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
2024 #define RTX_OK_FOR_BASE_P(X) \
2025 (REG_P (X) && REG_OK_FOR_BASE_P (X))
2027 #define RTX_OK_FOR_INDEX_P(MODE, X) \
2028 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
2029 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
2030 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
2032 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
2033 (GET_CODE (X) == PLUS \
2034 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
2035 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
2036 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
2038 static bool
2039 epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict)
2041 #define REG_OK_FOR_BASE_P(X) \
2042 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
2043 if (RTX_OK_FOR_BASE_P (x))
2044 return true;
2045 if (RTX_FRAME_OFFSET_P (x))
2046 return true;
2047 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
2048 return true;
2049 /* If this is a misaligned stack access, don't force it to reg+index. */
2050 if (GET_MODE_SIZE (mode) == 8
2051 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
2052 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
2053 && !(INTVAL (XEXP (x, 1)) & 3)
2054 && INTVAL (XEXP (x, 1)) >= -2047 * 4
2055 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
2056 return true;
2057 if (TARGET_POST_INC
2058 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
2059 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
2060 return true;
2061 if ((TARGET_POST_MODIFY || reload_completed)
2062 && GET_CODE (x) == POST_MODIFY
2063 && GET_CODE (XEXP ((x), 1)) == PLUS
2064 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
2065 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
2066 return true;
2067 if (mode == BLKmode)
2068 return epiphany_legitimate_address_p (SImode, x, strict);
2069 return false;
2072 static reg_class_t
2073 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
2074 machine_mode mode ATTRIBUTE_UNUSED,
2075 secondary_reload_info *sri)
2077 /* This could give more reload inheritance, but we are missing some
2078 reload infrastructure. */
2079 if (0)
2080 if (in_p && GET_CODE (x) == UNSPEC
2081 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
2083 gcc_assert (rclass == GENERAL_REGS);
2084 sri->icode = CODE_FOR_reload_insi_ra;
2085 return NO_REGS;
2087 return NO_REGS;
2090 bool
2091 epiphany_is_long_call_p (rtx x)
2093 tree decl = SYMBOL_REF_DECL (x);
2094 bool ret_val = !TARGET_SHORT_CALLS;
2095 tree attrs;
2097 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2098 probably encode information via encode_section_info, and also
2099 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2100 into account. */
2101 if (decl)
2103 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
2104 if (lookup_attribute ("long_call", attrs))
2105 ret_val = true;
2106 else if (lookup_attribute ("short_call", attrs))
2107 ret_val = false;
2109 return ret_val;
2112 bool
2113 epiphany_small16 (rtx x)
2115 rtx base = x;
2116 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2118 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2120 base = XEXP (XEXP (x, 0), 0);
2121 offs = XEXP (XEXP (x, 0), 1);
2123 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2124 && epiphany_is_long_call_p (base))
2125 return false;
2126 return TARGET_SMALL16 != 0;
2129 /* Return nonzero if it is ok to make a tail-call to DECL. */
2130 static bool
2131 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2133 bool cfun_interrupt_p, call_interrupt_p;
2135 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2136 (current_function_decl));
2137 if (decl)
2138 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2139 else
2141 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2143 gcc_assert (POINTER_TYPE_P (fn_type));
2144 fn_type = TREE_TYPE (fn_type);
2145 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2146 || TREE_CODE (fn_type) == METHOD_TYPE);
2147 call_interrupt_p
2148 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2151 /* Don't tailcall from or to an ISR routine - although we could in
2152 principle tailcall from one ISR routine to another, we'd need to
2153 handle this in sibcall_epilogue to make it work. */
2154 if (cfun_interrupt_p || call_interrupt_p)
2155 return false;
2157 /* Everything else is ok. */
2158 return true;
2161 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2162 expander.
2163 Return true iff the type of T has the uninterruptible attribute.
2164 If T is NULL, return false. */
2165 bool
2166 epiphany_uninterruptible_p (tree t)
2168 tree attrs;
2170 if (t)
2172 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2173 if (lookup_attribute ("disinterrupt", attrs))
2174 return true;
2176 return false;
2179 bool
2180 epiphany_call_uninterruptible_p (rtx mem)
2182 rtx addr = XEXP (mem, 0);
2183 tree t = NULL_TREE;
2185 if (GET_CODE (addr) == SYMBOL_REF)
2186 t = SYMBOL_REF_DECL (addr);
2187 if (!t)
2188 t = MEM_EXPR (mem);
2189 return epiphany_uninterruptible_p (t);
2192 static machine_mode
2193 epiphany_promote_function_mode (const_tree type, machine_mode mode,
2194 int *punsignedp ATTRIBUTE_UNUSED,
2195 const_tree funtype ATTRIBUTE_UNUSED,
2196 int for_return ATTRIBUTE_UNUSED)
2198 int dummy;
2200 return promote_mode (type, mode, &dummy);
2203 static void
2204 epiphany_conditional_register_usage (void)
2206 int i;
2208 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2210 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2211 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2213 if (TARGET_HALF_REG_FILE)
2215 for (i = 32; i <= 63; i++)
2217 fixed_regs[i] = 1;
2218 call_used_regs[i] = 1;
2221 if (epiphany_m1reg >= 0)
2223 fixed_regs[epiphany_m1reg] = 1;
2224 call_used_regs[epiphany_m1reg] = 1;
2226 if (!TARGET_PREFER_SHORT_INSN_REGS)
2227 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2228 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2229 reg_class_contents[GENERAL_REGS]);
2230 /* It would be simpler and quicker if we could just use
2231 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2232 it is set up later by our caller. */
2233 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2234 if (!call_used_regs[i])
2235 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2238 /* Determine where to put an argument to a function.
2239 Value is zero to push the argument on the stack,
2240 or a hard register in which to store the argument.
2242 MODE is the argument's machine mode.
2243 TYPE is the data type of the argument (as a tree).
2244 This is null for libcalls where that information may
2245 not be available.
2246 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2247 the preceding args and about the function being called.
2248 NAMED is nonzero if this argument is a named parameter
2249 (otherwise it is an extra parameter matching an ellipsis). */
2250 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2251 registers and the rest are pushed. */
2252 static rtx
2253 epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode,
2254 const_tree type, bool named ATTRIBUTE_UNUSED)
2256 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2258 if (PASS_IN_REG_P (cum, mode, type))
2259 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2260 return 0;
2263 /* Update the data in CUM to advance over an argument
2264 of mode MODE and data type TYPE.
2265 (TYPE is null for libcalls where that information may not be available.) */
2266 static void
2267 epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
2268 const_tree type, bool named ATTRIBUTE_UNUSED)
2270 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2272 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2275 /* Nested function support.
2276 An epiphany trampoline looks like this:
2277 mov r16,%low(fnaddr)
2278 movt r16,%high(fnaddr)
2279 mov ip,%low(cxt)
2280 movt ip,%high(cxt)
2281 jr r16 */
2283 #define EPIPHANY_LOW_RTX(X) \
2284 (gen_rtx_IOR (SImode, \
2285 gen_rtx_ASHIFT (SImode, \
2286 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2287 gen_rtx_ASHIFT (SImode, \
2288 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2289 #define EPIPHANY_HIGH_RTX(X) \
2290 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2292 /* Emit RTL insns to initialize the variable parts of a trampoline.
2293 FNADDR is an RTX for the address of the function's pure code.
2294 CXT is an RTX for the static chain value for the function. */
2295 static void
2296 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2298 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2299 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2301 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2302 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2303 EPIPHANY_LOW_RTX (fnaddr)));
2304 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2305 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2306 EPIPHANY_HIGH_RTX (fnaddr)));
2307 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2308 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2309 EPIPHANY_LOW_RTX (cxt)));
2310 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2311 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2312 EPIPHANY_HIGH_RTX (cxt)));
2313 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2314 GEN_INT (0x0802014f));
2317 bool
2318 epiphany_optimize_mode_switching (int entity)
2320 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2321 return false;
2322 switch (entity)
2324 case EPIPHANY_MSW_ENTITY_AND:
2325 case EPIPHANY_MSW_ENTITY_OR:
2326 case EPIPHANY_MSW_ENTITY_CONFIG:
2327 return true;
2328 case EPIPHANY_MSW_ENTITY_NEAREST:
2329 case EPIPHANY_MSW_ENTITY_TRUNC:
2330 return optimize > 0;
2331 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2332 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2333 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2334 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2335 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2336 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2337 return optimize == 0 || current_pass == pass_mode_switch_use;
2339 gcc_unreachable ();
2342 static int
2343 epiphany_mode_priority (int entity, int priority)
2345 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2346 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2347 return priority;
2348 if (priority > 3)
2349 switch (priority)
2351 case 4: return FP_MODE_ROUND_UNKNOWN;
2352 case 5: return FP_MODE_NONE;
2353 default: gcc_unreachable ();
2355 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2357 case FP_MODE_INT:
2358 switch (priority)
2360 case 0: return FP_MODE_INT;
2361 case 1: return epiphany_normal_fp_rounding;
2362 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2363 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2364 case 3: return FP_MODE_CALLER;
2366 case FP_MODE_ROUND_NEAREST:
2367 case FP_MODE_CALLER:
2368 switch (priority)
2370 case 0: return FP_MODE_ROUND_NEAREST;
2371 case 1: return FP_MODE_ROUND_TRUNC;
2372 case 2: return FP_MODE_INT;
2373 case 3: return FP_MODE_CALLER;
2375 case FP_MODE_ROUND_TRUNC:
2376 switch (priority)
2378 case 0: return FP_MODE_ROUND_TRUNC;
2379 case 1: return FP_MODE_ROUND_NEAREST;
2380 case 2: return FP_MODE_INT;
2381 case 3: return FP_MODE_CALLER;
2383 case FP_MODE_ROUND_UNKNOWN:
2384 case FP_MODE_NONE:
2385 gcc_unreachable ();
2387 gcc_unreachable ();
2391 epiphany_mode_needed (int entity, rtx_insn *insn)
2393 enum attr_fp_mode mode;
2395 if (recog_memoized (insn) < 0)
2397 if (entity == EPIPHANY_MSW_ENTITY_AND
2398 || entity == EPIPHANY_MSW_ENTITY_OR
2399 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2400 return 2;
2401 return FP_MODE_NONE;
2403 mode = get_attr_fp_mode (insn);
2405 switch (entity)
2407 case EPIPHANY_MSW_ENTITY_AND:
2408 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
2409 case EPIPHANY_MSW_ENTITY_OR:
2410 return mode == FP_MODE_INT ? 1 : 2;
2411 case EPIPHANY_MSW_ENTITY_CONFIG:
2412 /* We must know/save config before we set it to something else.
2413 Where we need the original value, we are fine with having it
2414 just unchanged from the function start.
2415 Because of the nature of the mode switching optimization,
2416 a restore will be dominated by a clobber. */
2417 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2418 return 1;
2419 /* A cpecial case are abnormal edges, which are deemed to clobber
2420 the mode as well. We need to pin this effect on a actually
2421 dominating insn, and one where the frame can be accessed, too, in
2422 case the pseudo used to save CONFIG doesn't get a hard register. */
2423 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2424 return 1;
2425 return 2;
2426 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2427 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2428 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2429 /* Fall through. */
2430 case EPIPHANY_MSW_ENTITY_NEAREST:
2431 case EPIPHANY_MSW_ENTITY_TRUNC:
2432 if (mode == FP_MODE_ROUND_UNKNOWN)
2434 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2435 return FP_MODE_NONE;
2437 return mode;
2438 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2439 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2440 return FP_MODE_ROUND_UNKNOWN;
2441 return mode;
2442 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2443 if (mode == FP_MODE_ROUND_UNKNOWN)
2444 return epiphany_normal_fp_rounding;
2445 return mode;
2446 default:
2447 gcc_unreachable ();
2451 static int
2452 epiphany_mode_entry_exit (int entity, bool exit)
2454 int normal_mode = epiphany_normal_fp_mode ;
2456 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2457 if (epiphany_is_interrupt_p (current_function_decl))
2458 normal_mode = FP_MODE_CALLER;
2459 switch (entity)
2461 case EPIPHANY_MSW_ENTITY_AND:
2462 if (exit)
2463 return normal_mode != FP_MODE_INT ? 1 : 2;
2464 return 0;
2465 case EPIPHANY_MSW_ENTITY_OR:
2466 if (exit)
2467 return normal_mode == FP_MODE_INT ? 1 : 2;
2468 return 0;
2469 case EPIPHANY_MSW_ENTITY_CONFIG:
2470 if (exit)
2471 return 2;
2472 return normal_mode == FP_MODE_CALLER ? 0 : 1;
2473 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2474 if (normal_mode == FP_MODE_ROUND_NEAREST
2475 || normal_mode == FP_MODE_ROUND_TRUNC)
2476 return FP_MODE_ROUND_UNKNOWN;
2477 /* Fall through. */
2478 case EPIPHANY_MSW_ENTITY_NEAREST:
2479 case EPIPHANY_MSW_ENTITY_TRUNC:
2480 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2481 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2482 return normal_mode;
2483 default:
2484 gcc_unreachable ();
2489 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn)
2491 /* We have too few call-saved registers to hope to keep the masks across
2492 calls. */
2493 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2495 if (CALL_P (insn))
2496 return 0;
2497 return last_mode;
2499 /* If there is an abnormal edge, we don't want the config register to
2500 be 'saved' again at the destination.
2501 The frame pointer adjustment is inside a PARALLEL because of the
2502 flags clobber. */
2503 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2504 && GET_CODE (PATTERN (insn)) == PARALLEL
2505 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2506 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2508 gcc_assert (cfun->has_nonlocal_label);
2509 return 1;
2511 if (recog_memoized (insn) < 0)
2512 return last_mode;
2513 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2514 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2516 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2517 return FP_MODE_ROUND_NEAREST;
2518 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2519 return FP_MODE_ROUND_TRUNC;
2521 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2523 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2524 int fp_mode;
2526 if (REG_P (src))
2527 return FP_MODE_CALLER;
2528 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2529 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2530 && (fp_mode == FP_MODE_ROUND_NEAREST
2531 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2532 return FP_MODE_ROUND_UNKNOWN;
2533 return fp_mode;
2535 return last_mode;
2538 static int
2539 epiphany_mode_entry (int entity)
2541 return epiphany_mode_entry_exit (entity, false);
2544 static int
2545 epiphany_mode_exit (int entity)
2547 return epiphany_mode_entry_exit (entity, true);
2550 void
2551 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
2552 HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2554 rtx save_cc, cc_reg, mask, src, src2;
2555 enum attr_fp_mode fp_mode;
2557 if (!MACHINE_FUNCTION (cfun)->and_mask)
2559 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2560 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2562 if (entity == EPIPHANY_MSW_ENTITY_AND)
2564 gcc_assert (mode >= 0 && mode <= 2);
2565 if (mode == 1)
2566 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2567 gen_int_mode (0xfff1fffe, SImode));
2568 return;
2570 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2572 gcc_assert (mode >= 0 && mode <= 2);
2573 if (mode == 1)
2574 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2575 return;
2577 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2579 /* Mode switching optimization is done after emit_initial_value_sets,
2580 so we have to take care of CONFIG_REGNUM here. */
2581 gcc_assert (mode >= 0 && mode <= 2);
2582 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2583 if (mode == 1)
2584 emit_insn (gen_save_config (save));
2585 return;
2587 fp_mode = (enum attr_fp_mode) mode;
2588 src = NULL_RTX;
2590 switch (fp_mode)
2592 case FP_MODE_CALLER:
2593 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2594 so that the config save gets inserted before the first use. */
2595 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2596 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2597 mask = MACHINE_FUNCTION (cfun)->and_mask;
2598 break;
2599 case FP_MODE_ROUND_UNKNOWN:
2600 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2601 mask = MACHINE_FUNCTION (cfun)->and_mask;
2602 break;
2603 case FP_MODE_ROUND_NEAREST:
2604 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2605 return;
2606 mask = MACHINE_FUNCTION (cfun)->and_mask;
2607 break;
2608 case FP_MODE_ROUND_TRUNC:
2609 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2610 return;
2611 mask = MACHINE_FUNCTION (cfun)->and_mask;
2612 break;
2613 case FP_MODE_INT:
2614 mask = MACHINE_FUNCTION (cfun)->or_mask;
2615 break;
2616 case FP_MODE_NONE:
2617 default:
2618 gcc_unreachable ();
2620 save_cc = gen_reg_rtx (CCmode);
2621 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2622 emit_move_insn (save_cc, cc_reg);
2623 mask = force_reg (SImode, mask);
2624 if (!src)
2626 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2628 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2630 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2631 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2632 src2 = copy_rtx (src);
2633 else
2635 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2637 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2639 emit_insn (gen_set_fp_mode (src, src2, mask));
2640 emit_move_insn (cc_reg, save_cc);
2643 void
2644 epiphany_expand_set_fp_mode (rtx *operands)
2646 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2647 rtx src = operands[0];
2648 rtx mask_reg = operands[2];
2649 rtx scratch = operands[3];
2650 enum attr_fp_mode fp_mode;
2653 gcc_assert (rtx_equal_p (src, operands[1])
2654 /* Sometimes reload gets silly and reloads the same pseudo
2655 into different registers. */
2656 || (REG_P (src) && REG_P (operands[1])));
2658 if (!epiphany_uninterruptible_p (current_function_decl))
2659 emit_insn (gen_gid ());
2660 emit_move_insn (scratch, ctrl);
2662 if (GET_CODE (src) == REG)
2664 /* FP_MODE_CALLER */
2665 emit_insn (gen_xorsi3 (scratch, scratch, src));
2666 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2667 emit_insn (gen_xorsi3 (scratch, scratch, src));
2669 else
2671 gcc_assert (GET_CODE (src) == CONST);
2672 src = XEXP (src, 0);
2673 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2674 switch (fp_mode)
2676 case FP_MODE_ROUND_NEAREST:
2677 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2678 break;
2679 case FP_MODE_ROUND_TRUNC:
2680 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2681 emit_insn (gen_add2_insn (scratch, const1_rtx));
2682 break;
2683 case FP_MODE_INT:
2684 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2685 break;
2686 case FP_MODE_CALLER:
2687 case FP_MODE_ROUND_UNKNOWN:
2688 case FP_MODE_NONE:
2689 gcc_unreachable ();
2692 emit_move_insn (ctrl, scratch);
2693 if (!epiphany_uninterruptible_p (current_function_decl))
2694 emit_insn (gen_gie ());
2697 void
2698 epiphany_insert_mode_switch_use (rtx_insn *insn,
2699 int entity ATTRIBUTE_UNUSED,
2700 int mode ATTRIBUTE_UNUSED)
2702 rtx pat = PATTERN (insn);
2703 rtvec v;
2704 int len, i;
2705 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2706 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2708 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2709 return;
2710 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2712 case FP_MODE_ROUND_NEAREST:
2713 near = gen_rtx_USE (VOIDmode, near);
2714 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2715 break;
2716 case FP_MODE_ROUND_TRUNC:
2717 near = gen_rtx_CLOBBER (VOIDmode, near);
2718 trunc = gen_rtx_USE (VOIDmode, trunc);
2719 break;
2720 case FP_MODE_ROUND_UNKNOWN:
2721 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2722 trunc = copy_rtx (near);
2723 /* Fall through. */
2724 case FP_MODE_INT:
2725 case FP_MODE_CALLER:
2726 near = gen_rtx_USE (VOIDmode, near);
2727 trunc = gen_rtx_USE (VOIDmode, trunc);
2728 break;
2729 case FP_MODE_NONE:
2730 gcc_unreachable ();
2732 gcc_assert (GET_CODE (pat) == PARALLEL);
2733 len = XVECLEN (pat, 0);
2734 v = rtvec_alloc (len + 2);
2735 for (i = 0; i < len; i++)
2736 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2737 RTVEC_ELT (v, len) = near;
2738 RTVEC_ELT (v, len + 1) = trunc;
2739 pat = gen_rtx_PARALLEL (VOIDmode, v);
2740 PATTERN (insn) = pat;
2741 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2744 bool
2745 epiphany_epilogue_uses (int regno)
2747 if (regno == GPR_LR)
2748 return true;
2749 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2751 if (fixed_regs[regno]
2752 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2753 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2754 return false;
2755 return true;
2757 if (regno == FP_NEAREST_REGNUM
2758 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2759 return true;
2760 if (regno == FP_TRUNCATE_REGNUM
2761 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2762 return true;
2763 return false;
2766 static unsigned int
2767 epiphany_min_divisions_for_recip_mul (machine_mode mode)
2769 if (flag_reciprocal_math && mode == SFmode)
2770 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2771 it already at the tree level and expose it to further optimizations. */
2772 return 1;
2773 return default_min_divisions_for_recip_mul (mode);
2776 static machine_mode
2777 epiphany_preferred_simd_mode (machine_mode mode ATTRIBUTE_UNUSED)
2779 return TARGET_VECT_DOUBLE ? DImode : SImode;
2782 static bool
2783 epiphany_vector_mode_supported_p (machine_mode mode)
2785 if (mode == V2SFmode)
2786 return true;
2787 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2788 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2789 return true;
2790 return false;
2793 static bool
2794 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2796 /* Vectors which aren't in packed structures will not be less aligned than
2797 the natural alignment of their element type, so this is safe. */
2798 if (TYPE_ALIGN_UNIT (type) == 4)
2799 return !is_packed;
2801 return default_builtin_vector_alignment_reachable (type, is_packed);
2804 static bool
2805 epiphany_support_vector_misalignment (machine_mode mode, const_tree type,
2806 int misalignment, bool is_packed)
2808 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2809 return true;
2810 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2811 is_packed);
2814 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2815 structs. Make structs double-word-aligned it they are a double word or
2816 (potentially) larger; failing that, do the same for a size of 32 bits. */
2817 unsigned
2818 epiphany_special_round_type_align (tree type, unsigned computed,
2819 unsigned specified)
2821 unsigned align = MAX (computed, specified);
2822 tree field;
2823 HOST_WIDE_INT total, max;
2824 unsigned try_align = FASTEST_ALIGNMENT;
2826 if (maximum_field_alignment && try_align > maximum_field_alignment)
2827 try_align = maximum_field_alignment;
2828 if (align >= try_align)
2829 return align;
2830 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2832 tree offset, size;
2834 if (TREE_CODE (field) != FIELD_DECL
2835 || TREE_TYPE (field) == error_mark_node)
2836 continue;
2837 offset = bit_position (field);
2838 size = DECL_SIZE (field);
2839 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
2840 || tree_to_uhwi (offset) >= try_align
2841 || tree_to_uhwi (size) >= try_align)
2842 return try_align;
2843 total = tree_to_uhwi (offset) + tree_to_uhwi (size);
2844 if (total > max)
2845 max = total;
2847 if (max >= (HOST_WIDE_INT) try_align)
2848 align = try_align;
2849 else if (try_align > 32 && max >= 32)
2850 align = max > 32 ? 64 : 32;
2851 return align;
2854 /* Upping the alignment of arrays in structs is not only a performance
2855 enhancement, it also helps preserve assumptions about how
2856 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2857 libgcov.c . */
2858 unsigned
2859 epiphany_adjust_field_align (tree type, unsigned computed)
2861 if (computed == 32
2862 && TREE_CODE (type) == ARRAY_TYPE)
2864 tree elmsz = TYPE_SIZE (TREE_TYPE (type));
2866 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
2867 return 64;
2869 return computed;
2872 /* Output code to add DELTA to the first argument, and then jump
2873 to FUNCTION. Used for C++ multiple inheritance. */
2874 static void
2875 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2876 HOST_WIDE_INT delta,
2877 HOST_WIDE_INT vcall_offset,
2878 tree function)
2880 int this_regno
2881 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2882 const char *this_name = reg_names[this_regno];
2883 const char *fname;
2885 /* We use IP and R16 as a scratch registers. */
2886 gcc_assert (call_used_regs [GPR_IP]);
2887 gcc_assert (call_used_regs [GPR_16]);
2889 /* Add DELTA. When possible use a plain add, otherwise load it into
2890 a register first. */
2891 if (delta == 0)
2892 ; /* Done. */
2893 else if (SIMM11 (delta))
2894 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2895 else if (delta < 0 && delta >= -0xffff)
2897 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2898 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2900 else
2902 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2903 if (delta & ~0xffff)
2904 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2905 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2908 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2909 if (vcall_offset != 0)
2911 /* ldr ip,[this] --> temp = *this
2912 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2913 add this,this,ip --> this+ = *(*this + vcall_offset) */
2914 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2915 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2916 || (vcall_offset & 3) != 0)
2918 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2919 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2920 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2922 else
2923 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2924 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2927 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2928 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2930 fputs ("\tmov\tip,%low(", file);
2931 assemble_name (file, fname);
2932 fputs (")\n\tmovt\tip,%high(", file);
2933 assemble_name (file, fname);
2934 fputs (")\n\tjr ip\n", file);
2936 else
2938 fputs ("\tb\t", file);
2939 assemble_name (file, fname);
2940 fputc ('\n', file);
2944 void
2945 epiphany_start_function (FILE *file, const char *name, tree decl)
2947 /* If the function doesn't fit into the on-chip memory, it will have a
2948 section attribute - or lack of it - that denotes it goes somewhere else.
2949 But the architecture spec says that an interrupt vector still has to
2950 point to on-chip memory. So we must place a jump there to get to the
2951 actual function implementation. The forwarder_section attribute
2952 specifies the section where this jump goes.
2953 This mechanism can also be useful to have a shortcall destination for
2954 a function that is actually placed much farther away. */
2955 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2957 attrs = DECL_ATTRIBUTES (decl);
2958 int_attr = lookup_attribute ("interrupt", attrs);
2959 if (int_attr)
2960 for (int_names = TREE_VALUE (int_attr); int_names;
2961 int_names = TREE_CHAIN (int_names))
2963 char buf[99];
2965 int_name = TREE_VALUE (int_names);
2966 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2967 switch_to_section (get_section (buf, SECTION_CODE, decl));
2968 fputs ("\tb\t", file);
2969 assemble_name (file, name);
2970 fputc ('\n', file);
2972 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2973 if (forwarder_attr)
2975 const char *prefix = "__forwarder_dst_";
2976 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2978 strcpy (dst_name, prefix);
2979 strcat (dst_name, name);
2980 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2981 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2982 SECTION_CODE, decl));
2983 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2984 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2986 int tmp = GPR_0;
2988 if (int_attr)
2989 fputs ("\tstrd r0,[sp,-1]\n", file);
2990 else
2991 tmp = GPR_16;
2992 gcc_assert (call_used_regs[tmp]);
2993 fprintf (file, "\tmov r%d,%%low(", tmp);
2994 assemble_name (file, dst_name);
2995 fprintf (file, ")\n"
2996 "\tmovt r%d,%%high(", tmp);
2997 assemble_name (file, dst_name);
2998 fprintf (file, ")\n"
2999 "\tjr r%d\n", tmp);
3001 else
3003 fputs ("\tb\t", file);
3004 assemble_name (file, dst_name);
3005 fputc ('\n', file);
3007 name = dst_name;
3009 switch_to_section (function_section (decl));
3010 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
3013 struct gcc_target targetm = TARGET_INITIALIZER;