Skip to content

Commit ce5726f

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 24535f6 commit ce5726f

17 files changed

+217
-116
lines changed

base/boot.jl

+3-3
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

+16-12
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))
@@ -525,7 +527,7 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
525527
append!(s_edges, edges)
526528
empty!(edges)
527529
end
528-
if me.src.edges !== nothing
530+
if me.src.edges !== nothing && me.src.edges !== Core.svec()
529531
append!(s_edges, me.src.edges::Vector)
530532
end
531533
# inspect whether our inference had a limited result accuracy,
@@ -610,11 +612,12 @@ function finishinfer!(me::InferenceState, interp::AbstractInterpreter)
610612
const_flags = 0x00
611613
end
612614
relocatability = 0x0
613-
edges = nothing
614-
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any),
615+
di = nothing
616+
edges = Core.svec()
617+
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any),
615618
result.ci, widenconst(result_type), widenconst(result.exc_result), rettype_const, const_flags,
616619
first(result.valid_worlds), last(result.valid_worlds),
617-
encode_effects(result.ipo_effects), result.analysis_results, edges)
620+
encode_effects(result.ipo_effects), result.analysis_results, di, edges)
618621
if is_cached(me)
619622
cached_results = cache_result!(me.interp, me.result)
620623
if !cached_results
@@ -988,6 +991,7 @@ function codeinfo_for_const(interp::AbstractInterpreter, mi::MethodInstance, @no
988991
tree.debuginfo = DebugInfo(mi)
989992
tree.ssaflags = UInt32[0]
990993
tree.rettype = Core.Typeof(val)
994+
tree.edges = Core.svec()
991995
set_inlineable!(tree, true)
992996
tree.parent = mi
993997
return tree
@@ -1005,7 +1009,7 @@ function codeinstance_for_const_with_code(interp::AbstractInterpreter, code::Cod
10051009
return CodeInstance(code.def, cache_owner(interp), code.rettype, code.exctype, code.rettype_const, src,
10061010
Int32(0x3), code.min_world, code.max_world,
10071011
code.ipo_purity_bits, code.analysis_results,
1008-
code.relocatability, src.debuginfo)
1012+
code.relocatability, src.debuginfo, src.edges)
10091013
end
10101014

10111015
result_is_constabi(interp::AbstractInterpreter, result::InferenceResult,
@@ -1167,7 +1171,7 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod
11671171
src isa CodeInfo || return nothing
11681172
return CodeInstance(mi, cache_owner(interp), Any, Any, nothing, src, Int32(0),
11691173
get_inference_world(interp), get_inference_world(interp),
1170-
UInt32(0), nothing, UInt8(0), src.debuginfo)
1174+
UInt32(0), nothing, UInt8(0), src.debuginfo, src.edges)
11711175
end
11721176
end
11731177
ci = engine_reserve(interp, mi)

base/expr.jl

+1-1
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

-2
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

+2-2
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

+35-23
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);
@@ -616,7 +626,7 @@ JL_DLLEXPORT void jl_fill_codeinst(
616626

617627
JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_uninit(jl_method_instance_t *mi, jl_value_t *owner)
618628
{
619-
jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL);
629+
jl_code_instance_t *codeinst = jl_new_codeinst(mi, owner, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, 0, NULL, NULL);
620630
jl_atomic_store_relaxed(&codeinst->min_world, 1); // make temporarily invalid before returning, so that jl_fill_codeinst is valid later
621631
return codeinst;
622632
}
@@ -2566,8 +2576,10 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
25662576
jl_code_instance_t *codeinst2 = jl_compile_method_internal(mi2, world);
25672577
jl_code_instance_t *codeinst = jl_get_method_inferred(
25682578
mi, codeinst2->rettype,
2569-
jl_atomic_load_relaxed(&codeinst2->min_world), jl_atomic_load_relaxed(&codeinst2->max_world),
2570-
jl_atomic_load_relaxed(&codeinst2->debuginfo));
2579+
jl_atomic_load_relaxed(&codeinst2->min_world),
2580+
jl_atomic_load_relaxed(&codeinst2->max_world),
2581+
jl_atomic_load_relaxed(&codeinst2->debuginfo),
2582+
jl_atomic_load_relaxed(&codeinst2->edges));
25712583
if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) {
25722584
codeinst->rettype_const = codeinst2->rettype_const;
25732585
jl_gc_wb(codeinst, codeinst->rettype_const);
@@ -2626,7 +2638,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
26262638
if (unspec && (unspec_invoke = jl_atomic_load_acquire(&unspec->invoke))) {
26272639
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
26282640
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
2629-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
2641+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
26302642
void *unspec_fptr = jl_atomic_load_relaxed(&unspec->specptr.fptr);
26312643
if (unspec_fptr) {
26322644
// wait until invoke and specsigflags are properly set
@@ -2653,7 +2665,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
26532665
if (!jl_code_requires_compiler(src, 0)) {
26542666
jl_code_instance_t *codeinst = jl_new_codeinst(mi, jl_nothing,
26552667
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
2656-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
2668+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
26572669
jl_atomic_store_release(&codeinst->invoke, jl_fptr_interpret_call);
26582670
jl_mi_cache_insert(mi, codeinst);
26592671
record_precompile_statement(mi, 0);
@@ -2713,7 +2725,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
27132725
jl_method_instance_t *unspec = jl_get_unspecialized(def);
27142726
if (unspec == NULL)
27152727
unspec = mi;
2716-
jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0, NULL);
2728+
jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0, NULL, NULL);
27172729
// ask codegen to make the fptr for unspec
27182730
jl_callptr_t ucache_invoke = jl_atomic_load_acquire(&ucache->invoke);
27192731
if (ucache_invoke == NULL) {
@@ -2733,7 +2745,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t
27332745
}
27342746
codeinst = jl_new_codeinst(mi, jl_nothing,
27352747
(jl_value_t*)jl_any_type, (jl_value_t*)jl_any_type, NULL, NULL,
2736-
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL);
2748+
0, 1, ~(size_t)0, 0, jl_nothing, 0, NULL, NULL);
27372749
void *unspec_fptr = jl_atomic_load_relaxed(&ucache->specptr.fptr);
27382750
if (unspec_fptr) {
27392751
// wait until invoke and specsigflags are properly set

0 commit comments

Comments
 (0)