Functions with interrupt or no_caller_saved_registers attribute should
have different function pointer types from those without the attribute
since they require different prologue and epilogue.  2 functions with
different interrupt or no_caller_saved_registers attribute, which are
otherwise equivalent, aren't identical.

In case of 2 identical functions with interrupt attribute, we issue an
error after the ICF merge to detect duplicated interrupt handlers to
reduce code size which is very important in embedded environment.  The
alternatives are

1. Disable the ICF merge, which leads to duplicated codes.
2. Allow the ICF merge and convert the ICF tail call to a jump, which
requires codegen changes in prologue and epilogue of interrupt handlers
as well as an extra jump.

OK for trunk if there is no regression on i686 and x86-64?

H.J.
---
gcc/

        PR target/78098
        * config/i386/i386.c (ix86_comp_type_attributes): Return 0 if
        interrupt or no_caller_saved_registers attribute is different.
        (ix86_expand_call): Issue a note when interrupt handler is
        merged.
        (ix86_attribute_table): Change the affects_type_identity field
        to true for interrupt and no_caller_saved_registers attributes.

gcc/testsuite/

        PR target/78098
        * gcc.target/i386/interrupt-1.c: Updated.
        * gcc.target/i386/interrupt-6.c: Likewise.
        * gcc.target/i386/interrupt-7.c: Likewise.
        * gcc.target/i386/interrupt-16.c: Likewise.
        * gcc.target/i386/interrupt-17.c: Likewise.
        * gcc.target/i386/interrupt-iamcu.c: Likewise.
        * gcc.target/i386/interrupt-sibcall-1.c: Likewise.
        * gcc.target/i386/interrupt-sibcall-2.c: Likewise.
        * gcc.target/i386/pr78098-1.c: New test.
        * gcc.target/i386/pr78098-2.c: Likewise.
        * gcc.target/i386/pr78098-3.c: Likewise.
        * gcc.target/i386/pr78098-4.c: Likewise.
        * gcc.target/i386/pr78098-5.c: Likewise.
        * gcc.target/i386/pr78098-6.c: Likewise.
        * gcc.target/i386/pr78098-7.c: Likewise.
        * gcc.target/i386/pr78098-8.c: Likewise.
        * gcc.target/i386/pr78098-9.c: Likewise.
---
 gcc/config/i386/i386.c                             | 30 +++++++++++++++++++---
 gcc/testsuite/gcc.target/i386/interrupt-1.c        |  1 +
 gcc/testsuite/gcc.target/i386/interrupt-16.c       |  1 +
 gcc/testsuite/gcc.target/i386/interrupt-17.c       |  1 +
 gcc/testsuite/gcc.target/i386/interrupt-6.c        |  3 ++-
 gcc/testsuite/gcc.target/i386/interrupt-iamcu.c    |  1 +
 .../gcc.target/i386/interrupt-sibcall-1.c          |  1 +
 .../gcc.target/i386/interrupt-sibcall-2.c          |  1 +
 gcc/testsuite/gcc.target/i386/pr78098-1.c          | 18 +++++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-2.c          | 19 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-3.c          | 19 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-4.c          | 19 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-5.c          | 19 ++++++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-6.c          | 13 ++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-7.c          | 12 +++++++++
 gcc/testsuite/gcc.target/i386/pr78098-8.c          | 13 ++++++++++
 gcc/testsuite/gcc.target/i386/pr78098-9.c          | 12 +++++++++
 17 files changed, 179 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr78098-9.c

diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index f70eb43..2dbabf5 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -7729,6 +7729,18 @@ ix86_comp_type_attributes (const_tree type1, const_tree 
type2)
       && TREE_CODE (type1) != METHOD_TYPE)
     return 1;
 
+  if ((lookup_attribute ("interrupt",
+                        TYPE_ATTRIBUTES (type1)) != NULL)
+       != (lookup_attribute ("interrupt",
+                            TYPE_ATTRIBUTES (type2)) != NULL))
+    return 0;
+
+  if ((lookup_attribute ("no_caller_saved_registers",
+                        TYPE_ATTRIBUTES (type1)) != NULL)
+       != (lookup_attribute ("no_caller_saved_registers",
+                            TYPE_ATTRIBUTES (type2)) != NULL))
+    return 0;
+
   ccvt1 = ix86_get_callcvt (type1);
   ccvt2 = ix86_get_callcvt (type2);
   if (ccvt1 != ccvt2)
@@ -28019,7 +28031,19 @@ ix86_expand_call (rtx retval, rtx fnaddr, rtx callarg1,
       if (fndecl
          && (lookup_attribute ("interrupt",
                                TYPE_ATTRIBUTES (TREE_TYPE (fndecl)))))
-       error ("interrupt service routine can't be called directly");
+       {
+         if (lookup_attribute ("interrupt",
+                               TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))
+             && cgraph_node::get (cfun->decl)->icf_merged)
+           {
+             error ("interrupt service routine is merged");
+             inform (input_location,
+                     "interrupt service routine %q+D is equivalent to %q+D",
+                     cfun->decl, fndecl);
+           }
+         else
+           error ("interrupt service routine can't be called directly");
+       }
     }
   else
     fndecl = NULL_TREE;
@@ -44977,9 +45001,9 @@ static const struct attribute_spec 
ix86_attribute_table[] =
   { "callee_pop_aggregate_return", 1, 1, false, true, true,
     ix86_handle_callee_pop_aggregate_return, true },
   { "interrupt", 0, 0, false, true, true,
-    ix86_handle_interrupt_attribute, false },
+    ix86_handle_interrupt_attribute, true },
   { "no_caller_saved_registers", 0, 0, false, true, true,
-    ix86_handle_no_caller_saved_registers_attribute, false },
+    ix86_handle_no_caller_saved_registers_attribute, true },
 
   /* End element.  */
   { NULL,        0, 0, false, false, false, NULL, false }
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-1.c 
b/gcc/testsuite/gcc.target/i386/interrupt-1.c
index 3dfe3d8..c82ed5c 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-1.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-1.c
@@ -4,6 +4,7 @@
 extern void foo (void *) __attribute__ ((interrupt));
 extern int bar (int);
 
+__attribute__ ((interrupt))
 void foo (void *frame)
 {
   int a,b,c,d,e,f,i;
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-16.c 
b/gcc/testsuite/gcc.target/i386/interrupt-16.c
index bc929c6..98c3d8e 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-16.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-16.c
@@ -4,6 +4,7 @@
 extern int foo (int) __attribute__ ((no_caller_saved_registers));
 extern int bar (int) __attribute__ ((no_caller_saved_registers));
 
+__attribute__ ((no_caller_saved_registers))
 int
 foo (int i)
 {
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-17.c 
b/gcc/testsuite/gcc.target/i386/interrupt-17.c
index 5d5b59e..a2b7556 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-17.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-17.c
@@ -4,6 +4,7 @@
 extern int foo (int) __attribute__ ((no_caller_saved_registers));
 extern int bar (int) __attribute__ ((no_caller_saved_registers));
 
+ __attribute__ ((no_caller_saved_registers))
 int
 foo (int i)
 {
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-6.c 
b/gcc/testsuite/gcc.target/i386/interrupt-6.c
index 2a0266a..998a834 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-6.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-6.c
@@ -33,8 +33,9 @@ fn4 (uword_t error_code, void *frame)
 
 extern int fn5 (void *) __attribute__ ((interrupt)); /* { dg-error "interrupt 
service routine can't have non-void return value" } */
 
+__attribute__ ((interrupt))
 int
 fn5 (void *frame)
-{
+{ /* { dg-error "interrupt service routine can't have non-void return value" } 
*/
   return 0;
 }
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c 
b/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c
index c2256ef..b8aaa0f 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-iamcu.c
@@ -4,6 +4,7 @@
 extern void foo (void *) __attribute__ ((interrupt));
 extern int bar (int);
 
+__attribute__ ((interrupt))
 void foo (void *frame)
 {
   int a,b,c,d,e,f,i;
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-sibcall-1.c 
b/gcc/testsuite/gcc.target/i386/interrupt-sibcall-1.c
index e2cda61..564d426 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-sibcall-1.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-sibcall-1.c
@@ -4,6 +4,7 @@
 extern void foo (void *) __attribute__ ((interrupt));
 extern void bar (void);
 
+__attribute__ ((interrupt))
 void foo (void *frame)
 {
   bar ();
diff --git a/gcc/testsuite/gcc.target/i386/interrupt-sibcall-2.c 
b/gcc/testsuite/gcc.target/i386/interrupt-sibcall-2.c
index f59253a..d8f4b5d 100644
--- a/gcc/testsuite/gcc.target/i386/interrupt-sibcall-2.c
+++ b/gcc/testsuite/gcc.target/i386/interrupt-sibcall-2.c
@@ -5,6 +5,7 @@
 extern void foo (void *) __attribute__ ((interrupt));
 extern void bar (void) __attribute__ ((no_caller_saved_registers));
 
+__attribute__ ((interrupt))
 void foo (void *frame)
 {
   bar ();
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-1.c 
b/gcc/testsuite/gcc.target/i386/pr78098-1.c
new file mode 100644
index 0000000..2096913
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+__attribute__((interrupt))
+void foo1 (void *p) /* { dg-error "interrupt service routine" } */
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+__attribute__((interrupt))
+void foo2 (void *p) /* { dg-message "note: interrupt service routine" } */
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-2.c 
b/gcc/testsuite/gcc.target/i386/pr78098-2.c
new file mode 100644
index 0000000..faadb80
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-2.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+__attribute__((interrupt))
+void foo2 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+/* { dg-final { scan-assembler-times "call\t_?bar" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-3.c 
b/gcc/testsuite/gcc.target/i386/pr78098-3.c
new file mode 100644
index 0000000..8158ca0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-3.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+__attribute__((interrupt))
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+void foo2 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+/* { dg-final { scan-assembler-times "call\t_?bar" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-4.c 
b/gcc/testsuite/gcc.target/i386/pr78098-4.c
new file mode 100644
index 0000000..35016f5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-4.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+__attribute__((no_caller_saved_registers))
+void foo2 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+/* { dg-final { scan-assembler-times "call\t_?bar" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-5.c 
b/gcc/testsuite/gcc.target/i386/pr78098-5.c
new file mode 100644
index 0000000..d4ce241
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-5.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+__attribute__((no_caller_saved_registers))
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+void foo2 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+/* { dg-final { scan-assembler-times "call\t_?bar" 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-6.c 
b/gcc/testsuite/gcc.target/i386/pr78098-6.c
new file mode 100644
index 0000000..45724f6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-6.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+__attribute__((interrupt))
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+void (*foo2) (void *) = foo1; /* { dg-message "incompatible pointer type" } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-7.c 
b/gcc/testsuite/gcc.target/i386/pr78098-7.c
new file mode 100644
index 0000000..7343826
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-7.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+void (*foo2) (void *) __attribute__((interrupt)) = foo1; /* { dg-message 
"incompatible pointer type" } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-8.c 
b/gcc/testsuite/gcc.target/i386/pr78098-8.c
new file mode 100644
index 0000000..6c2bdd7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-8.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+__attribute__((no_caller_saved_registers))
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+void (*foo2) (void *) = foo1; /* { dg-message "incompatible pointer type" } */
diff --git a/gcc/testsuite/gcc.target/i386/pr78098-9.c 
b/gcc/testsuite/gcc.target/i386/pr78098-9.c
new file mode 100644
index 0000000..eec5629
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr78098-9.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -mgeneral-regs-only" } */
+
+void bar (void *p);
+
+void foo1 (void *p)
+{
+  bar (p);
+  *((int *)0xFEE00080L) = 0;
+}
+
+void (*foo2) (void *) __attribute__((no_caller_saved_registers)) = foo1; /* { 
dg-message "incompatible pointer type" } */
-- 
2.7.4

Reply via email to