-
Notifications
You must be signed in to change notification settings - Fork 5
/
wasm_target.jl
115 lines (91 loc) · 3.57 KB
/
wasm_target.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Compiler Target adapted from
# https://seelengrab.github.io/articles/Running%20Julia%20baremetal%20on%20an%20Arduino/
using GPUCompiler
using StaticTools
#####
# Compiler Target
#####
struct WASMTarget <: GPUCompiler.AbstractCompilerTarget end
GPUCompiler.llvm_triple(::WASMTarget) = "wasm32-unknown-wasi"
#GPUCompiler.llvm_triple(::WASMTarget) = "wasm64-unknown-wasi"
GPUCompiler.runtime_slug(::GPUCompiler.CompilerJob{WASMTarget}) = "wasm-test"
struct WASMTargetParams <: GPUCompiler.AbstractCompilerParams end
module StaticRuntime
# the runtime library
signal_exception() = return
malloc(sz) = C_NULL
report_oom(sz) = return
report_exception(ex) = return
report_exception_name(ex) = return
report_exception_frame(idx, func, file, line) = return
end
GPUCompiler.runtime_module(::GPUCompiler.CompilerJob{WASMTarget}) = StaticRuntime
GPUCompiler.uses_julia_runtime(::GPUCompiler.CompilerJob{WASMTarget}) = false
GPUCompiler.can_throw(::GPUCompiler.CompilerJob{WASMTarget}) = false
function wasm_job(@nospecialize(func), @nospecialize(types))
@info "Creating compiler job for '$func($types)'"
source = methodinstance(typeof(func), types)
target = WASMTarget()
params = WASMTargetParams()
# per default the function name will use C++ name mangling (GPUCompiler 0.19)
# for example _Z3add5Int32S_ for add(Int32, Int32) (see llvm-cxxfilt)
# here we will prefix a function with julia_ as it was the default in
# GPUCompiler 0.17
config = GPUCompiler.CompilerConfig(
target,
params,
kernel = false,
name = string("julia_",func),
)
job = GPUCompiler.CompilerJob(source, config)
end
function build_obj(@nospecialize(func), @nospecialize(types); kwargs...)
job = wasm_job(func, types)
@info "Compiling WASM for '$func($types)'"
target = :obj
obj = GPUCompiler.JuliaContext() do ctx
GPUCompiler.compile(
target,job;
libraries=false,
validate = false,
strip=true)[1]
end
return obj
end
# https://surma.dev/things/c-to-webassembly/
# ┌───────────────┬─────────────────────┬────────────────────────┐
# │ data │ ← stack │ heap → │
# └───────────────┴─────────────────────┴────────────────────────┘
# 0 __data_end __heap_base
#
# The stack grows downwards and the heap grows upwards.
# LLVM uses __stack_pointer
# see stack_pointer.wat
stack_pointer() =
Ptr{Nothing}(ccall("extern get_stack_pointer", llvmcall, Cint, ()))
stack_pointer(p) =
ccall("extern set_stack_pointer", llvmcall, Cvoid, (Cint,),Cint(p))
function push_stack(value::T) where T
stackptr = stack_pointer()
stackptr -= sizeof(Ptr)
unsafe_store!(Ptr{T}(stackptr),value)
stack_pointer(stackptr)
return stackptr
end
# simple RNG
import Random: rand, AbstractRNG
mutable struct LinearCongruentialGenerators <: AbstractRNG
seed::Int32
end
rng = LinearCongruentialGenerators(42)
function rand(rng::LinearCongruentialGenerators,::Type{Int32})
m = Int64(1) << 31
a = 1103515245
c = 12345
rng.seed = Int32((a * rng.seed + c) % m)
return rng.seed
end
function rand(rng::LinearCongruentialGenerators,::Type{Float32})
r = Int64(typemax(Int32)) - typemin(Int32)
return (Int64(rand(rng,Int32)) - typemin(Int32))/Float32(r)
end