@@ -391,6 +391,9 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
cpp_define (pfile, "__WITH_AVRLIBC__");
#endif /* WITH_AVRLIBC */
+ // We support __attribute__((signal (n1, n2, ...))).
+ cpp_define (pfile, "__HAVE_SIGNAL_N__");
+
// From configure --with-libf7={|libgcc|math|math-symbols|yes|no}
#ifdef WITH_LIBF7_LIBGCC
@@ -35,6 +35,7 @@ extern void avr_init_expanders (void);
#ifdef TREE_CODE
extern void avr_asm_output_aligned_decl_common (FILE*, tree, const char*, unsigned HOST_WIDE_INT, unsigned int, bool);
extern void avr_asm_asm_output_aligned_bss (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int, void (*) (FILE *, tree, const char *, unsigned HOST_WIDE_INT, int));
+extern void avr_declare_function_name (FILE *, const char *, tree);
extern void asm_output_external (FILE *file, tree decl, char *name);
extern int avr_progmem_p (tree decl, tree attributes);
extern bool avr_addr_space_supported_p (addr_space_t, location_t loc = UNKNOWN_LOCATION);
@@ -1356,6 +1356,33 @@ avr_lookup_function_attribute1 (const_tree func, const char *name)
return NULL_TREE != lookup_attribute (name, TYPE_ATTRIBUTES (func));
}
+
+/* Call WORKER on all NAME attributes of function FUNC. */
+
+static void
+avr_foreach_function_attribute (tree func, const char *name,
+ void (*worker) (tree, tree, void *),
+ void *cookie)
+{
+ tree attrs = NULL_TREE;
+
+ if (TREE_CODE (func) == FUNCTION_DECL)
+ attrs = DECL_ATTRIBUTES (func);
+ else if (FUNC_OR_METHOD_TYPE_P (func))
+ attrs = TYPE_ATTRIBUTES (TREE_TYPE (func));
+
+ while (attrs)
+ {
+ attrs = lookup_attribute (name, attrs);
+ if (attrs)
+ {
+ worker (func, attrs, cookie);
+ attrs = TREE_CHAIN (attrs);
+ }
+ }
+}
+
+
/* Return nonzero if FUNC is a naked function. */
static bool
@@ -1364,22 +1391,48 @@ avr_naked_function_p (tree func)
return avr_lookup_function_attribute1 (func, "naked");
}
-/* Return nonzero if FUNC is an interrupt function as specified
- by the "interrupt" attribute. */
+/* Return 1 if FUNC is a function that has a "ATTR_NAME" attribute
+ (and perhaps also "ATTR_NAME(num)" attributes. Return -1 if FUNC has
+ "ATTR_NAME(num)" attribute(s) but no "ATTR_NAME" attribute.
+ When no form of ATTR_NAME is present, return 0. */
-static bool
-avr_interrupt_function_p (tree func)
+static int
+avr_interrupt_signal_function (tree func, const char *attr_name)
{
- return avr_lookup_function_attribute1 (func, "interrupt");
+ int res = 0;
+
+ avr_foreach_function_attribute (func, attr_name,
+ [] (tree, tree attr, void *cookie)
+ {
+ int *pcook = (int*) cookie;
+
+ *pcook = TREE_VALUE (attr)
+ ? *pcook ? *pcook : -1
+ : 1;
+ }, &res);
+
+ return res;
}
-/* Return nonzero if FUNC is a signal function as specified
- by the "signal" attribute. */
-static bool
-avr_signal_function_p (tree func)
+/* Return 1 if FUNC is an interrupt function that has an "interrupt" attribute
+ (and perhaps also "interrupt(num)" attributes. Return -1 if FUNC has
+ "interrupt(num)" attribute(s) but no "interrupt" attribute. */
+
+static int
+avr_interrupt_function (tree func)
+{
+ return avr_interrupt_signal_function (func, "interrupt");
+}
+
+/* Return 1 if FUNC is a signal function that has a "signal" attribute
+ (and perhaps also "signal(num)" attributes. Return -1 if FUNC has
+ "signal(num)" attribute(s) but no "signal" attribute. */
+
+static int
+avr_signal_function (tree func)
{
- return avr_lookup_function_attribute1 (func, "signal");
+ return avr_interrupt_signal_function (func, "signal");
}
/* Return nonzero if FUNC is an OS_task function. */
@@ -1437,8 +1490,8 @@ avr_set_current_function (tree decl)
location_t 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_signal = avr_signal_function (decl);
+ cfun->machine->is_interrupt = avr_interrupt_function (decl);
cfun->machine->is_OS_task = avr_OS_task_function_p (decl);
cfun->machine->is_OS_main = avr_OS_main_function_p (decl);
cfun->machine->is_no_gccisr = avr_no_gccisr_function_p (decl);
@@ -1475,23 +1528,25 @@ avr_set_current_function (tree decl)
/* 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);
+ {
+ error_at (loc, "%qs function cannot have arguments", isr);
+ if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ inform (loc, "method %qs has an inplicit %<this%> argument", name);
+ }
if (TREE_CODE (ret) != VOID_TYPE)
error_at (loc, "%qs function cannot return a value", isr);
#if defined WITH_AVRLIBC
- /* 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;
-
/* 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. */
+ when the user misspells the vector name. This check is only
+ required when the "interrupt" resp. "signal" attribute does not
+ have an IRQ-number argument. */
- if (!startswith (name, "__vector"))
+ if (!startswith (name, "__vector")
+ && (cfun->machine->is_interrupt == 1
+ || cfun->machine->is_signal == 1))
warning_at (loc, OPT_Wmisspelled_isr, "%qs appears to be a misspelled "
"%qs handler, missing %<__vector%> prefix", name, isr);
#endif // AVR-LibC naming conventions
@@ -2976,6 +3031,70 @@ avr_expand_prologue (void)
}
+/* Turn TVAL into an integer that represents an ISR number. When no such
+ conversion is possible, then return 0. Unfortunately, we don't know
+ how many IRQs the device actually has. */
+
+static int
+avr_isr_number (tree tval)
+{
+ return (TREE_CODE (tval) == INTEGER_CST
+ && tree_fits_shwi_p (tval)
+ && tree_to_shwi (tval) > 0)
+ ? (int) tree_to_shwi (tval)
+ : 0;
+}
+
+
+struct avr_fun_cookie
+{
+ FILE *file;
+ const char *name;
+ tree decl;
+};
+
+/* A helper for `avr_declare_function_name' below. When the function has
+ attributes like signal(N) or interrupt(N), then define __vector_N as
+ a global alias for the function name. */
+
+static void
+avr_asm_isr_alias (tree /*func*/, tree attr, void *pv)
+{
+ avr_fun_cookie *cookie = (avr_fun_cookie*) pv;
+
+ for (tree v = TREE_VALUE (attr); v; v = TREE_CHAIN (v))
+ {
+ int ival = avr_isr_number (TREE_VALUE (v));
+
+ if (ival)
+ {
+ fprintf (cookie->file, ".global __vector_%d\n", ival);
+ fprintf (cookie->file, "__vector_%d = ", ival);
+ assemble_name (cookie->file, cookie->name);
+ fprintf (cookie->file, "\n");
+ }
+ }
+}
+
+
+/* Worker for `ASM_DECLARE_FUNCTION_NAME'. */
+
+void
+avr_declare_function_name (FILE *file, const char *name, tree decl)
+{
+ // Default action without ASM_DECLARE_FUNCTION_NAME.
+ ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
+
+ avr_fun_cookie fc = { file, name, decl };
+
+ if (cfun->machine->is_signal)
+ avr_foreach_function_attribute (decl, "signal", avr_asm_isr_alias, &fc);
+
+ if (cfun->machine->is_interrupt)
+ avr_foreach_function_attribute (decl, "interrupt", avr_asm_isr_alias, &fc);
+}
+
+
/* Implement `TARGET_ASM_FUNCTION_END_PROLOGUE'. */
/* Output summary at end of function prologue. */
@@ -4366,8 +4485,8 @@ avr_xload_libgcc_p (machine_mode mode)
static rtx
avr_find_unused_d_reg (rtx_insn *insn, rtx exclude)
{
- bool isr_p = (avr_interrupt_function_p (current_function_decl)
- || avr_signal_function_p (current_function_decl));
+ bool isr_p = (avr_interrupt_function (current_function_decl)
+ || avr_signal_function (current_function_decl));
for (int regno = REG_16; regno < REG_32; regno++)
{
@@ -11583,9 +11702,9 @@ TARGET_GNU_ATTRIBUTES (avr_attribute_table,
affects_type_identity, handler, exclude } */
{ "progmem", 0, 0, false, false, false, false,
avr_handle_progmem_attribute, NULL },
- { "signal", 0, 0, true, false, false, false,
+ { "signal", 0, -1, true, false, false, false,
avr_handle_fndecl_attribute, NULL },
- { "interrupt", 0, 0, true, false, false, false,
+ { "interrupt", 0, -1, true, false, false, false,
avr_handle_fndecl_attribute, NULL },
{ "no_gccisr", 0, 0, true, false, false, false,
avr_handle_fndecl_attribute, NULL },
@@ -11815,6 +11934,33 @@ avr_pgm_check_var_decl (tree node)
}
+/* Helper for `avr_insert_attributes'. Print an error when there are invalid
+ attributes named NAME, where NAME is in { "signal", "interrupt" }. */
+
+static void
+avr_handle_isr_attribute (tree, tree *attrs, const char *name)
+{
+ bool seen = false;
+
+ for (tree list = lookup_attribute (name, *attrs); list;
+ list = lookup_attribute (name, TREE_CHAIN (list)))
+ {
+ seen = true;
+ for (tree v = TREE_VALUE (list); v; v = TREE_CHAIN (v))
+ {
+ if (! avr_isr_number (TREE_VALUE (v)))
+ error ("attribute %qs expects a constant positive integer argument",
+ name);
+ }
+ }
+
+ if (seen
+ && ! lookup_attribute ("used", *attrs))
+ {
+ *attrs = tree_cons (get_identifier ("used"), NULL, *attrs);
+ }
+}
+
/* Implement `TARGET_INSERT_ATTRIBUTES'. */
static void
@@ -11847,6 +11993,9 @@ avr_insert_attributes (tree node, tree *attributes)
NULL, *attributes);
}
+ avr_handle_isr_attribute (node, attributes, "signal");
+ avr_handle_isr_attribute (node, attributes, "interrupt");
+
/* Add the section attribute if the variable is in progmem. */
if (VAR_P (node)
@@ -424,6 +424,10 @@ typedef struct avr_args
#define ASM_OUTPUT_ALIGNED_DECL_LOCAL(STREAM, DECL, NAME, SIZE, ALIGN) \
avr_asm_output_aligned_decl_common (STREAM, DECL, NAME, SIZE, ALIGN, true)
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \
+ avr_declare_function_name (STREAM, NAME, DECL)
+
/* Globalizing directive for a label. */
#define GLOBAL_ASM_OP ".global\t"
@@ -548,12 +552,18 @@ struct GTY(()) machine_function
/* 'true' - if current function is a naked function. */
int is_naked;
- /* 'true' - if current function is an interrupt function
- as specified by the "interrupt" attribute. */
+ /* 0 when no "interrupt" attribute is present.
+ 1 when an "interrupt" attribute without arguments is present (and
+ perhaps also "interrupt" attributes with argument(s)).
+ -1 when "interrupt" attribute(s) with arguments are present but none
+ without argument. */
int is_interrupt;
- /* 'true' - if current function is a signal function
- as specified by the "signal" attribute. */
+ /* 0 when no "signal" attribute is present.
+ 1 when a "signal" attribute without arguments is present (and
+ perhaps also "signal" attributes with argument(s)).
+ -1 when "signal" attribute(s) with arguments are present but none
+ without argument. */
int is_signal;
/* 'true' - if current function is a 'task' function
@@ -5136,6 +5136,34 @@ ISR (ADC_vect, ISR_NOBLOCK) // Uses the "interrupt" attribute.
When both @code{signal} and @code{interrupt} are specified for the same
function, then @code{signal} is silently ignored.
+@cindex @code{signal(@var{num})} function attribute, AVR
+@cindex @code{interrupt(@var{num})} function attribute, AVR
+@item signal(@var{num})
+@itemx interrupt(@var{num})
+
+Similar to the @code{signal} resp. @code{interrupt} attribute without
+argument, but the IRQ number is supplied as an argument @var{num} to
+the attribute, rather than providing the ISR name itself as the function name:
+
+@example
+__attribute__((signal(1)))
+void my_handler (void)
+@{
+ // Code for __vector_1
+@}
+
+#include <avr/io.h>
+
+__attribute__((__signal__(PCINT0_vect_num, PCINT1_vect_num)))
+static void my_pcint0_1_handler (void)
+@{
+ // Code for PCINT0 and PCINT1 (__vector_3 and __vector_4
+ // on ATmega328).
+@}
+@end example
+
+Notice that the handler function needs not to be externally visible.
+
@cindex @code{naked} function attribute, AVR
@item naked
This attribute allows the compiler to construct the
@@ -24564,6 +24564,13 @@ and defined to@tie{}0, otherwise.
The compiler is configured to be used together with AVR-Libc.
See the @option{--with-avrlibc} configure option.
+@item __HAVE_SIGNAL_N__
+The compiler supports the @code{signal(@var{num})} and
+@code{interrupt(@var{num})}
+@ref{AVR Function Attributes,,function attributes}
+with an argument @var{num} that specifies the number of the
+interrupt service routine.
+
@item __HAVE_DOUBLE_MULTILIB__
Defined if @option{-mdouble=} acts as a multilib option.
new file mode 100644
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+
+volatile int i;
+
+__attribute__((signal(1,2)))
+static void fun12 (void)
+{
+ __asm goto ("brie %x0" ::: "memory" : l_abort);
+ i += 1234;
+ return;
+
+ l_abort:
+ __asm ("%~jmp abort" ::: "memory");
+}
+
+extern void isr1 (void) __asm("__vector_1");
+extern void isr2 (void) __asm("__vector_2");
+
+int main (void)
+{
+ __asm ("cli" ::: "memory");
+ isr1();
+ if (i != 1234)
+ __builtin_abort ();
+
+ __asm ("cli" ::: "memory");
+ isr2();
+ if (i != 2468)
+ __builtin_abort ();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+
+volatile int i;
+
+__attribute__((interrupt(1),interrupt(2)))
+static void fun12 (void)
+{
+ __asm goto ("brid %x0" ::: "memory" : l_abort);
+ i += 1234;
+ return;
+
+ l_abort:
+ __asm ("%~jmp abort" ::: "memory");
+}
+
+extern void isr1 (void) __asm("__vector_1");
+extern void isr2 (void) __asm("__vector_2");
+
+int main (void)
+{
+ __asm ("cli" ::: "memory");
+ isr1();
+ if (i != 1234)
+ __builtin_abort ();
+
+ __asm ("cli" ::: "memory");
+ isr2();
+ if (i != 2468)
+ __builtin_abort ();
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+__attribute__((signal(0))) static void fun1 (void); /* { dg-error "expects a constant positive integer" } */
+
+__attribute__((signal("1"))) static void fun2 (void); /* { dg-error "expects a constant positive integer" } */
+
+__attribute__((interrupt(-1))) void fun3 (void); /* { dg-error "expects a constant positive integer" } */
+
+__attribute__((interrupt("2"))) void fun4 (void); /* { dg-error "expects a constant positive integer" } */
+
new file mode 100644
@@ -0,0 +1,53 @@
+/* { dg-do run } */
+
+class IRQS
+{
+public:
+ void test (int x) const
+ {
+ if (i != x)
+ __builtin_abort ();
+ }
+
+private:
+ static volatile int i;
+
+ __attribute__((signal(1,2)))
+ static void fun12 ()
+ {
+ i += 1234;
+ }
+};
+
+extern void isr1 () __asm("__vector_1");
+extern void isr2 () __asm("__vector_2");
+extern void isr3 () __asm("__vector_3");
+
+IRQS irqs;
+
+volatile int IRQS::i;
+
+namespace
+{
+ int j;
+ __attribute__((signal(3)))
+ void handle3 ()
+ {
+ j = 444;
+ }
+}
+
+int main (void)
+{
+ isr1();
+ irqs.test (1234);
+
+ isr2();
+ irqs.test (2468);
+
+ isr3 ();
+ if (j != 444)
+ __builtin_abort();
+
+ return 0;
+}