1 /* Subroutines used for code generation on the EPIPHANY cpu.
2    Copyright (C) 1994-2018 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, machine_mode,
75 					const_tree, bool);
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_mode_tree_bool_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_regs[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 has type TYPE
715    and mode MODE, and we rely on this fact.  */
716 
717 
718 static void
epiphany_setup_incoming_varargs(cumulative_args_t cum,machine_mode mode,tree type,int * pretend_size,int no_rtl)719 epiphany_setup_incoming_varargs (cumulative_args_t cum, machine_mode mode,
720 				 tree type, int *pretend_size, int no_rtl)
721 {
722   int first_anon_arg;
723   CUMULATIVE_ARGS next_cum;
724   machine_function_t *mf = MACHINE_FUNCTION (cfun);
725 
726   /* All BLKmode values are passed by reference.  */
727   gcc_assert (mode != BLKmode);
728 
729   next_cum = *get_cumulative_args (cum);
730   next_cum
731     = ROUND_ADVANCE_CUM (next_cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
732   first_anon_arg = next_cum;
733 
734   if (first_anon_arg < MAX_EPIPHANY_PARM_REGS && !no_rtl)
735     {
736       /* Note that first_reg_offset < MAX_EPIPHANY_PARM_REGS.  */
737       int first_reg_offset = first_anon_arg;
738 
739       *pretend_size = ((MAX_EPIPHANY_PARM_REGS - first_reg_offset)
740 		       * UNITS_PER_WORD);
741     }
742   mf->args_parsed = 1;
743   mf->pretend_args_odd = ((*pretend_size & UNITS_PER_WORD) ? 1 : 0);
744 }
745 
746 static int
epiphany_arg_partial_bytes(cumulative_args_t cum,machine_mode mode,tree type,bool named ATTRIBUTE_UNUSED)747 epiphany_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
748 			    tree type, bool named ATTRIBUTE_UNUSED)
749 {
750   int words = 0, rounded_cum;
751 
752   gcc_assert (!epiphany_pass_by_reference (cum, mode, type, /* named */ true));
753 
754   rounded_cum = ROUND_ADVANCE_CUM (*get_cumulative_args (cum), mode, type);
755   if (rounded_cum < MAX_EPIPHANY_PARM_REGS)
756     {
757       words = MAX_EPIPHANY_PARM_REGS - rounded_cum;
758       if (words >= ROUND_ADVANCE_ARG (mode, type))
759 	words = 0;
760     }
761   return words * UNITS_PER_WORD;
762 }
763 
764 /* Cost functions.  */
765 
766 /* Compute a (partial) cost for rtx X.  Return true if the complete
767    cost has been computed, and false if subexpressions should be
768    scanned.  In either case, *TOTAL contains the cost result.  */
769 
770 static bool
epiphany_rtx_costs(rtx x,machine_mode mode,int outer_code,int opno ATTRIBUTE_UNUSED,int * total,bool speed ATTRIBUTE_UNUSED)771 epiphany_rtx_costs (rtx x, machine_mode mode, int outer_code,
772 		    int opno ATTRIBUTE_UNUSED,
773 		    int *total, bool speed ATTRIBUTE_UNUSED)
774 {
775   int code = GET_CODE (x);
776 
777   switch (code)
778     {
779       /* Small integers in the right context are as cheap as registers.  */
780     case CONST_INT:
781       if ((outer_code == PLUS || outer_code == MINUS)
782 	  && SIMM11 (INTVAL (x)))
783 	{
784 	  *total = 0;
785 	  return true;
786 	}
787       if (IMM16 (INTVAL (x)))
788 	{
789 	  *total = outer_code == SET ? 0 : COSTS_N_INSNS (1);
790 	  return true;
791 	}
792       /* FALLTHRU */
793 
794     case CONST:
795     case LABEL_REF:
796     case SYMBOL_REF:
797       *total = COSTS_N_INSNS ((epiphany_small16 (x) ? 0 : 1)
798 			      + (outer_code == SET ? 0 : 1));
799       return true;
800 
801     case CONST_DOUBLE:
802       {
803 	rtx high, low;
804 	split_double (x, &high, &low);
805 	*total = COSTS_N_INSNS (!IMM16 (INTVAL (high))
806 				+ !IMM16 (INTVAL (low)));
807 	return true;
808       }
809 
810     case ASHIFT:
811     case ASHIFTRT:
812     case LSHIFTRT:
813       *total = COSTS_N_INSNS (1);
814       return true;
815 
816     case COMPARE:
817       switch (mode)
818 	{
819 	/* There are a number of single-insn combiner patterns that use
820 	   the flag side effects of arithmetic.  */
821 	case E_CC_N_NEmode:
822 	case E_CC_C_LTUmode:
823 	case E_CC_C_GTUmode:
824 	  return true;
825 	default:
826 	  return false;
827 	}
828 
829 
830     case SET:
831       {
832 	rtx src = SET_SRC (x);
833 	if (BINARY_P (src))
834 	  *total = 0;
835 	return false;
836       }
837 
838     default:
839       return false;
840     }
841 }
842 
843 
844 /* Provide the costs of an addressing mode that contains ADDR.
845    If ADDR is not a valid address, its cost is irrelevant.  */
846 
847 static int
epiphany_address_cost(rtx addr,machine_mode mode,addr_space_t as ATTRIBUTE_UNUSED,bool speed)848 epiphany_address_cost (rtx addr, machine_mode mode,
849 		       addr_space_t as ATTRIBUTE_UNUSED, bool speed)
850 {
851   rtx reg;
852   rtx off = const0_rtx;
853   int i;
854 
855   if (speed)
856     return 0;
857   /* Return 0 for addresses valid in short insns, 1 for addresses only valid
858      in long insns.  */
859   switch (GET_CODE (addr))
860     {
861     case PLUS :
862       reg = XEXP (addr, 0);
863       off = XEXP (addr, 1);
864       break;
865     case POST_MODIFY:
866       reg = XEXP (addr, 0);
867       off = XEXP (addr, 1);
868       gcc_assert (GET_CODE (off) == PLUS && rtx_equal_p (reg, XEXP (off, 0)));
869       off = XEXP (off, 1);
870       if (satisfies_constraint_Rgs (reg) && satisfies_constraint_Rgs (off))
871 	return 0;
872       return 1;
873     case REG:
874     default:
875       reg = addr;
876       break;
877     }
878   if (!satisfies_constraint_Rgs (reg))
879     return 1;
880   /* The offset range available for short instructions depends on the mode
881      of the memory access.  */
882   /* First, make sure we have a valid integer.  */
883   if (!satisfies_constraint_L (off))
884     return 1;
885   i = INTVAL (off);
886   switch (GET_MODE_SIZE (mode))
887     {
888       default:
889       case 4:
890 	if (i & 1)
891 	  return 1;
892 	i >>= 1;
893 	/* Fall through.  */
894       case 2:
895 	if (i & 1)
896 	  return 1;
897 	i >>= 1;
898 	/* Fall through.  */
899       case 1:
900 	return i < -7 || i > 7;
901     }
902 }
903 
904 /* Compute the cost of moving data between registers and memory.
905    For integer, load latency is twice as long as register-register moves,
906    but issue pich is the same.  For floating point, load latency is three
907    times as much as a reg-reg move.  */
908 static int
epiphany_memory_move_cost(machine_mode mode,reg_class_t rclass ATTRIBUTE_UNUSED,bool in ATTRIBUTE_UNUSED)909 epiphany_memory_move_cost (machine_mode mode,
910                           reg_class_t rclass ATTRIBUTE_UNUSED,
911                           bool in ATTRIBUTE_UNUSED)
912 {
913   return GET_MODE_CLASS (mode) == MODE_INT ? 3 : 4;
914 }
915 
916 /* Function prologue/epilogue handlers.  */
917 
918 /* EPIPHANY stack frames look like:
919 
920 	     Before call                       After call
921 	+-----------------------+       +-----------------------+
922 	|                       |       |                       |
923    high |  local variables,     |       |  local variables,     |
924    mem  |  reg save area, etc.  |       |  reg save area, etc.  |
925 	|                       |       |                       |
926 	+-----------------------+       +-----------------------+
927 	|                       |       |                       |
928 	|  arguments on stack.  |       |  arguments on stack.  |
929 	|                       |       |                       |
930   SP+8->+-----------------------+FP+8m->+-----------------------+
931 	| 2 word save area for  |       |  reg parm save area,  |
932 	| leaf funcs / flags    |       |  only created for     |
933   SP+0->+-----------------------+       |  variable argument    |
934 					|  functions            |
935 				 FP+8n->+-----------------------+
936 					|                       |
937 					|  register save area   |
938 					|                       |
939 					+-----------------------+
940 					|                       |
941 					|  local variables      |
942 					|                       |
943 				  FP+0->+-----------------------+
944 					|                       |
945 					|  alloca allocations   |
946 					|                       |
947 					+-----------------------+
948 					|                       |
949 					|  arguments on stack   |
950 					|                       |
951 				  SP+8->+-----------------------+
952    low                                  | 2 word save area for  |
953    memory                               | leaf funcs / flags    |
954 				  SP+0->+-----------------------+
955 
956 Notes:
957 1) The "reg parm save area" does not exist for non variable argument fns.
958    The "reg parm save area" could be eliminated if we created our
959    own TARGET_GIMPLIFY_VA_ARG_EXPR, but that has tradeoffs as well
960    (so it's not done).  */
961 
962 /* Structure to be filled in by epiphany_compute_frame_size with register
963    save masks, and offsets for the current function.  */
964 struct epiphany_frame_info
965 {
966   unsigned int total_size;	/* # bytes that the entire frame takes up.  */
967   unsigned int pretend_size;	/* # bytes we push and pretend caller did.  */
968   unsigned int args_size;	/* # bytes that outgoing arguments take up.  */
969   unsigned int reg_size;	/* # bytes needed to store regs.  */
970   unsigned int var_size;	/* # bytes that variables take up.  */
971   HARD_REG_SET gmask;		/* Set of saved gp registers.  */
972   int          initialized;	/* Nonzero if frame size already calculated.  */
973   int      stld_sz;             /* Current load/store data size for offset
974 				   adjustment. */
975   int      need_fp;             /* value to override "frame_pointer_needed */
976   /* FIRST_SLOT is the slot that is saved first, at the very start of
977      the frame, with a POST_MODIFY to allocate the frame, if the size fits,
978      or at least the parm and register save areas, otherwise.
979      In the case of a large frame, LAST_SLOT is the slot that is saved last,
980      with a POST_MODIFY to allocate the rest of the frame.  */
981   int first_slot, last_slot, first_slot_offset, last_slot_offset;
982   int first_slot_size;
983   int small_threshold;
984 };
985 
986 /* Current frame information calculated by epiphany_compute_frame_size.  */
987 static struct epiphany_frame_info current_frame_info;
988 
989 /* Zero structure to initialize current_frame_info.  */
990 static struct epiphany_frame_info zero_frame_info;
991 
992 /* The usual; we set up our machine_function data.  */
993 static struct machine_function *
epiphany_init_machine_status(void)994 epiphany_init_machine_status (void)
995 {
996   struct machine_function *machine;
997 
998   /* Reset state info for each function.  */
999   current_frame_info = zero_frame_info;
1000 
1001   machine = ggc_cleared_alloc<machine_function_t> ();
1002 
1003   return machine;
1004 }
1005 
1006 /* Implements INIT_EXPANDERS.  We just set up to call the above
1007  *    function.  */
1008 void
epiphany_init_expanders(void)1009 epiphany_init_expanders (void)
1010 {
1011   init_machine_status = epiphany_init_machine_status;
1012 }
1013 
1014 /* Type of function DECL.
1015 
1016    The result is cached.  To reset the cache at the end of a function,
1017    call with DECL = NULL_TREE.  */
1018 
1019 static enum epiphany_function_type
epiphany_compute_function_type(tree decl)1020 epiphany_compute_function_type (tree decl)
1021 {
1022   tree a;
1023   /* Cached value.  */
1024   static enum epiphany_function_type fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1025   /* Last function we were called for.  */
1026   static tree last_fn = NULL_TREE;
1027 
1028   /* Resetting the cached value?  */
1029   if (decl == NULL_TREE)
1030     {
1031       fn_type = EPIPHANY_FUNCTION_UNKNOWN;
1032       last_fn = NULL_TREE;
1033       return fn_type;
1034     }
1035 
1036   if (decl == last_fn && fn_type != EPIPHANY_FUNCTION_UNKNOWN)
1037     return fn_type;
1038 
1039   /* Assume we have a normal function (not an interrupt handler).  */
1040   fn_type = EPIPHANY_FUNCTION_NORMAL;
1041 
1042   /* Now see if this is an interrupt handler.  */
1043   for (a = DECL_ATTRIBUTES (decl);
1044        a;
1045        a = TREE_CHAIN (a))
1046     {
1047       tree name = TREE_PURPOSE (a);
1048 
1049       if (name == get_identifier ("interrupt"))
1050 	fn_type = EPIPHANY_FUNCTION_INTERRUPT;
1051     }
1052 
1053   last_fn = decl;
1054   return fn_type;
1055 }
1056 
1057 #define RETURN_ADDR_REGNUM GPR_LR
1058 #define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
1059 #define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
1060 
1061 /* Tell prologue and epilogue if register REGNO should be saved / restored.
1062    The return address and frame pointer are treated separately.
1063    Don't consider them here.  */
1064 #define MUST_SAVE_REGISTER(regno, interrupt_p) \
1065   ((df_regs_ever_live_p (regno) \
1066     || (interrupt_p && !crtl->is_leaf \
1067 	&& call_used_regs[regno] && !fixed_regs[regno])) \
1068    && (!call_used_regs[regno] || regno == GPR_LR \
1069        || (interrupt_p && regno != GPR_SP)))
1070 
1071 #define MUST_SAVE_RETURN_ADDR 0
1072 
1073 /* Return the bytes needed to compute the frame pointer from the current
1074    stack pointer.
1075 
1076    SIZE is the size needed for local variables.  */
1077 
1078 static unsigned int
epiphany_compute_frame_size(int size)1079 epiphany_compute_frame_size (int size /* # of var. bytes allocated.  */)
1080 {
1081   int regno;
1082   unsigned int total_size, var_size, args_size, pretend_size, reg_size;
1083   HARD_REG_SET gmask;
1084   enum epiphany_function_type fn_type;
1085   int interrupt_p;
1086   int first_slot, last_slot, first_slot_offset, last_slot_offset;
1087   int first_slot_size;
1088   int small_slots = 0;
1089 
1090   var_size	= size;
1091   args_size	= crtl->outgoing_args_size;
1092   pretend_size	= crtl->args.pretend_args_size;
1093   total_size	= args_size + var_size;
1094   reg_size	= 0;
1095   CLEAR_HARD_REG_SET (gmask);
1096   first_slot = -1;
1097   first_slot_offset = 0;
1098   last_slot = -1;
1099   last_slot_offset = 0;
1100   first_slot_size = UNITS_PER_WORD;
1101 
1102   /* See if this is an interrupt handler.  Call used registers must be saved
1103      for them too.  */
1104   fn_type = epiphany_compute_function_type (current_function_decl);
1105   interrupt_p = EPIPHANY_INTERRUPT_P (fn_type);
1106 
1107   /* Calculate space needed for registers.  */
1108 
1109   for (regno = MAX_EPIPHANY_PARM_REGS - 1; pretend_size > reg_size; regno--)
1110     {
1111       reg_size += UNITS_PER_WORD;
1112       SET_HARD_REG_BIT (gmask, regno);
1113       if (epiphany_stack_offset - reg_size == 0)
1114 	first_slot = regno;
1115     }
1116 
1117   if (interrupt_p)
1118     reg_size += 2 * UNITS_PER_WORD;
1119   else
1120     small_slots = epiphany_stack_offset / UNITS_PER_WORD;
1121 
1122   if (frame_pointer_needed)
1123     {
1124       current_frame_info.need_fp = 1;
1125       if (!interrupt_p && first_slot < 0)
1126 	first_slot = GPR_FP;
1127     }
1128   else
1129     current_frame_info.need_fp = 0;
1130   for (regno = 0; regno <= GPR_LAST; regno++)
1131     {
1132       if (MUST_SAVE_REGISTER (regno, interrupt_p))
1133 	{
1134 	  gcc_assert (!TEST_HARD_REG_BIT (gmask, regno));
1135 	  reg_size += UNITS_PER_WORD;
1136 	  SET_HARD_REG_BIT (gmask, regno);
1137 	  /* FIXME: when optimizing for speed, take schedling into account
1138 	     when selecting these registers.  */
1139 	  if (regno == first_slot)
1140 	    gcc_assert (regno == GPR_FP && frame_pointer_needed);
1141 	  else if (!interrupt_p && first_slot < 0)
1142 	    first_slot = regno;
1143 	  else if (last_slot < 0
1144 		   && (first_slot ^ regno) != 1
1145 		   && (!interrupt_p || regno > GPR_1))
1146 	    last_slot = regno;
1147 	}
1148     }
1149   if (TEST_HARD_REG_BIT (gmask, GPR_LR))
1150     MACHINE_FUNCTION (cfun)->lr_clobbered = 1;
1151   /* ??? Could sometimes do better than that.  */
1152   current_frame_info.small_threshold
1153     = (optimize >= 3 || interrupt_p ? 0
1154        : pretend_size ? small_slots
1155        : 4 + small_slots - (first_slot == GPR_FP));
1156 
1157   /* If there might be variables with 64-bit alignment requirement, align the
1158      start of the variables.  */
1159   if (var_size >= 2 * UNITS_PER_WORD
1160       /* We don't want to split a double reg save/restore across two unpaired
1161 	 stack slots when optimizing.  This rounding could be avoided with
1162 	 more complex reordering of the register saves, but that would seem
1163 	 to be a lot of code complexity for little gain.  */
1164       || (reg_size > 8 && optimize))
1165     reg_size = EPIPHANY_STACK_ALIGN (reg_size);
1166   if (((total_size + reg_size
1167 	/* Reserve space for UNKNOWN_REGNUM.  */
1168 	+ EPIPHANY_STACK_ALIGN (4))
1169        <= (unsigned) epiphany_stack_offset)
1170       && !interrupt_p
1171       && crtl->is_leaf && !frame_pointer_needed)
1172     {
1173       first_slot = -1;
1174       last_slot = -1;
1175       goto alloc_done;
1176     }
1177   else if (reg_size
1178 	   && !interrupt_p
1179 	   && reg_size < (unsigned HOST_WIDE_INT) epiphany_stack_offset)
1180     reg_size = epiphany_stack_offset;
1181   if (interrupt_p)
1182     {
1183       if (total_size + reg_size < 0x3fc)
1184 	{
1185 	  first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1186 	  first_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1187 	  last_slot = -1;
1188 	}
1189       else
1190 	{
1191 	  first_slot_offset = EPIPHANY_STACK_ALIGN (reg_size);
1192 	  last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1193 	  last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1194 	  if (last_slot >= 0)
1195 	    CLEAR_HARD_REG_BIT (gmask, last_slot);
1196 	}
1197     }
1198   else if (total_size + reg_size < 0x1ffc && first_slot >= 0)
1199     {
1200       first_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1201       last_slot = -1;
1202     }
1203   else
1204     {
1205       if (total_size + reg_size <= (unsigned) epiphany_stack_offset)
1206 	{
1207 	  gcc_assert (first_slot < 0);
1208 	  gcc_assert (reg_size == 0 || (int) reg_size == epiphany_stack_offset);
1209 	  last_slot_offset = EPIPHANY_STACK_ALIGN (total_size + reg_size);
1210 	}
1211       else
1212 	{
1213 	  first_slot_offset
1214 	    = (reg_size
1215 	       ? EPIPHANY_STACK_ALIGN (reg_size - epiphany_stack_offset) : 0);
1216 	  if (!first_slot_offset)
1217 	    {
1218 	      if (first_slot != GPR_FP || !current_frame_info.need_fp)
1219 		last_slot = first_slot;
1220 	      first_slot = -1;
1221 	    }
1222 	  last_slot_offset = EPIPHANY_STACK_ALIGN (total_size);
1223 	  if (reg_size)
1224 	    last_slot_offset += EPIPHANY_STACK_ALIGN (epiphany_stack_offset);
1225 	}
1226       if (last_slot >= 0)
1227 	CLEAR_HARD_REG_BIT (gmask, last_slot);
1228     }
1229  alloc_done:
1230   if (first_slot >= 0)
1231     {
1232       CLEAR_HARD_REG_BIT (gmask, first_slot);
1233       if (TEST_HARD_REG_BIT (gmask, first_slot ^ 1)
1234 	  && epiphany_stack_offset - pretend_size >= 2 * UNITS_PER_WORD)
1235 	{
1236 	  CLEAR_HARD_REG_BIT (gmask, first_slot ^ 1);
1237 	  first_slot_size = 2 * UNITS_PER_WORD;
1238 	  first_slot &= ~1;
1239 	}
1240     }
1241   total_size = first_slot_offset + last_slot_offset;
1242 
1243   /* Save computed information.  */
1244   current_frame_info.total_size   = total_size;
1245   current_frame_info.pretend_size = pretend_size;
1246   current_frame_info.var_size     = var_size;
1247   current_frame_info.args_size    = args_size;
1248   current_frame_info.reg_size	  = reg_size;
1249   COPY_HARD_REG_SET (current_frame_info.gmask, gmask);
1250   current_frame_info.first_slot		= first_slot;
1251   current_frame_info.last_slot		= last_slot;
1252   current_frame_info.first_slot_offset	= first_slot_offset;
1253   current_frame_info.first_slot_size	= first_slot_size;
1254   current_frame_info.last_slot_offset	= last_slot_offset;
1255 
1256   current_frame_info.initialized  = reload_completed;
1257 
1258   /* Ok, we're done.  */
1259   return total_size;
1260 }
1261 
1262 /* Print operand X (an rtx) in assembler syntax to file FILE.
1263    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
1264    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
1265 
1266 static void
epiphany_print_operand(FILE * file,rtx x,int code)1267 epiphany_print_operand (FILE *file, rtx x, int code)
1268 {
1269   switch (code)
1270     {
1271     case 'd':
1272       fputs (epiphany_condition_codes[get_epiphany_condition_code (x)], file);
1273       return;
1274     case 'D':
1275      fputs (epiphany_condition_codes[EPIPHANY_INVERSE_CONDITION_CODE
1276 				 (get_epiphany_condition_code (x))],
1277 	     file);
1278       return;
1279 
1280     case 'X':
1281       current_frame_info.stld_sz = 8;
1282       break;
1283 
1284     case 'C' :
1285       current_frame_info.stld_sz = 4;
1286       break;
1287 
1288     case 'c' :
1289       current_frame_info.stld_sz = 2;
1290       break;
1291 
1292     case 'f':
1293      fputs (REG_P (x) ? "jalr " : "bl ", file);
1294      break;
1295 
1296     case '-':
1297     fprintf (file, "r%d", epiphany_m1reg);
1298     return;
1299 
1300     case 0 :
1301       /* Do nothing special.  */
1302       break;
1303     default :
1304       /* Unknown flag.  */
1305       output_operand_lossage ("invalid operand output code");
1306     }
1307 
1308   switch (GET_CODE (x))
1309     {
1310       rtx addr;
1311       rtx offset;
1312 
1313     case REG :
1314       fputs (reg_names[REGNO (x)], file);
1315       break;
1316     case MEM :
1317       if (code == 0)
1318 	current_frame_info.stld_sz = 1;
1319       fputc ('[', file);
1320       addr = XEXP (x, 0);
1321       switch (GET_CODE (addr))
1322 	{
1323 	  case POST_INC:
1324 	    offset = GEN_INT (GET_MODE_SIZE (GET_MODE (x)));
1325 	    addr = XEXP (addr, 0);
1326 	    break;
1327 	  case POST_DEC:
1328 	    offset = GEN_INT (-GET_MODE_SIZE (GET_MODE (x)));
1329 	    addr = XEXP (addr, 0);
1330 	    break;
1331 	  case POST_MODIFY:
1332 	    offset = XEXP (XEXP (addr, 1), 1);
1333 	    addr = XEXP (addr, 0);
1334 	    break;
1335 	  default:
1336 	    offset = 0;
1337 	    break;
1338 	}
1339       output_address (GET_MODE (x), addr);
1340       fputc (']', file);
1341       if (offset)
1342 	{
1343 	  fputc (',', file);
1344 	  if (CONST_INT_P (offset)) switch (GET_MODE_SIZE (GET_MODE (x)))
1345 	    {
1346 	      default:
1347 		gcc_unreachable ();
1348 	      case 8:
1349 		offset = GEN_INT (INTVAL (offset) >> 3);
1350 		break;
1351 	      case 4:
1352 		offset = GEN_INT (INTVAL (offset) >> 2);
1353 		break;
1354 	      case 2:
1355 		offset = GEN_INT (INTVAL (offset) >> 1);
1356 		break;
1357 	      case 1:
1358 		break;
1359 	    }
1360 	  output_address (GET_MODE (x), offset);
1361 	}
1362       break;
1363     case CONST_DOUBLE :
1364       /* We handle SFmode constants here as output_addr_const doesn't.  */
1365       if (GET_MODE (x) == SFmode)
1366 	{
1367 	  long l;
1368 
1369 	  REAL_VALUE_TO_TARGET_SINGLE (*CONST_DOUBLE_REAL_VALUE (x), l);
1370 	  fprintf (file, "%s0x%08lx", IMMEDIATE_PREFIX, l);
1371 	  break;
1372 	}
1373       /* FALLTHRU */
1374       /* Let output_addr_const deal with it.  */
1375     case CONST_INT:
1376       fprintf(file,"%s",IMMEDIATE_PREFIX);
1377       if (code == 'C' || code == 'X')
1378 	{
1379 	  fprintf (file, "%ld",
1380 		   (long) (INTVAL (x) / current_frame_info.stld_sz));
1381 	  break;
1382 	}
1383       /* Fall through */
1384     default :
1385       output_addr_const (file, x);
1386       break;
1387     }
1388 }
1389 
1390 /* Print a memory address as an operand to reference that memory location.  */
1391 
1392 static void
epiphany_print_operand_address(FILE * file,machine_mode,rtx addr)1393 epiphany_print_operand_address (FILE *file, machine_mode /*mode*/, rtx addr)
1394 {
1395   register rtx base, index = 0;
1396   int offset = 0;
1397 
1398   switch (GET_CODE (addr))
1399     {
1400     case REG :
1401       fputs (reg_names[REGNO (addr)], file);
1402       break;
1403     case SYMBOL_REF :
1404       if (/*???*/ 0 && SYMBOL_REF_FUNCTION_P (addr))
1405 	{
1406 	  output_addr_const (file, addr);
1407 	}
1408       else
1409 	{
1410 	  output_addr_const (file, addr);
1411 	}
1412       break;
1413     case PLUS :
1414       if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
1415 	offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
1416       else if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
1417 	offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
1418       else
1419 	base = XEXP (addr, 0), index = XEXP (addr, 1);
1420       gcc_assert (GET_CODE (base) == REG);
1421       fputs (reg_names[REGNO (base)], file);
1422       if (index == 0)
1423 	{
1424 	  /*
1425 	  ** ++rk quirky method to scale offset for ld/str.......
1426 	  */
1427 	  fprintf (file, ",%s%d", IMMEDIATE_PREFIX,
1428 		   offset/current_frame_info.stld_sz);
1429 	}
1430       else
1431 	{
1432 	  switch (GET_CODE (index))
1433 	    {
1434 	    case REG:
1435 	      fprintf (file, ",%s", reg_names[REGNO (index)]);
1436 	      break;
1437 	    case SYMBOL_REF:
1438 	      fputc (',', file), output_addr_const (file, index);
1439 	      break;
1440 	    default:
1441 	      gcc_unreachable ();
1442 	    }
1443 	}
1444       break;
1445     case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case POST_MODIFY:
1446       /* We shouldn't get here as we've lost the mode of the memory object
1447 	 (which says how much to inc/dec by.
1448 	 FIXME: We have the mode now, address printing can be moved into this
1449 	 function.  */
1450       gcc_unreachable ();
1451       break;
1452     default:
1453       output_addr_const (file, addr);
1454       break;
1455     }
1456 }
1457 
1458 void
epiphany_final_prescan_insn(rtx_insn * insn ATTRIBUTE_UNUSED,rtx * opvec ATTRIBUTE_UNUSED,int noperands ATTRIBUTE_UNUSED)1459 epiphany_final_prescan_insn (rtx_insn *insn ATTRIBUTE_UNUSED,
1460 			     rtx *opvec ATTRIBUTE_UNUSED,
1461 			     int noperands ATTRIBUTE_UNUSED)
1462 {
1463   int i = epiphany_n_nops;
1464   rtx pat ATTRIBUTE_UNUSED;
1465 
1466   while (i--)
1467     fputs ("\tnop\n", asm_out_file);
1468 }
1469 
1470 
1471 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
1472 
1473 static bool
epiphany_return_in_memory(const_tree type,const_tree fntype ATTRIBUTE_UNUSED)1474 epiphany_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
1475 {
1476   HOST_WIDE_INT size = int_size_in_bytes (type);
1477 
1478   if (AGGREGATE_TYPE_P (type)
1479       && (TYPE_MODE (type) == BLKmode || TYPE_NEEDS_CONSTRUCTING (type)))
1480     return true;
1481   return (size == -1 || size > 8);
1482 }
1483 
1484 /* For EPIPHANY, All aggregates and arguments greater than 8 bytes are
1485    passed by reference.  */
1486 
1487 static bool
epiphany_pass_by_reference(cumulative_args_t ca ATTRIBUTE_UNUSED,machine_mode mode,const_tree type,bool named ATTRIBUTE_UNUSED)1488 epiphany_pass_by_reference (cumulative_args_t ca ATTRIBUTE_UNUSED,
1489 		       machine_mode mode, const_tree type,
1490 		       bool named ATTRIBUTE_UNUSED)
1491 {
1492   if (type)
1493     {
1494       if (AGGREGATE_TYPE_P (type)
1495 	  && (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   COPY_HARD_REG_SET (reg_class_contents[SIBCALL_REGS],
2244 		     reg_class_contents[GENERAL_REGS]);
2245   /* It would be simpler and quicker if we could just use
2246      AND_COMPL_HARD_REG_SET, alas, call_used_reg_set is yet uninitialized;
2247      it is set up later by our caller.  */
2248   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
2249     if (!call_used_regs[i])
2250       CLEAR_HARD_REG_BIT (reg_class_contents[SIBCALL_REGS], i);
2251 }
2252 
2253 /* Determine where to put an argument to a function.
2254    Value is zero to push the argument on the stack,
2255    or a hard register in which to store the argument.
2256 
2257    MODE is the argument's machine mode.
2258    TYPE is the data type of the argument (as a tree).
2259     This is null for libcalls where that information may
2260     not be available.
2261    CUM is a variable of type CUMULATIVE_ARGS which gives info about
2262     the preceding args and about the function being called.
2263    NAMED is nonzero if this argument is a named parameter
2264     (otherwise it is an extra parameter matching an ellipsis).  */
2265 /* On the EPIPHANY the first MAX_EPIPHANY_PARM_REGS args are normally in
2266    registers and the rest are pushed.  */
2267 static rtx
epiphany_function_arg(cumulative_args_t cum_v,machine_mode mode,const_tree type,bool named ATTRIBUTE_UNUSED)2268 epiphany_function_arg (cumulative_args_t cum_v, machine_mode mode,
2269 		       const_tree type, bool named ATTRIBUTE_UNUSED)
2270 {
2271   CUMULATIVE_ARGS cum = *get_cumulative_args (cum_v);
2272 
2273   if (PASS_IN_REG_P (cum, mode, type))
2274     return gen_rtx_REG (mode, ROUND_ADVANCE_CUM (cum, mode, type));
2275   return 0;
2276 }
2277 
2278 /* Update the data in CUM to advance over an argument
2279    of mode MODE and data type TYPE.
2280    (TYPE is null for libcalls where that information may not be available.)  */
2281 static void
epiphany_function_arg_advance(cumulative_args_t cum_v,machine_mode mode,const_tree type,bool named ATTRIBUTE_UNUSED)2282 epiphany_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
2283 			       const_tree type, bool named ATTRIBUTE_UNUSED)
2284 {
2285   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
2286 
2287   *cum = ROUND_ADVANCE_CUM (*cum, mode, type) + ROUND_ADVANCE_ARG (mode, type);
2288 }
2289 
2290 /* Nested function support.
2291    An epiphany trampoline looks like this:
2292    mov r16,%low(fnaddr)
2293    movt r16,%high(fnaddr)
2294    mov ip,%low(cxt)
2295    movt ip,%high(cxt)
2296    jr r16  */
2297 
2298 #define EPIPHANY_LOW_RTX(X) \
2299   (gen_rtx_IOR (SImode, \
2300     gen_rtx_ASHIFT (SImode, \
2301 		    gen_rtx_AND (SImode, (X), GEN_INT (0xff)), GEN_INT (5)), \
2302     gen_rtx_ASHIFT (SImode, \
2303 		    gen_rtx_AND (SImode, (X), GEN_INT (0xff00)), GEN_INT (12))))
2304 #define EPIPHANY_HIGH_RTX(X) \
2305   EPIPHANY_LOW_RTX (gen_rtx_LSHIFTRT (SImode, (X), GEN_INT (16)))
2306 
2307 /* Emit RTL insns to initialize the variable parts of a trampoline.
2308    FNADDR is an RTX for the address of the function's pure code.
2309    CXT is an RTX for the static chain value for the function.  */
2310 static void
epiphany_trampoline_init(rtx tramp_mem,tree fndecl,rtx cxt)2311 epiphany_trampoline_init (rtx tramp_mem, tree fndecl, rtx cxt)
2312 {
2313   rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
2314   rtx tramp = force_reg (Pmode, XEXP (tramp_mem, 0));
2315 
2316   emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 0)),
2317 		  gen_rtx_IOR (SImode, GEN_INT (0x4002000b),
2318 			       EPIPHANY_LOW_RTX (fnaddr)));
2319   emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 4)),
2320 		  gen_rtx_IOR (SImode, GEN_INT (0x5002000b),
2321 			       EPIPHANY_HIGH_RTX (fnaddr)));
2322   emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 8)),
2323 		  gen_rtx_IOR (SImode, GEN_INT (0x2002800b),
2324 			       EPIPHANY_LOW_RTX (cxt)));
2325   emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 12)),
2326 		  gen_rtx_IOR (SImode, GEN_INT (0x3002800b),
2327 			       EPIPHANY_HIGH_RTX (cxt)));
2328   emit_move_insn (gen_rtx_MEM (SImode, plus_constant (Pmode, tramp, 16)),
2329 		  GEN_INT (0x0802014f));
2330 }
2331 
2332 bool
epiphany_optimize_mode_switching(int entity)2333 epiphany_optimize_mode_switching (int entity)
2334 {
2335   if (MACHINE_FUNCTION (cfun)->sw_entities_processed & (1 << entity))
2336     return false;
2337   switch (entity)
2338     {
2339     case EPIPHANY_MSW_ENTITY_AND:
2340     case EPIPHANY_MSW_ENTITY_OR:
2341     case EPIPHANY_MSW_ENTITY_CONFIG:
2342       return true;
2343     case EPIPHANY_MSW_ENTITY_NEAREST:
2344     case EPIPHANY_MSW_ENTITY_TRUNC:
2345       return optimize > 0;
2346     case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2347       return MACHINE_FUNCTION (cfun)->unknown_mode_uses != 0;
2348     case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2349       return (MACHINE_FUNCTION (cfun)->sw_entities_processed
2350 	      & (1 << EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN)) != 0;
2351     case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2352       return optimize == 0 || current_pass == pass_mode_switch_use;
2353     }
2354   gcc_unreachable ();
2355 }
2356 
2357 static int
epiphany_mode_priority(int entity,int priority)2358 epiphany_mode_priority (int entity, int priority)
2359 {
2360   if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR
2361       || entity== EPIPHANY_MSW_ENTITY_CONFIG)
2362     return priority;
2363   if (priority > 3)
2364     switch (priority)
2365       {
2366       case 4: return FP_MODE_ROUND_UNKNOWN;
2367       case 5: return FP_MODE_NONE;
2368       default: gcc_unreachable ();
2369       }
2370   switch ((enum attr_fp_mode) epiphany_normal_fp_mode)
2371     {
2372       case FP_MODE_INT:
2373 	switch (priority)
2374 	  {
2375 	  case 0: return FP_MODE_INT;
2376 	  case 1: return epiphany_normal_fp_rounding;
2377 	  case 2: return (epiphany_normal_fp_rounding == FP_MODE_ROUND_NEAREST
2378 			  ? FP_MODE_ROUND_TRUNC : FP_MODE_ROUND_NEAREST);
2379 	  case 3: return FP_MODE_CALLER;
2380 	  }
2381       case FP_MODE_ROUND_NEAREST:
2382       case FP_MODE_CALLER:
2383 	switch (priority)
2384 	  {
2385 	  case 0: return FP_MODE_ROUND_NEAREST;
2386 	  case 1: return FP_MODE_ROUND_TRUNC;
2387 	  case 2: return FP_MODE_INT;
2388 	  case 3: return FP_MODE_CALLER;
2389 	  }
2390       case FP_MODE_ROUND_TRUNC:
2391 	switch (priority)
2392 	  {
2393 	  case 0: return FP_MODE_ROUND_TRUNC;
2394 	  case 1: return FP_MODE_ROUND_NEAREST;
2395 	  case 2: return FP_MODE_INT;
2396 	  case 3: return FP_MODE_CALLER;
2397 	  }
2398       case FP_MODE_ROUND_UNKNOWN:
2399       case FP_MODE_NONE:
2400 	gcc_unreachable ();
2401     }
2402   gcc_unreachable ();
2403 }
2404 
2405 int
epiphany_mode_needed(int entity,rtx_insn * insn)2406 epiphany_mode_needed (int entity, rtx_insn *insn)
2407 {
2408   enum attr_fp_mode mode;
2409 
2410   if (recog_memoized (insn) < 0)
2411     {
2412       if (entity == EPIPHANY_MSW_ENTITY_AND
2413 	  || entity == EPIPHANY_MSW_ENTITY_OR
2414 	  || entity == EPIPHANY_MSW_ENTITY_CONFIG)
2415 	return 2;
2416       return FP_MODE_NONE;
2417     }
2418   mode = get_attr_fp_mode (insn);
2419 
2420   switch (entity)
2421   {
2422   case EPIPHANY_MSW_ENTITY_AND:
2423     return mode != FP_MODE_NONE && mode != FP_MODE_INT ? 1 : 2;
2424   case EPIPHANY_MSW_ENTITY_OR:
2425     return mode == FP_MODE_INT ? 1 : 2;
2426   case EPIPHANY_MSW_ENTITY_CONFIG:
2427     /* We must know/save config before we set it to something else.
2428        Where we need the original value, we are fine with having it
2429        just unchanged from the function start.
2430        Because of the nature of the mode switching optimization,
2431        a restore will be dominated by a clobber.  */
2432     if (mode != FP_MODE_NONE && mode != FP_MODE_CALLER)
2433       return 1;
2434     /* A cpecial case are abnormal edges, which are deemed to clobber
2435        the mode as well.  We need to pin this effect on a actually
2436        dominating insn, and one where the frame can be accessed, too, in
2437        case the pseudo used to save CONFIG doesn't get a hard register.  */
2438     if (CALL_P (insn) && find_reg_note (insn, REG_EH_REGION, NULL_RTX))
2439       return 1;
2440     return 2;
2441   case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2442     if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2443       mode = (enum attr_fp_mode) epiphany_mode_after (entity, mode, insn);
2444     /* Fall through.  */
2445   case EPIPHANY_MSW_ENTITY_NEAREST:
2446   case EPIPHANY_MSW_ENTITY_TRUNC:
2447     if (mode == FP_MODE_ROUND_UNKNOWN)
2448       {
2449 	MACHINE_FUNCTION (cfun)->unknown_mode_uses++;
2450 	return FP_MODE_NONE;
2451       }
2452     return mode;
2453   case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2454     if (mode == FP_MODE_ROUND_NEAREST || mode == FP_MODE_ROUND_TRUNC)
2455 	return FP_MODE_ROUND_UNKNOWN;
2456     return mode;
2457   case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2458     if (mode == FP_MODE_ROUND_UNKNOWN)
2459       return epiphany_normal_fp_rounding;
2460     return mode;
2461   default:
2462     gcc_unreachable ();
2463   }
2464 }
2465 
2466 static int
epiphany_mode_entry_exit(int entity,bool exit)2467 epiphany_mode_entry_exit (int entity, bool exit)
2468 {
2469   int normal_mode = epiphany_normal_fp_mode ;
2470 
2471   MACHINE_FUNCTION (cfun)->sw_entities_processed |= (1 << entity);
2472   if (epiphany_is_interrupt_p (current_function_decl))
2473     normal_mode = FP_MODE_CALLER;
2474   switch (entity)
2475     {
2476     case EPIPHANY_MSW_ENTITY_AND:
2477       if (exit)
2478 	return normal_mode != FP_MODE_INT ? 1 : 2;
2479       return 0;
2480     case EPIPHANY_MSW_ENTITY_OR:
2481       if (exit)
2482 	return normal_mode == FP_MODE_INT ? 1 : 2;
2483       return 0;
2484     case EPIPHANY_MSW_ENTITY_CONFIG:
2485       if (exit)
2486 	return 2;
2487       return normal_mode == FP_MODE_CALLER ? 0 : 1;
2488     case EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN:
2489       if (normal_mode == FP_MODE_ROUND_NEAREST
2490 	  || normal_mode == FP_MODE_ROUND_TRUNC)
2491       return FP_MODE_ROUND_UNKNOWN;
2492       /* Fall through.  */
2493     case EPIPHANY_MSW_ENTITY_NEAREST:
2494     case EPIPHANY_MSW_ENTITY_TRUNC:
2495     case EPIPHANY_MSW_ENTITY_ROUND_KNOWN:
2496     case EPIPHANY_MSW_ENTITY_FPU_OMNIBUS:
2497       return normal_mode;
2498     default:
2499       gcc_unreachable ();
2500     }
2501 }
2502 
2503 int
epiphany_mode_after(int entity,int last_mode,rtx_insn * insn)2504 epiphany_mode_after (int entity, int last_mode, rtx_insn *insn)
2505 {
2506   /* We have too few call-saved registers to hope to keep the masks across
2507      calls.  */
2508   if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
2509     {
2510       if (CALL_P (insn))
2511 	return 0;
2512       return last_mode;
2513     }
2514   /* If there is an abnormal edge, we don't want the config register to
2515      be 'saved' again at the destination.
2516      The frame pointer adjustment is inside a PARALLEL because of the
2517      flags clobber.  */
2518   if (entity == EPIPHANY_MSW_ENTITY_CONFIG && NONJUMP_INSN_P (insn)
2519       && GET_CODE (PATTERN (insn)) == PARALLEL
2520       && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET
2521       && SET_DEST (XVECEXP (PATTERN (insn), 0, 0)) == frame_pointer_rtx)
2522     {
2523       gcc_assert (cfun->has_nonlocal_label);
2524       return 1;
2525     }
2526   if (recog_memoized (insn) < 0)
2527     return last_mode;
2528   if (get_attr_fp_mode (insn) == FP_MODE_ROUND_UNKNOWN
2529       && last_mode != FP_MODE_ROUND_NEAREST && last_mode != FP_MODE_ROUND_TRUNC)
2530     {
2531       if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2532 	return FP_MODE_ROUND_NEAREST;
2533       if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2534 	return FP_MODE_ROUND_TRUNC;
2535     }
2536   if (recog_memoized (insn) == CODE_FOR_set_fp_mode)
2537     {
2538       rtx src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
2539       int fp_mode;
2540 
2541       if (REG_P (src))
2542 	return FP_MODE_CALLER;
2543       fp_mode = INTVAL (XVECEXP (XEXP (src, 0), 0, 0));
2544       if (entity == EPIPHANY_MSW_ENTITY_ROUND_UNKNOWN
2545 	  && (fp_mode == FP_MODE_ROUND_NEAREST
2546 	      || fp_mode == EPIPHANY_MSW_ENTITY_TRUNC))
2547 	return FP_MODE_ROUND_UNKNOWN;
2548       return fp_mode;
2549     }
2550   return last_mode;
2551 }
2552 
2553 static int
epiphany_mode_entry(int entity)2554 epiphany_mode_entry (int entity)
2555 {
2556   return epiphany_mode_entry_exit (entity, false);
2557 }
2558 
2559 static int
epiphany_mode_exit(int entity)2560 epiphany_mode_exit (int entity)
2561 {
2562   return epiphany_mode_entry_exit (entity, true);
2563 }
2564 
2565 void
emit_set_fp_mode(int entity,int mode,int prev_mode ATTRIBUTE_UNUSED,HARD_REG_SET regs_live ATTRIBUTE_UNUSED)2566 emit_set_fp_mode (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
2567 		  HARD_REG_SET regs_live ATTRIBUTE_UNUSED)
2568 {
2569   rtx save_cc, cc_reg, mask, src, src2;
2570   enum attr_fp_mode fp_mode;
2571 
2572   if (!MACHINE_FUNCTION (cfun)->and_mask)
2573     {
2574       MACHINE_FUNCTION (cfun)->and_mask = gen_reg_rtx (SImode);
2575       MACHINE_FUNCTION (cfun)->or_mask = gen_reg_rtx (SImode);
2576     }
2577   if (entity == EPIPHANY_MSW_ENTITY_AND)
2578     {
2579       gcc_assert (mode >= 0 && mode <= 2);
2580       if (mode == 1)
2581 	emit_move_insn (MACHINE_FUNCTION (cfun)->and_mask,
2582 			gen_int_mode (0xfff1fffe, SImode));
2583       return;
2584     }
2585   else if (entity == EPIPHANY_MSW_ENTITY_OR)
2586     {
2587       gcc_assert (mode >= 0 && mode <= 2);
2588       if (mode == 1)
2589 	emit_move_insn (MACHINE_FUNCTION (cfun)->or_mask, GEN_INT(0x00080000));
2590       return;
2591     }
2592   else if (entity == EPIPHANY_MSW_ENTITY_CONFIG)
2593     {
2594       /* Mode switching optimization is done after emit_initial_value_sets,
2595 	 so we have to take care of CONFIG_REGNUM here.  */
2596       gcc_assert (mode >= 0 && mode <= 2);
2597       rtx save = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2598       if (mode == 1)
2599 	emit_insn (gen_save_config (save));
2600       return;
2601     }
2602   fp_mode = (enum attr_fp_mode) mode;
2603   src = NULL_RTX;
2604 
2605   switch (fp_mode)
2606     {
2607       case FP_MODE_CALLER:
2608 	/* The EPIPHANY_MSW_ENTITY_CONFIG processing must come later
2609 	   so that the config save gets inserted before the first use.  */
2610 	gcc_assert (entity > EPIPHANY_MSW_ENTITY_CONFIG);
2611 	src = get_hard_reg_initial_val (SImode, CONFIG_REGNUM);
2612 	mask = MACHINE_FUNCTION (cfun)->and_mask;
2613 	break;
2614       case FP_MODE_ROUND_UNKNOWN:
2615 	MACHINE_FUNCTION (cfun)->unknown_mode_sets++;
2616 	mask = MACHINE_FUNCTION (cfun)->and_mask;
2617 	break;
2618       case FP_MODE_ROUND_NEAREST:
2619 	if (entity == EPIPHANY_MSW_ENTITY_TRUNC)
2620 	  return;
2621 	mask = MACHINE_FUNCTION (cfun)->and_mask;
2622 	break;
2623       case FP_MODE_ROUND_TRUNC:
2624 	if (entity == EPIPHANY_MSW_ENTITY_NEAREST)
2625 	  return;
2626 	mask = MACHINE_FUNCTION (cfun)->and_mask;
2627 	break;
2628       case FP_MODE_INT:
2629 	mask = MACHINE_FUNCTION (cfun)->or_mask;
2630 	break;
2631       case FP_MODE_NONE:
2632       default:
2633 	gcc_unreachable ();
2634     }
2635   save_cc = gen_reg_rtx (CCmode);
2636   cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
2637   emit_move_insn (save_cc, cc_reg);
2638   mask = force_reg (SImode, mask);
2639   if (!src)
2640     {
2641       rtvec v = gen_rtvec (1, GEN_INT (fp_mode));
2642 
2643       src = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2644     }
2645   if (entity == EPIPHANY_MSW_ENTITY_ROUND_KNOWN
2646       || entity == EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2647     src2 = copy_rtx (src);
2648   else
2649     {
2650       rtvec v = gen_rtvec (1, GEN_INT (FP_MODE_ROUND_UNKNOWN));
2651 
2652       src2 = gen_rtx_CONST (SImode, gen_rtx_UNSPEC (SImode, v, UNSPEC_FP_MODE));
2653     }
2654   emit_insn (gen_set_fp_mode (src, src2, mask));
2655   emit_move_insn (cc_reg, save_cc);
2656 }
2657 
2658 void
epiphany_expand_set_fp_mode(rtx * operands)2659 epiphany_expand_set_fp_mode (rtx *operands)
2660 {
2661   rtx ctrl = gen_rtx_REG (SImode, CONFIG_REGNUM);
2662   rtx src = operands[0];
2663   rtx mask_reg = operands[2];
2664   rtx scratch = operands[3];
2665   enum attr_fp_mode fp_mode;
2666 
2667 
2668   gcc_assert (rtx_equal_p (src, operands[1])
2669 	      /* Sometimes reload gets silly and reloads the same pseudo
2670 		 into different registers.  */
2671 	      || (REG_P (src) && REG_P (operands[1])));
2672 
2673   if (!epiphany_uninterruptible_p (current_function_decl))
2674     emit_insn (gen_gid ());
2675   emit_move_insn (scratch, ctrl);
2676 
2677   if (GET_CODE (src) == REG)
2678     {
2679       /* FP_MODE_CALLER */
2680       emit_insn (gen_xorsi3 (scratch, scratch, src));
2681       emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2682       emit_insn (gen_xorsi3 (scratch, scratch, src));
2683     }
2684   else
2685     {
2686       gcc_assert (GET_CODE (src) == CONST);
2687       src = XEXP (src, 0);
2688       fp_mode = (enum attr_fp_mode) INTVAL (XVECEXP (src, 0, 0));
2689       switch (fp_mode)
2690 	{
2691 	case FP_MODE_ROUND_NEAREST:
2692 	  emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2693 	  break;
2694 	case FP_MODE_ROUND_TRUNC:
2695 	  emit_insn (gen_andsi3 (scratch, scratch, mask_reg));
2696 	  emit_insn (gen_add2_insn (scratch, const1_rtx));
2697 	  break;
2698 	case FP_MODE_INT:
2699 	  emit_insn (gen_iorsi3 (scratch, scratch, mask_reg));
2700 	  break;
2701 	case FP_MODE_CALLER:
2702 	case FP_MODE_ROUND_UNKNOWN:
2703 	case FP_MODE_NONE:
2704 	  gcc_unreachable ();
2705 	}
2706     }
2707   emit_move_insn (ctrl, scratch);
2708   if (!epiphany_uninterruptible_p (current_function_decl))
2709     emit_insn (gen_gie ());
2710 }
2711 
2712 void
epiphany_insert_mode_switch_use(rtx_insn * insn,int entity ATTRIBUTE_UNUSED,int mode ATTRIBUTE_UNUSED)2713 epiphany_insert_mode_switch_use (rtx_insn *insn,
2714 				 int entity ATTRIBUTE_UNUSED,
2715 				 int mode ATTRIBUTE_UNUSED)
2716 {
2717   rtx pat = PATTERN (insn);
2718   rtvec v;
2719   int len, i;
2720   rtx near = gen_rtx_REG (SImode, FP_NEAREST_REGNUM);
2721   rtx trunc = gen_rtx_REG (SImode, FP_TRUNCATE_REGNUM);
2722 
2723   if (entity != EPIPHANY_MSW_ENTITY_FPU_OMNIBUS)
2724     return;
2725   switch ((enum attr_fp_mode) get_attr_fp_mode (insn))
2726     {
2727       case FP_MODE_ROUND_NEAREST:
2728 	near = gen_rtx_USE (VOIDmode, near);
2729 	trunc = gen_rtx_CLOBBER (VOIDmode, trunc);
2730 	break;
2731       case FP_MODE_ROUND_TRUNC:
2732 	near = gen_rtx_CLOBBER (VOIDmode, near);
2733 	trunc = gen_rtx_USE (VOIDmode, trunc);
2734 	break;
2735       case FP_MODE_ROUND_UNKNOWN:
2736 	near = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, FP_ANYFP_REGNUM));
2737 	trunc = copy_rtx (near);
2738 	/* Fall through.  */
2739       case FP_MODE_INT:
2740       case FP_MODE_CALLER:
2741 	near = gen_rtx_USE (VOIDmode, near);
2742 	trunc = gen_rtx_USE (VOIDmode, trunc);
2743 	break;
2744       case FP_MODE_NONE:
2745 	gcc_unreachable ();
2746     }
2747   gcc_assert (GET_CODE (pat) == PARALLEL);
2748   len = XVECLEN (pat, 0);
2749   v = rtvec_alloc (len + 2);
2750   for (i = 0; i < len; i++)
2751     RTVEC_ELT (v, i) = XVECEXP (pat, 0, i);
2752   RTVEC_ELT (v, len) = near;
2753   RTVEC_ELT (v, len + 1) = trunc;
2754   pat = gen_rtx_PARALLEL (VOIDmode, v);
2755   PATTERN (insn) = pat;
2756   MACHINE_FUNCTION (cfun)->control_use_inserted = true;
2757 }
2758 
2759 bool
epiphany_epilogue_uses(int regno)2760 epiphany_epilogue_uses (int regno)
2761 {
2762   if (regno == GPR_LR)
2763     return true;
2764   if (reload_completed && epiphany_is_interrupt_p (current_function_decl))
2765     {
2766       if (fixed_regs[regno]
2767 	  && regno != STATUS_REGNUM && regno != IRET_REGNUM
2768 	  && regno != FP_NEAREST_REGNUM && regno != FP_TRUNCATE_REGNUM)
2769 	return false;
2770       return true;
2771     }
2772   if (regno == FP_NEAREST_REGNUM
2773       && epiphany_normal_fp_mode != FP_MODE_ROUND_TRUNC)
2774     return true;
2775   if (regno == FP_TRUNCATE_REGNUM
2776       && epiphany_normal_fp_mode != FP_MODE_ROUND_NEAREST)
2777     return true;
2778   return false;
2779 }
2780 
2781 static unsigned int
epiphany_min_divisions_for_recip_mul(machine_mode mode)2782 epiphany_min_divisions_for_recip_mul (machine_mode mode)
2783 {
2784   if (flag_reciprocal_math && mode == SFmode)
2785     /* We'll expand into a multiply-by-reciprocal anyway, so we might a well do
2786        it already at the tree level and expose it to further optimizations.  */
2787     return 1;
2788   return default_min_divisions_for_recip_mul (mode);
2789 }
2790 
2791 static machine_mode
epiphany_preferred_simd_mode(scalar_mode mode ATTRIBUTE_UNUSED)2792 epiphany_preferred_simd_mode (scalar_mode mode ATTRIBUTE_UNUSED)
2793 {
2794   return TARGET_VECT_DOUBLE ? DImode : SImode;
2795 }
2796 
2797 static bool
epiphany_vector_mode_supported_p(machine_mode mode)2798 epiphany_vector_mode_supported_p (machine_mode mode)
2799 {
2800   if (mode == V2SFmode)
2801     return true;
2802   if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
2803       && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8))
2804     return true;
2805   return false;
2806 }
2807 
2808 static bool
epiphany_vector_alignment_reachable(const_tree type,bool is_packed)2809 epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
2810 {
2811   /* Vectors which aren't in packed structures will not be less aligned than
2812      the natural alignment of their element type, so this is safe.  */
2813   if (TYPE_ALIGN_UNIT (type) == 4)
2814     return !is_packed;
2815 
2816   return default_builtin_vector_alignment_reachable (type, is_packed);
2817 }
2818 
2819 static bool
epiphany_support_vector_misalignment(machine_mode mode,const_tree type,int misalignment,bool is_packed)2820 epiphany_support_vector_misalignment (machine_mode mode, const_tree type,
2821 				      int misalignment, bool is_packed)
2822 {
2823   if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
2824     return true;
2825   return default_builtin_support_vector_misalignment (mode, type, misalignment,
2826 						      is_packed);
2827 }
2828 
2829 /* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
2830    structs.  Make structs double-word-aligned it they are a double word or
2831    (potentially) larger;  failing that, do the same for a size of 32 bits.  */
2832 unsigned
epiphany_special_round_type_align(tree type,unsigned computed,unsigned specified)2833 epiphany_special_round_type_align (tree type, unsigned computed,
2834 				   unsigned specified)
2835 {
2836   unsigned align = MAX (computed, specified);
2837   tree field;
2838   HOST_WIDE_INT total, max;
2839   unsigned try_align = FASTEST_ALIGNMENT;
2840 
2841   if (maximum_field_alignment && try_align > maximum_field_alignment)
2842     try_align = maximum_field_alignment;
2843   if (align >= try_align)
2844     return align;
2845   for (max = 0, field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
2846     {
2847       tree offset, size;
2848 
2849       if (TREE_CODE (field) != FIELD_DECL
2850 	  || TREE_TYPE (field) == error_mark_node)
2851 	continue;
2852       offset = bit_position (field);
2853       size = DECL_SIZE (field);
2854       if (!tree_fits_uhwi_p (offset) || !tree_fits_uhwi_p (size)
2855 	  || tree_to_uhwi (offset) >= try_align
2856 	  || tree_to_uhwi (size) >= try_align)
2857 	return try_align;
2858       total = tree_to_uhwi (offset) + tree_to_uhwi (size);
2859       if (total > max)
2860 	max = total;
2861     }
2862   if (max >= (HOST_WIDE_INT) try_align)
2863     align = try_align;
2864   else if (try_align > 32 && max >= 32)
2865     align = max > 32 ? 64 : 32;
2866   return align;
2867 }
2868 
2869 /* Upping the alignment of arrays in structs is not only a performance
2870    enhancement, it also helps preserve assumptions about how
2871    arrays-at-the-end-of-structs work, like for struct gcov_fn_info in
2872    libgcov.c .  */
2873 unsigned
epiphany_adjust_field_align(tree type,unsigned computed)2874 epiphany_adjust_field_align (tree type, unsigned computed)
2875 {
2876   if (computed == 32
2877       && TREE_CODE (type) == ARRAY_TYPE)
2878     {
2879       tree elmsz = TYPE_SIZE (TREE_TYPE (type));
2880 
2881       if (!tree_fits_uhwi_p (elmsz) || tree_to_uhwi (elmsz) >= 32)
2882 	return 64;
2883     }
2884   return computed;
2885 }
2886 
2887 /* Output code to add DELTA to the first argument, and then jump
2888    to FUNCTION.  Used for C++ multiple inheritance.  */
2889 static void
epiphany_output_mi_thunk(FILE * file,tree thunk ATTRIBUTE_UNUSED,HOST_WIDE_INT delta,HOST_WIDE_INT vcall_offset,tree function)2890 epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
2891 			  HOST_WIDE_INT delta,
2892 			  HOST_WIDE_INT vcall_offset,
2893 			  tree function)
2894 {
2895   int this_regno
2896     = aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function) ? 1 : 0;
2897   const char *this_name = reg_names[this_regno];
2898   const char *fname;
2899 
2900   /* We use IP and R16 as a scratch registers.  */
2901   gcc_assert (call_used_regs [GPR_IP]);
2902   gcc_assert (call_used_regs [GPR_16]);
2903 
2904   /* Add DELTA.  When possible use a plain add, otherwise load it into
2905      a register first. */
2906   if (delta == 0)
2907     ; /* Done.  */
2908   else if (SIMM11 (delta))
2909     asm_fprintf (file, "\tadd\t%s,%s,%d\n", this_name, this_name, (int) delta);
2910   else if (delta < 0 && delta >= -0xffff)
2911     {
2912       asm_fprintf (file, "\tmov\tip,%d\n", (int) -delta);
2913       asm_fprintf (file, "\tsub\t%s,%s,ip\n", this_name, this_name);
2914     }
2915   else
2916     {
2917       asm_fprintf (file, "\tmov\tip,%%low(%ld)\n", (long) delta);
2918       if (delta & ~0xffff)
2919 	asm_fprintf (file, "\tmovt\tip,%%high(%ld)\n", (long) delta);
2920       asm_fprintf (file, "\tadd\t%s,%s,ip\n", this_name, this_name);
2921     }
2922 
2923   /* If needed, add *(*THIS + VCALL_OFFSET) to THIS.  */
2924   if (vcall_offset != 0)
2925     {
2926       /* ldr ip,[this]		--> temp = *this
2927 	 ldr ip,[ip,vcall_offset] > temp = *(*this + vcall_offset)
2928 	 add this,this,ip	--> this+ = *(*this + vcall_offset) */
2929       asm_fprintf (file, "\tldr\tip, [%s]\n", this_name);
2930       if (vcall_offset < -0x7ff * 4 || vcall_offset > 0x7ff * 4
2931 	  || (vcall_offset & 3) != 0)
2932 	{
2933 	  asm_fprintf (file, "\tmov\tr16, %%low(%ld)\n", (long) vcall_offset);
2934 	  asm_fprintf (file, "\tmovt\tr16, %%high(%ld)\n", (long) vcall_offset);
2935 	  asm_fprintf (file, "\tldr\tip, [ip,r16]\n");
2936 	}
2937       else
2938 	asm_fprintf (file, "\tldr\tip, [ip,%d]\n", (int) vcall_offset / 4);
2939       asm_fprintf (file, "\tadd\t%s, %s, ip\n", this_name, this_name);
2940     }
2941 
2942   fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
2943   if (epiphany_is_long_call_p (XEXP (DECL_RTL (function), 0)))
2944     {
2945       fputs ("\tmov\tip,%low(", file);
2946       assemble_name (file, fname);
2947       fputs (")\n\tmovt\tip,%high(", file);
2948       assemble_name (file, fname);
2949       fputs (")\n\tjr ip\n", file);
2950     }
2951   else
2952     {
2953       fputs ("\tb\t", file);
2954       assemble_name (file, fname);
2955       fputc ('\n', file);
2956     }
2957 }
2958 
2959 void
epiphany_start_function(FILE * file,const char * name,tree decl)2960 epiphany_start_function (FILE *file, const char *name, tree decl)
2961 {
2962   /* If the function doesn't fit into the on-chip memory, it will have a
2963      section attribute - or lack of it - that denotes it goes somewhere else.
2964      But the architecture spec says that an interrupt vector still has to
2965      point to on-chip memory.  So we must place a jump there to get to the
2966      actual function implementation.  The forwarder_section attribute
2967      specifies the section where this jump goes.
2968      This mechanism can also be useful to have a shortcall destination for
2969      a function that is actually placed much farther away.  */
2970   tree attrs, int_attr, int_names, int_name, forwarder_attr;
2971 
2972   attrs = DECL_ATTRIBUTES (decl);
2973   int_attr = lookup_attribute ("interrupt", attrs);
2974   if (int_attr)
2975     for (int_names = TREE_VALUE (int_attr); int_names;
2976 	 int_names = TREE_CHAIN (int_names))
2977       {
2978 	char buf[99];
2979 
2980 	int_name = TREE_VALUE (int_names);
2981 	sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
2982 	switch_to_section (get_section (buf, SECTION_CODE, decl));
2983 	fputs ("\tb\t", file);
2984 	assemble_name (file, name);
2985 	fputc ('\n', file);
2986       }
2987   forwarder_attr = lookup_attribute ("forwarder_section", attrs);
2988   if (forwarder_attr)
2989     {
2990       const char *prefix = "__forwarder_dst_";
2991       char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
2992 
2993       strcpy (dst_name, prefix);
2994       strcat (dst_name, name);
2995       forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
2996       switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
2997 			 SECTION_CODE, decl));
2998       ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
2999       if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
3000 	{
3001 	  int tmp = GPR_0;
3002 
3003 	  if (int_attr)
3004 	    fputs ("\tstrd r0,[sp,-1]\n", file);
3005 	  else
3006 	    tmp = GPR_16;
3007 	  gcc_assert (call_used_regs[tmp]);
3008 	  fprintf (file, "\tmov r%d,%%low(", tmp);
3009 	  assemble_name (file, dst_name);
3010 	  fprintf (file, ")\n"
3011 		   "\tmovt r%d,%%high(", tmp);
3012 	  assemble_name (file, dst_name);
3013 	  fprintf (file, ")\n"
3014 		 "\tjr r%d\n", tmp);
3015 	}
3016       else
3017 	{
3018 	  fputs ("\tb\t", file);
3019 	  assemble_name (file, dst_name);
3020 	  fputc ('\n', file);
3021 	}
3022       name = dst_name;
3023     }
3024   switch_to_section (function_section (decl));
3025   ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
3026 }
3027 
3028 
3029 /* Implement TARGET_CONSTANT_ALIGNMENT.  */
3030 
3031 static HOST_WIDE_INT
epiphany_constant_alignment(const_tree exp,HOST_WIDE_INT align)3032 epiphany_constant_alignment (const_tree exp, HOST_WIDE_INT align)
3033 {
3034   if (TREE_CODE (exp) == STRING_CST)
3035     return MAX (align, FASTEST_ALIGNMENT);
3036   return align;
3037 }
3038 
3039 /* Implement TARGET_STARTING_FRAME_OFFSET.  */
3040 
3041 static HOST_WIDE_INT
epiphany_starting_frame_offset(void)3042 epiphany_starting_frame_offset (void)
3043 {
3044   return epiphany_stack_offset;
3045 }
3046 
3047 struct gcc_target targetm = TARGET_INITIALIZER;
3048