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'. 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')