From patchwork Thu Oct 1 12:50:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 1375048 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=ucw.cz 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 4C2Cdy4DTCz9sSf for ; Thu, 1 Oct 2020 22:50:27 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 51DEE385ED4D; Thu, 1 Oct 2020 12:50:23 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from nikam.ms.mff.cuni.cz (nikam.ms.mff.cuni.cz [195.113.20.16]) by sourceware.org (Postfix) with ESMTPS id AE9BB3857C6D for ; Thu, 1 Oct 2020 12:50:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org AE9BB3857C6D Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=ucw.cz Authentication-Results: sourceware.org; spf=none smtp.mailfrom=hubicka@kam.mff.cuni.cz Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 0124128017E; Thu, 1 Oct 2020 14:50:12 +0200 (CEST) Date: Thu, 1 Oct 2020 14:50:12 +0200 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, rguenther@suse.de Subject: Commonize handling of attr-fnspec Message-ID: <20201001125012.GA63091@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) X-Spam-Status: No, score=-14.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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-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: , Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Hi, this patch adds the simple class for parsing fnspec attribute. I plan to add support for generating and modifying it too (it is used by fortran and I plan to make modref to detect noclobbers and stuff). Verification is disabled until we fix remaining fortran specifier (I got a promised help at monday) Bootstrapped/regtested x86_64-linux, OK? Honza gcc/ChangeLog: 2020-10-01 Jan Hubicka * calls.c (decl_return_flags): Implement using attr_fnspec. * gimple.c (gimple_call_arg_flags): Likewise (gimple_call_return_flags): Likewise * tree-into-ssa.c (pass_build_ssa::execute): Likewise. * tree-ssa-alias.c (attr_fnspec::verify): New * attr-fnspec.h: New file. diff --git a/gcc/calls.c b/gcc/calls.c index ed4363811c8..94f433685b9 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -58,6 +58,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "builtins.h" #include "gimple-fold.h" +#include "attr-fnspec.h" #include "tree-pretty-print.h" @@ -642,25 +643,14 @@ decl_return_flags (tree fndecl) if (!attr) return 0; - attr = TREE_VALUE (TREE_VALUE (attr)); - if (!attr || TREE_STRING_LENGTH (attr) < 1) - return 0; - - switch (TREE_STRING_POINTER (attr)[0]) - { - case '1': - case '2': - case '3': - case '4': - return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1'); + attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (attr))); - case 'm': - return ERF_NOALIAS; + if (fnspec.returns_arg () >= 0) + return ERF_RETURNS_ARG | fnspec.returns_arg (); - case '.': - default: - return 0; - } + if (fnspec.returns_noalias_p ()) + return ERF_NOALIAS; + return 0; } /* Return nonzero when FNDECL represents a call to setjmp. */ diff --git a/gcc/gimple.c b/gcc/gimple.c index fd4e0fac0d4..2f2db309df5 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "attribs.h" #include "asan.h" #include "langhooks.h" +#include "attr-fnspec.h" /* All the tuples have their operand vector (if present) at the very bottom @@ -1508,31 +1509,26 @@ gimple_call_arg_flags (const gcall *stmt, unsigned arg) { const_tree attr = gimple_call_fnspec (stmt); - if (!attr || 1 + arg >= (unsigned) TREE_STRING_LENGTH (attr)) + if (!attr) return 0; - switch (TREE_STRING_POINTER (attr)[1 + arg]) - { - case 'x': - case 'X': - return EAF_UNUSED; - - case 'R': - return EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE; - - case 'r': - return EAF_NOCLOBBER | EAF_NOESCAPE; - - case 'W': - return EAF_DIRECT | EAF_NOESCAPE; - - case 'w': - return EAF_NOESCAPE; + int flags = 0; + attr_fnspec fnspec (attr); - case '.': - default: - return 0; + if (!fnspec.arg_specified_p (arg)) + ; + else if (!fnspec.arg_used_p (arg)) + flags = EAF_UNUSED; + else + { + if (!fnspec.arg_direct_p (arg)) + flags |= EAF_DIRECT; + if (!fnspec.arg_noescape_p (arg)) + flags |= EAF_NOESCAPE; + if (!fnspec.arg_readonly_p (arg)) + flags |= EAF_NOCLOBBER; } + return flags; } /* Detects return flags for the call STMT. */ @@ -1546,24 +1542,16 @@ gimple_call_return_flags (const gcall *stmt) return ERF_NOALIAS; attr = gimple_call_fnspec (stmt); - if (!attr || TREE_STRING_LENGTH (attr) < 1) + if (!attr) return 0; + attr_fnspec fnspec (attr); - switch (TREE_STRING_POINTER (attr)[0]) - { - case '1': - case '2': - case '3': - case '4': - return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1'); - - case 'm': - return ERF_NOALIAS; + if (fnspec.returns_arg () >= 0) + return ERF_RETURNS_ARG | fnspec.returns_arg (); - case '.': - default: - return 0; - } + if (fnspec.returns_noalias_p ()) + return ERF_NOALIAS; + return 0; } diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 0d016134774..1493b323956 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -41,6 +41,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "asan.h" +#include "attr-fnspec.h" #define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y)) @@ -2492,19 +2493,19 @@ pass_build_ssa::execute (function *fun) } /* Initialize SSA_NAME_POINTS_TO_READONLY_MEMORY. */ - tree fnspec = lookup_attribute ("fn spec", - TYPE_ATTRIBUTES (TREE_TYPE (fun->decl))); - if (fnspec) + tree fnspec_tree + = lookup_attribute ("fn spec", + TYPE_ATTRIBUTES (TREE_TYPE (fun->decl))); + if (fnspec_tree) { - fnspec = TREE_VALUE (TREE_VALUE (fnspec)); - unsigned i = 1; + attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (fnspec_tree))); + unsigned i = 0; for (tree arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg), ++i) { - if (i >= (unsigned) TREE_STRING_LENGTH (fnspec)) - break; - if (TREE_STRING_POINTER (fnspec)[i] == 'R' - || TREE_STRING_POINTER (fnspec)[i] == 'r') + if (!fnspec.arg_specified_p (i)) + break; + if (fnspec.arg_readonly_p (i)) { tree name = ssa_default_def (fun, arg); if (name) diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index fe390d4ffbe..2b2d53ebb88 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -40,6 +40,8 @@ along with GCC; see the file COPYING3. If not see #include "varasm.h" #include "ipa-modref-tree.h" #include "ipa-modref.h" +#include "attr-fnspec.h" +#include "errors.h" /* Broad overview of how alias analysis on gimple works: @@ -3984,3 +3985,42 @@ walk_aliased_vdefs (ao_ref *ref, tree vdef, return ret; } +/* Verify validity of the fnspec string. + See attr-fnspec.h for details. */ + +void +attr_fnspec::verify () +{ + /* FIXME: Fortran trans-decl.c contains multiple wrong fnspec strings. + re-enable verification after these are fixed. */ + return; + bool err = false; + + /* Check return value specifier. */ + if (len < return_desc_size) + err = true; + else if ((str[0] < '1' || str[0] > '4') + && str[0] != '.' && str[0] != 'm') + err = true; + + /* Now check all parameters. */ + for (unsigned int i = 0; arg_specified_p (i); i++) + { + unsigned int idx = arg_idx (i); + switch (str[idx]) + { + case 'x': + case 'X': + case 'r': + case 'R': + case 'w': + case 'W': + case '.': + break; + default: + err = true; + } + } + if (err) + internal_error ("invalid fn spec attribute %s", str); +} --- attr-fnspec.h 2020-10-01 14:39:32.565476448 +0200 +++ attr-fnspec.h 2020-10-01 14:35:02.069814323 +0200 @@ -0,0 +1,150 @@ +/* Handling of fnspec attribute specifiers + Copyright (C) 2008-2020 Free Software Foundation, Inc. + Contributed by Richard Guenther + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + GCC is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +/* Parse string of attribute "fn spec". This is an internal attribute + describing side effects of a function as follows: + + character 0 specifies properties of return values as follows: + '1'...'4' specifies number of argument function returns (as in memset) + 'm' specifies that returned value is noalias (as in malloc) + '.' specifies that nothing is known. + + character 1+i specifies properties of argument number i as follows: + 'x' or 'X' specifies that parameter is unused. + 'r' or 'R' specifies that parameter is only read and memory pointed to is + never dereferenced. + 'w' or 'W' specifies that parameter is only written to. + '.' specifies that nothing is known. + The uppercase letter in addition specifies that parameter + is non-escaping. */ + +#ifndef ATTR_FNSPEC_H +#define ATTR_FNSPEC_H + +class attr_fnspec +{ +private: + /* fn spec attribute string. */ + const char *str; + /* length of the fn spec string. */ + const unsigned len; + /* Number of characters specifying return value. */ + const unsigned int return_desc_size = 1; + /* Number of characters specifying size. */ + const unsigned int arg_desc_size = 1; + + /* Return start of specifier of arg i. */ + unsigned int arg_idx (int i) + { + return return_desc_size + arg_desc_size * i; + } + +public: + attr_fnspec (const char *str, unsigned len) + : str (str), len (len) + { + if (flag_checking) + verify (); + } + attr_fnspec (const_tree identifier) + : str (TREE_STRING_POINTER (identifier)), + len (TREE_STRING_LENGTH (identifier)) + { + if (flag_checking) + verify (); + } + + /* Return true if arg I is specified. */ + bool + arg_specified_p (unsigned int i) + { + return len >= arg_idx (i + 1); + } + + /* True if the argument is not dereferenced recursively, thus only + directly reachable memory is read or written. */ + bool + arg_direct_p (unsigned int i) + { + unsigned int idx = arg_idx (i); + gcc_checking_assert (arg_specified_p (i)); + return str[idx] == 'R' || str[idx] == 'W'; + } + + /* True if argument is used. */ + bool + arg_used_p (unsigned int i) + { + unsigned int idx = arg_idx (i); + gcc_checking_assert (arg_specified_p (i)); + return str[idx] != 'x' && str[idx] != 'X'; + } + + /* True if memory reached by the argument is readonly (not clobbered). */ + bool + arg_readonly_p (unsigned int i) + { + unsigned int idx = arg_idx (i); + gcc_checking_assert (arg_specified_p (i)); + return str[idx] == 'r' || str[idx] == 'R'; + } + + /* True if memory reached is only written into (but not read). */ + bool + arg_writeonly_p (unsigned int i) + { + unsigned int idx = arg_idx (i); + gcc_checking_assert (arg_specified_p (i)); + return str[idx] == 'w' || str[idx] == 'W'; + } + + /* True if the argument does not escape. */ + bool + arg_noescape_p (unsigned int i) + { + unsigned int idx = arg_idx (i); + gcc_checking_assert (arg_specified_p (i)); + return str[idx] == 'w' || str[idx] == 'W' + || str[idx] == 'R' || str[idx] == 'r'; + } + + /* If not equal to -1 then it specifies number of argument returned by + the function. */ + int + returns_arg () + { + if (str[0] >= '1' && str[0] <= '4') + return str[0]-'1'; + return -1; + } + + /* Nonzero if the return value does not alias with anything. Functions + with the malloc attribute have this set on their return value. */ + int + returns_noalias_p () + { + return str[0] == 'm'; + } + + /* Check validity of the string. */ + void verify (); +}; + +#endif /* ATTR_FNSPEC_H */