aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorKito Cheng <kito.cheng@gmail.com>2018-07-12 19:59:09 +0000
committerJim Wilson <wilson@gcc.gnu.org>2018-07-12 12:59:09 -0700
commit8528f27bda0fd315eef48827c10a9c488071ceb3 (patch)
treeb66502e693e5e6a21f3dafc9da0ccfcf3df98c9d /gcc/config
parent9b4520336913e7015415fa921ea1de89ac98cfa9 (diff)
downloadgcc-8528f27bda0fd315eef48827c10a9c488071ceb3.zip
gcc-8528f27bda0fd315eef48827c10a9c488071ceb3.tar.gz
gcc-8528f27bda0fd315eef48827c10a9c488071ceb3.tar.bz2
RISC-V: Error if function declared with different interrupt modes.
gcc/ 2018-07-06 Kito Cheng <kito.cheng@gmail.com> * 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 <kito.cheng@gmail.com> * gcc.target/riscv/interrupt-conflict-mode.c: New. From-SVN: r262607
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/riscv/riscv.c82
1 files changed, 64 insertions, 18 deletions
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 218f4de..69e70fe 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