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