RISC-V: Add interrupt attribute modes.
authorJim Wilson <jimw@sifive.com>
Wed, 6 Jun 2018 19:08:36 +0000 (19:08 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Wed, 6 Jun 2018 19:08:36 +0000 (12:08 -0700)
gcc/
* config/riscv/riscv.c (enum riscv_privilege_levels): New.
(struct machine_function): New field interrupt_mode.
(riscv_handle_type_attribute): New function.  Add forward declaration.
(riscv_attribute_table) <interrupt>: Use riscv_handle_type_attribute.
(riscv_expand_epilogue): Check interrupt_mode field.
(riscv_set_current_function): Check interrupt attribute args and
set interrupt_mode field.
* config/riscv/riscv.md (UNSPECV_SRET, UNSPECV_URET): New.
(riscv_sret, riscv_uret): New.
* doc/extend.texi (RISC-V Function Attributes) <interrupt>: Document
new arguments to interrupt attribute.

gcc/testsuite/
* gcc.target/riscv/interrupt-5.c (sub3): Add new test.
* gcc.target/riscv/interrupt-mmode.c: New.
* gcc.target/riscv/interrupt-smode.c: New.
* gcc.target/riscv/interrupt-umode.c: New.

From-SVN: r261244

gcc/ChangeLog
gcc/config/riscv/riscv.c
gcc/config/riscv/riscv.md
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/riscv/interrupt-5.c
gcc/testsuite/gcc.target/riscv/interrupt-mmode.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/interrupt-smode.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/interrupt-umode.c [new file with mode: 0644]

index 94123164188e65d5afcd5bf97ad330501e7a6cbf..bf56e891c77174b0c85024746014e02c4e1bc6e9 100644 (file)
@@ -1,3 +1,17 @@
+2018-06-06  Jim Wilson  <jimw@sifive.com>
+
+       * config/riscv/riscv.c (enum riscv_privilege_levels): New.
+       (struct machine_function): New field interrupt_mode.
+       (riscv_handle_type_attribute): New function.  Add forward declaration.
+       (riscv_attribute_table) <interrupt>: Use riscv_handle_type_attribute.
+       (riscv_expand_epilogue): Check interrupt_mode field.
+       (riscv_set_current_function): Check interrupt attribute args and
+       set interrupt_mode field.
+       * config/riscv/riscv.md (UNSPECV_SRET, UNSPECV_URET): New.
+       (riscv_sret, riscv_uret): New.
+       * doc/extend.texi (RISC-V Function Attributes) <interrupt>: Document
+       new arguments to interrupt attribute.
+
 2018-06-06  Peter Bergner  <bergner@vnet.ibm.com>
 
        PR target/63177
index c418dc1ec2e18296cd8df54c88f5f65d930c4a5b..2709ebdd7975292b388e36360a185baa98ced002 100644 (file)
@@ -122,6 +122,10 @@ struct GTY(())  riscv_frame_info {
   HOST_WIDE_INT arg_pointer_offset;
 };
 
+enum riscv_privilege_levels {
+  USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
+};
+
 struct GTY(())  machine_function {
   /* The number of extra stack bytes taken up by register varargs.
      This area is allocated by the callee at the very top of the frame.  */
@@ -132,6 +136,8 @@ struct GTY(())  machine_function {
 
   /* True if current function is an interrupt function.  */
   bool interrupt_handler_p;
+  /* For an interrupt handler, indicates the privilege level.  */
+  enum riscv_privilege_levels interrupt_mode;
 
   /* True if attributes on current function have been checked.  */
   bool attributes_checked_p;
@@ -282,6 +288,7 @@ static const struct riscv_tune_info optimize_size_tune_info = {
 };
 
 static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
+static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *);
 
 /* Defining target-specific uses of __attribute__.  */
 static const struct attribute_spec riscv_attribute_table[] =
@@ -294,7 +301,8 @@ static const struct attribute_spec riscv_attribute_table[] =
   { "naked",   0,  0, true, false, false, false,
     riscv_handle_fndecl_attribute, NULL },
   /* This attribute generates prologue/epilogue for interrupt handlers.  */
-  { "interrupt", 0, 0, false, true, true, false, NULL, NULL },
+  { "interrupt", 0, 1, false, true, true, false,
+    riscv_handle_type_attribute, NULL },
 
   /* The last attribute spec is set to be NULL.  */
   { NULL,      0,  0, false, false, false, false, NULL, NULL }
@@ -2721,6 +2729,47 @@ riscv_handle_fndecl_attribute (tree *node, tree name,
   return NULL_TREE;
 }
 
+/* Verify type based attributes.  NODE is the what the attribute is being
+   applied to.  NAME is the attribute name.  ARGS are the attribute args.
+   FLAGS gives info about the context.  NO_ADD_ATTRS should be set to true if
+   the attribute should be ignored.  */
+
+static tree
+riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args,
+                            int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  /* Check for an argument.  */
+  if (is_attribute_p ("interrupt", name))
+    {
+      if (args)
+       {
+         tree cst = TREE_VALUE (args);
+         const char *string;
+
+         if (TREE_CODE (cst) != STRING_CST)
+           {
+             warning (OPT_Wattributes,
+                      "%qE attribute requires a string argument",
+                      name);
+             *no_add_attrs = true;
+             return NULL_TREE;
+           }
+
+         string = TREE_STRING_POINTER (cst);
+         if (strcmp (string, "user") && strcmp (string, "supervisor")
+             && strcmp (string, "machine"))
+           {
+             warning (OPT_Wattributes,
+                      "argument to %qE attribute is not \"user\", \"supervisor\", or \"machine\"",
+                      name);
+             *no_add_attrs = true;
+           }
+       }
+    }
+
+  return NULL_TREE;
+}
+
 /* Return true if function TYPE is an interrupt function.  */
 static bool
 riscv_interrupt_type_p (tree type)
@@ -3932,7 +3981,16 @@ riscv_expand_epilogue (int style)
 
   /* Return from interrupt.  */
   if (cfun->machine->interrupt_handler_p)
-    emit_insn (gen_riscv_mret ());
+    {
+      enum riscv_privilege_levels mode = cfun->machine->interrupt_mode;
+
+      if (mode == MACHINE_MODE)
+       emit_insn (gen_riscv_mret ());
+      else if (mode == SUPERVISOR_MODE)
+       emit_insn (gen_riscv_sret ());
+      else
+       emit_insn (gen_riscv_uret ());
+    }
   else if (style != SIBCALL_RETURN)
     emit_jump_insn (gen_simple_return_internal (ra));
 }
@@ -4494,14 +4552,32 @@ riscv_set_current_function (tree decl)
 
   if (cfun->machine->interrupt_handler_p)
     {
-      tree args = TYPE_ARG_TYPES (TREE_TYPE (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");
 
       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;
     }
 
   /* Don't print the above diagnostics more than once.  */
index b9faf00d076eb625f30876831ce961a595beb7a0..a5940dcc4253edfdca937d786700cf2e86b99763 100644 (file)
@@ -58,6 +58,8 @@
 
   ;; Interrupt handler instructions.
   UNSPECV_MRET
+  UNSPECV_SRET
+  UNSPECV_URET
 
   ;; Blockage and synchronization.
   UNSPECV_BLOCKAGE
   ""
   "mret")
 
+(define_insn "riscv_sret"
+  [(unspec_volatile [(const_int 0)] UNSPECV_SRET)]
+  ""
+  "sret")
+
+(define_insn "riscv_uret"
+  [(unspec_volatile [(const_int 0)] UNSPECV_URET)]
+  ""
+  "uret")
+
 (define_insn "stack_tie<mode>"
   [(set (mem:BLK (scratch))
        (unspec:BLK [(match_operand:X 0 "register_operand" "r")
index e9db1b292de54de91374b89c897e0cfab6ac4952..0c1c1b1dc169e8b6c406d34ee77adad8e25a6d3b 100644 (file)
@@ -5147,6 +5147,17 @@ depended upon to work reliably and are not supported.
 Use this attribute to indicate that the specified function is an interrupt
 handler.  The compiler generates function entry and exit sequences suitable
 for use in an interrupt handler when this attribute is present.
+
+You can specify the kind of interrupt to be handled by adding an optional
+parameter to the interrupt attribute like this:
+
+@smallexample
+void f (void) __attribute__ ((interrupt ("user")));
+@end smallexample
+
+Permissible values for this parameter are @code{user}, @code{supervisor},
+and @code{machine}.  If there is no parameter, then it defaults to
+@code{machine}.
 @end table
 
 @node RL78 Function Attributes
index 14f575e6e7935061e7dbcc73f2a06e2e2f46e0b3..aa24adfbbd6054f20eb812dc3698146fc011ec0a 100644 (file)
@@ -1,3 +1,10 @@
+2018-06-06  Jim Wilson  <jimw@sifive.com>
+
+       * gcc.target/riscv/interrupt-5.c (sub3): Add new test.
+       * gcc.target/riscv/interrupt-mmode.c: New.
+       * gcc.target/riscv/interrupt-smode.c: New.
+       * gcc.target/riscv/interrupt-umode.c: New.
+
 2018-06-06  Marek Polacek  <polacek@redhat.com>
 
        PR c++/85977
index bf65e988c4e763d4a3220025f3e973c6890e9353..324954eb1dd3ac956a206b0c65fcf350e6acf7ac 100644 (file)
@@ -14,3 +14,8 @@ void __attribute__ ((interrupt, naked))
 sub2 (void)
 { /* { dg-error "are mutually exclusive" } */
 }
+
+void __attribute__ ((interrupt ("hypervisor")))
+sub3 (void)
+{ /* { dg-warning "argument to" } */
+}
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-mmode.c b/gcc/testsuite/gcc.target/riscv/interrupt-mmode.c
new file mode 100644 (file)
index 0000000..fd7a7a1
--- /dev/null
@@ -0,0 +1,8 @@
+/* Verify the return instruction is mret.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+void __attribute__ ((interrupt ("machine")))
+foo (void)
+{
+}
+/* { dg-final { scan-assembler "mret" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-smode.c b/gcc/testsuite/gcc.target/riscv/interrupt-smode.c
new file mode 100644 (file)
index 0000000..2f696d3
--- /dev/null
@@ -0,0 +1,8 @@
+/* Verify the return instruction is mret.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+void __attribute__ ((interrupt ("supervisor")))
+foo (void)
+{
+}
+/* { dg-final { scan-assembler "sret" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-umode.c b/gcc/testsuite/gcc.target/riscv/interrupt-umode.c
new file mode 100644 (file)
index 0000000..cd120e4
--- /dev/null
@@ -0,0 +1,8 @@
+/* Verify the return instruction is mret.  */
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+void __attribute__ ((interrupt ("user")))
+foo (void)
+{
+}
+/* { dg-final { scan-assembler "uret" } } */