Marking select(2) as restrict

Bruce Evans brde at optusnet.com.au
Mon Feb 26 03:45:52 UTC 2018


On Sun, 25 Feb 2018, Mark Millard via freebsd-standards wrote:

> On 2018-Feb-25, at 12:48 PM, Tijl Coosemans <tijl at FreeBSD.org> wrote:
>
>> On Thu, 22 Feb 2018 12:56:08 +0200 Konstantin Belousov <kostikbel at gmail.com> wrote:
>>> Consider the recently changed devd code:
>>> 	select(n + 1, &fd, &fd, &fd);
>>> There, compiler can see that restrict is applied to arguments which are
>>> given same values.  Since this leads to the self-contradicting statement
>>> 	fd != fd
>>> which cannot be true, compliler in its optimizing wisdom can assume that
>>> the code is never executing and remove it.  I do not know whether clang
>>> actually makes such transformation, but it does not sound unfeasible
>>> looking at its other advances.
>>
>> There's an example in the C99 standard that indicates such a call is not
>> necessarily undefined so compilers cannot optimise it away:
>>
>> EXAMPLE 3
>> The function parameter declarations
>> void h(int n, int * restrict p, int * restrict q, int * restrict r)
>> {
>> 	int i;
>> 	for (i = 0; i < n; i++)
>> 		p[i] = q[i] + r[i];
>> }
>> illustrate how an unmodified object can be aliased through two restricted
>> pointers.  In particular, if a and b are disjoint arrays, a call of the
>> form h(100, a, b, b) has defined behavior, because array b is not modified
>> within function h.
>
> Good point. In essence the restrictions on the caller can
> not be known independently of how the parameters are used
> in the called code --something that prototype does not specify.
> This does constrain what the compiler can do about potential
> aliasing that it might detect.
>
> A prototype that would make h's restrictions clearer is
> one that reports that q and r are not used to modify
> memory:
>
> void h(int n, int * restrict p, int const * restrict q, int const * restrict r);
>
> With such a prototype, it is easier to known that q's "objects"
> and r's "objects" both simply must not overlap p's "objects".
> (See g from example 2 for its d+50 valid vs. d+1 invalid status.)

I think the example intentionally leaves out 'const'.  I think const
already prevents aliasing.  'restrict' prevents it even more.  Using
the combination in the exaple would make it less clear what the
'restrict' part does.

In draft C99 (n869.txt), Example 3 is much more complicated and seems
to be broken.  It is intentionally of how const can be used in
conjunction with restrict.  p has qualifiers const and restrict, and
q and r only have qualifier const, and it is claimed that p being
restrict- qualified implies that an object accessed through p is never
accessed through q or r, and that this is the precise assertion required
to optimize the loop.  const for p seems to be just a bug.  Removing
it gives an example of how restrict is not needed for the input-only
args since const suffices.  However, C99 TC3 (n1256.pdf) changes this
signficantly by removing all the consts and adding restricts.

This might be related to POSIX's inconsistencies for sigaction() and
nanosleep().  For sigaction(), the input arg is const restrict and the
output arg is restrict, but for nanosleep() the the input arg is just
const and the output arg is unqualified.  const on 1 arg seems to be
enough to prevent all aliasing when there are only 2 args that could
be aliased without it, but Example 3 no longer gives any hints about
how restrict interacts with const.

restrict gives stronger (but different) restrictions than const on
aliases with globals, but so should all POSIX syscall-like functions.
An application function miight access any application global state,
but library functions should only access documented global state.  For
syscall-like functions, the global state outside of the kernel should
be precisely errno.  POSIX should restrict aliasing to error in a
general way, but for sigaction() and nanosleep() it is clear that the
pointer args cannot be aliased to errno, since they don't point to
ints.

Bruce


More information about the freebsd-standards mailing list