Commonize handling of attr-fnspec
* attr-fnspec.h: New file. * calls.c (decl_return_flags): Use attr_fnspec. * gimple.c (gimple_call_arg_flags): Use attr_fnspec. (gimple_call_return_flags): Use attr_fnspec. * tree-into-ssa.c (pass_build_ssa::execute): Use attr_fnspec. * tree-ssa-alias.c (attr_fnspec::verify): New member fuction.
This commit is contained in:
parent
b8e773e992
commit
05d39f0de9
5 changed files with 229 additions and 62 deletions
145
gcc/attr-fnspec.h
Normal file
145
gcc/attr-fnspec.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/* Handling of fnspec attribute specifiers
|
||||
Copyright (C) 2008-2020 Free Software Foundation, Inc.
|
||||
Contributed by Richard Guenther <rguenther@suse.de>
|
||||
|
||||
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
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* 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 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';
|
||||
}
|
||||
|
||||
/* Return true if function returns value of its parameter. If ARG_NO is
|
||||
non-NULL return initialize it to the argument returned. */
|
||||
bool
|
||||
returns_arg (unsigned int *arg_no)
|
||||
{
|
||||
if (str[0] >= '1' && str[0] <= '4')
|
||||
{
|
||||
if (arg_no)
|
||||
*arg_no = str[0] - '1';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Nonzero if the return value does not alias with anything. Functions
|
||||
with the malloc attribute have this set on their return value. */
|
||||
bool
|
||||
returns_noalias_p ()
|
||||
{
|
||||
return str[0] == 'm';
|
||||
}
|
||||
|
||||
/* Check validity of the string. */
|
||||
void verify ();
|
||||
};
|
||||
|
||||
#endif /* ATTR_FNSPEC_H */
|
25
gcc/calls.c
25
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,15 @@ decl_return_flags (tree fndecl)
|
|||
if (!attr)
|
||||
return 0;
|
||||
|
||||
attr = TREE_VALUE (TREE_VALUE (attr));
|
||||
if (!attr || TREE_STRING_LENGTH (attr) < 1)
|
||||
return 0;
|
||||
attr_fnspec fnspec (TREE_VALUE (TREE_VALUE (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');
|
||||
unsigned int arg;
|
||||
if (fnspec.returns_arg (&arg))
|
||||
return ERF_RETURNS_ARG | arg;
|
||||
|
||||
case 'm':
|
||||
return ERF_NOALIAS;
|
||||
|
||||
case '.':
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (fnspec.returns_noalias_p ())
|
||||
return ERF_NOALIAS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero when FNDECL represents a call to setjmp. */
|
||||
|
|
61
gcc/gimple.c
61
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
|
||||
|
@ -1512,31 +1513,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])
|
||||
int flags = 0;
|
||||
attr_fnspec fnspec (attr);
|
||||
|
||||
if (!fnspec.arg_specified_p (arg))
|
||||
;
|
||||
else if (!fnspec.arg_used_p (arg))
|
||||
flags = EAF_UNUSED;
|
||||
else
|
||||
{
|
||||
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;
|
||||
|
||||
case '.':
|
||||
default:
|
||||
return 0;
|
||||
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. */
|
||||
|
@ -1550,24 +1546,17 @@ 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');
|
||||
unsigned int arg_no;
|
||||
if (fnspec.returns_arg (&arg_no))
|
||||
return ERF_RETURNS_ARG | arg_no;
|
||||
|
||||
case 'm':
|
||||
return ERF_NOALIAS;
|
||||
|
||||
case '.':
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (fnspec.returns_noalias_p ())
|
||||
return ERF_NOALIAS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
@ -4012,3 +4014,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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue