A small missed optimization I noticed while debugging another problem is that given int zed(); int x = zed(); struct foo { int a; int b; int c; int d; int e; }; foo bar = {x, 1, 2, 3, 4}; Only the first element has to be found at runtime, but llvm still produces code to initialize the full struct: define internal void @_GLOBAL__I_a() section ".text.startup" { entry: %call.i = tail call i32 @_Z3zedv() optsize store i32 %call.i, i32* @x, align 4, !tbaa !0 store i32 %call.i, i32* getelementptr inbounds (%struct.foo* @bar, i64 0, i32 0), align 4, !tbaa !0 store i32 1, i32* getelementptr inbounds (%struct.foo* @bar, i64 0, i32 1), align 4, !tbaa !0 store i32 2, i32* getelementptr inbounds (%struct.foo* @bar, i64 0, i32 2), align 4, !tbaa !0 store i32 3, i32* getelementptr inbounds (%struct.foo* @bar, i64 0, i32 3), align 4, !tbaa !0 store i32 4, i32* getelementptr inbounds (%struct.foo* @bar, i64 0, i32 4), align 4, !tbaa !0 ret void }
The optimization you're suggesting isn't correct in general. For instance, given: foo bar = {bar.d, 1, 2, 3, 4}; bar.a is required to be 0. C++ only allows us to convert dynamic initialization to static if it can be done for the entirety of a variable's initializer.
Well, no optimization is correct for a sufficiently general testcase :-) GCC does optimize this one: _GLOBAL__sub_I_x: pushq %rax call _Z3zedv movl %eax, x(%rip) movl %eax, bar(%rip) popq %rdx ret .... bar: .zero 4 .long 1 .long 2 .long 3 .long 4 I noticed this in code that was implementing some sort of inheritance with function pointers. In one TU we have foo base = { function_pointer1, function_pointer2, ...}; and in another foo derived = { other_function_pointer, base.function_pointer2}; the llvm generated code initializes all of derived at runtime, the gcc one only the bits that are not known constants.
Looks like g++ is miscompiling your code. Suppose you link that code against this: struct foo { int a; int b; int c; int d; int e; }; extern foo bar; int zed() { return bar.d; } We're back to the original situation: bar.a must be initialized by 0. C++ does not permit *part* of the initializer of a variable to be promoted from dynamic to static initialization, it's an all-or-nothing thing.
(In reply to comment #3) > Looks like g++ is miscompiling your code. > > Suppose you link that code against this: > > struct foo { > int a; > int b; > int c; > int d; > int e; > }; > extern foo bar; > int zed() { return bar.d; } > > We're back to the original situation: bar.a must be initialized by 0. C++ does > not permit *part* of the initializer of a variable to be promoted from dynamic > to static initialization, it's an all-or-nothing thing. And the order the fields of a struct are initialized in are also defined by the standard? May I trouble you for the standard sections? I will probably report this bug in gcc.
> And the order the fields of a struct are initialized in are also defined > by the standard? That's actually irrelevant for your example. What's relevant is that the standard guarantees that x is initialized before bar. > May I trouble you for the standard sections? [basic.start.init]p2 and p3 lay out the relevant rules here. In particular, note that [basic.start.init]p3 only permits the initialization for a *variable* to be promoted from dynamic to static, not the initialization for a *sub-object* of a variable. In this example, x may be initialized to 0 or to 3, but bar must be initialized to {0,1,2,3,4}.
Thanks a lot. I have reported http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54399