/* Subroutines for insn-output.c for NEC V850 series
- Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
+ Free Software Foundation, Inc.
Contributed by Jeff Law (law@cygnus.com).
This file is part of GNU CC.
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
-#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "cpplib.h"
#include "c-lex.h"
#include "ggc.h"
+#include "integrate.h"
#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
#ifndef streq
#define streq(a,b) (strcmp (a, b) == 0)
#endif
/* Function prototypes for stupid compilers: */
-static void const_double_split
- PARAMS ((rtx, HOST_WIDE_INT *, HOST_WIDE_INT *));
-static int const_costs_int PARAMS ((HOST_WIDE_INT, int));
-static void substitute_ep_register PARAMS ((rtx, rtx, int, int, rtx *, rtx *));
-static int ep_memory_offset PARAMS ((enum machine_mode, int));
-static void v850_set_data_area PARAMS ((tree, v850_data_area));
+static void const_double_split PARAMS ((rtx, HOST_WIDE_INT *, HOST_WIDE_INT *));
+static int const_costs_int PARAMS ((HOST_WIDE_INT, int));
+static void substitute_ep_register PARAMS ((rtx, rtx, int, int, rtx *, rtx *));
+static int ep_memory_offset PARAMS ((enum machine_mode, int));
+static void v850_set_data_area PARAMS ((tree, v850_data_area));
+const struct attribute_spec v850_attribute_table[];
+static tree v850_handle_interrupt_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static tree v850_handle_data_area_attribute PARAMS ((tree *, tree, tree, int, bool *));
+static void v850_insert_attributes PARAMS ((tree, tree *));
+static void v850_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT));
+static void v850_encode_data_area PARAMS ((tree));
+static void v850_encode_section_info PARAMS ((tree, int));
+static const char *v850_strip_name_encoding PARAMS ((const char *));
/* True if the current function has anonymous arguments. */
int current_function_anonymous_args;
/* Whether current function is an interrupt handler. */
static int v850_interrupt_p = FALSE;
+\f
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE v850_attribute_table
+
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES v850_insert_attributes
+
+#undef TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION v850_select_section
+
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO v850_encode_section_info
+#undef TARGET_STRIP_NAME_ENCODING
+#define TARGET_STRIP_NAME_ENCODING v850_strip_name_encoding
+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
if (small_memory[i].value)
{
if (!ISDIGIT (*small_memory[i].value))
- error ("%s=%s is not numeric.",
+ 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.",
+ error ("%s=%s is too large",
small_memory[i].name,
small_memory[i].value);
}
fprintf (file, reg_names[REGNO (x) + 1]);
break;
case MEM:
- x = XEXP (adj_offsettable_operand (x, 4), 0);
+ x = XEXP (adjust_address (x, SImode, 4), 0);
print_operand_address (file, x);
if (GET_CODE (x) == CONST_INT)
fprintf (file, "[r0]");
fputs (reg_names[REGNO (x)], file);
break;
case SUBREG:
- fputs (reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)], file);
+ fputs (reg_names[subreg_regno (x)], file);
break;
case CONST_INT:
case SYMBOL_REF:
if (GET_CODE (inside) == REG)
ptrreg = REGNO (inside);
else if (GET_CODE (inside) == SUBREG)
- ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside);
+ ptrreg = subreg_regno (inside);
else if (GET_CODE (inside) == PLUS)
ptrreg = REGNO (XEXP (inside, 0));
else if (GET_CODE (inside) == LO_SUM)
else if (mode == HImode)
mask = 0xffff;
else if (mode == SImode)
- mask = 0xffffffffU;
+ mask = 0xffffffff;
else
return 0;
as a C statement to act on the code starting at INSN.
On the 850, we use it to implement the -mep mode to copy heavily used
- pointers to ep to use the implicit addressing */
+ pointers to ep to use the implicit addressing. */
void v850_reorg (start_insn)
rtx start_insn;
rtx insn;
rtx pattern;
- /* If not ep mode, just return now */
+ /* If not ep mode, just return now. */
if (!TARGET_EP)
return;
int unsignedp = FALSE;
/* We might have (SUBREG (MEM)) here, so just get rid of the
- subregs to make this code simpler. It is safe to call
- alter_subreg any time after reload. */
- if (GET_CODE (dest) == SUBREG)
- dest = alter_subreg (dest);
- if (GET_CODE (src) == SUBREG)
- src = alter_subreg (src);
+ subregs to make this code simpler. */
+ if (GET_CODE (dest) == SUBREG
+ && (GET_CODE (SUBREG_REG (dest)) == MEM
+ || GET_CODE (SUBREG_REG (dest)) == REG))
+ alter_subreg (&dest);
+ if (GET_CODE (src) == SUBREG
+ && (GET_CODE (SUBREG_REG (src)) == MEM
+ || GET_CODE (SUBREG_REG (src)) == REG))
+ alter_subreg (&src);
if (GET_CODE (dest) == MEM && GET_CODE (src) == MEM)
mem = NULL_RTX;
long reg_saved = 0;
/* Count the return pointer if we need to save it. */
- if (profile_flag && !call_p)
+ if (current_function_profile && !call_p)
regs_ever_live [LINK_POINTER_REGNUM] = call_p = 1;
/* Count space for the register saves. */
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
registers that need to be saved. To detect this we note that the
- helper functions always push at least register r29 if the link
- register is not used, and at least registers r27 - r31 if the
- link register is used (and provided that the function is not an
- interrupt handler). */
+ helper functions always push at least register r29 (provided
+ that the function is not an interrupt handler). */
if (TARGET_PROLOG_FUNCTION
- && (i == 2 || i >= 20)
- && regs_ever_live[LINK_POINTER_REGNUM] ? (i < 28) : (i < 30))
+ && (i == 2 || ((i >= 20) && (i < 30))))
{
if (i == 2)
{
offset -= 4;
}
- code = recog (save_all, NULL_RTX, NULL_PTR);
+ code = recog (save_all, NULL_RTX, NULL);
if (code >= 0)
{
rtx insn = emit_insn (save_all);
offset -= 4;
}
- code = recog (restore_all, NULL_RTX, NULL_PTR);
+ code = recog (restore_all, NULL_RTX, NULL);
if (code >= 0)
{
v850_get_data_area (decl)
tree decl;
{
- if (lookup_attribute ("sda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+ if (lookup_attribute ("sda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
return DATA_AREA_SDA;
- if (lookup_attribute ("tda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+ if (lookup_attribute ("tda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
return DATA_AREA_TDA;
- if (lookup_attribute ("zda", DECL_MACHINE_ATTRIBUTES (decl)) != NULL_TREE)
+ if (lookup_attribute ("zda", DECL_ATTRIBUTES (decl)) != NULL_TREE)
return DATA_AREA_ZDA;
return DATA_AREA_NORMAL;
return;
}
- DECL_MACHINE_ATTRIBUTES (decl) = tree_cons
- (name, NULL, DECL_MACHINE_ATTRIBUTES (decl));
+ DECL_ATTRIBUTES (decl) = tree_cons
+ (name, NULL, DECL_ATTRIBUTES (decl));
}
\f
-/* Return nonzero if ATTR is a valid attribute for DECL.
- ARGS are the arguments supplied with ATTR. */
+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 }
+};
-int
-v850_valid_machine_decl_attribute (decl, attr, args)
- tree decl;
- tree attr;
- tree args;
+/* Handle an "interrupt" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_interrupt_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning ("`%s' attribute only applies to functions",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "sda", "tda" or "zda" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+v850_handle_data_area_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name;
+ tree args ATTRIBUTE_UNUSED;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
{
v850_data_area data_area;
v850_data_area area;
-
- if (args != NULL_TREE)
- return 0;
-
- if (is_attribute_p ("interrupt_handler", attr)
- || is_attribute_p ("interrupt", attr))
- return TREE_CODE (decl) == FUNCTION_DECL;
+ tree decl = *node;
/* Implement data area attribute. */
- if (is_attribute_p ("sda", attr))
+ if (is_attribute_p ("sda", name))
data_area = DATA_AREA_SDA;
- else if (is_attribute_p ("tda", attr))
+ else if (is_attribute_p ("tda", name))
data_area = DATA_AREA_TDA;
- else if (is_attribute_p ("zda", attr))
+ else if (is_attribute_p ("zda", name))
data_area = DATA_AREA_ZDA;
else
- return 0;
+ abort ();
switch (TREE_CODE (decl))
{
case VAR_DECL:
if (current_function_decl != NULL_TREE)
- error_with_decl (decl, "\
+ {
+ error_with_decl (decl, "\
a data area attribute cannot be specified for local variables");
-
+ *no_add_attrs = true;
+ }
+
/* Drop through. */
case FUNCTION_DECL:
area = v850_get_data_area (decl);
if (area != DATA_AREA_NORMAL && data_area != area)
- error_with_decl (decl, "\
+ {
+ error_with_decl (decl, "\
data area of '%s' conflicts with previous declaration");
-
- return 1;
+ *no_add_attrs = true;
+ }
+ break;
default:
break;
}
-
- return 0;
+
+ return NULL_TREE;
}
\f
if (TREE_CODE (func) != FUNCTION_DECL)
return 0;
- a = lookup_attribute ("interrupt_handler", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
if (a != NULL_TREE)
ret = 1;
else
{
- a = lookup_attribute ("interrupt", DECL_MACHINE_ATTRIBUTES (func));
+ a = lookup_attribute ("interrupt", DECL_ATTRIBUTES (func));
ret = a != NULL_TREE;
}
}
\f
-void
+static void
v850_encode_data_area (decl)
tree decl;
{
return;
}
- newstr = ggc_alloc_string (NULL, len + 2);
+ newstr = alloca (len + 2);
strcpy (newstr + 1, str);
default: abort ();
}
- XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
+ XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 2);
+}
+
+static void
+v850_encode_section_info (decl, first)
+ tree decl;
+ int first;
+{
+ if (first && TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+ v850_encode_data_area (decl);
+}
+
+static const char *
+v850_strip_name_encoding (str)
+ const char *str;
+{
+ return str + (ENCODED_NAME_P (str) || *str == '*');
}
/* Return true if the given RTX is a register which can be restored
if (count <= 2)
{
- error ("Bogus JR construction: %d\n", count);
+ error ("bogus JR construction: %d\n", count);
return NULL;
}
/* Make sure that the amount we are popping either 0 or 16 bytes. */
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;
}
if (count <= 2)
{
- error ("Bogus JARL construction: %d\n", count);
+ error ("bogus JARL construction: %d\n", count);
return NULL;
}
/* Make sure that the amount we are popping either 0 or 16 bytes. */
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;
}
v850_output_aligned_bss (file, decl, name, size, align)
FILE * file;
tree decl;
- char * name;
+ const char * name;
int size;
int align;
{
v850_output_common (file, decl, name, size, align)
FILE * file;
tree decl;
- char * name;
+ const char * name;
int size;
int align;
{
v850_output_local (file, decl, name, size, align)
FILE * file;
tree decl;
- char * name;
+ const char * name;
int size;
int align;
{
/* Add data area to the given declaration if a ghs data area pragma is
currently in effect (#pragma ghs startXXX/endXXX). */
-void
-v850_set_default_decl_attr (decl)
+static void
+v850_insert_attributes (decl, attr_ptr)
tree decl;
+ tree *attr_ptr ATTRIBUTE_UNUSED;
{
if (data_area_stack
&& data_area_stack->data_area
}
addr = save_expr (valist);
- incr = fold (build (PLUS_EXPR, ptr_type_node, valist,
+ incr = fold (build (PLUS_EXPR, ptr_type_node, addr,
build_int_2 (rsize, 0)));
incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
{
addr_rtx = force_reg (Pmode, addr_rtx);
addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
- MEM_ALIAS_SET (addr_rtx) = get_varargs_alias_set ();
+ 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. */
+
+rtx
+v850_return_addr (count)
+ int count;
+{
+ if (count != 0)
+ return const0_rtx;
+
+ return get_hard_reg_initial_val (Pmode, LINK_POINTER_REGNUM);
+}
+\f
+static void
+v850_select_section (exp, reloc, align)
+ tree exp;
+ int reloc;
+ unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+ if (TREE_CODE (exp) == VAR_DECL)
+ {
+ int is_const;
+ if (!TREE_READONLY (exp)
+ || TREE_SIDE_EFFECTS (exp)
+ || !DECL_INITIAL (exp)
+ || (DECL_INITIAL (exp) != error_mark_node
+ && !TREE_CONSTANT (DECL_INITIAL (exp))))
+ is_const = FALSE;
+ else
+ is_const = TRUE;
+
+ switch (v850_get_data_area (exp))
+ {
+ case DATA_AREA_ZDA:
+ if (is_const)
+ rozdata_section ();
+ else
+ zdata_section ();
+ break;
+
+ case DATA_AREA_TDA:
+ tdata_section ();
+ break;
+
+ case DATA_AREA_SDA:
+ if (is_const)
+ rosdata_section ();
+ else
+ sdata_section ();
+ break;
+
+ default:
+ if (is_const)
+ readonly_data_section ();
+ else
+ data_section ();
+ break;
+ }
+ }
+ else if (TREE_CODE (exp) == STRING_CST)
+ {
+ if (! flag_writable_strings)
+ readonly_data_section ();
+ else
+ data_section ();
+ }
+ else
+ readonly_data_section ();
+}