Skip to content

Commit 1e6116b

Browse files
Merge pull request #150 from gbaraldi/gb/refactor-code
Refactor code to make it more amenable to cross compilation
2 parents 73a033c + 0eb680b commit 1e6116b

File tree

5 files changed

+183
-98
lines changed

5 files changed

+183
-98
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
name = "StaticCompiler"
22
uuid = "81625895-6c0f-48fc-b932-11a18313743c"
33
authors = ["Tom Short and contributors"]
4-
version = "0.6.3"
4+
version = "0.7.0"
5+
56

67
[deps]
78
Clang_jll = "0ee61d77-7f21-5576-8119-9fcc46b10100"

src/StaticCompiler.jl

Lines changed: 70 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ using LLD_jll: lld
1212
using StaticTools
1313
using StaticTools: @symbolcall, @c_str, println
1414
using Core: MethodTable
15-
15+
using Base:BinaryPlatforms.Platform, BinaryPlatforms.HostPlatform, BinaryPlatforms.arch, BinaryPlatforms.os_str, BinaryPlatforms.libc_str
16+
using Base:BinaryPlatforms.platform_dlext
1617
export load_function, compile_shlib, compile_executable
17-
export native_code_llvm, native_code_typed, native_llvm_module, native_code_native
18+
export static_code_llvm, static_code_typed, static_llvm_module, static_code_native
1819
export @device_override, @print_and_throw
20+
export StaticTarget
1921

2022
include("interpreter.jl")
2123
include("target.jl")
@@ -32,6 +34,7 @@ compile_executable(f::Function, types::Tuple, path::String, [name::String=string
3234
filename::String=name,
3335
cflags=``, # Specify libraries you would like to link against, and other compiler options here
3436
also_expose=[],
37+
target::StaticTarget=StaticTarget(),
3538
method_table=StaticCompiler.method_table,
3639
kwargs...
3740
)
@@ -96,16 +99,16 @@ Hello, world!
9699
```
97100
"""
98101
function compile_executable(f::Function, types=(), path::String="./", name=fix_name(f);
99-
also_expose=Tuple{Function, Tuple{DataType}}[],
102+
also_expose=Tuple{Function, Tuple{DataType}}[], target::StaticTarget=StaticTarget(),
100103
kwargs...)
101-
102-
compile_executable(vcat([(f, types)], also_expose), path, name; kwargs...)
104+
compile_executable(vcat([(f, types)], also_expose), path, name; target, kwargs...)
103105
end
104106

105107
function compile_executable(funcs::Union{Array,Tuple}, path::String="./", name=fix_name(first(first(funcs)));
106108
filename = name,
107109
demangle = true,
108110
cflags = ``,
111+
target::StaticTarget=StaticTarget(),
109112
kwargs...
110113
)
111114

@@ -114,12 +117,12 @@ function compile_executable(funcs::Union{Array,Tuple}, path::String="./", name=f
114117
isexecutableargtype = tt == Tuple{} || tt == Tuple{Int, Ptr{Ptr{UInt8}}}
115118
isexecutableargtype || @warn "input type signature $types should be either `()` or `(Int, Ptr{Ptr{UInt8}})` for standard executables"
116119

117-
rt = last(only(native_code_typed(f, tt; kwargs...)))
120+
rt = last(only(static_code_typed(f, tt; target, kwargs...)))
118121
isconcretetype(rt) || error("`$f$types` did not infer to a concrete type. Got `$rt`")
119122
nativetype = isprimitivetype(rt) || isa(rt, Ptr)
120123
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!"
121124

122-
generate_executable(funcs, path, name, filename; demangle, cflags, kwargs...)
125+
generate_executable(funcs, path, name, filename; demangle, cflags, target, kwargs...)
123126
joinpath(abspath(path), filename)
124127
end
125128

@@ -129,13 +132,15 @@ compile_shlib(f::Function, types::Tuple, [path::String="./"], [name::String=stri
129132
filename::String=name,
130133
cflags=``,
131134
method_table=StaticCompiler.method_table,
135+
target::StaticTarget=StaticTarget(),
132136
kwargs...)
133137
134138
compile_shlib(funcs::Array, [path::String="./"];
135139
filename="libfoo",
136140
demangle=true,
137141
cflags=``,
138142
method_table=StaticCompiler.method_table,
143+
target::StaticTarget=StaticTarget(),
139144
kwargs...)
140145
```
141146
As `compile_executable`, but compiling to a standalone `.dylib`/`.so` shared library.
@@ -169,33 +174,35 @@ julia> ccall(("test", "test.dylib"), Float64, (Int64,), 100_000)
169174
"""
170175
function compile_shlib(f::Function, types=(), path::String="./", name=fix_name(f);
171176
filename=name,
177+
target::StaticTarget=StaticTarget(),
172178
kwargs...
173179
)
174-
compile_shlib(((f, types),), path; filename, kwargs...)
180+
compile_shlib(((f, types),), path; filename, target, kwargs...)
175181
end
176182
# As above, but taking an array of functions and returning a single shlib
177183
function compile_shlib(funcs::Union{Array,Tuple}, path::String="./";
178184
filename = "libfoo",
179185
demangle = true,
180186
cflags = ``,
187+
target::StaticTarget=StaticTarget(),
181188
kwargs...
182189
)
183190
for func in funcs
184191
f, types = func
185192
tt = Base.to_tuple_type(types)
186193
isconcretetype(tt) || error("input type signature `$types` is not concrete")
187194

188-
rt = last(only(native_code_typed(f, tt)))
195+
rt = last(only(static_code_typed(f, tt; target, kwargs...)))
189196
isconcretetype(rt) || error("`$f$types` did not infer to a concrete type. Got `$rt`")
190197
nativetype = isprimitivetype(rt) || isa(rt, Ptr)
191198
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!"
192199
end
193200

194-
generate_shlib(funcs, true, path, filename; demangle, cflags, kwargs...)
201+
generate_shlib(funcs, path, filename; demangle, cflags, target, kwargs...)
195202

196203
joinpath(abspath(path), filename * "." * Libdl.dlext)
197204
end
198-
205+
199206

200207
"""
201208
```julia
@@ -281,14 +288,18 @@ generate_executable(f, tt, args...; kwargs...) = generate_executable(((f, tt),),
281288
function generate_executable(funcs::Union{Array,Tuple}, path=tempname(), name=fix_name(first(first(funcs))), filename=name;
282289
demangle = true,
283290
cflags = ``,
291+
target::StaticTarget=StaticTarget(),
284292
kwargs...
285293
)
286-
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
287294
exec_path = joinpath(path, filename)
288-
external = true
289-
_, obj_path = generate_obj(funcs, external, path, filename; demangle, kwargs...)
295+
_, obj_path = generate_obj(funcs, path, filename; demangle, target, kwargs...)
290296
# Pick a compiler
291-
cc = Sys.isapple() ? `cc` : clang()
297+
if !isnothing(target.compiler)
298+
cc = `$(target.compiler)`
299+
else
300+
cc = Sys.isapple() ? `cc` : clang()
301+
end
302+
292303
# Compile!
293304
if Sys.isapple()
294305
# Apple no longer uses _start, so we can just specify a custom entry
@@ -318,8 +329,8 @@ end
318329

319330
"""
320331
```julia
321-
generate_shlib(f::Function, tt, [external::Bool=true], [path::String], [name], [filename]; kwargs...)
322-
generate_shlib(funcs::Array, [external::Bool=true], [path::String], [filename::String]; demangle=true, kwargs...)
332+
generate_shlib(f::Function, tt, [path::String], [name], [filename]; kwargs...)
333+
generate_shlib(funcs::Array, [path::String], [filename::String]; demangle=true, target::StaticTarget=StaticTarget(), kwargs...)
323334
```
324335
Low level interface for compiling a shared object / dynamically loaded library
325336
(`.so` / `.dylib`) for function `f` given a tuple type `tt` characterizing
@@ -356,75 +367,83 @@ julia> ccall(("test", "example/test.dylib"), Float64, (Int64,), 100_000)
356367
5.2564961094956075
357368
```
358369
"""
359-
function generate_shlib(f::Function, tt, external::Bool=true, path::String=tempname(), name=fix_name(f), filename=name; kwargs...)
360-
generate_shlib(((f, tt),), external, path, filename; kwargs...)
370+
function generate_shlib(f::Function, tt, path::String=tempname(), name=fix_name(f), filename=name; target=StaticTarget(), kwargs...)
371+
generate_shlib(((f, tt),), path, filename; target, kwargs...)
361372
end
362373
# As above, but taking an array of functions and returning a single shlib
363-
function generate_shlib(funcs::Union{Array,Tuple}, external::Bool=true, path::String=tempname(), filename::String="libfoo";
374+
function generate_shlib(funcs::Union{Array,Tuple}, path::String=tempname(), filename::String="libfoo";
364375
demangle = true,
365376
cflags = ``,
377+
target::StaticTarget=StaticTarget(),
366378
kwargs...
367379
)
380+
if !isnothing(target.platform)
381+
lib_path = joinpath(path, "$filename.$(platform_dlext(target.platform))")
382+
else
383+
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
384+
end
368385

369-
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
370-
371-
_, obj_path = generate_obj(funcs, external, path, filename; demangle, kwargs...)
386+
_, obj_path = generate_obj(funcs, path, filename; target, demangle, kwargs...)
372387
# Pick a Clang
373-
cc = Sys.isapple() ? `cc` : clang()
388+
if !isnothing(target.compiler)
389+
cc = `$(target.compiler)`
390+
else
391+
cc = Sys.isapple() ? `cc` : clang()
392+
end
374393
# Compile!
375394
run(`$cc -shared $cflags $obj_path -o $lib_path `)
376395

377396
path, name
378397
end
379398

380-
function native_code_llvm(@nospecialize(func), @nospecialize(types); kwargs...)
381-
job, kwargs = native_job(func, types, true; kwargs...)
382-
GPUCompiler.code_llvm(stdout, job; kwargs...)
399+
function static_code_llvm(@nospecialize(func), @nospecialize(types); target::StaticTarget=StaticTarget(), kwargs...)
400+
job, kwargs = static_job(func, types; target, kwargs...)
401+
GPUCompiler.code_llvm(stdout, job; libraries=false, kwargs...)
383402
end
384403

385-
function native_code_typed(@nospecialize(func), @nospecialize(types); kwargs...)
386-
job, kwargs = native_job(func, types, true; kwargs...)
404+
function static_code_typed(@nospecialize(func), @nospecialize(types); target::StaticTarget=StaticTarget(), kwargs...)
405+
job, kwargs = static_job(func, types; target, kwargs...)
387406
GPUCompiler.code_typed(job; kwargs...)
388407
end
389408

390-
function native_code_native(@nospecialize(f), @nospecialize(tt), fname=fix_name(f); kwargs...)
391-
job, kwargs = native_job(f, tt, true; fname, kwargs...)
392-
GPUCompiler.code_native(stdout, job; kwargs...)
409+
function static_code_native(@nospecialize(f), @nospecialize(tt), fname=fix_name(f); target::StaticTarget=StaticTarget(), kwargs...)
410+
job, kwargs = static_job(f, tt; fname, target, kwargs...)
411+
GPUCompiler.code_native(stdout, job; libraries=false, kwargs...)
393412
end
394413

395414
# Return an LLVM module
396-
function native_llvm_module(f, tt, name=fix_name(f); demangle, kwargs...)
415+
function static_llvm_module(f, tt, name=fix_name(f); demangle=true, target::StaticTarget=StaticTarget(), kwargs...)
397416
if !demangle
398417
name = "julia_"*name
399418
end
400-
job, kwargs = native_job(f, tt, true; name, kwargs...)
419+
job, kwargs = static_job(f, tt; name, target, kwargs...)
401420
m = GPUCompiler.JuliaContext() do context
402-
m, _ = GPUCompiler.codegen(:llvm, job; strip=true, only_entry=false, validate=false)
421+
m, _ = GPUCompiler.codegen(:llvm, job; strip=true, only_entry=false, validate=false, libraries=false)
403422
locate_pointers_and_runtime_calls(m)
404423
m
405424
end
406425
return m
407426
end
408427

409428
#Return an LLVM module for multiple functions
410-
function native_llvm_module(funcs::Union{Array,Tuple}; demangle=true, kwargs...)
429+
function static_llvm_module(funcs::Union{Array,Tuple}; demangle=true, target::StaticTarget=StaticTarget(), kwargs...)
411430
f,tt = funcs[1]
412431
mod = GPUCompiler.JuliaContext() do context
413432
name_f = fix_name(f)
414433
if !demangle
415434
name_f = "julia_"*name_f
416435
end
417-
job, kwargs = native_job(f, tt, true; name = name_f, kwargs...)
418-
mod,_ = GPUCompiler.codegen(:llvm, job; strip=true, only_entry=false, validate=false)
436+
job, kwargs = static_job(f, tt; name = name_f, target, kwargs...)
437+
mod,_ = GPUCompiler.codegen(:llvm, job; strip=true, only_entry=false, validate=false, libraries=false)
419438
if length(funcs) > 1
420439
for func in funcs[2:end]
421440
f,tt = func
422441
name_f = fix_name(f)
423442
if !demangle
424443
name_f = "julia_"*name_f
425444
end
426-
job, kwargs = native_job(f, tt, true; name = name_f, kwargs...)
427-
tmod,_ = GPUCompiler.codegen(:llvm, job; strip=true, only_entry=false, validate=false)
445+
job, kwargs = static_job(f, tt; name = name_f, target, kwargs...)
446+
tmod,_ = GPUCompiler.codegen(:llvm, job; strip=true, only_entry=false, validate=false, libraries=false)
428447
link!(mod,tmod)
429448
end
430449
end
@@ -458,8 +477,8 @@ end
458477

459478
"""
460479
```julia
461-
generate_obj(f, tt, external::Bool, path::String = tempname(), filenamebase::String="obj";
462-
target = (),
480+
generate_obj(f, tt, path::String = tempname(), filenamebase::String="obj";
481+
target::StaticTarget=StaticTarget(),
463482
demangle = true,
464483
strip_llvm = false,
465484
strip_asm = true,
@@ -471,7 +490,7 @@ a tuple type `tt` characterizing the types of the arguments for which the
471490
function will be compiled.
472491
473492
`target` can be used to change the output target. This is useful for compiling to WebAssembly and embedded targets.
474-
This is a named tuple with fields `triple`, `cpu`, and `features` (each of these are strings).
493+
This is a struct of the type StaticTarget()
475494
The defaults compile to the native target.
476495
477496
If `demangle` is set to `false`, compiled function names are prepended with "julia_".
@@ -481,7 +500,7 @@ If `demangle` is set to `false`, compiled function names are prepended with "jul
481500
julia> fib(n) = n <= 1 ? n : fib(n - 1) + fib(n - 2)
482501
fib (generic function with 1 method)
483502
484-
julia> path, name, table = StaticCompiler.generate_obj_for_compile(fib, Tuple{Int64}, "./test")
503+
julia> path, name, table = StaticCompiler.generate_obj(fib, Tuple{Int64}, "./test")
485504
("./test", "fib", IdDict{Any, String}())
486505
487506
shell> tree \$path
@@ -498,8 +517,8 @@ end
498517

499518
"""
500519
```julia
501-
generate_obj(funcs::Union{Array,Tuple}, external::Bool, path::String = tempname(), filenamebase::String="obj";
502-
target = (),
520+
generate_obj(funcs::Union{Array,Tuple}, path::String = tempname(), filenamebase::String="obj";
521+
target::StaticTarget=StaticTarget(),
503522
demangle =false,
504523
strip_llvm = false,
505524
strip_asm = true,
@@ -511,21 +530,22 @@ Low level interface for compiling object code (`.o`) for an array of Tuples
511530
which will be compiled.
512531
513532
`target` can be used to change the output target. This is useful for compiling to WebAssembly and embedded targets.
514-
This is a named tuple with fields `triple`, `cpu`, and `features` (each of these are strings).
533+
This is a struct of the type StaticTarget()
515534
The defaults compile to the native target.
516535
"""
517-
function generate_obj(funcs::Union{Array,Tuple}, external::Bool, path::String = tempname(), filenamebase::String="obj";
536+
function generate_obj(funcs::Union{Array,Tuple}, path::String = tempname(), filenamebase::String="obj";
518537
demangle = true,
519538
strip_llvm = false,
520539
strip_asm = true,
521540
opt_level = 3,
541+
target::StaticTarget=StaticTarget(),
522542
kwargs...)
523543
f, tt = funcs[1]
524544
mkpath(path)
525545
obj_path = joinpath(path, "$filenamebase.o")
526-
mod = native_llvm_module(funcs; demangle, kwargs...)
546+
mod = static_llvm_module(funcs; demangle, kwargs...)
527547
obj = GPUCompiler.JuliaContext() do ctx
528-
fakejob, _ = native_job(f, tt, external; kwargs...)
548+
fakejob, _ = static_job(f, tt; target, kwargs...)
529549
obj, _ = GPUCompiler.emit_asm(fakejob, mod; strip=strip_asm, validate=false, format=LLVM.API.LLVMObjectFile)
530550
obj
531551
end

0 commit comments

Comments
 (0)