Skip to content

Commit 2ef9d75

Browse files
authored
Helpers to compile to WebAssembly (#114)
1 parent 0034adc commit 2ef9d75

4 files changed

Lines changed: 53 additions & 14 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
matrix:
2020
version:
2121
- '1.8'
22-
- '^1.9.0-rc2'
22+
- '^1.9.0-rc3'
2323
os:
2424
- ubuntu-latest
2525
- macOS-latest

src/StaticCompiler.jl

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@ using Libdl: Libdl, dlsym, dlopen
88
using Base: RefValue
99
using Serialization: serialize, deserialize
1010
using Clang_jll: clang
11+
using LLD_jll: lld
1112
using StaticTools
1213
using StaticTools: @symbolcall, @c_str, println
1314

14-
export compile, load_function, compile_shlib, compile_executable
15+
export compile, load_function, compile_shlib, compile_executable, compile_wasm
1516
export native_code_llvm, native_code_typed, native_llvm_module, native_code_native
1617
export @device_override, @print_and_throw
1718

@@ -154,7 +155,8 @@ function generate_obj(f, tt, external = true, path::String = tempname(), name =
154155
mixtape = NoContext(),
155156
strip_llvm = false,
156157
strip_asm = true,
157-
opt_level=3,
158+
opt_level = 3,
159+
remove_julia_addrspaces = false,
158160
target = (),
159161
kwargs...)
160162
mkpath(path)
@@ -180,7 +182,7 @@ function generate_obj(f, tt, external = true, path::String = tempname(), name =
180182

181183
# Now that we've removed all the pointers from the code, we can (hopefully) safely lower all the instrinsics
182184
# (again, using Enzyme's pipeline)
183-
post_optimize!(mod, tm)
185+
post_optimize!(mod, tm; remove_julia_addrspaces)
184186

185187
# Make sure we didn't make any glaring errors
186188
LLVM.verify(mod)
@@ -355,6 +357,40 @@ function compile_shlib(funcs::Array, path::String="./";
355357
joinpath(abspath(path), filename * "." * Libdl.dlext)
356358
end
357359

360+
"""
361+
```julia
362+
compile_wasm(f::Function, types::Tuple, [path::String="./"], [name::String=repr(f)]; filename::String=name, flags=``, kwargs...)
363+
compile_wasm(funcs::Array, [path::String="./"]; filename="libfoo", demangle=false, flags=``, kwargs...)
364+
```
365+
As `compile_shlib`, but compiling to a WebAssembly library.
366+
367+
The compiled function is by default given the symbol name `julia_$(name)`, i.e.,
368+
the function `test` in the example below is called `julia_test` in the shared library.
369+
The keword argument `demangle=true` will remove this prefix, but is currently only
370+
supported the second (multi-function-shlib) method.
371+
```
372+
"""
373+
function compile_wasm(f::Function, types=();
374+
path::String="./",
375+
filename=fix_name(repr(f)),
376+
flags=``,
377+
kwargs...
378+
)
379+
tt = Base.to_tuple_type(types)
380+
obj_path, name = generate_obj(f, tt, true, path, filename; target = (triple = "wasm32-unknown-wasi", cpu = "", features = ""), remove_julia_addrspaces = true, kwargs...)
381+
run(`$(lld()) -flavor wasm --no-entry --export-all $flags $obj_path/obj.o -o $path/$name.wasm`)
382+
joinpath(abspath(path), filename * ".wasm")
383+
end
384+
function compile_wasm(funcs::Array;
385+
path::String="./",
386+
filename="libfoo",
387+
flags=``,
388+
kwargs...
389+
)
390+
obj_path, name = generate_obj(funcs, true; target = (triple = "wasm32-unknown-wasi", cpu = "", features = ""), remove_julia_addrspaces = true, kwargs...)
391+
run(`$(lld()) -flavor wasm --no-entry --export-all $flags $obj_path/obj.o -o $path/$filename.wasm`)
392+
joinpath(abspath(path), filename * ".wasm")
393+
end
358394

359395
"""
360396
```julia
@@ -606,7 +642,7 @@ function native_llvm_module(funcs::Array; demangle = false, kwargs...)
606642
return mod
607643
end
608644

609-
function generate_obj(funcs::Array, external, path::String = tempname(), filenamebase::String="obj";
645+
function generate_obj(funcs::Array, external::Bool, path::String = tempname(), filenamebase::String="obj";
610646
demangle =false,
611647
strip_llvm = false,
612648
strip_asm = true,
@@ -615,7 +651,7 @@ function generate_obj(funcs::Array, external, path::String = tempname(), filenam
615651
f, tt = funcs[1]
616652
mkpath(path)
617653
obj_path = joinpath(path, "$filenamebase.o")
618-
fakejob, kwargs = native_job(f, tt, external, kwargs...)
654+
fakejob, kwargs = native_job(f, tt, external; kwargs...)
619655
mod = native_llvm_module(funcs; demangle = demangle, kwargs...)
620656
obj, _ = GPUCompiler.emit_asm(fakejob, mod; strip=strip_asm, validate=false, format=LLVM.API.LLVMObjectFile)
621657
open(obj_path, "w") do io

src/optimize.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,8 @@ function addJuliaLegalizationPasses!(pm, lower_intrinsics=true)
211211
remove_ni!(pm)
212212
end
213213
end
214-
215-
function post_optimize!(mod, tm)
214+
215+
function post_optimize!(mod, tm; remove_julia_addrspaces = false)
216216
# @show "pre_post", mod
217217
# flush(stdout)
218218
# flush(stderr)
@@ -224,6 +224,9 @@ function post_optimize!(mod, tm)
224224
LLVM.ModulePassManager() do pm
225225
addJuliaLegalizationPasses!(pm, true)
226226
addMachinePasses!(pm)
227+
if remove_julia_addrspaces
228+
remove_julia_addrspaces!(pm)
229+
end
227230
run!(pm, mod)
228231
end
229232
# @show "post_mod", mod

test/testintegration.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -386,12 +386,12 @@ end
386386
@testset "Cross compiling to WebAssembly" begin
387387

388388
m2(x) = 2x
389-
obj_path, name = StaticCompiler.generate_obj(m2, Tuple{Float64}, true, tempname(); target = (triple = "wasm32-unknown-unknown", cpu = "", features = ""))
390-
# link with `lld` from LLD_jll
391-
run(`$(lld()) -flavor wasm --no-entry --export-all $obj_path/obj.o -o $name.wasm`)
392-
# On Julia v1.9, link with included linker
393-
# run(`$(Base.Linking.lld()) -flavor wasm --no-entry --export-all $obj_path/obj.o -o $name.wasm`)
394-
# run(`wasm2wat $name.wasm`) # to see a text representation (wasm2wat isn't included)
389+
m3(x) = 3x
390+
wasm_path = compile_wasm(m2, Tuple{Float64})
391+
wasm_path2 = compile_wasm([(m2, Tuple{Float64}), (m3, Tuple{Float64})])
392+
393+
wasm_path = compile_wasm(m2, (Float64,))
394+
wasm_path2 = compile_wasm([(m2, (Float64,)), (m3, (Float64,))])
395395

396396
end
397397

0 commit comments

Comments
 (0)