Restrict qualified pointers in C

K

Ken Camann

Hello!

I am having trouble understanding certain aspects of restrict
qualified pointers. I understand what they are in the simplest terms,
but I want to get high performance and portability out a certain piece
of code and there are some issues I don't fully understand. I'm
hoping someone can help me out. Suppose I have:

struct Vector
{
float x, y;
};

And then I make a method which takes 2 vectors, and adds the second
one componentwise to the first, so I have

inline Vector* add(Vector* v1, const Vector* v2)
{
v1->x += v2->x;
v1->y += v2->y;
return v1;
}

Note that I am able to call "add(v, v)" to add v to itself, so
aliasing is possible. But my naive understanding says that in this
special case aliasing shouldn't matter, and shouldn't change any
optimizations that might otherwise be made. Normally there is
aliasing because while v2 is const, the object it points to is not;
writes cannot happen to the object through the pointer v2, but they
_can_ happen through v1, so the compiler must assume they do.
However, notice that for all component-wise vector operations, the
values of v2 will never be read again once they are written to through
v1.

This wouldn't be true for something like the 3 dimensional cross
product, where you need to compute the new x, and then still use the
old x to compute the new z, etc. But for any of the +=, -=, *=, etc.
like binary operations, an rvalue isn't referenced again once it is
read the first time, in order to change the object.

My first question:

1. Can a compiler figure this out, and thus still generate fast code?
Even it can theoretically, would _most_ of them do it? I would like
the "performance" to be as portable as possible. The assembly from my
compiler looks ok.

2. Assuming the answer is "no", and most compilers cannot figure this
out, what happens if I start declaring things restricted? I'll be
using a new compiler soon, but right now I use Microsofts (no C99,
can't try it out). The definitions I've seen of restricted basically
say "it means they point to disjoint areas of memory". And here they
don't, but in this special case it _seems_ to not matter. Can I trick
the compiler into giving me extra performance? Will it ever come back
to bite me, depending on how exactly the assembly is generated?
Furthermore, will the compiler be intelligent enough to noice I'm
giving it the following "restricted" pointers:

add(v, v) //compiler says "hmmm, wait a minute..." and doesn't
compile?

Thanks for your time,
Ken
 
K

klaushuotari

Hello!

I am having trouble understanding certain aspects of restrict
qualified pointers. I understand what they are in the simplest terms,
but I want to get high performance and portability out a certain piece
of code and there are some issues I don't fully understand. I'm
hoping someone can help me out. Suppose I have:

struct Vector
{
float x, y;

};

And then I make a method which takes 2 vectors, and adds the second
one componentwise to the first, so I have

inline Vector* add(Vector* v1, const Vector* v2)
{
v1->x += v2->x;
v1->y += v2->y;
return v1;

}

Note that I am able to call "add(v, v)" to add v to itself, so
aliasing is possible. But my naive understanding says that in this
special case aliasing shouldn't matter, and shouldn't change any
optimizations that might otherwise be made. Normally there is
aliasing because while v2 is const, the object it points to is not;
writes cannot happen to the object through the pointer v2, but they
_can_ happen through v1, so the compiler must assume they do.
However, notice that for all component-wise vector operations, the
values of v2 will never be read again once they are written to through
v1.

This wouldn't be true for something like the 3 dimensional cross
product, where you need to compute the new x, and then still use the
old x to compute the new z, etc. But for any of the +=, -=, *=, etc.
like binary operations, an rvalue isn't referenced again once it is
read the first time, in order to change the object.

My first question:

1. Can a compiler figure this out, and thus still generate fast code?
Even it can theoretically, would _most_ of them do it? I would like
the "performance" to be as portable as possible. The assembly from my
compiler looks ok.

2. Assuming the answer is "no", and most compilers cannot figure this
out, what happens if I start declaring things restricted? I'll be
using a new compiler soon, but right now I use Microsofts (no C99,
can't try it out). The definitions I've seen of restricted basically
say "it means they point to disjoint areas of memory". And here they
don't, but in this special case it _seems_ to not matter. Can I trick
the compiler into giving me extra performance? Will it ever come back
to bite me, depending on how exactly the assembly is generated?
Furthermore, will the compiler be intelligent enough to noice I'm
giving it the following "restricted" pointers:

add(v, v) //compiler says "hmmm, wait a minute..." and doesn't
compile?

Thanks for your time,
Ken


What seems to be the problem?
 
P

Pierre Asselin

Your example didn't look like a good candidate for aggressive
optimization. How about this:

/* not tested */
void smear(int n, const float * restrict in, float * restrict out)
{
int i;
out[0]= ( in[0] + 2*in[1] )/3.f;
for(i= 1; i<n-1; i++) {
out= ( in[i-1] + in + in[i + 1] )/3.f;
}
out[n-1]= ( 2*in[n-2] + in[n-1] )/3.f;
}

(I think the "in" pointer doesn't need restrict, but I don't want
to spend time thinking about it.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top