views:

446

answers:

3

I have a general understanding of restrict but I'm hoping to clarify some fine points. I have a function that reads a null-terminated string from one buffer and writes out a URL encoded version in another buffer. The function has this signature (currently without restrict):

char const *StringUrlEncode(char const *unencoded, 
                            char *encoded,
                            char *encodedEnd);

unencoded is my null-terminated source string. The destination buffer is represented by encoded and encodedEnd, where encoded points to the first char in the buffer and encodedEnd points to the first char after the buffer, i.e. the function will write chars up to but not including the location pointed to by encodedEnd -- this is your basic begin/end iterator pair if you're familiar with C++ STL conventions.

If I add restrict to this function, should it only be applied to the first two parameters:

char const *StringUrlEncode(char const *restrict unencoded, 
                            char *restrict encoded,
                            char *encodedEnd);

or is there some benefit I'm not understanding by adding it to all three parameters?

I can see that making the input and output buffers restrict helps the compiler know that they don't overlap. But since the last parameter, encodedEnd, is only used to mark the end of the output buffer, I'm thinking that restrict wouldn't really be any help to the compiler here (though I assume it wouldn't hurt, other than adding unnecessary noise to the function declaration).

+2  A: 

I think you're right that it wouldn't hurt. Your loop pointer (call it p) will equal encodedEnd at the end of the loop. But nothing need be accessed after the loop (from either p or encodedEnd), so that shouldn't be a problem. I don't think it will help, either, because nothing is ever written or read from encodedEnd so there's nothing to optimize away.

But I agree with you having the first two restrict should really help.

Matthew Flaschen
Note that dereferencing encodedEnd is undefined behavior since encoded is also restrict - so indeed, it doesn't matter at all whether encodedEnd is restrict or not.
bdonlan
+4  A: 

Try Mike Acton's article here. Restrict is frightening because of both the performance implications of not using it and the consequences of using it incorrectly.

In your case, it sounds like you could safely apply restrict to all three pointers as none alias the same memory area. However there is going to be little to no performance benefit from using it on the third pointer.

Dan Olson
I've read Mike's article (twice now) and it's a good start, but left me with some questions :-)
Don McCaughey
The link given is non-functional. Google suggests there's an updated version at http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html (validated 2009-09-06) but that is giving problems too. The cached version is available at Google.
Jonathan Leffler
+1  A: 

In this particular case it won't make a difference whether encodedEnd is restrict or not; you have promised the compiler that no one aliases unencoded and encoded, and so the reads and writes won't interfere with each other.

The real reason that restrict is important in this case is that without it the compiler can't know that writes through encoded won't affect reads through unencoded. For example, if

encoded == unencoded+1

then each write to encoded would affect each subsequent read from unencoded, so the compiler can't schedule the load until the write has completed. restrict promises the compiler that the two pointers don't affect the same memory, so it can schedule loads far enough ahead to avoid pipeline stalls.

Crashworks