Fix numerous typos in comments
[official-gcc.git] / gcc / config / epiphany / epiphany.c
blobb9ec0f40d12ab4ac78091535d6945c146f105d9a
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 "optabs.h"
33 #include "emit-rtl.h"
34 #include "recog.h"
35 #include "diagnostic-core.h"
36 #include "alias.h"
37 #include "stor-layout.h"
38 #include "varasm.h"
39 #include "calls.h"
40 #include "output.h"
41 #include "insn-attr.h"
42 #include "explow.h"
43 #include "expr.h"
44 #include "tm-constrs.h"
45 #include "tree-pass.h" /* for current_pass */
46 #include "context.h"
47 #include "pass_manager.h"
48 #include "builtins.h"
50 /* Which cpu we're compiling for. */
51 int epiphany_cpu_type;
53 /* Name of mangle string to add to symbols to separate code compiled for each
54 cpu (or NULL). */
55 const char *epiphany_mangle_cpu;
57 /* Array of valid operand punctuation characters. */
58 char epiphany_punct_chars[256];
60 /* The rounding mode that we generally use for floating point. */
61 int epiphany_normal_fp_rounding;
63 /* The pass instance, for use in epiphany_optimize_mode_switching. */
64 static opt_pass *pass_mode_switch_use;
66 static void epiphany_init_reg_tables (void);
67 static int get_epiphany_condition_code (rtx);
68 static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
69 static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
70 bool *);
71 static bool epiphany_pass_by_reference (cumulative_args_t, machine_mode,
72 const_tree, bool);
73 static rtx_insn *frame_insn (rtx);
75 /* defines for the initialization of the GCC target structure. */
76 #define TARGET_ATTRIBUTE_TABLE epiphany_attribute_table
78 #define TARGET_PRINT_OPERAND epiphany_print_operand
79 #define TARGET_PRINT_OPERAND_ADDRESS epiphany_print_operand_address
81 #define TARGET_RTX_COSTS epiphany_rtx_costs
82 #define TARGET_ADDRESS_COST epiphany_address_cost
83 #define TARGET_MEMORY_MOVE_COST epiphany_memory_move_cost
85 #define TARGET_PROMOTE_FUNCTION_MODE epiphany_promote_function_mode
86 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
88 #define TARGET_RETURN_IN_MEMORY epiphany_return_in_memory
89 #define TARGET_PASS_BY_REFERENCE epiphany_pass_by_reference
90 #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
91 #define TARGET_FUNCTION_VALUE epiphany_function_value
92 #define TARGET_LIBCALL_VALUE epiphany_libcall_value
93 #define TARGET_FUNCTION_VALUE_REGNO_P epiphany_function_value_regno_p
95 #define TARGET_SETUP_INCOMING_VARARGS epiphany_setup_incoming_varargs
97 /* Using the simplistic varags handling forces us to do partial reg/stack
98 argument passing for types with larger size (> 4 bytes) than alignment. */
99 #define TARGET_ARG_PARTIAL_BYTES epiphany_arg_partial_bytes
101 #define TARGET_FUNCTION_OK_FOR_SIBCALL epiphany_function_ok_for_sibcall
103 #define TARGET_SCHED_ISSUE_RATE epiphany_issue_rate
104 #define TARGET_SCHED_ADJUST_COST epiphany_adjust_cost
106 #define TARGET_LRA_P hook_bool_void_false
108 #define TARGET_LEGITIMATE_ADDRESS_P epiphany_legitimate_address_p
110 #define TARGET_SECONDARY_RELOAD epiphany_secondary_reload
112 #define TARGET_OPTION_OVERRIDE epiphany_override_options
114 #define TARGET_CONDITIONAL_REGISTER_USAGE epiphany_conditional_register_usage
116 #define TARGET_FUNCTION_ARG epiphany_function_arg
118 #define TARGET_FUNCTION_ARG_ADVANCE epiphany_function_arg_advance
120 #define TARGET_FUNCTION_ARG_BOUNDARY epiphany_function_arg_boundary
122 #define TARGET_TRAMPOLINE_INIT epiphany_trampoline_init
124 /* Nonzero if the constant rtx value is a legitimate general operand.
125 We can handle any 32- or 64-bit constant. */
126 #define TARGET_LEGITIMATE_CONSTANT_P hook_bool_mode_rtx_true
128 #define TARGET_MIN_DIVISIONS_FOR_RECIP_MUL \
129 epiphany_min_divisions_for_recip_mul
131 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE epiphany_preferred_simd_mode
133 #define TARGET_VECTOR_MODE_SUPPORTED_P epiphany_vector_mode_supported_p
135 #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
136 epiphany_vector_alignment_reachable
138 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
139 epiphany_support_vector_misalignment
141 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \
142 hook_bool_const_tree_hwi_hwi_const_tree_true
143 #define TARGET_ASM_OUTPUT_MI_THUNK epiphany_output_mi_thunk
145 /* ??? we can use larger offsets for wider-mode sized accesses, but there
146 is no concept of anchors being dependent on the modes that they are used
147 for, so we can only use an offset range that would suit all modes. */
148 #define TARGET_MAX_ANCHOR_OFFSET (optimize_size ? 31 : 2047)
149 /* We further restrict the minimum to be a multiple of eight. */
150 #define TARGET_MIN_ANCHOR_OFFSET (optimize_size ? 0 : -2040)
152 /* Mode switching hooks. */
154 #define TARGET_MODE_EMIT emit_set_fp_mode
156 #define TARGET_MODE_NEEDED epiphany_mode_needed
158 #define TARGET_MODE_PRIORITY epiphany_mode_priority
160 #define TARGET_MODE_ENTRY epiphany_mode_entry
162 #define TARGET_MODE_EXIT epiphany_mode_exit
164 #define TARGET_MODE_AFTER epiphany_mode_after
166 #include "target-def.h"
168 #undef TARGET_ASM_ALIGNED_HI_OP
169 #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
170 #undef TARGET_ASM_ALIGNED_SI_OP
171 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
173 bool
174 epiphany_is_interrupt_p (tree decl)
176 tree attrs;
178 attrs = DECL_ATTRIBUTES (decl);
179 if (lookup_attribute ("interrupt", attrs))
180 return true;
181 else
182 return false;
185 /* Called from epiphany_override_options.
186 We use this to initialize various things. */
188 static void
189 epiphany_init (void)
191 /* N.B. this pass must not run before the first optimize_mode_switching
192 pass because of the side offect of epiphany_mode_needed on
193 MACHINE_FUNCTION(cfun)->unknown_mode_uses. But it must run before
194 pass_resolve_sw_modes. */
195 pass_mode_switch_use = make_pass_mode_switch_use (g);
196 struct register_pass_info insert_use_info
197 = { pass_mode_switch_use, "mode_sw",
198 1, PASS_POS_INSERT_AFTER
200 opt_pass *mode_sw2
201 = g->get_passes()->get_pass_mode_switching ()->clone ();
202 struct register_pass_info mode_sw2_info
203 = { mode_sw2, "mode_sw",
204 1, PASS_POS_INSERT_AFTER
206 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g);
207 struct register_pass_info mode_sw3_info
208 = { mode_sw3, "mode_sw",
209 1, PASS_POS_INSERT_AFTER
211 opt_pass *mode_sw4
212 = g->get_passes()->get_pass_split_all_insns ()->clone ();
213 struct register_pass_info mode_sw4_info
214 = { mode_sw4, "mode_sw",
215 1, PASS_POS_INSERT_AFTER
217 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
218 #define N_ENTITIES ARRAY_SIZE (num_modes)
220 epiphany_init_reg_tables ();
222 /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
223 memset (epiphany_punct_chars, 0, sizeof (epiphany_punct_chars));
224 epiphany_punct_chars['-'] = 1;
226 epiphany_normal_fp_rounding
227 = (epiphany_normal_fp_mode == FP_MODE_ROUND_TRUNC
228 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
229 register_pass (&mode_sw4_info);
230 register_pass (&mode_sw2_info);
231 register_pass (&mode_sw3_info);
232 register_pass (&insert_use_info);
233 register_pass (&mode_sw2_info);
234 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
235 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
237 #if 1 /* As long as peep2_rescan is not implemented,
238 (see http://gcc.gnu.org/ml/gcc-patches/2011-10/msg02819.html,)
239 we need a second peephole2 pass to get reasonable code. */
241 opt_pass *extra_peephole2
242 = g->get_passes ()->get_pass_peephole2 ()->clone ();
243 struct register_pass_info peep2_2_info
244 = { extra_peephole2, "peephole2",
245 1, PASS_POS_INSERT_AFTER
248 register_pass (&peep2_2_info);
250 #endif
253 /* The condition codes of the EPIPHANY, and the inverse function. */
254 static const char *const epiphany_condition_codes[] =
255 { /* 0 1 2 3 4 5 6 7 8 9 */
256 "eq", "ne", "ltu", "gteu", "gt", "lte", "gte", "lt", "gtu", "lteu",
257 /* 10 11 12 13 */
258 "beq","bne","blt", "blte",
261 #define EPIPHANY_INVERSE_CONDITION_CODE(X) ((X) ^ 1)
263 /* Returns the index of the EPIPHANY condition code string in
264 `epiphany_condition_codes'. COMPARISON should be an rtx like
265 `(eq (...) (...))'. */
267 static int
268 get_epiphany_condition_code (rtx comparison)
270 switch (GET_MODE (XEXP (comparison, 0)))
272 case CCmode:
273 switch (GET_CODE (comparison))
275 case EQ : return 0;
276 case NE : return 1;
277 case LTU : return 2;
278 case GEU : return 3;
279 case GT : return 4;
280 case LE : return 5;
281 case GE : return 6;
282 case LT : return 7;
283 case GTU : return 8;
284 case LEU : return 9;
286 default : gcc_unreachable ();
288 case CC_N_NEmode:
289 switch (GET_CODE (comparison))
291 case EQ: return 6;
292 case NE: return 7;
293 default: gcc_unreachable ();
295 case CC_C_LTUmode:
296 switch (GET_CODE (comparison))
298 case GEU: return 2;
299 case LTU: return 3;
300 default: gcc_unreachable ();
302 case CC_C_GTUmode:
303 switch (GET_CODE (comparison))
305 case LEU: return 3;
306 case GTU: return 2;
307 default: gcc_unreachable ();
309 case CC_FPmode:
310 switch (GET_CODE (comparison))
312 case EQ: return 10;
313 case NE: return 11;
314 case LT: return 12;
315 case LE: return 13;
316 default: gcc_unreachable ();
318 case CC_FP_EQmode:
319 switch (GET_CODE (comparison))
321 case EQ: return 0;
322 case NE: return 1;
323 default: gcc_unreachable ();
325 case CC_FP_GTEmode:
326 switch (GET_CODE (comparison))
328 case EQ: return 0;
329 case NE: return 1;
330 case GT : return 4;
331 case GE : return 6;
332 case UNLE : return 5;
333 case UNLT : return 7;
334 default: gcc_unreachable ();
336 case CC_FP_ORDmode:
337 switch (GET_CODE (comparison))
339 case ORDERED: return 9;
340 case UNORDERED: return 8;
341 default: gcc_unreachable ();
343 case CC_FP_UNEQmode:
344 switch (GET_CODE (comparison))
346 case UNEQ: return 9;
347 case LTGT: return 8;
348 default: gcc_unreachable ();
350 default: gcc_unreachable ();
352 /*NOTREACHED*/
353 return (42);
357 /* Return 1 if hard register REGNO can hold a value of machine_mode MODE. */
359 hard_regno_mode_ok (int regno, machine_mode mode)
361 if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
362 return (regno & 1) == 0 && GPR_P (regno);
363 else
364 return 1;
367 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
368 return the mode to be used for the comparison. */
370 machine_mode
371 epiphany_select_cc_mode (enum rtx_code op,
372 rtx x ATTRIBUTE_UNUSED,
373 rtx y ATTRIBUTE_UNUSED)
375 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
377 if (TARGET_SOFT_CMPSF
378 || op == ORDERED || op == UNORDERED)
380 if (op == EQ || op == NE)
381 return CC_FP_EQmode;
382 if (op == ORDERED || op == UNORDERED)
383 return CC_FP_ORDmode;
384 if (op == UNEQ || op == LTGT)
385 return CC_FP_UNEQmode;
386 return CC_FP_GTEmode;
388 return CC_FPmode;
390 /* recognize combiner pattern ashlsi_btst:
391 (parallel [
392 (set (reg:N_NE 65 cc1)
393 (compare:N_NE (zero_extract:SI (reg/v:SI 75 [ a ])
394 (const_int 1 [0x1])
395 (const_int 0 [0x0]))
396 (const_int 0 [0x0])))
397 (clobber (scratch:SI)) */
398 else if ((op == EQ || op == NE)
399 && GET_CODE (x) == ZERO_EXTRACT
400 && XEXP (x, 1) == const1_rtx
401 && CONST_INT_P (XEXP (x, 2)))
402 return CC_N_NEmode;
403 else if ((op == GEU || op == LTU) && GET_CODE (x) == PLUS)
404 return CC_C_LTUmode;
405 else if ((op == LEU || op == GTU) && GET_CODE (x) == MINUS)
406 return CC_C_GTUmode;
407 else
408 return CCmode;
411 enum reg_class epiphany_regno_reg_class[FIRST_PSEUDO_REGISTER];
413 static void
414 epiphany_init_reg_tables (void)
416 int i;
418 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
420 if (i == GPR_LR)
421 epiphany_regno_reg_class[i] = LR_REGS;
422 else if (i <= 7 && TARGET_PREFER_SHORT_INSN_REGS)
423 epiphany_regno_reg_class[i] = SHORT_INSN_REGS;
424 else if (call_used_regs[i]
425 && TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
426 epiphany_regno_reg_class[i] = SIBCALL_REGS;
427 else if (i >= CORE_CONTROL_FIRST && i <= CORE_CONTROL_LAST)
428 epiphany_regno_reg_class[i] = CORE_CONTROL_REGS;
429 else if (i < (GPR_LAST+1)
430 || i == ARG_POINTER_REGNUM || i == FRAME_POINTER_REGNUM)
431 epiphany_regno_reg_class[i] = GENERAL_REGS;
432 else if (i == CC_REGNUM)
433 epiphany_regno_reg_class[i] = NO_REGS /* CC_REG: must be NO_REGS */;
434 else
435 epiphany_regno_reg_class[i] = NO_REGS;
439 /* EPIPHANY specific attribute support.
441 The EPIPHANY has these attributes:
442 interrupt - for interrupt functions.
443 short_call - the function is assumed to be reachable with the b / bl
444 instructions.
445 long_call - the function address is loaded into a register before use.
446 disinterrupt - functions which mask interrupts throughout.
447 They unmask them while calling an interruptible
448 function, though. */
450 static const struct attribute_spec epiphany_attribute_table[] =
452 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
453 { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
454 { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
455 { "long_call", 0, 0, false, true, true, NULL, false },
456 { "short_call", 0, 0, false, true, true, NULL, false },
457 { "disinterrupt", 0, 0, false, true, true, NULL, true },
458 { NULL, 0, 0, false, false, false, NULL, false }
461 /* Handle an "interrupt" attribute; arguments as in
462 struct attribute_spec.handler. */
463 static tree
464 epiphany_handle_interrupt_attribute (tree *node, tree name, tree args,
465 int flags ATTRIBUTE_UNUSED,
466 bool *no_add_attrs)
468 tree value;
470 if (!args)
472 gcc_assert (DECL_P (*node));
473 tree t = TREE_TYPE (*node);
474 if (TREE_CODE (t) != FUNCTION_TYPE)
475 warning (OPT_Wattributes, "%qE attribute only applies to functions",
476 name);
477 /* Argument handling and the stack layout for interrupt handlers
478 don't mix. It makes no sense in the first place, so emit an
479 error for this. */
480 else if (TYPE_ARG_TYPES (t)
481 && TREE_VALUE (TYPE_ARG_TYPES (t)) != void_type_node)
482 error_at (DECL_SOURCE_LOCATION (*node),
483 "interrupt handlers cannot have arguments");
484 return NULL_TREE;
487 value = TREE_VALUE (args);
489 if (TREE_CODE (value) != STRING_CST)
491 warning (OPT_Wattributes,
492 "argument of %qE attribute is not a string constant", name);
493 *no_add_attrs = true;
495 else if (strcmp (TREE_STRING_POINTER (value), "reset")
496 && strcmp (TREE_STRING_POINTER (value), "software_exception")
497 && strcmp (TREE_STRING_POINTER (value), "page_miss")
498 && strcmp (TREE_STRING_POINTER (value), "timer0")
499 && strcmp (TREE_STRING_POINTER (value), "timer1")
500 && strcmp (TREE_STRING_POINTER (value), "message")
501 && strcmp (TREE_STRING_POINTER (value), "dma0")
502 && strcmp (TREE_STRING_POINTER (value), "dma1")
503 && strcmp (TREE_STRING_POINTER (value), "wand")
504 && strcmp (TREE_STRING_POINTER (value), "swi"))
506 warning (OPT_Wattributes,
507 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
508 name);
509 *no_add_attrs = true;
510 return NULL_TREE;
513 return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
514 flags, no_add_attrs);
517 /* Handle a "forwarder_section" attribute; arguments as in
518 struct attribute_spec.handler. */
519 static tree
520 epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
521 tree name, tree args,
522 int flags ATTRIBUTE_UNUSED,
523 bool *no_add_attrs)
525 tree value;
527 value = TREE_VALUE (args);
529 if (TREE_CODE (value) != STRING_CST)
531 warning (OPT_Wattributes,
532 "argument of %qE attribute is not a string constant", name);
533 *no_add_attrs = true;
535 return NULL_TREE;
539 /* Misc. utilities. */
541 /* Generate a SYMBOL_REF for the special function NAME. When the address
542 can't be placed directly into a call instruction, and if possible, copy
543 it to a register so that cse / code hoisting is possible. */
545 sfunc_symbol (const char *name)
547 rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
549 /* These sfuncs should be hidden, and every dso should get a copy. */
550 SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION | SYMBOL_FLAG_LOCAL;
551 if (TARGET_SHORT_CALLS)
552 ; /* Nothing to be done. */
553 else if (can_create_pseudo_p ())
554 sym = copy_to_mode_reg (Pmode, sym);
555 else /* We rely on reload to fix this up. */
556 gcc_assert (!reload_in_progress || reload_completed);
557 return sym;
560 /* X and Y are two things to compare using CODE in IN_MODE.
561 Emit the compare insn, construct the proper cc reg in the proper
562 mode, and return the rtx for the cc reg comparison in CMODE. */
565 gen_compare_reg (machine_mode cmode, enum rtx_code code,
566 machine_mode in_mode, rtx x, rtx y)
568 machine_mode mode = SELECT_CC_MODE (code, x, y);
569 rtx cc_reg, pat, clob0, clob1, clob2;
571 if (in_mode == VOIDmode)
572 in_mode = GET_MODE (x);
573 if (in_mode == VOIDmode)
574 in_mode = GET_MODE (y);
576 if (mode == CC_FPmode)
578 /* The epiphany has only EQ / NE / LT / LE conditions for
579 hardware floating point. */
580 if (code == GT || code == GE || code == UNLE || code == UNLT)
582 rtx tmp = x; x = y; y = tmp;
583 code = swap_condition (code);
585 cc_reg = gen_rtx_REG (mode, CCFP_REGNUM);
586 y = force_reg (in_mode, y);
588 else
590 if (mode == CC_FP_GTEmode
591 && (code == LE || code == LT || code == UNGT || code == UNGE))
593 if (flag_finite_math_only
594 && ((REG_P (x) && REGNO (x) == GPR_0)
595 || (REG_P (y) && REGNO (y) == GPR_1)))
596 switch (code)
598 case LE: code = UNLE; break;
599 case LT: code = UNLT; break;
600 case UNGT: code = GT; break;
601 case UNGE: code = GE; break;
602 default: gcc_unreachable ();
604 else
606 rtx tmp = x; x = y; y = tmp;
607 code = swap_condition (code);
610 cc_reg = gen_rtx_REG (mode, CC_REGNUM);
612 if ((mode == CC_FP_EQmode || mode == CC_FP_GTEmode
613 || mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
614 /* mov<mode>cc might want to re-emit a comparison during ifcvt. */
615 && (!REG_P (x) || REGNO (x) != GPR_0
616 || !REG_P (y) || REGNO (y) != GPR_1))
618 rtx reg;
620 #if 0
621 /* ??? We should really do the r0/r1 clobber only during rtl expansion,
622 but just like the flag clobber of movsicc, we have to allow
623 this for ifcvt to work, on the assumption that we'll only want
624 to do this if these registers have been used before by the
625 pre-ifcvt code. */
626 gcc_assert (currently_expanding_to_rtl);
627 #endif
628 reg = gen_rtx_REG (in_mode, GPR_0);
629 if (reg_overlap_mentioned_p (reg, y))
630 return 0;
631 emit_move_insn (reg, x);
632 x = reg;
633 reg = gen_rtx_REG (in_mode, GPR_1);
634 emit_move_insn (reg, y);
635 y = reg;
637 else
638 x = force_reg (in_mode, x);
640 pat = gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y));
641 if (mode == CC_FP_EQmode || mode == CC_FP_GTEmode)
643 const char *name = mode == CC_FP_EQmode ? "__eqsf2" : "__gtesf2";
644 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
646 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
647 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
648 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (4, pat, use, clob0, clob1));
650 else if (mode == CC_FP_ORDmode || mode == CC_FP_UNEQmode)
652 const char *name = mode == CC_FP_ORDmode ? "__ordsf2" : "__uneqsf2";
653 rtx use = gen_rtx_USE (VOIDmode, sfunc_symbol (name));
655 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_IP));
656 clob1 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_16));
657 clob2 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, GPR_LR));
658 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (5, pat, use,
659 clob0, clob1, clob2));
661 else
663 clob0 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (in_mode));
664 pat = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, pat, clob0));
666 emit_insn (pat);
667 return gen_rtx_fmt_ee (code, cmode, cc_reg, const0_rtx);
670 /* The ROUND_ADVANCE* macros are local to this file. */
671 /* Round SIZE up to a word boundary. */
672 #define ROUND_ADVANCE(SIZE) \
673 (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
675 /* Round arg MODE/TYPE up to the next word boundary. */
676 #define ROUND_ADVANCE_ARG(MODE, TYPE) \
677 ((MODE) == BLKmode \
678 ? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
679 : ROUND_ADVANCE (GET_MODE_SIZE (MODE)))
681 /* Round CUM up to the necessary point for argument MODE/TYPE. */
682 #define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \
683 (epiphany_function_arg_boundary ((MODE), (TYPE)) > BITS_PER_WORD \
684 ? (((CUM) + 1) & ~1) \
685 : (CUM))
687 static unsigned int
688 epiphany_function_arg_boundary (machine_mode mode, const_tree type)
690 if ((type ? TYPE_ALIGN (type) : GET_MODE_BITSIZE (mode)) <= PARM_BOUNDARY)
691 return PARM_BOUNDARY;
692 return 2 * PARM_BOUNDARY;
695 /* Do any needed setup for a variadic function. For the EPIPHANY, we
696 actually emit the code in epiphany_expand_prologue.
698 CUM has not been updated for the last named argument which has type TYPE
699 and mode MODE, and we rely on this fact. */
702 static void
703 epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
704 tree type, int *pretend_size, int no_rtl)
706 int first_anon_arg;
707 CUMULATIVE_ARGS next_cum;
708 machine_function_t *mf = MACHINE_FUNCTION (cfun);
710 /* All BLKmode values are passed by reference. */
711 gcc_assert (mode != BLKmode);
713 next_cum = *get_cumulative_args (cum);
714 next_cum
715 = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
716 first_anon_arg = next_cum;
718 if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
720 /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS. */
721 int first_reg_offset = first_anon_arg;
723 *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
724 * UNITS_PER_WORD);
726 mf->args_parsed = 1;
727 mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
730 static int
731 epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
732 tree type, bool named ATTRIBUTE_UNUSED)
734 int words = 0, rounded_cum;
736 gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
738 rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
739 if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
741 words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
742 if (words >= ROUND_ADVANCE_ARG (mode, type))
743 words = 0;
745 return words * UNITS_PER_WORD;
748 /* Cost functions. */
750 /* Compute a (partial) cost for rtx X. Return true if the complete
751 cost has been computed, and false if subexpressions should be
752 scanned. In either case, *TOTAL contains the cost result. */
754 static bool
755 epiphany_rtx_costs (rtx x, machine_mode mode, int outer_code,
756 int opno ATTRIBUTE_UNUSED,
757 int *total, bool speed ATTRIBUTE_UNUSED)
759 int code = GET_CODE (x);
761 switch (code)
763 /* Small integers in the right context are as cheap as registers. */
764 case CONST_INT:
765 if ((outer_code == PLUS || outer_code == MINUS)
766 && SIMM11 (INTVAL (x)))
768 *total = 0;
769 return true;
771 if (IMM16 (INTVAL (x)))
773 *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
774 return true;
776 /* FALLTHRU */
778 case CONST:
779 case LABEL_REF:
780 case SYMBOL_REF:
781 *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
782 + (outer_code == SET ? 0 : 1));
783 return true;
785 case CONST_DOUBLE:
787 rtx high, low;
788 split_double (x, &high, &low);
789 *total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
790 + !IMM16 (INTVAL (low)));
791 return true;
794 case ASHIFT:
795 case ASHIFTRT:
796 case LSHIFTRT:
797 *total = COSTS_N_INSNS (1);
798 return true;
800 case COMPARE:
801 switch (mode)
803 /* There are a number of single-insn combiner patterns that use
804 the flag side effects of arithmetic. */
805 case CC_N_NEmode:
806 case CC_C_LTUmode:
807 case CC_C_GTUmode:
808 return true;
809 default:
810 return false;
814 case SET:
816 rtx src = SET_SRC (x);
817 if (BINARY_P (src))
818 *total = 0;
819 return false;
822 default:
823 return false;
828 /* Provide the costs of an addressing mode that contains ADDR.
829 If ADDR is not a valid address, its cost is irrelevant. */
831 static int
832 epiphany_address_cost (rtx addr, machine_mode mode,
833 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
835 rtx reg;
836 rtx off = const0_rtx;
837 int i;
839 if (speed)
840 return 0;
841 /* Return 0 for addresses valid in short insns, 1 for addresses only valid
842 in long insns. */
843 switch (GET_CODE (addr))
845 case PLUS :
846 reg = XEXP (addr, 0);
847 off = XEXP (addr, 1);
848 break;
849 case POST_MODIFY:
850 reg = XEXP (addr, 0);
851 off = XEXP (addr, 1);
852 gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
853 off = XEXP (off, 1);
854 if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
855 return 0;
856 return 1;
857 case REG:
858 default:
859 reg = addr;
860 break;
862 if (!satisfies_constraint_Rgs (reg))
863 return 1;
864 /* The offset range available for short instructions depends on the mode
865 of the memory access. */
866 /* First, make sure we have a valid integer. */
867 if (!satisfies_constraint_L (off))
868 return 1;
869 i = INTVAL (off);
870 switch (GET_MODE_SIZE (mode))
872 default:
873 case 4:
874 if (i & 1)
875 return 1;
876 i >>= 1;
877 /* Fall through. */
878 case 2:
879 if (i & 1)
880 return 1;
881 i >>= 1;
882 /* Fall through. */
883 case 1:
884 return i < -7 || i > 7;
888 /* Compute the cost of moving data between registers and memory.
889 For integer, load latency is twice as long as register-register moves,
890 but issue pich is the same. For floating point, load latency is three
891 times as much as a reg-reg move. */
892 static int
893 epiphany_memory_move_cost (machine_mode mode,
894 reg_class_t rclass ATTRIBUTE_UNUSED,
895 bool in ATTRIBUTE_UNUSED)
897 return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
900 /* Function prologue/epilogue handlers. */
902 /* EPIPHANY stack frames look like:
904 Before call After call
905 +-----------------------+ +-----------------------+
906 | | | |
907 high | local variables, | | local variables, |
908 mem | reg save area, etc. | | reg save area, etc. |
909 | | | |
910 +-----------------------+ +-----------------------+
911 | | | |
912 | arguments on stack. | | arguments on stack. |
913 | | | |
914 SP+8->+-----------------------+FP+8m->+-----------------------+
915 | 2 word save area for | | reg parm save area, |
916 | leaf funcs / flags | | only created for |
917 SP+0->+-----------------------+ | variable argument |
918 | functions |
919 FP+8n->+-----------------------+
921 | register save area |
923 +-----------------------+
925 | local variables |
927 FP+0->+-----------------------+
929 | alloca allocations |
931 +-----------------------+
933 | arguments on stack |
935 SP+8->+-----------------------+
936 low | 2 word save area for |
937 memory | leaf funcs / flags |
938 SP+0->+-----------------------+
940 Notes:
941 1) The "reg parm save area" does not exist for non variable argument fns.
942 The "reg parm save area" could be eliminated if we created our
943 own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
944 (so it's not done). */
946 /* Structure to be filled in by epiphany_compute_frame_size with register
947 save masks, and offsets for the current function. */
948 struct epiphany_frame_info
950 unsigned int total_size; /* # bytes that the entire frame takes up. */
951 unsigned int pretend_size; /* # bytes we push and pretend caller did. */
952 unsigned int args_size; /* # bytes that outgoing arguments take up. */
953 unsigned int reg_size; /* # bytes needed to store regs. */
954 unsigned int var_size; /* # bytes that variables take up. */
955 HARD_REG_SET gmask; /* Set of saved gp registers. */
956 int initialized; /* Nonzero if frame size already calculated. */
957 int stld_sz; /* Current load/store data size for offset
958 adjustment. */
959 int need_fp; /* value to override "frame_pointer_needed */
960 /* FIRST_SLOT is the slot that is saved first, at the very start of
961 the frame, with a POST_MODIFY to allocate the frame, if the size fits,
962 or at least the parm and register save areas, otherwise.
963 In the case of a large frame, LAST_SLOT is the slot that is saved last,
964 with a POST_MODIFY to allocate the rest of the frame. */
965 int first_slot, last_slot, first_slot_offset, last_slot_offset;
966 int first_slot_size;
967 int small_threshold;
970 /* Current frame information calculated by epiphany_compute_frame_size. */
971 static struct epiphany_frame_info current_frame_info;
973 /* Zero structure to initialize current_frame_info. */
974 static struct epiphany_frame_info zero_frame_info;
976 /* The usual; we set up our machine_function data. */
977 static struct machine_function *
978 epiphany_init_machine_status (void)
980 struct machine_function *machine;
982 /* Reset state info for each function. */
983 current_frame_info = zero_frame_info;
985 machine = ggc_cleared_alloc<machine_function_t> ();
987 return machine;
990 /* Implements INIT_EXPANDERS. We just set up to call the above
991 * function. */
992 void
993 epiphany_init_expanders (void)
995 init_machine_status = epiphany_init_machine_status;
998 /* Type of function DECL.
1000 The result is cached. To reset the cache at the end of a function,
1001 call with DECL = NULL_TREE. */
1003 static enum epiphany_function_type
1004 epiphany_compute_function_type (tree decl)
1006 tree a;
1007 /* Cached value. */
1008 static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1009 /* Last function we were called for. */
1010 static tree last_fn = NULL_TREE;
1012 /* Resetting the cached value? */
1013 if (decl == NULL_TREE)
1015 fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1016 last_fn = NULL_TREE;
1017 return fn_type;
1020 if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
1021 return fn_type;
1023 /* Assume we have a normal function (not an interrupt handler). */
1024 fn_type = EPIPHANY_FUNCTION_NORMAL;
1026 /* Now see if this is an interrupt handler. */
1027 for (a = DECL_ATTRIBUTES (decl);
1029 a = TREE_CHAIN (a))
1031 tree name = TREE_PURPOSE (a);
1033 if (name == get_identifier ("interrupt"))
1034 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
1037 last_fn = decl;
1038 return fn_type;
1041 #define RETURN_ADDR_REGNUM GPR_LR
1042 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
1043 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
1045 /* Tell prologue and epilogue if register REGNO should be saved / restored.
1046 The return address and frame pointer are treated separately.
1047 Don't consider them here. */
1048 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
1049 ((df_regs_ever_live_p (regno) \
1050 || (interrupt_p && !crtl->is_leaf \
1051 && call_used_regs[regno] && !fixed_regs[regno])) \
1052 && (!call_used_regs[regno] || regno == GPR_LR \
1053 || (interrupt_p && regno != GPR_SP)))
1055 #define MUST_SAVE_RETURN_ADDR 0
1057 /* Return the bytes needed to compute the frame pointer from the current
1058 stack pointer.
1060 SIZE is the size needed for local variables. */
1062 static unsigned int
1063 epiphany_compute_frame_size (int size /* # of var. bytes allocated. */)
1065 int regno;
1066 unsigned int total_size, var_size, args_size, pretend_size, reg_size;
1067 HARD_REG_SET gmask;
1068 enum epiphany_function_type fn_type;
1069 int interrupt_p;
1070 int first_slot, last_slot, first_slot_offset, last_slot_offset;
1071 int first_slot_size;
1072 int small_slots = 0;
1074 var_size = size;
1075 args_size = crtl->outgoing_args_size;
1076 pretend_size = crtl->args.pretend_args_size;
1077 total_size = args_size + var_size;
1078 reg_size = 0;
1079 CLEAR_HARD_REG_SET (gmask);
1080 first_slot = -1;
1081 first_slot_offset = 0;
1082 last_slot = -1;
1083 last_slot_offset = 0;
1084 first_slot_size = UNITS_PER_WORD;
1086 /* See if this is an interrupt handler. Call used registers must be saved
1087 for them too. */
1088 fn_type = epiphany_compute_function_type (current_function_decl);
1089 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1091 /* Calculate space needed for registers. */
1093 for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
1095 reg_size += UNITS_PER_WORD;
1096 SET_HARD_REG_BIT (gmask, regno);
1097 if (epiphany_stack_offset - reg_size == 0)
1098 first_slot = regno;
1101 if (interrupt_p)
1102 reg_size += 2 * UNITS_PER_WORD;
1103 else
1104 small_slots = epiphany_stack_offset / UNITS_PER_WORD;
1106 if (frame_pointer_needed)
1108 current_frame_info.need_fp = 1;
1109 if (!interrupt_p && first_slot < 0)
1110 first_slot = GPR_FP;
1112 else
1113 current_frame_info.need_fp = 0;
1114 for (regno = 0; regno <= GPR_LAST; regno++)
1116 if (MUST_SAVE_REGISTER (regno, interrupt_p))
1118 gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1119 reg_size += UNITS_PER_WORD;
1120 SET_HARD_REG_BIT (gmask, regno);
1121 /* FIXME: when optimizing for speed, take schedling into account
1122 when selecting these registers. */
1123 if (regno == first_slot)
1124 gcc_assert (regno == GPR_FP && frame_pointer_needed);
1125 else if (!interrupt_p && first_slot < 0)
1126 first_slot = regno;
1127 else if (last_slot < 0
1128 && (first_slot ^ regno) != 1
1129 && (!interrupt_p || regno > GPR_1))
1130 last_slot = regno;
1133 if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1134 MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1135 /* ??? Could sometimes do better than that. */
1136 current_frame_info.small_threshold
1137 = (optimize >= 3 || interrupt_p ? 0
1138 : pretend_size ? small_slots
1139 : 4 + small_slots - (first_slot == GPR_FP));
1141 /* If there might be variables with 64-bit alignment requirement, align the
1142 start of the variables. */
1143 if (var_size >= 2 * UNITS_PER_WORD
1144 /* We don't want to split a double reg save/restore across two unpaired
1145 stack slots when optimizing. This rounding could be avoided with
1146 more complex reordering of the register saves, but that would seem
1147 to be a lot of code complexity for little gain. */
1148 || (reg_size > 8 && optimize))
1149 reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1150 if (((total_size + reg_size
1151 /* Reserve space for UNKNOWN_REGNUM. */
1152 + EPIPHANY_STACK_ALIGN (4))
1153 <= (unsigned) epiphany_stack_offset)
1154 && !interrupt_p
1155 && crtl->is_leaf && !frame_pointer_needed)
1157 first_slot = -1;
1158 last_slot = -1;
1159 goto alloc_done;
1161 else if (reg_size
1162 && !interrupt_p
1163 && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1164 reg_size = epiphany_stack_offset;
1165 if (interrupt_p)
1167 if (total_size + reg_size < 0x3fc)
1169 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1170 first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1171 last_slot = -1;
1173 else
1175 first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1176 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1177 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1178 if (last_slot >= 0)
1179 CLEAR_HARD_REG_BIT (gmask, last_slot);
1182 else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1184 first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1185 last_slot = -1;
1187 else
1189 if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1191 gcc_assert (first_slot < 0);
1192 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset);
1193 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1195 else
1197 first_slot_offset
1198 = (reg_size
1199 ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1200 if (!first_slot_offset)
1202 if (first_slot != GPR_FP || !current_frame_info.need_fp)
1203 last_slot = first_slot;
1204 first_slot = -1;
1206 last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1207 if (reg_size)
1208 last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1210 if (last_slot >= 0)
1211 CLEAR_HARD_REG_BIT (gmask, last_slot);
1213 alloc_done:
1214 if (first_slot >= 0)
1216 CLEAR_HARD_REG_BIT (gmask, first_slot);
1217 if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1218 && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1220 CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1221 first_slot_size = 2 * UNITS_PER_WORD;
1222 first_slot &= ~1;
1225 total_size = first_slot_offset + last_slot_offset;
1227 /* Save computed information. */
1228 current_frame_info.total_size = total_size;
1229 current_frame_info.pretend_size = pretend_size;
1230 current_frame_info.var_size = var_size;
1231 current_frame_info.args_size = args_size;
1232 current_frame_info.reg_size = reg_size;
1233 COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1234 current_frame_info.first_slot = first_slot;
1235 current_frame_info.last_slot = last_slot;
1236 current_frame_info.first_slot_offset = first_slot_offset;
1237 current_frame_info.first_slot_size = first_slot_size;
1238 current_frame_info.last_slot_offset = last_slot_offset;
1240 current_frame_info.initialized = reload_completed;
1242 /* Ok, we're done. */
1243 return total_size;
1246 /* Print operand X (an rtx) in assembler syntax to file FILE.
1247 CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1248 For `%' followed by punctuation, CODE is the punctuation and X is null. */
1250 static void
1251 epiphany_print_operand (FILE *file, rtx x, int code)
1253 switch (code)
1255 case 'd':
1256 fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1257 return;
1258 case 'D':
1259 fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1260 (get_epiphany_condition_code (x))],
1261 file);
1262 return;
1264 case 'X':
1265 current_frame_info.stld_sz = 8;
1266 break;
1268 case 'C' :
1269 current_frame_info.stld_sz = 4;
1270 break;
1272 case 'c' :
1273 current_frame_info.stld_sz = 2;
1274 break;
1276 case 'f':
1277 fputs (REG_P (x) ? "jalr " : "bl ", file);
1278 break;
1280 case '-':
1281 fprintf (file, "r%d", epiphany_m1reg);
1282 return;
1284 case 0 :
1285 /* Do nothing special. */
1286 break;
1287 default :
1288 /* Unknown flag. */
1289 output_operand_lossage ("invalid operand output code");
1292 switch (GET_CODE (x))
1294 rtx addr;
1295 rtx offset;
1297 case REG :
1298 fputs (reg_names[REGNO (x)], file);
1299 break;
1300 case MEM :
1301 if (code == 0)
1302 current_frame_info.stld_sz = 1;
1303 fputc ('[', file);
1304 addr = XEXP (x, 0);
1305 switch (GET_CODE (addr))
1307 case POST_INC:
1308 offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1309 addr = XEXP (addr, 0);
1310 break;
1311 case POST_DEC:
1312 offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1313 addr = XEXP (addr, 0);
1314 break;
1315 case POST_MODIFY:
1316 offset = XEXP (XEXP (addr, 1), 1);
1317 addr = XEXP (addr, 0);
1318 break;
1319 default:
1320 offset = 0;
1321 break;
1323 output_address (GET_MODE (x), addr);
1324 fputc (']', file);
1325 if (offset)
1327 fputc (',', file);
1328 if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1330 default:
1331 gcc_unreachable ();
1332 case 8:
1333 offset = GEN_INT (INTVAL (offset) >> 3);
1334 break;
1335 case 4:
1336 offset = GEN_INT (INTVAL (offset) >> 2);
1337 break;
1338 case 2:
1339 offset = GEN_INT (INTVAL (offset) >> 1);
1340 break;
1341 case 1:
1342 break;
1344 output_address (GET_MODE (x), offset);
1346 break;
1347 case CONST_DOUBLE :
1348 /* We handle SFmode constants here as output_addr_const doesn't. */
1349 if (GET_MODE (x) == SFmode)
1351 long l;
1353 REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l);
1354 fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1355 break;
1357 /* FALLTHRU */
1358 /* Let output_addr_const deal with it. */
1359 case CONST_INT:
1360 fprintf(file,"%s",IMMEDIATE_PREFIX);
1361 if (code == 'C' || code == 'X')
1363 fprintf (file, "%ld",
1364 (long) (INTVAL (x) / current_frame_info.stld_sz));
1365 break;
1367 /* Fall through */
1368 default :
1369 output_addr_const (file, x);
1370 break;
1374 /* Print a memory address as an operand to reference that memory location. */
1376 static void
1377 epiphany_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr)
1379 register rtx base, index = 0;
1380 int offset = 0;
1382 switch (GET_CODE (addr))
1384 case REG :
1385 fputs (reg_names[REGNO (addr)], file);
1386 break;
1387 case SYMBOL_REF :
1388 if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1390 output_addr_const (file, addr);
1392 else
1394 output_addr_const (file, addr);
1396 break;
1397 case PLUS :
1398 if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1399 offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1400 else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1401 offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1402 else
1403 base = XEXP (addr, 0), index = XEXP (addr, 1);
1404 gcc_assert (GET_CODE (base) == REG);
1405 fputs (reg_names[REGNO (base)], file);
1406 if (index == 0)
1409 ** ++rk quirky method to scale offset for ld/str.......
1411 fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1412 offset/current_frame_info.stld_sz);
1414 else
1416 switch (GET_CODE (index))
1418 case REG:
1419 fprintf (file, ",%s", reg_names[REGNO (index)]);
1420 break;
1421 case SYMBOL_REF:
1422 fputc (',', file), output_addr_const (file, index);
1423 break;
1424 default:
1425 gcc_unreachable ();
1428 break;
1429 case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1430 /* We shouldn't get here as we've lost the mode of the memory object
1431 (which says how much to inc/dec by.
1432 FIXME: We have the mode now, address printing can be moved into this
1433 function. */
1434 gcc_unreachable ();
1435 break;
1436 default:
1437 output_addr_const (file, addr);
1438 break;
1442 void
1443 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED,
1444 rtx *opvec ATTRIBUTE_UNUSED,
1445 int noperands ATTRIBUTE_UNUSED)
1447 int i = epiphany_n_nops;
1448 rtx pat ATTRIBUTE_UNUSED;
1450 while (i--)
1451 fputs ("\tnop\n", asm_out_file);
1455 /* Worker function for TARGET_RETURN_IN_MEMORY. */
1457 static bool
1458 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1460 HOST_WIDE_INT size = int_size_in_bytes (type);
1462 if (AGGREGATE_TYPE_P (type)
1463 && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1464 return true;
1465 return (size == -1 || size > 8);
1468 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1469 passed by reference. */
1471 static bool
1472 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1473 machine_mode mode, const_tree type,
1474 bool named ATTRIBUTE_UNUSED)
1476 if (type)
1478 if (AGGREGATE_TYPE_P (type)
1479 && (mode == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1480 return true;
1482 return false;
1486 static rtx
1487 epiphany_function_value (const_tree ret_type,
1488 const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
1489 bool outgoing ATTRIBUTE_UNUSED)
1491 machine_mode mode;
1493 mode = TYPE_MODE (ret_type);
1494 /* We must change the mode like PROMOTE_MODE does.
1495 ??? PROMOTE_MODE is ignored for non-scalar types.
1496 The set of types tested here has to be kept in sync
1497 with the one in explow.c:promote_mode. */
1498 if (GET_MODE_CLASS (mode) == MODE_INT
1499 && GET_MODE_SIZE (mode) < 4
1500 && (TREE_CODE (ret_type) == INTEGER_TYPE
1501 || TREE_CODE (ret_type) == ENUMERAL_TYPE
1502 || TREE_CODE (ret_type) == BOOLEAN_TYPE
1503 || TREE_CODE (ret_type) == OFFSET_TYPE))
1504 mode = SImode;
1505 return gen_rtx_REG (mode, 0);
1508 static rtx
1509 epiphany_libcall_value (machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED)
1511 return gen_rtx_REG (mode, 0);
1514 static bool
1515 epiphany_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED)
1517 return regno == 0;
1520 /* Fix up invalid option settings. */
1521 static void
1522 epiphany_override_options (void)
1524 if (epiphany_stack_offset < 4)
1525 error ("stack_offset must be at least 4");
1526 if (epiphany_stack_offset & 3)
1527 error ("stack_offset must be a multiple of 4");
1528 epiphany_stack_offset = (epiphany_stack_offset + 3) & -4;
1529 if (!TARGET_SOFT_CMPSF)
1530 flag_finite_math_only = 1;
1532 /* This needs to be done at start up. It's convenient to do it here. */
1533 epiphany_init ();
1536 /* For a DImode load / store SET, make a SImode set for a
1537 REG_FRAME_RELATED_EXPR note, using OFFSET to create a high or lowpart
1538 subreg. */
1539 static rtx
1540 frame_subreg_note (rtx set, int offset)
1542 rtx src = simplify_gen_subreg (SImode, SET_SRC (set), DImode, offset);
1543 rtx dst = simplify_gen_subreg (SImode, SET_DEST (set), DImode, offset);
1545 set = gen_rtx_SET (dst ,src);
1546 RTX_FRAME_RELATED_P (set) = 1;
1547 return set;
1550 static rtx_insn *
1551 frame_insn (rtx x)
1553 int i;
1554 rtx note = NULL_RTX;
1555 rtx_insn *insn;
1557 if (GET_CODE (x) == PARALLEL)
1559 rtx part = XVECEXP (x, 0, 0);
1561 if (GET_MODE (SET_DEST (part)) == DImode)
1563 note = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (XVECLEN (x, 0) + 1));
1564 XVECEXP (note, 0, 0) = frame_subreg_note (part, 0);
1565 XVECEXP (note, 0, 1) = frame_subreg_note (part, UNITS_PER_WORD);
1566 for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
1568 part = copy_rtx (XVECEXP (x, 0, i));
1570 if (GET_CODE (part) == SET)
1571 RTX_FRAME_RELATED_P (part) = 1;
1572 XVECEXP (note, 0, i + 1) = part;
1575 else
1577 for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
1579 part = XVECEXP (x, 0, i);
1581 if (GET_CODE (part) == SET)
1582 RTX_FRAME_RELATED_P (part) = 1;
1586 else if (GET_CODE (x) == SET && GET_MODE (SET_DEST (x)) == DImode)
1587 note = gen_rtx_PARALLEL (VOIDmode,
1588 gen_rtvec (2, frame_subreg_note (x, 0),
1589 frame_subreg_note (x, UNITS_PER_WORD)));
1590 insn = emit_insn (x);
1591 RTX_FRAME_RELATED_P (insn) = 1;
1592 if (note)
1593 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1594 return insn;
1597 static rtx_insn *
1598 frame_move_insn (rtx to, rtx from)
1600 return frame_insn (gen_rtx_SET (to, from));
1603 /* Generate a MEM referring to a varargs argument slot. */
1605 static rtx
1606 gen_varargs_mem (machine_mode mode, rtx addr)
1608 rtx mem = gen_rtx_MEM (mode, addr);
1609 MEM_NOTRAP_P (mem) = 1;
1610 set_mem_alias_set (mem, get_varargs_alias_set ());
1611 return mem;
1614 /* Emit instructions to save or restore registers in the range [MIN..LIMIT) .
1615 If EPILOGUE_P is 0, save; if it is one, restore.
1616 ADDR is the stack slot to save the first register to; subsequent
1617 registers are written to lower addresses.
1618 However, the order of register pairs can be reversed in order to
1619 use double-word load-store instructions. Likewise, an unpaired single
1620 word save slot can be skipped while double saves are carried out, and
1621 reused when a single register is to be saved. */
1623 static void
1624 epiphany_emit_save_restore (int min, int limit, rtx addr, int epilogue_p)
1626 int i;
1627 int stack_offset
1628 = current_frame_info.first_slot >= 0 ? epiphany_stack_offset : 0;
1629 rtx skipped_mem = NULL_RTX;
1630 int last_saved = limit - 1;
1632 if (!optimize)
1633 while (last_saved >= 0
1634 && !TEST_HARD_REG_BIT (current_frame_info.gmask, last_saved))
1635 last_saved--;
1636 for (i = 0; i < limit; i++)
1638 machine_mode mode = word_mode;
1639 rtx mem, reg;
1640 int n = i;
1641 rtx (*gen_mem) (machine_mode, rtx) = gen_frame_mem;
1643 /* Make sure we push the arguments in the right order. */
1644 if (n < MAX_EPIPHANY_PARM_REGS && crtl->args.pretend_args_size)
1646 n = MAX_EPIPHANY_PARM_REGS - 1 - n;
1647 gen_mem = gen_varargs_mem;
1649 if (stack_offset == current_frame_info.first_slot_size
1650 && current_frame_info.first_slot >= 0)
1652 if (current_frame_info.first_slot_size > UNITS_PER_WORD)
1654 mode = DImode;
1655 addr = plus_constant (Pmode, addr,
1656 - (HOST_WIDE_INT) UNITS_PER_WORD);
1658 if (i-- < min || !epilogue_p)
1659 goto next_slot;
1660 n = current_frame_info.first_slot;
1661 gen_mem = gen_frame_mem;
1663 else if (n == UNKNOWN_REGNUM
1664 && stack_offset > current_frame_info.first_slot_size)
1666 i--;
1667 goto next_slot;
1669 else if (!TEST_HARD_REG_BIT (current_frame_info.gmask, n))
1670 continue;
1671 else if (i < min)
1672 goto next_slot;
1674 /* Check for a register pair to save. */
1675 if (n == i
1676 && (n >= MAX_EPIPHANY_PARM_REGS || crtl->args.pretend_args_size == 0)
1677 && (n & 1) == 0 && n+1 < limit
1678 && TEST_HARD_REG_BIT (current_frame_info.gmask, n+1))
1680 /* If it fits in the current stack slot pair, place it there. */
1681 if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 0
1682 && stack_offset != 2 * UNITS_PER_WORD
1683 && (current_frame_info.last_slot < 0
1684 || INTVAL (XEXP (addr, 1)) != UNITS_PER_WORD)
1685 && (n+1 != last_saved || !skipped_mem))
1687 mode = DImode;
1688 i++;
1689 addr = plus_constant (Pmode, addr,
1690 - (HOST_WIDE_INT) UNITS_PER_WORD);
1692 /* If it fits in the following stack slot pair, that's fine, too. */
1693 else if (GET_CODE (addr) == PLUS && (stack_offset & 7) == 4
1694 && stack_offset != 2 * UNITS_PER_WORD
1695 && stack_offset != 3 * UNITS_PER_WORD
1696 && (current_frame_info.last_slot < 0
1697 || INTVAL (XEXP (addr, 1)) != 2 * UNITS_PER_WORD)
1698 && n + 1 != last_saved)
1700 gcc_assert (!skipped_mem);
1701 stack_offset -= GET_MODE_SIZE (mode);
1702 skipped_mem = gen_mem (mode, addr);
1703 mode = DImode;
1704 i++;
1705 addr = plus_constant (Pmode, addr,
1706 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1709 reg = gen_rtx_REG (mode, n);
1710 if (mode != DImode && skipped_mem)
1711 mem = skipped_mem;
1712 else
1713 mem = gen_mem (mode, addr);
1715 /* If we are loading / storing LR, note the offset that
1716 gen_reload_insi_ra requires. Since GPR_LR is even,
1717 we only need to test n, even if mode is DImode. */
1718 gcc_assert ((GPR_LR & 1) == 0);
1719 if (n == GPR_LR)
1721 long lr_slot_offset = 0;
1722 rtx m_addr = XEXP (mem, 0);
1724 if (GET_CODE (m_addr) == PLUS)
1725 lr_slot_offset = INTVAL (XEXP (m_addr, 1));
1726 if (frame_pointer_needed)
1727 lr_slot_offset += (current_frame_info.first_slot_offset
1728 - current_frame_info.total_size);
1729 if (MACHINE_FUNCTION (cfun)->lr_slot_known)
1730 gcc_assert (MACHINE_FUNCTION (cfun)->lr_slot_offset
1731 == lr_slot_offset);
1732 MACHINE_FUNCTION (cfun)->lr_slot_offset = lr_slot_offset;
1733 MACHINE_FUNCTION (cfun)->lr_slot_known = 1;
1736 if (!epilogue_p)
1737 frame_move_insn (mem, reg);
1738 else if (n >= MAX_EPIPHANY_PARM_REGS || !crtl->args.pretend_args_size)
1739 emit_move_insn (reg, mem);
1740 if (mem == skipped_mem)
1742 skipped_mem = NULL_RTX;
1743 continue;
1745 next_slot:
1746 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
1747 stack_offset -= GET_MODE_SIZE (mode);
1751 void
1752 epiphany_expand_prologue (void)
1754 int interrupt_p;
1755 enum epiphany_function_type fn_type;
1756 rtx addr, mem, off, reg;
1758 if (!current_frame_info.initialized)
1759 epiphany_compute_frame_size (get_frame_size ());
1761 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1762 if (flag_stack_usage_info)
1763 current_function_static_stack_size = current_frame_info.total_size;
1765 fn_type = epiphany_compute_function_type (current_function_decl);
1766 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1768 if (interrupt_p)
1770 addr = plus_constant (Pmode, stack_pointer_rtx,
1771 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1772 if (!lookup_attribute ("forwarder_section",
1773 DECL_ATTRIBUTES (current_function_decl))
1774 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1775 0)))
1776 frame_move_insn (gen_frame_mem (DImode, addr),
1777 gen_rtx_REG (DImode, GPR_0));
1778 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1779 gen_rtx_REG (word_mode, STATUS_REGNUM));
1780 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
1781 gen_rtx_REG (word_mode, IRET_REGNUM));
1782 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1783 off = GEN_INT (-current_frame_info.first_slot_offset);
1784 frame_insn (gen_stack_adjust_add (off, mem));
1785 if (!epiphany_uninterruptible_p (current_function_decl))
1786 emit_insn (gen_gie ());
1787 addr = plus_constant (Pmode, stack_pointer_rtx,
1788 current_frame_info.first_slot_offset
1789 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1791 else
1793 addr = plus_constant (Pmode, stack_pointer_rtx,
1794 epiphany_stack_offset
1795 - (HOST_WIDE_INT) UNITS_PER_WORD);
1796 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1797 addr, 0);
1798 /* Allocate register save area; for small to medium size frames,
1799 allocate the entire frame; this is joint with one register save. */
1800 if (current_frame_info.first_slot >= 0)
1802 machine_mode mode
1803 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1804 ? word_mode : DImode);
1806 off = GEN_INT (-current_frame_info.first_slot_offset);
1807 mem = gen_frame_mem (BLKmode,
1808 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1809 frame_insn (gen_stack_adjust_str
1810 (gen_frame_mem (mode, stack_pointer_rtx),
1811 gen_rtx_REG (mode, current_frame_info.first_slot),
1812 off, mem));
1813 addr = plus_constant (Pmode, addr,
1814 current_frame_info.first_slot_offset);
1817 epiphany_emit_save_restore (current_frame_info.small_threshold,
1818 FIRST_PSEUDO_REGISTER, addr, 0);
1819 if (current_frame_info.need_fp)
1820 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1821 /* For large frames, allocate bulk of frame. This is usually joint with one
1822 register save. */
1823 if (current_frame_info.last_slot >= 0)
1825 rtx ip, mem2, note;
1826 rtx_insn *insn;
1828 gcc_assert (current_frame_info.last_slot != GPR_FP
1829 || (!current_frame_info.need_fp
1830 && current_frame_info.first_slot < 0));
1831 off = GEN_INT (-current_frame_info.last_slot_offset);
1832 mem = gen_frame_mem (BLKmode,
1833 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1834 ip = gen_rtx_REG (Pmode, GPR_IP);
1835 frame_move_insn (ip, off);
1836 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1837 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1838 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1839 /* Instruction scheduling can separate the instruction setting IP from
1840 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1841 temporary register is. Example: _gcov.o */
1842 note = gen_rtx_SET (stack_pointer_rtx,
1843 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1844 note = gen_rtx_PARALLEL (VOIDmode,
1845 gen_rtvec (2, gen_rtx_SET (mem2, reg), note));
1846 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
1848 /* If there is only one or no register to save, yet we have a large frame,
1849 use an add. */
1850 else if (current_frame_info.last_slot_offset)
1852 mem = gen_frame_mem (BLKmode,
1853 plus_constant (Pmode, stack_pointer_rtx,
1854 current_frame_info.last_slot_offset));
1855 off = GEN_INT (-current_frame_info.last_slot_offset);
1856 if (!SIMM11 (INTVAL (off)))
1858 reg = gen_rtx_REG (Pmode, GPR_IP);
1859 frame_move_insn (reg, off);
1860 off = reg;
1862 frame_insn (gen_stack_adjust_add (off, mem));
1866 void
1867 epiphany_expand_epilogue (int sibcall_p)
1869 int interrupt_p;
1870 enum epiphany_function_type fn_type;
1871 rtx mem, addr, reg, off;
1872 HOST_WIDE_INT restore_offset;
1874 fn_type = epiphany_compute_function_type( current_function_decl);
1875 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1877 /* For variable frames, deallocate bulk of frame. */
1878 if (current_frame_info.need_fp)
1880 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1881 emit_insn (gen_stack_adjust_mov (mem));
1883 /* Else for large static frames, deallocate bulk of frame. */
1884 else if (current_frame_info.last_slot_offset)
1886 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1887 reg = gen_rtx_REG (Pmode, GPR_IP);
1888 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1889 emit_insn (gen_stack_adjust_add (reg, mem));
1891 restore_offset = (interrupt_p
1892 ? - 3 * UNITS_PER_WORD
1893 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1894 addr = plus_constant (Pmode, stack_pointer_rtx,
1895 (current_frame_info.first_slot_offset
1896 + restore_offset));
1897 epiphany_emit_save_restore (current_frame_info.small_threshold,
1898 FIRST_PSEUDO_REGISTER, addr, 1);
1900 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1901 emit_insn (gen_gid ());
1903 off = GEN_INT (current_frame_info.first_slot_offset);
1904 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1905 /* For large / variable size frames, deallocating the register save area is
1906 joint with one register restore; for medium size frames, we use a
1907 dummy post-increment load to dealloacte the whole frame. */
1908 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1910 emit_insn (gen_stack_adjust_ldr
1911 (gen_rtx_REG (word_mode,
1912 (current_frame_info.last_slot >= 0
1913 ? current_frame_info.last_slot : GPR_IP)),
1914 gen_frame_mem (word_mode, stack_pointer_rtx),
1915 off,
1916 mem));
1918 /* While for small frames, we deallocate the entire frame with one add. */
1919 else if (INTVAL (off))
1921 emit_insn (gen_stack_adjust_add (off, mem));
1923 if (interrupt_p)
1925 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1926 gen_rtx_REG (SImode, GPR_0));
1927 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
1928 gen_rtx_REG (SImode, GPR_1));
1929 addr = plus_constant (Pmode, stack_pointer_rtx,
1930 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
1931 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1932 gen_frame_mem (DImode, addr));
1934 addr = plus_constant (Pmode, stack_pointer_rtx,
1935 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1936 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1937 if (!sibcall_p)
1939 if (interrupt_p)
1940 emit_jump_insn (gen_return_internal_interrupt());
1941 else
1942 emit_jump_insn (gen_return_i ());
1947 epiphany_initial_elimination_offset (int from, int to)
1949 epiphany_compute_frame_size (get_frame_size ());
1950 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1951 return current_frame_info.total_size - current_frame_info.reg_size;
1952 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1953 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1954 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1955 return (current_frame_info.total_size
1956 - ((current_frame_info.pretend_size + 4) & -8));
1957 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1958 return (current_frame_info.first_slot_offset
1959 - ((current_frame_info.pretend_size + 4) & -8));
1960 gcc_unreachable ();
1963 bool
1964 epiphany_regno_rename_ok (unsigned, unsigned dst)
1966 enum epiphany_function_type fn_type;
1968 fn_type = epiphany_compute_function_type (current_function_decl);
1969 if (!EPIPHANY_INTERRUPT_P (fn_type))
1970 return true;
1971 if (df_regs_ever_live_p (dst))
1972 return true;
1973 return false;
1976 static int
1977 epiphany_issue_rate (void)
1979 return 2;
1982 /* Function to update the integer COST
1983 based on the relationship between INSN that is dependent on
1984 DEP_INSN through the dependence LINK. The default is to make no
1985 adjustment to COST. This can be used for example to specify to
1986 the scheduler that an output- or anti-dependence does not incur
1987 the same cost as a data-dependence. The return value should be
1988 the new value for COST. */
1989 static int
1990 epiphany_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
1991 int cost, unsigned int)
1993 if (dep_type == 0)
1995 rtx dep_set;
1997 if (recog_memoized (insn) < 0
1998 || recog_memoized (dep_insn) < 0)
1999 return cost;
2001 dep_set = single_set (dep_insn);
2003 /* The latency that we specify in the scheduling description refers
2004 to the actual output, not to an auto-increment register; for that,
2005 the latency is one. */
2006 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
2008 rtx set = single_set (insn);
2010 if (set
2011 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
2012 && (!MEM_P (SET_DEST (set))
2013 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
2014 XEXP (SET_DEST (set), 0))))
2015 cost = 1;
2018 return cost;
2021 #define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
2023 #define RTX_OK_FOR_BASE_P(X) \
2024 (REG_P (X) && REG_OK_FOR_BASE_P (X))
2026 #define RTX_OK_FOR_INDEX_P(MODE, X) \
2027 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
2028 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
2029 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
2031 #define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
2032 (GET_CODE (X) == PLUS \
2033 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
2034 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
2035 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
2037 static bool
2038 epiphany_legitimate_address_p (machine_mode mode, rtx x, bool strict)
2040 #define REG_OK_FOR_BASE_P(X) \
2041 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
2042 if (RTX_OK_FOR_BASE_P (x))
2043 return true;
2044 if (RTX_FRAME_OFFSET_P (x))
2045 return true;
2046 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
2047 return true;
2048 /* If this is a misaligned stack access, don't force it to reg+index. */
2049 if (GET_MODE_SIZE (mode) == 8
2050 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
2051 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
2052 && !(INTVAL (XEXP (x, 1)) & 3)
2053 && INTVAL (XEXP (x, 1)) >= -2047 * 4
2054 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
2055 return true;
2056 if (TARGET_POST_INC
2057 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
2058 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
2059 return true;
2060 if ((TARGET_POST_MODIFY || reload_completed)
2061 && GET_CODE (x) == POST_MODIFY
2062 && GET_CODE (XEXP ((x), 1)) == PLUS
2063 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
2064 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
2065 return true;
2066 if (mode == BLKmode)
2067 return epiphany_legitimate_address_p (SImode, x, strict);
2068 return false;
2071 static reg_class_t
2072 epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
2073 machine_mode mode ATTRIBUTE_UNUSED,
2074 secondary_reload_info *sri)
2076 /* This could give more reload inheritance, but we are missing some
2077 reload infrastructure. */
2078 if (0)
2079 if (in_p && GET_CODE (x) == UNSPEC
2080 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
2082 gcc_assert (rclass == GENERAL_REGS);
2083 sri->icode = CODE_FOR_reload_insi_ra;
2084 return NO_REGS;
2086 return NO_REGS;
2089 bool
2090 epiphany_is_long_call_p (rtx x)
2092 tree decl = SYMBOL_REF_DECL (x);
2093 bool ret_val = !TARGET_SHORT_CALLS;
2094 tree attrs;
2096 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2097 probably encode information via encode_section_info, and also
2098 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2099 into account. */
2100 if (decl)
2102 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
2103 if (lookup_attribute ("long_call", attrs))
2104 ret_val = true;
2105 else if (lookup_attribute ("short_call", attrs))
2106 ret_val = false;
2108 return ret_val;
2111 bool
2112 epiphany_small16 (rtx x)
2114 rtx base = x;
2115 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2117 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2119 base = XEXP (XEXP (x, 0), 0);
2120 offs = XEXP (XEXP (x, 0), 1);
2122 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2123 && epiphany_is_long_call_p (base))
2124 return false;
2125 return TARGET_SMALL16 != 0;
2128 /* Return nonzero if it is ok to make a tail-call to DECL. */
2129 static bool
2130 epiphany_function_ok_for_sibcall (tree decl, tree exp)
2132 bool cfun_interrupt_p, call_interrupt_p;
2134 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2135 (current_function_decl));
2136 if (decl)
2137 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2138 else
2140 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2142 gcc_assert (POINTER_TYPE_P (fn_type));
2143 fn_type = TREE_TYPE (fn_type);
2144 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2145 || TREE_CODE (fn_type) == METHOD_TYPE);
2146 call_interrupt_p
2147 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2150 /* Don't tailcall from or to an ISR routine - although we could in
2151 principle tailcall from one ISR routine to another, we'd need to
2152 handle this in sibcall_epilogue to make it work. */
2153 if (cfun_interrupt_p || call_interrupt_p)
2154 return false;
2156 /* Everything else is ok. */
2157 return true;
2160 /* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2161 expander.
2162 Return true iff the type of T has the uninterruptible attribute.
2163 If T is NULL, return false. */
2164 bool
2165 epiphany_uninterruptible_p (tree t)
2167 tree attrs;
2169 if (t)
2171 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2172 if (lookup_attribute ("disinterrupt", attrs))
2173 return true;
2175 return false;
2178 bool
2179 epiphany_call_uninterruptible_p (rtx mem)
2181 rtx addr = XEXP (mem, 0);
2182 tree t = NULL_TREE;
2184 if (GET_CODE (addr) == SYMBOL_REF)
2185 t = SYMBOL_REF_DECL (addr);
2186 if (!t)
2187 t = MEM_EXPR (mem);
2188 return epiphany_uninterruptible_p (t);
2191 static machine_mode
2192 epiphany_promote_function_mode (const_tree type, machine_mode mode,
2193 int *punsignedp ATTRIBUTE_UNUSED,
2194 const_tree funtype ATTRIBUTE_UNUSED,
2195 int for_return ATTRIBUTE_UNUSED)
2197 int dummy;
2199 return promote_mode (type, mode, &dummy);
2202 static void
2203 epiphany_conditional_register_usage (void)
2205 int i;
2207 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2209 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2210 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2212 if (TARGET_HALF_REG_FILE)
2214 for (i = 32; i <= 63; i++)
2216 fixed_regs[i] = 1;
2217 call_used_regs[i] = 1;
2220 if (epiphany_m1reg >= 0)
2222 fixed_regs[epiphany_m1reg] = 1;
2223 call_used_regs[epiphany_m1reg] = 1;
2225 if (!TARGET_PREFER_SHORT_INSN_REGS)
2226 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2227 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2228 reg_class_contents[GENERAL_REGS]);
2229 /* It would be simpler and quicker if we could just use
2230 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2231 it is set up later by our caller. */
2232 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2233 if (!call_used_regs[i])
2234 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2237 /* Determine where to put an argument to a function.
2238 Value is zero to push the argument on the stack,
2239 or a hard register in which to store the argument.
2241 MODE is the argument's machine mode.
2242 TYPE is the data type of the argument (as a tree).
2243 This is null for libcalls where that information may
2244 not be available.
2245 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2246 the preceding args and about the function being called.
2247 NAMED is nonzero if this argument is a named parameter
2248 (otherwise it is an extra parameter matching an ellipsis). */
2249 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2250 registers and the rest are pushed. */
2251 static rtx
2252 epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode,
2253 const_tree type, bool named ATTRIBUTE_UNUSED)
2255 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2257 if (PASS_IN_REG_P (cum, mode, type))
2258 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2259 return 0;
2262 /* Update the data in CUM to advance over an argument
2263 of mode MODE and data type TYPE.
2264 (TYPE is null for libcalls where that information may not be available.) */
2265 static void
2266 epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
2267 const_tree type, bool named ATTRIBUTE_UNUSED)
2269 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2271 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2274 /* Nested function support.
2275 An epiphany trampoline looks like this:
2276 mov r16,%low(fnaddr)
2277 movt r16,%high(fnaddr)
2278 mov ip,%low(cxt)
2279 movt ip,%high(cxt)
2280 jr r16 */
2282 #define EPIPHANY_LOW_RTX(X) \
2283 (gen_rtx_IOR (SImode, \
2284 gen_rtx_ASHIFT (SImode, \
2285 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2286 gen_rtx_ASHIFT (SImode, \
2287 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2288 #define EPIPHANY_HIGH_RTX(X) \
2289 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2291 /* Emit RTL insns to initialize the variable parts of a trampoline.
2292 FNADDR is an RTX for the address of the function's pure code.
2293 CXT is an RTX for the static chain value for the function. */
2294 static void
2295 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2297 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2298 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2300 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2301 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2302 EPIPHANY_LOW_RTX (fnaddr)));
2303 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2304 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2305 EPIPHANY_HIGH_RTX (fnaddr)));
2306 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2307 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2308 EPIPHANY_LOW_RTX (cxt)));
2309 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2310 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2311 EPIPHANY_HIGH_RTX (cxt)));
2312 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2313 GEN_INT (0x0802014f));
2316 bool
2317 epiphany_optimize_mode_switching (int entity)
2319 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2320 return false;
2321 switch (entity)
2323 case EPIPHANY_MSW_ENTITY_AND:
2324 case EPIPHANY_MSW_ENTITY_OR:
2325 case EPIPHANY_MSW_ENTITY_CONFIG:
2326 return true;
2327 case EPIPHANY_MSW_ENTITY_NEAREST:
2328 case EPIPHANY_MSW_ENTITY_TRUNC:
2329 return optimize > 0;
2330 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2331 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2332 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2333 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2334 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2335 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2336 return optimize == 0 || current_pass == pass_mode_switch_use;
2338 gcc_unreachable ();
2341 static int
2342 epiphany_mode_priority (int entity, int priority)
2344 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2345 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2346 return priority;
2347 if (priority > 3)
2348 switch (priority)
2350 case 4: return FP_MODE_ROUND_UNKNOWN;
2351 case 5: return FP_MODE_NONE;
2352 default: gcc_unreachable ();
2354 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2356 case FP_MODE_INT:
2357 switch (priority)
2359 case 0: return FP_MODE_INT;
2360 case 1: return epiphany_normal_fp_rounding;
2361 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2362 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2363 case 3: return FP_MODE_CALLER;
2365 case FP_MODE_ROUND_NEAREST:
2366 case FP_MODE_CALLER:
2367 switch (priority)
2369 case 0: return FP_MODE_ROUND_NEAREST;
2370 case 1: return FP_MODE_ROUND_TRUNC;
2371 case 2: return FP_MODE_INT;
2372 case 3: return FP_MODE_CALLER;
2374 case FP_MODE_ROUND_TRUNC:
2375 switch (priority)
2377 case 0: return FP_MODE_ROUND_TRUNC;
2378 case 1: return FP_MODE_ROUND_NEAREST;
2379 case 2: return FP_MODE_INT;
2380 case 3: return FP_MODE_CALLER;
2382 case FP_MODE_ROUND_UNKNOWN:
2383 case FP_MODE_NONE:
2384 gcc_unreachable ();
2386 gcc_unreachable ();
2390 epiphany_mode_needed (int entity, rtx_insn *insn)
2392 enum attr_fp_mode mode;
2394 if (recog_memoized (insn) < 0)
2396 if (entity == EPIPHANY_MSW_ENTITY_AND
2397 || entity == EPIPHANY_MSW_ENTITY_OR
2398 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2399 return 2;
2400 return FP_MODE_NONE;
2402 mode = get_attr_fp_mode (insn);
2404 switch (entity)
2406 case EPIPHANY_MSW_ENTITY_AND:
2407 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
2408 case EPIPHANY_MSW_ENTITY_OR:
2409 return mode == FP_MODE_INT ? 1 : 2;
2410 case EPIPHANY_MSW_ENTITY_CONFIG:
2411 /* We must know/save config before we set it to something else.
2412 Where we need the original value, we are fine with having it
2413 just unchanged from the function start.
2414 Because of the nature of the mode switching optimization,
2415 a restore will be dominated by a clobber. */
2416 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2417 return 1;
2418 /* A cpecial case are abnormal edges, which are deemed to clobber
2419 the mode as well. We need to pin this effect on a actually
2420 dominating insn, and one where the frame can be accessed, too, in
2421 case the pseudo used to save CONFIG doesn't get a hard register. */
2422 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2423 return 1;
2424 return 2;
2425 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2426 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2427 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2428 /* Fall through. */
2429 case EPIPHANY_MSW_ENTITY_NEAREST:
2430 case EPIPHANY_MSW_ENTITY_TRUNC:
2431 if (mode == FP_MODE_ROUND_UNKNOWN)
2433 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2434 return FP_MODE_NONE;
2436 return mode;
2437 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2438 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2439 return FP_MODE_ROUND_UNKNOWN;
2440 return mode;
2441 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2442 if (mode == FP_MODE_ROUND_UNKNOWN)
2443 return epiphany_normal_fp_rounding;
2444 return mode;
2445 default:
2446 gcc_unreachable ();
2450 static int
2451 epiphany_mode_entry_exit (int entity, bool exit)
2453 int normal_mode = epiphany_normal_fp_mode ;
2455 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2456 if (epiphany_is_interrupt_p (current_function_decl))
2457 normal_mode = FP_MODE_CALLER;
2458 switch (entity)
2460 case EPIPHANY_MSW_ENTITY_AND:
2461 if (exit)
2462 return normal_mode != FP_MODE_INT ? 1 : 2;
2463 return 0;
2464 case EPIPHANY_MSW_ENTITY_OR:
2465 if (exit)
2466 return normal_mode == FP_MODE_INT ? 1 : 2;
2467 return 0;
2468 case EPIPHANY_MSW_ENTITY_CONFIG:
2469 if (exit)
2470 return 2;
2471 return normal_mode == FP_MODE_CALLER ? 0 : 1;
2472 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2473 if (normal_mode == FP_MODE_ROUND_NEAREST
2474 || normal_mode == FP_MODE_ROUND_TRUNC)
2475 return FP_MODE_ROUND_UNKNOWN;
2476 /* Fall through. */
2477 case EPIPHANY_MSW_ENTITY_NEAREST:
2478 case EPIPHANY_MSW_ENTITY_TRUNC:
2479 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2480 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2481 return normal_mode;
2482 default:
2483 gcc_unreachable ();
2488 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn)
2490 /* We have too few call-saved registers to hope to keep the masks across
2491 calls. */
2492 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2494 if (CALL_P (insn))
2495 return 0;
2496 return last_mode;
2498 /* If there is an abnormal edge, we don't want the config register to
2499 be 'saved' again at the destination.
2500 The frame pointer adjustment is inside a PARALLEL because of the
2501 flags clobber. */
2502 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2503 && GET_CODE (PATTERN (insn)) == PARALLEL
2504 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2505 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2507 gcc_assert (cfun->has_nonlocal_label);
2508 return 1;
2510 if (recog_memoized (insn) < 0)
2511 return last_mode;
2512 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2513 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2515 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2516 return FP_MODE_ROUND_NEAREST;
2517 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2518 return FP_MODE_ROUND_TRUNC;
2520 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2522 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2523 int fp_mode;
2525 if (REG_P (src))
2526 return FP_MODE_CALLER;
2527 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2528 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2529 && (fp_mode == FP_MODE_ROUND_NEAREST
2530 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2531 return FP_MODE_ROUND_UNKNOWN;
2532 return fp_mode;
2534 return last_mode;
2537 static int
2538 epiphany_mode_entry (int entity)
2540 return epiphany_mode_entry_exit (entity, false);
2543 static int
2544 epiphany_mode_exit (int entity)
2546 return epiphany_mode_entry_exit (entity, true);
2549 void
2550 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
2551 HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2553 rtx save_cc, cc_reg, mask, src, src2;
2554 enum attr_fp_mode fp_mode;
2556 if (!MACHINE_FUNCTION (cfun)->and_mask)
2558 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2559 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2561 if (entity == EPIPHANY_MSW_ENTITY_AND)
2563 gcc_assert (mode >= 0 && mode <= 2);
2564 if (mode == 1)
2565 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2566 gen_int_mode (0xfff1fffe, SImode));
2567 return;
2569 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2571 gcc_assert (mode >= 0 && mode <= 2);
2572 if (mode == 1)
2573 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2574 return;
2576 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2578 /* Mode switching optimization is done after emit_initial_value_sets,
2579 so we have to take care of CONFIG_REGNUM here. */
2580 gcc_assert (mode >= 0 && mode <= 2);
2581 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2582 if (mode == 1)
2583 emit_insn (gen_save_config (save));
2584 return;
2586 fp_mode = (enum attr_fp_mode) mode;
2587 src = NULL_RTX;
2589 switch (fp_mode)
2591 case FP_MODE_CALLER:
2592 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2593 so that the config save gets inserted before the first use. */
2594 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2595 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2596 mask = MACHINE_FUNCTION (cfun)->and_mask;
2597 break;
2598 case FP_MODE_ROUND_UNKNOWN:
2599 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2600 mask = MACHINE_FUNCTION (cfun)->and_mask;
2601 break;
2602 case FP_MODE_ROUND_NEAREST:
2603 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2604 return;
2605 mask = MACHINE_FUNCTION (cfun)->and_mask;
2606 break;
2607 case FP_MODE_ROUND_TRUNC:
2608 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2609 return;
2610 mask = MACHINE_FUNCTION (cfun)->and_mask;
2611 break;
2612 case FP_MODE_INT:
2613 mask = MACHINE_FUNCTION (cfun)->or_mask;
2614 break;
2615 case FP_MODE_NONE:
2616 default:
2617 gcc_unreachable ();
2619 save_cc = gen_reg_rtx (CCmode);
2620 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2621 emit_move_insn (save_cc, cc_reg);
2622 mask = force_reg (SImode, mask);
2623 if (!src)
2625 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2627 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2629 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2630 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2631 src2 = copy_rtx (src);
2632 else
2634 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2636 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2638 emit_insn (gen_set_fp_mode (src, src2, mask));
2639 emit_move_insn (cc_reg, save_cc);
2642 void
2643 epiphany_expand_set_fp_mode (rtx *operands)
2645 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2646 rtx src = operands[0];
2647 rtx mask_reg = operands[2];
2648 rtx scratch = operands[3];
2649 enum attr_fp_mode fp_mode;
2652 gcc_assert (rtx_equal_p (src, operands[1])
2653 /* Sometimes reload gets silly and reloads the same pseudo
2654 into different registers. */
2655 || (REG_P (src) && REG_P (operands[1])));
2657 if (!epiphany_uninterruptible_p (current_function_decl))
2658 emit_insn (gen_gid ());
2659 emit_move_insn (scratch, ctrl);
2661 if (GET_CODE (src) == REG)
2663 /* FP_MODE_CALLER */
2664 emit_insn (gen_xorsi3 (scratch, scratch, src));
2665 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2666 emit_insn (gen_xorsi3 (scratch, scratch, src));
2668 else
2670 gcc_assert (GET_CODE (src) == CONST);
2671 src = XEXP (src, 0);
2672 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2673 switch (fp_mode)
2675 case FP_MODE_ROUND_NEAREST:
2676 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2677 break;
2678 case FP_MODE_ROUND_TRUNC:
2679 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2680 emit_insn (gen_add2_insn (scratch, const1_rtx));
2681 break;
2682 case FP_MODE_INT:
2683 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2684 break;
2685 case FP_MODE_CALLER:
2686 case FP_MODE_ROUND_UNKNOWN:
2687 case FP_MODE_NONE:
2688 gcc_unreachable ();
2691 emit_move_insn (ctrl, scratch);
2692 if (!epiphany_uninterruptible_p (current_function_decl))
2693 emit_insn (gen_gie ());
2696 void
2697 epiphany_insert_mode_switch_use (rtx_insn *insn,
2698 int entity ATTRIBUTE_UNUSED,
2699 int mode ATTRIBUTE_UNUSED)
2701 rtx pat = PATTERN (insn);
2702 rtvec v;
2703 int len, i;
2704 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2705 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2707 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2708 return;
2709 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2711 case FP_MODE_ROUND_NEAREST:
2712 near = gen_rtx_USE (VOIDmode, near);
2713 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2714 break;
2715 case FP_MODE_ROUND_TRUNC:
2716 near = gen_rtx_CLOBBER (VOIDmode, near);
2717 trunc = gen_rtx_USE (VOIDmode, trunc);
2718 break;
2719 case FP_MODE_ROUND_UNKNOWN:
2720 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2721 trunc = copy_rtx (near);
2722 /* Fall through. */
2723 case FP_MODE_INT:
2724 case FP_MODE_CALLER:
2725 near = gen_rtx_USE (VOIDmode, near);
2726 trunc = gen_rtx_USE (VOIDmode, trunc);
2727 break;
2728 case FP_MODE_NONE:
2729 gcc_unreachable ();
2731 gcc_assert (GET_CODE (pat) == PARALLEL);
2732 len = XVECLEN (pat, 0);
2733 v = rtvec_alloc (len + 2);
2734 for (i = 0; i < len; i++)
2735 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2736 RTVEC_ELT (v, len) = near;
2737 RTVEC_ELT (v, len + 1) = trunc;
2738 pat = gen_rtx_PARALLEL (VOIDmode, v);
2739 PATTERN (insn) = pat;
2740 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2743 bool
2744 epiphany_epilogue_uses (int regno)
2746 if (regno == GPR_LR)
2747 return true;
2748 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2750 if (fixed_regs[regno]
2751 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2752 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2753 return false;
2754 return true;
2756 if (regno == FP_NEAREST_REGNUM
2757 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2758 return true;
2759 if (regno == FP_TRUNCATE_REGNUM
2760 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2761 return true;
2762 return false;
2765 static unsigned int
2766 epiphany_min_divisions_for_recip_mul (machine_mode mode)
2768 if (flag_reciprocal_math && mode == SFmode)
2769 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2770 it already at the tree level and expose it to further optimizations. */
2771 return 1;
2772 return default_min_divisions_for_recip_mul (mode);
2775 static machine_mode
2776 epiphany_preferred_simd_mode (machine_mode mode ATTRIBUTE_UNUSED)
2778 return TARGET_VECT_DOUBLE ? DImode : SImode;
2781 static bool
2782 epiphany_vector_mode_supported_p (machine_mode mode)
2784 if (mode == V2SFmode)
2785 return true;
2786 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2787 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2788 return true;
2789 return false;
2792 static bool
2793 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2795 /* Vectors which aren't in packed structures will not be less aligned than
2796 the natural alignment of their element type, so this is safe. */
2797 if (TYPE_ALIGN_UNIT (type) == 4)
2798 return !is_packed;
2800 return default_builtin_vector_alignment_reachable (type, is_packed);
2803 static bool
2804 epiphany_support_vector_misalignment (machine_mode mode, const_tree type,
2805 int misalignment, bool is_packed)
2807 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2808 return true;
2809 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2810 is_packed);
2813 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2814 structs. Make structs double-word-aligned it they are a double word or
2815 (potentially) larger; failing that, do the same for a size of 32 bits. */
2816 unsigned
2817 epiphany_special_round_type_align (tree type, unsigned computed,
2818 unsigned specified)
2820 unsigned align = MAX (computed, specified);
2821 tree field;
2822 HOST_WIDE_INT total, max;
2823 unsigned try_align = FASTEST_ALIGNMENT;
2825 if (maximum_field_alignment && try_align > maximum_field_alignment)
2826 try_align = maximum_field_alignment;
2827 if (align >= try_align)
2828 return align;
2829 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2831 tree offset, size;
2833 if (TREE_CODE (field) != FIELD_DECL
2834 || TREE_TYPE (field) == error_mark_node)
2835 continue;
2836 offset = bit_position (field);
2837 size = DECL_SIZE (field);
2838 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
2839 || tree_to_uhwi (offset) >= try_align
2840 || tree_to_uhwi (size) >= try_align)
2841 return try_align;
2842 total = tree_to_uhwi (offset) + tree_to_uhwi (size);
2843 if (total > max)
2844 max = total;
2846 if (max >= (HOST_WIDE_INT) try_align)
2847 align = try_align;
2848 else if (try_align > 32 && max >= 32)
2849 align = max > 32 ? 64 : 32;
2850 return align;
2853 /* Upping the alignment of arrays in structs is not only a performance
2854 enhancement, it also helps preserve assumptions about how
2855 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2856 libgcov.c . */
2857 unsigned
2858 epiphany_adjust_field_align (tree type, unsigned computed)
2860 if (computed == 32
2861 && TREE_CODE (type) == ARRAY_TYPE)
2863 tree elmsz = TYPE_SIZE (TREE_TYPE (type));
2865 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
2866 return 64;
2868 return computed;
2871 /* Output code to add DELTA to the first argument, and then jump
2872 to FUNCTION. Used for C++ multiple inheritance. */
2873 static void
2874 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2875 HOST_WIDE_INT delta,
2876 HOST_WIDE_INT vcall_offset,
2877 tree function)
2879 int this_regno
2880 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2881 const char *this_name = reg_names[this_regno];
2882 const char *fname;
2884 /* We use IP and R16 as a scratch registers. */
2885 gcc_assert (call_used_regs [GPR_IP]);
2886 gcc_assert (call_used_regs [GPR_16]);
2888 /* Add DELTA. When possible use a plain add, otherwise load it into
2889 a register first. */
2890 if (delta == 0)
2891 ; /* Done. */
2892 else if (SIMM11 (delta))
2893 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2894 else if (delta < 0 && delta >= -0xffff)
2896 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2897 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2899 else
2901 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2902 if (delta & ~0xffff)
2903 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2904 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2907 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2908 if (vcall_offset != 0)
2910 /* ldr ip,[this] --> temp = *this
2911 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2912 add this,this,ip --> this+ = *(*this + vcall_offset) */
2913 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2914 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2915 || (vcall_offset & 3) != 0)
2917 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2918 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2919 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2921 else
2922 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2923 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2926 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2927 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2929 fputs ("\tmov\tip,%low(", file);
2930 assemble_name (file, fname);
2931 fputs (")\n\tmovt\tip,%high(", file);
2932 assemble_name (file, fname);
2933 fputs (")\n\tjr ip\n", file);
2935 else
2937 fputs ("\tb\t", file);
2938 assemble_name (file, fname);
2939 fputc ('\n', file);
2943 void
2944 epiphany_start_function (FILE *file, const char *name, tree decl)
2946 /* If the function doesn't fit into the on-chip memory, it will have a
2947 section attribute - or lack of it - that denotes it goes somewhere else.
2948 But the architecture spec says that an interrupt vector still has to
2949 point to on-chip memory. So we must place a jump there to get to the
2950 actual function implementation. The forwarder_section attribute
2951 specifies the section where this jump goes.
2952 This mechanism can also be useful to have a shortcall destination for
2953 a function that is actually placed much farther away. */
2954 tree attrs, int_attr, int_names, int_name, forwarder_attr;
2956 attrs = DECL_ATTRIBUTES (decl);
2957 int_attr = lookup_attribute ("interrupt", attrs);
2958 if (int_attr)
2959 for (int_names = TREE_VALUE (int_attr); int_names;
2960 int_names = TREE_CHAIN (int_names))
2962 char buf[99];
2964 int_name = TREE_VALUE (int_names);
2965 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2966 switch_to_section (get_section (buf, SECTION_CODE, decl));
2967 fputs ("\tb\t", file);
2968 assemble_name (file, name);
2969 fputc ('\n', file);
2971 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2972 if (forwarder_attr)
2974 const char *prefix = "__forwarder_dst_";
2975 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2977 strcpy (dst_name, prefix);
2978 strcat (dst_name, name);
2979 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2980 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2981 SECTION_CODE, decl));
2982 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2983 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2985 int tmp = GPR_0;
2987 if (int_attr)
2988 fputs ("\tstrd r0,[sp,-1]\n", file);
2989 else
2990 tmp = GPR_16;
2991 gcc_assert (call_used_regs[tmp]);
2992 fprintf (file, "\tmov r%d,%%low(", tmp);
2993 assemble_name (file, dst_name);
2994 fprintf (file, ")\n"
2995 "\tmovt r%d,%%high(", tmp);
2996 assemble_name (file, dst_name);
2997 fprintf (file, ")\n"
2998 "\tjr r%d\n", tmp);
3000 else
3002 fputs ("\tb\t", file);
3003 assemble_name (file, dst_name);
3004 fputc ('\n', file);
3006 name = dst_name;
3008 switch_to_section (function_section (decl));
3009 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
3012 struct gcc_target targetm = TARGET_INITIALIZER;