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