restrict keyword questions

C

copx

Restrict keyword questions

How far does the guarantee that an object is not accessed through another
pointer go? I mean, all examples I have seen are simple stuff like:

int f (int *restrict x, int *restrict y)
{
*x = 0;
*y = 1;
return *x;
}

Ok, the "return *x" can be optimised to "return 0" in this case, but what
happens if we add a function call:

int f (int *restrict x, int *restrict y)
{
*x = 0;
my_black_box_of_pain();
*y = 1;
return *x;
}

Does the guarantee that the x object is not modified persist? I mean
my_black_box_of_pain() could easily modify the memory area x points to. Now,
if the guarantee persists, then one should probably never use the restrict
keyword except when optimising very simple self-contained functions (i.e. no
calls to other functions). Because trying to ensure that all functions
called by a function which uses restrict parameters, and the functions
called by those functions etc. do not violate the contract is a recipe for
disaster. It so easy to introduce a bug there it is almost silly.
If the guarantee does NOT persist the restrict keyword is almost useless,
because you rarely see a C function which doesn't call other functions.
One way or the other, the restrict keyword seems to be for special interest
groups only. Right or not?

BTW, does the restrict keyword actually guarantee "mem area not modified
through another pointer" or not.
I wonder because I have heard different claims. I searched this group and
people here seem to think that restrict actually makes guarantees about the
object the restricted pointer points to (i.e. the mem area). However, this
article:

http://www.cellperformance.com/mike_acton/2006/05/demystifying_the_restrict_keyw.html

Seems to contradict these claims. Quotes
---------
"
The restrict keyword does not declare that the object being pointed to is
completely without aliases, only that the addresses that are loaded and
stored from are unaliased.
"

"
Memory windows can overlap and still be non-aliased.
"
------------

Now think of something like

int foo(int * restrict a, int * restrict b) {
a[1] = 20;
*b = 10;
return a[1];
}

foo(x, &x[1]);

a and b are not aliased here because they point to different addresses i.e.
the restrict requirements are met, at least according to that article. The
memory windows overlap but that is supposed to be ok..

I am definitely confused now..
 
T

Tim Prince

copx said:
Restrict keyword questions

How far does the guarantee that an object is not accessed through another
pointer go? I mean, all examples I have seen are simple stuff like:
restrict is an assertion by the programmer. If the programmer lies, but
the compiler believes it, it's UB.
 
A

Andrey Tarasevich

copx said:
...
but what happens if we add a function call:

int f (int *restrict x, int *restrict y)
{
*x = 0;
my_black_box_of_pain();
*y = 1;
return *x;
}

Does the guarantee that the x object is not modified persist? I mean
my_black_box_of_pain() could easily modify the memory area x points to.

It couldn't, unless you lied in your 'restrict'. Assume that your 'x' is
pointing to some object 'X'. When you declared your 'x' as 'restrict'
and actually modified the value of '*x' (i.e. modified 'X' through
'*x'), that automatically means that you promise the compiler that as
long as the above function block is executing, 'X' is not accessed
through any other means besides '*x'.

Since you don't pass 'x' to 'my_black_box_of_pain', how can
'my_black_box_of_pain' modify 'X'? If it uses any other means to access
'X' (for example 'X' is a global object, or there's another static
pointer pointing to 'X' and known to 'my_black_box_of_pain'), that
automatically violates the above promise and leads to undefined behavior.
Now,
if the guarantee persists, then one should probably never use the restrict
keyword except when optimising very simple self-contained functions (i.e. no
calls to other functions). Because trying to ensure that all functions
called by a function which uses restrict parameters, and the functions
called by those functions etc. do not violate the contract is a recipe for
disaster.

I don't see it as being that bad. Don't abuse file-scope variable
declarations (e.g. global variables). And don't provide multiple
alternative access paths to the same variable without a real need, and
you should be OK.

BTW, it's something that actually applies regardless of 'restrict' keyword.
It so easy to introduce a bug there it is almost silly.

It is not easier than it was before. Note, that it is not just the
compiler that makes assumption on the persistence of certain values. It
is the programmer who makes these assumptions and relies on them. That's
how it always been, long before any 'restrict' keywords. Programmers
always made such assumptions and relied on them. It is impossible to
avoid in any serious C program.

When your assumptions are correct, everything works. When they are
incorrect, everything breaks. Note: no 'restrict' keywords is involved
so far. Now, bring in the 'restrict'. The 'restrict' keyword lets you
share your assumptions with the compiler. Once again, when your
assumptions are correct, everything works [even better]. When they are
incorrect, everything breaks. But it breaks just like it broke before
the 'restrict'.
If the guarantee does NOT persist the restrict keyword is almost useless,
because you rarely see a C function which doesn't call other functions.
One way or the other, the restrict keyword seems to be for special interest
groups only. Right or not?

Not. The amount of attention you should give to your code when you use
'restrict' is not really much higher than you should give it anyway.
BTW, does the restrict keyword actually guarantee "mem area not modified
through another pointer" or not.

Yes and no. The guarantee is correct. But it is _you_ who's giving
(promising) this "guarantee" to the compiler by using the keyword.
Now think of something like

int foo(int * restrict a, int * restrict b) {
a[1] = 20;
*b = 10;
return a[1];
}

foo(x, &x[1]);

a and b are not aliased here because they point to different addresses i.e.
the restrict requirements are met, at least according to that article. The
memory windows overlap but that is supposed to be ok..

Once again, 'restrict' applied to pointer 'p' means that if you modify
some object through pointer 'p' (object '*p', or object 'p[5]') in some
block, you can only access it through 'p' in that block. In the above
example you violate that requirement. Once you did 'a[1] = 20' it is no
longer legal to access '*b' (even for reading). At the same time, if you
do 'a[0] = a[2] = a[4] = 20;', it is still OK to access 'b[0]', 'b[2]'
and 'b[4]' even though the "memory windows" are overlapping.
 

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

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top