diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 366db15507614..e20b74454bb22 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -1323,7 +1323,7 @@ function const_prop_call(interp::AbstractInterpreter, pop!(callstack) return nothing end - inf_result.ci_as_edge = codeinst_as_edge(interp, mi, Core.svec(frame.edges...)) + inf_result.ci_as_edge = codeinst_as_edge(interp, frame) @assert frame.frameid != 0 && frame.cycleid == frame.frameid @assert frame.parentid == sv.frameid @assert inf_result.result !== nothing diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index a95ad958e8e00..c3a0f944497a3 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -69,7 +69,7 @@ struct InliningEdgeTracker new(state.edges, invokesig) end -function add_inlining_edge!(et::InliningEdgeTracker, edge::CodeInstance) +function add_inlining_edge!(et::InliningEdgeTracker, edge::Union{CodeInstance,MethodInstance}) (; edges, invokesig) = et if invokesig === nothing add_one_edge!(edges, edge) @@ -785,9 +785,9 @@ function rewrite_apply_exprargs!(todo::Vector{Pair{Int,Any}}, return new_argtypes end -function compileable_specialization(edge::CodeInstance, effects::Effects, +function compileable_specialization(mi::MethodInstance, effects::Effects, et::InliningEdgeTracker, @nospecialize(info::CallInfo), state::InliningState) - mi_invoke = mi = edge.def + mi_invoke = mi method, atype, sparams = mi.def::Method, mi.specTypes, mi.sparam_vals if OptimizationParams(state.interp).compilesig_invokes new_atype = get_compileable_sig(method, atype, sparams) @@ -807,10 +807,9 @@ function compileable_specialization(edge::CodeInstance, effects::Effects, return nothing end end - add_inlining_edge!(et, edge) # to the dispatch lookup + add_inlining_edge!(et, mi) # to the dispatch lookup if mi_invoke !== mi - edge_invoke = codeinst_as_invoke_edge(state.interp, mi_invoke) - add_invoke_edge!(et.edges, method.sig, edge_invoke) # add_inlining_edge to the invoke call, if that is different + add_invoke_edge!(et.edges, method.sig, mi_invoke) # add_inlining_edge to the invoke call, if that is different end return InvokeCase(mi_invoke, effects, info) end @@ -871,18 +870,17 @@ function resolve_todo(mi::MethodInstance, result::Union{Nothing,InferenceResult, effects = decode_effects(inferred_result.ipo_purity_bits) edge = inferred_result else # there is no cached source available, bail out - edge = codeinst_as_invoke_edge(state.interp, mi) - return compileable_specialization(edge, Effects(), et, info, state) + return compileable_specialization(mi, Effects(), et, info, state) end # the duplicated check might have been done already within `analyze_method!`, but still # we need it here too since we may come here directly using a constant-prop' result if !OptimizationParams(state.interp).inlining || is_stmt_noinline(flag) - return compileable_specialization(edge, effects, et, info, state) + return compileable_specialization(edge.def, effects, et, info, state) end src_inlining_policy(state.interp, src, info, flag) || - return compileable_specialization(edge, effects, et, info, state) + return compileable_specialization(edge.def, effects, et, info, state) add_inlining_edge!(et, edge) if inferred_result isa CodeInstance @@ -1500,7 +1498,7 @@ function concrete_result_item(result::ConcreteResult, @nospecialize(info::CallIn invokesig::Union{Nothing,Vector{Any}}=nothing) if !may_inline_concrete_result(result) et = InliningEdgeTracker(state, invokesig) - return compileable_specialization(result.edge, result.effects, et, info, state) + return compileable_specialization(result.edge.def, result.effects, et, info, state) end @assert result.effects === EFFECTS_TOTAL return ConstantCase(quoted(result.result), result.edge) @@ -1557,7 +1555,9 @@ function handle_modifyop!_call!(ir::IRCode, idx::Int, stmt::Expr, info::ModifyOp match.fully_covers || return nothing edge = info.edges[1] if edge === nothing - edge = codeinst_as_invoke_edge(state.interp, specialize_method(match)) + edge = specialize_method(match) + else + edge = edge.def end case = compileable_specialization(edge, Effects(), InliningEdgeTracker(state), info, state) case === nothing && return nothing diff --git a/base/compiler/stmtinfo.jl b/base/compiler/stmtinfo.jl index 7268fe3e98d74..8a9f9dcd7d099 100644 --- a/base/compiler/stmtinfo.jl +++ b/base/compiler/stmtinfo.jl @@ -296,18 +296,44 @@ struct InvokeCallInfo <: CallInfo end function add_edges_impl(edges::Vector{Any}, info::InvokeCallInfo) edge = info.edge - if edge !== nothing + if edge === nothing + mi = specialize_method(info.match) + add_invoke_edge!(edges, info.atype, mi) + else add_invoke_edge!(edges, info.atype, edge) end nothing end +function add_invoke_edge!(edges::Vector{Any}, @nospecialize(atype), edge::MethodInstance) + for i in 2:length(edges) + edgeᵢ = edges[i] + edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def) + edgeᵢ isa MethodInstance || continue + if edgeᵢ === edge + edge_minus_1 = edges[i-1] + if edge_minus_1 isa Type && edge_minus_1 == atype + return # found existing covered edge + end + end + end + push!(edges, atype, edge) + nothing +end function add_invoke_edge!(edges::Vector{Any}, @nospecialize(atype), edge::CodeInstance) for i in 2:length(edges) edgeᵢ = edges[i] - if edgeᵢ isa CodeInstance && edgeᵢ.def === edge.def # XXX compare `CodeInstance` identify? + edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def) + edgeᵢ isa MethodInstance || continue + if edgeᵢ === edge.def edge_minus_1 = edges[i-1] if edge_minus_1 isa Type && edge_minus_1 == atype - return nothing + if edges[i] isa MethodInstance + # found edge we can upgrade + edges[i] = edge + return + elseif true # XXX compare `CodeInstance` identify? + return + end end end end diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 8b852617a312c..80e252dde3a02 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -3010,10 +3010,6 @@ function abstract_applicable(interp::AbstractInterpreter, argtypes::Vector{Any}, rt = Const(true) # has applicable matches end if rt !== Bool - for i = 1:napplicable - (; match, edges, edge_idx) = applicable[i] - edges[edge_idx] = codeinst_as_invoke_edge(interp, specialize_method(match)) - end info = VirtualMethodMatchInfo(matches.info) end end @@ -3055,8 +3051,7 @@ function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv vinfo = MethodMatchInfo(vresults, mt, types, false) # XXX: this should actually be an info with invoke-type edge else rt = Const(true) - edge = codeinst_as_invoke_edge(interp, specialize_method(match)) - vinfo = InvokeCallInfo(edge, match, nothing, types) + vinfo = InvokeCallInfo(nothing, match, nothing, types) end info = VirtualMethodMatchInfo(vinfo) return CallMeta(rt, Union{}, EFFECTS_TOTAL, info) diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 2e869ebabac6f..b3e2088fcd82d 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -739,12 +739,8 @@ function codeinst_as_edge(edge::MethodInstance, edges::SimpleVector, @nospeciali return CodeInstance(edge, owner, Any, Any, nothing, nothing, zero(Int32), min_world, max_world, zero(UInt32), nothing, zero(UInt8), nothing, edges) end -codeinst_as_edge(interp::AbstractInterpreter, edge::MethodInstance, edges::SimpleVector) = - codeinst_as_edge(edge, edges, cache_owner(interp), get_inference_world(interp), get_inference_world(interp)) -codeinst_as_invoke_edge(edge::MethodInstance, @nospecialize(owner), min_world::UInt, max_world::UInt) = - codeinst_as_edge(edge, empty_edges, owner, min_world, max_world) -codeinst_as_invoke_edge(interp::AbstractInterpreter, edge::MethodInstance) = - codeinst_as_edge(interp, edge, empty_edges) +codeinst_as_edge(interp::AbstractInterpreter, sv::InferenceState) = + codeinst_as_edge(sv.linfo, Core.svec(sv.edges...), cache_owner(interp), first(sv.valid_worlds), last(sv.valid_worlds)) # compute (and cache) an inferred AST and return the current best estimate of the result type function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize(atype), sparams::SimpleVector, caller::AbsIntState, edgecycle::Bool, edgelimited::Bool) diff --git a/test/compiler/contextual.jl b/test/compiler/contextual.jl index c66384237f423..8d526fdefdc5b 100644 --- a/test/compiler/contextual.jl +++ b/test/compiler/contextual.jl @@ -89,8 +89,7 @@ module MiniCassette @assert isa(src, CodeInfo) src = copy(src) @assert src.edges === Core.svec() - self_edge = Core.Compiler.codeinst_as_invoke_edge(mi, #=owner=#nothing, world, world) - src.edges = CodeInstance[self_edge] + src.edges = Any[mi] transform!(mi, src, length(args), match.sparams) # TODO: this is mandatory: code_info.min_world = max(code_info.min_world, min_world[]) # TODO: this is mandatory: code_info.max_world = min(code_info.max_world, max_world[])