diff options
author | Jin Ma <jinma@linux.alibaba.com> | 2023-06-19 13:02:47 -0600 |
---|---|---|
committer | Jeff Law <jlaw@ventanamicro.com> | 2023-06-19 13:02:47 -0600 |
commit | dbcbc858c71f69da76d1f36d6bb5d72f2db11eda (patch) | |
tree | 4a9629434541228a56360add55d3ee12dc2fa2de | |
parent | 827b2a279fc6ad5bb76e4d2c2eb3432955b5e11c (diff) | |
download | gcc-dbcbc858c71f69da76d1f36d6bb5d72f2db11eda.zip gcc-dbcbc858c71f69da76d1f36d6bb5d72f2db11eda.tar.gz gcc-dbcbc858c71f69da76d1f36d6bb5d72f2db11eda.tar.bz2 |
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.
-rw-r--r-- | gcc/config/riscv/riscv.cc | 48 | ||||
-rw-r--r-- | gcc/config/riscv/riscv.md | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/interrupt-fcsr-1.c | 15 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/riscv/interrupt-fcsr-2.c | 15 | ||||
-rw-r--r-- | 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 c4588a5..8d5b4c1 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 c2fe4c6..245cace 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 0000000..aaafb08 --- /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 0000000..ea22e6a --- /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 0000000..5e7eac4 --- /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" } } */ |