diff mbox series

'I' and 'U' fn spec specifiers

Message ID ZzdRWK0r3ft3T6hU@kam.mff.cuni.cz
State New
Headers show
Series 'I' and 'U' fn spec specifiers | expand

Commit Message

Jan Hubicka Nov. 15, 2024, 1:49 p.m. UTC
Hi,
To implement pointer parameters reproducible and unsequenced I would like to
use fnspec built at callgraph construction time.  Pointer parameters are either
const or non-const.  After discussion with Jens, I now understand that memory
pointed to by const pointers can only be read directly and not written to.
While parameters pointed to by normal pointers can be both read and written but
in a way that duplicated calls have no additional effect.

I.e.

int
test1 (int **a) [[reproducible]]
{
  return **a;
}
is not valid, since it has double-indirection

int
test2 (const int *a) [[reproducible]]
{
  *(int *)a = 1
}

is not valid since the parmaeter is const

int
test2 (int *a) [[reproducible]]
{
  a[1] = a[0];
}

is valid.

To represent the behaviour I need new fnspec specifiers.  Our 'R' specifies
that parameter is readonly and only used directly, but also implies noescape
that is not promised by the standard.  So I added 'I' (for input).  To
represent that parameters is both read and written, but not directly I added
'U' (for used).

I am not 100% sure we want to go the fnspec path.  It won't handle variadic
calls which I think are in general quite a minority though.

Bootstrapped/regtested x86_64-linux with the rest of reproducible/unsequenced code.
Does it seem sane?

gcc/ChangeLog:

	* attr-fnspec.h: Add 'I' and 'U' specifiers.
	(arg_direct_p): Use it.
	* tree-ssa-alias.cc (attr_fnspec::verify): Accept 'I' and 'U'.

Comments

Richard Biener Nov. 15, 2024, 2 p.m. UTC | #1
On Fri, 15 Nov 2024, Jan Hubicka wrote:

> Hi,
> To implement pointer parameters reproducible and unsequenced I would like to
> use fnspec built at callgraph construction time.  Pointer parameters are either
> const or non-const.  After discussion with Jens, I now understand that memory
> pointed to by const pointers can only be read directly and not written to.
> While parameters pointed to by normal pointers can be both read and written but
> in a way that duplicated calls have no additional effect.
> 
> I.e.
> 
> int
> test1 (int **a) [[reproducible]]
> {
>   return **a;
> }
> is not valid, since it has double-indirection
> 
> int
> test2 (const int *a) [[reproducible]]
> {
>   *(int *)a = 1
> }
> 
> is not valid since the parmaeter is const
> 
> int
> test2 (int *a) [[reproducible]]
> {
>   a[1] = a[0];
> }
> 
> is valid.
> 
> To represent the behaviour I need new fnspec specifiers.  Our 'R' specifies
> that parameter is readonly and only used directly, but also implies noescape
> that is not promised by the standard.  So I added 'I' (for input).  To
> represent that parameters is both read and written, but not directly I added
> 'U' (for used).
> 
> I am not 100% sure we want to go the fnspec path.  It won't handle variadic
> calls which I think are in general quite a minority though.
> 
> Bootstrapped/regtested x86_64-linux with the rest of reproducible/unsequenced code.
> Does it seem sane?

fnspec was originally introduced for PTA, but 'I' and 'U' given the
pointers escape, do not help PTA, as soon as pointers escape all (most)
bets are lost.

So where and how exactly do you plan to use those?  They seems to be
directed at redundancy elimination?

Richard.

> gcc/ChangeLog:
> 
> 	* attr-fnspec.h: Add 'I' and 'U' specifiers.
> 	(arg_direct_p): Use it.
> 	* tree-ssa-alias.cc (attr_fnspec::verify): Accept 'I' and 'U'.
> 
> diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
> index aef4701e6d1..4c332cb6c14 100644
> --- a/gcc/attr-fnspec.h
> +++ b/gcc/attr-fnspec.h
> @@ -41,6 +41,10 @@
>  		written and does not escape
>       'w' or 'W' specifies that the memory pointed to by the parameter does not
>  		escape
> +     'I'	specifies that parameter is only used read directly
> +		and *may* escape
> +     'U'	specifies that parameter is only used directly (read
> +		or written) and *may* escape
>       '1'....'9' specifies that the memory pointed to by the parameter is
>  		copied to memory pointed to by different parameter
>  		(as in memcpy).
> @@ -125,8 +129,9 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> -    return str[idx] == 'R' || str[idx] == 'O'
> -	   || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9');
> +    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'U'
> +	   || str[idx] == 'I' || str[idx] == 'W'
> +	   || (str[idx] >= '1' && str[idx] <= '9');
>    }
>  
>    /* True if argument is used.  */
> @@ -144,7 +149,8 @@ public:
>    {
>      unsigned int idx = arg_idx (i);
>      gcc_checking_assert (arg_specified_p (i));
> -    return str[idx] == 'r' || str[idx] == 'R' || (str[idx] >= '1' && str[idx] <= '9');
> +    return str[idx] == 'r' || str[idx] == 'R' || str[idx] == 'I'
> +	   || (str[idx] >= '1' && str[idx] <= '9');
>    }
>  
>    /* True if memory reached by the argument is read (directly or indirectly)  */
> diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
> index 8ad6a02ddc9..dca3b1cc721 100644
> --- a/gcc/tree-ssa-alias.cc
> +++ b/gcc/tree-ssa-alias.cc
> @@ -4138,6 +4138,8 @@ attr_fnspec::verify ()
>  	  case 'O':
>  	  case 'w':
>  	  case 'W':
> +	  case 'U':
> +	  case 'I':
>  	  case '.':
>  	    if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
>  		|| str[idx + 1] == 't')
>
Jₑₙₛ Gustedt Nov. 15, 2024, 2:20 p.m. UTC | #2
Hello Richard,

On Fri, 15 Nov 2024 15:00:44 +0100 (CET), Richard Biener wrote:

> fnspec was originally introduced for PTA, but 'I' and 'U' given the
> pointers escape, do not help PTA, as soon as pointers escape all
> (most) bets are lost.
> 
> So where and how exactly do you plan to use those?  They seems to be
> directed at redundancy elimination?

During the discussion with Honza it occured to me that maybe gcc
doesn't yet use the full potential of `restrict`-qualified pointers to
`const`-qualified base.

Thanks
Jₑₙₛ
Richard Biener Nov. 15, 2024, 2:24 p.m. UTC | #3
On Fri, 15 Nov 2024, Jₑₙₛ Gustedt wrote:

> Hello Richard,
> 
> On Fri, 15 Nov 2024 15:00:44 +0100 (CET), Richard Biener wrote:
> 
> > fnspec was originally introduced for PTA, but 'I' and 'U' given the
> > pointers escape, do not help PTA, as soon as pointers escape all
> > (most) bets are lost.
> > 
> > So where and how exactly do you plan to use those?  They seems to be
> > directed at redundancy elimination?
> 
> During the discussion with Honza it occured to me that maybe gcc
> doesn't yet use the full potential of `restrict`-qualified pointers to
> `const`-qualified base.

Could be - we have difficulties in applying 'restrict' to any pointer
that's not the formal parameter of a function as the formal definition
relies on properties of the language we cannot recover.

Richard.

> Thanks
> Jₑₙₛ
> 
> 
>
diff mbox series

Patch

diff --git a/gcc/attr-fnspec.h b/gcc/attr-fnspec.h
index aef4701e6d1..4c332cb6c14 100644
--- a/gcc/attr-fnspec.h
+++ b/gcc/attr-fnspec.h
@@ -41,6 +41,10 @@ 
 		written and does not escape
      'w' or 'W' specifies that the memory pointed to by the parameter does not
 		escape
+     'I'	specifies that parameter is only used read directly
+		and *may* escape
+     'U'	specifies that parameter is only used directly (read
+		or written) and *may* escape
      '1'....'9' specifies that the memory pointed to by the parameter is
 		copied to memory pointed to by different parameter
 		(as in memcpy).
@@ -125,8 +129,9 @@  public:
   {
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
-    return str[idx] == 'R' || str[idx] == 'O'
-	   || str[idx] == 'W' || (str[idx] >= '1' && str[idx] <= '9');
+    return str[idx] == 'R' || str[idx] == 'O' || str[idx] == 'U'
+	   || str[idx] == 'I' || str[idx] == 'W'
+	   || (str[idx] >= '1' && str[idx] <= '9');
   }
 
   /* True if argument is used.  */
@@ -144,7 +149,8 @@  public:
   {
     unsigned int idx = arg_idx (i);
     gcc_checking_assert (arg_specified_p (i));
-    return str[idx] == 'r' || str[idx] == 'R' || (str[idx] >= '1' && str[idx] <= '9');
+    return str[idx] == 'r' || str[idx] == 'R' || str[idx] == 'I'
+	   || (str[idx] >= '1' && str[idx] <= '9');
   }
 
   /* True if memory reached by the argument is read (directly or indirectly)  */
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index 8ad6a02ddc9..dca3b1cc721 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -4138,6 +4138,8 @@  attr_fnspec::verify ()
 	  case 'O':
 	  case 'w':
 	  case 'W':
+	  case 'U':
+	  case 'I':
 	  case '.':
 	    if ((str[idx + 1] >= '1' && str[idx + 1] <= '9')
 		|| str[idx + 1] == 't')