Date: Mon, 26 Feb 2018 14:45:42 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Mark Millard <marklmi26-fbsd@yahoo.com> Cc: Tijl Coosemans <tijl@freebsd.org>, FreeBSD Standards <freebsd-standards@freebsd.org>, FreeBSD Hackers <freebsd-hackers@freebsd.org>, Kevin Lo <kevlo@freebsd.org> Subject: Re: Marking select(2) as restrict Message-ID: <20180226135457.B1203@besplex.bde.org> In-Reply-To: <2909E983-953A-4463-959C-F3C386BC6C9A@yahoo.com> References: <CAF6rxg=h_oMiUu7P=GAOQf_OySQM2w31hg6Kas%2B3jeEM3qq_Cg@mail.gmail.com> <CAF6rxgnt9c0n8i-nHQwoKGbZKF2hM5AZqEJnz0CLo26XOO4_sg@mail.gmail.com> <20180221032247.GA81670@ns.kevlo.org> <CAF6rxg=WwqeBnmJzfOZgtwrYesXPfvJFeaVmQwtTa_89_sxaJg@mail.gmail.com> <CANCZdfo46bhfaRpbqOmJjk4%2B=1R2c5kvmrJPENaxNgK==5M4kg@mail.gmail.com> <CAF6rxg=wNVgDUF9o744ngmzPNeHB3hqdrLufy=yS3D4osczxFQ@mail.gmail.com> <20180221104400.GU94212@kib.kiev.ua> <20180222112752.10da7e51@kalimero.tijl.coosemans.org> <20180222105608.GE94212@kib.kiev.ua> <20180225214813.776a9f58@kalimero.tijl.coosemans.org> <2909E983-953A-4463-959C-F3C386BC6C9A@yahoo.com>
next in thread | previous in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20180226135457.B1203>