Please allow common-subexpression elimination to retain an indirect load when an intervening store provably cannot modify the loaded object. Currently, writing one structure member prevents reuse of a previously loaded member.
For example:
struct S
{
int value;
int other;
};
int f(struct S *s)
{
int old = s->value;
s->other = 7;
return old + s->value;
}
Compiled for Z80 with SDCC 4.6.4 r16999:
sdcc -mz80 --std-c99 --max-allocs-per-node 100 -S example.c
Before: 21 bytes. The generated function reloads s->value after the store:
_f::
ld e, l
ld d, h
ld c, (hl)
inc hl
ld b, (hl)
dec hl
inc de
inc de
ld a, #0x07
ld (de), a
inc de
xor a, a
ld (de), a
ld a, (hl)
inc hl
ld h, (hl)
ld l, a
add hl, bc
ex de, hl
ret
After implementing the proposal improvement to CSE: 18 bytes. The original value is reused:
_f::
ld e, l
ld d, h
ld c, (hl)
inc hl
ld b, (hl)
ld l, c
ld h, b
inc de
inc de
ld a, #0x07
ld (de), a
inc de
xor a, a
ld (de), a
add hl, bc
ex de, hl
ret
Changing the member, local variable and function return type gives these differences in code size when compiling for Z80 with the same options:
| Value type | Before | After |
|---|---|---|
char |
15 bytes | 10 bytes |
int |
21 bytes | 18 bytes |
long |
89 bytes | 65 bytes |
float |
112 bytes | 75 bytes |
The only requirement to achieve these improvements is to recognise constant, non-overlapping byte ranges derived from the same base pointer. Unknown or overlapping accesses remain conservative.
A secondary benefit is better _Optional inference. For example:
struct P
{
char padding;
_Optional int *p;
int count;
};
int g(struct P *s)
{
if (s->p)
{
s->count = 7;
return *s->p; // unwanted diagnostic message
}
return 0;
}
The store s->count = 7 cannot change the value read by s->p, but r16999 emits warning 355 at the pointer dereference:
<source>:13: warning 355: pointer to _Optional could not be proven to be non-null at dereference
See SDCC 4.6.0 on Compiler Explorer: https://godbolt.org/z/Ps1WaTW65
The proposed optimisation preserves the guarded load and removes that warning. First-member cases additionally need the separate #4148 fix. In CBUtilLib, the same improvement removes a warning in StringBuff.c and reduces its Z80 set_len function from 119 to 109 bytes. See https://github.com/chrisbazley/CBUtilLib/blob/main/StringBuff.c#L131