Hi all: This patch implemented TARGET_MERGE_DECL_ATTRIBUTES hook to check the interrupter is all compatible, tested with rv32ima and rv64ima elf toolchain.
gcc/ChangeLog 2018-07-06 Kito Cheng <kito.ch...@gmail.com> * config/riscv/riscv.c (enum riscv_privilege_levels): Add UNKNOWN_MODE. (riscv_expand_epilogue): Add more assertion to check interrupt mode. (riscv_set_current_function): Extract getting interrupt type to new function. (riscv_get_interrupt_type): New function. (riscv_merge_decl_attributes): New function, checking interrupt type is same. (TARGET_MERGE_DECL_ATTRIBUTES): Define. gcc/testsuite/ChangeLog 2018-07-06 Kito Cheng <kito.ch...@gmail.com> * gcc.target/riscv/interrupt-conflict-mode.c: New.
From ae275a1edd9b5c5f0126417542607aa667234823 Mon Sep 17 00:00:00 2001 From: Kito Cheng <kito.cheng@gmail.com> Date: Tue, 3 Jul 2018 13:29:02 +0800 Subject: [PATCH] RISC-V: Report error if function declare with different interrupt mode. --- gcc/config/riscv/riscv.c | 82 +++++++++++++++---- .../riscv/interrupt-conflict-mode.c | 10 +++ 2 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index d87836f53f8..c10c58e3cd5 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -123,7 +123,7 @@ struct GTY(()) riscv_frame_info { }; enum riscv_privilege_levels { - USER_MODE, SUPERVISOR_MODE, MACHINE_MODE + UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE }; struct GTY(()) machine_function { @@ -3984,6 +3984,8 @@ riscv_expand_epilogue (int style) { enum riscv_privilege_levels mode = cfun->machine->interrupt_mode; + gcc_assert (mode != UNKNOWN_MODE); + if (mode == MACHINE_MODE) emit_jump_insn (gen_riscv_mret ()); else if (mode == SUPERVISOR_MODE) @@ -4530,6 +4532,37 @@ riscv_function_ok_for_sibcall (tree decl ATTRIBUTE_UNUSED, return true; } +/* Get the intterupt type, return UNKNOWN_MODE if it's not + interrupt function. */ +static enum riscv_privilege_levels +riscv_get_interrupt_type (tree decl) +{ + gcc_assert (decl != NULL_TREE); + + if ((TREE_CODE(decl) != FUNCTION_DECL) + || (!riscv_interrupt_type_p (TREE_TYPE (decl)))) + return UNKNOWN_MODE; + + tree attr_args + = TREE_VALUE (lookup_attribute ("interrupt", + TYPE_ATTRIBUTES (TREE_TYPE (decl)))); + + if (attr_args && TREE_CODE (TREE_VALUE (attr_args)) != VOID_TYPE) + { + const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args)); + + if (!strcmp (string, "user")) + return USER_MODE; + else if (!strcmp (string, "supervisor")) + return SUPERVISOR_MODE; + else /* Must be "machine". */ + return MACHINE_MODE; + } + else + /* Interrupt attributes are machine mode by default. */ + return MACHINE_MODE; +} + /* Implement `TARGET_SET_CURRENT_FUNCTION'. */ /* Sanity cheching for above function attributes. */ static void @@ -4554,9 +4587,6 @@ riscv_set_current_function (tree decl) { tree ret = TREE_TYPE (TREE_TYPE (decl)); tree args = TYPE_ARG_TYPES (TREE_TYPE (decl)); - tree attr_args - = TREE_VALUE (lookup_attribute ("interrupt", - TYPE_ATTRIBUTES (TREE_TYPE (decl)))); if (TREE_CODE (ret) != VOID_TYPE) error ("%qs function cannot return a value", "interrupt"); @@ -4564,26 +4594,39 @@ riscv_set_current_function (tree decl) if (args && TREE_CODE (TREE_VALUE (args)) != VOID_TYPE) error ("%qs function cannot have arguments", "interrupt"); - if (attr_args && TREE_CODE (TREE_VALUE (attr_args)) != VOID_TYPE) - { - const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args)); - - if (!strcmp (string, "user")) - cfun->machine->interrupt_mode = USER_MODE; - else if (!strcmp (string, "supervisor")) - cfun->machine->interrupt_mode = SUPERVISOR_MODE; - else /* Must be "machine". */ - cfun->machine->interrupt_mode = MACHINE_MODE; - } - else - /* Interrupt attributes are machine mode by default. */ - cfun->machine->interrupt_mode = MACHINE_MODE; + cfun->machine->interrupt_mode = riscv_get_interrupt_type (decl); + + gcc_assert (cfun->machine->interrupt_mode != UNKNOWN_MODE); } /* Don't print the above diagnostics more than once. */ cfun->machine->attributes_checked_p = 1; } +/* Implement TARGET_MERGE_DECL_ATTRIBUTES. */ +static tree +riscv_merge_decl_attributes (tree olddecl, tree newdecl) +{ + tree combined_attrs; + + enum riscv_privilege_levels old_interrupt_type + = riscv_get_interrupt_type (olddecl); + enum riscv_privilege_levels new_interrupt_type + = riscv_get_interrupt_type (newdecl); + + /* Check old and new has same interrupt type. */ + if ((old_interrupt_type != UNKNOWN_MODE) + && (new_interrupt_type != UNKNOWN_MODE) + && (old_interrupt_type != new_interrupt_type)) + error ("%qs function cannot have different intterupt type.", "interrupt"); + + /* Create combined attributes. */ + combined_attrs = merge_attributes (DECL_ATTRIBUTES (olddecl), + DECL_ATTRIBUTES (newdecl)); + + return combined_attrs; +} + /* Implement TARGET_CANNOT_COPY_INSN_P. */ static bool @@ -4780,6 +4823,9 @@ riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align) #undef TARGET_CONSTANT_ALIGNMENT #define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment +#undef TARGET_MERGE_DECL_ATTRIBUTES +#define TARGET_MERGE_DECL_ATTRIBUTES riscv_merge_decl_attributes + #undef TARGET_ATTRIBUTE_TABLE #define TARGET_ATTRIBUTE_TABLE riscv_attribute_table diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c new file mode 100644 index 00000000000..6e280ed1771 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c @@ -0,0 +1,10 @@ +/* Verify proper errors are generated for conflicted interrupt type. */ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void __attribute__ ((interrupt ("user"))) +foo(void); + +void __attribute__ ((interrupt ("machine"))) +foo (void) +{ /* { dg-error "function cannot have different intterupt type." } */ +} -- 2.17.1