]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/epiphany/epiphany.c
Update copyright years in gcc/
[thirdparty/gcc.git] / gcc / config / epiphany / epiphany.c
CommitLineData
feeeff5c 1/* Subroutines used for code generation on the EPIPHANY cpu.
23a5b65a 2 Copyright (C) 1994-2014 Free Software Foundation, Inc.
feeeff5c
JR
3 Contributed by Embecosm on behalf of Adapteva, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tm.h"
25#include "tree.h"
d8a2d370
DN
26#include "stor-layout.h"
27#include "varasm.h"
28#include "calls.h"
29#include "stringpool.h"
feeeff5c
JR
30#include "rtl.h"
31#include "regs.h"
32#include "hard-reg-set.h"
33#include "real.h"
34#include "insn-config.h"
35#include "conditions.h"
36#include "output.h"
37#include "insn-attr.h"
38#include "flags.h"
39#include "function.h"
40#include "expr.h"
41#include "diagnostic-core.h"
42#include "recog.h"
43#include "toplev.h"
44#include "tm_p.h"
45#include "target.h"
46#include "df.h"
47#include "langhooks.h"
48#include "insn-codes.h"
49#include "ggc.h"
50#include "tm-constrs.h"
7ee2468b 51#include "tree-pass.h" /* for current_pass */
05555c4a
DM
52#include "context.h"
53#include "pass_manager.h"
feeeff5c
JR
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
05555c4a
DM
68/* The pass instance, for use in epiphany_optimize_mode_switching. */
69static opt_pass *pass_mode_switch_use;
70
feeeff5c
JR
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 *);
60098013
JR
74static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
75 bool *);
feeeff5c
JR
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. */
05555c4a
DM
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",
feeeff5c
JR
180 1, PASS_POS_INSERT_AFTER
181 };
05555c4a
DM
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",
feeeff5c
JR
186 1, PASS_POS_INSERT_AFTER
187 };
05555c4a
DM
188 opt_pass *mode_sw3 = make_pass_resolve_sw_modes (g);
189 struct register_pass_info mode_sw3_info
190 = { mode_sw3, "mode_sw",
feeeff5c
JR
191 1, PASS_POS_INSERT_AFTER
192 };
05555c4a
DM
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",
feeeff5c
JR
197 1, PASS_POS_INSERT_AFTER
198 };
566be57c
JR
199 static const int num_modes[] = NUM_MODES_FOR_MODE_SWITCHING;
200#define N_ENTITIES ARRAY_SIZE (num_modes)
feeeff5c
JR
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);
566be57c
JR
216 /* Verify that NUM_MODES_FOR_MODE_SWITCHING has one value per entity. */
217 gcc_assert (N_ENTITIES == EPIPHANY_MSW_ENTITY_NUM);
feeeff5c
JR
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 {
05555c4a
DM
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",
feeeff5c
JR
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 {
8afab237
JR
359 if (TARGET_SOFT_CMPSF
360 || op == ORDERED || op == UNORDERED)
feeeff5c
JR
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 } */
60098013
JR
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 },
feeeff5c
JR
437 { "long_call", 0, 0, false, true, true, NULL, false },
438 { "short_call", 0, 0, false, true, true, NULL, false },
60098013 439 { "disinterrupt", 0, 0, false, true, true, NULL, true },
feeeff5c
JR
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{
60098013
JR
451 tree value;
452
453 if (!args)
454 return NULL_TREE;
455
456 value = TREE_VALUE (args);
feeeff5c
JR
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")
188b7e23
JR
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")
feeeff5c
JR
470 && strcmp (TREE_STRING_POINTER (value), "dma0")
471 && strcmp (TREE_STRING_POINTER (value), "dma1")
188b7e23 472 && strcmp (TREE_STRING_POINTER (value), "wand")
feeeff5c
JR
473 && strcmp (TREE_STRING_POINTER (value), "swi"))
474 {
475 warning (OPT_Wattributes,
188b7e23 476 "argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
feeeff5c
JR
477 name);
478 *no_add_attrs = true;
60098013 479 return NULL_TREE;
feeeff5c
JR
480 }
481
60098013
JR
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 }
feeeff5c
JR
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 {
105766f3
JR
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 }
feeeff5c
JR
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. */
105766f3
JR
584 && (!REG_P (x) || REGNO (x) != GPR_0
585 || !REG_P (y) || REGNO (y) != GPR_1))
feeeff5c
JR
586 {
587 rtx reg;
588
105766f3
JR
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. */
feeeff5c 595 gcc_assert (currently_expanding_to_rtl);
105766f3
JR
596#endif
597 reg = gen_rtx_REG (in_mode, GPR_0);
598 if (reg_overlap_mentioned_p (reg, y))
599 return 0;
feeeff5c
JR
600 emit_move_insn (reg, x);
601 x = reg;
105766f3 602 reg = gen_rtx_REG (in_mode, GPR_1);
feeeff5c
JR
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
2266617f 776epiphany_address_cost (rtx addr, enum machine_mode mode,
b413068c 777 addr_space_t as ATTRIBUTE_UNUSED, bool speed)
feeeff5c
JR
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;
2266617f
JR
808 /* The offset range available for short instructions depends on the mode
809 of the memory access. */
feeeff5c
JR
810 /* First, make sure we have a valid integer. */
811 if (!satisfies_constraint_L (off))
812 return 1;
813 i = INTVAL (off);
2266617f
JR
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 }
feeeff5c
JR
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 */
4c97f1cc
JR
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. */
feeeff5c
JR
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 {
60098013 975 tree name = TREE_PURPOSE (a);
feeeff5c 976
60098013
JR
977 if (name == get_identifier ("interrupt"))
978 fn_type = EPIPHANY_FUNCTION_INTERRUPT;
feeeff5c
JR
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) \
416ff32e 994 || (interrupt_p && !crtl->is_leaf \
feeeff5c
JR
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;
feeeff5c
JR
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
105766f3 1073 && (!interrupt_p || regno > GPR_1))
feeeff5c
JR
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);
4c97f1cc
JR
1094 if (((total_size + reg_size
1095 /* Reserve space for UNKNOWN_REGNUM. */
1096 + EPIPHANY_STACK_ALIGN (4))
1097 <= (unsigned) epiphany_stack_offset)
feeeff5c 1098 && !interrupt_p
416ff32e 1099 && crtl->is_leaf && !frame_pointer_needed)
feeeff5c
JR
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);
160051af 1136 gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset);
feeeff5c
JR
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
feeeff5c
JR
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;
feeeff5c
JR
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
1565f169 1457static bool
feeeff5c
JR
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;
0a81f074
RS
1595 addr = plus_constant (Pmode, addr,
1596 - (HOST_WIDE_INT) UNITS_PER_WORD);
feeeff5c
JR
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++;
0a81f074
RS
1629 addr = plus_constant (Pmode, addr,
1630 - (HOST_WIDE_INT) UNITS_PER_WORD);
feeeff5c
JR
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++;
0a81f074
RS
1645 addr = plus_constant (Pmode, addr,
1646 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
feeeff5c
JR
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);
3b088b47
JR
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
feeeff5c
JR
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:
0a81f074 1686 addr = plus_constant (Pmode, addr, -(HOST_WIDE_INT) UNITS_PER_WORD);
feeeff5c
JR
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;
feeeff5c
JR
1697
1698 if (!current_frame_info.initialized)
1699 epiphany_compute_frame_size (get_frame_size ());
1700
1701 /* It is debatable if we should adjust this by epiphany_stack_offset. */
1702 if (flag_stack_usage_info)
1703 current_function_static_stack_size = current_frame_info.total_size;
1704
1705 fn_type = epiphany_compute_function_type (current_function_decl);
1706 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1707
1708 if (interrupt_p)
1709 {
0a81f074 1710 addr = plus_constant (Pmode, stack_pointer_rtx,
feeeff5c 1711 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
60098013
JR
1712 if (!lookup_attribute ("forwarder_section",
1713 DECL_ATTRIBUTES (current_function_decl))
1714 || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
1715 0)))
1716 frame_move_insn (gen_frame_mem (DImode, addr),
1717 gen_rtx_REG (DImode, GPR_0));
feeeff5c
JR
1718 frame_move_insn (gen_rtx_REG (SImode, GPR_0),
1719 gen_rtx_REG (word_mode, STATUS_REGNUM));
105766f3 1720 frame_move_insn (gen_rtx_REG (SImode, GPR_1),
feeeff5c
JR
1721 gen_rtx_REG (word_mode, IRET_REGNUM));
1722 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1723 off = GEN_INT (-current_frame_info.first_slot_offset);
1724 frame_insn (gen_stack_adjust_add (off, mem));
1725 if (!epiphany_uninterruptible_p (current_function_decl))
1726 emit_insn (gen_gie ());
0a81f074 1727 addr = plus_constant (Pmode, stack_pointer_rtx,
feeeff5c
JR
1728 current_frame_info.first_slot_offset
1729 - (HOST_WIDE_INT) 3 * UNITS_PER_WORD);
1730 }
1731 else
1732 {
0a81f074 1733 addr = plus_constant (Pmode, stack_pointer_rtx,
feeeff5c
JR
1734 epiphany_stack_offset
1735 - (HOST_WIDE_INT) UNITS_PER_WORD);
1736 epiphany_emit_save_restore (0, current_frame_info.small_threshold,
1737 addr, 0);
1738 /* Allocate register save area; for small to medium size frames,
1739 allocate the entire frame; this is joint with one register save. */
1740 if (current_frame_info.first_slot >= 0)
1741 {
1742 enum machine_mode mode
1743 = (current_frame_info.first_slot_size == UNITS_PER_WORD
1744 ? word_mode : DImode);
1745
1746 off = GEN_INT (-current_frame_info.first_slot_offset);
1747 mem = gen_frame_mem (BLKmode,
1748 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1749 frame_insn (gen_stack_adjust_str
1750 (gen_frame_mem (mode, stack_pointer_rtx),
1751 gen_rtx_REG (mode, current_frame_info.first_slot),
1752 off, mem));
0a81f074
RS
1753 addr = plus_constant (Pmode, addr,
1754 current_frame_info.first_slot_offset);
feeeff5c
JR
1755 }
1756 }
1757 epiphany_emit_save_restore (current_frame_info.small_threshold,
1758 FIRST_PSEUDO_REGISTER, addr, 0);
1759 if (current_frame_info.need_fp)
1760 frame_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
1761 /* For large frames, allocate bulk of frame. This is usually joint with one
1762 register save. */
1763 if (current_frame_info.last_slot >= 0)
1764 {
d4bca93c
JR
1765 rtx ip, mem2, insn, note;
1766
feeeff5c
JR
1767 gcc_assert (current_frame_info.last_slot != GPR_FP
1768 || (!current_frame_info.need_fp
1769 && current_frame_info.first_slot < 0));
1770 off = GEN_INT (-current_frame_info.last_slot_offset);
1771 mem = gen_frame_mem (BLKmode,
1772 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
d4bca93c
JR
1773 ip = gen_rtx_REG (Pmode, GPR_IP);
1774 frame_move_insn (ip, off);
1775 reg = gen_rtx_REG (word_mode, current_frame_info.last_slot),
1776 mem2 = gen_frame_mem (word_mode, stack_pointer_rtx),
1777 insn = frame_insn (gen_stack_adjust_str (mem2, reg, ip, mem));
1778 /* Instruction scheduling can separate the instruction setting IP from
1779 INSN so that dwarf2out_frame_debug_expr becomes confused what the
1780 temporary register is. Example: _gcov.o */
1781 note = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
1782 gen_rtx_PLUS (Pmode, stack_pointer_rtx, off));
1783 note = gen_rtx_PARALLEL (VOIDmode,
1784 gen_rtvec (2, gen_rtx_SET (VOIDmode, mem2, reg),
1785 note));
1786 add_reg_note (insn, REG_FRAME_RELATED_EXPR, note);
feeeff5c
JR
1787 }
1788 /* If there is only one or no register to save, yet we have a large frame,
1789 use an add. */
1790 else if (current_frame_info.last_slot_offset)
1791 {
1792 mem = gen_frame_mem (BLKmode,
0a81f074 1793 plus_constant (Pmode, stack_pointer_rtx,
feeeff5c
JR
1794 current_frame_info.last_slot_offset));
1795 off = GEN_INT (-current_frame_info.last_slot_offset);
1796 if (!SIMM11 (INTVAL (off)))
1797 {
1798 reg = gen_rtx_REG (Pmode, GPR_IP);
1799 frame_move_insn (reg, off);
1800 off = reg;
1801 }
1802 frame_insn (gen_stack_adjust_add (off, mem));
1803 }
feeeff5c
JR
1804}
1805
1806void
1807epiphany_expand_epilogue (int sibcall_p)
1808{
1809 int interrupt_p;
1810 enum epiphany_function_type fn_type;
1811 rtx mem, addr, reg, off;
1812 HOST_WIDE_INT restore_offset;
1813
1814 fn_type = epiphany_compute_function_type( current_function_decl);
1815 interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1816
1817 /* For variable frames, deallocate bulk of frame. */
1818 if (current_frame_info.need_fp)
1819 {
1820 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1821 emit_insn (gen_stack_adjust_mov (mem));
1822 }
1823 /* Else for large static frames, deallocate bulk of frame. */
1824 else if (current_frame_info.last_slot_offset)
1825 {
1826 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1827 reg = gen_rtx_REG (Pmode, GPR_IP);
1828 emit_move_insn (reg, GEN_INT (current_frame_info.last_slot_offset));
1829 emit_insn (gen_stack_adjust_add (reg, mem));
1830 }
1831 restore_offset = (interrupt_p
1832 ? - 3 * UNITS_PER_WORD
1833 : epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
0a81f074 1834 addr = plus_constant (Pmode, stack_pointer_rtx,
feeeff5c
JR
1835 (current_frame_info.first_slot_offset
1836 + restore_offset));
1837 epiphany_emit_save_restore (current_frame_info.small_threshold,
1838 FIRST_PSEUDO_REGISTER, addr, 1);
1839
1840 if (interrupt_p && !epiphany_uninterruptible_p (current_function_decl))
1841 emit_insn (gen_gid ());
1842
1843 off = GEN_INT (current_frame_info.first_slot_offset);
1844 mem = gen_frame_mem (BLKmode, stack_pointer_rtx);
1845 /* For large / variable size frames, deallocating the register save area is
1846 joint with one register restore; for medium size frames, we use a
1847 dummy post-increment load to dealloacte the whole frame. */
1848 if (!SIMM11 (INTVAL (off)) || current_frame_info.last_slot >= 0)
1849 {
1850 emit_insn (gen_stack_adjust_ldr
1851 (gen_rtx_REG (word_mode,
1852 (current_frame_info.last_slot >= 0
1853 ? current_frame_info.last_slot : GPR_IP)),
1854 gen_frame_mem (word_mode, stack_pointer_rtx),
1855 off,
1856 mem));
1857 }
1858 /* While for small frames, we deallocate the entire frame with one add. */
1859 else if (INTVAL (off))
1860 {
1861 emit_insn (gen_stack_adjust_add (off, mem));
1862 }
1863 if (interrupt_p)
1864 {
188b7e23
JR
1865 emit_move_insn (gen_rtx_REG (word_mode, STATUS_REGNUM),
1866 gen_rtx_REG (SImode, GPR_0));
1867 emit_move_insn (gen_rtx_REG (word_mode, IRET_REGNUM),
105766f3 1868 gen_rtx_REG (SImode, GPR_1));
0a81f074 1869 addr = plus_constant (Pmode, stack_pointer_rtx,
feeeff5c 1870 - (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
188b7e23
JR
1871 emit_move_insn (gen_rtx_REG (DImode, GPR_0),
1872 gen_frame_mem (DImode, addr));
feeeff5c 1873 }
0a81f074 1874 addr = plus_constant (Pmode, stack_pointer_rtx,
feeeff5c
JR
1875 epiphany_stack_offset - (HOST_WIDE_INT) UNITS_PER_WORD);
1876 epiphany_emit_save_restore (0, current_frame_info.small_threshold, addr, 1);
1877 if (!sibcall_p)
1878 {
1879 if (interrupt_p)
1880 emit_jump_insn (gen_return_internal_interrupt());
1881 else
1882 emit_jump_insn (gen_return_i ());
1883 }
1884}
1885
1886int
1887epiphany_initial_elimination_offset (int from, int to)
1888{
1889 epiphany_compute_frame_size (get_frame_size ());
1890 if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1891 return current_frame_info.total_size - current_frame_info.reg_size;
1892 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1893 return current_frame_info.first_slot_offset - current_frame_info.reg_size;
1894 if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
1895 return (current_frame_info.total_size
1896 - ((current_frame_info.pretend_size + 4) & -8));
1897 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1898 return (current_frame_info.first_slot_offset
1899 - ((current_frame_info.pretend_size + 4) & -8));
1900 gcc_unreachable ();
1901}
1902
ffcc7caf
JR
1903bool
1904epiphany_regno_rename_ok (unsigned, unsigned dst)
1905{
1906 enum epiphany_function_type fn_type;
1907
1908 fn_type = epiphany_compute_function_type (current_function_decl);
1909 if (!EPIPHANY_INTERRUPT_P (fn_type))
1910 return true;
1911 if (df_regs_ever_live_p (dst))
1912 return true;
1913 return false;
1914}
1915
feeeff5c
JR
1916static int
1917epiphany_issue_rate (void)
1918{
1919 return 2;
1920}
1921
1922/* Function to update the integer COST
1923 based on the relationship between INSN that is dependent on
1924 DEP_INSN through the dependence LINK. The default is to make no
1925 adjustment to COST. This can be used for example to specify to
1926 the scheduler that an output- or anti-dependence does not incur
1927 the same cost as a data-dependence. The return value should be
1928 the new value for COST. */
1929static int
1930epiphany_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
1931{
1932 if (REG_NOTE_KIND (link) == 0)
1933 {
1934 rtx dep_set;
1935
1936 if (recog_memoized (insn) < 0
1937 || recog_memoized (dep_insn) < 0)
1938 return cost;
1939
1940 dep_set = single_set (dep_insn);
1941
1942 /* The latency that we specify in the scheduling description refers
1943 to the actual output, not to an auto-increment register; for that,
1944 the latency is one. */
1945 if (dep_set && MEM_P (SET_SRC (dep_set)) && cost > 1)
1946 {
1947 rtx set = single_set (insn);
1948
1949 if (set
d9b83a68 1950 && !reg_overlap_mentioned_p (SET_DEST (dep_set), SET_SRC (set))
feeeff5c 1951 && (!MEM_P (SET_DEST (set))
d9b83a68
JR
1952 || !reg_overlap_mentioned_p (SET_DEST (dep_set),
1953 XEXP (SET_DEST (set), 0))))
feeeff5c
JR
1954 cost = 1;
1955 }
1956 }
1957 return cost;
1958}
1959
1960#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
1961
1962#define RTX_OK_FOR_BASE_P(X) \
1963 (REG_P (X) && REG_OK_FOR_BASE_P (X))
1964
1965#define RTX_OK_FOR_INDEX_P(MODE, X) \
1966 ((GET_MODE_CLASS (MODE) != MODE_VECTOR_INT \
1967 || epiphany_vect_align >= GET_MODE_SIZE (MODE)) \
1968 && (REG_P (X) && REG_OK_FOR_INDEX_P (X)))
1969
1970#define LEGITIMATE_OFFSET_ADDRESS_P(MODE, X) \
1971(GET_CODE (X) == PLUS \
1972 && RTX_OK_FOR_BASE_P (XEXP (X, 0)) \
1973 && (RTX_OK_FOR_INDEX_P (MODE, XEXP (X, 1)) \
1974 || RTX_OK_FOR_OFFSET_P (MODE, XEXP (X, 1))))
1975
1976static bool
1977epiphany_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
1978{
1979#define REG_OK_FOR_BASE_P(X) \
1980 (strict ? GPR_P (REGNO (X)) : GPR_AP_OR_PSEUDO_P (REGNO (X)))
1981 if (RTX_OK_FOR_BASE_P (x))
1982 return true;
1983 if (RTX_FRAME_OFFSET_P (x))
1984 return true;
1985 if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x))
1986 return true;
0ccfc3ab
JR
1987 /* If this is a misaligned stack access, don't force it to reg+index. */
1988 if (GET_MODE_SIZE (mode) == 8
1989 && GET_CODE (x) == PLUS && XEXP (x, 0) == stack_pointer_rtx
1990 /* Decomposed to SImode; GET_MODE_SIZE (SImode) == 4 */
1991 && !(INTVAL (XEXP (x, 1)) & 3)
1992 && INTVAL (XEXP (x, 1)) >= -2047 * 4
1993 && INTVAL (XEXP (x, 1)) <= 2046 * 4)
1994 return true;
feeeff5c
JR
1995 if (TARGET_POST_INC
1996 && (GET_CODE (x) == POST_DEC || GET_CODE (x) == POST_INC)
1997 && RTX_OK_FOR_BASE_P (XEXP ((x), 0)))
1998 return true;
1999 if ((TARGET_POST_MODIFY || reload_completed)
2000 && GET_CODE (x) == POST_MODIFY
2001 && GET_CODE (XEXP ((x), 1)) == PLUS
2002 && rtx_equal_p (XEXP ((x), 0), XEXP (XEXP ((x), 1), 0))
2003 && LEGITIMATE_OFFSET_ADDRESS_P (mode, XEXP ((x), 1)))
2004 return true;
2005 if (mode == BLKmode)
2006 return true;
2007 return false;
2008}
2009
2010static reg_class_t
2011epiphany_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
2012 enum machine_mode mode ATTRIBUTE_UNUSED,
2013 secondary_reload_info *sri)
2014{
2015 /* This could give more reload inheritance, but we are missing some
2016 reload infrastructure. */
2017 if (0)
2018 if (in_p && GET_CODE (x) == UNSPEC
2019 && satisfies_constraint_Sra (x) && !satisfies_constraint_Rra (x))
2020 {
2021 gcc_assert (rclass == GENERAL_REGS);
2022 sri->icode = CODE_FOR_reload_insi_ra;
2023 return NO_REGS;
2024 }
2025 return NO_REGS;
2026}
2027
2028bool
2029epiphany_is_long_call_p (rtx x)
2030{
2031 tree decl = SYMBOL_REF_DECL (x);
2032 bool ret_val = !TARGET_SHORT_CALLS;
2033 tree attrs;
2034
2035 /* ??? Is it safe to default to ret_val if decl is NULL? We should
2036 probably encode information via encode_section_info, and also
2037 have (an) option(s) to take SYMBOL_FLAG_LOCAL and/or SYMBOL_FLAG_EXTERNAL
2038 into account. */
2039 if (decl)
2040 {
2041 attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
2042 if (lookup_attribute ("long_call", attrs))
2043 ret_val = true;
2044 else if (lookup_attribute ("short_call", attrs))
2045 ret_val = false;
2046 }
2047 return ret_val;
2048}
2049
2050bool
2051epiphany_small16 (rtx x)
2052{
2053 rtx base = x;
2054 rtx offs ATTRIBUTE_UNUSED = const0_rtx;
2055
2056 if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
2057 {
2058 base = XEXP (XEXP (x, 0), 0);
2059 offs = XEXP (XEXP (x, 0), 1);
2060 }
2061 if (GET_CODE (base) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (base)
2062 && epiphany_is_long_call_p (base))
2063 return false;
2064 return TARGET_SMALL16 != 0;
2065}
2066
2067/* Return nonzero if it is ok to make a tail-call to DECL. */
2068static bool
2069epiphany_function_ok_for_sibcall (tree decl, tree exp)
2070{
2071 bool cfun_interrupt_p, call_interrupt_p;
2072
2073 cfun_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type
2074 (current_function_decl));
2075 if (decl)
2076 call_interrupt_p = EPIPHANY_INTERRUPT_P (epiphany_compute_function_type (decl));
2077 else
2078 {
2079 tree fn_type = TREE_TYPE (CALL_EXPR_FN (exp));
2080
2081 gcc_assert (POINTER_TYPE_P (fn_type));
2082 fn_type = TREE_TYPE (fn_type);
2083 gcc_assert (TREE_CODE (fn_type) == FUNCTION_TYPE
2084 || TREE_CODE (fn_type) == METHOD_TYPE);
2085 call_interrupt_p
2086 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (fn_type)) != NULL;
2087 }
2088
2089 /* Don't tailcall from or to an ISR routine - although we could in
2090 principle tailcall from one ISR routine to another, we'd need to
2091 handle this in sibcall_epilogue to make it work. */
2092 if (cfun_interrupt_p || call_interrupt_p)
2093 return false;
2094
2095 /* Everything else is ok. */
2096 return true;
2097}
2098
2099/* T is a function declaration or the MEM_EXPR of a MEM passed to a call
2100 expander.
2101 Return true iff the type of T has the uninterruptible attribute.
2102 If T is NULL, return false. */
2103bool
2104epiphany_uninterruptible_p (tree t)
2105{
2106 tree attrs;
2107
2108 if (t)
2109 {
2110 attrs = TYPE_ATTRIBUTES (TREE_TYPE (t));
2111 if (lookup_attribute ("disinterrupt", attrs))
2112 return true;
2113 }
2114 return false;
2115}
2116
2117bool
2118epiphany_call_uninterruptible_p (rtx mem)
2119{
2120 rtx addr = XEXP (mem, 0);
2121 tree t = NULL_TREE;
2122
2123 if (GET_CODE (addr) == SYMBOL_REF)
2124 t = SYMBOL_REF_DECL (addr);
2125 if (!t)
2126 t = MEM_EXPR (mem);
2127 return epiphany_uninterruptible_p (t);
2128}
2129
2130static enum machine_mode
2131epiphany_promote_function_mode (const_tree type, enum machine_mode mode,
2132 int *punsignedp ATTRIBUTE_UNUSED,
2133 const_tree funtype ATTRIBUTE_UNUSED,
2134 int for_return ATTRIBUTE_UNUSED)
2135{
2136 int dummy;
2137
2138 return promote_mode (type, mode, &dummy);
2139}
2140
2141static void
2142epiphany_conditional_register_usage (void)
2143{
2144 int i;
2145
2146 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
2147 {
2148 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2149 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
2150 }
2151 if (TARGET_HALF_REG_FILE)
2152 {
2153 for (i = 32; i <= 63; i++)
2154 {
2155 fixed_regs[i] = 1;
2156 call_used_regs[i] = 1;
2157 }
2158 }
2159 if (epiphany_m1reg >= 0)
2160 {
2161 fixed_regs[epiphany_m1reg] = 1;
2162 call_used_regs[epiphany_m1reg] = 1;
2163 }
2164 if (!TARGET_PREFER_SHORT_INSN_REGS)
2165 CLEAR_HARD_REG_SET (reg_class_contents[SHORT_INSN_REGS]);
2166 COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2167 reg_class_contents[GENERAL_REGS]);
2168 /* It would be simpler and quicker if we could just use
2169 AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2170 it is set up later by our caller. */
2171 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2172 if (!call_used_regs[i])
2173 CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2174}
2175
2176/* Determine where to put an argument to a function.
2177 Value is zero to push the argument on the stack,
2178 or a hard register in which to store the argument.
2179
2180 MODE is the argument's machine mode.
2181 TYPE is the data type of the argument (as a tree).
2182 This is null for libcalls where that information may
2183 not be available.
2184 CUM is a variable of type CUMULATIVE_ARGS which gives info about
2185 the preceding args and about the function being called.
2186 NAMED is nonzero if this argument is a named parameter
2187 (otherwise it is an extra parameter matching an ellipsis). */
2188/* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2189 registers and the rest are pushed. */
2190static rtx
2191epiphany_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
2192 const_tree type, bool named ATTRIBUTE_UNUSED)
2193{
2194 CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2195
2196 if (PASS_IN_REG_P (cum, mode, type))
2197 return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2198 return 0;
2199}
2200
2201/* Update the data in CUM to advance over an argument
2202 of mode MODE and data type TYPE.
2203 (TYPE is null for libcalls where that information may not be available.) */
2204static void
2205epiphany_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
2206 const_tree type, bool named ATTRIBUTE_UNUSED)
2207{
2208 CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2209
2210 *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2211}
2212\f
2213/* Nested function support.
2214 An epiphany trampoline looks like this:
2215 mov r16,%low(fnaddr)
2216 movt r16,%high(fnaddr)
2217 mov ip,%low(cxt)
2218 movt ip,%high(cxt)
2219 jr r16 */
2220
2221#define EPIPHANY_LOW_RTX(X) \
2222 (gen_rtx_IOR (SImode, \
2223 gen_rtx_ASHIFT (SImode, \
2224 gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2225 gen_rtx_ASHIFT (SImode, \
2226 gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2227#define EPIPHANY_HIGH_RTX(X) \
2228 EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2229
2230/* Emit RTL insns to initialize the variable parts of a trampoline.
2231 FNADDR is an RTX for the address of the function's pure code.
2232 CXT is an RTX for the static chain value for the function. */
2233static void
2234epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2235{
2236 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2237 rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2238
0a81f074 2239 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
feeeff5c
JR
2240 gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2241 EPIPHANY_LOW_RTX (fnaddr)));
0a81f074 2242 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
feeeff5c
JR
2243 gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2244 EPIPHANY_HIGH_RTX (fnaddr)));
0a81f074 2245 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
feeeff5c
JR
2246 gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2247 EPIPHANY_LOW_RTX (cxt)));
0a81f074 2248 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
feeeff5c
JR
2249 gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2250 EPIPHANY_HIGH_RTX (cxt)));
0a81f074 2251 emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
feeeff5c
JR
2252 GEN_INT (0x0802014f));
2253}
2254\f
2255bool
2256epiphany_optimize_mode_switching (int entity)
2257{
2258 if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2259 return false;
2260 switch (entity)
2261 {
2262 case EPIPHANY_MSW_ENTITY_AND:
2263 case EPIPHANY_MSW_ENTITY_OR:
566be57c 2264 case EPIPHANY_MSW_ENTITY_CONFIG:
feeeff5c
JR
2265 return true;
2266 case EPIPHANY_MSW_ENTITY_NEAREST:
2267 case EPIPHANY_MSW_ENTITY_TRUNC:
2268 return optimize > 0;
2269 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2270 return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2271 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2272 return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2273 & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2274 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
05555c4a 2275 return optimize == 0 || current_pass == pass_mode_switch_use;
feeeff5c
JR
2276 }
2277 gcc_unreachable ();
2278}
2279
2280int
2281epiphany_mode_priority_to_mode (int entity, unsigned priority)
2282{
566be57c
JR
2283 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2284 || entity== EPIPHANY_MSW_ENTITY_CONFIG)
feeeff5c
JR
2285 return priority;
2286 if (priority > 3)
2287 switch (priority)
2288 {
2289 case 4: return FP_MODE_ROUND_UNKNOWN;
2290 case 5: return FP_MODE_NONE;
2291 default: gcc_unreachable ();
2292 }
2293 switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2294 {
2295 case FP_MODE_INT:
2296 switch (priority)
2297 {
2298 case 0: return FP_MODE_INT;
2299 case 1: return epiphany_normal_fp_rounding;
2300 case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2301 ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2302 case 3: return FP_MODE_CALLER;
2303 }
2304 case FP_MODE_ROUND_NEAREST:
2305 case FP_MODE_CALLER:
2306 switch (priority)
2307 {
2308 case 0: return FP_MODE_ROUND_NEAREST;
2309 case 1: return FP_MODE_ROUND_TRUNC;
2310 case 2: return FP_MODE_INT;
2311 case 3: return FP_MODE_CALLER;
2312 }
2313 case FP_MODE_ROUND_TRUNC:
2314 switch (priority)
2315 {
2316 case 0: return FP_MODE_ROUND_TRUNC;
2317 case 1: return FP_MODE_ROUND_NEAREST;
2318 case 2: return FP_MODE_INT;
2319 case 3: return FP_MODE_CALLER;
2320 }
2321 case FP_MODE_ROUND_UNKNOWN:
2322 case FP_MODE_NONE:
2323 gcc_unreachable ();
2324 }
2325 gcc_unreachable ();
2326}
2327
2328int
2329epiphany_mode_needed (int entity, rtx insn)
2330{
2331 enum attr_fp_mode mode;
2332
2333 if (recog_memoized (insn) < 0)
2334 {
2335 if (entity == EPIPHANY_MSW_ENTITY_AND
566be57c
JR
2336 || entity == EPIPHANY_MSW_ENTITY_OR
2337 || entity == EPIPHANY_MSW_ENTITY_CONFIG)
feeeff5c
JR
2338 return 2;
2339 return FP_MODE_NONE;
2340 }
2341 mode = get_attr_fp_mode (insn);
2342
2343 switch (entity)
2344 {
2345 case EPIPHANY_MSW_ENTITY_AND:
566be57c 2346 return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
feeeff5c
JR
2347 case EPIPHANY_MSW_ENTITY_OR:
2348 return mode == FP_MODE_INT ? 1 : 2;
566be57c
JR
2349 case EPIPHANY_MSW_ENTITY_CONFIG:
2350 /* We must know/save config before we set it to something else.
2351 Where we need the original value, we are fine with having it
2352 just unchanged from the function start.
2353 Because of the nature of the mode switching optimization,
2354 a restore will be dominated by a clobber. */
2710a27a
JR
2355 if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2356 return 1;
2357 /* A cpecial case are abnormal edges, which are deemed to clobber
2358 the mode as well. We need to pin this effect on a actually
2359 dominating insn, and one where the frame can be accessed, too, in
2360 case the pseudo used to save CONFIG doesn't get a hard register. */
2361 if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2362 return 1;
2363 return 2;
feeeff5c
JR
2364 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2365 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2366 mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2367 /* Fall through. */
2368 case EPIPHANY_MSW_ENTITY_NEAREST:
2369 case EPIPHANY_MSW_ENTITY_TRUNC:
2370 if (mode == FP_MODE_ROUND_UNKNOWN)
2371 {
2372 MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2373 return FP_MODE_NONE;
2374 }
2375 return mode;
2376 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2377 if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2378 return FP_MODE_ROUND_UNKNOWN;
2379 return mode;
2380 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2381 if (mode == FP_MODE_ROUND_UNKNOWN)
2382 return epiphany_normal_fp_rounding;
2383 return mode;
2384 default:
2385 gcc_unreachable ();
2386 }
2387}
2388
2389int
2390epiphany_mode_entry_exit (int entity, bool exit)
2391{
2392 int normal_mode = epiphany_normal_fp_mode ;
2393
2394 MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2395 if (epiphany_is_interrupt_p (current_function_decl))
2396 normal_mode = FP_MODE_CALLER;
2397 switch (entity)
2398 {
2399 case EPIPHANY_MSW_ENTITY_AND:
2400 if (exit)
2401 return normal_mode != FP_MODE_INT ? 1 : 2;
2402 return 0;
2403 case EPIPHANY_MSW_ENTITY_OR:
2404 if (exit)
2405 return normal_mode == FP_MODE_INT ? 1 : 2;
2406 return 0;
566be57c
JR
2407 case EPIPHANY_MSW_ENTITY_CONFIG:
2408 if (exit)
2409 return 2;
2410 return normal_mode == FP_MODE_CALLER ? 0 : 1;
feeeff5c
JR
2411 case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2412 if (normal_mode == FP_MODE_ROUND_NEAREST
2413 || normal_mode == FP_MODE_ROUND_TRUNC)
2414 return FP_MODE_ROUND_UNKNOWN;
2415 /* Fall through. */
2416 case EPIPHANY_MSW_ENTITY_NEAREST:
2417 case EPIPHANY_MSW_ENTITY_TRUNC:
2418 case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2419 case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2420 return normal_mode;
2421 default:
2422 gcc_unreachable ();
2423 }
2424}
2425
2426int
2427epiphany_mode_after (int entity, int last_mode, rtx insn)
2428{
2429 /* We have too few call-saved registers to hope to keep the masks across
2430 calls. */
2431 if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2432 {
b64925dc 2433 if (CALL_P (insn))
feeeff5c
JR
2434 return 0;
2435 return last_mode;
2436 }
2710a27a
JR
2437 /* If there is an abnormal edge, we don't want the config register to
2438 be 'saved' again at the destination.
2439 The frame pointer adjustment is inside a PARALLEL because of the
2440 flags clobber. */
2441 if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2442 && GET_CODE (PATTERN (insn)) == PARALLEL
2443 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2444 && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2445 {
2446 gcc_assert (cfun->has_nonlocal_label);
2447 return 1;
2448 }
feeeff5c
JR
2449 if (recog_memoized (insn) < 0)
2450 return last_mode;
2451 if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2452 && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2453 {
2454 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2455 return FP_MODE_ROUND_NEAREST;
2456 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2457 return FP_MODE_ROUND_TRUNC;
2458 }
2459 if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2460 {
2461 rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2462 int fp_mode;
2463
2464 if (REG_P (src))
2465 return FP_MODE_CALLER;
2466 fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2467 if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2468 && (fp_mode == FP_MODE_ROUND_NEAREST
2469 || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2470 return FP_MODE_ROUND_UNKNOWN;
2471 return fp_mode;
2472 }
2473 return last_mode;
2474}
2475
2476void
2477emit_set_fp_mode (int entity, int mode, HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2478{
2479 rtx save_cc, cc_reg, mask, src, src2;
2480 enum attr_fp_mode fp_mode;
2481
2482 if (!MACHINE_FUNCTION (cfun)->and_mask)
2483 {
2484 MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2485 MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2486 }
2487 if (entity == EPIPHANY_MSW_ENTITY_AND)
2488 {
2489 gcc_assert (mode >= 0 && mode <= 2);
2490 if (mode == 1)
2491 emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2492 gen_int_mode (0xfff1fffe, SImode));
2493 return;
2494 }
2495 else if (entity == EPIPHANY_MSW_ENTITY_OR)
2496 {
2497 gcc_assert (mode >= 0 && mode <= 2);
2498 if (mode == 1)
2499 emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2500 return;
2501 }
566be57c
JR
2502 else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2503 {
2504 /* Mode switching optimization is done after emit_initial_value_sets,
2505 so we have to take care of CONFIG_REGNUM here. */
2506 gcc_assert (mode >= 0 && mode <= 2);
2507 rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2508 if (mode == 1)
2509 emit_insn (gen_save_config (save));
2510 return;
2511 }
feeeff5c
JR
2512 fp_mode = (enum attr_fp_mode) mode;
2513 src = NULL_RTX;
2514
2515 switch (fp_mode)
2516 {
2517 case FP_MODE_CALLER:
566be57c
JR
2518 /* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2519 so that the config save gets inserted before the first use. */
2520 gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
feeeff5c
JR
2521 src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2522 mask = MACHINE_FUNCTION (cfun)->and_mask;
2523 break;
2524 case FP_MODE_ROUND_UNKNOWN:
2525 MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2526 mask = MACHINE_FUNCTION (cfun)->and_mask;
2527 break;
2528 case FP_MODE_ROUND_NEAREST:
2529 if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2530 return;
2531 mask = MACHINE_FUNCTION (cfun)->and_mask;
2532 break;
2533 case FP_MODE_ROUND_TRUNC:
2534 if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2535 return;
2536 mask = MACHINE_FUNCTION (cfun)->and_mask;
2537 break;
2538 case FP_MODE_INT:
2539 mask = MACHINE_FUNCTION (cfun)->or_mask;
2540 break;
2541 case FP_MODE_NONE:
2542 default:
2543 gcc_unreachable ();
2544 }
2545 save_cc = gen_reg_rtx (CCmode);
2546 cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2547 emit_move_insn (save_cc, cc_reg);
2548 mask = force_reg (SImode, mask);
2549 if (!src)
2550 {
2551 rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2552
2553 src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2554 }
2555 if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2556 || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2557 src2 = copy_rtx (src);
2558 else
2559 {
2560 rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2561
2562 src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2563 }
2564 emit_insn (gen_set_fp_mode (src, src2, mask));
2565 emit_move_insn (cc_reg, save_cc);
2566}
2567
2568void
2569epiphany_expand_set_fp_mode (rtx *operands)
2570{
2571 rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2572 rtx src = operands[0];
2573 rtx mask_reg = operands[2];
2574 rtx scratch = operands[3];
2575 enum attr_fp_mode fp_mode;
2576
2577
2578 gcc_assert (rtx_equal_p (src, operands[1])
2579 /* Sometimes reload gets silly and reloads the same pseudo
2580 into different registers. */
2581 || (REG_P (src) && REG_P (operands[1])));
2582
2583 if (!epiphany_uninterruptible_p (current_function_decl))
2584 emit_insn (gen_gid ());
2585 emit_move_insn (scratch, ctrl);
2586
2587 if (GET_CODE (src) == REG)
2588 {
2589 /* FP_MODE_CALLER */
2590 emit_insn (gen_xorsi3 (scratch, scratch, src));
2591 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2592 emit_insn (gen_xorsi3 (scratch, scratch, src));
2593 }
2594 else
2595 {
2596 gcc_assert (GET_CODE (src) == CONST);
2597 src = XEXP (src, 0);
2598 fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2599 switch (fp_mode)
2600 {
2601 case FP_MODE_ROUND_NEAREST:
2602 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2603 break;
2604 case FP_MODE_ROUND_TRUNC:
2605 emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2606 emit_insn (gen_add2_insn (scratch, const1_rtx));
2607 break;
2608 case FP_MODE_INT:
2609 emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2610 break;
2611 case FP_MODE_CALLER:
2612 case FP_MODE_ROUND_UNKNOWN:
2613 case FP_MODE_NONE:
2614 gcc_unreachable ();
2615 }
2616 }
2617 emit_move_insn (ctrl, scratch);
2618 if (!epiphany_uninterruptible_p (current_function_decl))
2619 emit_insn (gen_gie ());
2620}
2621
2622void
2623epiphany_insert_mode_switch_use (rtx insn,
2624 int entity ATTRIBUTE_UNUSED,
2625 int mode ATTRIBUTE_UNUSED)
2626{
2627 rtx pat = PATTERN (insn);
2628 rtvec v;
2629 int len, i;
2630 rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2631 rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2632
2633 if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2634 return;
2635 switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2636 {
2637 case FP_MODE_ROUND_NEAREST:
2638 near = gen_rtx_USE (VOIDmode, near);
2639 trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2640 break;
2641 case FP_MODE_ROUND_TRUNC:
2642 near = gen_rtx_CLOBBER (VOIDmode, near);
2643 trunc = gen_rtx_USE (VOIDmode, trunc);
2644 break;
2645 case FP_MODE_ROUND_UNKNOWN:
2646 near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2647 trunc = copy_rtx (near);
2648 /* Fall through. */
2649 case FP_MODE_INT:
2650 case FP_MODE_CALLER:
2651 near = gen_rtx_USE (VOIDmode, near);
2652 trunc = gen_rtx_USE (VOIDmode, trunc);
2653 break;
2654 case FP_MODE_NONE:
2655 gcc_unreachable ();
2656 }
2657 gcc_assert (GET_CODE (pat) == PARALLEL);
2658 len = XVECLEN (pat, 0);
2659 v = rtvec_alloc (len + 2);
2660 for (i = 0; i < len; i++)
2661 RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2662 RTVEC_ELT (v, len) = near;
2663 RTVEC_ELT (v, len + 1) = trunc;
2664 pat = gen_rtx_PARALLEL (VOIDmode, v);
2665 PATTERN (insn) = pat;
2666 MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2667}
2668
2669bool
2670epiphany_epilogue_uses (int regno)
2671{
2672 if (regno == GPR_LR)
2673 return true;
2674 if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2675 {
2676 if (fixed_regs[regno]
2677 && regno != STATUS_REGNUM && regno != IRET_REGNUM
2678 && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2679 return false;
2680 return true;
2681 }
2682 if (regno == FP_NEAREST_REGNUM
2683 && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2684 return true;
2685 if (regno == FP_TRUNCATE_REGNUM
2686 && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2687 return true;
2688 return false;
2689}
2690
2691static unsigned int
2692epiphany_min_divisions_for_recip_mul (enum machine_mode mode)
2693{
2694 if (flag_reciprocal_math && mode == SFmode)
2695 /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2696 it already at the tree level and expose it to further optimizations. */
2697 return 1;
2698 return default_min_divisions_for_recip_mul (mode);
2699}
2700
2701static enum machine_mode
2702epiphany_preferred_simd_mode (enum machine_mode mode ATTRIBUTE_UNUSED)
2703{
2704 return TARGET_VECT_DOUBLE ? DImode : SImode;
2705}
2706
2707static bool
2708epiphany_vector_mode_supported_p (enum machine_mode mode)
2709{
2710 if (mode == V2SFmode)
2711 return true;
2712 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2713 && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2714 return true;
2715 return false;
2716}
2717
2718static bool
2719epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2720{
2721 /* Vectors which aren't in packed structures will not be less aligned than
2722 the natural alignment of their element type, so this is safe. */
2723 if (TYPE_ALIGN_UNIT (type) == 4)
2724 return !is_packed;
2725
2726 return default_builtin_vector_alignment_reachable (type, is_packed);
2727}
2728
2729static bool
2730epiphany_support_vector_misalignment (enum machine_mode mode, const_tree type,
2731 int misalignment, bool is_packed)
2732{
2733 if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2734 return true;
2735 return default_builtin_support_vector_misalignment (mode, type, misalignment,
2736 is_packed);
2737}
2738
2739/* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2740 structs. Make structs double-word-aligned it they are a double word or
2741 (potentially) larger; failing that, do the same for a size of 32 bits. */
2742unsigned
2743epiphany_special_round_type_align (tree type, unsigned computed,
2744 unsigned specified)
2745{
2746 unsigned align = MAX (computed, specified);
2747 tree field;
2748 HOST_WIDE_INT total, max;
2749 unsigned try_align = FASTEST_ALIGNMENT;
2750
2751 if (maximum_field_alignment && try_align > maximum_field_alignment)
2752 try_align = maximum_field_alignment;
2753 if (align >= try_align)
2754 return align;
2755 for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2756 {
2757 tree offset, size;
2758
2759 if (TREE_CODE (field) != FIELD_DECL
2760 || TREE_TYPE (field) == error_mark_node)
2761 continue;
2762 offset = bit_position (field);
2763 size = DECL_SIZE (field);
cc269bb6 2764 if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
eb1ce453
KZ
2765 || tree_to_uhwi (offset) >= try_align
2766 || tree_to_uhwi (size) >= try_align)
feeeff5c 2767 return try_align;
eb1ce453 2768 total = tree_to_uhwi (offset) + tree_to_uhwi (size);
feeeff5c
JR
2769 if (total > max)
2770 max = total;
2771 }
2772 if (max >= (HOST_WIDE_INT) try_align)
2773 align = try_align;
2774 else if (try_align > 32 && max >= 32)
2775 align = max > 32 ? 64 : 32;
2776 return align;
2777}
2778
2779/* Upping the alignment of arrays in structs is not only a performance
2780 enhancement, it also helps preserve assumptions about how
2781 arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2782 libgcov.c . */
2783unsigned
2784epiphany_adjust_field_align (tree field, unsigned computed)
2785{
2786 if (computed == 32
2787 && TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
2788 {
2789 tree elmsz = TYPE_SIZE (TREE_TYPE (TREE_TYPE (field)));
2790
ae7e9ddd 2791 if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
feeeff5c
JR
2792 return 64;
2793 }
2794 return computed;
2795}
2796
2797/* Output code to add DELTA to the first argument, and then jump
2798 to FUNCTION. Used for C++ multiple inheritance. */
2799static void
2800epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2801 HOST_WIDE_INT delta,
2802 HOST_WIDE_INT vcall_offset,
2803 tree function)
2804{
2805 int this_regno
2806 = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2807 const char *this_name = reg_names[this_regno];
2808 const char *fname;
2809
2810 /* We use IP and R16 as a scratch registers. */
2811 gcc_assert (call_used_regs [GPR_IP]);
2812 gcc_assert (call_used_regs [GPR_16]);
2813
2814 /* Add DELTA. When possible use a plain add, otherwise load it into
2815 a register first. */
2816 if (delta == 0)
2817 ; /* Done. */
2818 else if (SIMM11 (delta))
2819 asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2820 else if (delta < 0 && delta >= -0xffff)
2821 {
2822 asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2823 asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2824 }
2825 else
2826 {
2827 asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2828 if (delta & ~0xffff)
2829 asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2830 asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2831 }
2832
2833 /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */
2834 if (vcall_offset != 0)
2835 {
2836 /* ldr ip,[this] --> temp = *this
2837 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2838 add this,this,ip --> this+ = *(*this + vcall_offset) */
2839 asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2840 if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2841 || (vcall_offset & 3) != 0)
2842 {
2843 asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2844 asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2845 asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2846 }
2847 else
2848 asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2849 asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2850 }
2851
2852 fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2853 if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2854 {
2855 fputs ("\tmov\tip,%low(", file);
2856 assemble_name (file, fname);
2857 fputs (")\n\tmovt\tip,%high(", file);
2858 assemble_name (file, fname);
2859 fputs (")\n\tjr ip\n", file);
2860 }
2861 else
2862 {
2863 fputs ("\tb\t", file);
2864 assemble_name (file, fname);
2865 fputc ('\n', file);
2866 }
2867}
2868
188b7e23
JR
2869void
2870epiphany_start_function (FILE *file, const char *name, tree decl)
2871{
60098013
JR
2872 /* If the function doesn't fit into the on-chip memory, it will have a
2873 section attribute - or lack of it - that denotes it goes somewhere else.
2874 But the architecture spec says that an interrupt vector still has to
2875 point to on-chip memory. So we must place a jump there to get to the
2876 actual function implementation. The forwarder_section attribute
2877 specifies the section where this jump goes.
2878 This mechanism can also be useful to have a shortcall destination for
2879 a function that is actually placed much farther away. */
2880 tree attrs, int_attr, int_names, int_name, forwarder_attr;
188b7e23
JR
2881
2882 attrs = DECL_ATTRIBUTES (decl);
2883 int_attr = lookup_attribute ("interrupt", attrs);
2884 if (int_attr)
60098013
JR
2885 for (int_names = TREE_VALUE (int_attr); int_names;
2886 int_names = TREE_CHAIN (int_names))
2887 {
2888 char buf[99];
2889
2890 int_name = TREE_VALUE (int_names);
2891 sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2892 switch_to_section (get_section (buf, SECTION_CODE, decl));
2893 fputs ("\tb\t", file);
2894 assemble_name (file, name);
2895 fputc ('\n', file);
2896 }
2897 forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2898 if (forwarder_attr)
2899 {
2900 const char *prefix = "__forwarder_dst_";
2901 char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2902
2903 strcpy (dst_name, prefix);
2904 strcat (dst_name, name);
2905 forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2906 switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2907 SECTION_CODE, decl));
2908 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2909 if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
2910 {
2911 int tmp = GPR_0;
188b7e23 2912
60098013
JR
2913 if (int_attr)
2914 fputs ("\tstrd r0,[sp,-1]\n", file);
2915 else
2916 tmp = GPR_16;
2917 gcc_assert (call_used_regs[tmp]);
2918 fprintf (file, "\tmov r%d,%%low(", tmp);
2919 assemble_name (file, dst_name);
2920 fprintf (file, ")\n"
2921 "\tmovt r%d,%%high(", tmp);
2922 assemble_name (file, dst_name);
2923 fprintf (file, ")\n"
2924 "\tjr r%d\n", tmp);
2925 }
2926 else
2927 {
2928 fputs ("\tb\t", file);
2929 assemble_name (file, dst_name);
2930 fputc ('\n', file);
2931 }
2932 name = dst_name;
188b7e23 2933 }
60098013 2934 switch_to_section (function_section (decl));
188b7e23
JR
2935 ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2936}
2937
feeeff5c 2938struct gcc_target targetm = TARGET_INITIALIZER;