forked from MaxMood96/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Bitcode] materialize Functions early when BlockAddress taken
IRLinker builds a work list of functions to materialize, then moves them from a source module to a destination module one at a time. This is a problem for blockaddress Constants, since they need not refer to the function they are used in; IPSCCP is quite good at sinking these constants deep into other functions when passed as arguments. This would lead to curious errors during LTO: ld.lld: error: Never resolved function from blockaddress ... based on the ordering of function definitions in IR. The problem was that IRLinker would basically do: for function f in worklist: materialize f splice f from source module to destination module in one pass, with Functions being lazily added to the running worklist. This confuses BitcodeReader, which cannot disambiguate whether a blockaddress is referring to a function which has not yet been parsed ("materialized") or is simply empty because its body was spliced out. This causes BitcodeReader to insert Functions into its BasicBlockFwdRefs list incorrectly, as it will never re-materialize an already materialized (but spliced out) function. Because of the possibility that blockaddress Constants may appear in Functions other than the ones they reference, this patch adds a new bitcode function code FUNC_CODE_BLOCKADDR_USERS that is a simple list of Functions that contain BlockAddress Constants that refer back to this Function, rather then the Function they are scoped in. We then materialize those functions when materializing `f` from the example loop above. This might over-materialize Functions should the user of BitcodeReader ultimately decide not to link those Functions, but we can at least now we can avoid this ordering related issue with blockaddresses. Fixes: llvm#52787 Fixes: ClangBuiltLinux/linux#1215 Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D120781
- Loading branch information
1 parent
b18e821
commit 23ec578
Showing
6 changed files
with
233 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
; RUN: llvm-as %s -o %t.bc | ||
; RUN: llvm-bcanalyzer -dump %t.bc | FileCheck %s | ||
; RUN: llvm-dis %t.bc | ||
|
||
; There's a curious case where blockaddress constants may refer to functions | ||
; outside of the function they're used in. There's a special bitcode function | ||
; code, FUNC_CODE_BLOCKADDR_USERS, used to signify that this is the case. | ||
|
||
; The intent of this test is two-fold: | ||
; 1. Ensure we produce BLOCKADDR_USERS bitcode function code on the first fn, | ||
; @repro, since @fun and @fun2 both refer to @repro via blockaddress | ||
; constants. | ||
; 2. Ensure we can round-trip serializing+desearlizing such case. | ||
|
||
; CHECK: <FUNCTION_BLOCK | ||
; CHECK: <BLOCKADDR_USERS op0=2 op1=1 | ||
; CHECK: <FUNCTION_BLOCK | ||
; CHECK: <FUNCTION_BLOCK | ||
|
||
define void @repro() { | ||
br label %label | ||
|
||
label: | ||
call void @fun() | ||
ret void | ||
} | ||
|
||
define void @fun() noinline { | ||
call void @f(i8* blockaddress(@repro, %label)) | ||
ret void | ||
} | ||
|
||
define void @fun2() noinline { | ||
call void @f(i8* blockaddress(@repro, %label)) | ||
ret void | ||
} | ||
|
||
declare void @f(i8*) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
; RUN: llvm-as %s -o %t.bc | ||
; RUN: llvm-link %t.bc -S | FileCheck %s | ||
|
||
declare void @f(i8*) | ||
|
||
; Test that a blockaddress in @y referring to %label in @x can be moved when @y | ||
; appears after @x. | ||
define void @x() { | ||
br label %label | ||
|
||
label: | ||
call void @y() | ||
ret void | ||
} | ||
|
||
define void @y() { | ||
; CHECK: define void @y() { | ||
; CHECK-NEXT: call void @f(i8* blockaddress(@x, %label)) | ||
call void @f(i8* blockaddress(@x, %label)) | ||
ret void | ||
} | ||
|
||
; Test that a blockaddress in @a referring to %label in @b can be moved when @a | ||
; appears before @b. | ||
define void @a() { | ||
; CHECK: define void @a() { | ||
; CHECK-NEXT: call void @f(i8* blockaddress(@b, %label)) | ||
call void @f(i8* blockaddress(@b, %label)) | ||
ret void | ||
} | ||
|
||
define void @b() { | ||
br label %label | ||
|
||
label: | ||
call void @a() | ||
ret void | ||
} | ||
|
||
; Test that @c and @d can both have blockaddress Constants that refer to one | ||
; another. | ||
|
||
define void @c() { | ||
; CHECK: define void @c() { | ||
; CHECK-NEXT: br label %label | ||
; CHECK-EMPTY: | ||
; CHECK-NEXT: label: | ||
; CHECK-NEXT: call void @f(i8* blockaddress(@d, %label)) | ||
br label %label | ||
|
||
label: | ||
call void @f(i8* blockaddress(@d, %label)) | ||
ret void | ||
} | ||
|
||
define void @d() { | ||
; CHECK: define void @d() { | ||
; CHECK-NEXT: br label %label | ||
; CHECK-EMPTY: | ||
; CHECK-NEXT: label: | ||
; CHECK-NEXT: call void @f(i8* blockaddress(@c, %label)) | ||
br label %label | ||
|
||
label: | ||
call void @f(i8* blockaddress(@c, %label)) | ||
ret void | ||
} | ||
|
||
; Test that Functions added to IRLinker's Worklist member lazily (linkonce_odr) | ||
; aren't susceptible to the the same issues as @x/@y above. | ||
define void @parsed() { | ||
br label %label | ||
|
||
label: | ||
ret void | ||
} | ||
|
||
define linkonce_odr void @lazy() { | ||
; CHECK: define linkonce_odr void @lazy() { | ||
; CHECK-NEXT: br label %label | ||
; CHECK-EMPTY: | ||
; CHECK-NEXT: label: | ||
; CHECK-NEXT: call void @f(i8* blockaddress(@parsed, %label)) | ||
br label %label | ||
|
||
label: | ||
call void @f(i8* blockaddress(@parsed, %label)) | ||
ret void | ||
} | ||
|
||
define void @parsed2() { | ||
call void @lazy() | ||
ret void | ||
} | ||
|
||
; Same test as @lazy, just with one more level of lazy parsed functions. | ||
define void @parsed3() { | ||
br label %label | ||
|
||
label: | ||
ret void | ||
} | ||
|
||
define linkonce_odr void @lazy1() { | ||
; CHECK: define linkonce_odr void @lazy1() { | ||
; CHECK-NEXT: br label %label | ||
; CHECK-EMPTY: | ||
; CHECK-NEXT: label: | ||
; CHECK-NEXT: call void @f(i8* blockaddress(@parsed3, %label)) | ||
br label %label | ||
|
||
label: | ||
call void @f(i8* blockaddress(@parsed3, %label)) | ||
ret void | ||
} | ||
|
||
define linkonce_odr void @lazy2() { | ||
call void @lazy1() | ||
ret void | ||
} | ||
|
||
define void @parsed4() { | ||
call void @lazy2() | ||
ret void | ||
} |