-
Notifications
You must be signed in to change notification settings - Fork 81
Test embedded bitcode path #2684
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?
Changes from all commits
36656ad
20feb57
8001a7f
d1e792b
ef9878e
4758258
7f3b57d
657268d
0d1f934
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I seem to remember LLVM IR isn't very portable across major versions, I presume that'd be a potential problem here when testing different Julia (and llvm) versions?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with you, and I also didn't feel this was the best test case. The only way I could reproduce this error was with Also, have a look at this comment in the original issue. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| using Enzyme | ||
| using Clang_jll | ||
| using Libdl | ||
| using Test | ||
|
|
||
| const FUNC_LLVM_IR = """ | ||
| declare double @llvm.rint.f64(double) #1 | ||
|
|
||
| define i32 @func(double* noalias nocapture writeonly %retptr, { i8*, i32, i8*, i8*, i32 }** noalias nocapture readnone %excinfo, double %arg.t, i8* nocapture readnone %arg.arr.0, i8* nocapture readnone %arg.arr.1, i64 %arg.arr.2, i64 %arg.arr.3, double* %arg.arr.4, i64 %arg.arr.5.0, i64 %arg.arr.6.0) local_unnamed_addr #0 { | ||
| common.ret: | ||
| %.27 = fdiv double %arg.t, 1.000000e-02 | ||
| %.28 = tail call double @llvm.rint.f64(double %.27) | ||
| %.29 = fptosi double %.28 to i64 | ||
| %.42 = icmp slt i64 %.29, 0 | ||
| %.43 = select i1 %.42, i64 %arg.arr.5.0, i64 0 | ||
| %.44 = add i64 %.43, %.29 | ||
| %.55 = mul i64 %.44, %arg.arr.6.0 | ||
| %.56 = ptrtoint double* %arg.arr.4 to i64 | ||
| %.57 = add i64 %.55, %.56 | ||
| %.58 = inttoptr i64 %.57 to double* | ||
| %.59 = load double, double* %.58, align 8 | ||
| store double %.59, double* %retptr, align 8 | ||
| ret i32 0 | ||
| } | ||
|
|
||
| define double @func_wrap({ i8*, i32, i8*, i8*, i32 }** %excinfo, double %arg.t, i8* %arg.arr.0, i8* %arg.arr.1, i64 %arg.arr.2, i64 %arg.arr.3, double* %arg.arr.4, i64 %arg.arr.5.0, i64 %arg.arr.6.0) { | ||
| entry: | ||
| %tmp = alloca double, align 8 | ||
| %st = call i32 @func(double* %tmp, { i8*, i32, i8*, i8*, i32 }** %excinfo, double %arg.t, i8* %arg.arr.0, i8* %arg.arr.1, i64 %arg.arr.2, i64 %arg.arr.3, double* %arg.arr.4, i64 %arg.arr.5.0, i64 %arg.arr.6.0) | ||
| %val = load double, double* %tmp, align 8 | ||
| ret double %val | ||
| } | ||
|
|
||
|
|
||
| attributes #0 = { mustprogress nofree nosync nounwind willreturn } | ||
| attributes #1 = { mustprogress nocallback nofree nosync nounwind readnone speculatable willreturn } | ||
| attributes #2 = { noinline } | ||
| """ | ||
|
|
||
|
|
||
| tmp_dir = tempdir() | ||
| tmp_so_file = joinpath(tmp_dir, "func.so") | ||
| run( | ||
| pipeline( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this even necessary here? if you're starting from llvm anyways, why not just use llvmcall?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surprisingly, I won't hit that execution path when using The wrapper function around |
||
| `$(clang()) -x ir - -Xclang -no-opaque-pointers -O3 -fPIC -fembed-bitcode -shared -o $(tmp_so_file)`; | ||
| stdin=IOBuffer(FUNC_LLVM_IR) | ||
| ) | ||
| ) | ||
|
|
||
| lib = Libdl.dlopen(tmp_so_file) | ||
| const fptr = Libdl.dlsym(lib, :func_wrap) | ||
|
|
||
|
|
||
| function func_ccall(t::Float64, arr::AbstractVector{Float64}) | ||
| nitems = length(arr) | ||
| bitsize = Base.elsize(arr) | ||
| GC.@preserve arr begin | ||
| excinfo = Ptr{Ptr{Cvoid}}(C_NULL) | ||
| base::Ptr{Cdouble} = pointer(arr) | ||
|
|
||
| ccall(fptr, Cdouble, | ||
| (Ptr{Ptr{Cvoid}}, Cdouble, Ptr{Cvoid}, Ptr{Cvoid}, | ||
| Clong, Clong, Ptr{Cdouble}, Clong, Clong), | ||
| excinfo, t, C_NULL, C_NULL, nitems, bitsize, | ||
| base, nitems, nitems * bitsize) | ||
| end | ||
| end | ||
|
|
||
| @testset "Broken Function ccall + @view" begin | ||
| a = rand(10) | ||
| expected_grad_a = (nothing, [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) | ||
| grad_a = gradient(Reverse, func_ccall, Const(0.0), a) | ||
| @test expected_grad_a == grad_a | ||
|
|
||
|
|
||
| errstream = joinpath(tempdir(), "stdout.txt") | ||
| err_llvmir = nothing | ||
| b = @view a[1:5] | ||
|
|
||
| redirect_stdio(stdout=errstream, stderr=errstream, stdin=devnull) do | ||
| try | ||
| gradient(Reverse, func_ccall, Const(0.0), b) | ||
| catch e | ||
| err_llvmir = e | ||
| end | ||
|
|
||
| @test err_llvmir !== nothing | ||
| @test occursin("Broken function", err_llvmir.info) | ||
| end | ||
|
|
||
| errtxt = read(errstream, String) | ||
| @test occursin("Called function is not the same type as the call!", errtxt) | ||
| end | ||
Uh oh!
There was an error while loading. Please reload this page.