Context
SDCC claims to support C11. I use it to write games on Z80 target (for fun and experience).
C11 defines restrict
C11 specifies the restrict
keyword on pointers, which can improve generated code speed (and size often).
In a nutshell, when the programmer adds restrict
to a pointer definition, they (the programmer) promises that the memory accessed by this pointer will never overlap with any other memory. It is very often the case in (sane) API usage, but the compiler cannot guess what's sane.
Restrict and retrocomputing
Now, back to our retro world. Analysis and examples in Demystifying The Restrict Keyword analyses this in terms of load scheduling, which doesn't exist in Z80 (no delay, loads and store are committed at the end of all such instructions).
That said, though the example in Wikipedia mentions "'load' may have to wait until preceding 'store' completes", the example still partially makes sense without such notions.
Incidentally, although SDCC implements a number of optimizations, enough to actually produce good Z80 code, SDCC manual does not mention restrict
(or even strict aliasing rules).
Question 1
Is restrict
actually useful in a Z80 context? Intuitively it does make sense, but perhaps in practice due to the small number of registers it virtually never practically makes sense?
Experiment before asking
- I compiled the example code on the Wikipedia page about restrict with and without the restrict keyword, the result was exactly the same.
- I simplified the code using
char *
instead ofsize_t *
, the code was simpler on both sides. - All compilations with
sdcc -mz80 --allow-unsafe-read --max-allocs-per-node 100000
and two variants:--opt-code-size
and--opt-code-speed
.
Result: in all cases, adding restrict
keyword did not change generated code at all.
SDCC: read the source before asking
Does SDCC actually meaningfully implement restrict
? Checking the source code I can only confirm that it performs some checks (see for example https://sourceforge.net/p/sdcc/code/HEAD/tree/trunk/sdcc/src/SDCCicode.c#l2010 ), but cannot confirm that adding the keyword in source code can actually change generated code in any situation.
Code style
The example in Wikipedia :
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val) { *ptrA += *val; *ptrB += *val; }
can be rewritten
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val) { size_t v = *val; *ptrA += v; *ptrB += v; }
In practice, generated Z80 is slightly better, but restrict
still changed nothing. Perhaps writing C in a specific style is what counts in such a context?
(Considerations like "use global variables because Z80 is inefficient dealing with C-style stack and even code that access data at variable location" are generally relevant but that's not what I'm asking for.)
Questions
- Can anyone confirm what SDCC does with the
restrict
keyword? - Can anyone provide style recommendations specific to the topic or pointer aliasing and the benefit supposedly provided by the
restrict
keywords when the compiler does not actually support it?
restrict
makes sense on a retro target?restrict
so it's not clear how you arrived at the conclusion thatrestrict
doesn't affect code generation. Note that only the first example you gave would benefit from therestrict
keyword. Also you've misunderstood Demystifying The Restrict Keyword article,restrict
has nothing to do with how CPUs might perform "load scheduling", but how the compiler generates code. "proper use of the restrict keyword gives the compiler enough information to select a more optimal order of loads and stores" (emphasis mine).restrict
is not used by the compiler, manual C style does win.