I have some C code like this:
#include <stdint.h>
typedef struct {
int16_t x1;
int16_t x2;
} XSTATE;
typedef struct {
int16_t s1;
int32_t s2;
XSTATE x;
} STATE;
typedef int16_t (*FUNCTION_HANDLE_S16)(void *, int16_t arg);
// really lives in foo.h
inline int16_t foo(void *pxstate_raw, int16_t arg)
{
XSTATE *pxstate = pxstate_raw;
pxstate->x1 = arg;
return arg;
}
// really lives in bar.h
inline int16_t bar(STATE *pstate, FUNCTION_HANDLE_S16 f)
{
return f(&pstate->x, 1991);
}
int16_t test(STATE *pstate)
{
return bar(pstate, foo);
}
If I check the output in Compiler Explorer using gcc 12.1, I see this using -O1:
test:
mov WORD PTR [rdi+8], 1991
mov eax, 1991
ret
Perfect! pstate->x.x1 is being assigned the value 1991 and that value is returned to the caller.
But in -O0:
test:
push rbp
mov rbp, rsp
sub rsp, 16
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov esi, OFFSET FLAT:foo
mov rdi, rax
call bar
leave
ret
What gives? What happened to the 1991 constant, and the compiled output of bar? Only test shows up in the compiler output.
Versions of gcc since 5.1 don't produce output for bar but gcc 4.9.4 does produce output for bar.
Here's clang 14.0.0 with -O1:
test: # @test
mov word ptr [rdi + 8], 1991
mov ax, 1991
ret
and -O0:
push rbp
mov rbp, rsp
sub rsp, 16
mov qword ptr [rbp - 8], rdi
mov rdi, qword ptr [rbp - 8]
movabs rsi, offset foo
call bar
cwde
add rsp, 16
pop rbp
ret