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