Skip to content

Commit 4cb4940

Browse files
committed
Optimise opaque closures on 1.12
Copied over from @serenity4's work in chalk-lab/Mooncake.jl#714
1 parent 310f6f5 commit 4cb4940

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

src/copyable_task.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@ function build_callable(sig::Type{<:Tuple})
9090
unoptimised_ir = IRCode(bb)
9191
optimised_ir = optimise_ir!(unoptimised_ir)
9292
mc_ret_type = callable_ret_type(sig, types)
93-
mc = misty_closure(mc_ret_type, optimised_ir, refs...; isva=isva, do_compile=true)
93+
mc = optimized_misty_closure(
94+
mc_ret_type, optimised_ir, refs...; isva=isva, do_compile=true
95+
)
9496
mc_cache[key] = mc
9597
return mc, refs[end]
9698
end

src/utils.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
function get_mi(ci::Core.CodeInstance)
2+
@static isdefined(CC, :get_ci_mi) ? CC.get_ci_mi(ci) : ci.def
3+
end
4+
get_mi(mi::Core.MethodInstance) = mi
15

26
"""
37
replace_captures(oc::Toc, new_captures) where {Toc<:OpaqueClosure}
@@ -218,6 +222,55 @@ function opaque_closure(
218222
)::Core.OpaqueClosure{sig,ret_type}
219223
end
220224

225+
function optimized_opaque_closure(rtype, ir::IRCode, env...; kwargs...)
226+
oc = opaque_closure(rtype, ir, env...; kwargs...)
227+
world = UInt(oc.world)
228+
set_world_bounds_for_optimization!(oc)
229+
optimized_oc = optimize_opaque_closure(oc, rtype, env...; kwargs...)
230+
return optimized_oc
231+
end
232+
233+
function optimize_opaque_closure(oc::Core.OpaqueClosure, rtype, env...; kwargs...)
234+
method = oc.source
235+
ci = method.specializations.cache
236+
world = UInt(oc.world)
237+
ir = reinfer_and_inline(ci, world)
238+
ir === nothing && return oc # nothing to optimize
239+
return opaque_closure(rtype, ir, env...; kwargs...)
240+
end
241+
242+
# Allows optimization to make assumptions about binding access,
243+
# enabling inlining and other optimizations.
244+
function set_world_bounds_for_optimization!(oc::Core.OpaqueClosure)
245+
ci = oc.source.specializations.cache
246+
ci.inferred === nothing && return nothing
247+
ci.inferred.min_world = oc.world
248+
return ci.inferred.max_world = oc.world
249+
end
250+
251+
function reinfer_and_inline(ci::Core.CodeInstance, world::UInt)
252+
interp = CC.NativeInterpreter(world)
253+
mi = get_mi(ci)
254+
argtypes = collect(Any, mi.specTypes.parameters)
255+
irsv = CC.IRInterpretationState(interp, ci, mi, argtypes, world)
256+
irsv === nothing && return nothing
257+
for stmt in irsv.ir.stmts
258+
inst = stmt[:inst]
259+
if Meta.isexpr(inst, :loopinfo) ||
260+
Meta.isexpr(inst, :pop_exception) ||
261+
isa(inst, CC.GotoIfNot) ||
262+
isa(inst, CC.GotoNode) ||
263+
Meta.isexpr(inst, :copyast)
264+
continue
265+
end
266+
stmt[:flag] |= CC.IR_FLAG_REFINED
267+
end
268+
CC.ir_abstract_constant_propagation(interp, irsv)
269+
state = CC.InliningState(interp)
270+
ir = CC.ssa_inlining_pass!(irsv.ir, state, CC.propagate_inbounds(irsv))
271+
return ir
272+
end
273+
221274
"""
222275
misty_closure(
223276
ret_type::Type,
@@ -239,3 +292,15 @@ function misty_closure(
239292
)
240293
return MistyClosure(opaque_closure(ret_type, ir, env...; isva, do_compile), Ref(ir))
241294
end
295+
296+
function optimized_misty_closure(
297+
ret_type::Type,
298+
ir::IRCode,
299+
@nospecialize env...;
300+
isva::Bool=false,
301+
do_compile::Bool=true,
302+
)
303+
return MistyClosure(
304+
optimized_opaque_closure(ret_type, ir, env...; isva, do_compile), Ref(ir)
305+
)
306+
end

0 commit comments

Comments
 (0)