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