Index: gcc/gcc/config/v850/v850.c |
diff --git a/gcc/gcc/config/v850/v850.c b/gcc/gcc/config/v850/v850.c |
index 51146e65d43e600298c008f55cc81cde5134c5a4..b7dd0921d4a876cc422eb5ed027b3e8d37d8c214 100644 |
--- a/gcc/gcc/config/v850/v850.c |
+++ b/gcc/gcc/config/v850/v850.c |
@@ -1,6 +1,6 @@ |
/* Subroutines for insn-output.c for NEC V850 series |
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
- 2006, 2007, 2008 Free Software Foundation, Inc. |
+ 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
Contributed by Jeff Law (law@cygnus.com). |
This file is part of GCC. |
@@ -58,7 +58,6 @@ 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 *); |
@@ -67,12 +66,16 @@ 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 (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 ] = |
@@ -104,6 +107,20 @@ static GTY(()) section *tdata_section; |
static GTY(()) section *zdata_section; |
static GTY(()) section *zbss_section; |
+/* 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 } |
+}; |
+ |
+ |
/* Initialize the GCC target structure. */ |
#undef TARGET_ASM_ALIGNED_HI_OP |
#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t" |
@@ -148,6 +165,9 @@ static GTY(()) section *zbss_section; |
#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 |
@@ -160,6 +180,14 @@ static GTY(()) section *zbss_section; |
#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; |
/* Set the maximum size of small memory area TYPE to the value given |
@@ -236,8 +264,9 @@ v850_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, |
return size > 8; |
} |
-/* 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 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, |
@@ -245,7 +274,7 @@ function_arg (CUMULATIVE_ARGS * cum, |
tree type, |
int named) |
{ |
- rtx result = 0; |
+ rtx result = NULL_RTX; |
int size, align; |
if (TARGET_GHS && !named) |
@@ -257,7 +286,11 @@ function_arg (CUMULATIVE_ARGS * cum, |
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; |
@@ -267,11 +300,11 @@ function_arg (CUMULATIVE_ARGS * cum, |
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) |
{ |
@@ -288,7 +321,7 @@ function_arg (CUMULATIVE_ARGS * cum, |
result = gen_rtx_REG (mode, 9); |
break; |
default: |
- result = 0; |
+ result = NULL_RTX; |
} |
return result; |
@@ -312,12 +345,15 @@ v850_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode, |
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; |
@@ -420,10 +456,12 @@ const_costs (rtx r, enum rtx_code c) |
static bool |
v850_rtx_costs (rtx x, |
- int code, |
+ int codearg, |
int outer_code ATTRIBUTE_UNUSED, |
int * total, bool speed) |
{ |
+ enum rtx_code code = (enum rtx_code) codearg; |
+ |
switch (code) |
{ |
case CONST_INT: |
@@ -464,6 +502,11 @@ v850_rtx_costs (rtx x, |
*total = 20; |
return true; |
+ case ZERO_EXTRACT: |
+ if (outer_code == COMPARE) |
+ *total = 0; |
+ return false; |
+ |
default: |
return false; |
} |
@@ -1857,7 +1900,7 @@ Saved %d bytes via epilogue function (%d vs. %d) in function %s\n", |
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; |
@@ -1931,7 +1974,7 @@ Saved %d bytes via epilogue function (%d vs. %d) in function %s\n", |
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; |
@@ -2023,17 +2066,6 @@ v850_set_data_area (tree decl, v850_data_area data_area) |
(name, NULL, DECL_ATTRIBUTES (decl)); |
} |
-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 |
@@ -2045,8 +2077,8 @@ v850_handle_interrupt_attribute (tree * node, |
{ |
if (TREE_CODE (*node) != FUNCTION_DECL) |
{ |
- warning (OPT_Wattributes, "%qs attribute only applies to functions", |
- IDENTIFIER_POINTER (name)); |
+ warning (OPT_Wattributes, "%qE attribute only applies to functions", |
+ name); |
*no_add_attrs = true; |
} |
@@ -2081,8 +2113,9 @@ v850_handle_data_area_attribute (tree* node, |
case VAR_DECL: |
if (current_function_decl != NULL_TREE) |
{ |
- error ("%Jdata area attributes cannot be specified for " |
- "local variables", decl); |
+ error_at (DECL_SOURCE_LOCATION (decl), |
+ "data area attributes cannot be specified for " |
+ "local variables"); |
*no_add_attrs = true; |
} |
@@ -2934,6 +2967,17 @@ 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); |
+} |
+ |
/* Worker function for TARGET_SETUP_INCOMING_VARARGS. */ |
@@ -2947,4 +2991,43 @@ v850_setup_incoming_varargs (CUMULATIVE_ARGS *ca, |
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); |
+} |
+ |
+ |
+/* 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); |
+} |
+ |
#include "gt-v850.h" |