-
Notifications
You must be signed in to change notification settings - Fork 82
fix: duplicate global constants #2735
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
base: main
Are you sure you want to change the base?
Conversation
Even global constants with private linkage are converted to external global constants which cause duplicate when modules get linked. This happens only when LLVM IR's are called via `ccall`. This is not the case when `Base.llvmcall` is at play. A constant variable called `global_var_prefixes` is used to keep track of the non-special external global constans and incrementally rename them within each new module.
|
Your PR requires formatting changes to meet the project's style guidelines. Click here to view the suggested changes.diff --git a/test/global_constants.jl b/test/global_constants.jl
index 04c22700..64003d42 100644
--- a/test/global_constants.jl
+++ b/test/global_constants.jl
@@ -27,7 +27,7 @@ tmp_so_file = joinpath(tmp_dir, "func.so")
run(
pipeline(
`clang -x ir - -Xclang -no-opaque-pointers -O3 -fPIC -fembed-bitcode -shared -o $(tmp_so_file)`;
- stdin=IOBuffer(LLVM_IR)
+ stdin = IOBuffer(LLVM_IR)
)
);
lib = Libdl.dlopen(tmp_so_file);
@@ -36,8 +36,9 @@ const fptr = Libdl.dlsym(lib, :func);
function func_llvm(x::Float64, y::Float64, n::Int)
n >= 0 && n <= 2 || throw("0 ≤ n ≤ 2")
- Base.llvmcall((LLVM_IR, "func"), Cdouble,
- Tuple{Cdouble,Cdouble,Clong},
+ return Base.llvmcall(
+ (LLVM_IR, "func"), Cdouble,
+ Tuple{Cdouble, Cdouble, Clong},
x, y, n
)
end;
@@ -45,7 +46,8 @@ end;
function func_ccall(x::Float64, y::Float64, n::Int)
n >= 0 && n <= 2 || throw("0 ≤ n ≤ 2")
- ccall(fptr, Cdouble,
+ return ccall(
+ fptr, Cdouble,
(Cdouble, Cdouble, Clong),
x, y, n
)
@@ -59,9 +61,8 @@ end;
A = [1.0, 2.0, 3.0]
@test func_llvm(x, y, n) == func_ccall(x, y, n)
- @test func_llvm(x, y, n) == x * A[n+1] + y
- @test func_ccall(x, y, n) == x * A[n+1] + y
-
+ @test func_llvm(x, y, n) == x * A[n + 1] + y
+ @test func_ccall(x, y, n) == x * A[n + 1] + y
@test gradient(Reverse, func_llvm, Const(x), y, Const(n)) == (nothing, 1.0, nothing) |
src/compiler/orcv2.jl
Outdated
| end | ||
|
|
||
| # rename non-special global constants that | ||
| # have external linkage (modified by the ccall |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
alternate solution, can we just mark all defined symbols during the lto import phase as internal?
we should already do so for functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x/ref
Enzyme.jl/src/compiler/validation.jl
Line 596 in c009fa5
| linkage!(g, LLVM.API.LLVMExternalLinkage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worked like a charm! All the tests passed locally. This also explains why something like
@.const.array.data.5 = private unnamed_addr constant [48 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\D0?\00\00\00\00\00\00\D0?\00\00\00\00\00\00\E8?\00\00\00\00\00\00\E8?\00\00\00\00\00\00\F0?", align 8
turns into
@.const.array.data.5 = dso_local unnamed_addr constant [48 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\00\00\00\D0?\00\00\00\00\00\00\D0?\00\00\00\00\00\00\E8?\00\00\00\00\00\00\E8?\00\00\00\00\00\00\F0?", align 8
What was the initial thought behind changing the linkage to external in the first place?
|
So one challenge here is that we are hitting different language semantics. Julia code doesn't use LLVM globals as much, except for compilation unit local operations. In C/C++ that is not the case and I have to answer the question if a global variable with the same name ought to be unifed or not. This is AD independent and is normally handled by the dynamic linker, here we are consuming LLVM IR from before the dynamic linker phase and I think we must met the semantics. |
That clarifies the intent. Thanks! But what confused me earlier was that no matter how I defined the linkage in my LLVM IR, it was overwritten when the |
yeah so I think probably the thing to do is to mark it as external, but remove initialization assuming it will be initialized by the actual library itself [therefore preserving the one definiton, and not overwriting]. alternatively we can link it weakly/etc |
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## main #2735 +/- ##
===========================================
- Coverage 68.91% 50.87% -18.05%
===========================================
Files 58 13 -45
Lines 19861 1256 -18605
===========================================
- Hits 13688 639 -13049
+ Misses 6173 617 -5556 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
See issue #2706
This PR should resolve the issue when global constants with
privatelinkage getexternallinkage if the LLVM IR is called viaccallinterface. See the same issue above for detailed examination.