From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2119) id 59AC23858C54; Fri, 14 Jul 2023 02:47:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 59AC23858C54 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1689302860; bh=FRnOwwZR3m/bvmFo0Bc0rsXY+8dtImN7zzLYE8TMjJA=; h=From:To:Subject:Date:From; b=jNeWJr+CDSNO0+Y0DgQ6vuPsb+6qrJs2wA2uKV93pXFr3wH9RHD1uvmuR+HDZLI90 NK9d6dha03J8OOZgtp0/ijD1zEK7dCIHs10sslRcgR/82Ul5WgGC9kBDMbBe9pl99F NKKc+YE+OKytw5T2GLRmuS2h84L/q1w3I6qd3DpA= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Jeff Law To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/vendors/riscv/heads/gcc-13-with-riscv-opts)] RISC-V: Save and restore FCSR in interrupt functions to avoid program errors. X-Act-Checkin: gcc X-Git-Author: Jin Ma X-Git-Refname: refs/vendors/riscv/heads/gcc-13-with-riscv-opts X-Git-Oldrev: 418ef6fc297acb9bd1658b58e5221f4dd1049977 X-Git-Newrev: b0dfe6bc2803aaee058d04207406040185cba86e Message-Id: <20230714024740.59AC23858C54@sourceware.org> Date: Fri, 14 Jul 2023 02:47:40 +0000 (GMT) List-Id: https://gcc.gnu.org/g:b0dfe6bc2803aaee058d04207406040185cba86e commit b0dfe6bc2803aaee058d04207406040185cba86e Author: Jin Ma 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" } } */