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