From 83debce37b04bed177d54ddcc7eacb7a1b4feb89 Mon Sep 17 00:00:00 2001 From: amylaar Date: Tue, 7 Feb 2012 02:28:06 +0000 Subject: [PATCH] * 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) : min_len is 0, max_len is 9. : 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 --- gcc/ChangeLog | 21 ++++++ gcc/config/epiphany/epiphany.c | 148 ++++++++++++++++++++++++++++------------- gcc/config/epiphany/epiphany.h | 36 +++++++--- 3 files changed, 148 insertions(+), 57 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3307d71..2821874 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2012-02-07 Joern Rennecke + + * 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) : min_len is 0, max_len is 9. + : 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. + 2012-02-07 Alan Modra PR target/52107 diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c index a8fc034..aff3d1c 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 f92e197..572ec7e 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. */ -- 2.7.4