From 8528f27bda0fd315eef48827c10a9c488071ceb3 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Thu, 12 Jul 2018 19:59:09 +0000 Subject: [PATCH] RISC-V: Error if function declared with different interrupt modes. gcc/ 2018-07-06 Kito Cheng * config/riscv/riscv.c (enum riscv_privilege_levels): Add UNKNOWN_MODE. (riscv_expand_epilogue): Add 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/ 2018-07-06 Kito Cheng * gcc.target/riscv/interrupt-conflict-mode.c: New. From-SVN: r262607 --- gcc/ChangeLog | 11 +++ gcc/config/riscv/riscv.c | 82 +++++++++++++++---- gcc/testsuite/ChangeLog | 4 + .../riscv/interrupt-conflict-mode.c | 10 +++ 4 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 05b7ffbd392..9c955669e17 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2018-07-12 Kito Cheng + + * config/riscv/riscv.c (enum riscv_privilege_levels): Add UNKNOWN_MODE. + (riscv_expand_epilogue): Add 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. + 2018-07-12 Paul Koning * config/pdp11/pdp11.c (pdp11_output_def): Fix typo in .set diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 218f4de7d41..69e70feaf33 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/ChangeLog b/gcc/testsuite/ChangeLog index e72883860d6..48637b74d8a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2018-07-12 Kito Cheng + + * gcc.target/riscv/interrupt-conflict-mode.c: New. + 2018-07-12 Jakub Jelinek * c-c++-common/gomp/declare-target-3.c: New test. 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.30.2