Skip to content

Commit ca51bb2

Browse files
vchuravyjpsamaroo
andauthored
Support func entry abi (#287)
Co-authored-by: Julian Samaroo <[email protected]>
1 parent 2690e64 commit ca51bb2

File tree

6 files changed

+61
-13
lines changed

6 files changed

+61
-13
lines changed

src/driver.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ const __llvm_initialized = Ref(false)
203203

204204
@timeit_debug to "IR generation" begin
205205
ir, compiled = irgen(job, method_instance; ctx)
206-
entry_fn = compiled[method_instance].specfunc
206+
if job.entry_abi === :specfunc
207+
entry_fn = compiled[method_instance].specfunc
208+
else
209+
entry_fn = compiled[method_instance].func
210+
end
207211
entry = functions(ir)[entry_fn]
208212
end
209213

src/interface.jl

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,17 +117,37 @@ export CompilerJob
117117

118118
# a specific invocation of the compiler, bundling everything needed to generate code
119119

120+
"""
121+
CompilerJob(target, source, params, entry_abi)
122+
123+
Construct a `CompilerJob` for `source` that will be used to drive compilation for
124+
the given `target` and `params`. The `entry_abi` can be either `:specfunc` the default,
125+
or `:func`. `:specfunc` expects the arguments to be passed in registers, simple
126+
return values are returned in registers as well, and complex return values are returned
127+
on the stack using `sret`, the calling convention is `fastcc`. The `:func` abi is simpler
128+
with a calling convention of the first argument being the function itself (to support closures),
129+
the second argument being a pointer to a vector of boxed Julia values and the third argument
130+
being the number of values, the return value will also be boxed. The `:func` abi
131+
will internally call the `:specfunc` abi, but is generally easier to invoke directly.
132+
"""
120133
struct CompilerJob{T,P,F}
121134
target::T
122135
source::F
123136
params::P
137+
entry_abi::Symbol
124138

125-
CompilerJob(target::AbstractCompilerTarget, source::FunctionSpec, params::AbstractCompilerParams) =
126-
new{typeof(target), typeof(params), typeof(source)}(target, source, params)
139+
function CompilerJob(target::AbstractCompilerTarget, source::FunctionSpec, params::AbstractCompilerParams, entry_abi::Symbol)
140+
if entry_abi (:specfunc, :func)
141+
error("Unknown entry_abi=$entry_abi")
142+
end
143+
new{typeof(target), typeof(params), typeof(source)}(target, source, params, entry_abi)
144+
end
127145
end
146+
CompilerJob(target::AbstractCompilerTarget, source::FunctionSpec, params::AbstractCompilerParams; entry_abi=:specfunc) =
147+
CompilerJob(target, source, params, entry_abi)
128148

129149
Base.similar(@nospecialize(job::CompilerJob), @nospecialize(source::FunctionSpec)) =
130-
CompilerJob(job.target, source, job.params)
150+
CompilerJob(job.target, source, job.params, job.entry_abi)
131151

132152
function Base.show(io::IO, @nospecialize(job::CompilerJob{T})) where {T}
133153
print(io, "CompilerJob of ", job.source, " for ", T)
@@ -137,6 +157,7 @@ function Base.hash(job::CompilerJob, h::UInt)
137157
h = hash(job.target, h)
138158
h = hash(job.source, h)
139159
h = hash(job.params, h)
160+
h = hash(job.entry_abi, h)
140161
h
141162
end
142163

src/irgen.jl

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
function irgen(@nospecialize(job::CompilerJob), method_instance::Core.MethodInstance;
44
ctx::Context)
55
mod, compiled = @timeit_debug to "emission" compile_method_instance(job, method_instance; ctx)
6-
entry_fn = compiled[method_instance].specfunc
6+
if job.entry_abi === :specfunc
7+
entry_fn = compiled[method_instance].specfunc
8+
else
9+
entry_fn = compiled[method_instance].func
10+
end
711

812
# clean up incompatibilities
913
@timeit_debug to "clean-up" begin
@@ -16,8 +20,11 @@ function irgen(@nospecialize(job::CompilerJob), method_instance::Core.MethodInst
1620
end
1721

1822
# remove the non-specialized jfptr functions
19-
if startswith(LLVM.name(llvmf), "jfptr_")
20-
unsafe_delete!(mod, llvmf)
23+
# TODO: Do we need to remove these?
24+
if job.entry_abi === :specfunc
25+
if startswith(LLVM.name(llvmf), "jfptr_")
26+
unsafe_delete!(mod, llvmf)
27+
end
2128
end
2229
end
2330

@@ -55,9 +62,16 @@ function irgen(@nospecialize(job::CompilerJob), method_instance::Core.MethodInst
5562
LLVM.name!(entry, mangle_call(entry, job.source.tt))
5663
end
5764
entry = process_entry!(job, mod, entry)
65+
if job.entry_abi === :specfunc
66+
func = compiled[method_instance].func
67+
specfunc = LLVM.name(entry)
68+
else
69+
func = LLVM.name(entry)
70+
specfunc = compiled[method_instance].specfunc
71+
end
72+
5873
compiled[method_instance] =
59-
(; compiled[method_instance].ci, compiled[method_instance].func,
60-
specfunc=LLVM.name(entry))
74+
(; compiled[method_instance].ci, func, specfunc)
6175

6276
# minimal required optimization
6377
@timeit_debug to "rewrite" ModulePassManager() do pm

src/reflection.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ The following keyword arguments are supported:
102102
See also: [`@device_code_llvm`](@ref), `InteractiveUtils.code_llvm`
103103
"""
104104
function code_llvm(io::IO, @nospecialize(job::CompilerJob); optimize::Bool=true, raw::Bool=false,
105-
debuginfo::Symbol=:default, dump_module::Bool=false)
105+
debuginfo::Symbol=:default, dump_module::Bool=false, kwargs...)
106106
# NOTE: jl_dump_function_ir supports stripping metadata, so don't do it in the driver
107107
str = JuliaContext() do ctx
108-
ir, meta = codegen(:llvm, job; optimize=optimize, strip=false, validate=false, ctx)
108+
ir, meta = codegen(:llvm, job; optimize=optimize, strip=false, validate=false, ctx, kwargs...)
109109
ccall(:jl_dump_function_ir, Ref{String},
110110
(LLVM.API.LLVMValueRef, Bool, Bool, Ptr{UInt8}),
111111
meta.entry, !raw, dump_module, debuginfo)

test/definitions/native.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ end
1818

1919
GPUCompiler.method_table(@nospecialize(job::NativeCompilerJob)) = method_table
2020

21-
function native_job(@nospecialize(func), @nospecialize(types); kernel::Bool=false, kwargs...)
21+
function native_job(@nospecialize(func), @nospecialize(types); kernel::Bool=false, entry_abi=:specfunc, kwargs...)
2222
source = FunctionSpec(func, Base.to_tuple_type(types), kernel)
2323
target = NativeCompilerTarget(always_inline=true)
2424
params = TestCompilerParams()
25-
CompilerJob(target, source, params), kwargs
25+
CompilerJob(target, source, params, entry_abi), kwargs
2626
end
2727

2828
function native_code_typed(@nospecialize(func), @nospecialize(types); kwargs...)

test/native.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ end
135135
native_code_llvm(devnull, D32593, Tuple{Ptr{D32593_struct}})
136136
end
137137

138+
@testset "slow abi" begin
139+
x = 2
140+
f = () -> x+1
141+
ir = sprint(io->native_code_llvm(io, f, Tuple{}, entry_abi=:func, dump_module=true))
142+
@test occursin(r"define nonnull {}\* @jfptr", ir)
143+
@test occursin(r"define internal fastcc .+ @julia", ir)
144+
@test occursin(r"call fastcc .+ @julia", ir)
145+
end
146+
138147
end
139148

140149
############################################################################################

0 commit comments

Comments
 (0)