Skip to content

Commit

Permalink
inference: allocate CodeInstance with inference results ASAP [WIP]
Browse files Browse the repository at this point in the history
Update the CodeInstance after optimizations with code (if possible), but
construct it early so that there will be the option of using it for
edges and invoke during optimizations, without problems with cycles.
  • Loading branch information
vtjnash committed Jun 6, 2024
1 parent ec32170 commit a117769
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 41 deletions.
2 changes: 1 addition & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ function CodeInstance(
mi::MethodInstance, owner, @nospecialize(rettype), @nospecialize(exctype), @nospecialize(inferred_const),
@nospecialize(inferred), const_flags::Int32, min_world::UInt, max_world::UInt,
ipo_effects::UInt32, effects::UInt32, @nospecialize(analysis_results),
relocatability::UInt8, edges::DebugInfo)
relocatability::UInt8, edges::Union{DebugInfo,Nothing})
return ccall(:jl_new_codeinst, Ref{CodeInstance},
(Any, Any, Any, Any, Any, Any, Int32, UInt, UInt, UInt32, UInt32, Any, UInt8, Any),
mi, owner, rettype, exctype, inferred_const, inferred, const_flags, min_world, max_world,
Expand Down
1 change: 1 addition & 0 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const setproperty! = Core.setfield!
const swapproperty! = Core.swapfield!
const modifyproperty! = Core.modifyfield!
const replaceproperty! = Core.replacefield!
const _DOCS_ALIASING_WARNING = ""

ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false)

Expand Down
90 changes: 51 additions & 39 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,8 @@ function typeinf(interp::AbstractInterpreter, frame::InferenceState)
end
end

function finish!(interp::AbstractInterpreter, caller::InferenceState)
function finish!(interp::AbstractInterpreter, caller::InferenceState;
can_discard_trees::Bool=may_discard_trees(interp))
result = caller.result
valid_worlds = result.valid_worlds
if last(valid_worlds) >= get_world_counter()
Expand All @@ -228,6 +229,44 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState)
if opt isa OptimizationState
result.src = opt = ir_to_codeinf!(opt)
end
if isdefined(result, :ci)
ci = result.ci
relocatability = 0x0
if is_result_constabi_eligible(result) && can_discard_trees
inferred_result = nothing
relocatability = 0x1
const_flag = true
else
const_flag = false
inferred_result = transform_result_for_cache(interp, result.linfo, result.valid_worlds, result, can_discard_trees)
if inferred_result isa CodeInfo
edges = 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
elseif ci.owner === nothing
# The global cache can only handle objects that codegen understands
inferred_result = nothing
end
if isa(inferred_result, String)
t = @_gc_preserve_begin inferred_result
relocatability = unsafe_load(unsafe_convert(Ptr{UInt8}, inferred_result), Core.sizeof(inferred_result))
@_gc_preserve_end t
elseif inferred_result === nothing
relocatability = 0x1
end
end
# n.b. relocatability = (isa(inferred_result, String) && inferred_result[end]) || inferred_result === nothing
if !@isdefined edges
edges = DebugInfo(result.linfo)
end
ccall(:jl_update_codeinst, Cvoid, (Any, Any, Int32, UInt, UInt, UInt32, UInt32, Any, UInt8, Any),
ci, inferred_result, const_flag,
first(result.valid_worlds), last(result.valid_worlds),
# TODO: Actually do something with non-IPO effects
encode_effects(result.ipo_effects), encode_effects(result.ipo_effects), result.analysis_results,
relocatability, edges)
end
return nothing
end

Expand All @@ -251,7 +290,10 @@ function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
for caller in frames
caller.valid_worlds = cycle_valid_worlds
caller.ipo_effects = cycle_effects
finish(caller, caller.interp)
finishinfer(caller, caller.interp)
if is_cached(caller)
cache_result!(caller.interp, caller.result)
end
end
for caller in frames
opt = caller.result.src
Expand All @@ -261,9 +303,7 @@ function _typeinf(interp::AbstractInterpreter, frame::InferenceState)
end
for caller in frames
finish!(caller.interp, caller)
if is_cached(caller)
cache_result!(caller.interp, caller.result)
end
unlock_mi_inference(caller.interp, caller.linfo)
end
empty!(frames)
return true
Expand All @@ -273,8 +313,7 @@ function is_result_constabi_eligible(result::InferenceResult)
result_type = result.result
return isa(result_type, Const) && is_foldable_nothrow(result.ipo_effects) && is_inlineable_constant(result_type.val)
end
function CodeInstance(interp::AbstractInterpreter, result::InferenceResult;
can_discard_trees::Bool=may_discard_trees(interp))
function CodeInstance(interp::AbstractInterpreter, result::InferenceResult)
local const_flags::Int32
result_type = result.result
@assert !(result_type === nothing || result_type isa LimitedAccuracy)
Expand Down Expand Up @@ -308,38 +347,12 @@ function CodeInstance(interp::AbstractInterpreter, result::InferenceResult;
end
relocatability = 0x0
owner = cache_owner(interp)
if const_flags == 0x3 && can_discard_trees
inferred_result = nothing
relocatability = 0x1
else
inferred_result = transform_result_for_cache(interp, result.linfo, result.valid_worlds, result, can_discard_trees)
if inferred_result isa CodeInfo
edges = 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
elseif owner === nothing
# The global cache can only handle objects that codegen understands
inferred_result = nothing
end
if isa(inferred_result, String)
t = @_gc_preserve_begin inferred_result
relocatability = unsafe_load(unsafe_convert(Ptr{UInt8}, inferred_result), Core.sizeof(inferred_result))
@_gc_preserve_end t
elseif inferred_result === nothing
relocatability = 0x1
end
end
# n.b. relocatability = (isa(inferred_result, String) && inferred_result[end]) || inferred_result === nothing
if !@isdefined edges
edges = DebugInfo(result.linfo)
end
return CodeInstance(result.linfo, owner,
widenconst(result_type), widenconst(result.exc_result), rettype_const, inferred_result,
widenconst(result_type), widenconst(result.exc_result), rettype_const, nothing,
const_flags, first(result.valid_worlds), last(result.valid_worlds),
# TODO: Actually do something with non-IPO effects
encode_effects(result.ipo_effects), encode_effects(result.ipo_effects), result.analysis_results,
relocatability, edges)
relocatability, nothing)
end

function transform_result_for_cache(interp::AbstractInterpreter,
Expand Down Expand Up @@ -402,7 +415,6 @@ function cache_result!(interp::AbstractInterpreter, result::InferenceResult)
end
end
end
unlock_mi_inference(interp, mi)
nothing
end

Expand Down Expand Up @@ -521,7 +533,7 @@ end

# inference completed on `me`
# update the MethodInstance
function finish(me::InferenceState, interp::AbstractInterpreter)
function finishinfer(me::InferenceState, interp::AbstractInterpreter)
# prepare to run optimization passes on fulltree
s_edges = me.stmt_edges[1]
if s_edges === nothing
Expand Down Expand Up @@ -566,7 +578,6 @@ function finish(me::InferenceState, interp::AbstractInterpreter)
me.result.src = nothing
me.cache_mode = CACHE_MODE_NULL
set_inlineable!(me.src, false)
unlock_mi_inference(interp, me.linfo)
elseif limited_src
# a type result will be cached still, but not this intermediate work:
# we can throw everything else away now
Expand Down Expand Up @@ -1140,7 +1151,8 @@ function typeinf_ext(interp::AbstractInterpreter, mi::MethodInstance, source_mod
# We construct a new CodeInstance for it that is not part of the cache hierarchy.
can_discard_trees = source_mode SOURCE_MODE_FORCE_SOURCE &&
is_result_constabi_eligible(result)
code = CodeInstance(interp, result; can_discard_trees)
code = CodeInstance(interp, result)
finish!(interp, frame; can_discard_trees)

# If the caller cares about the code and this is constabi, still use our synthesis function
# anyway, because we will have not finished inferring the code inside the CodeInstance once
Expand Down
25 changes: 24 additions & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,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, edges);
jl_atomic_store_relaxed(&codeinst->debuginfo, (jl_value_t*)edges == jl_nothing ? NULL : edges);
jl_atomic_store_relaxed(&codeinst->specptr.fptr, NULL);
jl_atomic_store_relaxed(&codeinst->invoke, NULL);
if ((const_flags & 1) != 0) {
Expand All @@ -560,6 +560,29 @@ JL_DLLEXPORT jl_code_instance_t *jl_new_codeinst(
return codeinst;
}

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 ipo_effects, uint32_t effects, jl_value_t *analysis_results,
uint8_t relocatability, jl_debuginfo_t *edges /* , int absolute_max*/)
{
jl_atomic_store_relaxed(&codeinst->min_world, min_world);
jl_atomic_store_relaxed(&codeinst->max_world, max_world);
codeinst->relocatability = relocatability;
codeinst->analysis_results = analysis_results;
jl_gc_wb(codeinst, analysis_results);
codeinst->ipo_purity_bits = ipo_effects;
jl_atomic_store_relaxed(&codeinst->purity_bits, effects);
jl_atomic_store_relaxed(&codeinst->debuginfo, edges);
jl_gc_wb(codeinst, edges);
if ((const_flags & 1) != 0) {
assert(codeinst->rettype_const);
jl_atomic_store_release(&codeinst->invoke, jl_fptr_const_return);
}
jl_atomic_store_release(&codeinst->inferred, inferred);
jl_gc_wb(codeinst, inferred);
}

JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMENT,
jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED)
{
Expand Down

0 comments on commit a117769

Please sign in to comment.