/* Subroutines for insn-output.c for NEC V850 series
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
for more details.
You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ along with GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
+#include "df.h"
#ifndef streq
#define streq(a,b) (strcmp (a, b) == 0)
#endif
/* Function prototypes for stupid compilers: */
+static bool v850_handle_option (size_t, const char *, 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 (rtx, enum rtx_code);
-static bool v850_rtx_costs (rtx, int, int, int *);
+static bool v850_rtx_costs (rtx, int, int, int *, bool);
static void substitute_ep_register (rtx, rtx, int, int, rtx *, rtx *);
static void v850_reorg (void);
static int ep_memory_offset (enum machine_mode, int);
static void v850_set_data_area (tree, v850_data_area);
-const struct attribute_spec v850_attribute_table[];
static tree v850_handle_interrupt_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_select_section (tree, int, unsigned HOST_WIDE_INT);
+static void v850_asm_init_sections (void);
+static section *v850_select_section (tree, int, unsigned HOST_WIDE_INT);
static void v850_encode_data_area (tree, rtx);
static void v850_encode_section_info (tree, rtx, int);
-static bool v850_return_in_memory (tree, tree);
+static bool v850_return_in_memory (const_tree, const_tree);
+static rtx v850_function_value (const_tree, const_tree, bool);
static void v850_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
tree, int *, int);
+static bool v850_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+ const_tree, bool);
+static int v850_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, bool);
+static bool v850_can_eliminate (const int, const int);
+static void v850_asm_trampoline_template (FILE *);
+static void v850_trampoline_init (rtx, tree, rtx);
/* Information about the various small memory areas. */
struct small_memory_info small_memory[ (int)SMALL_MEMORY_max ] =
{
- /* name value max physical max */
- { "tda", (char *)0, 0, 256 },
- { "sda", (char *)0, 0, 65536 },
- { "zda", (char *)0, 0, 32768 },
+ /* name max physical max */
+ { "tda", 0, 256 },
+ { "sda", 0, 65536 },
+ { "zda", 0, 32768 },
};
/* Names of the various data areas used on the v850. */
/* Whether current function is an interrupt handler. */
static int v850_interrupt_p = FALSE;
+
+static GTY(()) section *rosdata_section;
+static GTY(()) section *rozdata_section;
+static GTY(()) section *tdata_section;
+static GTY(()) section *zdata_section;
+static GTY(()) section *zbss_section;
+\f
+/* V850 specific attributes. */
+
+static const struct attribute_spec v850_attribute_table[] =
+{
+ /* { 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", 0, 0, true, false, false, v850_handle_interrupt_attribute },
+ { "sda", 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 },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
\f
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#undef TARGET_ASM_SELECT_SECTION
#define TARGET_ASM_SELECT_SECTION v850_select_section
+/* The assembler supports switchable .bss sections, but
+ v850_select_section doesn't yet make use of them. */
+#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS
+#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false
+
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
#define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS (MASK_DEFAULT | MASK_APP_REGS)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION v850_handle_option
+
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS v850_rtx_costs
#undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST hook_int_rtx_0
-
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1
+#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG v850_reorg
#undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY v850_return_in_memory
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE v850_function_value
+
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE v850_pass_by_reference
+
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS v850_setup_incoming_varargs
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES v850_arg_partial_bytes
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE v850_can_eliminate
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE v850_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT v850_trampoline_init
+
struct gcc_target targetm = TARGET_INITIALIZER;
\f
-/* Sometimes certain combinations of command options do not make
- sense on a particular target machine. You can define a macro
- `OVERRIDE_OPTIONS' to take account of this. This macro, if
- defined, is executed once just after all the command options have
- been parsed.
+/* Set the maximum size of small memory area TYPE to the value given
+ by VALUE. Return true if VALUE was syntactically correct. VALUE
+ starts with the argument separator: either "-" or "=". */
- Don't use this macro to turn on various extra optimizations for
- `-O'. That is what `OPTIMIZATION_OPTIONS' is for. */
-
-void
-override_options (void)
+static bool
+v850_handle_memory_option (enum small_memory_type type, const char *value)
{
- int i;
- extern int atoi (const char *);
+ int i, size;
- /* Parse -m{s,t,z}da=nnn switches */
- for (i = 0; i < (int)SMALL_MEMORY_max; i++)
- {
- if (small_memory[i].value)
- {
- if (!ISDIGIT (*small_memory[i].value))
- error ("%s=%s is not numeric",
- small_memory[i].name,
- small_memory[i].value);
- else
- {
- small_memory[i].max = atoi (small_memory[i].value);
- if (small_memory[i].max > small_memory[i].physical_max)
- error ("%s=%s is too large",
- small_memory[i].name,
- small_memory[i].value);
- }
- }
- }
+ if (*value != '-' && *value != '=')
+ return false;
+
+ value++;
+ for (i = 0; value[i]; i++)
+ if (!ISDIGIT (value[i]))
+ return false;
+
+ size = atoi (value);
+ if (size > small_memory[type].physical_max)
+ error ("value passed to %<-m%s%> is too large", small_memory[type].name);
+ else
+ small_memory[type].max = size;
+ return true;
+}
+
+/* Implement TARGET_HANDLE_OPTION. */
- /* Make sure that the US_BIT_SET mask has been correctly initialized. */
- if ((target_flags & MASK_US_MASK_SET) == 0)
+static bool
+v850_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
{
- target_flags |= MASK_US_MASK_SET;
- target_flags &= ~MASK_US_BIT_SET;
+ case OPT_mspace:
+ target_flags |= MASK_EP | MASK_PROLOG_FUNCTION;
+ return true;
+
+ case OPT_mv850:
+ target_flags &= ~(MASK_CPU ^ MASK_V850);
+ return true;
+
+ case OPT_mv850e:
+ case OPT_mv850e1:
+ target_flags &= ~(MASK_CPU ^ MASK_V850E);
+ return true;
+
+ case OPT_mtda:
+ return v850_handle_memory_option (SMALL_MEMORY_TDA, arg);
+
+ case OPT_msda:
+ return v850_handle_memory_option (SMALL_MEMORY_SDA, arg);
+
+ case OPT_mzda:
+ return v850_handle_memory_option (SMALL_MEMORY_ZDA, arg);
+
+ default:
+ return true;
}
}
-
\f
+static bool
+v850_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode, const_tree type,
+ bool named ATTRIBUTE_UNUSED)
+{
+ unsigned HOST_WIDE_INT size;
+
+ if (type)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
-/* 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. */
+ return size > 8;
+}
+
+/* Return an RTX to represent where an argument with mode MODE
+ and type TYPE will be passed to a function. If the result
+ is NULL_RTX, the argument will be pushed. */
rtx
function_arg (CUMULATIVE_ARGS * cum,
tree type,
int named)
{
- rtx result = 0;
+ rtx result = NULL_RTX;
int size, align;
if (TARGET_GHS && !named)
size = GET_MODE_SIZE (mode);
if (size < 1)
- return 0;
+ {
+ /* Once we have stopped using argument registers, do not start up again. */
+ cum->nbytes = 4 * UNITS_PER_WORD;
+ return NULL_RTX;
+ }
if (type)
align = TYPE_ALIGN (type) / BITS_PER_UNIT;
cum->nbytes = (cum->nbytes + align - 1) &~(align - 1);
if (cum->nbytes > 4 * UNITS_PER_WORD)
- return 0;
+ return NULL_RTX;
if (type == NULL_TREE
&& cum->nbytes + size > 4 * UNITS_PER_WORD)
- return 0;
+ return NULL_RTX;
switch (cum->nbytes / UNITS_PER_WORD)
{
result = gen_rtx_REG (mode, 9);
break;
default:
- result = 0;
+ result = NULL_RTX;
}
return result;
}
\f
-/* Return the number of words 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. */
-int
-function_arg_partial_nregs (CUMULATIVE_ARGS * cum,
- enum machine_mode mode,
- tree type,
- int named)
+static int
+v850_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode,
+ tree type, bool named)
{
int size, align;
else
size = GET_MODE_SIZE (mode);
+ if (size < 1)
+ size = 1;
+
if (type)
align = TYPE_ALIGN (type) / BITS_PER_UNIT;
else
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)
return 0;
&& cum->nbytes + size > 4 * UNITS_PER_WORD)
return 0;
- return (4 * UNITS_PER_WORD - cum->nbytes) / UNITS_PER_WORD;
+ return 4 * UNITS_PER_WORD - cum->nbytes;
}
\f
static bool
v850_rtx_costs (rtx x,
- int code,
+ int codearg,
int outer_code ATTRIBUTE_UNUSED,
- int * total)
+ int * total, bool speed)
{
+ enum rtx_code code = (enum rtx_code) codearg;
+
switch (code)
{
case CONST_INT:
case DIV:
case UMOD:
case UDIV:
- if (TARGET_V850E && optimize_size)
+ if (TARGET_V850E && !speed)
*total = 6;
else
*total = 60;
*total = 20;
return true;
+ case ZERO_EXTRACT:
+ if (outer_code == COMPARE)
+ *total = 0;
+ return false;
+
default:
return false;
}
fprintf (file, "l");
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
case 'F': /* high word of CONST_DOUBLE */
- if (GET_CODE (x) == CONST_INT)
- fprintf (file, "%d", (INTVAL (x) >= 0) ? 0 : -1);
- else if (GET_CODE (x) == CONST_DOUBLE)
+ switch (GET_CODE (x))
{
+ case CONST_INT:
+ fprintf (file, "%d", (INTVAL (x) >= 0) ? 0 : -1);
+ break;
+
+ case CONST_DOUBLE:
const_double_split (x, &high, &low);
fprintf (file, "%ld", (long) high);
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
break;
case 'G': /* low word of CONST_DOUBLE */
- if (GET_CODE (x) == CONST_INT)
- fprintf (file, "%ld", (long) INTVAL (x));
- else if (GET_CODE (x) == CONST_DOUBLE)
+ switch (GET_CODE (x))
{
+ case CONST_INT:
+ fprintf (file, "%ld", (long) INTVAL (x));
+ break;
+
+ case CONST_DOUBLE:
const_double_split (x, &high, &low);
fprintf (file, "%ld", (long) low);
+ break;
+
+ default:
+ gcc_unreachable ();
}
- else
- abort ();
break;
case 'L':
fprintf (file, "%d\n", (int)(INTVAL (x) & 0xffff));
fprintf (file, "%d", exact_log2 (INTVAL (x)));
break;
case 'O':
- if (special_symbolref_operand (x, VOIDmode))
- {
- if (GET_CODE (x) == SYMBOL_REF)
- ;
- else if (GET_CODE (x) == CONST)
- x = XEXP (XEXP (x, 0), 0);
- else
- abort ();
-
- if (SYMBOL_REF_ZDA_P (x))
- fprintf (file, "zdaoff");
- else if (SYMBOL_REF_SDA_P (x))
- fprintf (file, "sdaoff");
- else if (SYMBOL_REF_TDA_P (x))
- fprintf (file, "tdaoff");
- else
- abort ();
- }
+ gcc_assert (special_symbolref_operand (x, VOIDmode));
+
+ if (GET_CODE (x) == CONST)
+ x = XEXP (XEXP (x, 0), 0);
else
- abort ();
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+ if (SYMBOL_REF_ZDA_P (x))
+ fprintf (file, "zdaoff");
+ else if (SYMBOL_REF_SDA_P (x))
+ fprintf (file, "sdaoff");
+ else if (SYMBOL_REF_TDA_P (x))
+ fprintf (file, "tdaoff");
+ else
+ gcc_unreachable ();
break;
case 'P':
- if (special_symbolref_operand (x, VOIDmode))
- output_addr_const (file, x);
- else
- abort ();
+ gcc_assert (special_symbolref_operand (x, VOIDmode));
+ output_addr_const (file, x);
break;
case 'Q':
- if (special_symbolref_operand (x, VOIDmode))
- {
- if (GET_CODE (x) == SYMBOL_REF)
- ;
- else if (GET_CODE (x) == CONST)
- x = XEXP (XEXP (x, 0), 0);
- else
- abort ();
-
- if (SYMBOL_REF_ZDA_P (x))
- fprintf (file, "r0");
- else if (SYMBOL_REF_SDA_P (x))
- fprintf (file, "gp");
- else if (SYMBOL_REF_TDA_P (x))
- fprintf (file, "ep");
- else
- abort ();
- }
+ gcc_assert (special_symbolref_operand (x, VOIDmode));
+
+ if (GET_CODE (x) == CONST)
+ x = XEXP (XEXP (x, 0), 0);
+ else
+ gcc_assert (GET_CODE (x) == SYMBOL_REF);
+
+ if (SYMBOL_REF_ZDA_P (x))
+ fprintf (file, "r0");
+ else if (SYMBOL_REF_SDA_P (x))
+ fprintf (file, "gp");
+ else if (SYMBOL_REF_TDA_P (x))
+ fprintf (file, "ep");
else
- abort ();
+ gcc_unreachable ();
break;
case 'R': /* 2nd word of a double. */
switch (GET_CODE (x))
break;
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))
fputs ("s", file);
switch (GET_MODE (x))
{
default:
- abort ();
+ gcc_unreachable ();
case QImode: fputs (".b", file); break;
case HImode: fputs (".h", file); break;
fputs (reg_names[0], file);
break;
case 'z': /* reg or zero */
- if (x == const0_rtx)
- fputs (reg_names[0], file);
- else if (GET_CODE (x) == REG)
+ if (GET_CODE (x) == REG)
fputs (reg_names[REGNO (x)], file);
else
- abort ();
+ {
+ gcc_assert (x == const0_rtx);
+ fputs (reg_names[0], file);
+ }
break;
default:
switch (GET_CODE (x))
print_operand_address (file, x);
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
reg_name = "ep";
}
else
- abort ();
+ gcc_unreachable ();
fprintf (file, "%s(", off_name);
output_addr_const (file, addr);
{
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";
- 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";
else if (CONST_OK_FOR_L (value)) /* Upper 16 bits were set. */
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";
- 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";
else if (CONST_OK_FOR_L (high)) /* Upper 16 bits were set. */
}
\f
-/* Return appropriate code to load up an 8 byte integer or
- floating point value */
-
-const char *
-output_move_double (rtx * operands)
-{
- enum machine_mode mode = GET_MODE (operands[0]);
- rtx dst = operands[0];
- rtx src = operands[1];
-
- if (register_operand (dst, mode)
- && register_operand (src, mode))
- {
- if (REGNO (src) + 1 == REGNO (dst))
- return "mov %R1,%R0\n\tmov %1,%0";
- else
- return "mov %1,%0\n\tmov %R1,%R0";
- }
-
- /* Storing 0 */
- if (GET_CODE (dst) == MEM
- && ((GET_CODE (src) == CONST_INT && INTVAL (src) == 0)
- || (GET_CODE (src) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (src))))
- return "st.w %.,%0\n\tst.w %.,%R0";
-
- if (GET_CODE (src) == CONST_INT || GET_CODE (src) == CONST_DOUBLE)
- {
- HOST_WIDE_INT high_low[2];
- int i;
- rtx xop[10];
-
- if (GET_CODE (src) == CONST_DOUBLE)
- const_double_split (src, &high_low[1], &high_low[0]);
- else
- {
- high_low[0] = INTVAL (src);
- high_low[1] = (INTVAL (src) >= 0) ? 0 : -1;
- }
-
- for (i = 0; i < 2; i++)
- {
- xop[0] = gen_rtx_REG (SImode, REGNO (dst)+i);
- xop[1] = GEN_INT (high_low[i]);
- output_asm_insn (output_move_single (xop), xop);
- }
-
- return "";
- }
-
- if (GET_CODE (src) == MEM)
- {
- int ptrreg = -1;
- int dreg = REGNO (dst);
- rtx inside = XEXP (src, 0);
-
- if (GET_CODE (inside) == REG)
- ptrreg = REGNO (inside);
- else if (GET_CODE (inside) == SUBREG)
- ptrreg = subreg_regno (inside);
- else if (GET_CODE (inside) == PLUS)
- ptrreg = REGNO (XEXP (inside, 0));
- else if (GET_CODE (inside) == LO_SUM)
- ptrreg = REGNO (XEXP (inside, 0));
-
- if (dreg == ptrreg)
- return "ld.w %R1,%R0\n\tld.w %1,%0";
- }
-
- if (GET_CODE (src) == MEM)
- return "ld.w %1,%0\n\tld.w %R1,%R0";
-
- if (GET_CODE (dst) == MEM)
- return "st.w %1,%0\n\tst.w %R1,%R0";
-
- return "mov %1,%0\n\tmov %R1,%R0";
-}
-
-\f
/* Return maximum offset supported for a short EP memory reference of mode
MODE and signedness UNSIGNEDP. */
int max_offset;
int mask;
+ /* If we are not using the EP register on a per-function basis
+ then do not allow this optimization at all. This is to
+ prevent the use of the SLD/SST instructions which cannot be
+ guaranteed to work properly due to a hardware bug. */
+ if (!TARGET_EP)
+ return FALSE;
+
if (GET_CODE (op) != MEM)
return FALSE;
return FALSE;
}
-
-/* Return true if OP is either a register or 0 */
-
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT)
- return INTVAL (op) == 0;
-
- else if (GET_CODE (op) == CONST_DOUBLE)
- return CONST_DOUBLE_OK_FOR_G (op);
-
- else
- return register_operand (op, mode);
-}
-
-/* Return true if OP is either a register or a signed five bit integer */
-
-int
-reg_or_int5_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT)
- return CONST_OK_FOR_J (INTVAL (op));
-
- else
- return register_operand (op, mode);
-}
-
-/* Return true if OP is either a register or a signed nine bit integer. */
-
-int
-reg_or_int9_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT)
- return CONST_OK_FOR_O (INTVAL (op));
-
- return register_operand (op, mode);
-}
-
-/* Return true if OP is either a register or a const integer. */
-
-int
-reg_or_const_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == CONST_INT)
- return TRUE;
-
- return register_operand (op, mode);
-}
-
-/* Return true if OP is a valid call operand. */
-
-int
-call_address_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- /* Only registers are valid call operands if TARGET_LONG_CALLS. */
- if (TARGET_LONG_CALLS)
- return GET_CODE (op) == REG;
- return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
-}
-
-int
-special_symbolref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) == CONST
- && GET_CODE (XEXP (op, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
- && CONST_OK_FOR_K (INTVAL (XEXP (XEXP (op, 0), 1))))
- op = XEXP (XEXP (op, 0), 0);
-
- if (GET_CODE (op) == SYMBOL_REF)
- return (SYMBOL_REF_FLAGS (op)
- & (SYMBOL_FLAG_ZDA | SYMBOL_FLAG_TDA | SYMBOL_FLAG_SDA)) != 0;
-
- return FALSE;
-}
-
-int
-movsi_source_operand (rtx op, enum machine_mode mode)
-{
- /* Some constants, as well as symbolic operands
- must be done with HIGH & LO_SUM patterns. */
- if (CONSTANT_P (op)
- && GET_CODE (op) != HIGH
- && !(GET_CODE (op) == CONST_INT
- && (CONST_OK_FOR_J (INTVAL (op))
- || CONST_OK_FOR_K (INTVAL (op))
- || CONST_OK_FOR_L (INTVAL (op)))))
- return special_symbolref_operand (op, mode);
- else
- return general_operand (op, mode);
-}
-
-int
-power_of_two_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != CONST_INT)
- return 0;
-
- if (exact_log2 (INTVAL (op)) == -1)
- return 0;
- return 1;
-}
-
-int
-not_power_of_two_operand (rtx op, enum machine_mode mode)
-{
- unsigned int mask;
-
- if (mode == QImode)
- mask = 0xff;
- else if (mode == HImode)
- mask = 0xffff;
- else if (mode == SImode)
- mask = 0xffffffff;
- else
- return 0;
-
- if (GET_CODE (op) != CONST_INT)
- return 0;
-
- if (exact_log2 (~INTVAL (op) & mask) == -1)
- return 0;
- return 1;
-}
-
\f
/* Substitute memory references involving a pointer, to use the ep pointer,
taking care to save and preserve the ep. */
if (!*p_r1)
{
- regs_ever_live[1] = 1;
+ df_set_regs_ever_live (1, true);
*p_r1 = gen_rtx_REG (Pmode, 1);
*p_ep = gen_rtx_REG (Pmode, 30);
}
int size = 0;
int i;
int interrupt_handler = v850_interrupt_function_p (current_function_decl);
- int call_p = regs_ever_live [LINK_POINTER_REGNUM];
+ int call_p = df_regs_ever_live_p (LINK_POINTER_REGNUM);
long reg_saved = 0;
/* Count the return pointer if we need to save it. */
- if (current_function_profile && !call_p)
- regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
+ if (crtl->profile && !call_p)
+ {
+ df_set_regs_ever_live (LINK_POINTER_REGNUM, true);
+ call_p = 1;
+ }
/* Count space for the register saves. */
if (interrupt_handler)
switch (i)
{
default:
- if (regs_ever_live[i] || call_p)
+ if (df_regs_ever_live_p (i) || call_p)
{
size += 4;
reg_saved |= 1L << i;
{
/* Find the first register that needs to be saved. */
for (i = 0; i <= 31; i++)
- if (regs_ever_live[i] && ((! call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ((! call_used_regs[i])
|| i == LINK_POINTER_REGNUM))
break;
reg_saved |= 1L << i;
}
- if (regs_ever_live [LINK_POINTER_REGNUM])
+ if (df_regs_ever_live_p (LINK_POINTER_REGNUM))
{
size += 4;
reg_saved |= 1L << LINK_POINTER_REGNUM;
else
{
for (; i <= 31; i++)
- if (regs_ever_live[i] && ((! call_used_regs[i])
+ if (df_regs_ever_live_p (i) && ((! call_used_regs[i])
|| i == LINK_POINTER_REGNUM))
{
size += 4;
{
return (size
+ compute_register_save_size (p_reg_saved)
- + current_function_outgoing_args_size);
+ + crtl->outgoing_args_size);
}
\f
}
/* Save arg registers to the stack if necessary. */
- else if (current_function_args_info.anonymous_args)
+ else if (crtl->args.info.anonymous_args)
{
if (TARGET_PROLOG_FUNCTION && TARGET_V850E && !TARGET_DISABLE_CALLT)
emit_insn (gen_save_r6_r9_v850e ());
if (init_stack_alloc)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
- GEN_INT (-init_stack_alloc)));
+ GEN_INT (- (signed) init_stack_alloc)));
/* Save the return pointer first. */
if (num_save > 0 && REGNO (save_regs[num_save-1]) == LINK_POINTER_REGNUM)
int offset;
unsigned int size = get_frame_size ();
long reg_saved = 0;
- unsigned int actual_fsize = compute_frame_size (size, ®_saved);
+ int actual_fsize = compute_frame_size (size, ®_saved);
unsigned int init_stack_free = 0;
rtx restore_regs[32];
rtx restore_all;
if (TARGET_PROLOG_FUNCTION
&& num_restore > 0
- && actual_fsize >= default_stack
+ && actual_fsize >= (signed) default_stack
&& !interrupt_handler)
{
int alloc_stack = (4 * num_restore) + default_stack;
}
}
- /* If no epilog save function is available, restore the registers the
+ /* If no epilogue save function is available, restore the registers the
old fashioned way (one by one). */
if (!restore_all)
{
if (actual_fsize && !CONST_OK_FOR_K (-actual_fsize))
init_stack_free = 4 * num_restore;
else
- init_stack_free = actual_fsize;
+ init_stack_free = (signed) actual_fsize;
/* Deallocate the rest of the stack if it is > 32K. */
- if (actual_fsize > init_stack_free)
+ if ((unsigned int) actual_fsize > init_stack_free)
{
int diff;
plus_constant (stack_pointer_rtx,
offset)));
- emit_insn (gen_rtx_USE (VOIDmode, restore_regs[i]));
+ emit_use (restore_regs[i]);
offset -= 4;
}
else if (actual_fsize)
emit_jump_insn (gen_return_internal ());
else
- emit_jump_insn (gen_return ());
+ emit_jump_insn (gen_return_simple ());
}
v850_interrupt_cache_p = FALSE;
(name, NULL, DECL_ATTRIBUTES (decl));
}
\f
-const struct attribute_spec v850_attribute_table[] =
-{
- /* { 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", 0, 0, true, false, false, v850_handle_interrupt_attribute },
- { "sda", 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 },
- { NULL, 0, 0, false, false, false, NULL }
-};
-
/* Handle an "interrupt" attribute; arguments as in
struct attribute_spec.handler. */
static tree
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
- warning ("`%s' attribute only applies to functions",
- IDENTIFIER_POINTER (name));
+ warning (OPT_Wattributes, "%qE attribute only applies to functions",
+ name);
*no_add_attrs = true;
}
else if (is_attribute_p ("zda", name))
data_area = DATA_AREA_ZDA;
else
- abort ();
+ gcc_unreachable ();
switch (TREE_CODE (decl))
{
case VAR_DECL:
if (current_function_decl != NULL_TREE)
{
- error ("%Jdata area attributes cannot be specified for "
- "local variables", decl, decl);
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "data area attributes cannot be specified for "
+ "local variables");
*no_add_attrs = true;
}
area = v850_get_data_area (decl);
if (area != DATA_AREA_NORMAL && data_area != area)
{
- error ("%Jdata area of '%D' conflicts with previous declaration",
- decl, decl);
+ error ("data area of %q+D conflicts with previous declaration",
+ decl);
*no_add_attrs = true;
}
break;
case DATA_AREA_ZDA: flags |= SYMBOL_FLAG_ZDA; break;
case DATA_AREA_TDA: flags |= SYMBOL_FLAG_TDA; break;
case DATA_AREA_SDA: flags |= SYMBOL_FLAG_SDA; break;
- default: abort ();
+ default: gcc_unreachable ();
}
SYMBOL_REF_FLAGS (symbol) = flags;
}
v850_encode_data_area (decl, XEXP (rtl, 0));
}
-/* Return true if the given RTX is a register which can be restored
- by a function epilogue. */
-int
-register_is_ok_for_epilogue (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- /* The save/restore routines can only cope with registers 20 - 31. */
- return ((GET_CODE (op) == REG)
- && (((REGNO (op) >= 20) && REGNO (op) <= 31)));
-}
-
-/* Return nonzero if the given RTX is suitable for collapsing into
- jump to a function epilogue. */
-int
-pattern_is_ok_for_epilogue (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- int count = XVECLEN (op, 0);
- int i;
-
- /* If there are no registers to restore then the function epilogue
- is not suitable. */
- if (count <= 2)
- return 0;
-
- /* The pattern matching has already established that we are performing a
- function epilogue and that we are popping at least one register. We must
- now check the remaining entries in the vector to make sure that they are
- also register pops. There is no good reason why there should ever be
- anything else in this vector, but being paranoid always helps...
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (match_operand:SI n "register_is_ok_for_epilogue" "r")
- (mem:SI (plus:SI (reg:SI 3) (match_operand:SI n "immediate_operand" "i"))))
- */
-
- for (i = 3; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
- rtx dest;
- rtx src;
- rtx plus;
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if (GET_CODE (dest) != REG
- || GET_MODE (dest) != SImode
- || ! register_is_ok_for_epilogue (dest, SImode)
- || GET_CODE (src) != MEM
- || GET_MODE (src) != SImode)
- return 0;
-
- plus = XEXP (src, 0);
-
- if (GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
- }
-
- return 1;
-}
-
/* 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
pops registers off the stack and possibly releases some extra stack space
if (count <= 2)
{
- error ("bogus JR construction: %d\n", count);
+ error ("bogus JR construction: %d", count);
return NULL;
}
/* Work out how many bytes to pop off the stack before retrieving
registers. */
- if (GET_CODE (XVECEXP (op, 0, 1)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
+ 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);
stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
{
rtx vector_element = XVECEXP (op, 0, i);
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_DEST (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode))
- abort ();
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
+ SImode));
mask |= 1 << REGNO (SET_DEST (vector_element));
}
break;
}
- if (first >= 32)
- abort ();
+ gcc_assert (first < 32);
/* Discover the last register to pop. */
if (mask & (1 << LINK_POINTER_REGNUM))
{
- if (stack_bytes != 16)
- abort ();
+ gcc_assert (stack_bytes == 16);
last = LINK_POINTER_REGNUM;
}
else
{
- if (stack_bytes != 0)
- abort ();
-
- if ((mask & (1 << 29)) == 0)
- abort ();
+ gcc_assert (!stack_bytes);
+ gcc_assert (mask & (1 << 29));
last = 29;
}
}
-/* Return nonzero if the given RTX is suitable for collapsing into
- a jump to a function prologue. */
-int
-pattern_is_ok_for_prologue (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- int count = XVECLEN (op, 0);
- int i;
- rtx vector_element;
-
- /* If there are no registers to save then the function prologue
- is not suitable. */
- if (count <= 2)
- return 0;
-
- /* The pattern matching has already established that we are adjusting the
- stack and pushing at least one register. We must now check that the
- remaining entries in the vector to make sure that they are also register
- pushes, except for the last entry which should be a CLOBBER of r10.
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (mem:SI (plus:SI (reg:SI 3)
- (match_operand:SI 2 "immediate_operand" "i")))
- (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
-
- */
-
- for (i = 2; i < count - (TARGET_LONG_CALLS ? 2: 1); i++)
- {
- rtx dest;
- rtx src;
- rtx plus;
-
- vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if (GET_CODE (dest) != MEM
- || GET_MODE (dest) != SImode
- || GET_CODE (src) != REG
- || GET_MODE (src) != SImode
- || ! register_is_ok_for_epilogue (src, SImode))
- return 0;
-
- plus = XEXP (dest, 0);
-
- if ( GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
-
- /* If the register is being pushed somewhere other than the stack
- space just acquired by the first operand then abandon this quest.
- Note: the test is <= because both values are negative. */
- if (INTVAL (XEXP (plus, 1))
- <= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
- {
- return 0;
- }
- }
-
- /* Make sure that the last entries in the vector are clobbers. */
- for (; i < count; i++)
- {
- vector_element = XVECEXP (op, 0, i);
-
- if (GET_CODE (vector_element) != CLOBBER
- || GET_CODE (XEXP (vector_element, 0)) != REG
- || !(REGNO (XEXP (vector_element, 0)) == 10
- || (TARGET_LONG_CALLS ? (REGNO (XEXP (vector_element, 0)) == 11) : 0 )))
- return 0;
- }
-
- return 1;
-}
-
/* 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
saves some of the registers r20 - r31 onto the stack, and possibly acquires
}
/* Paranoia. */
- if (GET_CODE (XVECEXP (op, 0, 0)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0)) != REG)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
+ 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)), 1)) == CONST_INT);
/* Work out how many bytes to push onto the stack after storing the
registers. */
{
rtx vector_element = XVECEXP (op, 0, i);
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_SRC (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_SRC (vector_element), SImode))
- abort ();
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
+ SImode));
mask |= 1 << REGNO (SET_SRC (vector_element));
}
break;
}
- if (first >= 32)
- abort ();
+ gcc_assert (first < 32);
/* Discover the last register to push. */
if (mask & (1 << LINK_POINTER_REGNUM))
{
- if (stack_bytes != -16)
- abort ();
+ gcc_assert (stack_bytes == -16);
last = LINK_POINTER_REGNUM;
}
else
{
- if (stack_bytes != 0)
- abort ();
- if ((mask & (1 << 29)) == 0)
- abort ();
+ gcc_assert (!stack_bytes);
+ gcc_assert (mask & (1 << 29));
last = 29;
}
v850_output_aligned_bss (FILE * file,
tree decl,
const char * name,
- int size,
+ unsigned HOST_WIDE_INT size,
int align)
{
switch (v850_get_data_area (decl))
{
case DATA_AREA_ZDA:
- zbss_section ();
+ switch_to_section (zbss_section);
break;
case DATA_AREA_SDA:
- sbss_section ();
+ switch_to_section (sbss_section);
break;
case DATA_AREA_TDA:
- tdata_section ();
+ switch_to_section (tdata_section);
default:
- bss_section ();
+ switch_to_section (bss_section);
break;
}
switch (v850_get_data_area (decl))
{
default:
- abort ();
+ gcc_unreachable ();
case DATA_AREA_SDA:
kind = ((TREE_READONLY (decl))
}
}
-/* Return nonzero if the given RTX is suitable
- for collapsing into a DISPOSE instruction. */
-
-int
-pattern_is_ok_for_dispose (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- int count = XVECLEN (op, 0);
- int i;
-
- /* If there are no registers to restore then
- the dispose instruction is not suitable. */
- if (count <= 2)
- return 0;
-
- /* The pattern matching has already established that we are performing a
- function epilogue and that we are popping at least one register. We must
- now check the remaining entries in the vector to make sure that they are
- also register pops. There is no good reason why there should ever be
- anything else in this vector, but being paranoid always helps...
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (match_operand:SI n "register_is_ok_for_epilogue" "r")
- (mem:SI (plus:SI (reg:SI 3)
- (match_operand:SI n "immediate_operand" "i"))))
- */
-
- for (i = 3; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
- rtx dest;
- rtx src;
- rtx plus;
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if ( GET_CODE (dest) != REG
- || GET_MODE (dest) != SImode
- || ! register_is_ok_for_epilogue (dest, SImode)
- || GET_CODE (src) != MEM
- || GET_MODE (src) != SImode)
- return 0;
-
- plus = XEXP (src, 0);
-
- if ( GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
- }
-
- return 1;
-}
-
/* Construct a DISPOSE instruction that is the equivalent of
the given RTX. We have already verified that this should
be possible. */
if (count <= 2)
{
- error ("Bogus DISPOSE construction: %d\n", count);
+ error ("bogus DISPOSE construction: %d", count);
return NULL;
}
/* Work out how many bytes to pop off the
stack before retrieving registers. */
- if (GET_CODE (XVECEXP (op, 0, 1)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 1))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1)) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 1)) == SET);
+ 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);
stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 1)), 1));
will fit into the DISPOSE instruction. */
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;
}
{
rtx vector_element = XVECEXP (op, 0, i);
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_DEST (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_DEST (vector_element), SImode))
- abort ();
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_DEST (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_DEST (vector_element),
+ SImode));
if (REGNO (SET_DEST (vector_element)) == 2)
use_callt = 1;
return buff;
}
-/* Return nonzero if the given RTX is suitable
- for collapsing into a PREPARE instruction. */
-
-int
-pattern_is_ok_for_prepare (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- int count = XVECLEN (op, 0);
- int i;
-
- /* If there are no registers to restore then the prepare instruction
- is not suitable. */
- if (count <= 1)
- return 0;
-
- /* The pattern matching has already established that we are adjusting the
- stack and pushing at least one register. We must now check that the
- remaining entries in the vector to make sure that they are also register
- pushes.
-
- The test below performs the C equivalent of this machine description
- pattern match:
-
- (set (mem:SI (plus:SI (reg:SI 3)
- (match_operand:SI 2 "immediate_operand" "i")))
- (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))
-
- */
-
- for (i = 2; i < count; i++)
- {
- rtx vector_element = XVECEXP (op, 0, i);
- rtx dest;
- rtx src;
- rtx plus;
-
- if (GET_CODE (vector_element) != SET)
- return 0;
-
- dest = SET_DEST (vector_element);
- src = SET_SRC (vector_element);
-
- if ( GET_CODE (dest) != MEM
- || GET_MODE (dest) != SImode
- || GET_CODE (src) != REG
- || GET_MODE (src) != SImode
- || ! register_is_ok_for_epilogue (src, SImode)
- )
- return 0;
-
- plus = XEXP (dest, 0);
-
- if ( GET_CODE (plus) != PLUS
- || GET_CODE (XEXP (plus, 0)) != REG
- || GET_MODE (XEXP (plus, 0)) != SImode
- || REGNO (XEXP (plus, 0)) != STACK_POINTER_REGNUM
- || GET_CODE (XEXP (plus, 1)) != CONST_INT)
- return 0;
-
- /* If the register is being pushed somewhere other than the stack
- space just acquired by the first operand then abandon this quest.
- Note: the test is <= because both values are negative. */
- if (INTVAL (XEXP (plus, 1))
- <= INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)))
- return 0;
- }
-
- return 1;
-}
-
/* Construct a PREPARE instruction that is the equivalent of
the given RTL. We have already verified that this should
be possible. */
if (count <= 1)
{
- error ("Bogus PREPEARE construction: %d\n", count);
+ error ("bogus PREPEARE construction: %d", count);
return NULL;
}
/* Work out how many bytes to push onto
the stack after storing the registers. */
- if (GET_CODE (XVECEXP (op, 0, 0)) != SET)
- abort ();
- if (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != PLUS)
- abort ();
- if (GET_CODE (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1)) != CONST_INT)
- abort ();
+ gcc_assert (GET_CODE (XVECEXP (op, 0, 0)) == SET);
+ 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);
stack_bytes = INTVAL (XEXP (SET_SRC (XVECEXP (op, 0, 0)), 1));
will fit into the DISPOSE instruction. */
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;
}
{
rtx vector_element = XVECEXP (op, 0, i);
- if (GET_CODE (vector_element) != SET)
- abort ();
- if (GET_CODE (SET_SRC (vector_element)) != REG)
- abort ();
- if (! register_is_ok_for_epilogue (SET_SRC (vector_element), SImode))
- abort ();
+ gcc_assert (GET_CODE (vector_element) == SET);
+ gcc_assert (GET_CODE (SET_SRC (vector_element)) == REG);
+ gcc_assert (register_is_ok_for_epilogue (SET_SRC (vector_element),
+ SImode));
if (REGNO (SET_SRC (vector_element)) == 2)
use_callt = 1;
return buff;
}
\f
-/* Implement `va_arg'. */
-
-rtx
-v850_va_arg (tree valist, tree type)
-{
- HOST_WIDE_INT size, rsize;
- tree addr, incr;
- rtx addr_rtx;
- int indirect;
-
- /* Round up sizeof(type) to a word. */
- size = int_size_in_bytes (type);
- rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
- indirect = 0;
-
- if (size > 8)
- {
- size = rsize = UNITS_PER_WORD;
- indirect = 1;
- }
-
- addr = save_expr (valist);
- incr = fold (build (PLUS_EXPR, ptr_type_node, addr,
- build_int_2 (rsize, 0)));
-
- incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
- TREE_SIDE_EFFECTS (incr) = 1;
- expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
-
- if (indirect)
- {
- addr_rtx = force_reg (Pmode, addr_rtx);
- addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
- set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
- }
-
- return addr_rtx;
-}
-\f
/* Return an RTX indicating where the return address to the
calling function can be found. */
return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
}
\f
+/* Implement TARGET_ASM_INIT_SECTIONS. */
+
static void
+v850_asm_init_sections (void)
+{
+ rosdata_section
+ = get_unnamed_section (0, output_section_asm_op,
+ "\t.section .rosdata,\"a\"");
+
+ rozdata_section
+ = get_unnamed_section (0, output_section_asm_op,
+ "\t.section .rozdata,\"a\"");
+
+ tdata_section
+ = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ "\t.section .tdata,\"aw\"");
+
+ zdata_section
+ = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ "\t.section .zdata,\"aw\"");
+
+ zbss_section
+ = get_unnamed_section (SECTION_WRITE | SECTION_BSS,
+ output_section_asm_op,
+ "\t.section .zbss,\"aw\"");
+}
+
+static section *
v850_select_section (tree exp,
int reloc ATTRIBUTE_UNUSED,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
switch (v850_get_data_area (exp))
{
case DATA_AREA_ZDA:
- if (is_const)
- rozdata_section ();
- else
- zdata_section ();
- break;
+ return is_const ? rozdata_section : zdata_section;
case DATA_AREA_TDA:
- tdata_section ();
- break;
+ return tdata_section;
case DATA_AREA_SDA:
- if (is_const)
- rosdata_section ();
- else
- sdata_section ();
- break;
+ return is_const ? rosdata_section : sdata_section;
default:
- if (is_const)
- readonly_data_section ();
- else
- data_section ();
- break;
+ return is_const ? readonly_data_section : data_section;
}
}
- else
- readonly_data_section ();
+ return readonly_data_section;
}
\f
/* Worker function for TARGET_RETURN_IN_MEMORY. */
static bool
-v850_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+v850_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
{
/* Return values > 8 bytes in length in memory. */
return int_size_in_bytes (type) > 8 || TYPE_MODE (type) == BLKmode;
}
+
+/* Worker function for TARGET_FUNCTION_VALUE. */
+
+rtx
+v850_function_value (const_tree valtype,
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (TYPE_MODE (valtype), 10);
+}
+
\f
/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */
{
ca->anonymous_args = (!TARGET_GHS ? 1 : 0);
}
+
+/* Worker function for TARGET_CAN_ELIMINATE. */
+
+static bool
+v850_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ return (to == STACK_POINTER_REGNUM ? ! frame_pointer_needed : true);
+}
+
+\f
+/* Worker function for TARGET_ASM_TRAMPOLINE_TEMPLATE. */
+
+static void
+v850_asm_trampoline_template (FILE *f)
+{
+ fprintf (f, "\tjarl .+4,r12\n");
+ fprintf (f, "\tld.w 12[r12],r20\n");
+ fprintf (f, "\tld.w 16[r12],r12\n");
+ fprintf (f, "\tjmp [r12]\n");
+ fprintf (f, "\tnop\n");
+ fprintf (f, "\t.long 0\n");
+ fprintf (f, "\t.long 0\n");
+}
+
+/* Worker function for TARGET_TRAMPOLINE_INIT. */
+
+static void
+v850_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx mem, fnaddr = XEXP (DECL_RTL (fndecl), 0);
+
+ emit_block_move (m_tramp, assemble_trampoline_template (),
+ GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+ mem = adjust_address (m_tramp, SImode, 16);
+ emit_move_insn (mem, chain_value);
+ mem = adjust_address (m_tramp, SImode, 20);
+ emit_move_insn (mem, fnaddr);
+}
+\f
+#include "gt-v850.h"