aboutsummaryrefslogtreecommitdiff
path: root/gcc
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
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')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/config/riscv/riscv.c82
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c10
4 files changed, 89 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 05b7ffb..9c95566 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2018-07-12 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.
+
2018-07-12 Paul Koning <ni1d@arrl.net>
* 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 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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e728838..48637b7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2018-07-12 Kito Cheng <kito.cheng@gmail.com>
+
+ * gcc.target/riscv/interrupt-conflict-mode.c: New.
+
2018-07-12 Jakub Jelinek <jakub@redhat.com>
* 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 0000000..6e280ed
--- /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." } */
+}