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