1919const InferenceKey = Union{CodeInstance,InferenceResult} # TODO make this `CodeInstance` fully
2020const InferenceDict{InferenceValue} = IdDict{InferenceKey, InferenceValue}
2121const PC2Remarks = Vector{Pair{Int, String}}
22+ const PC2CallMeta = Dict{Int, CallMeta}
2223const PC2Effects = Dict{Int, Effects}
2324const PC2Excts = Dict{Int, Any}
2425
@@ -29,6 +30,7 @@ struct CthulhuInterpreter <: AbstractInterpreter
2930 native:: AbstractInterpreter
3031 unopt:: InferenceDict{InferredSource}
3132 remarks:: InferenceDict{PC2Remarks}
33+ calls:: InferenceDict{PC2CallMeta}
3234 effects:: InferenceDict{PC2Effects}
3335 exception_types:: InferenceDict{PC2Excts}
3436end
@@ -39,6 +41,7 @@ function CthulhuInterpreter(interp::AbstractInterpreter=NativeInterpreter())
3941 interp,
4042 InferenceDict {InferredSource} (),
4143 InferenceDict {PC2Remarks} (),
44+ InferenceDict {PC2CallMeta} (),
4245 InferenceDict {PC2Effects} (),
4346 InferenceDict {PC2Excts} ())
4447end
@@ -96,6 +99,21 @@ function CC.update_exc_bestguess!(interp::CthulhuInterpreter, @nospecialize(exct
9699 frame:: InferenceState )
97100end
98101
102+ function CC. abstract_call (interp:: CthulhuInterpreter , arginfo:: CC.ArgInfo , sstate:: CC.StatementState , sv:: InferenceState )
103+ call = @invoke CC. abstract_call (interp:: AbstractInterpreter , arginfo:: CC.ArgInfo , sstate:: CC.StatementState , sv:: InferenceState )
104+ if isa (sv, InferenceState)
105+ key = get_inference_key (sv)
106+ if key != = nothing
107+ CC. Future {Any} (call, interp, sv) do call, interp, sv
108+ calls = get! (PC2CallMeta, interp. calls, key)
109+ calls[sv. currpc] = call
110+ nothing
111+ end
112+ end
113+ end
114+ return call
115+ end
116+
99117function InferredSource (state:: InferenceState )
100118 unoptsrc = copy (state. src)
101119 exct = state. result. exc_result
@@ -107,6 +125,66 @@ function InferredSource(state::InferenceState)
107125 exct)
108126end
109127
128+ @static if VERSION ≥ v " 1.13-"
129+ function _finishinfer! (frame:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int , opt_cache:: IdDict{MethodInstance, CodeInstance} )
130+ return @invoke CC. finishinfer! (frame:: InferenceState , interp:: AbstractInterpreter , cycleid:: Int , opt_cache:: IdDict{MethodInstance, CodeInstance} )
131+ end
132+ else
133+ function _finishinfer! (frame:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int )
134+ return @invoke CC. finishinfer! (frame:: InferenceState , interp:: AbstractInterpreter , cycleid:: Int )
135+ end
136+ end
137+
138+ function cthulhu_finish (result:: Union{Nothing, InferenceResult} , frame:: InferenceState , interp:: CthulhuInterpreter )
139+ key = get_inference_key (frame)
140+ key === nothing && return result
141+ interp. unopt[key] = InferredSource (frame)
142+
143+ # Wrap `CallInfo`s with `CthulhuCallInfo`s post-inference.
144+ calls = get (interp. calls, key, nothing )
145+ isnothing (calls) && return result
146+ for (i, info) in enumerate (frame. stmt_info)
147+ info === NoCallInfo () && continue
148+ call = get (calls, i, nothing )
149+ call === nothing && continue
150+ if isa (info, CC. UnionSplitApplyCallInfo)
151+ # XXX : `UnionSplitApplyCallInfo` is specially handled in `CC.inline_apply!`,
152+ # so we can't shove it under a `CthulhuCallInfo`.
153+ frame. stmt_info[i] = pack_cthulhuinfo_in_unionsplit (call, info)
154+ else
155+ frame. stmt_info[i] = CthulhuCallInfo (call)
156+ end
157+ end
158+
159+ return result
160+ end
161+
162+ # Rebuild a `CC.UnionSplitApplyCallInfo` structure where inner `ApplyCallInfo`s wrap a `CthulhuCallInfo`.
163+ # Note that technically, `rt`/`exct`/`effects`/`refinements` are incorrect for each apply call as they
164+ # apply to the union split as a whole, not to individual branches. The idea is simply to preserve them.
165+ function pack_cthulhuinfo_in_unionsplit (call:: CallMeta , info:: CC.UnionSplitApplyCallInfo )
166+ infos = CC. ApplyCallInfo[]
167+ for apply in info. infos
168+ meta = CallMeta (call. rt, call. exct, call. effects, apply. call, call. refinements)
169+ push! (infos, CC. ApplyCallInfo (CthulhuCallInfo (meta), apply. arginfo))
170+ end
171+ return CC. UnionSplitApplyCallInfo (infos)
172+ end
173+
174+ # Build a `CthulhuCallInfo` structure wrapping `CC.UnionSplitApplyCallInfo`.
175+ function unpack_cthulhuinfo_from_unionsplit (info:: CC.UnionSplitApplyCallInfo )
176+ isempty (info. infos) && return nothing
177+ apply = info. infos[1 ]
178+ isa (apply. call, CthulhuCallInfo) || return nothing
179+ (; rt, exct, effects, refinements) = apply. call. meta
180+ infos = CC. ApplyCallInfo[]
181+ for apply in info. infos
182+ push! (infos, CC. ApplyCallInfo (apply. call. meta. info, apply. arginfo))
183+ end
184+ call = CallMeta (rt, exct, effects, CC. UnionSplitApplyCallInfo (infos), refinements)
185+ return CthulhuCallInfo (call)
186+ end
187+
110188function create_cthulhu_source (result:: InferenceResult , effects:: Effects )
111189 isa (result. src, OptimizationState) || return result. src
112190 opt = result. src
@@ -127,25 +205,9 @@ function set_cthulhu_source!(result::InferenceResult)
127205end
128206
129207@static if VERSION ≥ v " 1.13-"
130- CC. finishinfer! (state:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int , opt_cache:: IdDict{MethodInstance, CodeInstance} ) = cthulhu_finish (CC. finishinfer!, state, interp, cycleid, opt_cache)
131- function cthulhu_finish (@specialize (finishfunc), state:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int , opt_cache:: IdDict{MethodInstance, CodeInstance} )
132- res = @invoke finishfunc (state:: InferenceState , interp:: AbstractInterpreter , cycleid:: Int , opt_cache:: IdDict{MethodInstance, CodeInstance} )
133- key = get_inference_key (state)
134- if key != = nothing
135- interp. unopt[key] = InferredSource (state)
136- end
137- return res
138- end
208+ CC. finishinfer! (state:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int , opt_cache:: IdDict{MethodInstance, CodeInstance} ) = cthulhu_finish (_finishinfer! (state, interp, cycleid, opt_cache), state, interp)
139209else
140- function cthulhu_finish (@specialize (finishfunc), state:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int )
141- res = @invoke finishfunc (state:: InferenceState , interp:: AbstractInterpreter , cycleid:: Int )
142- key = get_inference_key (state)
143- if key != = nothing
144- interp. unopt[key] = InferredSource (state)
145- end
146- return res
147- end
148- CC. finishinfer! (state:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int ) = cthulhu_finish (CC. finishinfer!, state, interp, cycleid)
210+ CC. finishinfer! (state:: InferenceState , interp:: CthulhuInterpreter , cycleid:: Int ) = cthulhu_finish (_finishinfer! (state, interp, cycleid), state, interp)
149211end
150212
151213function CC. finish! (interp:: CthulhuInterpreter , caller:: InferenceState , validation_world:: UInt , time_before:: UInt64 )
0 commit comments