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