summaryrefslogtreecommitdiff
path: root/gcc/config/epiphany
diff options
context:
space:
mode:
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-07 02:28:06 +0000
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2012-02-07 02:28:06 +0000
commit83debce37b04bed177d54ddcc7eacb7a1b4feb89 (patch)
treee276fcf92c6b5974ac19a30c894e2084e1bb3684 /gcc/config/epiphany
parent55fc45140a6ac4792813df170bdbfd3e007a9f3b (diff)
downloadgcc-83debce37b04bed177d54ddcc7eacb7a1b4feb89.tar.gz
* config/epiphany/epiphany.h (ASM_DECLARE_FUNCTION_SIZE): Redefine,
adding __forwarder_dst__ prefix if a forwarder_section attribute is present. (epiphany_function_type): Replace types for specific interrupts with EPIPHANY_FUNCTION_INTERRUPT. (EPIPHANY_INTERRUPT_P): Update. * config/epiphany/epiphany.c (epiphany_handle_forwarder_attribute): New static function. (epiphany_attribute_table) <interrupt>: min_len is 0, max_len is 9. <disinterrupt>: Affects type identity. (epiphany_handle_interrupt_attribute): Handle variable number of arguments. (epiphany_compute_function_type): Update for new epiphany_function_type definition. (epiphany_expand_prologue): Don't save (reg:DI GPR_0) for interrupt handlers with a longcall forwarder. (epiphany_start_function): Handle multiple interrupt arguments and/or forwarder_section attribute. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183953 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/epiphany')
-rw-r--r--gcc/config/epiphany/epiphany.c148
-rw-r--r--gcc/config/epiphany/epiphany.h36
2 files changed, 127 insertions, 57 deletions
diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c
index a8fc034811b..aff3d1cde6d 100644
--- a/gcc/config/epiphany/epiphany.c
+++ b/gcc/config/epiphany/epiphany.c
@@ -64,6 +64,8 @@ int epiphany_normal_fp_rounding;
static void epiphany_init_reg_tables (void);
static int get_epiphany_condition_code (rtx);
static tree epiphany_handle_interrupt_attribute (tree *, tree, tree, int, bool *);
+static tree epiphany_handle_forwarder_attribute (tree *, tree, tree, int,
+ bool *);
static bool epiphany_pass_by_reference (cumulative_args_t, enum machine_mode,
const_tree, bool);
static rtx frame_insn (rtx);
@@ -410,10 +412,11 @@ epiphany_init_reg_tables (void)
static const struct attribute_spec epiphany_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
- { "interrupt", 1, 1, true, false, false, epiphany_handle_interrupt_attribute, true },
+ { "interrupt", 0, 9, true, false, false, epiphany_handle_interrupt_attribute, true },
+ { "forwarder_section", 1, 1, true, false, false, epiphany_handle_forwarder_attribute, false },
{ "long_call", 0, 0, false, true, true, NULL, false },
{ "short_call", 0, 0, false, true, true, NULL, false },
- { "disinterrupt", 0, 0, false, true, true, NULL, false },
+ { "disinterrupt", 0, 0, false, true, true, NULL, true },
{ NULL, 0, 0, false, false, false, NULL, false }
};
@@ -425,7 +428,12 @@ epiphany_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED,
bool *no_add_attrs)
{
- tree value = TREE_VALUE (args);
+ tree value;
+
+ if (!args)
+ return NULL_TREE;
+
+ value = TREE_VALUE (args);
if (TREE_CODE (value) != STRING_CST)
{
@@ -448,8 +456,31 @@ epiphany_handle_interrupt_attribute (tree *node ATTRIBUTE_UNUSED,
"argument of %qE attribute is not \"reset\", \"software_exception\", \"page_miss\", \"timer0\", \"timer1\", \"message\", \"dma0\", \"dma1\", \"wand\" or \"swi\"",
name);
*no_add_attrs = true;
+ return NULL_TREE;
}
+ return epiphany_handle_interrupt_attribute (node, name, TREE_CHAIN (args),
+ flags, no_add_attrs);
+}
+
+/* Handle a "forwarder_section" attribute; arguments as in
+ struct attribute_spec.handler. */
+static tree
+epiphany_handle_forwarder_attribute (tree *node ATTRIBUTE_UNUSED,
+ tree name, tree args,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ tree value;
+
+ value = TREE_VALUE (args);
+
+ if (TREE_CODE (value) != STRING_CST)
+ {
+ warning (OPT_Wattributes,
+ "argument of %qE attribute is not a string constant", name);
+ *no_add_attrs = true;
+ }
return NULL_TREE;
}
@@ -883,38 +914,10 @@ epiphany_compute_function_type (tree decl)
a;
a = TREE_CHAIN (a))
{
- tree name = TREE_PURPOSE (a), args = TREE_VALUE (a);
+ tree name = TREE_PURPOSE (a);
- if (name == get_identifier ("interrupt")
- && list_length (args) == 1
- && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
- {
- tree value = TREE_VALUE (args);
-
- if (!strcmp (TREE_STRING_POINTER (value), "reset"))
- fn_type = EPIPHANY_FUNCTION_RESET;
- else if (!strcmp (TREE_STRING_POINTER (value), "software_exception"))
- fn_type = EPIPHANY_FUNCTION_SOFTWARE_EXCEPTION;
- else if (!strcmp (TREE_STRING_POINTER (value), "page_miss"))
- fn_type = EPIPHANY_FUNCTION_PAGE_MISS;
- else if (!strcmp (TREE_STRING_POINTER (value), "timer0"))
- fn_type = EPIPHANY_FUNCTION_TIMER0;
- else if (!strcmp (TREE_STRING_POINTER (value), "timer1"))
- fn_type = EPIPHANY_FUNCTION_TIMER1;
- else if (!strcmp (TREE_STRING_POINTER (value), "message"))
- fn_type = EPIPHANY_FUNCTION_MESSAGE;
- else if (!strcmp (TREE_STRING_POINTER (value), "dma0"))
- fn_type = EPIPHANY_FUNCTION_DMA0;
- else if (!strcmp (TREE_STRING_POINTER (value), "dma1"))
- fn_type = EPIPHANY_FUNCTION_DMA1;
- else if (!strcmp (TREE_STRING_POINTER (value), "wand"))
- fn_type = EPIPHANY_FUNCTION_WAND;
- else if (!strcmp (TREE_STRING_POINTER (value), "swi"))
- fn_type = EPIPHANY_FUNCTION_SWI;
- else
- gcc_unreachable ();
- break;
- }
+ if (name == get_identifier ("interrupt"))
+ fn_type = EPIPHANY_FUNCTION_INTERRUPT;
}
last_fn = decl;
@@ -1645,8 +1648,12 @@ epiphany_expand_prologue (void)
{
addr = plus_constant (stack_pointer_rtx,
- (HOST_WIDE_INT) 2 * UNITS_PER_WORD);
- frame_move_insn (gen_frame_mem (DImode, addr),
- gen_rtx_REG (DImode, GPR_0));
+ if (!lookup_attribute ("forwarder_section",
+ DECL_ATTRIBUTES (current_function_decl))
+ || !epiphany_is_long_call_p (XEXP (DECL_RTL (current_function_decl),
+ 0)))
+ frame_move_insn (gen_frame_mem (DImode, addr),
+ gen_rtx_REG (DImode, GPR_0));
frame_move_insn (gen_rtx_REG (SImode, GPR_0),
gen_rtx_REG (word_mode, STATUS_REGNUM));
frame_move_insn (gen_rtx_REG (SImode, GPR_0+1),
@@ -2760,24 +2767,69 @@ epiphany_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
void
epiphany_start_function (FILE *file, const char *name, tree decl)
{
- tree attrs, int_attr;
+ /* If the function doesn't fit into the on-chip memory, it will have a
+ section attribute - or lack of it - that denotes it goes somewhere else.
+ But the architecture spec says that an interrupt vector still has to
+ point to on-chip memory. So we must place a jump there to get to the
+ actual function implementation. The forwarder_section attribute
+ specifies the section where this jump goes.
+ This mechanism can also be useful to have a shortcall destination for
+ a function that is actually placed much farther away. */
+ tree attrs, int_attr, int_names, int_name, forwarder_attr;
attrs = DECL_ATTRIBUTES (decl);
int_attr = lookup_attribute ("interrupt", attrs);
if (int_attr)
- {
- char buf[99];
- const char *fname;
+ for (int_names = TREE_VALUE (int_attr); int_names;
+ int_names = TREE_CHAIN (int_names))
+ {
+ char buf[99];
+
+ int_name = TREE_VALUE (int_names);
+ sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_name));
+ switch_to_section (get_section (buf, SECTION_CODE, decl));
+ fputs ("\tb\t", file);
+ assemble_name (file, name);
+ fputc ('\n', file);
+ }
+ forwarder_attr = lookup_attribute ("forwarder_section", attrs);
+ if (forwarder_attr)
+ {
+ const char *prefix = "__forwarder_dst_";
+ char *dst_name = (char *) alloca (strlen (prefix) + strlen (name) + 1);
+
+ strcpy (dst_name, prefix);
+ strcat (dst_name, name);
+ forwarder_attr = TREE_VALUE (TREE_VALUE (forwarder_attr));
+ switch_to_section (get_section (TREE_STRING_POINTER (forwarder_attr),
+ SECTION_CODE, decl));
+ ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
+ if (epiphany_is_long_call_p (XEXP (DECL_RTL (decl), 0)))
+ {
+ int tmp = GPR_0;
- int_attr = TREE_VALUE (TREE_VALUE (int_attr));
- sprintf (buf, "ivt_entry_%.80s", TREE_STRING_POINTER (int_attr));
- switch_to_section (get_section (buf, SECTION_CODE, decl));
- fname = XSTR (XEXP (DECL_RTL (decl), 0), 0);
- fputs ("\tb\t", file);
- assemble_name (file, fname);
- fputc ('\n', file);
- switch_to_section (function_section (decl));
+ if (int_attr)
+ fputs ("\tstrd r0,[sp,-1]\n", file);
+ else
+ tmp = GPR_16;
+ gcc_assert (call_used_regs[tmp]);
+ fprintf (file, "\tmov r%d,%%low(", tmp);
+ assemble_name (file, dst_name);
+ fprintf (file, ")\n"
+ "\tmovt r%d,%%high(", tmp);
+ assemble_name (file, dst_name);
+ fprintf (file, ")\n"
+ "\tjr r%d\n", tmp);
+ }
+ else
+ {
+ fputs ("\tb\t", file);
+ assemble_name (file, dst_name);
+ fputc ('\n', file);
+ }
+ name = dst_name;
}
+ switch_to_section (function_section (decl));
ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
}
diff --git a/gcc/config/epiphany/epiphany.h b/gcc/config/epiphany/epiphany.h
index f92e1973e36..572ec7ecb3f 100644
--- a/gcc/config/epiphany/epiphany.h
+++ b/gcc/config/epiphany/epiphany.h
@@ -778,6 +778,31 @@ do { \
to a multiple of 2**LOG bytes. */
#define ASM_OUTPUT_ALIGN(FILE,LOG) \
do { if ((LOG) != 0) fprintf (FILE, "\t.balign %d\n", 1 << (LOG)); } while (0)
+
+/* This is how to declare the size of a function. */
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do \
+ { \
+ const char *__name = (FNAME); \
+ tree attrs = DECL_ATTRIBUTES ((DECL)); \
+ \
+ if (!flag_inhibit_size_directive) \
+ { \
+ if (lookup_attribute ("forwarder_section", attrs)) \
+ { \
+ const char *prefix = "__forwarder_dst_"; \
+ char *dst_name \
+ = (char *) alloca (strlen (prefix) + strlen (__name) + 1); \
+ \
+ strcpy (dst_name, prefix); \
+ strcat (dst_name, __name); \
+ __name = dst_name; \
+ } \
+ ASM_OUTPUT_MEASURED_SIZE ((FILE), __name); \
+ } \
+ } \
+ while (0)
/* Debugging information. */
@@ -831,17 +856,10 @@ do { if ((LOG) != 0) fprintf (FILE, "\t.balign %d\n", 1 << (LOG)); } while (0)
enum epiphany_function_type
{
EPIPHANY_FUNCTION_UNKNOWN, EPIPHANY_FUNCTION_NORMAL,
- /* These are interrupt handlers. The name corresponds to which type
- of interrupt handler we're dealing with. */
- EPIPHANY_FUNCTION_RESET, EPIPHANY_FUNCTION_SOFTWARE_EXCEPTION,
- EPIPHANY_FUNCTION_PAGE_MISS,
- EPIPHANY_FUNCTION_TIMER0, EPIPHANY_FUNCTION_TIMER1, EPIPHANY_FUNCTION_MESSAGE,
- EPIPHANY_FUNCTION_DMA0, EPIPHANY_FUNCTION_DMA1, EPIPHANY_FUNCTION_WAND,
- EPIPHANY_FUNCTION_SWI
+ EPIPHANY_FUNCTION_INTERRUPT
};
-#define EPIPHANY_INTERRUPT_P(TYPE) \
- ((TYPE) >= EPIPHANY_FUNCTION_RESET && (TYPE) <= EPIPHANY_FUNCTION_SWI)
+#define EPIPHANY_INTERRUPT_P(TYPE) ((TYPE) == EPIPHANY_FUNCTION_INTERRUPT)
/* Compute the type of a function from its DECL. */