Skip to content

Commit 91be20b

Browse files
committed
add edges metadata field to CodeInfo/CodeInstance, prepare for using
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).
1 parent a7fa1e7 commit 91be20b

17 files changed

+217
-116
lines changed

base/boot.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -510,11 +510,11 @@ function CodeInstance(
510510
mi::MethodInstance, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
511511
@nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt,
512512
effects::UInt32, @nospecialize(analysis_results),
513-
relocatability::UInt8, edges::Union{DebugInfo,Nothing})
513+
relocatability::UInt8, di::Union{DebugInfo,Nothing}, edges::SimpleVector)
514514
return ccall(:jl_new_codeinst, Ref{CodeInstance},
515-
(Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any),
515+
(Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
516516
mi, owner, rettype, exctype, inferred_const, inferred, const_flags, min_world, max_world,
517-
effects, analysis_results, relocatability, edges)
517+
effects, analysis_results, relocatability, di, edges)
518518
end
519519
GlobalRef(m::Module, s::Symbol) = ccall(:jl_module_globalref, Ref{GlobalRef}, (Any, Any), m, s)
520520
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)

base/compiler/typeinfer.jl

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,16 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
224224
if isdefined(result, :ci)
225225
ci = result.ci
226226
inferred_result = nothing
227+
edges = Core.svec() # This should be a computed input, for now it is approximated (badly) here
227228
relocatability = 0x1
228229
const_flag = is_result_constabi_eligible(result)
229230
if !can_discard_trees || (is_cached(caller) && !const_flag)
230231
inferred_result = transform_result_for_cache(interp, result.linfo, result.valid_worlds, result, can_discard_trees)
231232
relocatability = 0x0
232233
if inferred_result isa CodeInfo
233-
edges = inferred_result.debuginfo
234+
edges = ccall(:jl_ir_edges_legacy, Any, (Any,), inferred_result.code)
235+
inferred_result.edges = edges
236+
di = inferred_result.debuginfo
234237
uncompressed = inferred_result
235238
inferred_result = maybe_compress_codeinfo(interp, result.linfo, inferred_result, can_discard_trees)
236239
result.is_src_volatile |= uncompressed !== inferred_result
@@ -245,14 +248,14 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState;
245248
end
246249
end
247250
# n.b. relocatability = isa(inferred_result, String) && inferred_result[end]
248-
if !@isdefined edges
249-
edges = DebugInfo(result.linfo)
251+
if !@isdefined di
252+
di = DebugInfo(result.linfo)
250253
end
251-
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any),
254+
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
252255
ci, inferred_result, const_flag,
253256
first(result.valid_worlds), last(result.valid_worlds),
254257
encode_effects(result.ipo_effects), result.analysis_results,
255-
relocatability, edges)
258+
relocatability, di, edges)
256259
engine_reject(interp, ci)
257260
end
258261
return nothing
@@ -334,7 +337,6 @@ function is_result_constabi_eligible(result::InferenceResult)
334337
return isa(result_type, Const) && is_foldable_nothrow(result.ipo_effects) && is_inlineable_constant(result_type.val)
335338
end
336339

337-
338340
function transform_result_for_cache(interp::AbstractInterpreter,
339341
::MethodInstance, valid_worlds::WorldRange, result::InferenceResult,
340342
can_discard_trees::Bool=may_discard_trees(interp))
@@ -528,7 +530,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
528530
append!(s_edges, edges)
529531
empty!(edges)
530532
end
531-
if me.src.edges !== nothing
533+
if me.src.edges !== nothing && me.src.edges !== Core.svec()
532534
append!(s_edges, me.src.edges::Vector)
533535
end
534536
# inspect whether our inference had a limited result accuracy,
@@ -613,11 +615,12 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
613615
const_flags = 0x00
614616
end
615617
relocatability = 0x0
616-
edges = nothing
617-
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any),
618+
di = nothing
619+
edges = Core.svec()
620+
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any),
618621
result.ci, widenconst(result_type), widenconst(result.exc_result), rettype_const, const_flags,
619622
first(result.valid_worlds), last(result.valid_worlds),
620-
encode_effects(result.ipo_effects), result.analysis_results, edges)
623+
encode_effects(result.ipo_effects), result.analysis_results, di, edges)
621624
if is_cached(me)
622625
cached_results = cache_result!(me.interp, me.result)
623626
if !cached_results
@@ -991,6 +994,7 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no
991994
tree.debuginfo = DebugInfo(mi)
992995
tree.ssaflags = UInt32[0]
993996
tree.rettype = Core.Typeof(val)
997+
tree.edges = Core.svec()
994998
set_inlineable!(tree, true)
995999
tree.parent = mi
9961000
return tree
@@ -1008,7 +1012,7 @@ function codeinstance_for_const_with_code(interp::AbstractInterpreter, code::Cod
10081012
return CodeInstance(code.def, cache_owner(interp), code.rettype, code.exctype, code.rettype_const, src,
10091013
Int32(0x3), code.min_world, code.max_world,
10101014
code.ipo_purity_bits, code.analysis_results,
1011-
code.relocatability, src.debuginfo)
1015+
code.relocatability, src.debuginfo, src.edges)
10121016
end
10131017

10141018
result_is_constabi(interp::AbstractInterpreter, result::InferenceResult,
@@ -1170,7 +1174,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod
11701174
src isa CodeInfo || return nothing
11711175
return CodeInstance(mi, cache_owner(interp), Any, Any, nothing, src, Int32(0),
11721176
get_inference_world(interp), get_inference_world(interp),
1173-
UInt32(0), nothing, UInt8(0), src.debuginfo)
1177+
UInt32(0), nothing, UInt8(0), src.debuginfo, src.edges)
11741178
end
11751179
end
11761180
ci = engine_reserve(interp, mi)

base/expr.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function copy(c::CodeInfo)
7979
cnew.slottypes = copy(cnew.slottypes::Vector{Any})
8080
end
8181
cnew.ssaflags = copy(cnew.ssaflags)
82-
cnew.edges = cnew.edges === nothing ? nothing : copy(cnew.edges::Vector)
82+
cnew.edges = cnew.edges === nothing || cnew.edges isa Core.SimpleVector ? cnew.edges : copy(cnew.edges::Vector)
8383
ssavaluetypes = cnew.ssavaluetypes
8484
ssavaluetypes isa Vector{Any} && (cnew.ssavaluetypes = copy(ssavaluetypes))
8585
return cnew

src/common_symbols1.inc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,3 @@ jl_symbol("ifelse"),
8888
jl_symbol("Array"),
8989
jl_symbol("eq_int"),
9090
jl_symbol("throw_inexacterror"),
91-
jl_symbol("|"),
92-
jl_symbol("setproperty!"),

src/common_symbols2.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
jl_symbol("|"),
2+
jl_symbol("setproperty!"),
13
jl_symbol("sext_int"),
24
jl_symbol("String"),
35
jl_symbol("Int"),
@@ -244,5 +246,3 @@ jl_symbol("invokelatest"),
244246
jl_symbol("jl_array_del_end"),
245247
jl_symbol("_mod64"),
246248
jl_symbol("parameters"),
247-
jl_symbol("monotonic"),
248-
jl_symbol("regex.jl"),

src/gf.c

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a
322322

323323
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
324324
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, jl_nothing, jl_nothing,
325-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
325+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
326326
jl_mi_cache_insert(mi, codeinst);
327327
jl_atomic_store_relaxed(&codeinst->specptr.fptr1, fptr);
328328
jl_atomic_store_relaxed(&codeinst->invoke, jl_fptr_args);
@@ -480,7 +480,7 @@ JL_DLLEXPORT jl_value_t *jl_call_in_typeinf_world(jl_value_t **args, int nargs)
480480

481481
JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred(
482482
jl_method_instance_t *mi JL_PROPAGATES_ROOT, jl_value_t *rettype,
483-
size_t min_world, size_t max_world, jl_debuginfo_t *edges)
483+
size_t min_world, size_t max_world, jl_debuginfo_t *di, jl_svec_t *edges)
484484
{
485485
jl_value_t *owner = jl_nothing; // TODO: owner should be arg
486486
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
@@ -489,27 +489,30 @@ JL_DLLEXPORT jl_code_instance_t *jl_get_method_inferred(
489489
jl_atomic_load_relaxed(&codeinst->max_world) == max_world &&
490490
jl_egal(codeinst->owner, owner) &&
491491
jl_egal(codeinst->rettype, rettype)) {
492-
if (edges == NULL)
492+
if (di == NULL)
493493
return codeinst;
494494
jl_debuginfo_t *debuginfo = jl_atomic_load_relaxed(&codeinst->debuginfo);
495-
if (edges == debuginfo)
496-
return codeinst;
497-
if (debuginfo == NULL && jl_atomic_cmpswap_relaxed(&codeinst->debuginfo, &debuginfo, edges))
498-
return codeinst;
499-
if (debuginfo && jl_egal((jl_value_t*)debuginfo, (jl_value_t*)edges))
495+
if (di != debuginfo) {
496+
if (!(debuginfo == NULL && jl_atomic_cmpswap_relaxed(&codeinst->debuginfo, &debuginfo, di)))
497+
if (!(debuginfo && jl_egal((jl_value_t*)debuginfo, (jl_value_t*)di)))
498+
continue;
499+
}
500+
// TODO: this is implied by the matching worlds, since it is intrinsic, so do we really need to verify it?
501+
jl_svec_t *e = jl_atomic_load_relaxed(&codeinst->edges);
502+
if (e && jl_egal((jl_value_t*)e, (jl_value_t*)edges))
500503
return codeinst;
501504
}
502505
codeinst = jl_atomic_load_relaxed(&codeinst->next);
503506
}
504507
codeinst = jl_new_codeinst(
505508
mi, owner, rettype, (jl_value_t*)jl_any_type, NULL, NULL,
506-
0, min_world, max_world, 0, jl_nothing, 0, edges);
509+
0, min_world, max_world, 0, jl_nothing, 0, di, edges);
507510
jl_mi_cache_insert(mi, codeinst);
508511
return codeinst;
509512
}
510513

511514
JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi,
512-
jl_code_instance_t *ci)
515+
jl_code_instance_t *ci)
513516
{
514517
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
515518
while (codeinst) {
@@ -527,14 +530,15 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
527530
int32_t const_flags, size_t min_world, size_t max_world,
528531
uint32_t effects, jl_value_t *analysis_results,
529532
uint8_t relocatability,
530-
jl_debuginfo_t *edges /* , int absolute_max*/)
533+
jl_debuginfo_t *di, jl_svec_t *edges /*, int absolute_max*/)
531534
{
532535
jl_task_t *ct = jl_current_task;
533536
assert(min_world <= max_world && "attempting to set invalid world constraints");
534537
jl_code_instance_t *codeinst = (jl_code_instance_t*)jl_gc_alloc(ct->ptls, sizeof(jl_code_instance_t),
535538
jl_code_instance_type);
536539
codeinst->def = mi;
537540
codeinst->owner = owner;
541+
jl_atomic_store_relaxed(&codeinst->edges, edges);
538542
jl_atomic_store_relaxed(&codeinst->min_world, min_world);
539543
jl_atomic_store_relaxed(&codeinst->max_world, max_world);
540544
codeinst->rettype = rettype;
@@ -543,7 +547,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
543547
if ((const_flags & 2) == 0)
544548
inferred_const = NULL;
545549
codeinst->rettype_const = inferred_const;
546-
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)edges == jl_nothing ? NULL : edges);
550+
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)di == jl_nothing ? NULL : di);
547551
jl_atomic_store_relaxed(&codeinst->specptr.fptr, NULL);
548552
jl_atomic_store_relaxed(&codeinst->invoke, NULL);
549553
if ((const_flags & 1) != 0) {
@@ -563,13 +567,15 @@ JL_DLLEXPORT void jl_update_codeinst(
563567
jl_code_instance_t *codeinst, jl_value_t *inferred,
564568
int32_t const_flags, size_t min_world, size_t max_world,
565569
uint32_t effects, jl_value_t *analysis_results,
566-
uint8_t relocatability, jl_debuginfo_t *edges /* , int absolute_max*/)
570+
uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/)
567571
{
568572
codeinst->relocatability = relocatability;
569573
codeinst->analysis_results = analysis_results;
570574
jl_gc_wb(codeinst, analysis_results);
571575
jl_atomic_store_relaxed(&codeinst->ipo_purity_bits, effects);
572-
jl_atomic_store_relaxed(&codeinst->debuginfo, edges);
576+
jl_atomic_store_relaxed(&codeinst->debuginfo, di);
577+
jl_gc_wb(codeinst, di);
578+
jl_atomic_store_relaxed(&codeinst->edges, edges);
573579
jl_gc_wb(codeinst, edges);
574580
if ((const_flags & 1) != 0) {
575581
assert(codeinst->rettype_const);
@@ -587,7 +593,7 @@ JL_DLLEXPORT void jl_fill_codeinst(
587593
jl_value_t *inferred_const,
588594
int32_t const_flags, size_t min_world, size_t max_world,
589595
uint32_t effects, jl_value_t *analysis_results,
590-
jl_debuginfo_t *edges /* , int absolute_max*/)
596+
jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/)
591597
{
592598
assert(min_world <= max_world && "attempting to set invalid world constraints");
593599
codeinst->rettype = rettype;
@@ -598,8 +604,12 @@ JL_DLLEXPORT void jl_fill_codeinst(
598604
codeinst->rettype_const = inferred_const;
599605
jl_gc_wb(codeinst, inferred_const);
600606
}
601-
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)edges == jl_nothing ? NULL : edges);
607+
jl_atomic_store_relaxed(&codeinst->edges, edges);
602608
jl_gc_wb(codeinst, edges);
609+
if ((jl_value_t*)di != jl_nothing) {
610+
jl_atomic_store_relaxed(&codeinst->debuginfo, di);
611+
jl_gc_wb(codeinst, di);
612+
}
603613
if ((const_flags & 1) != 0) {
604614
// TODO: may want to follow ordering restrictions here (see jitlayers.cpp)
605615
assert(const_flags & 2);
@@ -615,7 +625,7 @@ JL_DLLEXPORT void jl_fill_codeinst(
615625

616626
JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner)
617627
{
618-
jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL);
628+
jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL);
619629
jl_atomic_store_relaxed(&codeinst->min_world, 1); // make temporarily invalid before returning, so that jl_fill_codeinst is valid later
620630
return codeinst;
621631
}
@@ -2563,8 +2573,10 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
25632573
jl_code_instance_t *codeinst2 = jl_compile_method_internal(mi2, world);
25642574
jl_code_instance_t *codeinst = jl_get_method_inferred(
25652575
mi, codeinst2->rettype,
2566-
jl_atomic_load_relaxed(&codeinst2->min_world), jl_atomic_load_relaxed(&codeinst2->max_world),
2567-
jl_atomic_load_relaxed(&codeinst2->debuginfo));
2576+
jl_atomic_load_relaxed(&codeinst2->min_world),
2577+
jl_atomic_load_relaxed(&codeinst2->max_world),
2578+
jl_atomic_load_relaxed(&codeinst2->debuginfo),
2579+
jl_atomic_load_relaxed(&codeinst2->edges));
25682580
if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) {
25692581
codeinst->rettype_const = codeinst2->rettype_const;
25702582
jl_gc_wb(codeinst, codeinst->rettype_const);
@@ -2623,7 +2635,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
26232635
if (unspec && (unspec_invoke = jl_atomic_load_acquire(&unspec->invoke))) {
26242636
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
26252637
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
2626-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
2638+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
26272639
void *unspec_fptr = jl_atomic_load_relaxed(&unspec->specptr.fptr);
26282640
if (unspec_fptr) {
26292641
// wait until invoke and specsigflags are properly set
@@ -2650,7 +2662,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
26502662
if (!jl_code_requires_compiler(src, 0)) {
26512663
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
26522664
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
2653-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
2665+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
26542666
jl_atomic_store_release(&codeinst->invoke, jl_fptr_interpret_call);
26552667
jl_mi_cache_insert(mi, codeinst);
26562668
record_precompile_statement(mi, 0);
@@ -2710,7 +2722,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
27102722
jl_method_instance_t *unspec = jl_get_unspecialized(def);
27112723
if (unspec == NULL)
27122724
unspec = mi;
2713-
jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0, NULL);
2725+
jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0, NULL, NULL);
27142726
// ask codegen to make the fptr for unspec
27152727
jl_callptr_t ucache_invoke = jl_atomic_load_acquire(&ucache->invoke);
27162728
if (ucache_invoke == NULL) {
@@ -2730,7 +2742,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
27302742
}
27312743
codeinst = jl_new_codeinst(mi, jl_nothing,
27322744
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
2733-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
2745+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
27342746
void *unspec_fptr = jl_atomic_load_relaxed(&ucache->specptr.fptr);
27352747
if (unspec_fptr) {
27362748
// wait until invoke and specsigflags are properly set

0 commit comments

Comments
 (0)