This adds basic interrupt attribute support to the RISC-V port. This will
save every register before it is used, will save every temporary and argument
register and the return address register before a call, and emits a mret
instruction at the end. I've included some docs and some testcases to verify
the support.
I've also added a few misc cleanups I noticed while writing this patch.
This was tested with riscv{32,64}-{elf,linux} cross builds and checks. There
were no regressions.
Committed.
Jim
gcc/
* config/riscv/riscv-protos.h (riscv_epilogue_uses): New.
* config/riscv/riscv.c (struct machine_function): Add
interrupt_handler_p and attribute_checked_p fields.
(riscv_attribute_table): Add interrupt.
(riscv_interrupt_type_p): New.
(riscv_save_reg_p): Save extra regs for interrupt handler.
(riscv_use_save_libcall): Return false for interrupt handler.
(riscv_first_stack_step): Add forward declaration.
(riscv_compute_frame_info): New local interrupt_save_t1. Set it
for interrupt handler with large frame. Use it for saved reg list.
(riscv_expand_prologue): Move flag_stack_usage_info support to
eliminate duplication.
(riscv_expand_epilogue): Generate mret for interrupt handler.
(riscv_epilogue_uses): New.
(riscv_can_use_return_insn): Return false for interrupt handler.
(riscv_function_ok_for_sibcall): Likewise.
(riscv_set_current_function): Add interrupt handler support.
* config/riscv/riscv.h (EPILOGUE_USES): Call riscv_epilogue_uses.
* config/riscv/riscv.md (UNSPECV_MRET): New.
(GP_REGNUM): New.
(riscv_frflags, riscv_fsflags): Use tab after opcode.
(riscv_mret): New.
* doc/extend.texi (RISC-V Function Attributes) : New.
gcc/testsuite/
* gcc.target/riscv/interrupt-1.c: New.
* gcc.target/riscv/interrupt-2.c: New.
* gcc.target/riscv/interrupt-3.c: New.
* gcc.target/riscv/interrupt-4.c: New.
* gcc.target/riscv/interrupt-5.c: New.
---
gcc/config/riscv/riscv-protos.h | 1 +
gcc/config/riscv/riscv.c | 127 +++
gcc/config/riscv/riscv.h | 2 +-
gcc/config/riscv/riscv.md| 13 ++-
gcc/doc/extend.texi | 6 ++
gcc/testsuite/gcc.target/riscv/interrupt-1.c | 8 ++
gcc/testsuite/gcc.target/riscv/interrupt-2.c | 17
gcc/testsuite/gcc.target/riscv/interrupt-3.c | 9 ++
gcc/testsuite/gcc.target/riscv/interrupt-4.c | 18
gcc/testsuite/gcc.target/riscv/interrupt-5.c | 16
10 files changed, 199 insertions(+), 18 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-1.c
create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-2.c
create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-3.c
create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-4.c
create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-5.c
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 0538ede77e4..a194b192a2b 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -67,6 +67,7 @@ extern rtx riscv_return_addr (int, rtx);
extern HOST_WIDE_INT riscv_initial_elimination_offset (int, int);
extern void riscv_expand_prologue (void);
extern void riscv_expand_epilogue (bool);
+extern bool riscv_epilogue_uses (unsigned int);
extern bool riscv_can_use_return_insn (void);
extern rtx riscv_function_value (const_tree, const_tree, enum machine_mode);
extern bool riscv_expand_block_move (rtx, rtx, rtx);
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 9a9d9e1befe..7ea2657d8c8 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -130,6 +130,12 @@ struct GTY(()) machine_function {
/* True if current function is a naked function. */
bool naked_p;
+ /* True if current function is an interrupt function. */
+ bool interrupt_handler_p;
+
+ /* True if attributes on current function have been checked. */
+ bool attributes_checked_p;
+
/* The current frame information, calculated by riscv_compute_frame_info. */
struct riscv_frame_info frame;
};
@@ -287,6 +293,8 @@ static const struct attribute_spec riscv_attribute_table[] =
/* The attribute telling no prologue/epilogue. */
{ "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 },
/* The last attribute spec is set to be NULL. */
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
@@ -2713,7 +2721,14 @@ riscv_handle_fndecl_attribute (tree *node, tree name,
return NULL_TREE;
}
-/* Return true if func is a naked function. */
+/* Return true if funcion TYPE is an