[LLVMdev] c const

Christopher Lamb christopher.lamb at gmail.com
Sun Aug 26 13:41:00 PDT 2007


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





More information about the llvm-dev mailing list