https://gcc.gnu.org/g:0f1de0c4ce6eb237128d8f6439c2434aded1f51a

commit r15-2367-g0f1de0c4ce6eb237128d8f6439c2434aded1f51a
Author: Georg-Johann Lay <a...@gjlay.de>
Date:   Wed Jul 24 08:37:43 2024 +0200

    AVR target 116056 - Support attribute signal(n), interrupt(n) and noblock.
    
    This patch adds support for arguments to the signal and interrupt
    function attributes.  It allows to specify the ISR by means of the
    associated IRQ number, in extension to the current attributes that
    require to specify the ISR name like "__vector_1" as (assembly) name
    for the function.  The new feature is more convenient, e.g. when the
    ISR is implemented by a class method or in a namespace.  There is no
    requirement that the ISR is externally visible.  The syntax is like:
    
    __attribute__((signal(1, 2, ...), signal(3, 4, ...)))
    [static] void isr_function (void)
    {
        // Code
    }
    
    Moreover, this patch adds support for the "noblock" function attribute
    to let an ISR start with a SEI instruction.  Attribute "signal" together
    with "noblock" behaves like "interrupt" but without imposing a specific
    function name or visibility like "interrupt" does.
    
            PR target/116056
    gcc/
            * config/avr/avr.h (machine_function) <is_noblock>: New field.
            * config/avr/avr-c.cc (avr_cpu_cpp_builtins) <__HAVE_SIGNAL_N__>: 
New
            built-in macro.
            * config/avr/avr.cc (avr_declare_function_name): New function.
            (avr_attribute_table) <noblock>: New function attribute>.
            <signal, interrupt>: Allow any number of args.
            (avr_insert_attributes): Check validity of "signal" and "interrupt"
            arguments.
            (avr_foreach_function_attribute, avr_interrupt_signal_function)
            (avr_isr_number, avr_asm_isr_alias, avr_handle_isr_attribute)
            (avr_noblock_function_p): New static functions.
            (avr_interrupt_function): New from avr_interrupt_function_p.
            Adjust callers.
            (avr_signal_function): New from avr_signal_function_p.
            Adjust callers.
            (avr_set_current_function): Only diagnose non-__vector ISR names
            when "signal" or "interrupt" attribute has no args. Set
            cfun->machine->is_noblock.  Warn about "noblock" in non-ISR 
functions.
            (struct avr_fun_cookie): New.
            (avr_expand_prologue, avr_asm_function_end_prologue): Handle 
"noblock".
            * config/avr/elf.h (ASM_DECLARE_FUNCTION_NAME): New define.
            * config/avr/avr-protos.h (avr_declare_function_name): New proto.
            * doc/extend.texi (AVR Function Attributes): Document
            signal(num) and interrupt(num).
            * doc/invoke.texi (AVR Built-in Macros) <__HAVE_SIGNAL_N__>: 
Document.
    gcc/testsuite/
            * gcc.target/avr/torture/signal_n-1.c: New test.
            * gcc.target/avr/torture/signal_n-2.c: New test.
            * gcc.target/avr/torture/signal_n-3.c: New test.
            * gcc.target/avr/torture/signal_n-4.cpp: New test.

Diff:
---
 gcc/config/avr/avr-c.cc                            |   4 +
 gcc/config/avr/avr-protos.h                        |   1 +
 gcc/config/avr/avr.cc                              | 226 ++++++++++++++++++---
 gcc/config/avr/avr.h                               |  18 +-
 gcc/config/avr/elf.h                               |   4 +
 gcc/doc/extend.texi                                |  38 ++++
 gcc/doc/invoke.texi                                |   7 +
 gcc/testsuite/gcc.target/avr/torture/signal_n-1.c  |  49 +++++
 gcc/testsuite/gcc.target/avr/torture/signal_n-2.c  |  32 +++
 gcc/testsuite/gcc.target/avr/torture/signal_n-3.c  |  13 ++
 .../gcc.target/avr/torture/signal_n-4.cpp          |  53 +++++
 11 files changed, 413 insertions(+), 32 deletions(-)

diff --git a/gcc/config/avr/avr-c.cc b/gcc/config/avr/avr-c.cc
index 5e7f759ed738..ca484f26132a 100644
--- a/gcc/config/avr/avr-c.cc
+++ b/gcc/config/avr/avr-c.cc
@@ -391,6 +391,10 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
   cpp_define (pfile, "__WITH_AVRLIBC__");
 #endif /* WITH_AVRLIBC */
 
+  // We support __attribute__((signal/interrupt (n1, n2, ...)[, noblock]))
+  cpp_define (pfile, "__HAVE_SIGNAL_N__");
+
+
   // From configure --with-libf7={|libgcc|math|math-symbols|yes|no}
 
 #ifdef WITH_LIBF7_LIBGCC
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index 5fdb13057570..7b666f17718d 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -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);
diff --git a/gcc/config/avr/avr.cc b/gcc/config/avr/avr.cc
index e941730452e5..dffb7e056bec 100644
--- a/gcc/config/avr/avr.cc
+++ b/gcc/config/avr/avr.cc
@@ -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,56 @@ 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 nonzero if FUNC is a noblock function.  */
 
 static bool
-avr_interrupt_function_p (tree func)
+avr_noblock_function_p (tree func)
 {
-  return avr_lookup_function_attribute1 (func, "interrupt");
+  return avr_lookup_function_attribute1 (func, "noblock");
 }
 
-/* Return nonzero if FUNC is a signal function as specified
-   by the "signal" 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_signal_function_p (tree func)
+static int
+avr_interrupt_signal_function (tree func, const char *attr_name)
 {
-  return avr_lookup_function_attribute1 (func, "signal");
+  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 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_interrupt_signal_function (func, "signal");
 }
 
 /* Return nonzero if FUNC is an OS_task function.  */
@@ -1437,8 +1498,9 @@ 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_noblock = avr_noblock_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);
   cfun->machine->is_no_gccisr = avr_no_gccisr_function_p (decl);
@@ -1475,27 +1537,34 @@ 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
     }
+  else if (cfun->machine->is_noblock)
+    {
+      warning (OPT_Wattributes, "%qs attribute ignored on non-ISR function",
+              "noblock");
+    }
 
 #if defined WITH_AVRLIBC
   // Common problem is using "ISR" without first including avr/interrupt.h.
@@ -2793,11 +2862,14 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, 
HARD_REG_SET set)
             Always move through unspec, see PR50063.
             For meaning of irq_state see movhi_sp_r insn.  */
 
-         if (cfun->machine->is_interrupt)
+         if (cfun->machine->is_interrupt
+             || (cfun->machine->is_signal
+                 && cfun->machine->is_noblock))
            irq_state = 1;
 
          if (TARGET_NO_INTERRUPTS
-             || cfun->machine->is_signal
+             || (cfun->machine->is_signal
+                 && ! cfun->machine->is_noblock)
              || cfun->machine->is_OS_main)
            irq_state = 0;
 
@@ -2892,7 +2964,8 @@ avr_expand_prologue (void)
     {
       int treg = AVR_TMP_REGNO;
       /* Enable interrupts.  */
-      if (cfun->machine->is_interrupt)
+      if (cfun->machine->is_interrupt
+         || cfun->machine->is_noblock)
        emit_insn (gen_enable_interrupt ());
 
       if (cfun->machine->gasisr.maybe)
@@ -2976,6 +3049,68 @@ 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;
+};
+
+/* 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 from elfos.h.
+  ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
+  ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
+  ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
+
+  avr_fun_cookie fc = { file, name };
+
+  avr_foreach_function_attribute (decl, "signal", avr_asm_isr_alias, &fc);
+  avr_foreach_function_attribute (decl, "interrupt", avr_asm_isr_alias, &fc);
+}
+
+
 /* Implement `TARGET_ASM_FUNCTION_END_PROLOGUE'.  */
 /* Output summary at end of function prologue.  */
 
@@ -2988,7 +3123,9 @@ avr_asm_function_end_prologue (FILE *file)
     }
   else
     {
-      if (cfun->machine->is_interrupt)
+      if (cfun->machine->is_interrupt
+         || (cfun->machine->is_signal
+             && cfun->machine->is_noblock))
        {
          fputs ("/* prologue: Interrupt */\n", file);
        }
@@ -4366,8 +4503,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++)
     {
@@ -11385,6 +11522,7 @@ avr_class_likely_spilled_p (reg_class_t c)
                After function prologue interrupts remain disabled.
    interrupt - Make a function to be hardware interrupt. Before function
                prologue interrupts are enabled by means of SEI.
+   noblock   - The function is an ISR that starts with a SEI instruction.
    naked     - Don't generate function prologue/epilogue and RET
                instruction.  */
 
@@ -11583,9 +11721,11 @@ 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 },
+  { "noblock", 0, 0, true,  false, false, false,
     avr_handle_fndecl_attribute, NULL },
   { "no_gccisr", 0, 0, true,  false, false, false,
     avr_handle_fndecl_attribute, NULL },
@@ -11815,6 +11955,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 +12014,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)
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 4977e15eeede..56b7f39b8344 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -548,14 +548,24 @@ 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 non-blocking interrupt service
+     routine as specified by the "isr_noblock" attribute.  */
+  int is_noblock;
+
   /* 'true' - if current function is a 'task' function 
      as specified by the "OS_task" attribute.  */
   int is_OS_task;
diff --git a/gcc/config/avr/elf.h b/gcc/config/avr/elf.h
index e334deeb79cf..0112aa3d4327 100644
--- a/gcc/config/avr/elf.h
+++ b/gcc/config/avr/elf.h
@@ -31,3 +31,7 @@
 /* Be conservative in crtstuff.c.  */
 #undef INIT_SECTION_ASM_OP
 #undef FINI_SECTION_ASM_OP
+
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(STREAM, NAME, DECL) \
+       avr_declare_function_name (STREAM, NAME, DECL)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 66c99ef7a667..927aa24ab635 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5136,6 +5136,44 @@ 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{noblock} function attribute, AVR
+@item noblock
+
+This attribute can be used together with the @code{signal} attribute
+to indicate that an interrupt service routine should start with a @code{SEI}
+instruction to globally re-enable interrupts. Using attributes @code{signal}
+and @code{noblock} together has the same effect like using the @code{interrupt}
+attribute.  Using the @code{noblock} attribute without @code{signal} has no
+effect.
+
 @cindex @code{naked} function attribute, AVR
 @item naked
 This attribute allows the compiler to construct the
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9fb0925ed292..e495b1271fa7 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -24569,6 +24569,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.
 
diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-1.c 
b/gcc/testsuite/gcc.target/avr/torture/signal_n-1.c
new file mode 100644
index 000000000000..d5f422d2d990
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-1.c
@@ -0,0 +1,49 @@
+/* { 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");
+}
+
+__attribute__((signal(3),noblock))
+static void fun3 (void)
+{
+  __asm goto ("brid %x0" ::: "memory" : l_abort);
+  i += 333;
+  return;
+  
+ l_abort:
+  __asm ("%~jmp abort" ::: "memory");
+}
+
+extern void isr1 (void) __asm("__vector_1");
+extern void isr2 (void) __asm("__vector_2");
+extern void isr3 (void) __asm("__vector_3");
+
+int main (void)
+{
+  __asm ("cli" ::: "memory");
+  isr1();
+  if (i != 1234)
+    __builtin_abort ();
+
+  __asm ("cli" ::: "memory");
+  isr2();
+  if (i != 2468)
+    __builtin_abort ();
+
+  __asm ("cli" ::: "memory");
+  isr3();
+  if (i != 2468 + 333)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-2.c 
b/gcc/testsuite/gcc.target/avr/torture/signal_n-2.c
new file mode 100644
index 000000000000..f6cc19d9842b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-2.c
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-3.c 
b/gcc/testsuite/gcc.target/avr/torture/signal_n-3.c
new file mode 100644
index 000000000000..55f7d14543d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Wattributes" } */
+
+__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" } */
+
+__attribute__((noblock)) void fun5 (void) { } /* { dg-warning "attribute 
ignored on non-ISR" } */
+
diff --git a/gcc/testsuite/gcc.target/avr/torture/signal_n-4.cpp 
b/gcc/testsuite/gcc.target/avr/torture/signal_n-4.cpp
new file mode 100644
index 000000000000..749fe3cce783
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/torture/signal_n-4.cpp
@@ -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;
+}

Reply via email to