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