RISC-V: Error if function declared with different interrupt modes.
authorKito Cheng <kito.cheng@gmail.com>
Thu, 12 Jul 2018 19:59:09 +0000 (19:59 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Thu, 12 Jul 2018 19:59:09 +0000 (12:59 -0700)
gcc/
2018-07-06  Kito Cheng  <kito.cheng@gmail.com>
        * config/riscv/riscv.c (enum riscv_privilege_levels): Add UNKNOWN_MODE.
        (riscv_expand_epilogue): Add assertion to check interrupt mode.
        (riscv_set_current_function): Extract getting interrupt type to new
        function.
        (riscv_get_interrupt_type): New function.
        (riscv_merge_decl_attributes): New function, checking interrupt type is
        same.
        (TARGET_MERGE_DECL_ATTRIBUTES): Define.

gcc/testsuite/
2018-07-06  Kito Cheng  <kito.cheng@gmail.com>
        * gcc.target/riscv/interrupt-conflict-mode.c: New.

From-SVN: r262607

gcc/ChangeLog
gcc/config/riscv/riscv.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c [new file with mode: 0644]

index 05b7ffbd392db52d5ca9ab65318858ad58d9b4d0..9c955669e174bc82becca952dd894c8f834f18f4 100644 (file)
@@ -1,3 +1,14 @@
+2018-07-12  Kito Cheng  <kito.cheng@gmail.com>
+
+        * config/riscv/riscv.c (enum riscv_privilege_levels): Add UNKNOWN_MODE.
+        (riscv_expand_epilogue): Add assertion to check interrupt mode.
+        (riscv_set_current_function): Extract getting interrupt type to new
+        function.
+        (riscv_get_interrupt_type): New function.
+        (riscv_merge_decl_attributes): New function, checking interrupt type is
+        same.
+        (TARGET_MERGE_DECL_ATTRIBUTES): Define.
+
 2018-07-12  Paul Koning  <ni1d@arrl.net>
 
        * config/pdp11/pdp11.c (pdp11_output_def): Fix typo in .set
index 218f4de7d415611af7281804bcdb00a47505c93d..69e70feaf33bab1da3ca6bc22b322eefe2dad08c 100644 (file)
@@ -123,7 +123,7 @@ struct GTY(())  riscv_frame_info {
 };
 
 enum riscv_privilege_levels {
-  USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
+  UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
 };
 
 struct GTY(())  machine_function {
@@ -3984,6 +3984,8 @@ riscv_expand_epilogue (int style)
     {
       enum riscv_privilege_levels mode = cfun->machine->interrupt_mode;
 
+      gcc_assert (mode != UNKNOWN_MODE);
+
       if (mode == MACHINE_MODE)
        emit_jump_insn (gen_riscv_mret ());
       else if (mode == SUPERVISOR_MODE)
@@ -4530,6 +4532,37 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED,
   return true;
 }
 
+/* Get the intterupt type, return UNKNOWN_MODE if it's not
+   interrupt function. */
+static enum riscv_privilege_levels
+riscv_get_interrupt_type (tree decl)
+{
+  gcc_assert (decl != NULL_TREE);
+
+  if ((TREE_CODE(decl) != FUNCTION_DECL)
+      || (!riscv_interrupt_type_p (TREE_TYPE (decl))))
+    return UNKNOWN_MODE;
+
+  tree attr_args
+    = TREE_VALUE (lookup_attribute ("interrupt",
+                                   TYPE_ATTRIBUTES (TREE_TYPE (decl))));
+
+  if (attr_args && TREE_CODE (TREE_VALUE (attr_args)) != VOID_TYPE)
+    {
+      const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args));
+
+      if (!strcmp (string, "user"))
+       return USER_MODE;
+      else if (!strcmp (string, "supervisor"))
+       return SUPERVISOR_MODE;
+      else /* Must be "machine".  */
+       return MACHINE_MODE;
+    }
+  else
+    /* Interrupt attributes are machine mode by default.  */
+    return MACHINE_MODE;
+}
+
 /* Implement `TARGET_SET_CURRENT_FUNCTION'.  */
 /* Sanity cheching for above function attributes.  */
 static void
@@ -4554,9 +4587,6 @@ riscv_set_current_function (tree decl)
     {
       tree ret = TREE_TYPE (TREE_TYPE (decl));
       tree args = TYPE_ARG_TYPES (TREE_TYPE (decl));
-      tree attr_args
-       = TREE_VALUE (lookup_attribute ("interrupt",
-                                       TYPE_ATTRIBUTES (TREE_TYPE (decl))));
 
       if (TREE_CODE (ret) != VOID_TYPE)
        error ("%qs function cannot return a value", "interrupt");
@@ -4564,26 +4594,39 @@ riscv_set_current_function (tree decl)
       if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE)
        error ("%qs function cannot have arguments", "interrupt");
 
-      if (attr_args && TREE_CODE (TREE_VALUE (attr_args)) != VOID_TYPE)
-       {
-         const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args));
-
-         if (!strcmp (string, "user"))
-           cfun->machine->interrupt_mode = USER_MODE;
-         else if (!strcmp (string, "supervisor"))
-           cfun->machine->interrupt_mode = SUPERVISOR_MODE;
-         else /* Must be "machine".  */
-           cfun->machine->interrupt_mode = MACHINE_MODE;
-       }
-      else
-       /* Interrupt attributes are machine mode by default.  */
-       cfun->machine->interrupt_mode = MACHINE_MODE;
+      cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl);
+
+      gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE);
     }
 
   /* Don't print the above diagnostics more than once.  */
   cfun->machine->attributes_checked_p = 1;
 }
 
+/* Implement TARGET_MERGE_DECL_ATTRIBUTES. */
+static tree
+riscv_merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  tree combined_attrs;
+
+  enum riscv_privilege_levels old_interrupt_type
+    = riscv_get_interrupt_type (olddecl);
+  enum riscv_privilege_levels new_interrupt_type
+    = riscv_get_interrupt_type (newdecl);
+
+  /* Check old and new has same interrupt type. */
+  if ((old_interrupt_type != UNKNOWN_MODE)
+      && (new_interrupt_type != UNKNOWN_MODE)
+      && (old_interrupt_type != new_interrupt_type))
+    error ("%qs function cannot have different intterupt type.", "interrupt");
+
+  /* Create combined attributes.  */
+  combined_attrs = merge_attributes (DECL_ATTRIBUTES (olddecl),
+                                     DECL_ATTRIBUTES (newdecl));
+
+  return combined_attrs;
+}
+
 /* Implement TARGET_CANNOT_COPY_INSN_P.  */
 
 static bool
@@ -4780,6 +4823,9 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
 #undef TARGET_CONSTANT_ALIGNMENT
 #define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment
 
+#undef TARGET_MERGE_DECL_ATTRIBUTES
+#define TARGET_MERGE_DECL_ATTRIBUTES riscv_merge_decl_attributes
+
 #undef TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE riscv_attribute_table
 
index e72883860d6ae7f0b9ae0af942f8d8d410a8684a..48637b74d8a6538f4a9e625bc15b60fa88309f36 100644 (file)
@@ -1,3 +1,7 @@
+2018-07-12  Kito Cheng  <kito.cheng@gmail.com>
+
+        * gcc.target/riscv/interrupt-conflict-mode.c: New.
+
 2018-07-12  Jakub Jelinek  <jakub@redhat.com>
 
        * c-c++-common/gomp/declare-target-3.c: New test.
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
new file mode 100644 (file)
index 0000000..6e280ed
--- /dev/null
@@ -0,0 +1,10 @@
+/* Verify proper errors are generated for conflicted interrupt type.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+void __attribute__ ((interrupt ("user")))
+foo(void);
+
+void __attribute__ ((interrupt ("machine")))
+foo (void)
+{ /* { dg-error "function cannot have different intterupt type." } */
+}