LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 13677 - llvm doesn't partially remove static initializers
Summary: llvm doesn't partially remove static initializers
Status: RESOLVED INVALID
Alias: None
Product: libraries
Classification: Unclassified
Component: Interprocedural Optimizations (show other bugs)
Version: trunk
Hardware: PC Linux
: P enhancement
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-08-23 09:23 PDT by Rafael Ávila de Espíndola
Modified: 2012-08-28 20:25 PDT (History)
2 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rafael Ávila de Espíndola 2012-08-23 09:23:44 PDT
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
}
Comment 1 Richard Smith 2012-08-24 18:54:21 PDT
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.
Comment 2 Rafael Ávila de Espíndola 2012-08-24 21:47:18 PDT
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.
Comment 3 Richard Smith 2012-08-25 00:38:57 PDT
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.
Comment 4 Rafael Ávila de Espíndola 2012-08-25 08:35:54 PDT
(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.
Comment 5 Richard Smith 2012-08-28 08:06:40 PDT
> 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}.
Comment 6 Rafael Ávila de Espíndola 2012-08-28 20:25:14 PDT
Thanks a lot.
I have reported http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54399