Skip to content

Commit

Permalink
Cleanup and more support for arrays of functions (reland) (#122)
Browse files Browse the repository at this point in the history
* Cleanup and more support for arrays of functions

* switch wasm back to generate_obj_for_compile
  • Loading branch information
MasonProtter committed May 10, 2023
1 parent a076a62 commit 70d4065
Showing 1 changed file with 103 additions and 37 deletions.
140 changes: 103 additions & 37 deletions src/StaticCompiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ function compile(f, _tt, path::String = tempname();
rt = last(only(native_code_typed(f, tt, mixtape = mixtape)))
isconcretetype(rt) || error("$f on $_tt did not infer to a concrete type. Got $rt")
f_wrap!(out::Ref, args::Ref{<:Tuple}) = (out[] = f(args[]...); nothing)
_, _, table = generate_obj(f_wrap!, Tuple{RefValue{rt}, RefValue{tt}}, false, path, name; mixtape = mixtape, opt_level, strip_llvm, strip_asm, filename, kwargs...)
_, _, table = generate_obj_for_compile(f_wrap!, Tuple{RefValue{rt}, RefValue{tt}}, false, path, name; mixtape = mixtape, opt_level, strip_llvm, strip_asm, filename, kwargs...)

lf = LazyStaticCompiledFunction{rt, tt}(Symbol(f), path, name, filename, table)
cjl_path = joinpath(path, "$filename.cjl")
Expand All @@ -117,7 +117,7 @@ end

"""
```julia
generate_obj(f, tt, path::String = tempname(), name = fix_name(repr(f)), filenamebase::String="obj";
generate_obj_for_compile(f, tt, path::String = tempname(), name = fix_name(repr(f)), filenamebase::String="obj";
\tmixtape = NoContext(),
\tstrip_llvm = false,
\tstrip_asm = true,
Expand All @@ -141,7 +141,7 @@ The defaults compile to the native target.
julia> fib(n) = n <= 1 ? n : fib(n - 1) + fib(n - 2)
fib (generic function with 1 method)
julia> path, name, table = StaticCompiler.generate_obj(fib, Tuple{Int64}, "./test")
julia> path, name, table = StaticCompiler.generate_obj_for_compile(fib, Tuple{Int64}, "./test")
("./test", "fib", IdDict{Any, String}())
shell> tree \$path
Expand All @@ -151,7 +151,7 @@ shell> tree \$path
0 directories, 1 file
```
"""
function generate_obj(f, tt, external = true, path::String = tempname(), name = fix_name(repr(f)), filenamebase::String="obj";
function generate_obj_for_compile(f, tt, external = true, path::String = tempname(), name = fix_name(repr(f)), filenamebase::String="obj";
mixtape = NoContext(),
strip_llvm = false,
strip_asm = true,
Expand Down Expand Up @@ -200,10 +200,13 @@ end
compile_executable(f::Function, types::Tuple, path::String, [name::String=repr(f)];
filename::String=name,
cflags=``, # Specify libraries you would like to link against, and other compiler options here
also_expose=[],
kwargs...
)
```
Attempt to compile a standalone executable that runs function `f` with a type signature given by the tuple of `types`.
If there are extra methods you would like to protect from name mangling in the produced binary for whatever reason,
you can provide them as a vector of tuples of functions and types, i.e. `[(f1, types1), (f2, types2), ...]`
### Examples
```julia
Expand Down Expand Up @@ -261,11 +264,21 @@ Hello, world!
```
"""
function compile_executable(f::Function, types=(), path::String="./", name=fix_name(repr(f));
also_expose=[],
filename=name,
cflags=``,
kwargs...)
compile_executable(vcat([(f, types)], also_expose), path, name; filename, cflags, kwargs...)
end


function compile_executable(funcs::Array, path::String="./", name=fix_name(repr(funcs[1][1]));
filename=name,
cflags=``,
kwargs...
)

(f, types) = funcs[1]
tt = Base.to_tuple_type(types)
isexecutableargtype = tt == Tuple{} || tt == Tuple{Int, Ptr{Ptr{UInt8}}}
isexecutableargtype || @warn "input type signature $types should be either `()` or `(Int, Ptr{Ptr{UInt8}})` for standard executables"
Expand All @@ -274,13 +287,11 @@ function compile_executable(f::Function, types=(), path::String="./", name=fix_n
isconcretetype(rt) || error("`$f$types` did not infer to a concrete type. Got `$rt`")
nativetype = isprimitivetype(rt) || isa(rt, Ptr)
nativetype || @warn "Return type `$rt` of `$f$types` does not appear to be a native type. Consider returning only a single value of a native machine type (i.e., a single float, int/uint, bool, or pointer). \n\nIgnoring this warning may result in Undefined Behavior!"

generate_executable(f, tt, path, name, filename; cflags=cflags, kwargs...)


generate_executable(funcs, path, name, filename; cflags=cflags, kwargs...)
joinpath(abspath(path), filename)
end


"""
```julia
compile_shlib(f::Function, types::Tuple, [path::String="./"], [name::String=repr(f)]; filename::String=name, cflags=``, kwargs...)
Expand Down Expand Up @@ -377,7 +388,7 @@ function compile_wasm(f::Function, types=();
kwargs...
)
tt = Base.to_tuple_type(types)
obj_path, name = generate_obj(f, tt, true, path, filename; target = (triple = "wasm32-unknown-wasi", cpu = "", features = ""), remove_julia_addrspaces = true, kwargs...)
obj_path, name = generate_obj_for_compile(f, tt, true, path, filename; target = (triple = "wasm32-unknown-wasi", cpu = "", features = ""), remove_julia_addrspaces = true, kwargs...)
run(`$(lld()) -flavor wasm --no-entry --export-all $flags $obj_path/obj.o -o $path/$name.wasm`)
joinpath(abspath(path), filename * ".wasm")
end
Expand Down Expand Up @@ -471,21 +482,19 @@ shell> ./hello
Hello, world!
```
"""
function generate_executable(f, tt, path=tempname(), name=fix_name(repr(f)), filename=string(name);
cflags=``,
kwargs...
)
mkpath(path)
obj_path = joinpath(path, "$filename.o")
exec_path = joinpath(path, filename)
job, kwargs = native_job(f, tt, true; name, kwargs...)
obj, _ = GPUCompiler.codegen(:obj, job; strip=true, only_entry=false, validate=false)

# Write to file
open(obj_path, "w") do io
write(io, obj)
end
function generate_executable(f, tt, args...; kwargs...)
generate_executable([(f, tt)], args...; kwargs...)
end

function generate_executable(funcs::Array, path=tempname(), name=fix_name(repr(funcs[1][1])), filename=string(name);
demangle=false,
cflags=``,
kwargs...
)
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
exec_path = joinpath(path, filename)
external = true
_, obj_path = generate_obj(funcs, external, path, filename; demangle=demangle, kwargs...)
# Pick a compiler
cc = Sys.isapple() ? `cc` : clang()
# Compile!
Expand All @@ -510,10 +519,10 @@ function generate_executable(f, tt, path=tempname(), name=fix_name(repr(f)), fil
# Clean up
run(`rm $wrapper_path`)
end

path, name
end


"""
```julia
generate_shlib(f::Function, tt, [external::Bool=true], [path::String], [name], [filename]; kwargs...)
Expand Down Expand Up @@ -553,23 +562,15 @@ julia> ccall(("julia_test", "example/test.dylib"), Float64, (Int64,), 100_000)
```
"""
function generate_shlib(f::Function, tt, external::Bool=true, path::String=tempname(), name=fix_name(repr(f)), filename=name;
cflags=``,
cflags=``, demangle=false,
kwargs...
)

mkpath(path)
obj_path = joinpath(path, "$filename.o")
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
job, kwargs = native_job(f, tt, external; name, kwargs...)
obj, _ = GPUCompiler.codegen(:obj, job; strip=true, only_entry=false, validate=false)

open(obj_path, "w") do io
write(io, obj)
end

_, obj_path = generate_obj([(f, tt)], external, path, filename; demangle=demangle, kwargs...)

# Pick a Clang
cc = Sys.isapple() ? `cc` : clang()
# Compile!
# Compile
run(`$cc -shared $cflags $obj_path -o $lib_path`)

path, name
Expand All @@ -583,7 +584,7 @@ function generate_shlib(funcs::Array, external::Bool=true, path::String=tempname

lib_path = joinpath(path, "$filename.$(Libdl.dlext)")

_,obj_path = generate_obj(funcs, external, path, filename; demangle=demangle, kwargs...)
_, obj_path = generate_obj(funcs, external, path, filename; demangle=demangle, kwargs...)
# Pick a Clang
cc = Sys.isapple() ? `cc` : clang()
# Compile!
Expand Down Expand Up @@ -642,6 +643,71 @@ function native_llvm_module(funcs::Array; demangle = false, kwargs...)
return mod
end


"""
```julia
generate_obj(f, tt, external::Bool, path::String = tempname(), filenamebase::String="obj";
mixtape = NoContext(),
target = (),
demangle =false,
strip_llvm = false,
strip_asm = true,
opt_level=3,
kwargs...)
```
Low level interface for compiling object code (`.o`) for for function `f` given
a tuple type `tt` characterizing the types of the arguments for which the
function will be compiled.
`mixtape` defines a context that can be used to transform IR prior to compilation using
[Mixtape](https://github.com/JuliaCompilerPlugins/Mixtape.jl) features.
`target` can be used to change the output target. This is useful for compiling to WebAssembly and embedded targets.
This is a named tuple with fields `triple`, `cpu`, and `features` (each of these are strings).
The defaults compile to the native target.
### Examples
```julia
julia> fib(n) = n <= 1 ? n : fib(n - 1) + fib(n - 2)
fib (generic function with 1 method)
julia> path, name, table = StaticCompiler.generate_obj_for_compile(fib, Tuple{Int64}, "./test")
("./test", "fib", IdDict{Any, String}())
shell> tree \$path
./test
└── obj.o
0 directories, 1 file
```
"""
function generate_obj(f, tt, args...; kwargs...)
generate_obj([(f, tt)], args...; kwargs...)
end


"""
```julia
generate_obj(funcs::Array, external::Bool, path::String = tempname(), filenamebase::String="obj";
mixtape = NoContext(),
target = (),
demangle =false,
strip_llvm = false,
strip_asm = true,
opt_level=3,
kwargs...)
```
Low level interface for compiling object code (`.o`) for an array of Tuples
(f, tt) where each function `f` and tuple type `tt` determine the set of methods
which will be compiled.
`mixtape` defines a context that can be used to transform IR prior to compilation using
[Mixtape](https://github.com/JuliaCompilerPlugins/Mixtape.jl) features.
`target` can be used to change the output target. This is useful for compiling to WebAssembly and embedded targets.
This is a named tuple with fields `triple`, `cpu`, and `features` (each of these are strings).
The defaults compile to the native target.
"""
function generate_obj(funcs::Array, external::Bool, path::String = tempname(), filenamebase::String="obj";
demangle =false,
strip_llvm = false,
Expand Down

2 comments on commit 70d4065

@brenhinkeller
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register

Release notes:

  • More support for arrays of functions
  • Various cleanup and testing improvments

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/83515

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.4.11 -m "<description of version>" 70d406566e7c24c7a3487a9b11e742e78c9dfcd8
git push origin v0.4.11

Please sign in to comment.