From patchwork Wed Jun 6 19:09:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jim Wilson X-Patchwork-Id: 926016 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-479210-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=sifive.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="W/9h5zo5"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 411JC15GJ9z9s2t for ; Thu, 7 Jun 2018 05:09:48 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; q=dns; s=default; b=iOrVDbKg3Rlt 7ir9Dr8ROBnT6yzAyGk88iyPrUIPOiV9gaMZ/qDsGXTz2kS9QpH5H4TBmIGcBqh/ 873rTupNKwQl1pkJ+6+zjaiVcuCQcp5wTJSeDPIURLzUMyi+V2mBADcxA0T9tb7f 5qISvER47J37EmC9pXfTW0Wt8Gizs1s= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id; s=default; bh=BYS3/07HhkaLYcyiIx 0ujOBYOAc=; b=W/9h5zo5+t4b8cRH8qwzpDf3sFcZKZqdTqgXwiMbJ9jgbwphWr OHmwlNqCaGzOVPTN+d0IsgD8olj8nSyLF/vD62ueGu2QtJy2pXzYX/dw6DpbNuMo R5thwQA2IRq58R/jny1O8couhYe1c9Nh9hPMmkmNr5DBYHswBNUdnP+30= Received: (qmail 120532 invoked by alias); 6 Jun 2018 19:09:42 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 119809 invoked by uid 89); 6 Jun 2018 19:09:41 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=defaults, supervisor, HX-Received:sk:d63-v6m, HX-Received:3c5 X-HELO: mail-pl0-f65.google.com Received: from mail-pl0-f65.google.com (HELO mail-pl0-f65.google.com) (209.85.160.65) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 06 Jun 2018 19:09:39 +0000 Received: by mail-pl0-f65.google.com with SMTP id f1-v6so4400349plt.6 for ; Wed, 06 Jun 2018 12:09:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=sBGfA6YHzCB+/SdACJt5BGhyhu5jDFpkZVnYunCK6eI=; b=X6pvLpg9jvln/FYUkmm/yDt5jEJ/i3TWk8kvI0++BtcHnOnstqQ+zp4T0HpqR/FTsO DXCilQ7gyqsRs4OWxFLBAkYOb6vCjkmhETpVUV86N7Cr1kI0u5yHHOOgmYnl0iolQE34 ZWh3aasJoT8stVjO8y3YRjJ2DZE4NHnc/h5ldXMcOTPf3oo65FWJBZ08oIWvX65Gxc7I iNHKoN9D0UvtassWopXZak3LTb7/NdP+Z7j9ZnWX2oMbNIhI81Mp478v80jTMOocgMk0 bQdQRBuCjSwLo2lxyuMyZVuZ5wrh/USjJgybv40n3HFxHrC4IrB7rTHe27ZQi4D6NTnS 2szg== X-Gm-Message-State: APt69E1j/5c/vuAig5ZXmVSCdKbd0G/6zE7xbn0DOD/yJjXFxr8IRoPf tk3i6jVeMvtQA31vWChqR653GGWPfmQ= X-Google-Smtp-Source: ADUXVKJgE5z+jV6h+yd0SuLnczNE3uDrFgix+uzkcn0D7BXfmrDTVwDgc0/6J0LoGTZLGNC9L9EBdA== X-Received: by 2002:a17:902:3c5:: with SMTP id d63-v6mr4417788pld.163.1528312177182; Wed, 06 Jun 2018 12:09:37 -0700 (PDT) Received: from rohan.hsd1.ca.comcast.net ([2601:646:c103:8ec:c578:c418:8704:1d46]) by smtp.gmail.com with ESMTPSA id h84-v6sm55454065pfd.69.2018.06.06.12.09.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 06 Jun 2018 12:09:36 -0700 (PDT) From: Jim Wilson To: gcc-patches@gcc.gnu.org Cc: Jim Wilson Subject: [PATCH] RISC-V: Add interrupt attribute modes. Date: Wed, 6 Jun 2018 12:09:33 -0700 Message-Id: <20180606190933.19318-1-jimw@sifive.com> This adds support for interrupt attributes to be used for user-level and supervisor-level delegated interrupts by adding an argument that allows one to specify the privilege level (aka mode). This also adds some testcases and documentation updates for the new feature. This was tested with riscv32-elf and riscv64-linux cross builds and checks. There were no regressions. Committed. Jim gcc/ * config/riscv/riscv.c (enum riscv_privilege_levels): New. (struct machine_function): New field interrupt_mode. (riscv_handle_type_attribute): New function. Add forward declaration. (riscv_attribute_table) : Use riscv_handle_type_attribute. (riscv_expand_epilogue): Check interrupt_mode field. (riscv_set_current_function): Check interrupt attribute args and set interrupt_mode field. * config/riscv/riscv.md (UNSPECV_SRET, UNSPECV_URET): New. (riscv_sret, riscv_uret): New. * doc/extend.texi (RISC-V Function Attributes) : Document new arguments to interrupt attribute. gcc/testsuite/ * gcc.target/riscv/interrupt-5.c (sub3): Add new test. * gcc.target/riscv/interrupt-mmode.c: New. * gcc.target/riscv/interrupt-smode.c: New. * gcc.target/riscv/interrupt-umode.c: New. --- gcc/config/riscv/riscv.c | 82 ++++++++++++++++++- gcc/config/riscv/riscv.md | 12 +++ gcc/doc/extend.texi | 11 +++ gcc/testsuite/gcc.target/riscv/interrupt-5.c | 5 ++ .../gcc.target/riscv/interrupt-mmode.c | 8 ++ .../gcc.target/riscv/interrupt-smode.c | 8 ++ .../gcc.target/riscv/interrupt-umode.c | 8 ++ 7 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-mmode.c create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-smode.c create mode 100644 gcc/testsuite/gcc.target/riscv/interrupt-umode.c diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index c418dc1ec2e..2709ebdd797 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -122,6 +122,10 @@ struct GTY(()) riscv_frame_info { HOST_WIDE_INT arg_pointer_offset; }; +enum riscv_privilege_levels { + USER_MODE, SUPERVISOR_MODE, MACHINE_MODE +}; + struct GTY(()) machine_function { /* The number of extra stack bytes taken up by register varargs. This area is allocated by the callee at the very top of the frame. */ @@ -132,6 +136,8 @@ struct GTY(()) machine_function { /* True if current function is an interrupt function. */ bool interrupt_handler_p; + /* For an interrupt handler, indicates the privilege level. */ + enum riscv_privilege_levels interrupt_mode; /* True if attributes on current function have been checked. */ bool attributes_checked_p; @@ -282,6 +288,7 @@ static const struct riscv_tune_info optimize_size_tune_info = { }; static tree riscv_handle_fndecl_attribute (tree *, tree, tree, int, bool *); +static tree riscv_handle_type_attribute (tree *, tree, tree, int, bool *); /* Defining target-specific uses of __attribute__. */ static const struct attribute_spec riscv_attribute_table[] = @@ -294,7 +301,8 @@ static const struct attribute_spec riscv_attribute_table[] = { "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 }, + { "interrupt", 0, 1, false, true, true, false, + riscv_handle_type_attribute, NULL }, /* The last attribute spec is set to be NULL. */ { NULL, 0, 0, false, false, false, false, NULL, NULL } @@ -2721,6 +2729,47 @@ riscv_handle_fndecl_attribute (tree *node, tree name, return NULL_TREE; } +/* Verify type based attributes. NODE is the what the attribute is being + applied to. NAME is the attribute name. ARGS are the attribute args. + FLAGS gives info about the context. NO_ADD_ATTRS should be set to true if + the attribute should be ignored. */ + +static tree +riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + /* Check for an argument. */ + if (is_attribute_p ("interrupt", name)) + { + if (args) + { + tree cst = TREE_VALUE (args); + const char *string; + + if (TREE_CODE (cst) != STRING_CST) + { + warning (OPT_Wattributes, + "%qE attribute requires a string argument", + name); + *no_add_attrs = true; + return NULL_TREE; + } + + string = TREE_STRING_POINTER (cst); + if (strcmp (string, "user") && strcmp (string, "supervisor") + && strcmp (string, "machine")) + { + warning (OPT_Wattributes, + "argument to %qE attribute is not \"user\", \"supervisor\", or \"machine\"", + name); + *no_add_attrs = true; + } + } + } + + return NULL_TREE; +} + /* Return true if function TYPE is an interrupt function. */ static bool riscv_interrupt_type_p (tree type) @@ -3932,7 +3981,16 @@ riscv_expand_epilogue (int style) /* Return from interrupt. */ if (cfun->machine->interrupt_handler_p) - emit_insn (gen_riscv_mret ()); + { + enum riscv_privilege_levels mode = cfun->machine->interrupt_mode; + + if (mode == MACHINE_MODE) + emit_insn (gen_riscv_mret ()); + else if (mode == SUPERVISOR_MODE) + emit_insn (gen_riscv_sret ()); + else + emit_insn (gen_riscv_uret ()); + } else if (style != SIBCALL_RETURN) emit_jump_insn (gen_simple_return_internal (ra)); } @@ -4494,14 +4552,32 @@ riscv_set_current_function (tree decl) if (cfun->machine->interrupt_handler_p) { - tree args = TYPE_ARG_TYPES (TREE_TYPE (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"); 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; } /* Don't print the above diagnostics more than once. */ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index b9faf00d076..a5940dcc425 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -58,6 +58,8 @@ ;; Interrupt handler instructions. UNSPECV_MRET + UNSPECV_SRET + UNSPECV_URET ;; Blockage and synchronization. UNSPECV_BLOCKAGE @@ -2298,6 +2300,16 @@ "" "mret") +(define_insn "riscv_sret" + [(unspec_volatile [(const_int 0)] UNSPECV_SRET)] + "" + "sret") + +(define_insn "riscv_uret" + [(unspec_volatile [(const_int 0)] UNSPECV_URET)] + "" + "uret") + (define_insn "stack_tie" [(set (mem:BLK (scratch)) (unspec:BLK [(match_operand:X 0 "register_operand" "r") diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index e9db1b292de..0c1c1b1dc16 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5147,6 +5147,17 @@ depended upon to work reliably and are not supported. Use this attribute to indicate that the specified function is an interrupt handler. The compiler generates function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. + +You can specify the kind of interrupt to be handled by adding an optional +parameter to the interrupt attribute like this: + +@smallexample +void f (void) __attribute__ ((interrupt ("user"))); +@end smallexample + +Permissible values for this parameter are @code{user}, @code{supervisor}, +and @code{machine}. If there is no parameter, then it defaults to +@code{machine}. @end table @node RL78 Function Attributes diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-5.c b/gcc/testsuite/gcc.target/riscv/interrupt-5.c index bf65e988c4e..324954eb1dd 100644 --- a/gcc/testsuite/gcc.target/riscv/interrupt-5.c +++ b/gcc/testsuite/gcc.target/riscv/interrupt-5.c @@ -14,3 +14,8 @@ void __attribute__ ((interrupt, naked)) sub2 (void) { /* { dg-error "are mutually exclusive" } */ } + +void __attribute__ ((interrupt ("hypervisor"))) +sub3 (void) +{ /* { dg-warning "argument to" } */ +} diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-mmode.c b/gcc/testsuite/gcc.target/riscv/interrupt-mmode.c new file mode 100644 index 00000000000..fd7a7a17e17 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/interrupt-mmode.c @@ -0,0 +1,8 @@ +/* Verify the return instruction is mret. */ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void __attribute__ ((interrupt ("machine"))) +foo (void) +{ +} +/* { dg-final { scan-assembler "mret" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-smode.c b/gcc/testsuite/gcc.target/riscv/interrupt-smode.c new file mode 100644 index 00000000000..2f696d30b02 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/interrupt-smode.c @@ -0,0 +1,8 @@ +/* Verify the return instruction is mret. */ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void __attribute__ ((interrupt ("supervisor"))) +foo (void) +{ +} +/* { dg-final { scan-assembler "sret" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-umode.c b/gcc/testsuite/gcc.target/riscv/interrupt-umode.c new file mode 100644 index 00000000000..cd120e489ca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/interrupt-umode.c @@ -0,0 +1,8 @@ +/* Verify the return instruction is mret. */ +/* { dg-do compile } */ +/* { dg-options "-O" } */ +void __attribute__ ((interrupt ("user"))) +foo (void) +{ +} +/* { dg-final { scan-assembler "uret" } } */