Hi Daniel,
On Aug 24, 2007, at 10:20 AM, Daniel Berlin wrote:
> On 8/22/07, Christopher Lamb <christopher.lamb at gmail.com> wrote:
>>
>>
>> On Aug 22, 2007, at 3:48 PM, Duncan Sands wrote:
>>
>> Hi Christopher,
>>
>>
>> If A and B are function arguments then there is no "based on"
>> relationship between pointer expressions A+0 and B+0. This is because
>> changing one of the pointers, A for example, to point to a copy of
>> the object it points to would change the value of the pointer
>> expression A+0, but not the expression B+0.
>>
>> I was assuming that *(A+0) and *(B+0) are pointer expressions. Is
>> that not the case?
>> I believe the expressions you mention are indeed not pointer
>> expressions as
>> they evaluate to a value of the pointed-to type rather than a
>> pointer to the
>> type. Only pointers may be "based on" other pointers from my
>> reading of the
>> spec.
>
> Christopher, just to point something out.
>
> Earlier you said that restrict says something about the relationship
> of a pointer to non-restricted pointers. This is not true except for
> one small case.
> Restricted pointers in general only tell you things about a
> relationship to other restricted pointers.
I'm not sure which previous statement was unclear, but I can believe
I was a bit loose with the details on this point. My understanding is
that as long as the analysis can determine the "based on"
relationship between two pointers, then restrict does say something
about those two pointers, even if one is not restrict.
> IE the following is perfectly legal:
>
> int foo(int *a, restrict int *b)
> {
> int *c = a;
>
> a = b; (1)
> *a = 90;
> a = c; (2)
> *a = 90;
> }
Here the alias analysis would be incorrect if it determined that the
value of 'a' at point (2) was "based on" 'b'. This
allows restrict to
play a role in allowing the query alias(a(2), b) == No.
Here's an example where restrict would have a harder time playing a
role:
int foo(int *a, restrict int *b)
{
int *c = bar(a, b);
a = b; (1)
*a = 90;
a = c; (2)
*a = 90;
}
Here 'a' at point (2) may be "based on" 'b', depending
on the
implementation of bar(). Unless the compiler can determine that the
second parameter of bar() has no affect on its return value, then the
alias analysis will have to return alias(a(2), b) == May.
> The following is not:
>
> int foo(int *a, restrict int *b, restrict int *c)
> {
> a = b;
> *a = 90;
> a = c;
> *a = 90;
> }
>
> 6.7.3.1 only says you can't change a pointer to point to *another
> restricted pointer*.
>
> "If P is assigned the value of a pointer expression that is based on
> *another restricted pointer object P2*, associated with block B2, then
> either the execution of B2 shall begin before
> the execution of B, or the execution of B2 shall end prior to the
> assignment. If these
> requirements are not met, then the behavior is unde�ned.
> "
I don't agree. The spec defines P as "designating an object P as a
restrict-qualified pointer". The preceding example casts away the
restrict-ness of the pointers, but is perfectly legal by my reading
of the spec given that P in your example is not a restrict-qualified
pointer and so the clause you cite is not applicable.
If the function were foo(int * restrict a, restrict int *b, restrict
int *c), then I believe that the the behavior would be undefined
because of the clause you cite.
> It also says that the behavior is only undefined if the value is
> modified.
>
> This means loads from restricted pointers and non-restricted pointers
> can alias, as can loads from restricted pointers and other restricted
> pointers.
>
> They even given an example of this, and declare it legal.
Indeed, if you are referring to Example 3 in 6.7.3.1 this does not
imply that the compiler must determine that these pointers may or
must alias. My reading of this example is that it explains that even
though the compiler can assume that two restrict pointers, or even a
restrict and a non-restrict pointer, do not alias, when those
pointers point to the same object it will not lead to undefined
behavior if the two pointers are not used to modify the objects they
point to.
Their example:
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];
}
If a and b are disjoint, then h(100, a, b, b) has defined behavior.
This is not a requirement of the spec, but an example of defined
behavior that emerges due to the requirements set out earlier in the
section.
By my reading of the spec, the following modified example would also
have defined behavior under the same conditions as the previous one.
void h'(int n, int * restrict p, int * restrict q, int * r)
{
int i;
for (i = 0; i < n; i++)
p[i] = q[i] + r[i];
}
As neither p nor q is "based on" r, the alias analysis is free to
determine that they do not alias r given the restrict nature of q and
q. And neither q nor r is used to modify the object it points to.
> Restrict is sadly not that useful in the way the standard actually
> specfiies.
In practice I have actually found the restrict qualifier to be
critical to generating efficient code in certain circumstances. These
cases were specialized compute codes, however, not typically user apps.
Cheers
--
Chris