Skip to content

Commit

Permalink
add edges metadata field to CodeInfo/CodeInstance, prepare for using
Browse files Browse the repository at this point in the history
This records all invoke targets as edges as a functionality test, before
finishing the implementation of recording the edges accurately during
inference (via backedges + inference).
  • Loading branch information
vtjnash committed Jun 24, 2024
1 parent a7fa1e7 commit af03fd5
Show file tree
Hide file tree
Showing 17 changed files with 217 additions and 116 deletions.
6 changes: 3 additions & 3 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -510,11 +510,11 @@ function CodeInstance(
mi::MethodInstance, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
@nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt,
effects::UInt32, @nospecialize(analysis_results),
relocatability::UInt8, edges::Union{DebugInfo,Nothing})
relocatability::UInt8, di::Union{DebugInfo,Nothing}, edges::SimpleVector)
return ccall(:jl_new_codeinst, Ref{CodeInstance},
(Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any),
(Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
mi, owner, rettype, exctype, inferred_const, inferred, const_flags, min_world, max_world,
effects, analysis_results, relocatability, edges)
effects, analysis_results, relocatability, di, edges)
end
GlobalRef(m::Module, s::Symbol) = ccall(:jl_module_globalref, Ref{GlobalRef}, (Any, Any), m, s)
Module(name::Symbol=:anonymous, std_imports::Bool=true, default_names::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool, Bool), name, std_imports, default_names)
Expand Down
28 changes: 16 additions & 12 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,16 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
if isdefined(result, :ci)
ci = result.ci
inferred_result = nothing
edges = Core.svec() # This should be a computed input, for now it is approximated (badly) here
relocatability = 0x1
const_flag = is_result_constabi_eligible(result)
if !can_discard_trees || (is_cached(caller) && !const_flag)
inferred_result = transform_result_for_cache(interp, result.linfo, result.valid_worlds, result, can_discard_trees)
relocatability = 0x0
if inferred_result isa CodeInfo
edges = inferred_result.debuginfo
edges = ccall(:jl_ir_edges_legacy, Any, (Any,), inferred_result.code)
inferred_result.edges = edges
di = inferred_result.debuginfo
uncompressed = inferred_result
inferred_result = maybe_compress_codeinfo(interp, result.linfo, inferred_result, can_discard_trees)
result.is_src_volatile |= uncompressed !== inferred_result
Expand All @@ -245,14 +248,14 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
end
end
# n.b. relocatability = isa(inferred_result, String) && inferred_result[end]
if !@isdefined edges
edges = DebugInfo(result.linfo)
if !@isdefined di
di = DebugInfo(result.linfo)
end
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any),
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
ci, inferred_result, const_flag,
first(result.valid_worlds), last(result.valid_worlds),
encode_effects(result.ipo_effects), result.analysis_results,
relocatability, edges)
relocatability, di, edges)
engine_reject(interp, ci)
end
return nothing
Expand Down Expand Up @@ -334,7 +337,6 @@ function is_result_constabi_eligible(result::InferenceResult)
return isa(result_type, Const) && is_foldable_nothrow(result.ipo_effects) && is_inlineable_constant(result_type.val)
end


function transform_result_for_cache(interp::AbstractInterpreter,
::MethodInstance, valid_worlds::WorldRange, result::InferenceResult,
can_discard_trees::Bool=may_discard_trees(interp))
Expand Down Expand Up @@ -528,7 +530,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
append!(s_edges, edges)
empty!(edges)
end
if me.src.edges !== nothing
if me.src.edges !== nothing && me.src.edges !== Core.svec()
append!(s_edges, me.src.edges::Vector)
end
# inspect whether our inference had a limited result accuracy,
Expand Down Expand Up @@ -613,11 +615,12 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
const_flags = 0x00
end
relocatability = 0x0
edges = nothing
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any),
di = nothing
edges = Core.svec()
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any),
result.ci, widenconst(result_type), widenconst(result.exc_result), rettype_const, const_flags,
first(result.valid_worlds), last(result.valid_worlds),
encode_effects(result.ipo_effects), result.analysis_results, edges)
encode_effects(result.ipo_effects), result.analysis_results, di, edges)
if is_cached(me)
cached_results = cache_result!(me.interp, me.result)
if !cached_results
Expand Down Expand Up @@ -991,6 +994,7 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no
tree.debuginfo = DebugInfo(mi)
tree.ssaflags = UInt32[0]
tree.rettype = Core.Typeof(val)
tree.edges = Core.svec()
set_inlineable!(tree, true)
tree.parent = mi
return tree
Expand All @@ -1008,7 +1012,7 @@ function codeinstance_for_const_with_code(interp::AbstractInterpreter, code::Cod
return CodeInstance(code.def, cache_owner(interp), code.rettype, code.exctype, code.rettype_const, src,
Int32(0x3), code.min_world, code.max_world,
code.ipo_purity_bits, code.analysis_results,
code.relocatability, src.debuginfo)
code.relocatability, src.debuginfo, src.edges)
end

result_is_constabi(interp::AbstractInterpreter, result::InferenceResult,
Expand Down Expand Up @@ -1170,7 +1174,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod
src isa CodeInfo || return nothing
return CodeInstance(mi, cache_owner(interp), Any, Any, nothing, src, Int32(0),
get_inference_world(interp), get_inference_world(interp),
UInt32(0), nothing, UInt8(0), src.debuginfo)
UInt32(0), nothing, UInt8(0), src.debuginfo, src.edges)
end
end
ci = engine_reserve(interp, mi)
Expand Down
2 changes: 1 addition & 1 deletion base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function copy(c::CodeInfo)
cnew.slottypes = copy(cnew.slottypes::Vector{Any})
end
cnew.ssaflags = copy(cnew.ssaflags)
cnew.edges = cnew.edges === nothing ? nothing : copy(cnew.edges::Vector)
cnew.edges = cnew.edges === nothing || cnew.edges isa Core.SimpleVector ? cnew.edges : copy(cnew.edges::Vector)
ssavaluetypes = cnew.ssavaluetypes
ssavaluetypes isa Vector{Any} && (cnew.ssavaluetypes = copy(ssavaluetypes))
return cnew
Expand Down
2 changes: 0 additions & 2 deletions src/common_symbols1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,3 @@ jl_symbol("ifelse"),
jl_symbol("Array"),
jl_symbol("eq_int"),
jl_symbol("throw_inexacterror"),
jl_symbol("|"),
jl_symbol("setproperty!"),
4 changes: 2 additions & 2 deletions src/common_symbols2.inc
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
jl_symbol("|"),
jl_symbol("setproperty!"),
jl_symbol("sext_int"),
jl_symbol("String"),
jl_symbol("Int"),
Expand Down Expand Up @@ -244,5 +246,3 @@ jl_symbol("invokelatest"),
jl_symbol("jl_array_del_end"),
jl_symbol("_mod64"),
jl_symbol("parameters"),
jl_symbol("monotonic"),
jl_symbol("regex.jl"),
58 changes: 35 additions & 23 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a

jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, jl_nothing, jl_nothing,
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
jl_mi_cache_insert(mi, codeinst);
jl_atomic_store_relaxed(&codeinst->specptr.fptr1, fptr);
jl_atomic_store_relaxed(&codeinst->invoke, jl_fptr_args);
Expand Down Expand Up @@ -480,7 +480,7 @@ JL_DLLEXPORT jl_value_t *jl_call_in_typeinf_world(jl_value_t **args, int nargs)

JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred(
jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_value_t *rettype,
size_t min_world, size_t max_world, jl_debuginfo_t *edges)
size_t min_world, size_t max_world, jl_debuginfo_t *di, jl_svec_t *edges)
{
jl_value_t *owner = jl_nothing; // TODO: owner should be arg
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
Expand All @@ -489,27 +489,30 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred(
jl_atomic_load_relaxed(&codeinst->max_world) == max_world &&
jl_egal(codeinst->owner, owner) &&
jl_egal(codeinst->rettype, rettype)) {
if (edges == NULL)
if (di == NULL)
return codeinst;
jl_debuginfo_t *debuginfo = jl_atomic_load_relaxed(&codeinst->debuginfo);
if (edges == debuginfo)
return codeinst;
if (debuginfo == NULL && jl_atomic_cmpswap_relaxed(&codeinst->debuginfo, &debuginfo, edges))
return codeinst;
if (debuginfo && jl_egal((jl_value_t*)debuginfo, (jl_value_t*)edges))
if (di != debuginfo) {
if (!(debuginfo == NULL && jl_atomic_cmpswap_relaxed(&codeinst->debuginfo, &debuginfo, di)))
if (!(debuginfo && jl_egal((jl_value_t*)debuginfo, (jl_value_t*)di)))
continue;
}
// TODO: this is implied by the matching worlds, since it is intrinsic, so do we really need to verify it?
jl_svec_t *e = jl_atomic_load_relaxed(&codeinst->edges);
if (e && jl_egal((jl_value_t*)e, (jl_value_t*)edges))
return codeinst;
}
codeinst = jl_atomic_load_relaxed(&codeinst->next);
}
codeinst = jl_new_codeinst(
mi, owner, rettype, (jl_value_t*)jl_any_type, NULL, NULL,
0, min_world, max_world, 0, jl_nothing, 0, edges);
0, min_world, max_world, 0, jl_nothing, 0, di, edges);
jl_mi_cache_insert(mi, codeinst);
return codeinst;
}

JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi,
jl_code_instance_t *ci)
jl_code_instance_t *ci)
{
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
while (codeinst) {
Expand All @@ -527,14 +530,15 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
int32_t const_flags, size_t min_world, size_t max_world,
uint32_t effects, jl_value_t *analysis_results,
uint8_t relocatability,
jl_debuginfo_t *edges /* , int absolute_max*/)
jl_debuginfo_t *di, jl_svec_t *edges /*, int absolute_max*/)
{
jl_task_t *ct = jl_current_task;
assert(min_world <= max_world && "attempting to set invalid world constraints");
jl_code_instance_t *codeinst = (jl_code_instance_t*)jl_gc_alloc(ct->ptls, sizeof(jl_code_instance_t),
jl_code_instance_type);
codeinst->def = mi;
codeinst->owner = owner;
jl_atomic_store_relaxed(&codeinst->edges, edges);
jl_atomic_store_relaxed(&codeinst->min_world, min_world);
jl_atomic_store_relaxed(&codeinst->max_world, max_world);
codeinst->rettype = rettype;
Expand All @@ -543,7 +547,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
if ((const_flags & 2) == 0)
inferred_const = NULL;
codeinst->rettype_const = inferred_const;
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)edges == jl_nothing ? NULL : edges);
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)di == jl_nothing ? NULL : di);
jl_atomic_store_relaxed(&codeinst->specptr.fptr, NULL);
jl_atomic_store_relaxed(&codeinst->invoke, NULL);
if ((const_flags & 1) != 0) {
Expand All @@ -563,13 +567,15 @@ JL_DLLEXPORT void jl_update_codeinst(
jl_code_instance_t *codeinst, jl_value_t *inferred,
int32_t const_flags, size_t min_world, size_t max_world,
uint32_t effects, jl_value_t *analysis_results,
uint8_t relocatability, jl_debuginfo_t *edges /* , int absolute_max*/)
uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/)
{
codeinst->relocatability = relocatability;
codeinst->analysis_results = analysis_results;
jl_gc_wb(codeinst, analysis_results);
jl_atomic_store_relaxed(&codeinst->ipo_purity_bits, effects);
jl_atomic_store_relaxed(&codeinst->debuginfo, edges);
jl_atomic_store_relaxed(&codeinst->debuginfo, di);
jl_gc_wb(codeinst, di);
jl_atomic_store_relaxed(&codeinst->edges, edges);
jl_gc_wb(codeinst, edges);
if ((const_flags & 1) != 0) {
assert(codeinst->rettype_const);
Expand All @@ -587,7 +593,7 @@ JL_DLLEXPORT void jl_fill_codeinst(
jl_value_t *inferred_const,
int32_t const_flags, size_t min_world, size_t max_world,
uint32_t effects, jl_value_t *analysis_results,
jl_debuginfo_t *edges /* , int absolute_max*/)
jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/)
{
assert(min_world <= max_world && "attempting to set invalid world constraints");
codeinst->rettype = rettype;
Expand All @@ -598,8 +604,12 @@ JL_DLLEXPORT void jl_fill_codeinst(
codeinst->rettype_const = inferred_const;
jl_gc_wb(codeinst, inferred_const);
}
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)edges == jl_nothing ? NULL : edges);
jl_atomic_store_relaxed(&codeinst->edges, edges);
jl_gc_wb(codeinst, edges);
if ((jl_value_t*)di != jl_nothing) {
jl_atomic_store_relaxed(&codeinst->debuginfo, di);
jl_gc_wb(codeinst, di);
}
if ((const_flags & 1) != 0) {
// TODO: may want to follow ordering restrictions here (see jitlayers.cpp)
assert(const_flags & 2);
Expand All @@ -615,7 +625,7 @@ JL_DLLEXPORT void jl_fill_codeinst(

JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner)
{
jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL);
jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL);
jl_atomic_store_relaxed(&codeinst->min_world, 1); // make temporarily invalid before returning, so that jl_fill_codeinst is valid later
return codeinst;
}
Expand Down Expand Up @@ -2563,8 +2573,10 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
jl_code_instance_t *codeinst2 = jl_compile_method_internal(mi2, world);
jl_code_instance_t *codeinst = jl_get_method_inferred(
mi, codeinst2->rettype,
jl_atomic_load_relaxed(&codeinst2->min_world), jl_atomic_load_relaxed(&codeinst2->max_world),
jl_atomic_load_relaxed(&codeinst2->debuginfo));
jl_atomic_load_relaxed(&codeinst2->min_world),
jl_atomic_load_relaxed(&codeinst2->max_world),
jl_atomic_load_relaxed(&codeinst2->debuginfo),
jl_atomic_load_relaxed(&codeinst2->edges));
if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) {
codeinst->rettype_const = codeinst2->rettype_const;
jl_gc_wb(codeinst, codeinst->rettype_const);
Expand Down Expand Up @@ -2623,7 +2635,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
if (unspec && (unspec_invoke = jl_atomic_load_acquire(&unspec->invoke))) {
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
void *unspec_fptr = jl_atomic_load_relaxed(&unspec->specptr.fptr);
if (unspec_fptr) {
// wait until invoke and specsigflags are properly set
Expand All @@ -2650,7 +2662,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
if (!jl_code_requires_compiler(src, 0)) {
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
jl_atomic_store_release(&codeinst->invoke, jl_fptr_interpret_call);
jl_mi_cache_insert(mi, codeinst);
record_precompile_statement(mi, 0);
Expand Down Expand Up @@ -2710,7 +2722,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
jl_method_instance_t *unspec = jl_get_unspecialized(def);
if (unspec == NULL)
unspec = mi;
jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0, NULL);
jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0, NULL, NULL);
// ask codegen to make the fptr for unspec
jl_callptr_t ucache_invoke = jl_atomic_load_acquire(&ucache->invoke);
if (ucache_invoke == NULL) {
Expand All @@ -2730,7 +2742,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
}
codeinst = jl_new_codeinst(mi, jl_nothing,
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
void *unspec_fptr = jl_atomic_load_relaxed(&ucache->specptr.fptr);
if (unspec_fptr) {
// wait until invoke and specsigflags are properly set
Expand Down
Loading

0 comments on commit af03fd5

Please sign in to comment.