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