llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.92k stars 11.52k forks source link

ThinLTO undefined ref due to imported DIGlobalVariable reference at -O0 #30122

Open llvmbot opened 7 years ago

llvmbot commented 7 years ago
Bugzilla Link 30774
Version 3.9
OS Linux
Reporter LLVM Bugzilla Contributor
CC @JohanEngelen,@joker-eph,@pcc

Extended Description

Johan reported an issue hit using the 3.9 compiler and ThinLTO, when building with -O0 -g. The issue occurs when importing from a module with a const global variable - while we don't import the global variable definition, we do import the debug metadata, and in the 3.9 timeframe the DIGlobalVariable metadata still contained a reference to the associated GlobalVariable. At -O2 the GV declaration is eliminated as is the reference from the DIGlobalVariable, but at -O0 we get an undefined reference linker error.

This doesn't occur at head due to pcc's change to reverse the GlobalVariable/DIGlobalVariable edge (https://reviews.llvm.org/rL281284).

In reality, we shouldn't bother doing any importing at -O0 - inlining is disabled, so this is just wasted work. My plan is to disable importing and other ThinLTO optimizations at -O0, both in trunk and in 3.9 (which will fix this 3.9 issue).

To reproduce:

$ cat global_main.c extern int foo(); int main() { return foo(); }

$ cat global.c const int foobar = 10;

int foo() { return 1; }

$ clang -c -O2 global.c global_main.c -flto=thin -g

$ clang global.o global_main.o -flto=thin -g -O0

/tmp/lto-llvm-14880f.o(.debug_info+0x6f): error: undefined reference to 'foobar' clang-3.9: error: linker command failed with exit code 1 (use -v to see invocation)

pcc commented 7 years ago

I think edges are still possible for template value parameters, see the test case for https://reviews.llvm.org/D26212

joker-eph commented 7 years ago

Are we sure we can't have anymore any edges from metadata to globals in the IR? The fact the IRLinker/IRmover generates incorrect IR isn't nice.

llvmbot commented 7 years ago

The main issue is that 3.9 contains references from DIGlobalVariable to GlobalVariable, combined with the fact that the ThinLTO reference graph is not representing those metadata references.

At head we no longer have references from DIGlobalVariable to GlobalVariable, due to r281284, but that is too heavy-weight to backport. Fixing the ThinLTO reference graph for 3.9 to include these references also seems heavy-weight, especially since it isn't needed at head.

Simply avoiding importing in the O0 case seems like the right thing to do anyway (which is why I sent a head patch for that first).

joker-eph commented 7 years ago

The description is also not clear why this is only a O0 issue and why it can't happen with O2?

In the test case from Johan, and my reduced test case below, the imported declaration and the reference from the imported DIGlobalVariable are eliminated during optimization. If it can't be eliminated from the importing module at -O2, then I expect that is because there is a reference from imported code - in which case it should have been reflected in the reference graph and the exporting module would not have been able to internalize it.

Using optimizations to 'fix' some importing bug is not correct. It is still not clear to me if we're in this case here or not.

llvmbot commented 7 years ago

It is not clear to me how you propose to fix it: What if one module is built with O0 and the other with O3?

This is occurring when the link step is passed -O0. E.g. this is passed to gold-plugin via its O0 option, but was not affecting ThinLTO behavior. See https://reviews.llvm.org/D25918 for the head fix - it is handled in LTO so affects all modules.

The description is also not clear why this is only a O0 issue and why it can't happen with O2?

In the test case from Johan, and my reduced test case below, the imported declaration and the reference from the imported DIGlobalVariable are eliminated during optimization. If it can't be eliminated from the importing module at -O2, then I expect that is because there is a reference from imported code - in which case it should have been reflected in the reference graph and the exporting module would not have been able to internalize it.

joker-eph commented 7 years ago

It is not clear to me how you propose to fix it: What if one module is built with O0 and the other with O3?

The description is also not clear why this is only a O0 issue and why it can't happen with O2?

llvmbot commented 2 months ago

@llvm/issue-subscribers-debuginfo

Author: None (llvmbot)

| | | | --- | --- | | Bugzilla Link | [30774](https://llvm.org/bz30774) | | Version | 3.9 | | OS | Linux | | Reporter | LLVM Bugzilla Contributor | | CC | @JohanEngelen,@joker-eph,@pcc | ## Extended Description Johan reported an issue hit using the 3.9 compiler and ThinLTO, when building with -O0 -g. The issue occurs when importing from a module with a const global variable - while we don't import the global variable definition, we do import the debug metadata, and in the 3.9 timeframe the DIGlobalVariable metadata still contained a reference to the associated GlobalVariable. At -O2 the GV declaration is eliminated as is the reference from the DIGlobalVariable, but at -O0 we get an undefined reference linker error. This doesn't occur at head due to pcc's change to reverse the GlobalVariable/DIGlobalVariable edge (https://reviews.llvm.org/rL281284). In reality, we shouldn't bother doing any importing at -O0 - inlining is disabled, so this is just wasted work. My plan is to disable importing and other ThinLTO optimizations at -O0, both in trunk and in 3.9 (which will fix this 3.9 issue). To reproduce: $ cat global_main.c extern int foo(); int main() { return foo(); } $ cat global.c const int foobar = 10; int foo() { return 1; } $ clang -c -O2 global.c global_main.c -flto=thin -g $ clang global.o global_main.o -flto=thin -g -O0 /tmp/lto-llvm-14880f.o(.debug_info+0x6f): error: undefined reference to 'foobar' clang-3.9: error: linker command failed with exit code 1 (use -v to see invocation)