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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [v850/] [v850.c] - Diff between revs 154 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Subroutines for insn-output.c for NEC V850 series
/* Subroutines for insn-output.c for NEC V850 series
   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
   2007 Free Software Foundation, Inc.
   2007 Free Software Foundation, Inc.
   Contributed by Jeff Law (law@cygnus.com).
   Contributed by Jeff Law (law@cygnus.com).
 
 
   This file is part of GCC.
   This file is part of GCC.
 
 
   GCC is free software; you can redistribute it and/or modify it
   GCC is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   the Free Software Foundation; either version 3, or (at your option)
   any later version.
   any later version.
 
 
   GCC is distributed in the hope that it will be useful, but WITHOUT
   GCC is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for more details.
   for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with GCC; see the file COPYING3.  If not see
   along with GCC; see the file COPYING3.  If not see
   <http://www.gnu.org/licenses/>.  */
   <http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "tree.h"
#include "tree.h"
#include "rtl.h"
#include "rtl.h"
#include "regs.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "real.h"
#include "real.h"
#include "insn-config.h"
#include "insn-config.h"
#include "conditions.h"
#include "conditions.h"
#include "output.h"
#include "output.h"
#include "insn-attr.h"
#include "insn-attr.h"
#include "flags.h"
#include "flags.h"
#include "recog.h"
#include "recog.h"
#include "expr.h"
#include "expr.h"
#include "function.h"
#include "function.h"
#include "toplev.h"
#include "toplev.h"
#include "ggc.h"
#include "ggc.h"
#include "integrate.h"
#include "integrate.h"
#include "tm_p.h"
#include "tm_p.h"
#include "target.h"
#include "target.h"
#include "target-def.h"
#include "target-def.h"
 
 
#ifndef streq
#ifndef streq
#define streq(a,b) (strcmp (a, b) == 0)
#define streq(a,b) (strcmp (a, b) == 0)
#endif
#endif
 
 
/* Function prototypes for stupid compilers:  */
/* Function prototypes for stupid compilers:  */
static bool v850_handle_option       (size_t, const char *, int);
static bool v850_handle_option       (size_t, const char *, int);
static void const_double_split       (rtx, HOST_WIDE_INT *, HOST_WIDE_INT *);
static void const_double_split       (rtx, HOST_WIDE_INT *, HOST_WIDE_INT *);
static int  const_costs_int          (HOST_WIDE_INT, int);
static int  const_costs_int          (HOST_WIDE_INT, int);
static int  const_costs              (rtx, enum rtx_code);
static int  const_costs              (rtx, enum rtx_code);
static bool v850_rtx_costs           (rtx, int, int, int *);
static bool v850_rtx_costs           (rtx, int, int, int *);
static void substitute_ep_register   (rtx, rtx, int, int, rtx *, rtx *);
static void substitute_ep_register   (rtx, rtx, int, int, rtx *, rtx *);
static void v850_reorg               (void);
static void v850_reorg               (void);
static int  ep_memory_offset         (enum machine_mode, int);
static int  ep_memory_offset         (enum machine_mode, int);
static void v850_set_data_area       (tree, v850_data_area);
static void v850_set_data_area       (tree, v850_data_area);
const struct attribute_spec v850_attribute_table[];
const struct attribute_spec v850_attribute_table[];
static tree v850_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
static tree v850_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
static tree v850_handle_data_area_attribute (tree *, tree, tree, int, bool *);
static tree v850_handle_data_area_attribute (tree *, tree, tree, int, bool *);
static void v850_insert_attributes   (tree, tree *);
static void v850_insert_attributes   (tree, tree *);
static void v850_asm_init_sections   (void);
static void v850_asm_init_sections   (void);
static section *v850_select_section (tree, int, unsigned HOST_WIDE_INT);
static section *v850_select_section (tree, int, unsigned HOST_WIDE_INT);
static void v850_encode_data_area    (tree, rtx);
static void v850_encode_data_area    (tree, rtx);
static void v850_encode_section_info (tree, rtx, int);
static void v850_encode_section_info (tree, rtx, int);
static bool v850_return_in_memory    (tree, tree);
static bool v850_return_in_memory    (tree, tree);
static void v850_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
static void v850_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
                                         tree, int *, int);
                                         tree, int *, int);
static bool v850_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
static bool v850_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
                                    tree, bool);
                                    tree, bool);
static int v850_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
static int v850_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
                                   tree, bool);
                                   tree, bool);
 
 
/* Information about the various small memory areas.  */
/* Information about the various small memory areas.  */
struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
{
{
  /* name       max     physical max */
  /* name       max     physical max */
  { "tda",      0,               256 },
  { "tda",      0,               256 },
  { "sda",      0,               65536 },
  { "sda",      0,               65536 },
  { "zda",      0,               32768 },
  { "zda",      0,               32768 },
};
};
 
 
/* Names of the various data areas used on the v850.  */
/* Names of the various data areas used on the v850.  */
tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
tree GHS_default_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
tree GHS_current_section_names [(int) COUNT_OF_GHS_SECTION_KINDS];
 
 
/* Track the current data area set by the data area pragma (which
/* Track the current data area set by the data area pragma (which
   can be nested).  Tested by check_default_data_area.  */
   can be nested).  Tested by check_default_data_area.  */
data_area_stack_element * data_area_stack = NULL;
data_area_stack_element * data_area_stack = NULL;
 
 
/* True if we don't need to check any more if the current
/* True if we don't need to check any more if the current
   function is an interrupt handler.  */
   function is an interrupt handler.  */
static int v850_interrupt_cache_p = FALSE;
static int v850_interrupt_cache_p = FALSE;
 
 
/* Whether current function is an interrupt handler.  */
/* Whether current function is an interrupt handler.  */
static int v850_interrupt_p = FALSE;
static int v850_interrupt_p = FALSE;
 
 
static GTY(()) section *rosdata_section;
static GTY(()) section *rosdata_section;
static GTY(()) section *rozdata_section;
static GTY(()) section *rozdata_section;
static GTY(()) section *tdata_section;
static GTY(()) section *tdata_section;
static GTY(()) section *zdata_section;
static GTY(()) section *zdata_section;
static GTY(()) section *zbss_section;
static GTY(()) section *zbss_section;


/* Initialize the GCC target structure.  */
/* Initialize the GCC target structure.  */
#undef TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
 
 
#undef TARGET_ATTRIBUTE_TABLE
#undef TARGET_ATTRIBUTE_TABLE
#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
 
 
#undef TARGET_INSERT_ATTRIBUTES
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
 
 
#undef  TARGET_ASM_SELECT_SECTION
#undef  TARGET_ASM_SELECT_SECTION
#define TARGET_ASM_SELECT_SECTION  v850_select_section
#define TARGET_ASM_SELECT_SECTION  v850_select_section
 
 
/* The assembler supports switchable .bss sections, but
/* The assembler supports switchable .bss sections, but
   v850_select_section doesn't yet make use of them.  */
   v850_select_section doesn't yet make use of them.  */
#undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
#undef  TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
 
 
#undef TARGET_ENCODE_SECTION_INFO
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
 
 
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
 
 
#undef TARGET_DEFAULT_TARGET_FLAGS
#undef TARGET_DEFAULT_TARGET_FLAGS
#define TARGET_DEFAULT_TARGET_FLAGS (MASK_DEFAULT | MASK_APP_REGS)
#define TARGET_DEFAULT_TARGET_FLAGS (MASK_DEFAULT | MASK_APP_REGS)
#undef TARGET_HANDLE_OPTION
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION v850_handle_option
#define TARGET_HANDLE_OPTION v850_handle_option
 
 
#undef TARGET_RTX_COSTS
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS v850_rtx_costs
#define TARGET_RTX_COSTS v850_rtx_costs
 
 
#undef TARGET_ADDRESS_COST
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hook_int_rtx_0
#define TARGET_ADDRESS_COST hook_int_rtx_0
 
 
#undef TARGET_MACHINE_DEPENDENT_REORG
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG v850_reorg
#define TARGET_MACHINE_DEPENDENT_REORG v850_reorg
 
 
#undef TARGET_PROMOTE_PROTOTYPES
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
 
 
#undef TARGET_RETURN_IN_MEMORY
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY v850_return_in_memory
#define TARGET_RETURN_IN_MEMORY v850_return_in_memory
 
 
#undef TARGET_PASS_BY_REFERENCE
#undef TARGET_PASS_BY_REFERENCE
#define TARGET_PASS_BY_REFERENCE v850_pass_by_reference
#define TARGET_PASS_BY_REFERENCE v850_pass_by_reference
 
 
#undef TARGET_CALLEE_COPIES
#undef TARGET_CALLEE_COPIES
#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
 
 
#undef TARGET_SETUP_INCOMING_VARARGS
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS v850_setup_incoming_varargs
#define TARGET_SETUP_INCOMING_VARARGS v850_setup_incoming_varargs
 
 
#undef TARGET_ARG_PARTIAL_BYTES
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES v850_arg_partial_bytes
#define TARGET_ARG_PARTIAL_BYTES v850_arg_partial_bytes
 
 
struct gcc_target targetm = TARGET_INITIALIZER;
struct gcc_target targetm = TARGET_INITIALIZER;


/* Set the maximum size of small memory area TYPE to the value given
/* Set the maximum size of small memory area TYPE to the value given
   by VALUE.  Return true if VALUE was syntactically correct.  VALUE
   by VALUE.  Return true if VALUE was syntactically correct.  VALUE
   starts with the argument separator: either "-" or "=".  */
   starts with the argument separator: either "-" or "=".  */
 
 
static bool
static bool
v850_handle_memory_option (enum small_memory_type type, const char *value)
v850_handle_memory_option (enum small_memory_type type, const char *value)
{
{
  int i, size;
  int i, size;
 
 
  if (*value != '-' && *value != '=')
  if (*value != '-' && *value != '=')
    return false;
    return false;
 
 
  value++;
  value++;
  for (i = 0; value[i]; i++)
  for (i = 0; value[i]; i++)
    if (!ISDIGIT (value[i]))
    if (!ISDIGIT (value[i]))
      return false;
      return false;
 
 
  size = atoi (value);
  size = atoi (value);
  if (size > small_memory[type].physical_max)
  if (size > small_memory[type].physical_max)
    error ("value passed to %<-m%s%> is too large", small_memory[type].name);
    error ("value passed to %<-m%s%> is too large", small_memory[type].name);
  else
  else
    small_memory[type].max = size;
    small_memory[type].max = size;
  return true;
  return true;
}
}
 
 
/* Implement TARGET_HANDLE_OPTION.  */
/* Implement TARGET_HANDLE_OPTION.  */
 
 
static bool
static bool
v850_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
v850_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
{
{
  switch (code)
  switch (code)
    {
    {
    case OPT_mspace:
    case OPT_mspace:
      target_flags |= MASK_EP | MASK_PROLOG_FUNCTION;
      target_flags |= MASK_EP | MASK_PROLOG_FUNCTION;
      return true;
      return true;
 
 
    case OPT_mv850:
    case OPT_mv850:
      target_flags &= ~(MASK_CPU ^ MASK_V850);
      target_flags &= ~(MASK_CPU ^ MASK_V850);
      return true;
      return true;
 
 
    case OPT_mv850e:
    case OPT_mv850e:
    case OPT_mv850e1:
    case OPT_mv850e1:
      target_flags &= ~(MASK_CPU ^ MASK_V850E);
      target_flags &= ~(MASK_CPU ^ MASK_V850E);
      return true;
      return true;
 
 
    case OPT_mtda:
    case OPT_mtda:
      return v850_handle_memory_option (SMALL_MEMORY_TDA, arg);
      return v850_handle_memory_option (SMALL_MEMORY_TDA, arg);
 
 
    case OPT_msda:
    case OPT_msda:
      return v850_handle_memory_option (SMALL_MEMORY_SDA, arg);
      return v850_handle_memory_option (SMALL_MEMORY_SDA, arg);
 
 
    case OPT_mzda:
    case OPT_mzda:
      return v850_handle_memory_option (SMALL_MEMORY_ZDA, arg);
      return v850_handle_memory_option (SMALL_MEMORY_ZDA, arg);
 
 
    default:
    default:
      return true;
      return true;
    }
    }
}
}


static bool
static bool
v850_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
v850_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
                        enum machine_mode mode, tree type,
                        enum machine_mode mode, tree type,
                        bool named ATTRIBUTE_UNUSED)
                        bool named ATTRIBUTE_UNUSED)
{
{
  unsigned HOST_WIDE_INT size;
  unsigned HOST_WIDE_INT size;
 
 
  if (type)
  if (type)
    size = int_size_in_bytes (type);
    size = int_size_in_bytes (type);
  else
  else
    size = GET_MODE_SIZE (mode);
    size = GET_MODE_SIZE (mode);
 
 
  return size > 8;
  return size > 8;
}
}
 
 
/* Return an RTX to represent where a value with mode MODE will be returned
/* Return an RTX to represent where a value with mode MODE will be returned
   from a function.  If the result is 0, the argument is pushed.  */
   from a function.  If the result is 0, the argument is pushed.  */
 
 
rtx
rtx
function_arg (CUMULATIVE_ARGS * cum,
function_arg (CUMULATIVE_ARGS * cum,
              enum machine_mode mode,
              enum machine_mode mode,
              tree type,
              tree type,
              int named)
              int named)
{
{
  rtx result = 0;
  rtx result = 0;
  int size, align;
  int size, align;
 
 
  if (TARGET_GHS && !named)
  if (TARGET_GHS && !named)
    return NULL_RTX;
    return NULL_RTX;
 
 
  if (mode == BLKmode)
  if (mode == BLKmode)
    size = int_size_in_bytes (type);
    size = int_size_in_bytes (type);
  else
  else
    size = GET_MODE_SIZE (mode);
    size = GET_MODE_SIZE (mode);
 
 
  if (size < 1)
  if (size < 1)
    return 0;
    return 0;
 
 
  if (type)
  if (type)
    align = TYPE_ALIGN (type) / BITS_PER_UNIT;
    align = TYPE_ALIGN (type) / BITS_PER_UNIT;
  else
  else
    align = size;
    align = size;
 
 
  cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
  cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
 
 
  if (cum->nbytes > 4 * UNITS_PER_WORD)
  if (cum->nbytes > 4 * UNITS_PER_WORD)
    return 0;
    return 0;
 
 
  if (type == NULL_TREE
  if (type == NULL_TREE
      && cum->nbytes + size > 4 * UNITS_PER_WORD)
      && cum->nbytes + size > 4 * UNITS_PER_WORD)
    return 0;
    return 0;
 
 
  switch (cum->nbytes / UNITS_PER_WORD)
  switch (cum->nbytes / UNITS_PER_WORD)
    {
    {
    case 0:
    case 0:
      result = gen_rtx_REG (mode, 6);
      result = gen_rtx_REG (mode, 6);
      break;
      break;
    case 1:
    case 1:
      result = gen_rtx_REG (mode, 7);
      result = gen_rtx_REG (mode, 7);
      break;
      break;
    case 2:
    case 2:
      result = gen_rtx_REG (mode, 8);
      result = gen_rtx_REG (mode, 8);
      break;
      break;
    case 3:
    case 3:
      result = gen_rtx_REG (mode, 9);
      result = gen_rtx_REG (mode, 9);
      break;
      break;
    default:
    default:
      result = 0;
      result = 0;
    }
    }
 
 
  return result;
  return result;
}
}
 
 


/* Return the number of bytes which must be put into registers
/* Return the number of bytes which must be put into registers
   for values which are part in registers and part in memory.  */
   for values which are part in registers and part in memory.  */
 
 
static int
static int
v850_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode,
v850_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode,
                        tree type, bool named)
                        tree type, bool named)
{
{
  int size, align;
  int size, align;
 
 
  if (TARGET_GHS && !named)
  if (TARGET_GHS && !named)
    return 0;
    return 0;
 
 
  if (mode == BLKmode)
  if (mode == BLKmode)
    size = int_size_in_bytes (type);
    size = int_size_in_bytes (type);
  else
  else
    size = GET_MODE_SIZE (mode);
    size = GET_MODE_SIZE (mode);
 
 
  if (type)
  if (type)
    align = TYPE_ALIGN (type) / BITS_PER_UNIT;
    align = TYPE_ALIGN (type) / BITS_PER_UNIT;
  else
  else
    align = size;
    align = size;
 
 
  cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
  cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
 
 
  if (cum->nbytes > 4 * UNITS_PER_WORD)
  if (cum->nbytes > 4 * UNITS_PER_WORD)
    return 0;
    return 0;
 
 
  if (cum->nbytes + size <= 4 * UNITS_PER_WORD)
  if (cum->nbytes + size <= 4 * UNITS_PER_WORD)
    return 0;
    return 0;
 
 
  if (type == NULL_TREE
  if (type == NULL_TREE
      && cum->nbytes + size > 4 * UNITS_PER_WORD)
      && cum->nbytes + size > 4 * UNITS_PER_WORD)
    return 0;
    return 0;
 
 
  return 4 * UNITS_PER_WORD - cum->nbytes;
  return 4 * UNITS_PER_WORD - cum->nbytes;
}
}
 
 


/* Return the high and low words of a CONST_DOUBLE */
/* Return the high and low words of a CONST_DOUBLE */
 
 
static void
static void
const_double_split (rtx x, HOST_WIDE_INT * p_high, HOST_WIDE_INT * p_low)
const_double_split (rtx x, HOST_WIDE_INT * p_high, HOST_WIDE_INT * p_low)
{
{
  if (GET_CODE (x) == CONST_DOUBLE)
  if (GET_CODE (x) == CONST_DOUBLE)
    {
    {
      long t[2];
      long t[2];
      REAL_VALUE_TYPE rv;
      REAL_VALUE_TYPE rv;
 
 
      switch (GET_MODE (x))
      switch (GET_MODE (x))
        {
        {
        case DFmode:
        case DFmode:
          REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
          REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
          REAL_VALUE_TO_TARGET_DOUBLE (rv, t);
          REAL_VALUE_TO_TARGET_DOUBLE (rv, t);
          *p_high = t[1];       /* since v850 is little endian */
          *p_high = t[1];       /* since v850 is little endian */
          *p_low = t[0]; /* high is second word */
          *p_low = t[0]; /* high is second word */
          return;
          return;
 
 
        case SFmode:
        case SFmode:
          REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
          REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
          REAL_VALUE_TO_TARGET_SINGLE (rv, *p_high);
          REAL_VALUE_TO_TARGET_SINGLE (rv, *p_high);
          *p_low = 0;
          *p_low = 0;
          return;
          return;
 
 
        case VOIDmode:
        case VOIDmode:
        case DImode:
        case DImode:
          *p_high = CONST_DOUBLE_HIGH (x);
          *p_high = CONST_DOUBLE_HIGH (x);
          *p_low  = CONST_DOUBLE_LOW (x);
          *p_low  = CONST_DOUBLE_LOW (x);
          return;
          return;
 
 
        default:
        default:
          break;
          break;
        }
        }
    }
    }
 
 
  fatal_insn ("const_double_split got a bad insn:", x);
  fatal_insn ("const_double_split got a bad insn:", x);
}
}
 
 


/* Return the cost of the rtx R with code CODE.  */
/* Return the cost of the rtx R with code CODE.  */
 
 
static int
static int
const_costs_int (HOST_WIDE_INT value, int zero_cost)
const_costs_int (HOST_WIDE_INT value, int zero_cost)
{
{
  if (CONST_OK_FOR_I (value))
  if (CONST_OK_FOR_I (value))
      return zero_cost;
      return zero_cost;
  else if (CONST_OK_FOR_J (value))
  else if (CONST_OK_FOR_J (value))
    return 1;
    return 1;
  else if (CONST_OK_FOR_K (value))
  else if (CONST_OK_FOR_K (value))
    return 2;
    return 2;
  else
  else
    return 4;
    return 4;
}
}
 
 
static int
static int
const_costs (rtx r, enum rtx_code c)
const_costs (rtx r, enum rtx_code c)
{
{
  HOST_WIDE_INT high, low;
  HOST_WIDE_INT high, low;
 
 
  switch (c)
  switch (c)
    {
    {
    case CONST_INT:
    case CONST_INT:
      return const_costs_int (INTVAL (r), 0);
      return const_costs_int (INTVAL (r), 0);
 
 
    case CONST_DOUBLE:
    case CONST_DOUBLE:
      const_double_split (r, &high, &low);
      const_double_split (r, &high, &low);
      if (GET_MODE (r) == SFmode)
      if (GET_MODE (r) == SFmode)
        return const_costs_int (high, 1);
        return const_costs_int (high, 1);
      else
      else
        return const_costs_int (high, 1) + const_costs_int (low, 1);
        return const_costs_int (high, 1) + const_costs_int (low, 1);
 
 
    case SYMBOL_REF:
    case SYMBOL_REF:
    case LABEL_REF:
    case LABEL_REF:
    case CONST:
    case CONST:
      return 2;
      return 2;
 
 
    case HIGH:
    case HIGH:
      return 1;
      return 1;
 
 
    default:
    default:
      return 4;
      return 4;
    }
    }
}
}
 
 
static bool
static bool
v850_rtx_costs (rtx x,
v850_rtx_costs (rtx x,
                int code,
                int code,
                int outer_code ATTRIBUTE_UNUSED,
                int outer_code ATTRIBUTE_UNUSED,
                int * total)
                int * total)
{
{
  switch (code)
  switch (code)
    {
    {
    case CONST_INT:
    case CONST_INT:
    case CONST_DOUBLE:
    case CONST_DOUBLE:
    case CONST:
    case CONST:
    case SYMBOL_REF:
    case SYMBOL_REF:
    case LABEL_REF:
    case LABEL_REF:
      *total = COSTS_N_INSNS (const_costs (x, code));
      *total = COSTS_N_INSNS (const_costs (x, code));
      return true;
      return true;
 
 
    case MOD:
    case MOD:
    case DIV:
    case DIV:
    case UMOD:
    case UMOD:
    case UDIV:
    case UDIV:
      if (TARGET_V850E && optimize_size)
      if (TARGET_V850E && optimize_size)
        *total = 6;
        *total = 6;
      else
      else
        *total = 60;
        *total = 60;
      return true;
      return true;
 
 
    case MULT:
    case MULT:
      if (TARGET_V850E
      if (TARGET_V850E
          && (   GET_MODE (x) == SImode
          && (   GET_MODE (x) == SImode
              || GET_MODE (x) == HImode
              || GET_MODE (x) == HImode
              || GET_MODE (x) == QImode))
              || GET_MODE (x) == QImode))
        {
        {
          if (GET_CODE (XEXP (x, 1)) == REG)
          if (GET_CODE (XEXP (x, 1)) == REG)
            *total = 4;
            *total = 4;
          else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
          else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
            {
            {
              if (CONST_OK_FOR_O (INTVAL (XEXP (x, 1))))
              if (CONST_OK_FOR_O (INTVAL (XEXP (x, 1))))
                *total = 6;
                *total = 6;
              else if (CONST_OK_FOR_K (INTVAL (XEXP (x, 1))))
              else if (CONST_OK_FOR_K (INTVAL (XEXP (x, 1))))
                *total = 10;
                *total = 10;
            }
            }
        }
        }
      else
      else
        *total = 20;
        *total = 20;
      return true;
      return true;
 
 
    default:
    default:
      return false;
      return false;
    }
    }
}
}


/* Print operand X using operand code CODE to assembly language output file
/* Print operand X using operand code CODE to assembly language output file
   FILE.  */
   FILE.  */
 
 
void
void
print_operand (FILE * file, rtx x, int code)
print_operand (FILE * file, rtx x, int code)
{
{
  HOST_WIDE_INT high, low;
  HOST_WIDE_INT high, low;
 
 
  switch (code)
  switch (code)
    {
    {
    case 'c':
    case 'c':
      /* We use 'c' operands with symbols for .vtinherit */
      /* We use 'c' operands with symbols for .vtinherit */
      if (GET_CODE (x) == SYMBOL_REF)
      if (GET_CODE (x) == SYMBOL_REF)
        {
        {
          output_addr_const(file, x);
          output_addr_const(file, x);
          break;
          break;
        }
        }
      /* fall through */
      /* fall through */
    case 'b':
    case 'b':
    case 'B':
    case 'B':
    case 'C':
    case 'C':
      switch ((code == 'B' || code == 'C')
      switch ((code == 'B' || code == 'C')
              ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
              ? reverse_condition (GET_CODE (x)) : GET_CODE (x))
        {
        {
          case NE:
          case NE:
            if (code == 'c' || code == 'C')
            if (code == 'c' || code == 'C')
              fprintf (file, "nz");
              fprintf (file, "nz");
            else
            else
              fprintf (file, "ne");
              fprintf (file, "ne");
            break;
            break;
          case EQ:
          case EQ:
            if (code == 'c' || code == 'C')
            if (code == 'c' || code == 'C')
              fprintf (file, "z");
              fprintf (file, "z");
            else
            else
              fprintf (file, "e");
              fprintf (file, "e");
            break;
            break;
          case GE:
          case GE:
            fprintf (file, "ge");
            fprintf (file, "ge");
            break;
            break;
          case GT:
          case GT:
            fprintf (file, "gt");
            fprintf (file, "gt");
            break;
            break;
          case LE:
          case LE:
            fprintf (file, "le");
            fprintf (file, "le");
            break;
            break;
          case LT:
          case LT:
            fprintf (file, "lt");
            fprintf (file, "lt");
            break;
            break;
          case GEU:
          case GEU:
            fprintf (file, "nl");
            fprintf (file, "nl");
            break;
            break;
          case GTU:
          case GTU:
            fprintf (file, "h");
            fprintf (file, "h");
            break;
            break;
          case LEU:
          case LEU:
            fprintf (file, "nh");
            fprintf (file, "nh");
            break;
            break;
          case LTU:
          case LTU:
            fprintf (file, "l");
            fprintf (file, "l");
            break;
            break;
          default:
          default:
            gcc_unreachable ();
            gcc_unreachable ();
        }
        }
      break;
      break;
    case 'F':                   /* high word of CONST_DOUBLE */
    case 'F':                   /* high word of CONST_DOUBLE */
      switch (GET_CODE (x))
      switch (GET_CODE (x))
        {
        {
        case CONST_INT:
        case CONST_INT:
          fprintf (file, "%d", (INTVAL (x) >= 0) ? 0 : -1);
          fprintf (file, "%d", (INTVAL (x) >= 0) ? 0 : -1);
          break;
          break;
 
 
        case CONST_DOUBLE:
        case CONST_DOUBLE:
          const_double_split (x, &high, &low);
          const_double_split (x, &high, &low);
          fprintf (file, "%ld", (long) high);
          fprintf (file, "%ld", (long) high);
          break;
          break;
 
 
        default:
        default:
          gcc_unreachable ();
          gcc_unreachable ();
        }
        }
      break;
      break;
    case 'G':                   /* low word of CONST_DOUBLE */
    case 'G':                   /* low word of CONST_DOUBLE */
      switch (GET_CODE (x))
      switch (GET_CODE (x))
        {
        {
        case CONST_INT:
        case CONST_INT:
          fprintf (file, "%ld", (long) INTVAL (x));
          fprintf (file, "%ld", (long) INTVAL (x));
          break;
          break;
 
 
        case CONST_DOUBLE:
        case CONST_DOUBLE:
          const_double_split (x, &high, &low);
          const_double_split (x, &high, &low);
          fprintf (file, "%ld", (long) low);
          fprintf (file, "%ld", (long) low);
          break;
          break;
 
 
        default:
        default:
          gcc_unreachable ();
          gcc_unreachable ();
        }
        }
      break;
      break;
    case 'L':
    case 'L':
      fprintf (file, "%d\n", (int)(INTVAL (x) & 0xffff));
      fprintf (file, "%d\n", (int)(INTVAL (x) & 0xffff));
      break;
      break;
    case 'M':
    case 'M':
      fprintf (file, "%d", exact_log2 (INTVAL (x)));
      fprintf (file, "%d", exact_log2 (INTVAL (x)));
      break;
      break;
    case 'O':
    case 'O':
      gcc_assert (special_symbolref_operand (x, VOIDmode));
      gcc_assert (special_symbolref_operand (x, VOIDmode));
 
 
      if (GET_CODE (x) == CONST)
      if (GET_CODE (x) == CONST)
        x = XEXP (XEXP (x, 0), 0);
        x = XEXP (XEXP (x, 0), 0);
      else
      else
        gcc_assert (GET_CODE (x) == SYMBOL_REF);
        gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
 
      if (SYMBOL_REF_ZDA_P (x))
      if (SYMBOL_REF_ZDA_P (x))
        fprintf (file, "zdaoff");
        fprintf (file, "zdaoff");
      else if (SYMBOL_REF_SDA_P (x))
      else if (SYMBOL_REF_SDA_P (x))
        fprintf (file, "sdaoff");
        fprintf (file, "sdaoff");
      else if (SYMBOL_REF_TDA_P (x))
      else if (SYMBOL_REF_TDA_P (x))
        fprintf (file, "tdaoff");
        fprintf (file, "tdaoff");
      else
      else
        gcc_unreachable ();
        gcc_unreachable ();
      break;
      break;
    case 'P':
    case 'P':
      gcc_assert (special_symbolref_operand (x, VOIDmode));
      gcc_assert (special_symbolref_operand (x, VOIDmode));
      output_addr_const (file, x);
      output_addr_const (file, x);
      break;
      break;
    case 'Q':
    case 'Q':
      gcc_assert (special_symbolref_operand (x, VOIDmode));
      gcc_assert (special_symbolref_operand (x, VOIDmode));
 
 
      if (GET_CODE (x) == CONST)
      if (GET_CODE (x) == CONST)
        x = XEXP (XEXP (x, 0), 0);
        x = XEXP (XEXP (x, 0), 0);
      else
      else
        gcc_assert (GET_CODE (x) == SYMBOL_REF);
        gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
 
      if (SYMBOL_REF_ZDA_P (x))
      if (SYMBOL_REF_ZDA_P (x))
        fprintf (file, "r0");
        fprintf (file, "r0");
      else if (SYMBOL_REF_SDA_P (x))
      else if (SYMBOL_REF_SDA_P (x))
        fprintf (file, "gp");
        fprintf (file, "gp");
      else if (SYMBOL_REF_TDA_P (x))
      else if (SYMBOL_REF_TDA_P (x))
        fprintf (file, "ep");
        fprintf (file, "ep");
      else
      else
        gcc_unreachable ();
        gcc_unreachable ();
      break;
      break;
    case 'R':           /* 2nd word of a double.  */
    case 'R':           /* 2nd word of a double.  */
      switch (GET_CODE (x))
      switch (GET_CODE (x))
        {
        {
        case REG:
        case REG:
          fprintf (file, reg_names[REGNO (x) + 1]);
          fprintf (file, reg_names[REGNO (x) + 1]);
          break;
          break;
        case MEM:
        case MEM:
          x = XEXP (adjust_address (x, SImode, 4), 0);
          x = XEXP (adjust_address (x, SImode, 4), 0);
          print_operand_address (file, x);
          print_operand_address (file, x);
          if (GET_CODE (x) == CONST_INT)
          if (GET_CODE (x) == CONST_INT)
            fprintf (file, "[r0]");
            fprintf (file, "[r0]");
          break;
          break;
 
 
        default:
        default:
          break;
          break;
        }
        }
      break;
      break;
    case 'S':
    case 'S':
      {
      {
        /* If it's a reference to a TDA variable, use sst/sld vs. st/ld.  */
        /* If it's a reference to a TDA variable, use sst/sld vs. st/ld.  */
        if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), FALSE))
        if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), FALSE))
          fputs ("s", file);
          fputs ("s", file);
 
 
        break;
        break;
      }
      }
    case 'T':
    case 'T':
      {
      {
        /* Like an 'S' operand above, but for unsigned loads only.  */
        /* Like an 'S' operand above, but for unsigned loads only.  */
        if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), TRUE))
        if (GET_CODE (x) == MEM && ep_memory_operand (x, GET_MODE (x), TRUE))
          fputs ("s", file);
          fputs ("s", file);
 
 
        break;
        break;
      }
      }
    case 'W':                   /* print the instruction suffix */
    case 'W':                   /* print the instruction suffix */
      switch (GET_MODE (x))
      switch (GET_MODE (x))
        {
        {
        default:
        default:
          gcc_unreachable ();
          gcc_unreachable ();
 
 
        case QImode: fputs (".b", file); break;
        case QImode: fputs (".b", file); break;
        case HImode: fputs (".h", file); break;
        case HImode: fputs (".h", file); break;
        case SImode: fputs (".w", file); break;
        case SImode: fputs (".w", file); break;
        case SFmode: fputs (".w", file); break;
        case SFmode: fputs (".w", file); break;
        }
        }
      break;
      break;
    case '.':                   /* register r0 */
    case '.':                   /* register r0 */
      fputs (reg_names[0], file);
      fputs (reg_names[0], file);
      break;
      break;
    case 'z':                   /* reg or zero */
    case 'z':                   /* reg or zero */
      if (GET_CODE (x) == REG)
      if (GET_CODE (x) == REG)
        fputs (reg_names[REGNO (x)], file);
        fputs (reg_names[REGNO (x)], file);
      else
      else
        {
        {
          gcc_assert (x == const0_rtx);
          gcc_assert (x == const0_rtx);
          fputs (reg_names[0], file);
          fputs (reg_names[0], file);
        }
        }
      break;
      break;
    default:
    default:
      switch (GET_CODE (x))
      switch (GET_CODE (x))
        {
        {
        case MEM:
        case MEM:
          if (GET_CODE (XEXP (x, 0)) == CONST_INT)
          if (GET_CODE (XEXP (x, 0)) == CONST_INT)
            output_address (gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, 0),
            output_address (gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, 0),
                                          XEXP (x, 0)));
                                          XEXP (x, 0)));
          else
          else
            output_address (XEXP (x, 0));
            output_address (XEXP (x, 0));
          break;
          break;
 
 
        case REG:
        case REG:
          fputs (reg_names[REGNO (x)], file);
          fputs (reg_names[REGNO (x)], file);
          break;
          break;
        case SUBREG:
        case SUBREG:
          fputs (reg_names[subreg_regno (x)], file);
          fputs (reg_names[subreg_regno (x)], file);
          break;
          break;
        case CONST_INT:
        case CONST_INT:
        case SYMBOL_REF:
        case SYMBOL_REF:
        case CONST:
        case CONST:
        case LABEL_REF:
        case LABEL_REF:
        case CODE_LABEL:
        case CODE_LABEL:
          print_operand_address (file, x);
          print_operand_address (file, x);
          break;
          break;
        default:
        default:
          gcc_unreachable ();
          gcc_unreachable ();
        }
        }
      break;
      break;
 
 
    }
    }
}
}
 
 


/* Output assembly language output for the address ADDR to FILE.  */
/* Output assembly language output for the address ADDR to FILE.  */
 
 
void
void
print_operand_address (FILE * file, rtx addr)
print_operand_address (FILE * file, rtx addr)
{
{
  switch (GET_CODE (addr))
  switch (GET_CODE (addr))
    {
    {
    case REG:
    case REG:
      fprintf (file, "0[");
      fprintf (file, "0[");
      print_operand (file, addr, 0);
      print_operand (file, addr, 0);
      fprintf (file, "]");
      fprintf (file, "]");
      break;
      break;
    case LO_SUM:
    case LO_SUM:
      if (GET_CODE (XEXP (addr, 0)) == REG)
      if (GET_CODE (XEXP (addr, 0)) == REG)
        {
        {
          /* reg,foo */
          /* reg,foo */
          fprintf (file, "lo(");
          fprintf (file, "lo(");
          print_operand (file, XEXP (addr, 1), 0);
          print_operand (file, XEXP (addr, 1), 0);
          fprintf (file, ")[");
          fprintf (file, ")[");
          print_operand (file, XEXP (addr, 0), 0);
          print_operand (file, XEXP (addr, 0), 0);
          fprintf (file, "]");
          fprintf (file, "]");
        }
        }
      break;
      break;
    case PLUS:
    case PLUS:
      if (GET_CODE (XEXP (addr, 0)) == REG
      if (GET_CODE (XEXP (addr, 0)) == REG
          || GET_CODE (XEXP (addr, 0)) == SUBREG)
          || GET_CODE (XEXP (addr, 0)) == SUBREG)
        {
        {
          /* reg,foo */
          /* reg,foo */
          print_operand (file, XEXP (addr, 1), 0);
          print_operand (file, XEXP (addr, 1), 0);
          fprintf (file, "[");
          fprintf (file, "[");
          print_operand (file, XEXP (addr, 0), 0);
          print_operand (file, XEXP (addr, 0), 0);
          fprintf (file, "]");
          fprintf (file, "]");
        }
        }
      else
      else
        {
        {
          print_operand (file, XEXP (addr, 0), 0);
          print_operand (file, XEXP (addr, 0), 0);
          fprintf (file, "+");
          fprintf (file, "+");
          print_operand (file, XEXP (addr, 1), 0);
          print_operand (file, XEXP (addr, 1), 0);
        }
        }
      break;
      break;
    case SYMBOL_REF:
    case SYMBOL_REF:
      {
      {
        const char *off_name = NULL;
        const char *off_name = NULL;
        const char *reg_name = NULL;
        const char *reg_name = NULL;
 
 
        if (SYMBOL_REF_ZDA_P (addr))
        if (SYMBOL_REF_ZDA_P (addr))
          {
          {
            off_name = "zdaoff";
            off_name = "zdaoff";
            reg_name = "r0";
            reg_name = "r0";
          }
          }
        else if (SYMBOL_REF_SDA_P (addr))
        else if (SYMBOL_REF_SDA_P (addr))
          {
          {
            off_name = "sdaoff";
            off_name = "sdaoff";
            reg_name = "gp";
            reg_name = "gp";
          }
          }
        else if (SYMBOL_REF_TDA_P (addr))
        else if (SYMBOL_REF_TDA_P (addr))
          {
          {
            off_name = "tdaoff";
            off_name = "tdaoff";
            reg_name = "ep";
            reg_name = "ep";
          }
          }
 
 
        if (off_name)
        if (off_name)
          fprintf (file, "%s(", off_name);
          fprintf (file, "%s(", off_name);
        output_addr_const (file, addr);
        output_addr_const (file, addr);
        if (reg_name)
        if (reg_name)
          fprintf (file, ")[%s]", reg_name);
          fprintf (file, ")[%s]", reg_name);
      }
      }
      break;
      break;
    case CONST:
    case CONST:
      if (special_symbolref_operand (addr, VOIDmode))
      if (special_symbolref_operand (addr, VOIDmode))
        {
        {
          rtx x = XEXP (XEXP (addr, 0), 0);
          rtx x = XEXP (XEXP (addr, 0), 0);
          const char *off_name;
          const char *off_name;
          const char *reg_name;
          const char *reg_name;
 
 
          if (SYMBOL_REF_ZDA_P (x))
          if (SYMBOL_REF_ZDA_P (x))
            {
            {
              off_name = "zdaoff";
              off_name = "zdaoff";
              reg_name = "r0";
              reg_name = "r0";
            }
            }
          else if (SYMBOL_REF_SDA_P (x))
          else if (SYMBOL_REF_SDA_P (x))
            {
            {
              off_name = "sdaoff";
              off_name = "sdaoff";
              reg_name = "gp";
              reg_name = "gp";
            }
            }
          else if (SYMBOL_REF_TDA_P (x))
          else if (SYMBOL_REF_TDA_P (x))
            {
            {
              off_name = "tdaoff";
              off_name = "tdaoff";
              reg_name = "ep";
              reg_name = "ep";
            }
            }
          else
          else
            gcc_unreachable ();
            gcc_unreachable ();
 
 
          fprintf (file, "%s(", off_name);
          fprintf (file, "%s(", off_name);
          output_addr_const (file, addr);
          output_addr_const (file, addr);
          fprintf (file, ")[%s]", reg_name);
          fprintf (file, ")[%s]", reg_name);
        }
        }
      else
      else
        output_addr_const (file, addr);
        output_addr_const (file, addr);
      break;
      break;
    default:
    default:
      output_addr_const (file, addr);
      output_addr_const (file, addr);
      break;
      break;
    }
    }
}
}
 
 
/* When assemble_integer is used to emit the offsets for a switch
/* When assemble_integer is used to emit the offsets for a switch
   table it can encounter (TRUNCATE:HI (MINUS:SI (LABEL_REF:SI) (LABEL_REF:SI))).
   table it can encounter (TRUNCATE:HI (MINUS:SI (LABEL_REF:SI) (LABEL_REF:SI))).
   output_addr_const will normally barf at this, but it is OK to omit
   output_addr_const will normally barf at this, but it is OK to omit
   the truncate and just emit the difference of the two labels.  The
   the truncate and just emit the difference of the two labels.  The
   .hword directive will automatically handle the truncation for us.
   .hword directive will automatically handle the truncation for us.
 
 
   Returns 1 if rtx was handled, 0 otherwise.  */
   Returns 1 if rtx was handled, 0 otherwise.  */
 
 
int
int
v850_output_addr_const_extra (FILE * file, rtx x)
v850_output_addr_const_extra (FILE * file, rtx x)
{
{
  if (GET_CODE (x) != TRUNCATE)
  if (GET_CODE (x) != TRUNCATE)
    return 0;
    return 0;
 
 
  x = XEXP (x, 0);
  x = XEXP (x, 0);
 
 
  /* We must also handle the case where the switch table was passed a
  /* We must also handle the case where the switch table was passed a
     constant value and so has been collapsed.  In this case the first
     constant value and so has been collapsed.  In this case the first
     label will have been deleted.  In such a case it is OK to emit
     label will have been deleted.  In such a case it is OK to emit
     nothing, since the table will not be used.
     nothing, since the table will not be used.
     (cf gcc.c-torture/compile/990801-1.c).  */
     (cf gcc.c-torture/compile/990801-1.c).  */
  if (GET_CODE (x) == MINUS
  if (GET_CODE (x) == MINUS
      && GET_CODE (XEXP (x, 0)) == LABEL_REF
      && GET_CODE (XEXP (x, 0)) == LABEL_REF
      && GET_CODE (XEXP (XEXP (x, 0), 0)) == CODE_LABEL
      && GET_CODE (XEXP (XEXP (x, 0), 0)) == CODE_LABEL
      && INSN_DELETED_P (XEXP (XEXP (x, 0), 0)))
      && INSN_DELETED_P (XEXP (XEXP (x, 0), 0)))
    return 1;
    return 1;
 
 
  output_addr_const (file, x);
  output_addr_const (file, x);
  return 1;
  return 1;
}
}


/* Return appropriate code to load up a 1, 2, or 4 integer/floating
/* Return appropriate code to load up a 1, 2, or 4 integer/floating
   point value.  */
   point value.  */
 
 
const char *
const char *
output_move_single (rtx * operands)
output_move_single (rtx * operands)
{
{
  rtx dst = operands[0];
  rtx dst = operands[0];
  rtx src = operands[1];
  rtx src = operands[1];
 
 
  if (REG_P (dst))
  if (REG_P (dst))
    {
    {
      if (REG_P (src))
      if (REG_P (src))
        return "mov %1,%0";
        return "mov %1,%0";
 
 
      else if (GET_CODE (src) == CONST_INT)
      else if (GET_CODE (src) == CONST_INT)
        {
        {
          HOST_WIDE_INT value = INTVAL (src);
          HOST_WIDE_INT value = INTVAL (src);
 
 
          if (CONST_OK_FOR_J (value))           /* Signed 5 bit immediate.  */
          if (CONST_OK_FOR_J (value))           /* Signed 5 bit immediate.  */
            return "mov %1,%0";
            return "mov %1,%0";
 
 
          else if (CONST_OK_FOR_K (value))      /* Signed 16 bit immediate.  */
          else if (CONST_OK_FOR_K (value))      /* Signed 16 bit immediate.  */
            return "movea lo(%1),%.,%0";
            return "movea lo(%1),%.,%0";
 
 
          else if (CONST_OK_FOR_L (value))      /* Upper 16 bits were set.  */
          else if (CONST_OK_FOR_L (value))      /* Upper 16 bits were set.  */
            return "movhi hi(%1),%.,%0";
            return "movhi hi(%1),%.,%0";
 
 
          /* A random constant.  */
          /* A random constant.  */
          else if (TARGET_V850E)
          else if (TARGET_V850E)
              return "mov %1,%0";
              return "mov %1,%0";
          else
          else
            return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
            return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
        }
        }
 
 
      else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
      else if (GET_CODE (src) == CONST_DOUBLE && GET_MODE (src) == SFmode)
        {
        {
          HOST_WIDE_INT high, low;
          HOST_WIDE_INT high, low;
 
 
          const_double_split (src, &high, &low);
          const_double_split (src, &high, &low);
 
 
          if (CONST_OK_FOR_J (high))            /* Signed 5 bit immediate.  */
          if (CONST_OK_FOR_J (high))            /* Signed 5 bit immediate.  */
            return "mov %F1,%0";
            return "mov %F1,%0";
 
 
          else if (CONST_OK_FOR_K (high))       /* Signed 16 bit immediate.  */
          else if (CONST_OK_FOR_K (high))       /* Signed 16 bit immediate.  */
            return "movea lo(%F1),%.,%0";
            return "movea lo(%F1),%.,%0";
 
 
          else if (CONST_OK_FOR_L (high))       /* Upper 16 bits were set.  */
          else if (CONST_OK_FOR_L (high))       /* Upper 16 bits were set.  */
            return "movhi hi(%F1),%.,%0";
            return "movhi hi(%F1),%.,%0";
 
 
          /* A random constant.  */
          /* A random constant.  */
          else if (TARGET_V850E)
          else if (TARGET_V850E)
              return "mov %F1,%0";
              return "mov %F1,%0";
 
 
          else
          else
            return "movhi hi(%F1),%.,%0\n\tmovea lo(%F1),%0,%0";
            return "movhi hi(%F1),%.,%0\n\tmovea lo(%F1),%0,%0";
        }
        }
 
 
      else if (GET_CODE (src) == MEM)
      else if (GET_CODE (src) == MEM)
        return "%S1ld%W1 %1,%0";
        return "%S1ld%W1 %1,%0";
 
 
      else if (special_symbolref_operand (src, VOIDmode))
      else if (special_symbolref_operand (src, VOIDmode))
        return "movea %O1(%P1),%Q1,%0";
        return "movea %O1(%P1),%Q1,%0";
 
 
      else if (GET_CODE (src) == LABEL_REF
      else if (GET_CODE (src) == LABEL_REF
               || GET_CODE (src) == SYMBOL_REF
               || GET_CODE (src) == SYMBOL_REF
               || GET_CODE (src) == CONST)
               || GET_CODE (src) == CONST)
        {
        {
          if (TARGET_V850E)
          if (TARGET_V850E)
            return "mov hilo(%1),%0";
            return "mov hilo(%1),%0";
          else
          else
            return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
            return "movhi hi(%1),%.,%0\n\tmovea lo(%1),%0,%0";
        }
        }
 
 
      else if (GET_CODE (src) == HIGH)
      else if (GET_CODE (src) == HIGH)
        return "movhi hi(%1),%.,%0";
        return "movhi hi(%1),%.,%0";
 
 
      else if (GET_CODE (src) == LO_SUM)
      else if (GET_CODE (src) == LO_SUM)
        {
        {
          operands[2] = XEXP (src, 0);
          operands[2] = XEXP (src, 0);
          operands[3] = XEXP (src, 1);
          operands[3] = XEXP (src, 1);
          return "movea lo(%3),%2,%0";
          return "movea lo(%3),%2,%0";
        }
        }
    }
    }
 
 
  else if (GET_CODE (dst) == MEM)
  else if (GET_CODE (dst) == MEM)
    {
    {
      if (REG_P (src))
      if (REG_P (src))
        return "%S0st%W0 %1,%0";
        return "%S0st%W0 %1,%0";
 
 
      else if (GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
      else if (GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
        return "%S0st%W0 %.,%0";
        return "%S0st%W0 %.,%0";
 
 
      else if (GET_CODE (src) == CONST_DOUBLE
      else if (GET_CODE (src) == CONST_DOUBLE
               && CONST0_RTX (GET_MODE (dst)) == src)
               && CONST0_RTX (GET_MODE (dst)) == src)
        return "%S0st%W0 %.,%0";
        return "%S0st%W0 %.,%0";
    }
    }
 
 
  fatal_insn ("output_move_single:", gen_rtx_SET (VOIDmode, dst, src));
  fatal_insn ("output_move_single:", gen_rtx_SET (VOIDmode, dst, src));
  return "";
  return "";
}
}
 
 


/* Return appropriate code to load up an 8 byte integer or
/* Return appropriate code to load up an 8 byte integer or
   floating point value */
   floating point value */
 
 
const char *
const char *
output_move_double (rtx * operands)
output_move_double (rtx * operands)
{
{
  enum machine_mode mode = GET_MODE (operands[0]);
  enum machine_mode mode = GET_MODE (operands[0]);
  rtx dst = operands[0];
  rtx dst = operands[0];
  rtx src = operands[1];
  rtx src = operands[1];
 
 
  if (register_operand (dst, mode)
  if (register_operand (dst, mode)
      && register_operand (src, mode))
      && register_operand (src, mode))
    {
    {
      if (REGNO (src) + 1 == REGNO (dst))
      if (REGNO (src) + 1 == REGNO (dst))
        return "mov %R1,%R0\n\tmov %1,%0";
        return "mov %R1,%R0\n\tmov %1,%0";
      else
      else
        return "mov %1,%0\n\tmov %R1,%R0";
        return "mov %1,%0\n\tmov %R1,%R0";
    }
    }
 
 
  /* Storing 0 */
  /* Storing 0 */
  if (GET_CODE (dst) == MEM
  if (GET_CODE (dst) == MEM
      && ((GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
      && ((GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
          || (GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src))))
          || (GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src))))
    return "st.w %.,%0\n\tst.w %.,%R0";
    return "st.w %.,%0\n\tst.w %.,%R0";
 
 
  if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
  if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
    {
    {
      HOST_WIDE_INT high_low[2];
      HOST_WIDE_INT high_low[2];
      int i;
      int i;
      rtx xop[10];
      rtx xop[10];
 
 
      if (GET_CODE (src) == CONST_DOUBLE)
      if (GET_CODE (src) == CONST_DOUBLE)
        const_double_split (src, &high_low[1], &high_low[0]);
        const_double_split (src, &high_low[1], &high_low[0]);
      else
      else
        {
        {
          high_low[0] = INTVAL (src);
          high_low[0] = INTVAL (src);
          high_low[1] = (INTVAL (src) >= 0) ? 0 : -1;
          high_low[1] = (INTVAL (src) >= 0) ? 0 : -1;
        }
        }
 
 
      for (i = 0; i < 2; i++)
      for (i = 0; i < 2; i++)
        {
        {
          xop[0] = gen_rtx_REG (SImode, REGNO (dst)+i);
          xop[0] = gen_rtx_REG (SImode, REGNO (dst)+i);
          xop[1] = GEN_INT (high_low[i]);
          xop[1] = GEN_INT (high_low[i]);
          output_asm_insn (output_move_single (xop), xop);
          output_asm_insn (output_move_single (xop), xop);
        }
        }
 
 
      return "";
      return "";
    }
    }
 
 
  if (GET_CODE (src) == MEM)
  if (GET_CODE (src) == MEM)
    {
    {
      int ptrreg = -1;
      int ptrreg = -1;
      int dreg = REGNO (dst);
      int dreg = REGNO (dst);
      rtx inside = XEXP (src, 0);
      rtx inside = XEXP (src, 0);
 
 
      if (GET_CODE (inside) == REG)
      if (GET_CODE (inside) == REG)
        ptrreg = REGNO (inside);
        ptrreg = REGNO (inside);
      else if (GET_CODE (inside) == SUBREG)
      else if (GET_CODE (inside) == SUBREG)
        ptrreg = subreg_regno (inside);
        ptrreg = subreg_regno (inside);
      else if (GET_CODE (inside) == PLUS)
      else if (GET_CODE (inside) == PLUS)
        ptrreg = REGNO (XEXP (inside, 0));
        ptrreg = REGNO (XEXP (inside, 0));
      else if (GET_CODE (inside) == LO_SUM)
      else if (GET_CODE (inside) == LO_SUM)
        ptrreg = REGNO (XEXP (inside, 0));
        ptrreg = REGNO (XEXP (inside, 0));
 
 
      if (dreg == ptrreg)
      if (dreg == ptrreg)
        return "ld.w %R1,%R0\n\tld.w %1,%0";
        return "ld.w %R1,%R0\n\tld.w %1,%0";
    }
    }
 
 
  if (GET_CODE (src) == MEM)
  if (GET_CODE (src) == MEM)
    return "ld.w %1,%0\n\tld.w %R1,%R0";
    return "ld.w %1,%0\n\tld.w %R1,%R0";
 
 
  if (GET_CODE (dst) == MEM)
  if (GET_CODE (dst) == MEM)
    return "st.w %1,%0\n\tst.w %R1,%R0";
    return "st.w %1,%0\n\tst.w %R1,%R0";
 
 
  return "mov %1,%0\n\tmov %R1,%R0";
  return "mov %1,%0\n\tmov %R1,%R0";
}
}
 
 


/* Return maximum offset supported for a short EP memory reference of mode
/* Return maximum offset supported for a short EP memory reference of mode
   MODE and signedness UNSIGNEDP.  */
   MODE and signedness UNSIGNEDP.  */
 
 
static int
static int
ep_memory_offset (enum machine_mode mode, int unsignedp ATTRIBUTE_UNUSED)
ep_memory_offset (enum machine_mode mode, int unsignedp ATTRIBUTE_UNUSED)
{
{
  int max_offset = 0;
  int max_offset = 0;
 
 
  switch (mode)
  switch (mode)
    {
    {
    case QImode:
    case QImode:
      if (TARGET_SMALL_SLD)
      if (TARGET_SMALL_SLD)
        max_offset = (1 << 4);
        max_offset = (1 << 4);
      else if (TARGET_V850E
      else if (TARGET_V850E
               && (   (  unsignedp && ! TARGET_US_BIT_SET)
               && (   (  unsignedp && ! TARGET_US_BIT_SET)
                   || (! unsignedp &&   TARGET_US_BIT_SET)))
                   || (! unsignedp &&   TARGET_US_BIT_SET)))
        max_offset = (1 << 4);
        max_offset = (1 << 4);
      else
      else
        max_offset = (1 << 7);
        max_offset = (1 << 7);
      break;
      break;
 
 
    case HImode:
    case HImode:
      if (TARGET_SMALL_SLD)
      if (TARGET_SMALL_SLD)
        max_offset = (1 << 5);
        max_offset = (1 << 5);
      else if (TARGET_V850E
      else if (TARGET_V850E
               && (   (  unsignedp && ! TARGET_US_BIT_SET)
               && (   (  unsignedp && ! TARGET_US_BIT_SET)
                   || (! unsignedp &&   TARGET_US_BIT_SET)))
                   || (! unsignedp &&   TARGET_US_BIT_SET)))
        max_offset = (1 << 5);
        max_offset = (1 << 5);
      else
      else
        max_offset = (1 << 8);
        max_offset = (1 << 8);
      break;
      break;
 
 
    case SImode:
    case SImode:
    case SFmode:
    case SFmode:
      max_offset = (1 << 8);
      max_offset = (1 << 8);
      break;
      break;
 
 
    default:
    default:
      break;
      break;
    }
    }
 
 
  return max_offset;
  return max_offset;
}
}
 
 
/* Return true if OP is a valid short EP memory reference */
/* Return true if OP is a valid short EP memory reference */
 
 
int
int
ep_memory_operand (rtx op, enum machine_mode mode, int unsigned_load)
ep_memory_operand (rtx op, enum machine_mode mode, int unsigned_load)
{
{
  rtx addr, op0, op1;
  rtx addr, op0, op1;
  int max_offset;
  int max_offset;
  int mask;
  int mask;
 
 
  /* If we are not using the EP register on a per-function basis
  /* If we are not using the EP register on a per-function basis
     then do not allow this optimization at all.  This is to
     then do not allow this optimization at all.  This is to
     prevent the use of the SLD/SST instructions which cannot be
     prevent the use of the SLD/SST instructions which cannot be
     guaranteed to work properly due to a hardware bug.  */
     guaranteed to work properly due to a hardware bug.  */
  if (!TARGET_EP)
  if (!TARGET_EP)
    return FALSE;
    return FALSE;
 
 
  if (GET_CODE (op) != MEM)
  if (GET_CODE (op) != MEM)
    return FALSE;
    return FALSE;
 
 
  max_offset = ep_memory_offset (mode, unsigned_load);
  max_offset = ep_memory_offset (mode, unsigned_load);
 
 
  mask = GET_MODE_SIZE (mode) - 1;
  mask = GET_MODE_SIZE (mode) - 1;
 
 
  addr = XEXP (op, 0);
  addr = XEXP (op, 0);
  if (GET_CODE (addr) == CONST)
  if (GET_CODE (addr) == CONST)
    addr = XEXP (addr, 0);
    addr = XEXP (addr, 0);
 
 
  switch (GET_CODE (addr))
  switch (GET_CODE (addr))
    {
    {
    default:
    default:
      break;
      break;
 
 
    case SYMBOL_REF:
    case SYMBOL_REF:
      return SYMBOL_REF_TDA_P (addr);
      return SYMBOL_REF_TDA_P (addr);
 
 
    case REG:
    case REG:
      return REGNO (addr) == EP_REGNUM;
      return REGNO (addr) == EP_REGNUM;
 
 
    case PLUS:
    case PLUS:
      op0 = XEXP (addr, 0);
      op0 = XEXP (addr, 0);
      op1 = XEXP (addr, 1);
      op1 = XEXP (addr, 1);
      if (GET_CODE (op1) == CONST_INT
      if (GET_CODE (op1) == CONST_INT
          && INTVAL (op1) < max_offset
          && INTVAL (op1) < max_offset
          && INTVAL (op1) >= 0
          && INTVAL (op1) >= 0
          && (INTVAL (op1) & mask) == 0)
          && (INTVAL (op1) & mask) == 0)
        {
        {
          if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM)
          if (GET_CODE (op0) == REG && REGNO (op0) == EP_REGNUM)
            return TRUE;
            return TRUE;
 
 
          if (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_TDA_P (op0))
          if (GET_CODE (op0) == SYMBOL_REF && SYMBOL_REF_TDA_P (op0))
            return TRUE;
            return TRUE;
        }
        }
      break;
      break;
    }
    }
 
 
  return FALSE;
  return FALSE;
}
}


/* Substitute memory references involving a pointer, to use the ep pointer,
/* Substitute memory references involving a pointer, to use the ep pointer,
   taking care to save and preserve the ep.  */
   taking care to save and preserve the ep.  */
 
 
static void
static void
substitute_ep_register (rtx first_insn,
substitute_ep_register (rtx first_insn,
                        rtx last_insn,
                        rtx last_insn,
                        int uses,
                        int uses,
                        int regno,
                        int regno,
                        rtx * p_r1,
                        rtx * p_r1,
                        rtx * p_ep)
                        rtx * p_ep)
{
{
  rtx reg = gen_rtx_REG (Pmode, regno);
  rtx reg = gen_rtx_REG (Pmode, regno);
  rtx insn;
  rtx insn;
 
 
  if (!*p_r1)
  if (!*p_r1)
    {
    {
      regs_ever_live[1] = 1;
      regs_ever_live[1] = 1;
      *p_r1 = gen_rtx_REG (Pmode, 1);
      *p_r1 = gen_rtx_REG (Pmode, 1);
      *p_ep = gen_rtx_REG (Pmode, 30);
      *p_ep = gen_rtx_REG (Pmode, 30);
    }
    }
 
 
  if (TARGET_DEBUG)
  if (TARGET_DEBUG)
    fprintf (stderr, "\
    fprintf (stderr, "\
Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, ending at %d\n",
             2 * (uses - 3), uses, reg_names[regno],
             2 * (uses - 3), uses, reg_names[regno],
             IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
             IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
             INSN_UID (first_insn), INSN_UID (last_insn));
             INSN_UID (first_insn), INSN_UID (last_insn));
 
 
  if (GET_CODE (first_insn) == NOTE)
  if (GET_CODE (first_insn) == NOTE)
    first_insn = next_nonnote_insn (first_insn);
    first_insn = next_nonnote_insn (first_insn);
 
 
  last_insn = next_nonnote_insn (last_insn);
  last_insn = next_nonnote_insn (last_insn);
  for (insn = first_insn; insn && insn != last_insn; insn = NEXT_INSN (insn))
  for (insn = first_insn; insn && insn != last_insn; insn = NEXT_INSN (insn))
    {
    {
      if (GET_CODE (insn) == INSN)
      if (GET_CODE (insn) == INSN)
        {
        {
          rtx pattern = single_set (insn);
          rtx pattern = single_set (insn);
 
 
          /* Replace the memory references.  */
          /* Replace the memory references.  */
          if (pattern)
          if (pattern)
            {
            {
              rtx *p_mem;
              rtx *p_mem;
              /* Memory operands are signed by default.  */
              /* Memory operands are signed by default.  */
              int unsignedp = FALSE;
              int unsignedp = FALSE;
 
 
              if (GET_CODE (SET_DEST (pattern)) == MEM
              if (GET_CODE (SET_DEST (pattern)) == MEM
                  && GET_CODE (SET_SRC (pattern)) == MEM)
                  && GET_CODE (SET_SRC (pattern)) == MEM)
                p_mem = (rtx *)0;
                p_mem = (rtx *)0;
 
 
              else if (GET_CODE (SET_DEST (pattern)) == MEM)
              else if (GET_CODE (SET_DEST (pattern)) == MEM)
                p_mem = &SET_DEST (pattern);
                p_mem = &SET_DEST (pattern);
 
 
              else if (GET_CODE (SET_SRC (pattern)) == MEM)
              else if (GET_CODE (SET_SRC (pattern)) == MEM)
                p_mem = &SET_SRC (pattern);
                p_mem = &SET_SRC (pattern);
 
 
              else if (GET_CODE (SET_SRC (pattern)) == SIGN_EXTEND
              else if (GET_CODE (SET_SRC (pattern)) == SIGN_EXTEND
                       && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
                       && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
                p_mem = &XEXP (SET_SRC (pattern), 0);
                p_mem = &XEXP (SET_SRC (pattern), 0);
 
 
              else if (GET_CODE (SET_SRC (pattern)) == ZERO_EXTEND
              else if (GET_CODE (SET_SRC (pattern)) == ZERO_EXTEND
                       && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
                       && GET_CODE (XEXP (SET_SRC (pattern), 0)) == MEM)
                {
                {
                  p_mem = &XEXP (SET_SRC (pattern), 0);
                  p_mem = &XEXP (SET_SRC (pattern), 0);
                  unsignedp = TRUE;
                  unsignedp = TRUE;
                }
                }
              else
              else
                p_mem = (rtx *)0;
                p_mem = (rtx *)0;
 
 
              if (p_mem)
              if (p_mem)
                {
                {
                  rtx addr = XEXP (*p_mem, 0);
                  rtx addr = XEXP (*p_mem, 0);
 
 
                  if (GET_CODE (addr) == REG && REGNO (addr) == (unsigned) regno)
                  if (GET_CODE (addr) == REG && REGNO (addr) == (unsigned) regno)
                    *p_mem = change_address (*p_mem, VOIDmode, *p_ep);
                    *p_mem = change_address (*p_mem, VOIDmode, *p_ep);
 
 
                  else if (GET_CODE (addr) == PLUS
                  else if (GET_CODE (addr) == PLUS
                           && GET_CODE (XEXP (addr, 0)) == REG
                           && GET_CODE (XEXP (addr, 0)) == REG
                           && REGNO (XEXP (addr, 0)) == (unsigned) regno
                           && REGNO (XEXP (addr, 0)) == (unsigned) regno
                           && GET_CODE (XEXP (addr, 1)) == CONST_INT
                           && GET_CODE (XEXP (addr, 1)) == CONST_INT
                           && ((INTVAL (XEXP (addr, 1)))
                           && ((INTVAL (XEXP (addr, 1)))
                               < ep_memory_offset (GET_MODE (*p_mem),
                               < ep_memory_offset (GET_MODE (*p_mem),
                                                   unsignedp))
                                                   unsignedp))
                           && ((INTVAL (XEXP (addr, 1))) >= 0))
                           && ((INTVAL (XEXP (addr, 1))) >= 0))
                    *p_mem = change_address (*p_mem, VOIDmode,
                    *p_mem = change_address (*p_mem, VOIDmode,
                                             gen_rtx_PLUS (Pmode,
                                             gen_rtx_PLUS (Pmode,
                                                           *p_ep,
                                                           *p_ep,
                                                           XEXP (addr, 1)));
                                                           XEXP (addr, 1)));
                }
                }
            }
            }
        }
        }
    }
    }
 
 
  /* Optimize back to back cases of ep <- r1 & r1 <- ep.  */
  /* Optimize back to back cases of ep <- r1 & r1 <- ep.  */
  insn = prev_nonnote_insn (first_insn);
  insn = prev_nonnote_insn (first_insn);
  if (insn && GET_CODE (insn) == INSN
  if (insn && GET_CODE (insn) == INSN
      && GET_CODE (PATTERN (insn)) == SET
      && GET_CODE (PATTERN (insn)) == SET
      && SET_DEST (PATTERN (insn)) == *p_ep
      && SET_DEST (PATTERN (insn)) == *p_ep
      && SET_SRC (PATTERN (insn)) == *p_r1)
      && SET_SRC (PATTERN (insn)) == *p_r1)
    delete_insn (insn);
    delete_insn (insn);
  else
  else
    emit_insn_before (gen_rtx_SET (Pmode, *p_r1, *p_ep), first_insn);
    emit_insn_before (gen_rtx_SET (Pmode, *p_r1, *p_ep), first_insn);
 
 
  emit_insn_before (gen_rtx_SET (Pmode, *p_ep, reg), first_insn);
  emit_insn_before (gen_rtx_SET (Pmode, *p_ep, reg), first_insn);
  emit_insn_before (gen_rtx_SET (Pmode, *p_ep, *p_r1), last_insn);
  emit_insn_before (gen_rtx_SET (Pmode, *p_ep, *p_r1), last_insn);
}
}
 
 


/* TARGET_MACHINE_DEPENDENT_REORG.  On the 850, we use it to implement
/* TARGET_MACHINE_DEPENDENT_REORG.  On the 850, we use it to implement
   the -mep mode to copy heavily used pointers to ep to use the implicit
   the -mep mode to copy heavily used pointers to ep to use the implicit
   addressing.  */
   addressing.  */
 
 
static void
static void
v850_reorg (void)
v850_reorg (void)
{
{
  struct
  struct
  {
  {
    int uses;
    int uses;
    rtx first_insn;
    rtx first_insn;
    rtx last_insn;
    rtx last_insn;
  }
  }
  regs[FIRST_PSEUDO_REGISTER];
  regs[FIRST_PSEUDO_REGISTER];
 
 
  int i;
  int i;
  int use_ep = FALSE;
  int use_ep = FALSE;
  rtx r1 = NULL_RTX;
  rtx r1 = NULL_RTX;
  rtx ep = NULL_RTX;
  rtx ep = NULL_RTX;
  rtx insn;
  rtx insn;
  rtx pattern;
  rtx pattern;
 
 
  /* If not ep mode, just return now.  */
  /* If not ep mode, just return now.  */
  if (!TARGET_EP)
  if (!TARGET_EP)
    return;
    return;
 
 
  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    {
    {
      regs[i].uses = 0;
      regs[i].uses = 0;
      regs[i].first_insn = NULL_RTX;
      regs[i].first_insn = NULL_RTX;
      regs[i].last_insn = NULL_RTX;
      regs[i].last_insn = NULL_RTX;
    }
    }
 
 
  for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
  for (insn = get_insns (); insn != NULL_RTX; insn = NEXT_INSN (insn))
    {
    {
      switch (GET_CODE (insn))
      switch (GET_CODE (insn))
        {
        {
          /* End of basic block */
          /* End of basic block */
        default:
        default:
          if (!use_ep)
          if (!use_ep)
            {
            {
              int max_uses = -1;
              int max_uses = -1;
              int max_regno = -1;
              int max_regno = -1;
 
 
              for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
              for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                {
                {
                  if (max_uses < regs[i].uses)
                  if (max_uses < regs[i].uses)
                    {
                    {
                      max_uses = regs[i].uses;
                      max_uses = regs[i].uses;
                      max_regno = i;
                      max_regno = i;
                    }
                    }
                }
                }
 
 
              if (max_uses > 3)
              if (max_uses > 3)
                substitute_ep_register (regs[max_regno].first_insn,
                substitute_ep_register (regs[max_regno].first_insn,
                                        regs[max_regno].last_insn,
                                        regs[max_regno].last_insn,
                                        max_uses, max_regno, &r1, &ep);
                                        max_uses, max_regno, &r1, &ep);
            }
            }
 
 
          use_ep = FALSE;
          use_ep = FALSE;
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
            {
            {
              regs[i].uses = 0;
              regs[i].uses = 0;
              regs[i].first_insn = NULL_RTX;
              regs[i].first_insn = NULL_RTX;
              regs[i].last_insn = NULL_RTX;
              regs[i].last_insn = NULL_RTX;
            }
            }
          break;
          break;
 
 
        case NOTE:
        case NOTE:
          break;
          break;
 
 
        case INSN:
        case INSN:
          pattern = single_set (insn);
          pattern = single_set (insn);
 
 
          /* See if there are any memory references we can shorten */
          /* See if there are any memory references we can shorten */
          if (pattern)
          if (pattern)
            {
            {
              rtx src = SET_SRC (pattern);
              rtx src = SET_SRC (pattern);
              rtx dest = SET_DEST (pattern);
              rtx dest = SET_DEST (pattern);
              rtx mem;
              rtx mem;
              /* Memory operands are signed by default.  */
              /* Memory operands are signed by default.  */
              int unsignedp = FALSE;
              int unsignedp = FALSE;
 
 
              /* We might have (SUBREG (MEM)) here, so just get rid of the
              /* We might have (SUBREG (MEM)) here, so just get rid of the
                 subregs to make this code simpler.  */
                 subregs to make this code simpler.  */
              if (GET_CODE (dest) == SUBREG
              if (GET_CODE (dest) == SUBREG
                  && (GET_CODE (SUBREG_REG (dest)) == MEM
                  && (GET_CODE (SUBREG_REG (dest)) == MEM
                      || GET_CODE (SUBREG_REG (dest)) == REG))
                      || GET_CODE (SUBREG_REG (dest)) == REG))
                alter_subreg (&dest);
                alter_subreg (&dest);
              if (GET_CODE (src) == SUBREG
              if (GET_CODE (src) == SUBREG
                  && (GET_CODE (SUBREG_REG (src)) == MEM
                  && (GET_CODE (SUBREG_REG (src)) == MEM
                      || GET_CODE (SUBREG_REG (src)) == REG))
                      || GET_CODE (SUBREG_REG (src)) == REG))
                alter_subreg (&src);
                alter_subreg (&src);
 
 
              if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
              if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
                mem = NULL_RTX;
                mem = NULL_RTX;
 
 
              else if (GET_CODE (dest) == MEM)
              else if (GET_CODE (dest) == MEM)
                mem = dest;
                mem = dest;
 
 
              else if (GET_CODE (src) == MEM)
              else if (GET_CODE (src) == MEM)
                mem = src;
                mem = src;
 
 
              else if (GET_CODE (src) == SIGN_EXTEND
              else if (GET_CODE (src) == SIGN_EXTEND
                       && GET_CODE (XEXP (src, 0)) == MEM)
                       && GET_CODE (XEXP (src, 0)) == MEM)
                mem = XEXP (src, 0);
                mem = XEXP (src, 0);
 
 
              else if (GET_CODE (src) == ZERO_EXTEND
              else if (GET_CODE (src) == ZERO_EXTEND
                       && GET_CODE (XEXP (src, 0)) == MEM)
                       && GET_CODE (XEXP (src, 0)) == MEM)
                {
                {
                  mem = XEXP (src, 0);
                  mem = XEXP (src, 0);
                  unsignedp = TRUE;
                  unsignedp = TRUE;
                }
                }
              else
              else
                mem = NULL_RTX;
                mem = NULL_RTX;
 
 
              if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
              if (mem && ep_memory_operand (mem, GET_MODE (mem), unsignedp))
                use_ep = TRUE;
                use_ep = TRUE;
 
 
              else if (!use_ep && mem
              else if (!use_ep && mem
                       && GET_MODE_SIZE (GET_MODE (mem)) <= UNITS_PER_WORD)
                       && GET_MODE_SIZE (GET_MODE (mem)) <= UNITS_PER_WORD)
                {
                {
                  rtx addr = XEXP (mem, 0);
                  rtx addr = XEXP (mem, 0);
                  int regno = -1;
                  int regno = -1;
                  int short_p;
                  int short_p;
 
 
                  if (GET_CODE (addr) == REG)
                  if (GET_CODE (addr) == REG)
                    {
                    {
                      short_p = TRUE;
                      short_p = TRUE;
                      regno = REGNO (addr);
                      regno = REGNO (addr);
                    }
                    }
 
 
                  else if (GET_CODE (addr) == PLUS
                  else if (GET_CODE (addr) == PLUS
                           && GET_CODE (XEXP (addr, 0)) == REG
                           && GET_CODE (XEXP (addr, 0)) == REG
                           && GET_CODE (XEXP (addr, 1)) == CONST_INT
                           && GET_CODE (XEXP (addr, 1)) == CONST_INT
                           && ((INTVAL (XEXP (addr, 1)))
                           && ((INTVAL (XEXP (addr, 1)))
                               < ep_memory_offset (GET_MODE (mem), unsignedp))
                               < ep_memory_offset (GET_MODE (mem), unsignedp))
                           && ((INTVAL (XEXP (addr, 1))) >= 0))
                           && ((INTVAL (XEXP (addr, 1))) >= 0))
                    {
                    {
                      short_p = TRUE;
                      short_p = TRUE;
                      regno = REGNO (XEXP (addr, 0));
                      regno = REGNO (XEXP (addr, 0));
                    }
                    }
 
 
                  else
                  else
                    short_p = FALSE;
                    short_p = FALSE;
 
 
                  if (short_p)
                  if (short_p)
                    {
                    {
                      regs[regno].uses++;
                      regs[regno].uses++;
                      regs[regno].last_insn = insn;
                      regs[regno].last_insn = insn;
                      if (!regs[regno].first_insn)
                      if (!regs[regno].first_insn)
                        regs[regno].first_insn = insn;
                        regs[regno].first_insn = insn;
                    }
                    }
                }
                }
 
 
              /* Loading up a register in the basic block zaps any savings
              /* Loading up a register in the basic block zaps any savings
                 for the register */
                 for the register */
              if (GET_CODE (dest) == REG)
              if (GET_CODE (dest) == REG)
                {
                {
                  enum machine_mode mode = GET_MODE (dest);
                  enum machine_mode mode = GET_MODE (dest);
                  int regno;
                  int regno;
                  int endregno;
                  int endregno;
 
 
                  regno = REGNO (dest);
                  regno = REGNO (dest);
                  endregno = regno + HARD_REGNO_NREGS (regno, mode);
                  endregno = regno + HARD_REGNO_NREGS (regno, mode);
 
 
                  if (!use_ep)
                  if (!use_ep)
                    {
                    {
                      /* See if we can use the pointer before this
                      /* See if we can use the pointer before this
                         modification.  */
                         modification.  */
                      int max_uses = -1;
                      int max_uses = -1;
                      int max_regno = -1;
                      int max_regno = -1;
 
 
                      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                        {
                        {
                          if (max_uses < regs[i].uses)
                          if (max_uses < regs[i].uses)
                            {
                            {
                              max_uses = regs[i].uses;
                              max_uses = regs[i].uses;
                              max_regno = i;
                              max_regno = i;
                            }
                            }
                        }
                        }
 
 
                      if (max_uses > 3
                      if (max_uses > 3
                          && max_regno >= regno
                          && max_regno >= regno
                          && max_regno < endregno)
                          && max_regno < endregno)
                        {
                        {
                          substitute_ep_register (regs[max_regno].first_insn,
                          substitute_ep_register (regs[max_regno].first_insn,
                                                  regs[max_regno].last_insn,
                                                  regs[max_regno].last_insn,
                                                  max_uses, max_regno, &r1,
                                                  max_uses, max_regno, &r1,
                                                  &ep);
                                                  &ep);
 
 
                          /* Since we made a substitution, zap all remembered
                          /* Since we made a substitution, zap all remembered
                             registers.  */
                             registers.  */
                          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
                            {
                            {
                              regs[i].uses = 0;
                              regs[i].uses = 0;
                              regs[i].first_insn = NULL_RTX;
                              regs[i].first_insn = NULL_RTX;
                              regs[i].last_insn = NULL_RTX;
                              regs[i].last_insn = NULL_RTX;
                            }
                            }
                        }
                        }
                    }
                    }
 
 
                  for (i = regno; i < endregno; i++)
                  for (i = regno; i < endregno; i++)
                    {
                    {
                      regs[i].uses = 0;
                      regs[i].uses = 0;
                      regs[i].first_insn = NULL_RTX;
                      regs[i].first_insn = NULL_RTX;
                      regs[i].last_insn = NULL_RTX;
                      regs[i].last_insn = NULL_RTX;
                    }
                    }
                }
                }
            }
            }
        }
        }
    }
    }
}
}
 
 


/* # of registers saved by the interrupt handler.  */
/* # of registers saved by the interrupt handler.  */
#define INTERRUPT_FIXED_NUM 4
#define INTERRUPT_FIXED_NUM 4
 
 
/* # of bytes for registers saved by the interrupt handler.  */
/* # of bytes for registers saved by the interrupt handler.  */
#define INTERRUPT_FIXED_SAVE_SIZE (4 * INTERRUPT_FIXED_NUM)
#define INTERRUPT_FIXED_SAVE_SIZE (4 * INTERRUPT_FIXED_NUM)
 
 
/* # of registers saved in register parameter area.  */
/* # of registers saved in register parameter area.  */
#define INTERRUPT_REGPARM_NUM 4
#define INTERRUPT_REGPARM_NUM 4
/* # of words saved for other registers.  */
/* # of words saved for other registers.  */
#define INTERRUPT_ALL_SAVE_NUM \
#define INTERRUPT_ALL_SAVE_NUM \
  (30 - INTERRUPT_FIXED_NUM + INTERRUPT_REGPARM_NUM)
  (30 - INTERRUPT_FIXED_NUM + INTERRUPT_REGPARM_NUM)
 
 
#define INTERRUPT_ALL_SAVE_SIZE (4 * INTERRUPT_ALL_SAVE_NUM)
#define INTERRUPT_ALL_SAVE_SIZE (4 * INTERRUPT_ALL_SAVE_NUM)
 
 
int
int
compute_register_save_size (long * p_reg_saved)
compute_register_save_size (long * p_reg_saved)
{
{
  int size = 0;
  int size = 0;
  int i;
  int i;
  int interrupt_handler = v850_interrupt_function_p (current_function_decl);
  int interrupt_handler = v850_interrupt_function_p (current_function_decl);
  int call_p = regs_ever_live [LINK_POINTER_REGNUM];
  int call_p = regs_ever_live [LINK_POINTER_REGNUM];
  long reg_saved = 0;
  long reg_saved = 0;
 
 
  /* Count the return pointer if we need to save it.  */
  /* Count the return pointer if we need to save it.  */
  if (current_function_profile && !call_p)
  if (current_function_profile && !call_p)
    regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
    regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
 
 
  /* Count space for the register saves.  */
  /* Count space for the register saves.  */
  if (interrupt_handler)
  if (interrupt_handler)
    {
    {
      for (i = 0; i <= 31; i++)
      for (i = 0; i <= 31; i++)
        switch (i)
        switch (i)
          {
          {
          default:
          default:
            if (regs_ever_live[i] || call_p)
            if (regs_ever_live[i] || call_p)
              {
              {
                size += 4;
                size += 4;
                reg_saved |= 1L << i;
                reg_saved |= 1L << i;
              }
              }
            break;
            break;
 
 
            /* We don't save/restore r0 or the stack pointer */
            /* We don't save/restore r0 or the stack pointer */
          case 0:
          case 0:
          case STACK_POINTER_REGNUM:
          case STACK_POINTER_REGNUM:
            break;
            break;
 
 
            /* For registers with fixed use, we save them, set them to the
            /* For registers with fixed use, we save them, set them to the
               appropriate value, and then restore them.
               appropriate value, and then restore them.
               These registers are handled specially, so don't list them
               These registers are handled specially, so don't list them
               on the list of registers to save in the prologue.  */
               on the list of registers to save in the prologue.  */
          case 1:               /* temp used to hold ep */
          case 1:               /* temp used to hold ep */
          case 4:               /* gp */
          case 4:               /* gp */
          case 10:              /* temp used to call interrupt save/restore */
          case 10:              /* temp used to call interrupt save/restore */
          case EP_REGNUM:       /* ep */
          case EP_REGNUM:       /* ep */
            size += 4;
            size += 4;
            break;
            break;
          }
          }
    }
    }
  else
  else
    {
    {
      /* Find the first register that needs to be saved.  */
      /* Find the first register that needs to be saved.  */
      for (i = 0; i <= 31; i++)
      for (i = 0; i <= 31; i++)
        if (regs_ever_live[i] && ((! call_used_regs[i])
        if (regs_ever_live[i] && ((! call_used_regs[i])
                                  || i == LINK_POINTER_REGNUM))
                                  || i == LINK_POINTER_REGNUM))
          break;
          break;
 
 
      /* If it is possible that an out-of-line helper function might be
      /* If it is possible that an out-of-line helper function might be
         used to generate the prologue for the current function, then we
         used to generate the prologue for the current function, then we
         need to cover the possibility that such a helper function will
         need to cover the possibility that such a helper function will
         be used, despite the fact that there might be gaps in the list of
         be used, despite the fact that there might be gaps in the list of
         registers that need to be saved.  To detect this we note that the
         registers that need to be saved.  To detect this we note that the
         helper functions always push at least register r29 (provided
         helper functions always push at least register r29 (provided
         that the function is not an interrupt handler).  */
         that the function is not an interrupt handler).  */
 
 
      if (TARGET_PROLOG_FUNCTION
      if (TARGET_PROLOG_FUNCTION
          && (i == 2 || ((i >= 20) && (i < 30))))
          && (i == 2 || ((i >= 20) && (i < 30))))
        {
        {
          if (i == 2)
          if (i == 2)
            {
            {
              size += 4;
              size += 4;
              reg_saved |= 1L << i;
              reg_saved |= 1L << i;
 
 
              i = 20;
              i = 20;
            }
            }
 
 
          /* Helper functions save all registers between the starting
          /* Helper functions save all registers between the starting
             register and the last register, regardless of whether they
             register and the last register, regardless of whether they
             are actually used by the function or not.  */
             are actually used by the function or not.  */
          for (; i <= 29; i++)
          for (; i <= 29; i++)
            {
            {
              size += 4;
              size += 4;
              reg_saved |= 1L << i;
              reg_saved |= 1L << i;
            }
            }
 
 
          if (regs_ever_live [LINK_POINTER_REGNUM])
          if (regs_ever_live [LINK_POINTER_REGNUM])
            {
            {
              size += 4;
              size += 4;
              reg_saved |= 1L << LINK_POINTER_REGNUM;
              reg_saved |= 1L << LINK_POINTER_REGNUM;
            }
            }
        }
        }
      else
      else
        {
        {
          for (; i <= 31; i++)
          for (; i <= 31; i++)
            if (regs_ever_live[i] && ((! call_used_regs[i])
            if (regs_ever_live[i] && ((! call_used_regs[i])
                                      || i == LINK_POINTER_REGNUM))
                                      || i == LINK_POINTER_REGNUM))
              {
              {
                size += 4;
                size += 4;
                reg_saved |= 1L << i;
                reg_saved |= 1L << i;
              }
              }
        }
        }
    }
    }
 
 
  if (p_reg_saved)
  if (p_reg_saved)
    *p_reg_saved = reg_saved;
    *p_reg_saved = reg_saved;
 
 
  return size;
  return size;
}
}
 
 
int
int
compute_frame_size (int size, long * p_reg_saved)
compute_frame_size (int size, long * p_reg_saved)
{
{
  return (size
  return (size
          + compute_register_save_size (p_reg_saved)
          + compute_register_save_size (p_reg_saved)
          + current_function_outgoing_args_size);
          + current_function_outgoing_args_size);
}
}
 
 


void
void
expand_prologue (void)
expand_prologue (void)
{
{
  unsigned int i;
  unsigned int i;
  int offset;
  int offset;
  unsigned int size = get_frame_size ();
  unsigned int size = get_frame_size ();
  unsigned int actual_fsize;
  unsigned int actual_fsize;
  unsigned int init_stack_alloc = 0;
  unsigned int init_stack_alloc = 0;
  rtx save_regs[32];
  rtx save_regs[32];
  rtx save_all;
  rtx save_all;
  unsigned int num_save;
  unsigned int num_save;
  unsigned int default_stack;
  unsigned int default_stack;
  int code;
  int code;
  int interrupt_handler = v850_interrupt_function_p (current_function_decl);
  int interrupt_handler = v850_interrupt_function_p (current_function_decl);
  long reg_saved = 0;
  long reg_saved = 0;
 
 
  actual_fsize = compute_frame_size (size, &reg_saved);
  actual_fsize = compute_frame_size (size, &reg_saved);
 
 
  /* Save/setup global registers for interrupt functions right now.  */
  /* Save/setup global registers for interrupt functions right now.  */
  if (interrupt_handler)
  if (interrupt_handler)
    {
    {
      if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
      if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
        emit_insn (gen_callt_save_interrupt ());
        emit_insn (gen_callt_save_interrupt ());
      else
      else
        emit_insn (gen_save_interrupt ());
        emit_insn (gen_save_interrupt ());
 
 
      actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
      actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
 
 
      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
        actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
        actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
    }
    }
 
 
  /* Save arg registers to the stack if necessary.  */
  /* Save arg registers to the stack if necessary.  */
  else if (current_function_args_info.anonymous_args)
  else if (current_function_args_info.anonymous_args)
    {
    {
      if (TARGET_PROLOG_FUNCTION && TARGET_V850E && !TARGET_DISABLE_CALLT)
      if (TARGET_PROLOG_FUNCTION && TARGET_V850E && !TARGET_DISABLE_CALLT)
        emit_insn (gen_save_r6_r9_v850e ());
        emit_insn (gen_save_r6_r9_v850e ());
      else if (TARGET_PROLOG_FUNCTION && ! TARGET_LONG_CALLS)
      else if (TARGET_PROLOG_FUNCTION && ! TARGET_LONG_CALLS)
        emit_insn (gen_save_r6_r9 ());
        emit_insn (gen_save_r6_r9 ());
      else
      else
        {
        {
          offset = 0;
          offset = 0;
          for (i = 6; i < 10; i++)
          for (i = 6; i < 10; i++)
            {
            {
              emit_move_insn (gen_rtx_MEM (SImode,
              emit_move_insn (gen_rtx_MEM (SImode,
                                           plus_constant (stack_pointer_rtx,
                                           plus_constant (stack_pointer_rtx,
                                                          offset)),
                                                          offset)),
                              gen_rtx_REG (SImode, i));
                              gen_rtx_REG (SImode, i));
              offset += 4;
              offset += 4;
            }
            }
        }
        }
    }
    }
 
 
  /* Identify all of the saved registers.  */
  /* Identify all of the saved registers.  */
  num_save = 0;
  num_save = 0;
  default_stack = 0;
  default_stack = 0;
  for (i = 1; i < 31; i++)
  for (i = 1; i < 31; i++)
    {
    {
      if (((1L << i) & reg_saved) != 0)
      if (((1L << i) & reg_saved) != 0)
        save_regs[num_save++] = gen_rtx_REG (Pmode, i);
        save_regs[num_save++] = gen_rtx_REG (Pmode, i);
    }
    }
 
 
  /* If the return pointer is saved, the helper functions also allocate
  /* If the return pointer is saved, the helper functions also allocate
     16 bytes of stack for arguments to be saved in.  */
     16 bytes of stack for arguments to be saved in.  */
  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
    {
    {
      save_regs[num_save++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
      save_regs[num_save++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
      default_stack = 16;
      default_stack = 16;
    }
    }
 
 
  /* See if we have an insn that allocates stack space and saves the particular
  /* See if we have an insn that allocates stack space and saves the particular
     registers we want to.  */
     registers we want to.  */
  save_all = NULL_RTX;
  save_all = NULL_RTX;
  if (TARGET_PROLOG_FUNCTION && num_save > 0 && actual_fsize >= default_stack)
  if (TARGET_PROLOG_FUNCTION && num_save > 0 && actual_fsize >= default_stack)
    {
    {
      int alloc_stack = (4 * num_save) + default_stack;
      int alloc_stack = (4 * num_save) + default_stack;
      int unalloc_stack = actual_fsize - alloc_stack;
      int unalloc_stack = actual_fsize - alloc_stack;
      int save_func_len = 4;
      int save_func_len = 4;
      int save_normal_len;
      int save_normal_len;
 
 
      if (unalloc_stack)
      if (unalloc_stack)
        save_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
        save_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
 
 
      /* see if we would have used ep to save the stack */
      /* see if we would have used ep to save the stack */
      if (TARGET_EP && num_save > 3 && (unsigned)actual_fsize < 255)
      if (TARGET_EP && num_save > 3 && (unsigned)actual_fsize < 255)
        save_normal_len = (3 * 2) + (2 * num_save);
        save_normal_len = (3 * 2) + (2 * num_save);
      else
      else
        save_normal_len = 4 * num_save;
        save_normal_len = 4 * num_save;
 
 
      save_normal_len += CONST_OK_FOR_J (actual_fsize) ? 2 : 4;
      save_normal_len += CONST_OK_FOR_J (actual_fsize) ? 2 : 4;
 
 
      /* Don't bother checking if we don't actually save any space.
      /* Don't bother checking if we don't actually save any space.
         This happens for instance if one register is saved and additional
         This happens for instance if one register is saved and additional
         stack space is allocated.  */
         stack space is allocated.  */
      if (save_func_len < save_normal_len)
      if (save_func_len < save_normal_len)
        {
        {
          save_all = gen_rtx_PARALLEL
          save_all = gen_rtx_PARALLEL
            (VOIDmode,
            (VOIDmode,
             rtvec_alloc (num_save + 1
             rtvec_alloc (num_save + 1
                          + (TARGET_V850 ? (TARGET_LONG_CALLS ? 2 : 1) : 0)));
                          + (TARGET_V850 ? (TARGET_LONG_CALLS ? 2 : 1) : 0)));
 
 
          XVECEXP (save_all, 0, 0)
          XVECEXP (save_all, 0, 0)
            = gen_rtx_SET (VOIDmode,
            = gen_rtx_SET (VOIDmode,
                           stack_pointer_rtx,
                           stack_pointer_rtx,
                           plus_constant (stack_pointer_rtx, -alloc_stack));
                           plus_constant (stack_pointer_rtx, -alloc_stack));
 
 
          offset = - default_stack;
          offset = - default_stack;
          for (i = 0; i < num_save; i++)
          for (i = 0; i < num_save; i++)
            {
            {
              XVECEXP (save_all, 0, i+1)
              XVECEXP (save_all, 0, i+1)
                = gen_rtx_SET (VOIDmode,
                = gen_rtx_SET (VOIDmode,
                               gen_rtx_MEM (Pmode,
                               gen_rtx_MEM (Pmode,
                                            plus_constant (stack_pointer_rtx,
                                            plus_constant (stack_pointer_rtx,
                                                           offset)),
                                                           offset)),
                               save_regs[i]);
                               save_regs[i]);
              offset -= 4;
              offset -= 4;
            }
            }
 
 
          if (TARGET_V850)
          if (TARGET_V850)
            {
            {
              XVECEXP (save_all, 0, num_save + 1)
              XVECEXP (save_all, 0, num_save + 1)
                = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 10));
                = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 10));
 
 
              if (TARGET_LONG_CALLS)
              if (TARGET_LONG_CALLS)
                XVECEXP (save_all, 0, num_save + 2)
                XVECEXP (save_all, 0, num_save + 2)
                  = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
                  = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
            }
            }
 
 
          code = recog (save_all, NULL_RTX, NULL);
          code = recog (save_all, NULL_RTX, NULL);
          if (code >= 0)
          if (code >= 0)
            {
            {
              rtx insn = emit_insn (save_all);
              rtx insn = emit_insn (save_all);
              INSN_CODE (insn) = code;
              INSN_CODE (insn) = code;
              actual_fsize -= alloc_stack;
              actual_fsize -= alloc_stack;
 
 
              if (TARGET_DEBUG)
              if (TARGET_DEBUG)
                fprintf (stderr, "\
                fprintf (stderr, "\
Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
Saved %d bytes via prologue function (%d vs. %d) for function %s\n",
                         save_normal_len - save_func_len,
                         save_normal_len - save_func_len,
                         save_normal_len, save_func_len,
                         save_normal_len, save_func_len,
                         IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
                         IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
            }
            }
          else
          else
            save_all = NULL_RTX;
            save_all = NULL_RTX;
        }
        }
    }
    }
 
 
  /* If no prolog save function is available, store the registers the old
  /* If no prolog save function is available, store the registers the old
     fashioned way (one by one).  */
     fashioned way (one by one).  */
  if (!save_all)
  if (!save_all)
    {
    {
      /* Special case interrupt functions that save all registers for a call.  */
      /* Special case interrupt functions that save all registers for a call.  */
      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
        {
        {
          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
            emit_insn (gen_callt_save_all_interrupt ());
            emit_insn (gen_callt_save_all_interrupt ());
          else
          else
            emit_insn (gen_save_all_interrupt ());
            emit_insn (gen_save_all_interrupt ());
        }
        }
      else
      else
        {
        {
          /* If the stack is too big, allocate it in chunks so we can do the
          /* If the stack is too big, allocate it in chunks so we can do the
             register saves.  We use the register save size so we use the ep
             register saves.  We use the register save size so we use the ep
             register.  */
             register.  */
          if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
          if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
            init_stack_alloc = compute_register_save_size (NULL);
            init_stack_alloc = compute_register_save_size (NULL);
          else
          else
            init_stack_alloc = actual_fsize;
            init_stack_alloc = actual_fsize;
 
 
          /* Save registers at the beginning of the stack frame.  */
          /* Save registers at the beginning of the stack frame.  */
          offset = init_stack_alloc - 4;
          offset = init_stack_alloc - 4;
 
 
          if (init_stack_alloc)
          if (init_stack_alloc)
            emit_insn (gen_addsi3 (stack_pointer_rtx,
            emit_insn (gen_addsi3 (stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   GEN_INT (-init_stack_alloc)));
                                   GEN_INT (-init_stack_alloc)));
 
 
          /* Save the return pointer first.  */
          /* Save the return pointer first.  */
          if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)
          if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)
            {
            {
              emit_move_insn (gen_rtx_MEM (SImode,
              emit_move_insn (gen_rtx_MEM (SImode,
                                           plus_constant (stack_pointer_rtx,
                                           plus_constant (stack_pointer_rtx,
                                                          offset)),
                                                          offset)),
                              save_regs[--num_save]);
                              save_regs[--num_save]);
              offset -= 4;
              offset -= 4;
            }
            }
 
 
          for (i = 0; i < num_save; i++)
          for (i = 0; i < num_save; i++)
            {
            {
              emit_move_insn (gen_rtx_MEM (SImode,
              emit_move_insn (gen_rtx_MEM (SImode,
                                           plus_constant (stack_pointer_rtx,
                                           plus_constant (stack_pointer_rtx,
                                                          offset)),
                                                          offset)),
                              save_regs[i]);
                              save_regs[i]);
              offset -= 4;
              offset -= 4;
            }
            }
        }
        }
    }
    }
 
 
  /* Allocate the rest of the stack that was not allocated above (either it is
  /* Allocate the rest of the stack that was not allocated above (either it is
     > 32K or we just called a function to save the registers and needed more
     > 32K or we just called a function to save the registers and needed more
     stack.  */
     stack.  */
  if (actual_fsize > init_stack_alloc)
  if (actual_fsize > init_stack_alloc)
    {
    {
      int diff = actual_fsize - init_stack_alloc;
      int diff = actual_fsize - init_stack_alloc;
      if (CONST_OK_FOR_K (diff))
      if (CONST_OK_FOR_K (diff))
        emit_insn (gen_addsi3 (stack_pointer_rtx,
        emit_insn (gen_addsi3 (stack_pointer_rtx,
                               stack_pointer_rtx,
                               stack_pointer_rtx,
                               GEN_INT (-diff)));
                               GEN_INT (-diff)));
      else
      else
        {
        {
          rtx reg = gen_rtx_REG (Pmode, 12);
          rtx reg = gen_rtx_REG (Pmode, 12);
          emit_move_insn (reg, GEN_INT (-diff));
          emit_move_insn (reg, GEN_INT (-diff));
          emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
          emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
        }
        }
    }
    }
 
 
  /* If we need a frame pointer, set it up now.  */
  /* If we need a frame pointer, set it up now.  */
  if (frame_pointer_needed)
  if (frame_pointer_needed)
    emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
    emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
}
}


 
 
void
void
expand_epilogue (void)
expand_epilogue (void)
{
{
  unsigned int i;
  unsigned int i;
  int offset;
  int offset;
  unsigned int size = get_frame_size ();
  unsigned int size = get_frame_size ();
  long reg_saved = 0;
  long reg_saved = 0;
  unsigned int actual_fsize = compute_frame_size (size, &reg_saved);
  unsigned int actual_fsize = compute_frame_size (size, &reg_saved);
  unsigned int init_stack_free = 0;
  unsigned int init_stack_free = 0;
  rtx restore_regs[32];
  rtx restore_regs[32];
  rtx restore_all;
  rtx restore_all;
  unsigned int num_restore;
  unsigned int num_restore;
  unsigned int default_stack;
  unsigned int default_stack;
  int code;
  int code;
  int interrupt_handler = v850_interrupt_function_p (current_function_decl);
  int interrupt_handler = v850_interrupt_function_p (current_function_decl);
 
 
  /* Eliminate the initial stack stored by interrupt functions.  */
  /* Eliminate the initial stack stored by interrupt functions.  */
  if (interrupt_handler)
  if (interrupt_handler)
    {
    {
      actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
      actual_fsize -= INTERRUPT_FIXED_SAVE_SIZE;
      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
      if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
        actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
        actual_fsize -= INTERRUPT_ALL_SAVE_SIZE;
    }
    }
 
 
  /* Cut off any dynamic stack created.  */
  /* Cut off any dynamic stack created.  */
  if (frame_pointer_needed)
  if (frame_pointer_needed)
    emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
    emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
 
 
  /* Identify all of the saved registers.  */
  /* Identify all of the saved registers.  */
  num_restore = 0;
  num_restore = 0;
  default_stack = 0;
  default_stack = 0;
  for (i = 1; i < 31; i++)
  for (i = 1; i < 31; i++)
    {
    {
      if (((1L << i) & reg_saved) != 0)
      if (((1L << i) & reg_saved) != 0)
        restore_regs[num_restore++] = gen_rtx_REG (Pmode, i);
        restore_regs[num_restore++] = gen_rtx_REG (Pmode, i);
    }
    }
 
 
  /* If the return pointer is saved, the helper functions also allocate
  /* If the return pointer is saved, the helper functions also allocate
     16 bytes of stack for arguments to be saved in.  */
     16 bytes of stack for arguments to be saved in.  */
  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
  if (((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
    {
    {
      restore_regs[num_restore++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
      restore_regs[num_restore++] = gen_rtx_REG (Pmode, LINK_POINTER_REGNUM);
      default_stack = 16;
      default_stack = 16;
    }
    }
 
 
  /* See if we have an insn that restores the particular registers we
  /* See if we have an insn that restores the particular registers we
     want to.  */
     want to.  */
  restore_all = NULL_RTX;
  restore_all = NULL_RTX;
 
 
  if (TARGET_PROLOG_FUNCTION
  if (TARGET_PROLOG_FUNCTION
      && num_restore > 0
      && num_restore > 0
      && actual_fsize >= default_stack
      && actual_fsize >= default_stack
      && !interrupt_handler)
      && !interrupt_handler)
    {
    {
      int alloc_stack = (4 * num_restore) + default_stack;
      int alloc_stack = (4 * num_restore) + default_stack;
      int unalloc_stack = actual_fsize - alloc_stack;
      int unalloc_stack = actual_fsize - alloc_stack;
      int restore_func_len = 4;
      int restore_func_len = 4;
      int restore_normal_len;
      int restore_normal_len;
 
 
      if (unalloc_stack)
      if (unalloc_stack)
        restore_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
        restore_func_len += CONST_OK_FOR_J (unalloc_stack) ? 2 : 4;
 
 
      /* See if we would have used ep to restore the registers.  */
      /* See if we would have used ep to restore the registers.  */
      if (TARGET_EP && num_restore > 3 && (unsigned)actual_fsize < 255)
      if (TARGET_EP && num_restore > 3 && (unsigned)actual_fsize < 255)
        restore_normal_len = (3 * 2) + (2 * num_restore);
        restore_normal_len = (3 * 2) + (2 * num_restore);
      else
      else
        restore_normal_len = 4 * num_restore;
        restore_normal_len = 4 * num_restore;
 
 
      restore_normal_len += (CONST_OK_FOR_J (actual_fsize) ? 2 : 4) + 2;
      restore_normal_len += (CONST_OK_FOR_J (actual_fsize) ? 2 : 4) + 2;
 
 
      /* Don't bother checking if we don't actually save any space.  */
      /* Don't bother checking if we don't actually save any space.  */
      if (restore_func_len < restore_normal_len)
      if (restore_func_len < restore_normal_len)
        {
        {
          restore_all = gen_rtx_PARALLEL (VOIDmode,
          restore_all = gen_rtx_PARALLEL (VOIDmode,
                                          rtvec_alloc (num_restore + 2));
                                          rtvec_alloc (num_restore + 2));
          XVECEXP (restore_all, 0, 0) = gen_rtx_RETURN (VOIDmode);
          XVECEXP (restore_all, 0, 0) = gen_rtx_RETURN (VOIDmode);
          XVECEXP (restore_all, 0, 1)
          XVECEXP (restore_all, 0, 1)
            = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
            = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
                            gen_rtx_PLUS (Pmode,
                            gen_rtx_PLUS (Pmode,
                                          stack_pointer_rtx,
                                          stack_pointer_rtx,
                                          GEN_INT (alloc_stack)));
                                          GEN_INT (alloc_stack)));
 
 
          offset = alloc_stack - 4;
          offset = alloc_stack - 4;
          for (i = 0; i < num_restore; i++)
          for (i = 0; i < num_restore; i++)
            {
            {
              XVECEXP (restore_all, 0, i+2)
              XVECEXP (restore_all, 0, i+2)
                = gen_rtx_SET (VOIDmode,
                = gen_rtx_SET (VOIDmode,
                               restore_regs[i],
                               restore_regs[i],
                               gen_rtx_MEM (Pmode,
                               gen_rtx_MEM (Pmode,
                                            plus_constant (stack_pointer_rtx,
                                            plus_constant (stack_pointer_rtx,
                                                           offset)));
                                                           offset)));
              offset -= 4;
              offset -= 4;
            }
            }
 
 
          code = recog (restore_all, NULL_RTX, NULL);
          code = recog (restore_all, NULL_RTX, NULL);
 
 
          if (code >= 0)
          if (code >= 0)
            {
            {
              rtx insn;
              rtx insn;
 
 
              actual_fsize -= alloc_stack;
              actual_fsize -= alloc_stack;
              if (actual_fsize)
              if (actual_fsize)
                {
                {
                  if (CONST_OK_FOR_K (actual_fsize))
                  if (CONST_OK_FOR_K (actual_fsize))
                    emit_insn (gen_addsi3 (stack_pointer_rtx,
                    emit_insn (gen_addsi3 (stack_pointer_rtx,
                                           stack_pointer_rtx,
                                           stack_pointer_rtx,
                                           GEN_INT (actual_fsize)));
                                           GEN_INT (actual_fsize)));
                  else
                  else
                    {
                    {
                      rtx reg = gen_rtx_REG (Pmode, 12);
                      rtx reg = gen_rtx_REG (Pmode, 12);
                      emit_move_insn (reg, GEN_INT (actual_fsize));
                      emit_move_insn (reg, GEN_INT (actual_fsize));
                      emit_insn (gen_addsi3 (stack_pointer_rtx,
                      emit_insn (gen_addsi3 (stack_pointer_rtx,
                                             stack_pointer_rtx,
                                             stack_pointer_rtx,
                                             reg));
                                             reg));
                    }
                    }
                }
                }
 
 
              insn = emit_jump_insn (restore_all);
              insn = emit_jump_insn (restore_all);
              INSN_CODE (insn) = code;
              INSN_CODE (insn) = code;
 
 
              if (TARGET_DEBUG)
              if (TARGET_DEBUG)
                fprintf (stderr, "\
                fprintf (stderr, "\
Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
Saved %d bytes via epilogue function (%d vs. %d) in function %s\n",
                         restore_normal_len - restore_func_len,
                         restore_normal_len - restore_func_len,
                         restore_normal_len, restore_func_len,
                         restore_normal_len, restore_func_len,
                         IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
                         IDENTIFIER_POINTER (DECL_NAME (current_function_decl)));
            }
            }
          else
          else
            restore_all = NULL_RTX;
            restore_all = NULL_RTX;
        }
        }
    }
    }
 
 
  /* If no epilog save function is available, restore the registers the
  /* If no epilog save function is available, restore the registers the
     old fashioned way (one by one).  */
     old fashioned way (one by one).  */
  if (!restore_all)
  if (!restore_all)
    {
    {
      /* If the stack is large, we need to cut it down in 2 pieces.  */
      /* If the stack is large, we need to cut it down in 2 pieces.  */
      if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
      if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
        init_stack_free = 4 * num_restore;
        init_stack_free = 4 * num_restore;
      else
      else
        init_stack_free = actual_fsize;
        init_stack_free = actual_fsize;
 
 
      /* Deallocate the rest of the stack if it is > 32K.  */
      /* Deallocate the rest of the stack if it is > 32K.  */
      if (actual_fsize > init_stack_free)
      if (actual_fsize > init_stack_free)
        {
        {
          int diff;
          int diff;
 
 
          diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);
          diff = actual_fsize - ((interrupt_handler) ? 0 : init_stack_free);
 
 
          if (CONST_OK_FOR_K (diff))
          if (CONST_OK_FOR_K (diff))
            emit_insn (gen_addsi3 (stack_pointer_rtx,
            emit_insn (gen_addsi3 (stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   GEN_INT (diff)));
                                   GEN_INT (diff)));
          else
          else
            {
            {
              rtx reg = gen_rtx_REG (Pmode, 12);
              rtx reg = gen_rtx_REG (Pmode, 12);
              emit_move_insn (reg, GEN_INT (diff));
              emit_move_insn (reg, GEN_INT (diff));
              emit_insn (gen_addsi3 (stack_pointer_rtx,
              emit_insn (gen_addsi3 (stack_pointer_rtx,
                                     stack_pointer_rtx,
                                     stack_pointer_rtx,
                                     reg));
                                     reg));
            }
            }
        }
        }
 
 
      /* Special case interrupt functions that save all registers
      /* Special case interrupt functions that save all registers
         for a call.  */
         for a call.  */
      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
      if (interrupt_handler && ((1L << LINK_POINTER_REGNUM) & reg_saved) != 0)
        {
        {
          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
            emit_insn (gen_callt_restore_all_interrupt ());
            emit_insn (gen_callt_restore_all_interrupt ());
          else
          else
            emit_insn (gen_restore_all_interrupt ());
            emit_insn (gen_restore_all_interrupt ());
        }
        }
      else
      else
        {
        {
          /* Restore registers from the beginning of the stack frame.  */
          /* Restore registers from the beginning of the stack frame.  */
          offset = init_stack_free - 4;
          offset = init_stack_free - 4;
 
 
          /* Restore the return pointer first.  */
          /* Restore the return pointer first.  */
          if (num_restore > 0
          if (num_restore > 0
              && REGNO (restore_regs [num_restore - 1]) == LINK_POINTER_REGNUM)
              && REGNO (restore_regs [num_restore - 1]) == LINK_POINTER_REGNUM)
            {
            {
              emit_move_insn (restore_regs[--num_restore],
              emit_move_insn (restore_regs[--num_restore],
                              gen_rtx_MEM (SImode,
                              gen_rtx_MEM (SImode,
                                           plus_constant (stack_pointer_rtx,
                                           plus_constant (stack_pointer_rtx,
                                                          offset)));
                                                          offset)));
              offset -= 4;
              offset -= 4;
            }
            }
 
 
          for (i = 0; i < num_restore; i++)
          for (i = 0; i < num_restore; i++)
            {
            {
              emit_move_insn (restore_regs[i],
              emit_move_insn (restore_regs[i],
                              gen_rtx_MEM (SImode,
                              gen_rtx_MEM (SImode,
                                           plus_constant (stack_pointer_rtx,
                                           plus_constant (stack_pointer_rtx,
                                                          offset)));
                                                          offset)));
 
 
              emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));
              emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));
              offset -= 4;
              offset -= 4;
            }
            }
 
 
          /* Cut back the remainder of the stack.  */
          /* Cut back the remainder of the stack.  */
          if (init_stack_free)
          if (init_stack_free)
            emit_insn (gen_addsi3 (stack_pointer_rtx,
            emit_insn (gen_addsi3 (stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   stack_pointer_rtx,
                                   GEN_INT (init_stack_free)));
                                   GEN_INT (init_stack_free)));
        }
        }
 
 
      /* And return or use reti for interrupt handlers.  */
      /* And return or use reti for interrupt handlers.  */
      if (interrupt_handler)
      if (interrupt_handler)
        {
        {
          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
          if (TARGET_V850E && ! TARGET_DISABLE_CALLT)
            emit_insn (gen_callt_return_interrupt ());
            emit_insn (gen_callt_return_interrupt ());
          else
          else
            emit_jump_insn (gen_return_interrupt ());
            emit_jump_insn (gen_return_interrupt ());
         }
         }
      else if (actual_fsize)
      else if (actual_fsize)
        emit_jump_insn (gen_return_internal ());
        emit_jump_insn (gen_return_internal ());
      else
      else
        emit_jump_insn (gen_return ());
        emit_jump_insn (gen_return ());
    }
    }
 
 
  v850_interrupt_cache_p = FALSE;
  v850_interrupt_cache_p = FALSE;
  v850_interrupt_p = FALSE;
  v850_interrupt_p = FALSE;
}
}
 
 


/* Update the condition code from the insn.  */
/* Update the condition code from the insn.  */
 
 
void
void
notice_update_cc (rtx body, rtx insn)
notice_update_cc (rtx body, rtx insn)
{
{
  switch (get_attr_cc (insn))
  switch (get_attr_cc (insn))
    {
    {
    case CC_NONE:
    case CC_NONE:
      /* Insn does not affect CC at all.  */
      /* Insn does not affect CC at all.  */
      break;
      break;
 
 
    case CC_NONE_0HIT:
    case CC_NONE_0HIT:
      /* Insn does not change CC, but the 0'th operand has been changed.  */
      /* Insn does not change CC, but the 0'th operand has been changed.  */
      if (cc_status.value1 != 0
      if (cc_status.value1 != 0
          && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
          && reg_overlap_mentioned_p (recog_data.operand[0], cc_status.value1))
        cc_status.value1 = 0;
        cc_status.value1 = 0;
      break;
      break;
 
 
    case CC_SET_ZN:
    case CC_SET_ZN:
      /* Insn sets the Z,N flags of CC to recog_data.operand[0].
      /* Insn sets the Z,N flags of CC to recog_data.operand[0].
         V,C is in an unusable state.  */
         V,C is in an unusable state.  */
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
      cc_status.flags |= CC_OVERFLOW_UNUSABLE | CC_NO_CARRY;
      cc_status.value1 = recog_data.operand[0];
      cc_status.value1 = recog_data.operand[0];
      break;
      break;
 
 
    case CC_SET_ZNV:
    case CC_SET_ZNV:
      /* Insn sets the Z,N,V flags of CC to recog_data.operand[0].
      /* Insn sets the Z,N,V flags of CC to recog_data.operand[0].
         C is in an unusable state.  */
         C is in an unusable state.  */
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      cc_status.flags |= CC_NO_CARRY;
      cc_status.flags |= CC_NO_CARRY;
      cc_status.value1 = recog_data.operand[0];
      cc_status.value1 = recog_data.operand[0];
      break;
      break;
 
 
    case CC_COMPARE:
    case CC_COMPARE:
      /* The insn is a compare instruction.  */
      /* The insn is a compare instruction.  */
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      cc_status.value1 = SET_SRC (body);
      cc_status.value1 = SET_SRC (body);
      break;
      break;
 
 
    case CC_CLOBBER:
    case CC_CLOBBER:
      /* Insn doesn't leave CC in a usable state.  */
      /* Insn doesn't leave CC in a usable state.  */
      CC_STATUS_INIT;
      CC_STATUS_INIT;
      break;
      break;
    }
    }
}
}


/* Retrieve the data area that has been chosen for the given decl.  */
/* Retrieve the data area that has been chosen for the given decl.  */
 
 
v850_data_area
v850_data_area
v850_get_data_area (tree decl)
v850_get_data_area (tree decl)
{
{
  if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
  if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
    return DATA_AREA_SDA;
    return DATA_AREA_SDA;
 
 
  if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
  if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
    return DATA_AREA_TDA;
    return DATA_AREA_TDA;
 
 
  if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
  if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
    return DATA_AREA_ZDA;
    return DATA_AREA_ZDA;
 
 
  return DATA_AREA_NORMAL;
  return DATA_AREA_NORMAL;
}
}
 
 
/* Store the indicated data area in the decl's attributes.  */
/* Store the indicated data area in the decl's attributes.  */
 
 
static void
static void
v850_set_data_area (tree decl, v850_data_area data_area)
v850_set_data_area (tree decl, v850_data_area data_area)
{
{
  tree name;
  tree name;
 
 
  switch (data_area)
  switch (data_area)
    {
    {
    case DATA_AREA_SDA: name = get_identifier ("sda"); break;
    case DATA_AREA_SDA: name = get_identifier ("sda"); break;
    case DATA_AREA_TDA: name = get_identifier ("tda"); break;
    case DATA_AREA_TDA: name = get_identifier ("tda"); break;
    case DATA_AREA_ZDA: name = get_identifier ("zda"); break;
    case DATA_AREA_ZDA: name = get_identifier ("zda"); break;
    default:
    default:
      return;
      return;
    }
    }
 
 
  DECL_ATTRIBUTES (decl) = tree_cons
  DECL_ATTRIBUTES (decl) = tree_cons
    (name, NULL, DECL_ATTRIBUTES (decl));
    (name, NULL, DECL_ATTRIBUTES (decl));
}
}


const struct attribute_spec v850_attribute_table[] =
const struct attribute_spec v850_attribute_table[] =
{
{
  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
  { "interrupt_handler", 0, 0, true,  false, false, v850_handle_interrupt_attribute },
  { "interrupt_handler", 0, 0, true,  false, false, v850_handle_interrupt_attribute },
  { "interrupt",         0, 0, true,  false, false, v850_handle_interrupt_attribute },
  { "interrupt",         0, 0, true,  false, false, v850_handle_interrupt_attribute },
  { "sda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
  { "sda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
  { "tda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
  { "tda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
  { "zda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
  { "zda",               0, 0, true,  false, false, v850_handle_data_area_attribute },
  { NULL,                0, 0, false, false, false, NULL }
  { NULL,                0, 0, false, false, false, NULL }
};
};
 
 
/* Handle an "interrupt" attribute; arguments as in
/* Handle an "interrupt" attribute; arguments as in
   struct attribute_spec.handler.  */
   struct attribute_spec.handler.  */
static tree
static tree
v850_handle_interrupt_attribute (tree * node,
v850_handle_interrupt_attribute (tree * node,
                                 tree name,
                                 tree name,
                                 tree args ATTRIBUTE_UNUSED,
                                 tree args ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED,
                                 bool * no_add_attrs)
                                 bool * no_add_attrs)
{
{
  if (TREE_CODE (*node) != FUNCTION_DECL)
  if (TREE_CODE (*node) != FUNCTION_DECL)
    {
    {
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
               IDENTIFIER_POINTER (name));
      *no_add_attrs = true;
      *no_add_attrs = true;
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 
/* Handle a "sda", "tda" or "zda" attribute; arguments as in
/* Handle a "sda", "tda" or "zda" attribute; arguments as in
   struct attribute_spec.handler.  */
   struct attribute_spec.handler.  */
static tree
static tree
v850_handle_data_area_attribute (tree* node,
v850_handle_data_area_attribute (tree* node,
                                 tree name,
                                 tree name,
                                 tree args ATTRIBUTE_UNUSED,
                                 tree args ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED,
                                 int flags ATTRIBUTE_UNUSED,
                                 bool * no_add_attrs)
                                 bool * no_add_attrs)
{
{
  v850_data_area data_area;
  v850_data_area data_area;
  v850_data_area area;
  v850_data_area area;
  tree decl = *node;
  tree decl = *node;
 
 
  /* Implement data area attribute.  */
  /* Implement data area attribute.  */
  if (is_attribute_p ("sda", name))
  if (is_attribute_p ("sda", name))
    data_area = DATA_AREA_SDA;
    data_area = DATA_AREA_SDA;
  else if (is_attribute_p ("tda", name))
  else if (is_attribute_p ("tda", name))
    data_area = DATA_AREA_TDA;
    data_area = DATA_AREA_TDA;
  else if (is_attribute_p ("zda", name))
  else if (is_attribute_p ("zda", name))
    data_area = DATA_AREA_ZDA;
    data_area = DATA_AREA_ZDA;
  else
  else
    gcc_unreachable ();
    gcc_unreachable ();
 
 
  switch (TREE_CODE (decl))
  switch (TREE_CODE (decl))
    {
    {
    case VAR_DECL:
    case VAR_DECL:
      if (current_function_decl != NULL_TREE)
      if (current_function_decl != NULL_TREE)
        {
        {
          error ("%Jdata area attributes cannot be specified for "
          error ("%Jdata area attributes cannot be specified for "
                 "local variables", decl);
                 "local variables", decl);
          *no_add_attrs = true;
          *no_add_attrs = true;
        }
        }
 
 
      /* Drop through.  */
      /* Drop through.  */
 
 
    case FUNCTION_DECL:
    case FUNCTION_DECL:
      area = v850_get_data_area (decl);
      area = v850_get_data_area (decl);
      if (area != DATA_AREA_NORMAL && data_area != area)
      if (area != DATA_AREA_NORMAL && data_area != area)
        {
        {
          error ("data area of %q+D conflicts with previous declaration",
          error ("data area of %q+D conflicts with previous declaration",
                 decl);
                 decl);
          *no_add_attrs = true;
          *no_add_attrs = true;
        }
        }
      break;
      break;
 
 
    default:
    default:
      break;
      break;
    }
    }
 
 
  return NULL_TREE;
  return NULL_TREE;
}
}
 
 


/* Return nonzero if FUNC is an interrupt function as specified
/* Return nonzero if FUNC is an interrupt function as specified
   by the "interrupt" attribute.  */
   by the "interrupt" attribute.  */
 
 
int
int
v850_interrupt_function_p (tree func)
v850_interrupt_function_p (tree func)
{
{
  tree a;
  tree a;
  int ret = 0;
  int ret = 0;
 
 
  if (v850_interrupt_cache_p)
  if (v850_interrupt_cache_p)
    return v850_interrupt_p;
    return v850_interrupt_p;
 
 
  if (TREE_CODE (func) != FUNCTION_DECL)
  if (TREE_CODE (func) != FUNCTION_DECL)
    return 0;
    return 0;
 
 
  a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
  a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
  if (a != NULL_TREE)
  if (a != NULL_TREE)
    ret = 1;
    ret = 1;
 
 
  else
  else
    {
    {
      a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
      a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
      ret = a != NULL_TREE;
      ret = a != NULL_TREE;
    }
    }
 
 
  /* Its not safe to trust global variables until after function inlining has
  /* Its not safe to trust global variables until after function inlining has
     been done.  */
     been done.  */
  if (reload_completed | reload_in_progress)
  if (reload_completed | reload_in_progress)
    v850_interrupt_p = ret;
    v850_interrupt_p = ret;
 
 
  return ret;
  return ret;
}
}
 
 


static void
static void
v850_encode_data_area (tree decl, rtx symbol)
v850_encode_data_area (tree decl, rtx symbol)
{
{
  int flags;
  int flags;
 
 
  /* Map explicit sections into the appropriate attribute */
  /* Map explicit sections into the appropriate attribute */
  if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
  if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
    {
    {
      if (DECL_SECTION_NAME (decl))
      if (DECL_SECTION_NAME (decl))
        {
        {
          const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
          const char *name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
 
 
          if (streq (name, ".zdata") || streq (name, ".zbss"))
          if (streq (name, ".zdata") || streq (name, ".zbss"))
            v850_set_data_area (decl, DATA_AREA_ZDA);
            v850_set_data_area (decl, DATA_AREA_ZDA);
 
 
          else if (streq (name, ".sdata") || streq (name, ".sbss"))
          else if (streq (name, ".sdata") || streq (name, ".sbss"))
            v850_set_data_area (decl, DATA_AREA_SDA);
            v850_set_data_area (decl, DATA_AREA_SDA);
 
 
          else if (streq (name, ".tdata"))
          else if (streq (name, ".tdata"))
            v850_set_data_area (decl, DATA_AREA_TDA);
            v850_set_data_area (decl, DATA_AREA_TDA);
        }
        }
 
 
      /* If no attribute, support -m{zda,sda,tda}=n */
      /* If no attribute, support -m{zda,sda,tda}=n */
      else
      else
        {
        {
          int size = int_size_in_bytes (TREE_TYPE (decl));
          int size = int_size_in_bytes (TREE_TYPE (decl));
          if (size <= 0)
          if (size <= 0)
            ;
            ;
 
 
          else if (size <= small_memory [(int) SMALL_MEMORY_TDA].max)
          else if (size <= small_memory [(int) SMALL_MEMORY_TDA].max)
            v850_set_data_area (decl, DATA_AREA_TDA);
            v850_set_data_area (decl, DATA_AREA_TDA);
 
 
          else if (size <= small_memory [(int) SMALL_MEMORY_SDA].max)
          else if (size <= small_memory [(int) SMALL_MEMORY_SDA].max)
            v850_set_data_area (decl, DATA_AREA_SDA);
            v850_set_data_area (decl, DATA_AREA_SDA);
 
 
          else if (size <= small_memory [(int) SMALL_MEMORY_ZDA].max)
          else if (size <= small_memory [(int) SMALL_MEMORY_ZDA].max)
            v850_set_data_area (decl, DATA_AREA_ZDA);
            v850_set_data_area (decl, DATA_AREA_ZDA);
        }
        }
 
 
      if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
      if (v850_get_data_area (decl) == DATA_AREA_NORMAL)
        return;
        return;
    }
    }
 
 
  flags = SYMBOL_REF_FLAGS (symbol);
  flags = SYMBOL_REF_FLAGS (symbol);
  switch (v850_get_data_area (decl))
  switch (v850_get_data_area (decl))
    {
    {
    case DATA_AREA_ZDA: flags |= SYMBOL_FLAG_ZDA; break;
    case DATA_AREA_ZDA: flags |= SYMBOL_FLAG_ZDA; break;
    case DATA_AREA_TDA: flags |= SYMBOL_FLAG_TDA; break;
    case DATA_AREA_TDA: flags |= SYMBOL_FLAG_TDA; break;
    case DATA_AREA_SDA: flags |= SYMBOL_FLAG_SDA; break;
    case DATA_AREA_SDA: flags |= SYMBOL_FLAG_SDA; break;
    default: gcc_unreachable ();
    default: gcc_unreachable ();
    }
    }
  SYMBOL_REF_FLAGS (symbol) = flags;
  SYMBOL_REF_FLAGS (symbol) = flags;
}
}
 
 
static void
static void
v850_encode_section_info (tree decl, rtx rtl, int first)
v850_encode_section_info (tree decl, rtx rtl, int first)
{
{
  default_encode_section_info (decl, rtl, first);
  default_encode_section_info (decl, rtl, first);
 
 
  if (TREE_CODE (decl) == VAR_DECL
  if (TREE_CODE (decl) == VAR_DECL
      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
    v850_encode_data_area (decl, XEXP (rtl, 0));
    v850_encode_data_area (decl, XEXP (rtl, 0));
}
}
 
 
/* Construct a JR instruction to a routine that will perform the equivalent of
/* Construct a JR instruction to a routine that will perform the equivalent of
   the RTL passed in as an argument.  This RTL is a function epilogue that
   the RTL passed in as an argument.  This RTL is a function epilogue that
   pops registers off the stack and possibly releases some extra stack space
   pops registers off the stack and possibly releases some extra stack space
   as well.  The code has already verified that the RTL matches these
   as well.  The code has already verified that the RTL matches these
   requirements.  */
   requirements.  */
char *
char *
construct_restore_jr (rtx op)
construct_restore_jr (rtx op)
{
{
  int count = XVECLEN (op, 0);
  int count = XVECLEN (op, 0);
  int stack_bytes;
  int stack_bytes;
  unsigned long int mask;
  unsigned long int mask;
  unsigned long int first;
  unsigned long int first;
  unsigned long int last;
  unsigned long int last;
  int i;
  int i;
  static char buff [100]; /* XXX */
  static char buff [100]; /* XXX */
 
 
  if (count <= 2)
  if (count <= 2)
    {
    {
      error ("bogus JR construction: %d", count);
      error ("bogus JR construction: %d", count);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Work out how many bytes to pop off the stack before retrieving
  /* Work out how many bytes to pop off the stack before retrieving
     registers.  */
     registers.  */
  gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
  gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT);
 
 
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
 
 
  /* Each pop will remove 4 bytes from the stack....  */
  /* Each pop will remove 4 bytes from the stack....  */
  stack_bytes -= (count - 2) * 4;
  stack_bytes -= (count - 2) * 4;
 
 
  /* Make sure that the amount we are popping either 0 or 16 bytes.  */
  /* Make sure that the amount we are popping either 0 or 16 bytes.  */
  if (stack_bytes != 0 && stack_bytes != 16)
  if (stack_bytes != 0 && stack_bytes != 16)
    {
    {
      error ("bad amount of stack space removal: %d", stack_bytes);
      error ("bad amount of stack space removal: %d", stack_bytes);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Now compute the bit mask of registers to push.  */
  /* Now compute the bit mask of registers to push.  */
  mask = 0;
  mask = 0;
  for (i = 2; i < count; i++)
  for (i = 2; i < count; i++)
    {
    {
      rtx vector_element = XVECEXP (op, 0, i);
      rtx vector_element = XVECEXP (op, 0, i);
 
 
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
      gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
      gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
      gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
                                               SImode));
                                               SImode));
 
 
      mask |= 1 << REGNO (SET_DEST (vector_element));
      mask |= 1 << REGNO (SET_DEST (vector_element));
    }
    }
 
 
  /* Scan for the first register to pop.  */
  /* Scan for the first register to pop.  */
  for (first = 0; first < 32; first++)
  for (first = 0; first < 32; first++)
    {
    {
      if (mask & (1 << first))
      if (mask & (1 << first))
        break;
        break;
    }
    }
 
 
  gcc_assert (first < 32);
  gcc_assert (first < 32);
 
 
  /* Discover the last register to pop.  */
  /* Discover the last register to pop.  */
  if (mask & (1 << LINK_POINTER_REGNUM))
  if (mask & (1 << LINK_POINTER_REGNUM))
    {
    {
      gcc_assert (stack_bytes == 16);
      gcc_assert (stack_bytes == 16);
 
 
      last = LINK_POINTER_REGNUM;
      last = LINK_POINTER_REGNUM;
    }
    }
  else
  else
    {
    {
      gcc_assert (!stack_bytes);
      gcc_assert (!stack_bytes);
      gcc_assert (mask & (1 << 29));
      gcc_assert (mask & (1 << 29));
 
 
      last = 29;
      last = 29;
    }
    }
 
 
  /* Note, it is possible to have gaps in the register mask.
  /* Note, it is possible to have gaps in the register mask.
     We ignore this here, and generate a JR anyway.  We will
     We ignore this here, and generate a JR anyway.  We will
     be popping more registers than is strictly necessary, but
     be popping more registers than is strictly necessary, but
     it does save code space.  */
     it does save code space.  */
 
 
  if (TARGET_LONG_CALLS)
  if (TARGET_LONG_CALLS)
    {
    {
      char name[40];
      char name[40];
 
 
      if (first == last)
      if (first == last)
        sprintf (name, "__return_%s", reg_names [first]);
        sprintf (name, "__return_%s", reg_names [first]);
      else
      else
        sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]);
        sprintf (name, "__return_%s_%s", reg_names [first], reg_names [last]);
 
 
      sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6",
      sprintf (buff, "movhi hi(%s), r0, r6\n\tmovea lo(%s), r6, r6\n\tjmp r6",
               name, name);
               name, name);
    }
    }
  else
  else
    {
    {
      if (first == last)
      if (first == last)
        sprintf (buff, "jr __return_%s", reg_names [first]);
        sprintf (buff, "jr __return_%s", reg_names [first]);
      else
      else
        sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
        sprintf (buff, "jr __return_%s_%s", reg_names [first], reg_names [last]);
    }
    }
 
 
  return buff;
  return buff;
}
}
 
 
 
 
/* Construct a JARL instruction to a routine that will perform the equivalent
/* Construct a JARL instruction to a routine that will perform the equivalent
   of the RTL passed as a parameter.  This RTL is a function prologue that
   of the RTL passed as a parameter.  This RTL is a function prologue that
   saves some of the registers r20 - r31 onto the stack, and possibly acquires
   saves some of the registers r20 - r31 onto the stack, and possibly acquires
   some stack space as well.  The code has already verified that the RTL
   some stack space as well.  The code has already verified that the RTL
   matches these requirements.  */
   matches these requirements.  */
char *
char *
construct_save_jarl (rtx op)
construct_save_jarl (rtx op)
{
{
  int count = XVECLEN (op, 0);
  int count = XVECLEN (op, 0);
  int stack_bytes;
  int stack_bytes;
  unsigned long int mask;
  unsigned long int mask;
  unsigned long int first;
  unsigned long int first;
  unsigned long int last;
  unsigned long int last;
  int i;
  int i;
  static char buff [100]; /* XXX */
  static char buff [100]; /* XXX */
 
 
  if (count <= 2)
  if (count <= 2)
    {
    {
      error ("bogus JARL construction: %d\n", count);
      error ("bogus JARL construction: %d\n", count);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Paranoia.  */
  /* Paranoia.  */
  gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
  gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) == REG);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) == REG);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT);
 
 
  /* Work out how many bytes to push onto the stack after storing the
  /* Work out how many bytes to push onto the stack after storing the
     registers.  */
     registers.  */
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
 
 
  /* Each push will put 4 bytes from the stack....  */
  /* Each push will put 4 bytes from the stack....  */
  stack_bytes += (count - (TARGET_LONG_CALLS ? 3 : 2)) * 4;
  stack_bytes += (count - (TARGET_LONG_CALLS ? 3 : 2)) * 4;
 
 
  /* Make sure that the amount we are popping either 0 or 16 bytes.  */
  /* Make sure that the amount we are popping either 0 or 16 bytes.  */
  if (stack_bytes != 0 && stack_bytes != -16)
  if (stack_bytes != 0 && stack_bytes != -16)
    {
    {
      error ("bad amount of stack space removal: %d", stack_bytes);
      error ("bad amount of stack space removal: %d", stack_bytes);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Now compute the bit mask of registers to push.  */
  /* Now compute the bit mask of registers to push.  */
  mask = 0;
  mask = 0;
  for (i = 1; i < count - (TARGET_LONG_CALLS ? 2 : 1); i++)
  for (i = 1; i < count - (TARGET_LONG_CALLS ? 2 : 1); i++)
    {
    {
      rtx vector_element = XVECEXP (op, 0, i);
      rtx vector_element = XVECEXP (op, 0, i);
 
 
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
      gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
      gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
      gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
                                               SImode));
                                               SImode));
 
 
      mask |= 1 << REGNO (SET_SRC (vector_element));
      mask |= 1 << REGNO (SET_SRC (vector_element));
    }
    }
 
 
  /* Scan for the first register to push.  */
  /* Scan for the first register to push.  */
  for (first = 0; first < 32; first++)
  for (first = 0; first < 32; first++)
    {
    {
      if (mask & (1 << first))
      if (mask & (1 << first))
        break;
        break;
    }
    }
 
 
  gcc_assert (first < 32);
  gcc_assert (first < 32);
 
 
  /* Discover the last register to push.  */
  /* Discover the last register to push.  */
  if (mask & (1 << LINK_POINTER_REGNUM))
  if (mask & (1 << LINK_POINTER_REGNUM))
    {
    {
      gcc_assert (stack_bytes == -16);
      gcc_assert (stack_bytes == -16);
 
 
      last = LINK_POINTER_REGNUM;
      last = LINK_POINTER_REGNUM;
    }
    }
  else
  else
    {
    {
      gcc_assert (!stack_bytes);
      gcc_assert (!stack_bytes);
      gcc_assert (mask & (1 << 29));
      gcc_assert (mask & (1 << 29));
 
 
      last = 29;
      last = 29;
    }
    }
 
 
  /* Note, it is possible to have gaps in the register mask.
  /* Note, it is possible to have gaps in the register mask.
     We ignore this here, and generate a JARL anyway.  We will
     We ignore this here, and generate a JARL anyway.  We will
     be pushing more registers than is strictly necessary, but
     be pushing more registers than is strictly necessary, but
     it does save code space.  */
     it does save code space.  */
 
 
  if (TARGET_LONG_CALLS)
  if (TARGET_LONG_CALLS)
    {
    {
      char name[40];
      char name[40];
 
 
      if (first == last)
      if (first == last)
        sprintf (name, "__save_%s", reg_names [first]);
        sprintf (name, "__save_%s", reg_names [first]);
      else
      else
        sprintf (name, "__save_%s_%s", reg_names [first], reg_names [last]);
        sprintf (name, "__save_%s_%s", reg_names [first], reg_names [last]);
 
 
      sprintf (buff, "movhi hi(%s), r0, r11\n\tmovea lo(%s), r11, r11\n\tjarl .+4, r10\n\tadd 4, r10\n\tjmp r11",
      sprintf (buff, "movhi hi(%s), r0, r11\n\tmovea lo(%s), r11, r11\n\tjarl .+4, r10\n\tadd 4, r10\n\tjmp r11",
               name, name);
               name, name);
    }
    }
  else
  else
    {
    {
      if (first == last)
      if (first == last)
        sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
        sprintf (buff, "jarl __save_%s, r10", reg_names [first]);
      else
      else
        sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
        sprintf (buff, "jarl __save_%s_%s, r10", reg_names [first],
                 reg_names [last]);
                 reg_names [last]);
    }
    }
 
 
  return buff;
  return buff;
}
}
 
 
extern tree last_assemble_variable_decl;
extern tree last_assemble_variable_decl;
extern int size_directive_output;
extern int size_directive_output;
 
 
/* A version of asm_output_aligned_bss() that copes with the special
/* A version of asm_output_aligned_bss() that copes with the special
   data areas of the v850.  */
   data areas of the v850.  */
void
void
v850_output_aligned_bss (FILE * file,
v850_output_aligned_bss (FILE * file,
                         tree decl,
                         tree decl,
                         const char * name,
                         const char * name,
                         unsigned HOST_WIDE_INT size,
                         unsigned HOST_WIDE_INT size,
                         int align)
                         int align)
{
{
  switch (v850_get_data_area (decl))
  switch (v850_get_data_area (decl))
    {
    {
    case DATA_AREA_ZDA:
    case DATA_AREA_ZDA:
      switch_to_section (zbss_section);
      switch_to_section (zbss_section);
      break;
      break;
 
 
    case DATA_AREA_SDA:
    case DATA_AREA_SDA:
      switch_to_section (sbss_section);
      switch_to_section (sbss_section);
      break;
      break;
 
 
    case DATA_AREA_TDA:
    case DATA_AREA_TDA:
      switch_to_section (tdata_section);
      switch_to_section (tdata_section);
 
 
    default:
    default:
      switch_to_section (bss_section);
      switch_to_section (bss_section);
      break;
      break;
    }
    }
 
 
  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
  ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
#ifdef ASM_DECLARE_OBJECT_NAME
#ifdef ASM_DECLARE_OBJECT_NAME
  last_assemble_variable_decl = decl;
  last_assemble_variable_decl = decl;
  ASM_DECLARE_OBJECT_NAME (file, name, decl);
  ASM_DECLARE_OBJECT_NAME (file, name, decl);
#else
#else
  /* Standard thing is just output label for the object.  */
  /* Standard thing is just output label for the object.  */
  ASM_OUTPUT_LABEL (file, name);
  ASM_OUTPUT_LABEL (file, name);
#endif /* ASM_DECLARE_OBJECT_NAME */
#endif /* ASM_DECLARE_OBJECT_NAME */
  ASM_OUTPUT_SKIP (file, size ? size : 1);
  ASM_OUTPUT_SKIP (file, size ? size : 1);
}
}
 
 
/* Called via the macro ASM_OUTPUT_DECL_COMMON */
/* Called via the macro ASM_OUTPUT_DECL_COMMON */
void
void
v850_output_common (FILE * file,
v850_output_common (FILE * file,
                    tree decl,
                    tree decl,
                    const char * name,
                    const char * name,
                    int size,
                    int size,
                    int align)
                    int align)
{
{
  if (decl == NULL_TREE)
  if (decl == NULL_TREE)
    {
    {
      fprintf (file, "%s", COMMON_ASM_OP);
      fprintf (file, "%s", COMMON_ASM_OP);
    }
    }
  else
  else
    {
    {
      switch (v850_get_data_area (decl))
      switch (v850_get_data_area (decl))
        {
        {
        case DATA_AREA_ZDA:
        case DATA_AREA_ZDA:
          fprintf (file, "%s", ZCOMMON_ASM_OP);
          fprintf (file, "%s", ZCOMMON_ASM_OP);
          break;
          break;
 
 
        case DATA_AREA_SDA:
        case DATA_AREA_SDA:
          fprintf (file, "%s", SCOMMON_ASM_OP);
          fprintf (file, "%s", SCOMMON_ASM_OP);
          break;
          break;
 
 
        case DATA_AREA_TDA:
        case DATA_AREA_TDA:
          fprintf (file, "%s", TCOMMON_ASM_OP);
          fprintf (file, "%s", TCOMMON_ASM_OP);
          break;
          break;
 
 
        default:
        default:
          fprintf (file, "%s", COMMON_ASM_OP);
          fprintf (file, "%s", COMMON_ASM_OP);
          break;
          break;
        }
        }
    }
    }
 
 
  assemble_name (file, name);
  assemble_name (file, name);
  fprintf (file, ",%u,%u\n", size, align / BITS_PER_UNIT);
  fprintf (file, ",%u,%u\n", size, align / BITS_PER_UNIT);
}
}
 
 
/* Called via the macro ASM_OUTPUT_DECL_LOCAL */
/* Called via the macro ASM_OUTPUT_DECL_LOCAL */
void
void
v850_output_local (FILE * file,
v850_output_local (FILE * file,
                   tree decl,
                   tree decl,
                   const char * name,
                   const char * name,
                   int size,
                   int size,
                   int align)
                   int align)
{
{
  fprintf (file, "%s", LOCAL_ASM_OP);
  fprintf (file, "%s", LOCAL_ASM_OP);
  assemble_name (file, name);
  assemble_name (file, name);
  fprintf (file, "\n");
  fprintf (file, "\n");
 
 
  ASM_OUTPUT_ALIGNED_DECL_COMMON (file, decl, name, size, align);
  ASM_OUTPUT_ALIGNED_DECL_COMMON (file, decl, name, size, align);
}
}
 
 
/* Add data area to the given declaration if a ghs data area pragma is
/* Add data area to the given declaration if a ghs data area pragma is
   currently in effect (#pragma ghs startXXX/endXXX).  */
   currently in effect (#pragma ghs startXXX/endXXX).  */
static void
static void
v850_insert_attributes (tree decl, tree * attr_ptr ATTRIBUTE_UNUSED )
v850_insert_attributes (tree decl, tree * attr_ptr ATTRIBUTE_UNUSED )
{
{
  if (data_area_stack
  if (data_area_stack
      && data_area_stack->data_area
      && data_area_stack->data_area
      && current_function_decl == NULL_TREE
      && current_function_decl == NULL_TREE
      && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL)
      && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL)
      && v850_get_data_area (decl) == DATA_AREA_NORMAL)
      && v850_get_data_area (decl) == DATA_AREA_NORMAL)
    v850_set_data_area (decl, data_area_stack->data_area);
    v850_set_data_area (decl, data_area_stack->data_area);
 
 
  /* Initialize the default names of the v850 specific sections,
  /* Initialize the default names of the v850 specific sections,
     if this has not been done before.  */
     if this has not been done before.  */
 
 
  if (GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA] == NULL)
  if (GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA] == NULL)
    {
    {
      GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA]
      GHS_default_section_names [(int) GHS_SECTION_KIND_SDATA]
        = build_string (sizeof (".sdata")-1, ".sdata");
        = build_string (sizeof (".sdata")-1, ".sdata");
 
 
      GHS_default_section_names [(int) GHS_SECTION_KIND_ROSDATA]
      GHS_default_section_names [(int) GHS_SECTION_KIND_ROSDATA]
        = build_string (sizeof (".rosdata")-1, ".rosdata");
        = build_string (sizeof (".rosdata")-1, ".rosdata");
 
 
      GHS_default_section_names [(int) GHS_SECTION_KIND_TDATA]
      GHS_default_section_names [(int) GHS_SECTION_KIND_TDATA]
        = build_string (sizeof (".tdata")-1, ".tdata");
        = build_string (sizeof (".tdata")-1, ".tdata");
 
 
      GHS_default_section_names [(int) GHS_SECTION_KIND_ZDATA]
      GHS_default_section_names [(int) GHS_SECTION_KIND_ZDATA]
        = build_string (sizeof (".zdata")-1, ".zdata");
        = build_string (sizeof (".zdata")-1, ".zdata");
 
 
      GHS_default_section_names [(int) GHS_SECTION_KIND_ROZDATA]
      GHS_default_section_names [(int) GHS_SECTION_KIND_ROZDATA]
        = build_string (sizeof (".rozdata")-1, ".rozdata");
        = build_string (sizeof (".rozdata")-1, ".rozdata");
    }
    }
 
 
  if (current_function_decl == NULL_TREE
  if (current_function_decl == NULL_TREE
      && (TREE_CODE (decl) == VAR_DECL
      && (TREE_CODE (decl) == VAR_DECL
          || TREE_CODE (decl) == CONST_DECL
          || TREE_CODE (decl) == CONST_DECL
          || TREE_CODE (decl) == FUNCTION_DECL)
          || TREE_CODE (decl) == FUNCTION_DECL)
      && (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl))
      && (!DECL_EXTERNAL (decl) || DECL_INITIAL (decl))
      && !DECL_SECTION_NAME (decl))
      && !DECL_SECTION_NAME (decl))
    {
    {
      enum GHS_section_kind kind = GHS_SECTION_KIND_DEFAULT;
      enum GHS_section_kind kind = GHS_SECTION_KIND_DEFAULT;
      tree chosen_section;
      tree chosen_section;
 
 
      if (TREE_CODE (decl) == FUNCTION_DECL)
      if (TREE_CODE (decl) == FUNCTION_DECL)
        kind = GHS_SECTION_KIND_TEXT;
        kind = GHS_SECTION_KIND_TEXT;
      else
      else
        {
        {
          /* First choose a section kind based on the data area of the decl.  */
          /* First choose a section kind based on the data area of the decl.  */
          switch (v850_get_data_area (decl))
          switch (v850_get_data_area (decl))
            {
            {
            default:
            default:
              gcc_unreachable ();
              gcc_unreachable ();
 
 
            case DATA_AREA_SDA:
            case DATA_AREA_SDA:
              kind = ((TREE_READONLY (decl))
              kind = ((TREE_READONLY (decl))
                      ? GHS_SECTION_KIND_ROSDATA
                      ? GHS_SECTION_KIND_ROSDATA
                      : GHS_SECTION_KIND_SDATA);
                      : GHS_SECTION_KIND_SDATA);
              break;
              break;
 
 
            case DATA_AREA_TDA:
            case DATA_AREA_TDA:
              kind = GHS_SECTION_KIND_TDATA;
              kind = GHS_SECTION_KIND_TDATA;
              break;
              break;
 
 
            case DATA_AREA_ZDA:
            case DATA_AREA_ZDA:
              kind = ((TREE_READONLY (decl))
              kind = ((TREE_READONLY (decl))
                      ? GHS_SECTION_KIND_ROZDATA
                      ? GHS_SECTION_KIND_ROZDATA
                      : GHS_SECTION_KIND_ZDATA);
                      : GHS_SECTION_KIND_ZDATA);
              break;
              break;
 
 
            case DATA_AREA_NORMAL:               /* default data area */
            case DATA_AREA_NORMAL:               /* default data area */
              if (TREE_READONLY (decl))
              if (TREE_READONLY (decl))
                kind = GHS_SECTION_KIND_RODATA;
                kind = GHS_SECTION_KIND_RODATA;
              else if (DECL_INITIAL (decl))
              else if (DECL_INITIAL (decl))
                kind = GHS_SECTION_KIND_DATA;
                kind = GHS_SECTION_KIND_DATA;
              else
              else
                kind = GHS_SECTION_KIND_BSS;
                kind = GHS_SECTION_KIND_BSS;
            }
            }
        }
        }
 
 
      /* Now, if the section kind has been explicitly renamed,
      /* Now, if the section kind has been explicitly renamed,
         then attach a section attribute.  */
         then attach a section attribute.  */
      chosen_section = GHS_current_section_names [(int) kind];
      chosen_section = GHS_current_section_names [(int) kind];
 
 
      /* Otherwise, if this kind of section needs an explicit section
      /* Otherwise, if this kind of section needs an explicit section
         attribute, then also attach one.  */
         attribute, then also attach one.  */
      if (chosen_section == NULL)
      if (chosen_section == NULL)
        chosen_section = GHS_default_section_names [(int) kind];
        chosen_section = GHS_default_section_names [(int) kind];
 
 
      if (chosen_section)
      if (chosen_section)
        {
        {
          /* Only set the section name if specified by a pragma, because
          /* Only set the section name if specified by a pragma, because
             otherwise it will force those variables to get allocated storage
             otherwise it will force those variables to get allocated storage
             in this module, rather than by the linker.  */
             in this module, rather than by the linker.  */
          DECL_SECTION_NAME (decl) = chosen_section;
          DECL_SECTION_NAME (decl) = chosen_section;
        }
        }
    }
    }
}
}
 
 
/* Construct a DISPOSE instruction that is the equivalent of
/* Construct a DISPOSE instruction that is the equivalent of
   the given RTX.  We have already verified that this should
   the given RTX.  We have already verified that this should
   be possible.  */
   be possible.  */
 
 
char *
char *
construct_dispose_instruction (rtx op)
construct_dispose_instruction (rtx op)
{
{
  int                count = XVECLEN (op, 0);
  int                count = XVECLEN (op, 0);
  int                stack_bytes;
  int                stack_bytes;
  unsigned long int  mask;
  unsigned long int  mask;
  int                i;
  int                i;
  static char        buff[ 100 ]; /* XXX */
  static char        buff[ 100 ]; /* XXX */
  int                use_callt = 0;
  int                use_callt = 0;
 
 
  if (count <= 2)
  if (count <= 2)
    {
    {
      error ("bogus DISPOSE construction: %d", count);
      error ("bogus DISPOSE construction: %d", count);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Work out how many bytes to pop off the
  /* Work out how many bytes to pop off the
     stack before retrieving registers.  */
     stack before retrieving registers.  */
  gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
  gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) == PLUS);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) == CONST_INT);
 
 
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
 
 
  /* Each pop will remove 4 bytes from the stack....  */
  /* Each pop will remove 4 bytes from the stack....  */
  stack_bytes -= (count - 2) * 4;
  stack_bytes -= (count - 2) * 4;
 
 
  /* Make sure that the amount we are popping
  /* Make sure that the amount we are popping
     will fit into the DISPOSE instruction.  */
     will fit into the DISPOSE instruction.  */
  if (stack_bytes > 128)
  if (stack_bytes > 128)
    {
    {
      error ("too much stack space to dispose of: %d", stack_bytes);
      error ("too much stack space to dispose of: %d", stack_bytes);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Now compute the bit mask of registers to push.  */
  /* Now compute the bit mask of registers to push.  */
  mask = 0;
  mask = 0;
 
 
  for (i = 2; i < count; i++)
  for (i = 2; i < count; i++)
    {
    {
      rtx vector_element = XVECEXP (op, 0, i);
      rtx vector_element = XVECEXP (op, 0, i);
 
 
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
      gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
      gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
      gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
                                               SImode));
                                               SImode));
 
 
      if (REGNO (SET_DEST (vector_element)) == 2)
      if (REGNO (SET_DEST (vector_element)) == 2)
        use_callt = 1;
        use_callt = 1;
      else
      else
        mask |= 1 << REGNO (SET_DEST (vector_element));
        mask |= 1 << REGNO (SET_DEST (vector_element));
    }
    }
 
 
  if (! TARGET_DISABLE_CALLT
  if (! TARGET_DISABLE_CALLT
      && (use_callt || stack_bytes == 0 || stack_bytes == 16))
      && (use_callt || stack_bytes == 0 || stack_bytes == 16))
    {
    {
      if (use_callt)
      if (use_callt)
        {
        {
          sprintf (buff, "callt ctoff(__callt_return_r2_r%d)", (mask & (1 << 31)) ? 31 : 29);
          sprintf (buff, "callt ctoff(__callt_return_r2_r%d)", (mask & (1 << 31)) ? 31 : 29);
          return buff;
          return buff;
        }
        }
      else
      else
        {
        {
          for (i = 20; i < 32; i++)
          for (i = 20; i < 32; i++)
            if (mask & (1 << i))
            if (mask & (1 << i))
              break;
              break;
 
 
          if (i == 31)
          if (i == 31)
            sprintf (buff, "callt ctoff(__callt_return_r31c)");
            sprintf (buff, "callt ctoff(__callt_return_r31c)");
          else
          else
            sprintf (buff, "callt ctoff(__callt_return_r%d_r%d%s)",
            sprintf (buff, "callt ctoff(__callt_return_r%d_r%d%s)",
                     i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
                     i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
        }
        }
    }
    }
  else
  else
    {
    {
      static char        regs [100]; /* XXX */
      static char        regs [100]; /* XXX */
      int                done_one;
      int                done_one;
 
 
      /* Generate the DISPOSE instruction.  Note we could just issue the
      /* Generate the DISPOSE instruction.  Note we could just issue the
         bit mask as a number as the assembler can cope with this, but for
         bit mask as a number as the assembler can cope with this, but for
         the sake of our readers we turn it into a textual description.  */
         the sake of our readers we turn it into a textual description.  */
      regs[0] = 0;
      regs[0] = 0;
      done_one = 0;
      done_one = 0;
 
 
      for (i = 20; i < 32; i++)
      for (i = 20; i < 32; i++)
        {
        {
          if (mask & (1 << i))
          if (mask & (1 << i))
            {
            {
              int first;
              int first;
 
 
              if (done_one)
              if (done_one)
                strcat (regs, ", ");
                strcat (regs, ", ");
              else
              else
                done_one = 1;
                done_one = 1;
 
 
              first = i;
              first = i;
              strcat (regs, reg_names[ first ]);
              strcat (regs, reg_names[ first ]);
 
 
              for (i++; i < 32; i++)
              for (i++; i < 32; i++)
                if ((mask & (1 << i)) == 0)
                if ((mask & (1 << i)) == 0)
                  break;
                  break;
 
 
              if (i > first + 1)
              if (i > first + 1)
                {
                {
                  strcat (regs, " - ");
                  strcat (regs, " - ");
                  strcat (regs, reg_names[ i - 1 ] );
                  strcat (regs, reg_names[ i - 1 ] );
                }
                }
            }
            }
        }
        }
 
 
      sprintf (buff, "dispose %d {%s}, r31", stack_bytes / 4, regs);
      sprintf (buff, "dispose %d {%s}, r31", stack_bytes / 4, regs);
    }
    }
 
 
  return buff;
  return buff;
}
}
 
 
/* Construct a PREPARE instruction that is the equivalent of
/* Construct a PREPARE instruction that is the equivalent of
   the given RTL.  We have already verified that this should
   the given RTL.  We have already verified that this should
   be possible.  */
   be possible.  */
 
 
char *
char *
construct_prepare_instruction (rtx op)
construct_prepare_instruction (rtx op)
{
{
  int                count = XVECLEN (op, 0);
  int                count = XVECLEN (op, 0);
  int                stack_bytes;
  int                stack_bytes;
  unsigned long int  mask;
  unsigned long int  mask;
  int                i;
  int                i;
  static char        buff[ 100 ]; /* XXX */
  static char        buff[ 100 ]; /* XXX */
  int                use_callt = 0;
  int                use_callt = 0;
 
 
  if (count <= 1)
  if (count <= 1)
    {
    {
      error ("bogus PREPEARE construction: %d", count);
      error ("bogus PREPEARE construction: %d", count);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Work out how many bytes to push onto
  /* Work out how many bytes to push onto
     the stack after storing the registers.  */
     the stack after storing the registers.  */
  gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
  gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS);
  gcc_assert (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) == PLUS);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT);
  gcc_assert (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) == CONST_INT);
 
 
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
  stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
 
 
  /* Each push will put 4 bytes from the stack.  */
  /* Each push will put 4 bytes from the stack.  */
  stack_bytes += (count - 1) * 4;
  stack_bytes += (count - 1) * 4;
 
 
  /* Make sure that the amount we are popping
  /* Make sure that the amount we are popping
     will fit into the DISPOSE instruction.  */
     will fit into the DISPOSE instruction.  */
  if (stack_bytes < -128)
  if (stack_bytes < -128)
    {
    {
      error ("too much stack space to prepare: %d", stack_bytes);
      error ("too much stack space to prepare: %d", stack_bytes);
      return NULL;
      return NULL;
    }
    }
 
 
  /* Now compute the bit mask of registers to push.  */
  /* Now compute the bit mask of registers to push.  */
  mask = 0;
  mask = 0;
  for (i = 1; i < count; i++)
  for (i = 1; i < count; i++)
    {
    {
      rtx vector_element = XVECEXP (op, 0, i);
      rtx vector_element = XVECEXP (op, 0, i);
 
 
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (vector_element) == SET);
      gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
      gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
      gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
      gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
                                               SImode));
                                               SImode));
 
 
      if (REGNO (SET_SRC (vector_element)) == 2)
      if (REGNO (SET_SRC (vector_element)) == 2)
        use_callt = 1;
        use_callt = 1;
      else
      else
        mask |= 1 << REGNO (SET_SRC (vector_element));
        mask |= 1 << REGNO (SET_SRC (vector_element));
    }
    }
 
 
  if ((! TARGET_DISABLE_CALLT)
  if ((! TARGET_DISABLE_CALLT)
      && (use_callt || stack_bytes == 0 || stack_bytes == -16))
      && (use_callt || stack_bytes == 0 || stack_bytes == -16))
    {
    {
      if (use_callt)
      if (use_callt)
        {
        {
          sprintf (buff, "callt ctoff(__callt_save_r2_r%d)", (mask & (1 << 31)) ? 31 : 29 );
          sprintf (buff, "callt ctoff(__callt_save_r2_r%d)", (mask & (1 << 31)) ? 31 : 29 );
          return buff;
          return buff;
        }
        }
 
 
      for (i = 20; i < 32; i++)
      for (i = 20; i < 32; i++)
        if (mask & (1 << i))
        if (mask & (1 << i))
          break;
          break;
 
 
      if (i == 31)
      if (i == 31)
        sprintf (buff, "callt ctoff(__callt_save_r31c)");
        sprintf (buff, "callt ctoff(__callt_save_r31c)");
      else
      else
        sprintf (buff, "callt ctoff(__callt_save_r%d_r%d%s)",
        sprintf (buff, "callt ctoff(__callt_save_r%d_r%d%s)",
                 i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
                 i, (mask & (1 << 31)) ? 31 : 29, stack_bytes ? "c" : "");
    }
    }
  else
  else
    {
    {
      static char        regs [100]; /* XXX */
      static char        regs [100]; /* XXX */
      int                done_one;
      int                done_one;
 
 
 
 
      /* Generate the PREPARE instruction.  Note we could just issue the
      /* Generate the PREPARE instruction.  Note we could just issue the
         bit mask as a number as the assembler can cope with this, but for
         bit mask as a number as the assembler can cope with this, but for
         the sake of our readers we turn it into a textual description.  */
         the sake of our readers we turn it into a textual description.  */
      regs[0] = 0;
      regs[0] = 0;
      done_one = 0;
      done_one = 0;
 
 
      for (i = 20; i < 32; i++)
      for (i = 20; i < 32; i++)
        {
        {
          if (mask & (1 << i))
          if (mask & (1 << i))
            {
            {
              int first;
              int first;
 
 
              if (done_one)
              if (done_one)
                strcat (regs, ", ");
                strcat (regs, ", ");
              else
              else
                done_one = 1;
                done_one = 1;
 
 
              first = i;
              first = i;
              strcat (regs, reg_names[ first ]);
              strcat (regs, reg_names[ first ]);
 
 
              for (i++; i < 32; i++)
              for (i++; i < 32; i++)
                if ((mask & (1 << i)) == 0)
                if ((mask & (1 << i)) == 0)
                  break;
                  break;
 
 
              if (i > first + 1)
              if (i > first + 1)
                {
                {
                  strcat (regs, " - ");
                  strcat (regs, " - ");
                  strcat (regs, reg_names[ i - 1 ] );
                  strcat (regs, reg_names[ i - 1 ] );
                }
                }
            }
            }
        }
        }
 
 
      sprintf (buff, "prepare {%s}, %d", regs, (- stack_bytes) / 4);
      sprintf (buff, "prepare {%s}, %d", regs, (- stack_bytes) / 4);
    }
    }
 
 
  return buff;
  return buff;
}
}


/* Return an RTX indicating where the return address to the
/* Return an RTX indicating where the return address to the
   calling function can be found.  */
   calling function can be found.  */
 
 
rtx
rtx
v850_return_addr (int count)
v850_return_addr (int count)
{
{
  if (count != 0)
  if (count != 0)
    return const0_rtx;
    return const0_rtx;
 
 
  return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
  return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
}
}


/* Implement TARGET_ASM_INIT_SECTIONS.  */
/* Implement TARGET_ASM_INIT_SECTIONS.  */
 
 
static void
static void
v850_asm_init_sections (void)
v850_asm_init_sections (void)
{
{
  rosdata_section
  rosdata_section
    = get_unnamed_section (0, output_section_asm_op,
    = get_unnamed_section (0, output_section_asm_op,
                           "\t.section .rosdata,\"a\"");
                           "\t.section .rosdata,\"a\"");
 
 
  rozdata_section
  rozdata_section
    = get_unnamed_section (0, output_section_asm_op,
    = get_unnamed_section (0, output_section_asm_op,
                           "\t.section .rozdata,\"a\"");
                           "\t.section .rozdata,\"a\"");
 
 
  tdata_section
  tdata_section
    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
                           "\t.section .tdata,\"aw\"");
                           "\t.section .tdata,\"aw\"");
 
 
  zdata_section
  zdata_section
    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
                           "\t.section .zdata,\"aw\"");
                           "\t.section .zdata,\"aw\"");
 
 
  zbss_section
  zbss_section
    = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
    = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
                           output_section_asm_op,
                           output_section_asm_op,
                           "\t.section .zbss,\"aw\"");
                           "\t.section .zbss,\"aw\"");
}
}
 
 
static section *
static section *
v850_select_section (tree exp,
v850_select_section (tree exp,
                     int reloc ATTRIBUTE_UNUSED,
                     int reloc ATTRIBUTE_UNUSED,
                     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
                     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
{
  if (TREE_CODE (exp) == VAR_DECL)
  if (TREE_CODE (exp) == VAR_DECL)
    {
    {
      int is_const;
      int is_const;
      if (!TREE_READONLY (exp)
      if (!TREE_READONLY (exp)
          || TREE_SIDE_EFFECTS (exp)
          || TREE_SIDE_EFFECTS (exp)
          || !DECL_INITIAL (exp)
          || !DECL_INITIAL (exp)
          || (DECL_INITIAL (exp) != error_mark_node
          || (DECL_INITIAL (exp) != error_mark_node
              && !TREE_CONSTANT (DECL_INITIAL (exp))))
              && !TREE_CONSTANT (DECL_INITIAL (exp))))
        is_const = FALSE;
        is_const = FALSE;
      else
      else
        is_const = TRUE;
        is_const = TRUE;
 
 
      switch (v850_get_data_area (exp))
      switch (v850_get_data_area (exp))
        {
        {
        case DATA_AREA_ZDA:
        case DATA_AREA_ZDA:
          return is_const ? rozdata_section : zdata_section;
          return is_const ? rozdata_section : zdata_section;
 
 
        case DATA_AREA_TDA:
        case DATA_AREA_TDA:
          return tdata_section;
          return tdata_section;
 
 
        case DATA_AREA_SDA:
        case DATA_AREA_SDA:
          return is_const ? rosdata_section : sdata_section;
          return is_const ? rosdata_section : sdata_section;
 
 
        default:
        default:
          return is_const ? readonly_data_section : data_section;
          return is_const ? readonly_data_section : data_section;
        }
        }
    }
    }
  return readonly_data_section;
  return readonly_data_section;
}
}


/* Worker function for TARGET_RETURN_IN_MEMORY.  */
/* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 
static bool
static bool
v850_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
v850_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
{
{
  /* Return values > 8 bytes in length in memory.  */
  /* Return values > 8 bytes in length in memory.  */
  return int_size_in_bytes (type) > 8 || TYPE_MODE (type) == BLKmode;
  return int_size_in_bytes (type) > 8 || TYPE_MODE (type) == BLKmode;
}
}


/* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
/* Worker function for TARGET_SETUP_INCOMING_VARARGS.  */
 
 
static void
static void
v850_setup_incoming_varargs (CUMULATIVE_ARGS *ca,
v850_setup_incoming_varargs (CUMULATIVE_ARGS *ca,
                             enum machine_mode mode ATTRIBUTE_UNUSED,
                             enum machine_mode mode ATTRIBUTE_UNUSED,
                             tree type ATTRIBUTE_UNUSED,
                             tree type ATTRIBUTE_UNUSED,
                             int *pretend_arg_size ATTRIBUTE_UNUSED,
                             int *pretend_arg_size ATTRIBUTE_UNUSED,
                             int second_time ATTRIBUTE_UNUSED)
                             int second_time ATTRIBUTE_UNUSED)
{
{
  ca->anonymous_args = (!TARGET_GHS ? 1 : 0);
  ca->anonymous_args = (!TARGET_GHS ? 1 : 0);
}
}
 
 
#include "gt-v850.h"
#include "gt-v850.h"
 
 

powered by: WebSVN 2.1.0

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