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