]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Add support for resumable non-maskable interrupt (RNMI) handlers
authorChristoph Müllner <christoph.muellner@vrull.eu>
Thu, 24 Jul 2025 21:08:40 +0000 (23:08 +0200)
committerChristoph Müllner <christoph.muellner@vrull.eu>
Fri, 25 Jul 2025 07:35:50 +0000 (09:35 +0200)
The Smrnmi extension introduces the nmret instruction to return from RNMI
handlers.  We already have basic Smrnmi support.  This patch introduces
support for the nmret instruction and the ability to set the function
attribute `__attribute__ ((interrupt ("rnmi")))` to let the compiler
generate RNMI handlers.

The attribute name is proposed in a PR for the RISC C API and approved
by LLVM maintainers:
  https://github.com/riscv-non-isa/riscv-c-api-doc/pull/116

gcc/ChangeLog:

* config/riscv/riscv.cc (enum riscv_privilege_levels): Add
RNMI_MODE.
(riscv_handle_type_attribute): Handle 'rnmi' interrupt attribute.
(riscv_expand_epilogue): Generate nmret for RNMI handlers.
(riscv_get_interrupt_type): Handle 'rnmi' interrupt attribute.
* config/riscv/riscv.md (riscv_rnmi): Add nmret INSN.
* doc/extend.texi: Add documentation for 'rnmi' interrupt attribute.

gcc/testsuite/ChangeLog:

* gcc.target/riscv/interrupt-rnmi.c: New test.

Signed-off-by: Christoph Müllner <christoph.muellner@vrull.eu>
gcc/config/riscv/riscv.cc
gcc/config/riscv/riscv.md
gcc/doc/extend.texi
gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c [new file with mode: 0644]

index c6fa4289346de9e11da3e4383b0ca5f836d59f2c..b80d2a0efab4578c1ea8396c1d9e208bdc0d29ae 100644 (file)
@@ -170,7 +170,7 @@ struct GTY(())  riscv_frame_info {
 };
 
 enum riscv_privilege_levels {
-  UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
+  UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE, RNMI_MODE
 };
 
 struct GTY(()) mode_switching_info {
@@ -6924,12 +6924,17 @@ riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args,
            }
 
          string = TREE_STRING_POINTER (cst);
-         if (strcmp (string, "user") && strcmp (string, "supervisor")
-             && strcmp (string, "machine"))
+         if (!strcmp (string, "rnmi") && !TARGET_SMRNMI)
+           {
+             error ("attribute 'rnmi' requires the Smrnmi ISA extension");
+             *no_add_attrs = true;
+           }
+         else if (strcmp (string, "user") && strcmp (string, "supervisor")
+             && strcmp (string, "machine") && strcmp (string, "rnmi"))
            {
              warning (OPT_Wattributes,
                       "argument to %qE attribute is not %<\"user\"%>, %<\"supervisor\"%>, "
-                      "or %<\"machine\"%>", name);
+                      "%<\"machine\"%>, or %<\"rnmi\"%>", name);
              *no_add_attrs = true;
            }
        }
@@ -9714,6 +9719,8 @@ riscv_expand_epilogue (int style)
        emit_jump_insn (gen_riscv_mret ());
       else if (mode == SUPERVISOR_MODE)
        emit_jump_insn (gen_riscv_sret ());
+      else if (mode == RNMI_MODE)
+       emit_jump_insn (gen_riscv_mnret ());
       else
        emit_jump_insn (gen_riscv_uret ());
     }
@@ -12061,6 +12068,8 @@ riscv_get_interrupt_type (tree decl)
        return USER_MODE;
       else if (!strcmp (string, "supervisor"))
        return SUPERVISOR_MODE;
+      else if (!strcmp (string, "rnmi"))
+       return RNMI_MODE;
       else /* Must be "machine".  */
        return MACHINE_MODE;
     }
index c3b504d088360f591837c4a0c64cdd10e78f553a..0f29baa47e20d69ec6dc085ec1b75979aeb942fd 100644 (file)
   UNSPECV_MRET
   UNSPECV_SRET
   UNSPECV_URET
+  UNSPECV_MNRET
 
   ;; Blockage and synchronization.
   UNSPECV_BLOCKAGE
   "uret"
   [(set_attr "type" "ret")])
 
+(define_insn "riscv_mnret"
+  [(return)
+   (unspec_volatile [(const_int 0)] UNSPECV_MNRET)]
+  "TARGET_SMRNMI"
+  "mnret"
+  [(set_attr "type" "ret")])
+
 (define_insn "stack_tie<mode>"
   [(set (mem:BLK (scratch))
        (unspec:BLK [(match_operand:X 0 "register_operand" "r")
index 76fed32918f6369bfba36156980c29885b39bebf..125eaf46331b7522c3f846e82d290b2a3d3df80e 100644 (file)
@@ -5658,8 +5658,8 @@ 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}.
+@code{machine}, and @code{rnmi}.  If there is no parameter, then it
+defaults to @code{machine}.
 
 @cindex @code{riscv_vector_cc} function attribute, RISC-V
 @item riscv_vector_cc
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c b/gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c
new file mode 100644 (file)
index 0000000..f340108
--- /dev/null
@@ -0,0 +1,11 @@
+/* Verify the return instruction is mnret.  */
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_smrnmi" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_smrnmi" { target { rv64 } } } */
+
+void __attribute__ ((interrupt ("rnmi")))
+foo (void)
+{
+}
+
+/* { dg-final { scan-assembler {\mmnret} } } */