Consider the following code:
__attribute__((noinline)) int foo1(int x, int y)
{
return x;
}
int bar1(int* a)
{
int b = foo1(a[5], a[10]);
return b * b;
}
Even though foo1
is not inlined, a compiler can easily tell one of its parameters is unused; so it's not actually necessary to bother initializing it. And indeed, both GCC 8.2 and clang 7.0 compile bar1()
to only read the first argument's value from memory.
Now suppose we put those two int parameters into a struct:
struct two_ints { int x, y; };
__attribute__((noinline)) int foo2(struct two_ints s)
{
return s.x;
}
int bar2(int* a)
{
struct two_ints ti = { a[5], a[10] };
int b = foo2(ti);
return b * b;
}
There shouldn't be any difference, right? The parameters (certainly as far as the assembly is concerned) are two integers; and the second one is not used. So I would expect to see the same assembly code. Yet... I don't. Both clang and gcc initialize both fields of ti
before calling foo2()
.
Both code fragments with gcc & clang (GodBolt.org)
So, is there anything obligating compilers to initialize both fields, or is this a missed optimization opportunity?