diff options
author | gjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-05-09 16:28:53 +0000 |
---|---|---|
committer | gjl <gjl@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-05-09 16:28:53 +0000 |
commit | ea6793617689dbadd8265f25f77ba85ee6077711 (patch) | |
tree | 14aca0a603bf73054927ff0215465c4416a351f4 | |
parent | 37ca432506c69627cd91cc76717a1304bfaccabb (diff) | |
download | gcc-ea6793617689dbadd8265f25f77ba85ee6077711.tar.gz |
PR target/53256
* config/avr/elf.h (ASM_DECLARE_FUNCTION_NAME): Remove.
* config/avr/avr-protos.h (avr_asm_declare_function_name): Remove.
* config/avr/avr.h (struct machine_function): Add attributes_checked_p.
* config/avr/avr.c (avr_asm_declare_function_name): Remove.
(expand_prologue): Move initialization of cfun->machine->is_naked,
is_interrupt, is_signal, is_OS_task, is_OS_main from here to...
(avr_set_current_function): ...this new static function.
(TARGET_SET_CURRENT_FUNCTION): New define.
(avr_function_ok_for_sibcall): Use cfun->machine->is_* instead of
checking attributes of current_function_decl.
(avr_regs_to_save): Ditto.
(signal_function_p): Rename to avr_signal_function_p.
(interrupt_function_p): Rename to avr_interrupt_function_p.
* doc/extend.texi (Function Attributes): Better explanation of
'interrupt' and 'signal' for AVR. Move 'ifunc' down to establish
alphabetical order.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@187342 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/config/avr/avr-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/avr/avr.c | 146 | ||||
-rw-r--r-- | gcc/config/avr/avr.h | 4 | ||||
-rw-r--r-- | gcc/config/avr/elf.h | 5 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 118 |
6 files changed, 181 insertions, 114 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7af99fc387c..f32e96f76b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2012-05-09 Georg-Johann Lay <avr@gjlay.de> + + PR target/53256 + * config/avr/elf.h (ASM_DECLARE_FUNCTION_NAME): Remove. + * config/avr/avr-protos.h (avr_asm_declare_function_name): Remove. + * config/avr/avr.h (struct machine_function): Add attributes_checked_p. + * config/avr/avr.c (avr_asm_declare_function_name): Remove. + (expand_prologue): Move initialization of cfun->machine->is_naked, + is_interrupt, is_signal, is_OS_task, is_OS_main from here to... + (avr_set_current_function): ...this new static function. + (TARGET_SET_CURRENT_FUNCTION): New define. + (avr_function_ok_for_sibcall): Use cfun->machine->is_* instead of + checking attributes of current_function_decl. + (avr_regs_to_save): Ditto. + (signal_function_p): Rename to avr_signal_function_p. + (interrupt_function_p): Rename to avr_interrupt_function_p. + + * doc/extend.texi (Function Attributes): Better explanation of + 'interrupt' and 'signal' for AVR. Move 'ifunc' down to establish + alphabetical order. + 2012-05-09 Michael Matz <matz@suse.de> PR tree-optimization/53185 diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h index 158a7be5b3e..fa1462ce886 100644 --- a/gcc/config/avr/avr-protos.h +++ b/gcc/config/avr/avr-protos.h @@ -26,7 +26,6 @@ extern int function_arg_regno_p (int r); extern void avr_cpu_cpp_builtins (struct cpp_reader * pfile); extern enum reg_class avr_regno_reg_class (int r); extern void asm_globalize_label (FILE *file, const char *name); -extern void avr_asm_declare_function_name (FILE *, const char *, tree); extern void order_regs_for_local_alloc (void); extern int avr_initial_elimination_offset (int from, int to); extern int avr_simple_epilogue (void); diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index bf00d88a07b..5b28096d799 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -138,12 +138,6 @@ static const char* out_movqi_mr_r (rtx, rtx[], int*); static const char* out_movhi_mr_r (rtx, rtx[], int*); static const char* out_movsi_mr_r (rtx, rtx[], int*); -static int avr_naked_function_p (tree); -static int interrupt_function_p (tree); -static int signal_function_p (tree); -static int avr_OS_task_function_p (tree); -static int avr_OS_main_function_p (tree); -static int avr_regs_to_save (HARD_REG_SET *); static int get_sequence_length (rtx insns); static int sequent_regs_live (void); static const char *ptrreg_to_str (int); @@ -491,7 +485,7 @@ avr_naked_function_p (tree func) by the "interrupt" attribute. */ static int -interrupt_function_p (tree func) +avr_interrupt_function_p (tree func) { return avr_lookup_function_attribute1 (func, "interrupt"); } @@ -500,7 +494,7 @@ interrupt_function_p (tree func) by the "signal" attribute. */ static int -signal_function_p (tree func) +avr_signal_function_p (tree func) { return avr_lookup_function_attribute1 (func, "signal"); } @@ -522,6 +516,80 @@ avr_OS_main_function_p (tree func) } +/* Implement `TARGET_SET_CURRENT_FUNCTION'. */ +/* Sanity cheching for above function attributes. */ + +static void +avr_set_current_function (tree decl) +{ + location_t loc; + const char *isr; + + if (decl == NULL_TREE + || current_function_decl == NULL_TREE + || current_function_decl == error_mark_node + || cfun->machine->attributes_checked_p) + return; + + loc = DECL_SOURCE_LOCATION (decl); + + cfun->machine->is_naked = avr_naked_function_p (decl); + cfun->machine->is_signal = avr_signal_function_p (decl); + cfun->machine->is_interrupt = avr_interrupt_function_p (decl); + cfun->machine->is_OS_task = avr_OS_task_function_p (decl); + cfun->machine->is_OS_main = avr_OS_main_function_p (decl); + + isr = cfun->machine->is_interrupt ? "interrupt" : "signal"; + + /* Too much attributes make no sense as they request conflicting features. */ + + if (cfun->machine->is_OS_task + cfun->machine->is_OS_main + + (cfun->machine->is_signal || cfun->machine->is_interrupt) > 1) + error_at (loc, "function attributes %qs, %qs and %qs are mutually" + " exclusive", "OS_task", "OS_main", isr); + + /* 'naked' will hide effects of 'OS_task' and 'OS_main'. */ + + if (cfun->machine->is_naked + && (cfun->machine->is_OS_task || cfun->machine->is_OS_main)) + warning_at (loc, OPT_Wattributes, "function attributes %qs and %qs have" + " no effect on %qs function", "OS_task", "OS_main", "naked"); + + if (cfun->machine->is_interrupt || cfun->machine->is_signal) + { + tree args = TYPE_ARG_TYPES (TREE_TYPE (decl)); + tree ret = TREE_TYPE (TREE_TYPE (decl)); + const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); + + /* Silently ignore 'signal' if 'interrupt' is present. AVR-LibC startet + using this when it switched from SIGNAL and INTERRUPT to ISR. */ + + if (cfun->machine->is_interrupt) + cfun->machine->is_signal = 0; + + /* Interrupt handlers must be void __vector (void) functions. */ + + if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE) + error_at (loc, "%qs function cannot have arguments", isr); + + if (TREE_CODE (ret) != VOID_TYPE) + error_at (loc, "%qs function cannot return a value", isr); + + /* If the function has the 'signal' or 'interrupt' attribute, ensure + that the name of the function is "__vector_NN" so as to catch + when the user misspells the vector name. */ + + if (!STR_PREFIX_P (name, "__vector")) + warning_at (loc, 0, "%qs appears to be a misspelled %s handler", + name, isr); + } + + /* Avoid the above diagnosis to be printed more than once. */ + + cfun->machine->attributes_checked_p = 1; +} + + /* Implement `ACCUMULATE_OUTGOING_ARGS'. */ int @@ -570,8 +638,7 @@ static int avr_regs_to_save (HARD_REG_SET *set) { int reg, count; - int int_or_sig_p = (interrupt_function_p (current_function_decl) - || signal_function_p (current_function_decl)); + int int_or_sig_p = cfun->machine->is_interrupt || cfun->machine->is_signal; if (set) CLEAR_HARD_REG_SET (*set); @@ -683,9 +750,9 @@ avr_simple_epilogue (void) && get_frame_size () == 0 && avr_outgoing_args_size() == 0 && avr_regs_to_save (NULL) == 0 - && ! interrupt_function_p (current_function_decl) - && ! signal_function_p (current_function_decl) - && ! avr_naked_function_p (current_function_decl) + && ! cfun->machine->is_interrupt + && ! cfun->machine->is_signal + && ! cfun->machine->is_naked && ! TREE_THIS_VOLATILE (current_function_decl)); } @@ -1096,12 +1163,6 @@ expand_prologue (void) size = get_frame_size() + avr_outgoing_args_size(); - /* Init cfun->machine. */ - cfun->machine->is_naked = avr_naked_function_p (current_function_decl); - cfun->machine->is_interrupt = interrupt_function_p (current_function_decl); - cfun->machine->is_signal = signal_function_p (current_function_decl); - cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl); - cfun->machine->is_OS_main = avr_OS_main_function_p (current_function_decl); cfun->machine->stack_usage = 0; /* Prologue: naked. */ @@ -2458,17 +2519,17 @@ avr_function_ok_for_sibcall (tree decl_callee, tree exp_callee) /* Ensure that caller and callee have compatible epilogues */ - if (interrupt_function_p (current_function_decl) - || signal_function_p (current_function_decl) + if (cfun->machine->is_interrupt + || cfun->machine->is_signal + || cfun->machine->is_naked || avr_naked_function_p (decl_callee) - || avr_naked_function_p (current_function_decl) /* FIXME: For OS_task and OS_main, we are over-conservative. This is due to missing documentation of these attributes and what they actually should do and should not do. */ || (avr_OS_task_function_p (decl_callee) - != avr_OS_task_function_p (current_function_decl)) + != cfun->machine->is_OS_task) || (avr_OS_main_function_p (decl_callee) - != avr_OS_main_function_p (current_function_decl))) + != cfun->machine->is_OS_main)) { return false; } @@ -6656,40 +6717,6 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p) } -/* Worker function for ASM_DECLARE_FUNCTION_NAME. */ - -void -avr_asm_declare_function_name (FILE *file, const char *name, tree decl) -{ - - /* If the function has the 'signal' or 'interrupt' attribute, test to - make sure that the name of the function is "__vector_NN" so as to - catch when the user misspells the interrupt vector name. */ - - if (cfun->machine->is_interrupt) - { - if (!STR_PREFIX_P (name, "__vector")) - { - warning_at (DECL_SOURCE_LOCATION (decl), 0, - "%qs appears to be a misspelled interrupt handler", - name); - } - } - else if (cfun->machine->is_signal) - { - if (!STR_PREFIX_P (name, "__vector")) - { - warning_at (DECL_SOURCE_LOCATION (decl), 0, - "%qs appears to be a misspelled signal handler", - name); - } - } - - ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); - ASM_OUTPUT_LABEL (file, name); -} - - /* Return value is nonzero if pseudos that have been assigned to registers of class CLASS would likely be spilled because registers of CLASS are needed for spill registers. */ @@ -10865,6 +10892,9 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg, #undef TARGET_FUNCTION_ARG_ADVANCE #define TARGET_FUNCTION_ARG_ADVANCE avr_function_arg_advance +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION avr_set_current_function + #undef TARGET_RETURN_IN_MEMORY #define TARGET_RETURN_IN_MEMORY avr_return_in_memory diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index ef98a911b9d..dfbd071d192 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -707,6 +707,10 @@ struct GTY(()) machine_function /* 'true' if a callee might be tail called */ int sibcall_fails; + + /* 'true' if the above is_foo predicates are sanity-checked to avoid + multiple diagnose for the same function. */ + int attributes_checked_p; }; /* AVR does not round pushes, but the existance of this macro is diff --git a/gcc/config/avr/elf.h b/gcc/config/avr/elf.h index ebda5dd11e0..6d79dc38cb8 100644 --- a/gcc/config/avr/elf.h +++ b/gcc/config/avr/elf.h @@ -32,11 +32,6 @@ #undef STRING_LIMIT #define STRING_LIMIT ((unsigned) 64) -/* Take care of `signal' and `interrupt' attributes. */ -#undef ASM_DECLARE_FUNCTION_NAME -#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ - avr_asm_declare_function_name ((FILE), (NAME), (DECL)) - /* Output alignment 2**1 for jump tables. */ #undef ASM_OUTPUT_BEFORE_CASE_LABEL #define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) \ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 5d55ea853a5..22087c35eec 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2714,6 +2714,51 @@ then be sure to write this declaration in both files. This attribute is ignored for R8C target. +@item ifunc ("@var{resolver}") +@cindex @code{ifunc} attribute +The @code{ifunc} attribute is used to mark a function as an indirect +function using the STT_GNU_IFUNC symbol type extension to the ELF +standard. This allows the resolution of the symbol value to be +determined dynamically at load time, and an optimized version of the +routine can be selected for the particular processor or other system +characteristics determined then. To use this attribute, first define +the implementation functions available, and a resolver function that +returns a pointer to the selected implementation function. The +implementation functions' declarations must match the API of the +function being implemented, the resolver's declaration is be a +function returning pointer to void function returning void: + +@smallexample +void *my_memcpy (void *dst, const void *src, size_t len) +@{ + @dots{} +@} + +static void (*resolve_memcpy (void)) (void) +@{ + return my_memcpy; // we'll just always select this routine +@} +@end smallexample + +The exported header file declaring the function the user calls would +contain: + +@smallexample +extern void *memcpy (void *, const void *, size_t); +@end smallexample + +allowing the user to call this as a regular function, unaware of the +implementation. Finally, the indirect function needs to be defined in +the same translation unit as the resolver function: + +@smallexample +void *memcpy (void *, const void *, size_t) + __attribute__ ((ifunc ("resolve_memcpy"))); +@end smallexample + +Indirect functions cannot be weak, and require a recent binutils (at +least version 2.20.1), and GNU C library (at least version 2.11.1). + @item interrupt @cindex interrupt handler functions Use this attribute on the ARM, AVR, CR16, Epiphany, M32C, M32R/D, m68k, MeP, MIPS, @@ -2726,7 +2771,13 @@ code to initialize the interrupt vector table. Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, MicroBlaze, and SH processors can be specified via the @code{interrupt_handler} attribute. -Note, on the AVR, interrupts will be enabled inside the function. +Note, on the AVR, the hardware globally disables interrupts when an +interrupt is executed. The first instruction of an interrupt handler +declared with this attribute will be a @code{SEI} instruction to +re-enable interrupts. See also the @code{signal} function attribute +that does not insert a @code{SEI} instuction. If both @code{signal} and +@code{interrupt} are specified for the same function, @code{signal} +will be silently ignored. Note, for the ARM, you can specify the kind of interrupt to be handled by adding an optional parameter to the interrupt attribute like this: @@ -2822,51 +2873,6 @@ On RL78, use @code{brk_interrupt} instead of @code{interrupt} for handlers intended to be used with the @code{BRK} opcode (i.e. those that must end with @code{RETB} instead of @code{RETI}). -@item ifunc ("@var{resolver}") -@cindex @code{ifunc} attribute -The @code{ifunc} attribute is used to mark a function as an indirect -function using the STT_GNU_IFUNC symbol type extension to the ELF -standard. This allows the resolution of the symbol value to be -determined dynamically at load time, and an optimized version of the -routine can be selected for the particular processor or other system -characteristics determined then. To use this attribute, first define -the implementation functions available, and a resolver function that -returns a pointer to the selected implementation function. The -implementation functions' declarations must match the API of the -function being implemented, the resolver's declaration is be a -function returning pointer to void function returning void: - -@smallexample -void *my_memcpy (void *dst, const void *src, size_t len) -@{ - @dots{} -@} - -static void (*resolve_memcpy (void)) (void) -@{ - return my_memcpy; // we'll just always select this routine -@} -@end smallexample - -The exported header file declaring the function the user calls would -contain: - -@smallexample -extern void *memcpy (void *, const void *, size_t); -@end smallexample - -allowing the user to call this as a regular function, unaware of the -implementation. Finally, the indirect function needs to be defined in -the same translation unit as the resolver function: - -@smallexample -void *memcpy (void *, const void *, size_t) - __attribute__ ((ifunc ("resolve_memcpy"))); -@end smallexample - -Indirect functions cannot be weak, and require a recent binutils (at -least version 2.20.1), and GNU C library (at least version 2.11.1). - @item interrupt_handler @cindex interrupt handler functions on the Blackfin, m68k, H8/300 and SH processors Use this attribute on the Blackfin, m68k, H8/300, H8/300H, H8S, and SH to @@ -3471,11 +3477,23 @@ See long_call/short_call. See longcall/shortcall. @item signal -@cindex signal handler functions on the AVR processors +@cindex interrupt handler functions on the AVR processors Use this attribute on the AVR to indicate that the specified -function is a signal handler. The compiler will generate function -entry and exit sequences suitable for use in a signal handler when this -attribute is present. Interrupts will be disabled inside the function. +function is an interrupt handler. The compiler will generate function +entry and exit sequences suitable for use in an interrupt handler when this +attribute is present. + +See also the @code{interrupt} function attribute. + +The AVR hardware globally disables interrupts when an interrupt is executed. +Interrupt handler functions defined with the @code{signal} attribute +do not re-enable interrupts. It is save to enable interrupts in a +@code{signal} handler. This ``save'' only applies to the code +generated by the compiler and not to the IRQ-layout of the +application which is responsibility of the application. + +If both @code{signal} and @code{interrupt} are specified for the same +function, @code{signal} will be silently ignored. @item sp_switch Use this attribute on the SH to indicate an @code{interrupt_handler} |