OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [config/] [epiphany/] [epiphany.c] - Blame information for rev 709

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.