Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

llvm doesn't partially remove static initializers #14049

Closed
llvmbot opened this issue Aug 23, 2012 · 6 comments
Closed

llvm doesn't partially remove static initializers #14049

llvmbot opened this issue Aug 23, 2012 · 6 comments
Labels
bugzilla Issues migrated from bugzilla invalid Resolved as invalid, i.e. not a bug ipo Interprocedural optimizations

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented Aug 23, 2012

Bugzilla Link 13677
Resolution INVALID
Resolved on Aug 28, 2012 20:25
Version trunk
OS Linux
Reporter LLVM Bugzilla Contributor
CC @zygoloid

Extended Description

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
}

@zygoloid
Copy link
Mannequin

zygoloid mannequin commented Aug 25, 2012

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.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Aug 25, 2012

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.

@zygoloid
Copy link
Mannequin

zygoloid mannequin commented Aug 25, 2012

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.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Aug 25, 2012

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.

@zygoloid
Copy link
Mannequin

zygoloid mannequin commented Aug 28, 2012

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}.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Aug 29, 2012

Thanks a lot.
I have reported http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54399

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 3, 2021
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla invalid Resolved as invalid, i.e. not a bug ipo Interprocedural optimizations
Projects
None yet
Development

No branches or pull requests

1 participant