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