Resolve MethodInstance-targeted invokes in get_codeinfos - #19
Merged
Conversation
Inlining's compileable_specialization leaves an :invoke target as a bare MethodInstance when the compileable specialization is not cached at optimization time, and codegen unconditionally lowers such operands to runtime jl_invoke calls. get_codeinfos only followed CodeInstance edges, so these callees were dropped from the collection, breaking closed-world code generation (order-dependent InvalidIRErrors in GPU stacks, e.g. JuliaGPU/Metal.jl#870). get_codeinfos now requires the interpreter (breaking; the interp-less forms' "typeinf! ran first" precondition was unverifiable and violated by the natural cache-hit path) and uses it to close the collection: bare MethodInstance targets callable through a native ABI are inferred and the statements rewritten to their CodeInstance in a copy of the source, and referenced CIs lacking stored source are re-inferred instead of asserting. Abstract targets (e.g. @nospecialize-widened compileable signatures) keep their runtime-dispatch fallback. The const-specialized variant now seeds the walk from the const-optimized root source. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes order-dependent
InvalidIRError: unsupported dynamic function invocationfailuresin GPU stacks on Julia 1.12+ (e.g. JuliaGPU/Metal.jl#876, checked conversions hitting the
throw_inexacterroroverlay).Problem
Inlining's
compileable_specializationleaves an:invoketarget as a bareMethodInstancewhen the compileable specialization is not in the code cache atoptimization time, and that operand gets baked into the cached optimized source. Codegen
(
emit_invoke, all 1.12+ versions incl. master) lowers aMethodInstanceoperand to aruntime
jl_invokecall unconditionally — including the callee's CI in thejl_emit_nativepayload is not enough, the operand itself must be rewritten.get_codeinfosonly followedCodeInstanceedges, so such callees were silentlydropped from the collection, violating the documented contract that it returns the
transitive callee closure. On CPU that degrades to runtime dispatch; on GPU it's
invalid IR. Whether it triggers depends on cache history, hence the flaky,
order-dependent CI failures.
Fix
get_codeinfos(interp, ci)/get_codeinfos(interp, ci, argtypes)now resolveMethodInstance-targeted:invoke/:invoke_modifystatements throughtypeinf!andrewrite the operand to the resulting
CodeInstance, in a copy of the containing source(cached
CodeInfois never mutated; untouched sources are returned as-is). ReferencedCIs that lack stored source (e.g. from an earlier session) are re-inferred instead of
asserting.
Only targets callable through a native ABI are resolved:
isdispatchtuple(specTypes)plus a mirror of nightly's
has_valid_abi_sparams(TypeVar/svec/Vararg sparams takecodegen's
needsparamspath, which emitsjl_invokeeven for CI operands). Abstracttargets — e.g.
@nospecialize-widened compileable signatures — deterministically keeptheir runtime-dispatch fallback, so GPUCompiler's dynamic-call diagnostics are
unaffected.
The const-specialized variant now seeds the walk from the const-optimized root source,
so callees reachable only from const-optimized code are included (previously they got
runtime-dispatch stubs).
Breaking: interpreter argument is required
The interpreter-less
get_codeinfos(ci)andget_codeinfos(ci, argtypes)are removed:typeinf!ran first, in this session — is unverifiable, and thenatural cache-hit → codegen pattern violates it (our own
examples/native.jldid),with an un-closed collection as the silent failure mode.
passing it costs nothing and lets collection repair gaps instead of asserting.
Compiler/src/typeinfer.jlthe interpreter travels insideCompilationQueue, and thecompile!/add_codeinsts_to_jit!drain loops fusecollection with re-inference. There is no interpreter-less collection in Base either.
Migration:
get_codeinfos(ci)→get_codeinfos(interp, ci), whereinterpmatchesthe cache owner and world that produced
ci(typically the one passed totypeinf!).Version bumped to 0.4.0. GPUCompiler follow-up is a one-line call-site change plus the
compat bump.