Skip to content

Commit d9d1fc5

Browse files
authored
fix some new-edges issues (JuliaLang#56598)
- incorrect edge types were being added from inlining: there is minimal dispatch info available, so best not to add that (which was already added earlier) as it results in failures to validate later - MethodTable/sig order in edges could confuse the iterator: always put the type before the edge now as that is more consistent - edges wasn't converted to a SimpleVector, so they might get ignored later from being in the wrong format - edges were not populated for optimize=false, which made debugging them more inconvenient Fixes JuliaLang#56577
1 parent 0592b54 commit d9d1fc5

File tree

6 files changed

+143
-143
lines changed

6 files changed

+143
-143
lines changed

Compiler/src/optimize.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ include("ssair/irinterp.jl")
224224
function ir_to_codeinf!(opt::OptimizationState)
225225
(; linfo, src) = opt
226226
src = ir_to_codeinf!(src, opt.ir::IRCode)
227-
src.edges = opt.inlining.edges
227+
src.edges = Core.svec(opt.inlining.edges...)
228228
opt.ir = nothing
229229
maybe_validate_code(linfo, src, "optimized")
230230
return src

Compiler/src/ssair/inlining.jl

+13-28
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,11 @@ end
6464

6565
struct InliningEdgeTracker
6666
edges::Vector{Any}
67-
invokesig::Union{Nothing,Vector{Any}}
68-
InliningEdgeTracker(state::InliningState, invokesig::Union{Nothing,Vector{Any}}=nothing) =
69-
new(state.edges, invokesig)
67+
InliningEdgeTracker(state::InliningState) = new(state.edges)
7068
end
7169

72-
function add_inlining_edge!(et::InliningEdgeTracker, edge::Union{CodeInstance,MethodInstance})
73-
(; edges, invokesig) = et
74-
if invokesig === nothing
75-
add_one_edge!(edges, edge)
76-
else # invoke backedge
77-
add_invoke_edge!(edges, invoke_signature(invokesig), edge)
78-
end
79-
return nothing
80-
end
70+
add_inlining_edge!(et::InliningEdgeTracker, edge::CodeInstance) = add_inlining_edge!(et.edges, edge)
71+
add_inlining_edge!(et::InliningEdgeTracker, edge::MethodInstance) = add_inlining_edge!(et.edges, edge)
8172

8273
function ssa_inlining_pass!(ir::IRCode, state::InliningState, propagate_inbounds::Bool)
8374
# Go through the function, performing simple inlining (e.g. replacing call by constants
@@ -795,10 +786,7 @@ function compileable_specialization(mi::MethodInstance, effects::Effects,
795786
return nothing
796787
end
797788
end
798-
add_inlining_edge!(et, mi) # to the dispatch lookup
799-
if mi_invoke !== mi
800-
add_invoke_edge!(et.edges, method.sig, mi_invoke) # add_inlining_edge to the invoke call, if that is different
801-
end
789+
add_inlining_edge!(et, mi_invoke) # to the dispatch lookup
802790
return InvokeCase(mi_invoke, effects, info)
803791
end
804792

@@ -834,9 +822,8 @@ end
834822

835823
# the general resolver for usual and const-prop'ed calls
836824
function resolve_todo(mi::MethodInstance, result::Union{Nothing,InferenceResult,VolatileInferenceResult},
837-
@nospecialize(info::CallInfo), flag::UInt32, state::InliningState;
838-
invokesig::Union{Nothing,Vector{Any}}=nothing)
839-
et = InliningEdgeTracker(state, invokesig)
825+
@nospecialize(info::CallInfo), flag::UInt32, state::InliningState)
826+
et = InliningEdgeTracker(state)
840827

841828
preserve_local_sources = true
842829
if isa(result, InferenceResult)
@@ -922,7 +909,7 @@ end
922909

923910
function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
924911
@nospecialize(info::CallInfo), flag::UInt32, state::InliningState;
925-
allow_typevars::Bool, invokesig::Union{Nothing,Vector{Any}}=nothing,
912+
allow_typevars::Bool,
926913
volatile_inf_result::Union{Nothing,VolatileInferenceResult}=nothing)
927914
method = match.method
928915

@@ -953,7 +940,7 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
953940
# Get the specialization for this method signature
954941
# (later we will decide what to do with it)
955942
mi = specialize_method(match)
956-
return resolve_todo(mi, volatile_inf_result, info, flag, state; invokesig)
943+
return resolve_todo(mi, volatile_inf_result, info, flag, state)
957944
end
958945

959946
function retrieve_ir_for_inlining(cached_result::CodeInstance, src::String)
@@ -1164,9 +1151,8 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
11641151
return nothing
11651152
end
11661153
result = info.result
1167-
invokesig = sig.argtypes
11681154
if isa(result, ConcreteResult)
1169-
item = concrete_result_item(result, info, state; invokesig)
1155+
item = concrete_result_item(result, info, state)
11701156
elseif isa(result, SemiConcreteResult)
11711157
item = semiconcrete_result_item(result, info, flag, state)
11721158
else
@@ -1175,13 +1161,13 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
11751161
mi = result.result.linfo
11761162
validate_sparams(mi.sparam_vals) || return nothing
11771163
if Union{} !== argtypes_to_type(argtypes) <: mi.def.sig
1178-
item = resolve_todo(mi, result.result, info, flag, state; invokesig)
1164+
item = resolve_todo(mi, result.result, info, flag, state)
11791165
handle_single_case!(todo, ir, idx, stmt, item, true)
11801166
return nothing
11811167
end
11821168
end
11831169
volatile_inf_result = result isa VolatileInferenceResult ? result : nothing
1184-
item = analyze_method!(match, argtypes, info, flag, state; allow_typevars=false, invokesig, volatile_inf_result)
1170+
item = analyze_method!(match, argtypes, info, flag, state; allow_typevars=false, volatile_inf_result)
11851171
end
11861172
handle_single_case!(todo, ir, idx, stmt, item, true)
11871173
return nothing
@@ -1477,10 +1463,9 @@ end
14771463
may_inline_concrete_result(result::ConcreteResult) =
14781464
isdefined(result, :result) && is_inlineable_constant(result.result)
14791465

1480-
function concrete_result_item(result::ConcreteResult, @nospecialize(info::CallInfo), state::InliningState;
1481-
invokesig::Union{Nothing,Vector{Any}}=nothing)
1466+
function concrete_result_item(result::ConcreteResult, @nospecialize(info::CallInfo), state::InliningState)
14821467
if !may_inline_concrete_result(result)
1483-
et = InliningEdgeTracker(state, invokesig)
1468+
et = InliningEdgeTracker(state)
14841469
return compileable_specialization(result.edge.def, result.effects, et, info, state)
14851470
end
14861471
@assert result.effects === EFFECTS_TOTAL

Compiler/src/stmtinfo.jl

+68-9
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
4949
if !fully_covering(info)
5050
# add legacy-style missing backedge info also
5151
exists = false
52-
for i in 1:length(edges)
53-
if edges[i] === info.mt && edges[i+1] == info.atype
52+
for i in 2:length(edges)
53+
if edges[i] === info.mt && edges[i-1] == info.atype
5454
exists = true
5555
break
5656
end
5757
end
5858
if !exists
59-
push!(edges, info.mt, info.atype)
59+
push!(edges, info.atype)
60+
push!(edges, info.mt)
6061
end
6162
end
6263
nmatches = length(info.results)
@@ -98,22 +99,27 @@ function _add_edges_impl(edges::Vector{Any}, info::MethodMatchInfo, mi_edge::Boo
9899
nothing
99100
end
100101
function add_one_edge!(edges::Vector{Any}, edge::MethodInstance)
101-
for i in 1:length(edges)
102+
i = 1
103+
while i <= length(edges)
102104
edgeᵢ = edges[i]
105+
edgeᵢ isa Int && (i += 2 + edgeᵢ; continue)
103106
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
104-
edgeᵢ isa MethodInstance || continue
107+
edgeᵢ isa MethodInstance || (i += 1; continue)
105108
if edgeᵢ === edge && !(i > 1 && edges[i-1] isa Type)
106109
return # found existing covered edge
107110
end
111+
i += 1
108112
end
109113
push!(edges, edge)
110114
nothing
111115
end
112116
function add_one_edge!(edges::Vector{Any}, edge::CodeInstance)
113-
for i in 1:length(edges)
117+
i = 1
118+
while i <= length(edges)
114119
edgeᵢ_orig = edgeᵢ = edges[i]
120+
edgeᵢ isa Int && (i += 2 + edgeᵢ; continue)
115121
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
116-
edgeᵢ isa MethodInstance || continue
122+
edgeᵢ isa MethodInstance || (i += 1; continue)
117123
if edgeᵢ === edge.def && !(i > 1 && edges[i-1] isa Type)
118124
if edgeᵢ_orig isa MethodInstance
119125
# found edge we can upgrade
@@ -123,6 +129,7 @@ function add_one_edge!(edges::Vector{Any}, edge::CodeInstance)
123129
return
124130
end
125131
end
132+
i += 1
126133
end
127134
push!(edges, edge)
128135
nothing
@@ -296,7 +303,8 @@ function add_invoke_edge!(edges::Vector{Any}, @nospecialize(atype), edge::Union{
296303
end
297304
end
298305
end
299-
push!(edges, atype, edge)
306+
push!(edges, atype)
307+
push!(edges, edge)
300308
nothing
301309
end
302310
function add_invoke_edge!(edges::Vector{Any}, @nospecialize(atype), edge::CodeInstance)
@@ -317,10 +325,61 @@ function add_invoke_edge!(edges::Vector{Any}, @nospecialize(atype), edge::CodeIn
317325
end
318326
end
319327
end
320-
push!(edges, atype, edge)
328+
push!(edges, atype)
329+
push!(edges, edge)
321330
nothing
322331
end
323332

333+
function add_inlining_edge!(edges::Vector{Any}, edge::MethodInstance)
334+
# check if we already have an edge to this code
335+
i = 1
336+
while i <= length(edges)
337+
edgeᵢ = edges[i]
338+
if edgeᵢ isa Method && edgeᵢ === edge.def
339+
# found edge we can upgrade
340+
edges[i] = edge
341+
return
342+
end
343+
edgeᵢ isa CodeInstance && (edgeᵢ = edgeᵢ.def)
344+
if edgeᵢ isa MethodInstance && edgeᵢ === edge
345+
return # found existing covered edge
346+
end
347+
i += 1
348+
end
349+
# add_invoke_edge alone
350+
push!(edges, (edge.def::Method).sig)
351+
push!(edges, edge)
352+
nothing
353+
end
354+
function add_inlining_edge!(edges::Vector{Any}, edge::CodeInstance)
355+
# check if we already have an edge to this code
356+
i = 1
357+
while i <= length(edges)
358+
edgeᵢ = edges[i]
359+
if edgeᵢ isa Method && edgeᵢ === edge.def.def
360+
# found edge we can upgrade
361+
edges[i] = edge
362+
return
363+
end
364+
if edgeᵢ isa MethodInstance && edgeᵢ === edge.def
365+
# found edge we can upgrade
366+
edges[i] = edge
367+
return
368+
end
369+
if edgeᵢ isa CodeInstance && edgeᵢ.def === edge.def
370+
# found existing edge
371+
# XXX compare `CodeInstance` identify?
372+
return
373+
end
374+
i += 1
375+
end
376+
# add_invoke_edge alone
377+
push!(edges, (edge.def.def::Method).sig)
378+
push!(edges, edge)
379+
nothing
380+
end
381+
382+
324383
"""
325384
info::OpaqueClosureCallInfo
326385

Compiler/src/typeinfer.jl

+46-11
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,12 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
9797
result = caller.result
9898
opt = result.src
9999
if opt isa OptimizationState
100-
result.src = ir_to_codeinf!(opt)
100+
src = ir_to_codeinf!(opt)
101+
edges = src.edges::SimpleVector
102+
caller.src = result.src = src
103+
else
104+
edges = Core.svec(caller.edges...)
105+
caller.src.edges = edges
101106
end
102107
#@assert last(result.valid_worlds) <= get_world_counter() || isempty(caller.edges)
103108
if isdefined(result, :ci)
@@ -112,7 +117,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
112117
if last(result.valid_worlds) == typemax(UInt)
113118
# if we can record all of the backedges in the global reverse-cache,
114119
# we can now widen our applicability in the global cache too
115-
store_backedges(ci, caller.edges)
120+
store_backedges(ci, edges)
116121
end
117122
inferred_result = nothing
118123
relocatability = 0x1
@@ -142,7 +147,7 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
142147
end
143148
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
144149
ci, inferred_result, const_flag, first(result.valid_worlds), last(result.valid_worlds), encode_effects(result.ipo_effects),
145-
result.analysis_results, relocatability, di, Core.svec(caller.edges...))
150+
result.analysis_results, relocatability, di, edges)
146151
engine_reject(interp, ci)
147152
end
148153
return nothing
@@ -488,14 +493,43 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
488493
end
489494

490495
# record the backedges
491-
function store_backedges(caller::CodeInstance, edges::Vector{Any})
496+
function store_backedges(caller::CodeInstance, edges::SimpleVector)
492497
isa(caller.def.def, Method) || return # don't add backedges to toplevel method instance
493-
for itr in BackedgeIterator(edges)
494-
callee = itr.caller
495-
if isa(callee, MethodInstance)
496-
ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, itr.sig, caller)
498+
i = 1
499+
while true
500+
i > length(edges) && return nothing
501+
item = edges[i]
502+
if item isa Int
503+
i += 2
504+
continue # ignore the query information if present but process the contents
505+
elseif isa(item, Method)
506+
# ignore `Method`-edges (from e.g. failed `abstract_call_method`)
507+
i += 1
508+
continue
509+
end
510+
if isa(item, CodeInstance)
511+
item = item.def
512+
end
513+
if isa(item, MethodInstance) # regular dispatch
514+
ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), item, nothing, caller)
515+
i += 1
497516
else
498-
ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), callee, itr.sig, caller)
517+
callee = edges[i+1]
518+
if isa(callee, MethodTable) # abstract dispatch (legacy style edges)
519+
ccall(:jl_method_table_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller)
520+
i += 2
521+
continue
522+
end
523+
# `invoke` edge
524+
if isa(callee, Method)
525+
# ignore `Method`-edges (from e.g. failed `abstract_call_method`)
526+
i += 2
527+
continue
528+
elseif isa(callee, CodeInstance)
529+
callee = callee.def
530+
end
531+
ccall(:jl_method_instance_add_backedge, Cvoid, (Any, Any, Any), callee, item, caller)
532+
i += 2
499533
end
500534
end
501535
nothing
@@ -734,13 +768,14 @@ function codeinst_as_edge(interp::AbstractInterpreter, sv::InferenceState)
734768
if max_world >= get_world_counter()
735769
max_world = typemax(UInt)
736770
end
771+
edges = Core.svec(sv.edges...)
737772
ci = CodeInstance(mi, owner, Any, Any, nothing, nothing, zero(Int32),
738-
min_world, max_world, zero(UInt32), nothing, zero(UInt8), nothing, Core.svec(sv.edges...))
773+
min_world, max_world, zero(UInt32), nothing, zero(UInt8), nothing, edges)
739774
if max_world == typemax(UInt)
740775
# if we can record all of the backedges in the global reverse-cache,
741776
# we can now widen our applicability in the global cache too
742777
# TODO: this should probably come after we decide this edge is even useful
743-
store_backedges(ci, sv.edges)
778+
store_backedges(ci, edges)
744779
end
745780
return ci
746781
end

0 commit comments

Comments
 (0)