public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/riscv/heads/gcc-13-with-riscv-opts)] RISC-V: Save and restore FCSR in interrupt functions to avoid program errors.
@ 2023-06-26 20:55 Jeff Law
  0 siblings, 0 replies; 2+ messages in thread
From: Jeff Law @ 2023-06-26 20:55 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:75399fe03f41b58b9621e219921d6b9bbf85b885

commit 75399fe03f41b58b9621e219921d6b9bbf85b885
Author: Jin Ma <jinma@linux.alibaba.com>
Date:   Mon Jun 19 13:02:47 2023 -0600

    RISC-V: Save and restore FCSR in interrupt functions to avoid program errors.
    
    In order to avoid interrupt functions to change the FCSR, it needs to be saved
    and restored at the beginning and end of the function.
    
    gcc/ChangeLog:
    
            * config/riscv/riscv.cc (riscv_compute_frame_info): Allocate frame for FCSR.
            (riscv_for_each_saved_reg): Save and restore FCSR in interrupt functions.
            * config/riscv/riscv.md (riscv_frcsr): New patterns.
            (riscv_fscsr): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/interrupt-fcsr-1.c: New test.
            * gcc.target/riscv/interrupt-fcsr-2.c: New test.
            * gcc.target/riscv/interrupt-fcsr-3.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                         | 48 +++++++++++++++++++++--
 gcc/config/riscv/riscv.md                         | 13 ++++++
 gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c | 15 +++++++
 gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c | 15 +++++++
 gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c | 14 +++++++
 5 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index c4588a55e04..8d5b4c163d3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -5113,12 +5113,15 @@ riscv_compute_frame_info (void)
 
   frame = &cfun->machine->frame;
 
-  /* In an interrupt function, if we have a large frame, then we need to
-     save/restore t0.  We check for this before clearing the frame struct.  */
+  /* In an interrupt function, there are two cases in which t0 needs to be used:
+     1, If we have a large frame, then we need to save/restore t0.  We check for
+     this before clearing the frame struct.
+     2, Need to save and restore some CSRs in the frame.  */
   if (cfun->machine->interrupt_handler_p)
     {
       HOST_WIDE_INT step1 = riscv_first_stack_step (frame, frame->total_size);
-      if (! POLY_SMALL_OPERAND_P ((frame->total_size - step1)))
+      if (! POLY_SMALL_OPERAND_P ((frame->total_size - step1))
+	  || (TARGET_HARD_FLOAT || TARGET_ZFINX))
 	interrupt_save_prologue_temp = true;
     }
 
@@ -5165,6 +5168,17 @@ riscv_compute_frame_info (void)
 	}
     }
 
+  /* In an interrupt function, we need extra space for the initial saves of CSRs.  */
+  if (cfun->machine->interrupt_handler_p
+      && ((TARGET_HARD_FLOAT && frame->fmask)
+	  || (TARGET_ZFINX
+	      /* Except for RISCV_PROLOGUE_TEMP_REGNUM.  */
+	      && (frame->mask & ~(1 << RISCV_PROLOGUE_TEMP_REGNUM)))))
+    /* Save and restore FCSR.  */
+    /* TODO: When P or V extensions support interrupts, some of their CSRs
+       may also need to be saved and restored.  */
+    x_save_size += riscv_stack_align (1 * UNITS_PER_WORD);
+
   /* At the bottom of the frame are any outgoing stack arguments. */
   offset = riscv_stack_align (crtl->outgoing_args_size);
   /* Next are local stack variables. */
@@ -5410,6 +5424,34 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 	    }
 	}
 
+      /* In an interrupt function, save and restore some necessary CSRs in the stack
+	 to avoid changes in CSRs.  */
+      if (regno == RISCV_PROLOGUE_TEMP_REGNUM
+	  && cfun->machine->interrupt_handler_p
+	  && ((TARGET_HARD_FLOAT  && cfun->machine->frame.fmask)
+	      || (TARGET_ZFINX
+		  && (cfun->machine->frame.mask & ~(1 << RISCV_PROLOGUE_TEMP_REGNUM)))))
+	{
+	  unsigned int fcsr_size = GET_MODE_SIZE (SImode);
+	  if (!epilogue)
+	    {
+	      riscv_save_restore_reg (word_mode, regno, offset, fn);
+	      offset -= fcsr_size;
+	      emit_insn (gen_riscv_frcsr (RISCV_PROLOGUE_TEMP (SImode)));
+	      riscv_save_restore_reg (SImode, RISCV_PROLOGUE_TEMP_REGNUM,
+				      offset, riscv_save_reg);
+	    }
+	  else
+	    {
+	      riscv_save_restore_reg (SImode, RISCV_PROLOGUE_TEMP_REGNUM,
+				      offset - fcsr_size, riscv_restore_reg);
+	      emit_insn (gen_riscv_fscsr (RISCV_PROLOGUE_TEMP (SImode)));
+	      riscv_save_restore_reg (word_mode, regno, offset, fn);
+	      offset -= fcsr_size;
+	    }
+	  continue;
+	}
+
       riscv_save_restore_reg (word_mode, regno, offset, fn);
     }
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index c2fe4c6164a..245cace4c8d 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -78,6 +78,8 @@
   UNSPECV_GPR_RESTORE
 
   ;; Floating-point unspecs.
+  UNSPECV_FRCSR
+  UNSPECV_FSCSR
   UNSPECV_FRFLAGS
   UNSPECV_FSFLAGS
   UNSPECV_FSNVSNAN
@@ -3061,6 +3063,17 @@
   ""
   "")
 
+(define_insn "riscv_frcsr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec_volatile [(const_int 0)] UNSPECV_FRCSR))]
+  "TARGET_HARD_FLOAT || TARGET_ZFINX"
+  "frcsr\t%0")
+
+(define_insn "riscv_fscsr"
+  [(unspec_volatile [(match_operand:SI 0 "csr_operand" "rK")] UNSPECV_FSCSR)]
+  "TARGET_HARD_FLOAT || TARGET_ZFINX"
+  "fscsr\t%0")
+
 (define_insn "riscv_frflags"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(unspec_volatile [(const_int 0)] UNSPECV_FRFLAGS))]
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c
new file mode 100644
index 00000000000..aaafb08a674
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c
@@ -0,0 +1,15 @@
+/* Verify that fcsr instructions emitted.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O" } */
+
+extern int foo (void);
+
+void __attribute__ ((interrupt))
+sub (void)
+{
+  foo ();
+}
+
+/* { dg-final { scan-assembler-times "frcsr\t" 1 } } */
+/* { dg-final { scan-assembler-times "fscsr\t" 1 } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c
new file mode 100644
index 00000000000..ea22e6a2be4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c
@@ -0,0 +1,15 @@
+/* Verify that fcsr instructions emitted.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O" } */
+
+extern int foo (void);
+extern float interrupt_count;
+void __attribute__ ((interrupt))
+sub (void)
+{
+  interrupt_count++;
+}
+
+/* { dg-final { scan-assembler-times "frcsr\t" 1 } } */
+/* { dg-final { scan-assembler-times "fscsr\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c
new file mode 100644
index 00000000000..5e7eac4b770
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c
@@ -0,0 +1,14 @@
+/* Verify that fcsr instructions are not emitted.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O" } */
+
+extern int foo (void);
+
+void __attribute__ ((interrupt))
+sub (void)
+{
+}
+
+/* { dg-final { scan-assembler-not "frcsr\t" } } */
+/* { dg-final { scan-assembler-not "fscsr\t" } } */

^ permalink raw reply	[flat|nested] 2+ messages in thread

* [gcc(refs/vendors/riscv/heads/gcc-13-with-riscv-opts)] RISC-V: Save and restore FCSR in interrupt functions to avoid program errors.
@ 2023-07-14  2:47 Jeff Law
  0 siblings, 0 replies; 2+ messages in thread
From: Jeff Law @ 2023-07-14  2:47 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:b0dfe6bc2803aaee058d04207406040185cba86e

commit b0dfe6bc2803aaee058d04207406040185cba86e
Author: Jin Ma <jinma@linux.alibaba.com>
Date:   Mon Jun 19 13:02:47 2023 -0600

    RISC-V: Save and restore FCSR in interrupt functions to avoid program errors.
    
    In order to avoid interrupt functions to change the FCSR, it needs to be saved
    and restored at the beginning and end of the function.
    
    gcc/ChangeLog:
    
            * config/riscv/riscv.cc (riscv_compute_frame_info): Allocate frame for FCSR.
            (riscv_for_each_saved_reg): Save and restore FCSR in interrupt functions.
            * config/riscv/riscv.md (riscv_frcsr): New patterns.
            (riscv_fscsr): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/riscv/interrupt-fcsr-1.c: New test.
            * gcc.target/riscv/interrupt-fcsr-2.c: New test.
            * gcc.target/riscv/interrupt-fcsr-3.c: New test.

Diff:
---
 gcc/config/riscv/riscv.cc                         | 48 +++++++++++++++++++++--
 gcc/config/riscv/riscv.md                         | 13 ++++++
 gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c | 15 +++++++
 gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c | 15 +++++++
 gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c | 14 +++++++
 5 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index c4588a55e04..8d5b4c163d3 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -5113,12 +5113,15 @@ riscv_compute_frame_info (void)
 
   frame = &cfun->machine->frame;
 
-  /* In an interrupt function, if we have a large frame, then we need to
-     save/restore t0.  We check for this before clearing the frame struct.  */
+  /* In an interrupt function, there are two cases in which t0 needs to be used:
+     1, If we have a large frame, then we need to save/restore t0.  We check for
+     this before clearing the frame struct.
+     2, Need to save and restore some CSRs in the frame.  */
   if (cfun->machine->interrupt_handler_p)
     {
       HOST_WIDE_INT step1 = riscv_first_stack_step (frame, frame->total_size);
-      if (! POLY_SMALL_OPERAND_P ((frame->total_size - step1)))
+      if (! POLY_SMALL_OPERAND_P ((frame->total_size - step1))
+	  || (TARGET_HARD_FLOAT || TARGET_ZFINX))
 	interrupt_save_prologue_temp = true;
     }
 
@@ -5165,6 +5168,17 @@ riscv_compute_frame_info (void)
 	}
     }
 
+  /* In an interrupt function, we need extra space for the initial saves of CSRs.  */
+  if (cfun->machine->interrupt_handler_p
+      && ((TARGET_HARD_FLOAT && frame->fmask)
+	  || (TARGET_ZFINX
+	      /* Except for RISCV_PROLOGUE_TEMP_REGNUM.  */
+	      && (frame->mask & ~(1 << RISCV_PROLOGUE_TEMP_REGNUM)))))
+    /* Save and restore FCSR.  */
+    /* TODO: When P or V extensions support interrupts, some of their CSRs
+       may also need to be saved and restored.  */
+    x_save_size += riscv_stack_align (1 * UNITS_PER_WORD);
+
   /* At the bottom of the frame are any outgoing stack arguments. */
   offset = riscv_stack_align (crtl->outgoing_args_size);
   /* Next are local stack variables. */
@@ -5410,6 +5424,34 @@ riscv_for_each_saved_reg (poly_int64 sp_offset, riscv_save_restore_fn fn,
 	    }
 	}
 
+      /* In an interrupt function, save and restore some necessary CSRs in the stack
+	 to avoid changes in CSRs.  */
+      if (regno == RISCV_PROLOGUE_TEMP_REGNUM
+	  && cfun->machine->interrupt_handler_p
+	  && ((TARGET_HARD_FLOAT  && cfun->machine->frame.fmask)
+	      || (TARGET_ZFINX
+		  && (cfun->machine->frame.mask & ~(1 << RISCV_PROLOGUE_TEMP_REGNUM)))))
+	{
+	  unsigned int fcsr_size = GET_MODE_SIZE (SImode);
+	  if (!epilogue)
+	    {
+	      riscv_save_restore_reg (word_mode, regno, offset, fn);
+	      offset -= fcsr_size;
+	      emit_insn (gen_riscv_frcsr (RISCV_PROLOGUE_TEMP (SImode)));
+	      riscv_save_restore_reg (SImode, RISCV_PROLOGUE_TEMP_REGNUM,
+				      offset, riscv_save_reg);
+	    }
+	  else
+	    {
+	      riscv_save_restore_reg (SImode, RISCV_PROLOGUE_TEMP_REGNUM,
+				      offset - fcsr_size, riscv_restore_reg);
+	      emit_insn (gen_riscv_fscsr (RISCV_PROLOGUE_TEMP (SImode)));
+	      riscv_save_restore_reg (word_mode, regno, offset, fn);
+	      offset -= fcsr_size;
+	    }
+	  continue;
+	}
+
       riscv_save_restore_reg (word_mode, regno, offset, fn);
     }
 
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index c2fe4c6164a..245cace4c8d 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -78,6 +78,8 @@
   UNSPECV_GPR_RESTORE
 
   ;; Floating-point unspecs.
+  UNSPECV_FRCSR
+  UNSPECV_FSCSR
   UNSPECV_FRFLAGS
   UNSPECV_FSFLAGS
   UNSPECV_FSNVSNAN
@@ -3061,6 +3063,17 @@
   ""
   "")
 
+(define_insn "riscv_frcsr"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+	(unspec_volatile [(const_int 0)] UNSPECV_FRCSR))]
+  "TARGET_HARD_FLOAT || TARGET_ZFINX"
+  "frcsr\t%0")
+
+(define_insn "riscv_fscsr"
+  [(unspec_volatile [(match_operand:SI 0 "csr_operand" "rK")] UNSPECV_FSCSR)]
+  "TARGET_HARD_FLOAT || TARGET_ZFINX"
+  "fscsr\t%0")
+
 (define_insn "riscv_frflags"
   [(set (match_operand:SI 0 "register_operand" "=r")
 	(unspec_volatile [(const_int 0)] UNSPECV_FRFLAGS))]
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c
new file mode 100644
index 00000000000..aaafb08a674
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c
@@ -0,0 +1,15 @@
+/* Verify that fcsr instructions emitted.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O" } */
+
+extern int foo (void);
+
+void __attribute__ ((interrupt))
+sub (void)
+{
+  foo ();
+}
+
+/* { dg-final { scan-assembler-times "frcsr\t" 1 } } */
+/* { dg-final { scan-assembler-times "fscsr\t" 1 } } */
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c
new file mode 100644
index 00000000000..ea22e6a2be4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c
@@ -0,0 +1,15 @@
+/* Verify that fcsr instructions emitted.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O" } */
+
+extern int foo (void);
+extern float interrupt_count;
+void __attribute__ ((interrupt))
+sub (void)
+{
+  interrupt_count++;
+}
+
+/* { dg-final { scan-assembler-times "frcsr\t" 1 } } */
+/* { dg-final { scan-assembler-times "fscsr\t" 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c
new file mode 100644
index 00000000000..5e7eac4b770
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-fcsr-3.c
@@ -0,0 +1,14 @@
+/* Verify that fcsr instructions are not emitted.  */
+/* { dg-do compile } */
+/* { dg-require-effective-target hard_float } */
+/* { dg-options "-O" } */
+
+extern int foo (void);
+
+void __attribute__ ((interrupt))
+sub (void)
+{
+}
+
+/* { dg-final { scan-assembler-not "frcsr\t" } } */
+/* { dg-final { scan-assembler-not "fscsr\t" } } */

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-07-14  2:47 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-26 20:55 [gcc(refs/vendors/riscv/heads/gcc-13-with-riscv-opts)] RISC-V: Save and restore FCSR in interrupt functions to avoid program errors Jeff Law
2023-07-14  2:47 Jeff Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).