From patchwork Tue Jul 14 14:45:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Qing Zhao X-Patchwork-Id: 1328939 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=J10WT74Y; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4B5k0D3FT5z9sQt for ; Wed, 15 Jul 2020 00:48:10 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 84F9F3875419; Tue, 14 Jul 2020 14:48:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 84F9F3875419 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1594738087; bh=lJOTLcTYUwBUcSdvCWmS7VDgtTiM5DOPYZEhk515Tsk=; h=Subject:Date:In-Reply-To:To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=J10WT74YAe2KUiteS3K1boT53T5fEOg3EuX+ggS5IIdChJ2wWDb7tjegVoTZcs7Bj 0VyFeRPDegUFypICsgFlzg4D9V/+BSIDgYvEXHt2WZ9WxVOiKEB+5yorFfExu9byKp 1r6e5uwg61/INdfp7phWrpBp4zlF5IfgA6rgiUbs= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from userp2120.oracle.com (userp2120.oracle.com [156.151.31.85]) by sourceware.org (Postfix) with ESMTPS id 59429386486B for ; Tue, 14 Jul 2020 14:47:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 59429386486B Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 06EEb1eM092834; Tue, 14 Jul 2020 14:47:11 GMT Received: from aserp3020.oracle.com (aserp3020.oracle.com [141.146.126.70]) by userp2120.oracle.com with ESMTP id 32762ndp6c-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 14 Jul 2020 14:47:10 +0000 Received: from pps.filterd (aserp3020.oracle.com [127.0.0.1]) by aserp3020.oracle.com (8.16.0.42/8.16.0.42) with SMTP id 06EEbZom148243; Tue, 14 Jul 2020 14:45:09 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserp3020.oracle.com with ESMTP id 327qb49t9f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 14 Jul 2020 14:45:08 +0000 Received: from abhmp0008.oracle.com (abhmp0008.oracle.com [141.146.116.14]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id 06EEj6cK002666; Tue, 14 Jul 2020 14:45:06 GMT Received: from dhcp-10-154-178-119.vpn.oracle.com (/10.154.178.119) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 14 Jul 2020 07:45:06 -0700 Message-Id: <4ADA2BFC-DE6C-449E-84F7-2FFED4AF0789@ORACLE.COM> Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.14\)) Subject: [Patch][Middle-end]Add -fzero-call-used-regs=[skip|used-gpr|all-gpr|used|all] Date: Tue, 14 Jul 2020 09:45:04 -0500 In-Reply-To: To: Richard Biener , Uros Bizjak , "H.J. Lu" References: <20200504190118.1889086-1-hjl.tools@gmail.com> <20200504190118.1889086-2-hjl.tools@gmail.com> X-Mailer: Apple Mail (2.3445.104.14) X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9681 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxlogscore=999 malwarescore=0 mlxscore=0 spamscore=0 phishscore=0 suspectscore=4 bulkscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2007140113 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9681 signatures=668680 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 mlxscore=0 malwarescore=0 spamscore=0 clxscore=1011 priorityscore=1501 mlxlogscore=999 lowpriorityscore=0 bulkscore=0 suspectscore=4 phishscore=0 adultscore=0 impostorscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2006250000 definitions=main-2007140113 X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, KAM_SHORT, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP, UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Qing Zhao via Gcc-patches From: Qing Zhao Reply-To: Qing Zhao Cc: Jakub Jelinek , "gcc-patches@gcc.gnu.org" , Kees Cook , "Rodriguez Bahena, Victor" Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Hi, Gcc team, This patch is a follow-up on the previous patch and corresponding discussion: https://gcc.gnu.org/pipermail/gcc-patches/2020-May/545101.html From the previous round of discussion, the major issues raised were: A. should be rewritten by using regsets infrastructure. B. Put the patch into middle-end instead of x86 backend. This new patch is rewritten based on the above 2 comments. The major changes compared to the previous patch are: 1. Change the names of the option and attribute from -mzero-caller-saved-regs=[skip|used-gpr|all-gpr|used|all] and zero_caller_saved_regs("skip|used-gpr|all-gpr||used|all”) to: -fzero-call-used-regs=[skip|used-gpr|all-gpr|used|all] and zero_call_used_regs("skip|used-gpr|all-gpr||used|all”) Add the new option and new attribute in general. 2. The main code generation part is moved from i386 backend to middle-end; 3. Add 4 target-hooks; 4. Implement these 4 target-hooks on i386 backend. 5. On a target that does not implement the target hook, issue error for the new option, issue warning for the new attribute. The patch is as following: [PATCH] Add -fzero-call-used-regs=[skip|used-gpr|all-gpr|used|all] command-line option and zero_call_used_regs("skip|used-gpr|all-gpr||used|all") function attribue: 1. -fzero-call-used-regs=skip and zero_call_used_regs("skip") Don't zero call-used registers upon function return. 2. -fzero-call-used-regs=used-gpr and zero_call_used_regs("used-gpr") Zero used call-used general purpose registers upon function return. 3. -fzero-call-used-regs=all-gpr and zero_call_used_regs("all-gpr") Zero all call-used general purpose registers upon function return. 4. -fzero-call-used-regs=used and zero_call_used_regs("used") Zero used call-used registers upon function return. 5. -fzero-call-used-regs=all and zero_call_used_regs("all") Zero all call-used registers upon function return. The feature is implemented in middle-end. But currently is only valid on X86. Tested on x86-64 and aarch64 with bootstrapping GCC trunk, making -fzero-call-used-regs=used-gpr, -fzero-call-used-regs=all-gpr -fzero-call-used-regs=used, and -fzero-call-used-regs=all enabled by default on x86-64. Please take a look and let me know any more comment? thanks. Qing ==================================== gcc/ChangeLog: 2020-07-13 qing zhao > 2020-07-13 H.J. Lu > * common.opt: Add new option -fzero-call-used-regs. * config/i386/i386.c (ix86_zero_call_used_regno_p): New function. (ix86_zero_call_used_regno_mode): Likewise. (ix86_zero_all_vector_registers): Likewise. (ix86_expand_prologue): Replace gen_prologue_use with gen_pro_epilogue_use. (TARGET_ZERO_CALL_USED_REGNO_P): Define. (TARGET_ZERO_CALL_USED_REGNO_MODE): Define. (TARGET_PRO_EPILOGUE_USE): Define. (TARGET_ZERO_ALL_VECTOR_REGISTERS): Define. * config/i386/i386.md: Replace UNSPECV_PROLOGUE_USE with UNSPECV_PRO_EPILOGUE_USE. * coretypes.h (enum zero_call_used_regs): New type. * doc/extend.texi: Document the new zero_call_used_regs attribute. * doc/invoke.texi: Document the new -fzero-call-used-regs option. * doc/tm.texi: Regenerate. * doc/tm.texi.in (TARGET_ZERO_CALL_USED_REGNO_P): New hook. (TARGET_ZERO_CALL_USED_REGNO_MODE): Likewise. (TARGET_PRO_EPILOGUE_USE): Likewise. (TARGET_ZERO_ALL_VECTOR_REGISTERS): Likewise. * function.c (is_live_reg_at_exit): New function. (gen_call_used_regs_seq): Likewise. (make_epilogue_seq): Call gen_call_used_regs_seq. * function.h (is_live_reg_at_exit): Declare. * target.def (zero_call_used_regno_p): New hook. (zero_call_used_regno_mode): Likewise. (pro_epilogue_use): Likewise. (zero_all_vector_registers): Likewise. * targhooks.c (default_zero_call_used_regno_p): New function. (default_zero_call_used_regno_mode): Likewise. * targhooks.h (default_zero_call_used_regno_p): Declare. (default_zero_call_used_regno_mode): Declare. * toplev.c (process_options): Issue errors when -fzero-call-used-regs is used on targets that do not support it. * tree-core.h (struct tree_decl_with_vis): New field zero_call_used_regs_type. * tree.h (DECL_ZERO_CALL_USED_REGS): New macro. gcc/c-family/ChangeLog: 2020-07-13 qing zhao > 2020-07-13 H.J. Lu > * c-attribs.c (c_common_attribute_table): Add new attribute zero_call_used_regs. (handle_zero_call_used_regs_attribute): New function. gcc/c/ChangeLog: 2020-07-13 qing zhao > 2020-07-13 H.J. Lu > * c-decl.c (merge_decls): Merge zero_call_used_regs_type. gcc/testsuite/ChangeLog: 2020-07-13 qing zhao > 2020-07-13 H.J. Lu > * c-c++-common/zero-scratch-regs-1.c: New test. * c-c++-common/zero-scratch-regs-2.c: Likewise. * gcc.target/i386/zero-scratch-regs-1.c: Likewise. * gcc.target/i386/zero-scratch-regs-10.c: Likewise. * gcc.target/i386/zero-scratch-regs-11.c: Likewise. * gcc.target/i386/zero-scratch-regs-12.c: Likewise. * gcc.target/i386/zero-scratch-regs-13.c: Likewise. * gcc.target/i386/zero-scratch-regs-14.c: Likewise. * gcc.target/i386/zero-scratch-regs-15.c: Likewise. * gcc.target/i386/zero-scratch-regs-16.c: Likewise. * gcc.target/i386/zero-scratch-regs-17.c: Likewise. * gcc.target/i386/zero-scratch-regs-18.c: Likewise. * gcc.target/i386/zero-scratch-regs-19.c: Likewise. * gcc.target/i386/zero-scratch-regs-2.c: Likewise. * gcc.target/i386/zero-scratch-regs-20.c: Likewise. * gcc.target/i386/zero-scratch-regs-21.c: Likewise. * gcc.target/i386/zero-scratch-regs-22.c: Likewise. * gcc.target/i386/zero-scratch-regs-23.c: Likewise. * gcc.target/i386/zero-scratch-regs-3.c: Likewise. * gcc.target/i386/zero-scratch-regs-4.c: Likewise. * gcc.target/i386/zero-scratch-regs-5.c: Likewise. * gcc.target/i386/zero-scratch-regs-6.c: Likewise. * gcc.target/i386/zero-scratch-regs-7.c: Likewise. * gcc.target/i386/zero-scratch-regs-8.c: Likewise. * gcc.target/i386/zero-scratch-regs-9.c: Likewise. --- gcc/c-family/c-attribs.c | 68 ++++++++++ gcc/c/c-decl.c | 4 + gcc/common.opt | 23 ++++ gcc/config/i386/i386.c | 58 ++++++++- gcc/config/i386/i386.md | 6 +- gcc/coretypes.h | 10 ++ gcc/doc/extend.texi | 11 ++ gcc/doc/invoke.texi | 13 +- gcc/doc/tm.texi | 27 ++++ gcc/doc/tm.texi.in | 8 ++ gcc/function.c | 145 +++++++++++++++++++++ gcc/function.h | 2 + gcc/target.def | 33 +++++ gcc/targhooks.c | 17 +++ gcc/targhooks.h | 3 + gcc/testsuite/c-c++-common/zero-scratch-regs-1.c | 3 + gcc/testsuite/c-c++-common/zero-scratch-regs-2.c | 4 + .../gcc.target/i386/zero-scratch-regs-1.c | 12 ++ .../gcc.target/i386/zero-scratch-regs-10.c | 21 +++ .../gcc.target/i386/zero-scratch-regs-11.c | 39 ++++++ .../gcc.target/i386/zero-scratch-regs-12.c | 39 ++++++ .../gcc.target/i386/zero-scratch-regs-13.c | 21 +++ .../gcc.target/i386/zero-scratch-regs-14.c | 19 +++ .../gcc.target/i386/zero-scratch-regs-15.c | 14 ++ .../gcc.target/i386/zero-scratch-regs-16.c | 14 ++ .../gcc.target/i386/zero-scratch-regs-17.c | 13 ++ .../gcc.target/i386/zero-scratch-regs-18.c | 13 ++ .../gcc.target/i386/zero-scratch-regs-19.c | 12 ++ .../gcc.target/i386/zero-scratch-regs-2.c | 19 +++ .../gcc.target/i386/zero-scratch-regs-20.c | 23 ++++ .../gcc.target/i386/zero-scratch-regs-21.c | 14 ++ .../gcc.target/i386/zero-scratch-regs-22.c | 19 +++ .../gcc.target/i386/zero-scratch-regs-23.c | 19 +++ .../gcc.target/i386/zero-scratch-regs-3.c | 12 ++ .../gcc.target/i386/zero-scratch-regs-4.c | 14 ++ .../gcc.target/i386/zero-scratch-regs-5.c | 20 +++ .../gcc.target/i386/zero-scratch-regs-6.c | 14 ++ .../gcc.target/i386/zero-scratch-regs-7.c | 13 ++ .../gcc.target/i386/zero-scratch-regs-8.c | 19 +++ .../gcc.target/i386/zero-scratch-regs-9.c | 15 +++ gcc/toplev.c | 9 ++ gcc/tree-core.h | 6 +- gcc/tree.h | 5 + 43 files changed, 866 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/zero-scratch-regs-1.c create mode 100644 gcc/testsuite/c-c++-common/zero-scratch-regs-2.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c create mode 100644 gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 3721483..cc93d6f 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -136,6 +136,8 @@ static tree handle_target_clones_attribute (tree *, tree, tree, int, bool *); static tree handle_optimize_attribute (tree *, tree, tree, int, bool *); static tree ignore_attribute (tree *, tree, tree, int, bool *); static tree handle_no_split_stack_attribute (tree *, tree, tree, int, bool *); +static tree handle_zero_call_used_regs_attribute (tree *, tree, tree, int, + bool *); static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *); static tree handle_warn_unused_attribute (tree *, tree, tree, int, bool *); static tree handle_returns_nonnull_attribute (tree *, tree, tree, int, bool *); @@ -434,6 +436,9 @@ const struct attribute_spec c_common_attribute_table[] = ignore_attribute, NULL }, { "no_split_stack", 0, 0, true, false, false, false, handle_no_split_stack_attribute, NULL }, + { "zero_call_used_regs", 1, 1, true, false, false, false, + handle_zero_call_used_regs_attribute, NULL }, + /* For internal use (marking of builtins and runtime functions) only. The name contains space to prevent its usage in source code. */ { "fn spec", 1, 1, false, true, true, false, @@ -4506,6 +4511,69 @@ handle_no_split_stack_attribute (tree *node, tree name, return NULL_TREE; } +/* Handle a "zero_call_used_regs" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_zero_call_used_regs_attribute (tree *node, tree name, tree args, + int ARG_UNUSED (flags), + bool *no_add_attris) +{ + tree decl = *node; + tree id = TREE_VALUE (args); + enum zero_call_used_regs zero_call_used_regs_type = zero_call_used_regs_unset; + + if (TREE_CODE (decl) != FUNCTION_DECL) + { + error_at (DECL_SOURCE_LOCATION (decl), + "%qE attribute applies only to functions", name); + *no_add_attris = true; + return NULL_TREE; + } + else if (DECL_INITIAL (decl)) + { + error_at (DECL_SOURCE_LOCATION (decl), + "cannot set %qE attribute after definition", name); + *no_add_attris = true; + return NULL_TREE; + } + + if (TREE_CODE (id) != STRING_CST) + { + error ("attribute %qE arguments not a string", name); + *no_add_attris = true; + return NULL_TREE; + } + + if (!targetm.calls.pro_epilogue_use) + { + warning (OPT_Wattributes, "%qE attribute directive ignored", name); + return NULL_TREE; + } + + if (strcmp (TREE_STRING_POINTER (id), "skip") == 0) + zero_call_used_regs_type = zero_call_used_regs_skip; + else if (strcmp (TREE_STRING_POINTER (id), "used-gpr") == 0) + zero_call_used_regs_type = zero_call_used_regs_used_gpr; + else if (strcmp (TREE_STRING_POINTER (id), "all-gpr") == 0) + zero_call_used_regs_type = zero_call_used_regs_all_gpr; + else if (strcmp (TREE_STRING_POINTER (id), "used") == 0) + zero_call_used_regs_type = zero_call_used_regs_used; + else if (strcmp (TREE_STRING_POINTER (id), "all") == 0) + zero_call_used_regs_type = zero_call_used_regs_all; + else + { + error ("attribute %qE argument must be one of %qs, %qs, %qs, %qs, or %qs", + name, "skip", "used-gpr", "all-gpr", "used", "all"); + *no_add_attris = true; + return NULL_TREE; + } + + DECL_ZERO_CALL_USED_REGS (decl) = zero_call_used_regs_type; + + return NULL_TREE; +} + /* Handle a "returns_nonnull" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 81bd2ee..ded1880 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2681,6 +2681,10 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl); } + /* Merge the zero_call_used_regs_type information. */ + if (TREE_CODE (newdecl) == FUNCTION_DECL) + DECL_ZERO_CALL_USED_REGS (newdecl) = DECL_ZERO_CALL_USED_REGS (olddecl); + /* Merge the storage class information. */ merge_weak (newdecl, olddecl); diff --git a/gcc/common.opt b/gcc/common.opt index df8af36..19900f9 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3083,6 +3083,29 @@ fzero-initialized-in-bss Common Report Var(flag_zero_initialized_in_bss) Init(1) Put zero initialized data in the bss section. +fzero-call-used-regs= +Common Report RejectNegative Joined Enum(zero_call_used_regs) Var(flag_zero_call_used_regs) Init(zero_call_used_regs_skip) +Clear call-used registers upon function return. + +Enum +Name(zero_call_used_regs) Type(enum zero_call_used_regs) +Known choices of clearing call-used registers upon function return (for use with the -fzero-call-used-regs= option): + +EnumValue +Enum(zero_call_used_regs) String(skip) Value(zero_call_used_regs_skip) + +EnumValue +Enum(zero_call_used_regs) String(used-gpr) Value(zero_call_used_regs_used_gpr) + +EnumValue +Enum(zero_call_used_regs) String(all-gpr) Value(zero_call_used_regs_all_gpr) + +EnumValue +Enum(zero_call_used_regs) String(used) Value(zero_call_used_regs_used) + +EnumValue +Enum(zero_call_used_regs) String(all) Value(zero_call_used_regs_all) + g Common Driver RejectNegative JoinedOrMissing Generate debug information in default format. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 5c373c0..fd1aa9c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -3551,6 +3551,48 @@ ix86_function_value_regno_p (const unsigned int regno) return false; } +/* TARGET_ZERO_CALL_USED_REGNO_P. */ + +static bool +ix86_zero_call_used_regno_p (const unsigned int regno, + bool gpr_only) +{ + return GENERAL_REGNO_P (regno) || (!gpr_only && SSE_REGNO_P (regno)); +} + +/* TARGET_ZERO_CALL_USED_REGNO_MODE. */ + +static machine_mode +ix86_zero_call_used_regno_mode (const unsigned int regno, machine_mode) +{ + /* NB: We only need to zero the lower 32 bits for integer registers + and the lower 128 bits for vector registers since destination are + zero-extended to the full register width. */ + return GENERAL_REGNO_P (regno) ? SImode : V4SFmode; +} + +/* TARGET_ZERO_ALL_VECTOR_REGISTERS. */ + +static rtx +ix86_zero_all_vector_registers (bool used_only) +{ + if (!TARGET_AVX) + return NULL; + + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if ((IN_RANGE (regno, FIRST_SSE_REG, LAST_SSE_REG) + || (TARGET_64BIT + && (REX_SSE_REGNO_P (regno) + || (TARGET_AVX512F && EXT_REX_SSE_REGNO_P (regno))))) + && (!this_target_hard_regs->x_call_used_regs[regno] + || fixed_regs[regno] + || is_live_reg_at_exit (regno) + || (used_only && !df_regs_ever_live_p (regno)))) + return NULL; + + return gen_avx_vzeroall (); +} + /* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). If the precise function being called is known, FUNC is its FUNCTION_DECL; @@ -8513,7 +8555,7 @@ ix86_expand_prologue (void) insn = emit_insn (gen_set_got (pic)); RTX_FRAME_RELATED_P (insn) = 1; add_reg_note (insn, REG_CFA_FLUSH_QUEUE, NULL_RTX); - emit_insn (gen_prologue_use (pic)); + emit_insn (gen_pro_epilogue_use (pic)); /* Deleting already emmitted SET_GOT if exist and allocated to REAL_PIC_OFFSET_TABLE_REGNUM. */ ix86_elim_entry_set_got (pic); @@ -8542,7 +8584,7 @@ ix86_expand_prologue (void) Further, prevent alloca modifications to the stack pointer from being combined with prologue modifications. */ if (TARGET_SEH) - emit_insn (gen_prologue_use (stack_pointer_rtx)); + emit_insn (gen_pro_epilogue_use (stack_pointer_rtx)); } /* Emit code to restore REG using a POP insn. */ @@ -23319,6 +23361,18 @@ ix86_run_selftests (void) #undef TARGET_FUNCTION_VALUE_REGNO_P #define TARGET_FUNCTION_VALUE_REGNO_P ix86_function_value_regno_p +#undef TARGET_ZERO_CALL_USED_REGNO_P +#define TARGET_ZERO_CALL_USED_REGNO_P ix86_zero_call_used_regno_p + +#undef TARGET_ZERO_CALL_USED_REGNO_MODE +#define TARGET_ZERO_CALL_USED_REGNO_MODE ix86_zero_call_used_regno_mode + +#undef TARGET_PRO_EPILOGUE_USE +#define TARGET_PRO_EPILOGUE_USE gen_pro_epilogue_use + +#undef TARGET_ZERO_ALL_VECTOR_REGISTERS +#define TARGET_ZERO_ALL_VECTOR_REGISTERS ix86_zero_all_vector_registers + #undef TARGET_PROMOTE_FUNCTION_MODE #define TARGET_PROMOTE_FUNCTION_MODE ix86_promote_function_mode diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index d0ecd9e..e7df59f 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -194,7 +194,7 @@ UNSPECV_STACK_PROBE UNSPECV_PROBE_STACK_RANGE UNSPECV_ALIGN - UNSPECV_PROLOGUE_USE + UNSPECV_PRO_EPILOGUE_USE UNSPECV_SPLIT_STACK_RETURN UNSPECV_CLD UNSPECV_NOPS @@ -13525,8 +13525,8 @@ ;; As USE insns aren't meaningful after reload, this is used instead ;; to prevent deleting instructions setting registers for PIC code -(define_insn "prologue_use" - [(unspec_volatile [(match_operand 0)] UNSPECV_PROLOGUE_USE)] +(define_insn "pro_epilogue_use" + [(unspec_volatile [(match_operand 0)] UNSPECV_PRO_EPILOGUE_USE)] "" "" [(set_attr "length" "0")]) diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 6b6cfcd..e56d6ec 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -418,6 +418,16 @@ enum symbol_visibility VISIBILITY_INTERNAL }; +/* Zero call-used registers type. */ +enum zero_call_used_regs { + zero_call_used_regs_unset = 0, + zero_call_used_regs_skip, + zero_call_used_regs_used_gpr, + zero_call_used_regs_all_gpr, + zero_call_used_regs_used, + zero_call_used_regs_all +}; + /* enums used by the targetm.excess_precision hook. */ enum flt_eval_method diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index c800b74..b32c55f 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3984,6 +3984,17 @@ performing a link with relocatable output (i.e.@: @code{ld -r}) on them. A declaration to which @code{weakref} is attached and that is associated with a named @code{target} must be @code{static}. +@item zero_call_used_regs ("@var{choice}") +@cindex @code{zero_call_used_regs} function attribute +The @code{zero_call_used_regs} attribute causes the compiler to zero +call-used registers at function return according to @var{choice}. +@samp{skip} doesn't zero call-used registers. @samp{used-gpr} zeros +call-used general purpose registers which are used in funciton. +@samp{all-gpr} zeros all call-used general purpose registers. +@samp{used} zeros call-used registers which are used in function. +@samp{all} zeros all call-used registers. The default for the +attribute is controlled by @option{-fzero-call-used-regs}. + @end table @c This is the end of the target-independent attribute table diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 09bcc5b..da02686 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -542,7 +542,7 @@ Objective-C and Objective-C++ Dialects}. -funit-at-a-time -funroll-all-loops -funroll-loops @gol -funsafe-math-optimizations -funswitch-loops @gol -fipa-ra -fvariable-expansion-in-unroller -fvect-cost-model -fvpt @gol --fweb -fwhole-program -fwpa -fuse-linker-plugin @gol +-fweb -fwhole-program -fwpa -fuse-linker-plugin -fzero-call-used-regs @gol --param @var{name}=@var{value} -O -O0 -O1 -O2 -O3 -Os -Ofast -Og} @@ -12273,6 +12273,17 @@ int foo (void) Not all targets support this option. +@item -fzero-call-used-regs=@var{choice} +@opindex fzero-call-used-regs +Zero call-used registers at function return according to +@var{choice}. @samp{skip}, which is the default, doesn't zero +call-used registers. @samp{used-gpr} zeros call-used general purpose +registers which are used in function. @samp{all-gpr} zeros all +call-used registers. @samp{used} zeros call-used registers which +are used in function. @samp{all} zeros all call-used registers. You +can control this behavior for a specific function by using the function +attribute @code{zero_call_used_regs}. @xref{Function Attributes}. + @item --param @var{name}=@var{value} @opindex param In some places, GCC uses various constants to control the amount of diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 6e7d9dc..43dddd3 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -4571,6 +4571,22 @@ should recognize only the caller's register numbers. If this hook is not defined, then FUNCTION_VALUE_REGNO_P will be used. @end deftypefn +@deftypefn {Target Hook} bool TARGET_ZERO_CALL_USED_REGNO_P (const unsigned int @var{regno}, bool @var{general_reg_only_p}) +A target hook that returns @code{true} if @var{regno} is the number of a +call used register. If @var{general_reg_only_p} is @code{true}, +@var{regno} must be the number of a hard general register. + +If this hook is not defined, then default_zero_call_used_regno_p will be used. +@end deftypefn + +@deftypefn {Target Hook} machine_mode TARGET_ZERO_CALL_USED_REGNO_MODE (const unsigned int @var{regno}, machine_mode @var{mode}) +A target hook that returns a mode of suitable to zero the register for the +call used register @var{regno} in @var{mode}. + +If this hook is not defined, then default_zero_call_used_regno_mode will be +used. +@end deftypefn + @defmac APPLY_RESULT_SIZE Define this macro if @samp{untyped_call} and @samp{untyped_return} need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for @@ -12043,6 +12059,17 @@ argument list due to stack realignment. Return @code{NULL} if no DRAP is needed. @end deftypefn +@deftypefn {Target Hook} rtx TARGET_PRO_EPILOGUE_USE (rtx @var{reg}) +This hook should return a UNSPEC_VOLATILE rtx to mark a register in use to +prevent deleting register setting instructions in proprologue and epilogue. +@end deftypefn + +@deftypefn {Target Hook} rtx TARGET_ZERO_ALL_VECTOR_REGISTERS (bool @var{used_only}) +This hook should return an rtx to zero all vector registers at function +exit. If @var{used_only} is @code{true}, only used vector registers should +be zeroed. Return @code{NULL} if possible +@end deftypefn + @deftypefn {Target Hook} bool TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS (void) When optimization is disabled, this hook indicates whether or not arguments should be allocated to stack slots. Normally, GCC allocates diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 3be984b..bee917a 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -3430,6 +3430,10 @@ for a new target instead. @hook TARGET_FUNCTION_VALUE_REGNO_P +@hook TARGET_ZERO_CALL_USED_REGNO_P + +@hook TARGET_ZERO_CALL_USED_REGNO_MODE + @defmac APPLY_RESULT_SIZE Define this macro if @samp{untyped_call} and @samp{untyped_return} need more space than is implied by @code{FUNCTION_VALUE_REGNO_P} for @@ -8109,6 +8113,10 @@ and the associated definitions of those functions. @hook TARGET_GET_DRAP_RTX +@hook TARGET_PRO_EPILOGUE_USE + +@hook TARGET_ZERO_ALL_VECTOR_REGISTERS + @hook TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS @hook TARGET_CONST_ANCHOR diff --git a/gcc/function.c b/gcc/function.c index 9eee9b5..9908530 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "emit-rtl.h" #include "recog.h" #include "rtl-error.h" +#include "hard-reg-set.h" #include "alias.h" #include "fold-const.h" #include "stor-layout.h" @@ -5808,6 +5809,147 @@ make_prologue_seq (void) return seq; } +/* Check whether the hard register REGNO is live at the exit block + * of the current routine. */ +bool +is_live_reg_at_exit (unsigned int regno) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds) + { + bitmap live_out = df_get_live_out (e->src); + if (REGNO_REG_SET_P (live_out, regno)) + return true; + } + + return false; +} + +/* Emit a sequence of insns to zero the call-used-registers for the current + * function. */ + +static void +gen_call_used_regs_seq (void) +{ + if (!targetm.calls.pro_epilogue_use) + return; + + bool gpr_only = true; + bool used_only = true; + enum zero_call_used_regs zero_call_used_regs_type = zero_call_used_regs_unset; + + if (flag_zero_call_used_regs) + if (DECL_ZERO_CALL_USED_REGS (current_function_decl) + == zero_call_used_regs_unset) + zero_call_used_regs_type = flag_zero_call_used_regs; + else + zero_call_used_regs_type + = DECL_ZERO_CALL_USED_REGS (current_function_decl); + else + zero_call_used_regs_type = DECL_ZERO_CALL_USED_REGS (current_function_decl); + + /* No need to zero call-used-regs when no user request is present. */ + if (zero_call_used_regs_type <= zero_call_used_regs_skip) + return; + + /* No need to zero call-used-regs in main (). */ + if (MAIN_NAME_P (DECL_NAME (current_function_decl))) + return; + + /* No need to zero call-used-regs if __builtin_eh_return is called + since it isn't a normal function return. */ + if (crtl->calls_eh_return) + return; + + /* If gpr_only is true, only zero call-used-registers that are + general-purpose registers; if used_only is true, only zero + call-used-registers that are used in the current function. */ + switch (zero_call_used_regs_type) + { + case zero_call_used_regs_all_gpr: + used_only = false; + break; + case zero_call_used_regs_used: + gpr_only = false; + break; + case zero_call_used_regs_all: + gpr_only = false; + used_only = false; + break; + default: + break; + } + + /* An optimization to use a single hard insn to zero all vector registers on + the target that provides such insn. */ + if (!gpr_only + && targetm.calls.zero_all_vector_registers) + { + rtx zero_all_vec_insn + = targetm.calls.zero_all_vector_registers (used_only); + if (zero_all_vec_insn) + { + emit_insn (zero_all_vec_insn); + gpr_only = true; + } + } + + /* For each of the hard registers, check to see whether we should zero it if: + 1. it is a call-used-registers; + and 2. it is not a fixed-registers; + and 3. it is not live at the end of the routine; + and 4. it is general purpose register if gpr_only is true; + and 5. it is used in the routine if used_only is true; + */ + + /* This array holds the zero rtx with the correponding machine mode. */ + rtx zero_rtx[(int)MAX_MACHINE_MODE]; + for (int i = 0; i < (int) MAX_MACHINE_MODE; i++) + zero_rtx[i] = NULL_RTX; + + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + { + if (!this_target_hard_regs->x_call_used_regs[regno]) + continue; + if (fixed_regs[regno]) + continue; + if (is_live_reg_at_exit (regno)) + continue; + if (!targetm.calls.zero_call_used_regno_p (regno, gpr_only)) + continue; + if (used_only && !df_regs_ever_live_p (regno)) + continue; + + /* Now we can emit insn to zero this register. */ + rtx reg, tmp; + + machine_mode mode + = targetm.calls.zero_call_used_regno_mode (regno, + reg_raw_mode[regno]); + if (mode == VOIDmode) + continue; + if (!have_regs_of_mode[mode]) + continue; + + reg = gen_rtx_REG (mode, regno); + if (zero_rtx[(int)mode] == NULL_RTX) + { + zero_rtx[(int)mode] = reg; + tmp = gen_rtx_SET (reg, const0_rtx); + emit_insn (tmp); + } + else + emit_move_insn (reg, zero_rtx[(int)mode]); + + emit_insn (targetm.calls.pro_epilogue_use (reg)); + } + + return; +} + + /* Return a sequence to be used as the epilogue for the current function, or NULL. */ @@ -5819,6 +5961,9 @@ make_epilogue_seq (void) start_sequence (); emit_note (NOTE_INSN_EPILOGUE_BEG); + + gen_call_used_regs_seq (); + rtx_insn *seq = targetm.gen_epilogue (); if (seq) emit_jump_insn (seq); diff --git a/gcc/function.h b/gcc/function.h index d55cbdd..fc36c3e 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -705,4 +705,6 @@ extern const char *current_function_name (void); extern void used_types_insert (tree); +extern bool is_live_reg_at_exit (unsigned int); + #endif /* GCC_FUNCTION_H */ diff --git a/gcc/target.def b/gcc/target.def index 07059a8..8aab63e 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -5022,6 +5022,26 @@ If this hook is not defined, then FUNCTION_VALUE_REGNO_P will be used.", default_function_value_regno_p) DEFHOOK +(zero_call_used_regno_p, + "A target hook that returns @code{true} if @var{regno} is the number of a\n\ +call used register. If @var{general_reg_only_p} is @code{true},\n\ +@var{regno} must be the number of a hard general register.\n\ +\n\ +If this hook is not defined, then default_zero_call_used_regno_p will be used.", + bool, (const unsigned int regno, bool general_reg_only_p), + default_zero_call_used_regno_p) + +DEFHOOK +(zero_call_used_regno_mode, + "A target hook that returns a mode of suitable to zero the register for the\n\ +call used register @var{regno} in @var{mode}.\n\ +\n\ +If this hook is not defined, then default_zero_call_used_regno_mode will be\n\ +used.", + machine_mode, (const unsigned int regno, machine_mode mode), + default_zero_call_used_regno_mode) + +DEFHOOK (fntype_abi, "Return the ABI used by a function with type @var{type}; see the\n\ definition of @code{predefined_function_abi} for details of the ABI\n\ @@ -5068,6 +5088,19 @@ argument list due to stack realignment. Return @code{NULL} if no DRAP\n\ is needed.", rtx, (void), NULL) +DEFHOOK +(pro_epilogue_use, + "This hook should return a UNSPEC_VOLATILE rtx to mark a register in use to\n\ +prevent deleting register setting instructions in proprologue and epilogue.", + rtx, (rtx reg), NULL) + +DEFHOOK +(zero_all_vector_registers, + "This hook should return an rtx to zero all vector registers at function\n\ +exit. If @var{used_only} is @code{true}, only used vector registers should\n\ +be zeroed. Return @code{NULL} if possible", + rtx, (bool used_only), NULL) + /* Return true if all function parameters should be spilled to the stack. */ DEFHOOK diff --git a/gcc/targhooks.c b/gcc/targhooks.c index 0113c7b..ed02173 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -987,6 +987,23 @@ default_function_value_regno_p (const unsigned int regno ATTRIBUTE_UNUSED) #endif } +/* The default hook for TARGET_ZERO_CALL_USED_REGNO_P. */ + +bool +default_zero_call_used_regno_p (const unsigned int, + bool) +{ + return false; +} + +/* The default hook for TARGET_ZERO_CALL_USED_REGNO_MODE. */ + +machine_mode +default_zero_call_used_regno_mode (const unsigned int, machine_mode mode) +{ + return mode; +} + rtx default_internal_arg_pointer (void) { diff --git a/gcc/targhooks.h b/gcc/targhooks.h index b572a36..370df19 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -162,6 +162,9 @@ extern bool hook_bool_const_rtx_commutative_p (const_rtx, int); extern rtx default_function_value (const_tree, const_tree, bool); extern rtx default_libcall_value (machine_mode, const_rtx); extern bool default_function_value_regno_p (const unsigned int); +extern bool default_zero_call_used_regno_p (const unsigned int, bool); +extern machine_mode default_zero_call_used_regno_mode (const unsigned int, + machine_mode); extern rtx default_internal_arg_pointer (void); extern rtx default_static_chain (const_tree, bool); extern void default_trampoline_init (rtx, tree, rtx); diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-1.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-1.c new file mode 100644 index 0000000..3c2ac72 --- /dev/null +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-1.c @@ -0,0 +1,3 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fzero-call-used-regs=used" } */ +/* { dg-error "'-fzero-call-used-regs=' is not supported for this target" "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */ diff --git a/gcc/testsuite/c-c++-common/zero-scratch-regs-2.c b/gcc/testsuite/c-c++-common/zero-scratch-regs-2.c new file mode 100644 index 0000000..acf48c4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/zero-scratch-regs-2.c @@ -0,0 +1,4 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2" } */ + +extern int foo (int) __attribute__ ((zero_call_used_regs("all-gpr"))); /* { dg-warning " attribute directive ignored" "" {target { ! "i?86-*-* x86_64-*-*" } } 0 } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c new file mode 100644 index 0000000..9f61dc4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-1.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=used" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c new file mode 100644 index 0000000..09048e5 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-10.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ + +extern int foo (int) __attribute__ ((zero_call_used_regs("all-gpr"))); + +int +foo (int x) +{ + return x; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%edx, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c new file mode 100644 index 0000000..4862688 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-11.c @@ -0,0 +1,39 @@ +/* { dg-do run { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=used-gpr" } */ + +struct S { int i; }; +__attribute__((const, noinline, noclone)) +struct S foo (int x) +{ + struct S s; + s.i = x; + return s; +} + +int a[2048], b[2048], c[2048], d[2048]; +struct S e[2048]; + +__attribute__((noinline, noclone)) void +bar (void) +{ + int i; + for (i = 0; i < 1024; i++) + { + e[i] = foo (i); + a[i+2] = a[i] + a[i+1]; + b[10] = b[10] + i; + c[i] = c[2047 - i]; + d[i] = d[i + 1]; + } +} + +int +main () +{ + int i; + bar (); + for (i = 0; i < 1024; i++) + if (e[i].i != i) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c new file mode 100644 index 0000000..500251b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-12.c @@ -0,0 +1,39 @@ +/* { dg-do run { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ + +struct S { int i; }; +__attribute__((const, noinline, noclone)) +struct S foo (int x) +{ + struct S s; + s.i = x; + return s; +} + +int a[2048], b[2048], c[2048], d[2048]; +struct S e[2048]; + +__attribute__((noinline, noclone)) void +bar (void) +{ + int i; + for (i = 0; i < 1024; i++) + { + e[i] = foo (i); + a[i+2] = a[i] + a[i+1]; + b[10] = b[10] + i; + c[i] = c[2047 - i]; + d[i] = d[i + 1]; + } +} + +int +main () +{ + int i; + bar (); + for (i = 0; i < 1024; i++) + if (e[i].i != i) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c new file mode 100644 index 0000000..8b058e3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-13.c @@ -0,0 +1,21 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm0, %xmm0" } } */ +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm0, %xmm\[0-9\]+" 7 { target { ia32 } } } } */ +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm0, %xmm\[0-9\]+" 15 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c new file mode 100644 index 0000000..d4eaaf7 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-14.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7 -mavx" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-times "vzeroall" 1 } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c new file mode 100644 index 0000000..dd3bb90 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-15.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ + +extern void foo (void) __attribute__ ((zero_call_used_regs("used"))); + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c new file mode 100644 index 0000000..e2274f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-16.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all" } */ + +extern void foo (void) __attribute__ ((zero_call_used_regs("skip"))); + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c new file mode 100644 index 0000000..7f5d153 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-17.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=used" } */ + +int +foo (int x) +{ + return x; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" { target ia32 } } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%edi, %edi" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c new file mode 100644 index 0000000..fe13d2b --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-18.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=used -march=corei7" } */ + +float +foo (float z, float y, float x) +{ + return x + y; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm1, %xmm1" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movaps\[ \t\]*%xmm1, %xmm2" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c new file mode 100644 index 0000000..205a532 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-19.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=used -march=corei7" } */ + +float +foo (float z, float y, float x) +{ + return x; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm2, %xmm2" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c new file mode 100644 index 0000000..e046684 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-2.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c new file mode 100644 index 0000000..4be8ff6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-20.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7" } */ + +float +foo (float z, float y, float x) +{ + return x + y; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm0, %xmm0" { target { ia32 } } } } */ +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm1, %xmm1" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm0, %xmm\[0-9\]+" 7 { target { ia32 } } } } */ +/* { dg-final { scan-assembler-times "movaps\[ \t\]*%xmm1, %xmm\[0-9\]+" 14 { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c new file mode 100644 index 0000000..0eb34e0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-21.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip -march=corei7" } */ + +__attribute__ ((zero_call_used_regs("used"))) +float +foo (float z, float y, float x) +{ + return x + y; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler "pxor\[ \t\]*%xmm1, %xmm1" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movaps\[ \t\]*%xmm1, %xmm2" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c new file mode 100644 index 0000000..cbb63a4 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-22.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7 -mavx" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c new file mode 100644 index 0000000..7573197 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-23.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all -march=corei7 -mavx512f" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c new file mode 100644 index 0000000..de71223 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-3.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c new file mode 100644 index 0000000..ccfa441 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-4.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ + +extern void foo (void) __attribute__ ((zero_call_used_regs("used-gpr"))); + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c new file mode 100644 index 0000000..6b46ca3 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-5.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ + +__attribute__ ((zero_call_used_regs("all-gpr"))) +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%eax, %eax" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%eax, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c new file mode 100644 index 0000000..0680f38 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-6.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ + +extern void foo (void) __attribute__ ((zero_call_used_regs("skip"))); + +void +foo (void) +{ +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" } } */ +/* { dg-final { scan-assembler-not "movl\[ \t\]*%" } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c new file mode 100644 index 0000000..534defa --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-7.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=used-gpr" } */ + +int +foo (int x) +{ + return x; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" { target ia32 } } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%edi, %edi" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c new file mode 100644 index 0000000..477bb19 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-8.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=all-gpr" } */ + +int +foo (int x) +{ + return x; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%edx, %edx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %ecx" } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %esi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %edi" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r8d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r9d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r10d" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movl\[ \t\]*%edx, %r11d" { target { ! ia32 } } } } */ diff --git a/gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c new file mode 100644 index 0000000..a305a60 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/zero-scratch-regs-9.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target *-*-linux* } } */ +/* { dg-options "-O2 -fzero-call-used-regs=skip" } */ + +extern int foo (int) __attribute__ ((zero_call_used_regs("used-gpr"))); + +int +foo (int x) +{ + return x; +} + +/* { dg-final { scan-assembler-not "vzeroall" } } */ +/* { dg-final { scan-assembler-not "%xmm" } } */ +/* { dg-final { scan-assembler-not "xorl\[ \t\]*%" { target ia32 } } } */ +/* { dg-final { scan-assembler "xorl\[ \t\]*%edi, %edi" { target { ! ia32 } } } } */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 95eea63..01a1f24 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -1464,6 +1464,15 @@ process_options (void) } } + if (flag_zero_call_used_regs != zero_call_used_regs_skip + && !targetm.calls.pro_epilogue_use) + { + error_at (UNKNOWN_LOCATION, + "%<-fzero-call-used-regs=%> is not supported for this " + "target"); + flag_zero_call_used_regs = zero_call_used_regs_skip; + } + /* One region RA really helps to decrease the code size. */ if (flag_ira_region == IRA_REGION_AUTODETECT) flag_ira_region diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 8c5a2e3..71badbd 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1825,7 +1825,11 @@ struct GTY(()) tree_decl_with_vis { unsigned final : 1; /* Belong to FUNCTION_DECL exclusively. */ unsigned regdecl_flag : 1; - /* 14 unused bits. */ + + /* How to clear call-used registers upon function return. */ + ENUM_BITFIELD(zero_call_used_regs) zero_call_used_regs_type : 3; + + /* 11 unused bits. */ }; struct GTY(()) tree_var_decl { diff --git a/gcc/tree.h b/gcc/tree.h index cf546ed..d378a88 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2925,6 +2925,11 @@ extern void decl_value_expr_insert (tree, tree); #define DECL_VISIBILITY(NODE) \ (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.visibility) +/* Value of the function decl's type of zeroing the call used + registers upon return from function. */ +#define DECL_ZERO_CALL_USED_REGS(NODE) \ + (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.zero_call_used_regs_type) + /* Nonzero means that the decl (or an enclosing scope) had its visibility specified rather than being inferred. */ #define DECL_VISIBILITY_SPECIFIED(NODE) \