Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9f9d9d4

Browse files
committedJan 4, 2025·
fix handling of experimental module compile flag
Add a new `finish!` function which skips any inference/optimization and just directly uses the (uninferred) source as the result, setting all fields correctly assuming they might have come from a generated function in the very unlikely case it set some of them, and making sure this is now correctly synchronized with the cache lookup and insertion calls once again. This code feature was added without any tests in #37041, so I cannot guarantee there aren't any mistakes still lurking here, either mine or original, but it gets some testing by some _jll packages. Fixes #53431
1 parent 638dacc commit 9f9d9d4

File tree

5 files changed

+92
-45
lines changed

5 files changed

+92
-45
lines changed
 

‎Compiler/src/typeinfer.jl

+59-13
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,39 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState)
173173
return nothing
174174
end
175175

176+
function finish!(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInstance, src::CodeInfo)
177+
user_edges = src.edges
178+
edges = user_edges isa SimpleVector ? user_edges : user_edges === nothing ? Core.svec() : Core.svec(user_edges...)
179+
relocatability = 0x1
180+
const_flag = false
181+
di = src.debuginfo
182+
rettype = Any
183+
exctype = Any
184+
rettype_const = nothing
185+
const_flags = 0x0
186+
ipo_effects = zero(UInt32)
187+
min_world = src.min_world
188+
max_world = src.max_world
189+
if max_world >= get_world_counter()
190+
max_world = typemax(UInt)
191+
end
192+
if max_world == typemax(UInt)
193+
# if we can record all of the backedges in the global reverse-cache,
194+
# we can now widen our applicability in the global cache too
195+
store_backedges(ci, edges)
196+
end
197+
ccall(:jl_fill_codeinst, Cvoid, (Any, Any, Any, Any, Int32, UInt, UInt, UInt32, Any, Any, Any),
198+
ci, rettype, exctype, nothing, const_flags, min_world, max_world, ipo_effects, nothing, di, edges)
199+
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, Any, UInt8, Any, Any),
200+
ci, nothing, const_flag, min_world, max_world, ipo_effects, nothing, relocatability, di, edges)
201+
code_cache(interp)[mi] = ci
202+
if isdefined(interp, :codegen)
203+
interp.codegen[ci] = src
204+
end
205+
engine_reject(interp, ci)
206+
return nothing
207+
end
208+
176209
function finish_nocycle(::AbstractInterpreter, frame::InferenceState)
177210
finishinfer!(frame, frame.interp)
178211
opt = frame.result.src
@@ -826,7 +859,7 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize
826859
end
827860
end
828861
end
829-
if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0 && !generating_output(#=incremental=#false)
862+
if ccall(:jl_get_module_infer, Cint, (Any,), method.module) == 0
830863
add_remark!(interp, caller, "[typeinf_edge] Inference is disabled for the target module")
831864
return Future(MethodCallResult(interp, caller, method, Any, Any, Effects(), nothing, edgecycle, edgelimited))
832865
end
@@ -1096,15 +1129,6 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod
10961129
end
10971130
end
10981131
def = mi.def
1099-
if isa(def, Method)
1100-
if ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 && !generating_output(#=incremental=#false)
1101-
src = retrieve_code_info(mi, get_inference_world(interp))
1102-
src isa CodeInfo || return nothing
1103-
return CodeInstance(mi, cache_owner(interp), Any, Any, nothing, src, Int32(0),
1104-
get_inference_world(interp), get_inference_world(interp),
1105-
UInt32(0), nothing, UInt8(0), src.debuginfo, src.edges)
1106-
end
1107-
end
11081132
ci = engine_reserve(interp, mi)
11091133
# check cache again if it is still new after reserving in the engine
11101134
let code = get(code_cache(interp), mi, nothing)
@@ -1117,11 +1141,22 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod
11171141
end
11181142
end
11191143
end
1144+
if isa(def, Method) && ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0
1145+
src = retrieve_code_info(mi, get_inference_world(interp))
1146+
if src isa CodeInfo
1147+
finish!(interp, mi, ci, src)
1148+
else
1149+
engine_reject(interp, ci)
1150+
end
1151+
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
1152+
return ci
1153+
end
11201154
result = InferenceResult(mi, typeinf_lattice(interp))
11211155
result.ci = ci
11221156
frame = InferenceState(result, #=cache_mode=#:global, interp)
11231157
if frame === nothing
11241158
engine_reject(interp, ci)
1159+
ccall(:jl_typeinf_timing_end, Cvoid, (UInt64,), start_time)
11251160
return nothing
11261161
end
11271162
typeinf(interp, frame)
@@ -1263,18 +1298,29 @@ function typeinf_ext_toplevel(methods::Vector{Any}, worlds::Vector{UInt}, trim::
12631298
callee in inspected && continue
12641299
push!(inspected, callee)
12651300
# now make sure everything has source code, if desired
1266-
# TODO: typeinf_code could return something with different edges/ages (needing an update to callee), which we don't handle here
1301+
mi = get_ci_mi(callee)
1302+
def = mi.def
12671303
if use_const_api(callee)
1268-
src = codeinfo_for_const(interp, callee.def, code.rettype_const)
1304+
src = codeinfo_for_const(interp, mi, code.rettype_const)
12691305
elseif haskey(interp.codegen, callee)
12701306
src = interp.codegen[callee]
1307+
elseif isa(def, Method) && ccall(:jl_get_module_infer, Cint, (Any,), def.module) == 0 && !trim
1308+
src = retrieve_code_info(mi, get_inference_world(interp))
12711309
else
1272-
src = typeinf_code(interp, callee.def, true)
1310+
# TODO: typeinf_code could return something with different edges/ages/owner/abi (needing an update to callee), which we don't handle here
1311+
src = typeinf_code(interp, mi, true)
12731312
end
12741313
if src isa CodeInfo
12751314
collectinvokes!(tocompile, src)
1315+
# It is somewhat ambiguous if typeinf_ext might have callee in the caches,
1316+
# but for the purpose of native compile, we always want them put there.
1317+
if iszero(ccall(:jl_mi_cache_has_ci, Cint, (Any, Any), mi, callee))
1318+
code_cache(interp)[mi] = callee
1319+
end
12761320
push!(codeinfos, callee)
12771321
push!(codeinfos, src)
1322+
elseif trim
1323+
println("warning: failed to get code for ", mi)
12781324
end
12791325
end
12801326
end

‎src/aotcompile.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ static void resolve_workqueue(jl_codegen_params_t &params, egal_set &method_root
429429
}
430430
}
431431
else if (params.params->trim) {
432-
jl_safe_printf("warning: no code provided for function");
432+
jl_safe_printf("warning: no code provided for function ");
433433
jl_(codeinst->def);
434434
if (params.params->trim)
435435
abort();
@@ -441,7 +441,7 @@ static void resolve_workqueue(jl_codegen_params_t &params, egal_set &method_root
441441
Function *pinvoke = nullptr;
442442
if (preal_decl.empty()) {
443443
if (invokeName.empty() && params.params->trim) {
444-
jl_safe_printf("warning: bailed out to invoke when compiling:");
444+
jl_safe_printf("warning: bailed out to invoke when compiling: ");
445445
jl_(codeinst->def);
446446
abort();
447447
}
@@ -658,7 +658,7 @@ void *jl_emit_native_impl(jl_array_t *codeinfos, LLVMOrcThreadSafeModuleRef llvm
658658
else if (params.params->trim) {
659659
// if we're building a small image, we need to compile everything
660660
// to ensure that we have all the information we need.
661-
jl_safe_printf("codegen failed to compile code root");
661+
jl_safe_printf("codegen failed to compile code root ");
662662
jl_(mi);
663663
abort();
664664
}

‎src/gf.c

+27
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,33 @@ JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi,
581581
return 0;
582582
}
583583

584+
// look for something with an egal ABI and properties that is already in the JIT (compiled=true) or simply in the cache (compiled=false)
585+
JL_DLLEXPORT jl_code_instance_t *jl_get_ci_equiv(jl_code_instance_t *ci JL_PROPAGATES_ROOT, int compiled) JL_NOTSAFEPOINT
586+
{
587+
jl_value_t *def = ci->def;
588+
jl_method_instance_t *mi = jl_get_ci_mi(ci);
589+
jl_value_t *owner = ci->owner;
590+
jl_value_t *rettype = ci->rettype;
591+
size_t min_world = jl_atomic_load_relaxed(&ci->min_world);
592+
size_t max_world = jl_atomic_load_relaxed(&ci->max_world);
593+
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
594+
while (codeinst) {
595+
if (codeinst != ci &&
596+
jl_atomic_load_relaxed(&codeinst->inferred) != NULL &&
597+
(!compiled || jl_atomic_load_relaxed(&codeinst->invoke) != NULL) &&
598+
jl_atomic_load_relaxed(&codeinst->min_world) <= min_world &&
599+
jl_atomic_load_relaxed(&codeinst->max_world) >= max_world &&
600+
jl_egal(codeinst->def, def) &&
601+
jl_egal(codeinst->owner, owner) &&
602+
jl_egal(codeinst->rettype, rettype)) {
603+
return codeinst;
604+
}
605+
codeinst = jl_atomic_load_relaxed(&codeinst->next);
606+
}
607+
return (jl_code_instance_t*)jl_nothing;
608+
}
609+
610+
584611
JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
585612
jl_method_instance_t *mi, jl_value_t *owner,
586613
jl_value_t *rettype, jl_value_t *exctype,

‎src/jitlayers.cpp

+2-28
Original file line numberDiff line numberDiff line change
@@ -301,32 +301,6 @@ static void finish_params(Module *M, jl_codegen_params_t &params) JL_NOTSAFEPOIN
301301
}
302302
}
303303

304-
// look for something with an egal ABI that is already in the JIT
305-
static jl_code_instance_t *jl_method_compiled_egal(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
306-
{
307-
jl_value_t *def = ci->def;
308-
jl_method_instance_t *mi = jl_get_ci_mi(ci);
309-
jl_value_t *owner = ci->owner;
310-
jl_value_t *rettype = ci->rettype;
311-
size_t min_world = jl_atomic_load_relaxed(&ci->min_world);
312-
size_t max_world = jl_atomic_load_relaxed(&ci->max_world);
313-
jl_code_instance_t *codeinst = jl_atomic_load_relaxed(&mi->cache);
314-
while (codeinst) {
315-
if (codeinst != ci &&
316-
jl_atomic_load_relaxed(&codeinst->inferred) != NULL &&
317-
jl_atomic_load_relaxed(&codeinst->invoke) != NULL &&
318-
jl_atomic_load_relaxed(&codeinst->min_world) <= min_world &&
319-
jl_atomic_load_relaxed(&codeinst->max_world) >= max_world &&
320-
jl_egal(codeinst->def, def) &&
321-
jl_egal(codeinst->owner, owner) &&
322-
jl_egal(codeinst->rettype, rettype)) {
323-
return codeinst;
324-
}
325-
codeinst = jl_atomic_load_relaxed(&codeinst->next);
326-
}
327-
return codeinst;
328-
}
329-
330304
static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t &params, bool forceall=false) JL_NOTSAFEPOINT_LEAVE JL_NOTSAFEPOINT_ENTER
331305
{
332306
jl_task_t *ct = jl_current_task;
@@ -377,8 +351,8 @@ static int jl_analyze_workqueue(jl_code_instance_t *callee, jl_codegen_params_t
377351
}
378352
if (preal_decl.empty()) {
379353
// there may be an equivalent method already compiled (or at least registered with the JIT to compile), in which case we should be using that instead
380-
jl_code_instance_t *compiled_ci = jl_method_compiled_egal(codeinst);
381-
if (compiled_ci) {
354+
jl_code_instance_t *compiled_ci = jl_get_ci_equiv(codeinst, 1);
355+
if ((jl_value_t*)compiled_ci != jl_nothing) {
382356
codeinst = compiled_ci;
383357
uint8_t specsigflags;
384358
void *fptr;

‎src/julia_internal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,7 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
692692
int32_t const_flags, size_t min_world, size_t max_world,
693693
uint32_t effects, jl_value_t *analysis_results,
694694
uint8_t relocatability, jl_debuginfo_t *di, jl_svec_t *edges /* , int absolute_max*/);
695+
JL_DLLEXPORT jl_code_instance_t *jl_get_ci_equiv(jl_code_instance_t *ci JL_PROPAGATES_ROOT, int compiled) JL_NOTSAFEPOINT;
695696

696697
STATIC_INLINE jl_method_instance_t *jl_get_ci_mi(jl_code_instance_t *ci JL_PROPAGATES_ROOT) JL_NOTSAFEPOINT
697698
{
@@ -1221,7 +1222,6 @@ JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMEN
12211222
JL_DLLEXPORT int jl_mi_try_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT,
12221223
jl_code_instance_t *expected_ci,
12231224
jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED);
1224-
JL_DLLEXPORT int jl_mi_cache_has_ci(jl_method_instance_t *mi, jl_code_instance_t *ci) JL_NOTSAFEPOINT;
12251225
JL_DLLEXPORT jl_code_instance_t *jl_cached_uninferred(jl_code_instance_t *codeinst, size_t world);
12261226
JL_DLLEXPORT jl_code_instance_t *jl_cache_uninferred(jl_method_instance_t *mi, jl_code_instance_t *checked, size_t world, jl_code_instance_t *newci JL_MAYBE_UNROOTED);
12271227
JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst_for_uninferred(jl_method_instance_t *mi, jl_code_info_t *src);

0 commit comments

Comments
 (0)
Please sign in to comment.