llvm / llvm-project

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

Link will change global value order #28025

Open llvmbot opened 8 years ago

llvmbot commented 8 years ago
Bugzilla Link 27651
Version 3.8
OS Linux
Reporter LLVM Bugzilla Contributor

Extended Description

We are using a module as library and link the source code in the library and when the source code has some blocks there are some bugs with the global value. In debug version the ~Module will assert.

Here is llvm ir for global values before link and after link: Before link: @​_NSConcreteGlobalBlock = external global i8 @.str = private unnamed_addr addrspace(2) constant [9 x i8] c"i12@?0i8\00", align 1 @​__block_descriptor_tmp = internal constant { i64, i64, i8 addrspace(2), i8 addrspace(2) } { i64 0, i64 32, i8 addrspace(2) getelementptr inbounds ([9 x i8], [9 x i8] addrspace(2) @.str, i32 0, i32 0), i8 addrspace(2) null }

@​block_literal_global = internal constant { i8*, i32, i32, i8, %struct.block_descriptor* } { i8* @​_NSConcreteGlobalBlock, i32 1342177280, i32 0, i8 bitcast (i32 (i8, i32) @​test_block_invoke to i8*), %struct.block_descriptor bitcast ({ i64, i64, i8 addrspace(2), i8 addrspace(2) } @​block_descriptor_tmp to %struct.block_descriptor*) }, align 8

After link: @​block_literal_global = internal constant { i8*, i32, i32, i8, %struct.block_descriptor* } { i8* @​_NSConcreteGlobalBlock, i32 1342177280, i32 0, i8 bitcast (i32 (i8, i32) @​test_block_invoke to i8*), %struct.block_descriptor bitcast ({ i64, i64, i8 addrspace(2), i8 addrspace(2) } @​block_descriptor_tmp to %struct.block_descriptor) }, align 8 @​_NSConcreteGlobalBlock = external global i8 @​__block_descriptor_tmp = internal constant { i64, i64, i8 addrspace(2), i8 addrspace(2) } { i64 0, i64 32, i8 addrspace(2) getelementptr inbounds ([9 x i8], [9 x i8] addrspace(2) @.str, i32 0, i32 0), i8 addrspace(2)* null } @.str = private unnamed_addr addrspace(2) constant [9 x i8] c"i12@?0i8\00", align 1

As the global valve orders change, the dependency of these global values are messed.

It seems the bug was caused by ModuleLinker::linkIfNeeded with a recursion call but with a wrong order.

llvmbot commented 8 years ago

Can you please provide a testcase to reproduce the issue? Thanks

llvmbot commented 8 years ago

Backtrace when decl for @_NSConcreteGlobalBlock

llvmbot commented 8 years ago

After some gdb trace, I found that the bug is caused by the MapValue function. In the source module the only global value used in function is @​block_literal_global, and when the inst used @​block_literal_global was used from linkFunctionBody to RemapInstruction and then to MapValue, it will first be materializeDeclFor into the Dst module. Then the linkGlobalValueBody and linkGlobalInit will map those global value used in @​block_literal_global one by one. So after link we can see @​block_literal_global at first, followed by @​_NSConcreteGlobalBlock ,@block_descriptor_tmp and the @.str used in @​block_descriptor_tmp.

But this order is not correct in a module, the value @​__block_literal_global depends on some value declared after it. And when we want to delete the module there will be assert about delete some value that are still have users.