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}
@@ -68,7 +72,11 @@ function optimise_ir!(ir::IRCode; show_ir=false, do_inline=true)
6872
6973 ir = CC. compact! (ir)
7074 # CC.verify_ir(ir, true, false, CC.optimizer_lattice(local_interp))
71- CC. verify_linetable (ir. linetable, true )
75+ @static if VERSION >= v " 1.12-"
76+ CC. verify_linetable (ir. debuginfo, div (length (ir. debuginfo. codelocs), 3 ), true )
77+ else
78+ CC. verify_linetable (ir. linetable, true )
79+ end
7280 if show_ir
7381 println (" Post-optimization" )
7482 display (ir)
96104# Run type inference and constant propagation on the ir. Credit to @oxinabox:
97105# https://gist.github.com/oxinabox/cdcffc1392f91a2f6d80b2524726d802#file-example-jl-L54
98106function __infer_ir! (ir, interp:: CC.AbstractInterpreter , mi:: CC.MethodInstance )
99- method_info = CC. MethodInfo (true , nothing ) #= propagate_inbounds=#
100- min_world = world = get_inference_world (interp)
101- max_world = Base. get_world_counter ()
102- irsv = CC. IRInterpretationState (
103- interp, method_info, ir, mi, ir. argtypes, world, min_world, max_world
104- )
105- rt = CC. _ir_abstract_constant_propagation (interp, irsv)
107+ @static if VERSION >= v " 1.12-"
108+ nargs = length (ir. argtypes) - 1
109+ # TODO (mhauru) How should we figure out isva? I don't think it's in ir or mi.
110+ isva = false
111+ propagate_inbounds = true
112+ spec_info = CC. SpecInfo (nargs, isva, propagate_inbounds, nothing )
113+ min_world = world = get_inference_world (interp)
114+ max_world = Base. get_world_counter ()
115+ irsv = CC. IRInterpretationState (
116+ interp, spec_info, ir, mi, ir. argtypes, world, min_world, max_world
117+ )
118+ rt = CC. ir_abstract_constant_propagation (interp, irsv)
119+ else
120+ method_info = CC. MethodInfo (true , nothing ) #= propagate_inbounds=#
121+ min_world = world = get_inference_world (interp)
122+ max_world = Base. get_world_counter ()
123+ irsv = CC. IRInterpretationState (
124+ interp, method_info, ir, mi, ir. argtypes, world, min_world, max_world
125+ )
126+ rt = CC. _ir_abstract_constant_propagation (interp, irsv)
127+ end
106128 return ir
107129end
108130
@@ -168,19 +190,85 @@ function opaque_closure(
168190)
169191 # This implementation is copied over directly from `Core.OpaqueClosure`.
170192 ir = CC. copy (ir)
171- nargs = length (ir. argtypes) - 1
172- sig = Base. Experimental. compute_oc_signature (ir, nargs, isva)
193+ @static if VERSION >= v " 1.12-"
194+ # On v1.12 OpaqueClosure expects the first arg to be the environment.
195+ ir. argtypes[1 ] = typeof (env)
196+ end
197+ nargtypes = length (ir. argtypes)
198+ nargs = nargtypes - 1
199+ @static if VERSION >= v " 1.12-"
200+ sig = CC. compute_oc_signature (ir, nargs, isva)
201+ else
202+ sig = Base. Experimental. compute_oc_signature (ir, nargs, isva)
203+ end
173204 src = ccall (:jl_new_code_info_uninit , Ref{CC. CodeInfo}, ())
174- src. slotnames = fill ( :none , nargs + 1 )
175- src. slotflags = fill (zero (UInt8), length (ir . argtypes) )
205+ src. slotnames = [ Symbol ( :_ , i) for i in 1 : nargtypes]
206+ src. slotflags = fill (zero (UInt8), nargtypes )
176207 src. slottypes = copy (ir. argtypes)
177- src. rettype = ret_type
208+ @static if VERSION > v " 1.12-"
209+ ir. debuginfo. def === nothing &&
210+ (ir. debuginfo. def = :var"generated IR for OpaqueClosure" )
211+ src. min_world = ir. valid_worlds. min_world
212+ src. max_world = ir. valid_worlds. max_world
213+ src. isva = isva
214+ src. nargs = nargtypes
215+ end
178216 src = CC. ir_to_codeinf! (src, ir)
217+ src. rettype = ret_type
179218 return Base. Experimental. generate_opaque_closure (
180219 sig, Union{}, ret_type, src, nargs, isva, env... ; do_compile
181220 ):: Core.OpaqueClosure{sig,ret_type}
182221end
183222
223+ function optimized_opaque_closure (rtype, ir:: IRCode , env... ; kwargs... )
224+ oc = opaque_closure (rtype, ir, env... ; kwargs... )
225+ world = UInt (oc. world)
226+ set_world_bounds_for_optimization! (oc)
227+ optimized_oc = optimize_opaque_closure (oc, rtype, env... ; kwargs... )
228+ return optimized_oc
229+ end
230+
231+ function optimize_opaque_closure (oc:: Core.OpaqueClosure , rtype, env... ; kwargs... )
232+ method = oc. source
233+ ci = method. specializations. cache
234+ world = UInt (oc. world)
235+ ir = reinfer_and_inline (ci, world)
236+ ir === nothing && return oc # nothing to optimize
237+ return opaque_closure (rtype, ir, env... ; kwargs... )
238+ end
239+
240+ # Allows optimization to make assumptions about binding access,
241+ # enabling inlining and other optimizations.
242+ function set_world_bounds_for_optimization! (oc:: Core.OpaqueClosure )
243+ ci = oc. source. specializations. cache
244+ ci. inferred === nothing && return nothing
245+ ci. inferred. min_world = oc. world
246+ return ci. inferred. max_world = oc. world
247+ end
248+
249+ function reinfer_and_inline (ci:: Core.CodeInstance , world:: UInt )
250+ interp = CC. NativeInterpreter (world)
251+ mi = get_mi (ci)
252+ argtypes = collect (Any, mi. specTypes. parameters)
253+ irsv = CC. IRInterpretationState (interp, ci, mi, argtypes, world)
254+ irsv === nothing && return nothing
255+ for stmt in irsv. ir. stmts
256+ inst = stmt[:inst ]
257+ if Meta. isexpr (inst, :loopinfo ) ||
258+ Meta. isexpr (inst, :pop_exception ) ||
259+ isa (inst, CC. GotoIfNot) ||
260+ isa (inst, CC. GotoNode) ||
261+ Meta. isexpr (inst, :copyast )
262+ continue
263+ end
264+ stmt[:flag ] |= CC. IR_FLAG_REFINED
265+ end
266+ CC. ir_abstract_constant_propagation (interp, irsv)
267+ state = CC. InliningState (interp)
268+ ir = CC. ssa_inlining_pass! (irsv. ir, state, CC. propagate_inbounds (irsv))
269+ return ir
270+ end
271+
184272"""
185273 misty_closure(
186274 ret_type::Type,
@@ -202,3 +290,15 @@ function misty_closure(
202290)
203291 return MistyClosure (opaque_closure (ret_type, ir, env... ; isva, do_compile), Ref (ir))
204292end
293+
294+ function optimized_misty_closure (
295+ ret_type:: Type ,
296+ ir:: IRCode ,
297+ @nospecialize env... ;
298+ isva:: Bool = false ,
299+ do_compile:: Bool = true ,
300+ )
301+ return MistyClosure (
302+ optimized_opaque_closure (ret_type, ir, env... ; isva, do_compile), Ref (ir)
303+ )
304+ end
0 commit comments