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