Skip to content

Commit

Permalink
Sink CodeInfo transformation into transform_result_for_cache
Browse files Browse the repository at this point in the history
Several downstream consumers want to cache IRCode rather than CodeInfo.
Right now they need to override both `finish!` and `transform_result_for_cache`.
With this change, only overriding the latter should be sufficient.
As a nice bonus, we can avoid doing the work of converting to CodeInfo
for interpreters that don't cache at all such as the REPL interpreter.
  • Loading branch information
Cédric Belmant committed Feb 12, 2025
1 parent 6dca4f4 commit 3d708e3
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 18 deletions.
12 changes: 9 additions & 3 deletions Compiler/src/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ is_declared_noinline(@nospecialize src::MaybeCompressed) =
# return whether this src should be inlined. If so, retrieve_ir_for_inlining must return an IRCode from it
function src_inlining_policy(interp::AbstractInterpreter,
@nospecialize(src), @nospecialize(info::CallInfo), stmt_flag::UInt32)
if isa(src, OptimizationState)
src = something(src.ir, src.src)
end
if isa(src, MaybeCompressed)
src_inlineable = is_stmt_inline(stmt_flag) || is_inlineable(src)
return src_inlineable
Expand Down Expand Up @@ -226,10 +229,13 @@ include("ssair/passes.jl")
include("ssair/irinterp.jl")

function ir_to_codeinf!(opt::OptimizationState)
(; linfo, src) = opt
src = ir_to_codeinf!(src, opt.ir::IRCode)
src.edges = Core.svec(opt.inlining.edges...)
(; linfo, src, ir) = opt
if ir === nothing
return src
end
src = ir_to_codeinf!(src, ir::IRCode)
opt.ir = nothing
opt.src = src
maybe_validate_code(linfo, src, "optimized")
return src
end
Expand Down
4 changes: 4 additions & 0 deletions Compiler/src/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,10 @@ function retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode, preserve_local
ir.debuginfo.def = mi
return ir, spec_info, DebugInfo(ir.debuginfo, length(ir.stmts))
end
function retrieve_ir_for_inlining(mi::MethodInstance, opt::OptimizationState, preserve_local_sources::Bool)
opt.ir !== nothing && return retrieve_ir_for_inlining(mi, opt.ir, preserve_local_sources)
retrieve_ir_for_inlining(mi, opt.src, preserve_local_sources)
end

function handle_single_case!(todo::Vector{Pair{Int,Any}},
ir::IRCode, idx::Int, stmt::Expr, @nospecialize(case),
Expand Down
31 changes: 22 additions & 9 deletions Compiler/src/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,21 @@ If set to `true`, record per-method-instance timings within type inference in th
__set_measure_typeinf(onoff::Bool) = __measure_typeinf__[] = onoff
const __measure_typeinf__ = RefValue{Bool}(false)

function finish!(interp::AbstractInterpreter, caller::InferenceState, validation_world::UInt)
function result_edges(interp::AbstractInterpreter, caller::InferenceState)
result = caller.result
opt = result.src
if opt isa OptimizationState
src = ir_to_codeinf!(opt)
edges = src.edges::SimpleVector
caller.src = result.src = src
if isa(opt, OptimizationState)
return Core.svec(opt.inlining.edges...)
else
edges = Core.svec(caller.edges...)
caller.src.edges = edges
return Core.svec(caller.edges...)
end
end

function finish!(interp::AbstractInterpreter, caller::InferenceState, validation_world::UInt)
result = caller.result
#@assert last(result.valid_worlds) <= get_world_counter() || isempty(caller.edges)
if isdefined(result, :ci)
edges = result_edges(interp, caller)
ci = result.ci
# if we aren't cached, we don't need this edge
# but our caller might, so let's just make it anyways
Expand All @@ -118,9 +120,10 @@ function finish!(interp::AbstractInterpreter, caller::InferenceState, validation
const_flag = is_result_constabi_eligible(result)
discard_src = caller.cache_mode === CACHE_MODE_NULL || const_flag
if !discard_src
inferred_result = transform_result_for_cache(interp, result)
inferred_result = transform_result_for_cache(interp, result, edges)
# TODO: do we want to augment edges here with any :invoke targets that we got from inlining (such that we didn't have a direct edge to it already)?
if inferred_result isa CodeInfo
result.src = inferred_result
if may_compress(interp)
nslots = length(inferred_result.slotflags)
resize!(inferred_result.slottypes::Vector{Any}, nslots)
Expand Down Expand Up @@ -275,7 +278,16 @@ function is_result_constabi_eligible(result::InferenceResult)
return isa(result_type, Const) && is_foldable_nothrow(result.ipo_effects) && is_inlineable_constant(result_type.val)
end

transform_result_for_cache(::AbstractInterpreter, result::InferenceResult) = result.src
function transform_result_for_cache(::AbstractInterpreter, result::InferenceResult, edges::SimpleVector)
src = result.src
if isa(src, OptimizationState)
src = ir_to_codeinf!(src)
end
if isa(src, CodeInfo)
src.edges = edges
end
return src
end

function maybe_compress_codeinfo(interp::AbstractInterpreter, mi::MethodInstance, ci::CodeInfo)
def = mi.def
Expand Down Expand Up @@ -1061,6 +1073,7 @@ function typeinf_frame(interp::AbstractInterpreter, mi::MethodInstance, run_opti
opt = OptimizationState(frame, interp)
optimize(interp, opt, frame.result)
src = ir_to_codeinf!(opt)
src.edges = Core.svec(opt.inlining.edges...)
end
result.src = frame.src = src
end
Expand Down
6 changes: 3 additions & 3 deletions Compiler/test/AbstractInterpreter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Compiler.may_optimize(::AbsIntOnlyInterp1) = false
# it should work even if the interpreter discards inferred source entirely
@newinterp AbsIntOnlyInterp2
Compiler.may_optimize(::AbsIntOnlyInterp2) = false
Compiler.transform_result_for_cache(::AbsIntOnlyInterp2, ::Compiler.InferenceResult) = nothing
Compiler.transform_result_for_cache(::AbsIntOnlyInterp2, ::Compiler.InferenceResult, edges::Core.SimpleVector) = nothing
@test Base.infer_return_type(Base.init_stdio, (Ptr{Cvoid},); interp=AbsIntOnlyInterp2()) >: IO

# OverlayMethodTable
Expand Down Expand Up @@ -493,9 +493,9 @@ struct CustomData
inferred
CustomData(@nospecialize inferred) = new(inferred)
end
function Compiler.transform_result_for_cache(interp::CustomDataInterp, result::Compiler.InferenceResult)
function Compiler.transform_result_for_cache(interp::CustomDataInterp, result::Compiler.InferenceResult, edges::Core.SimpleVector)
inferred_result = @invoke Compiler.transform_result_for_cache(
interp::Compiler.AbstractInterpreter, result::Compiler.InferenceResult)
interp::Compiler.AbstractInterpreter, result::Compiler.InferenceResult, edges::Core.SimpleVector)
return CustomData(inferred_result)
end
function Compiler.src_inlining_policy(interp::CustomDataInterp, @nospecialize(src),
Expand Down
2 changes: 1 addition & 1 deletion stdlib/REPL/src/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ CC.cache_owner(::REPLInterpreter) = REPLCacheToken()
CC.may_optimize(::REPLInterpreter) = false

# REPLInterpreter doesn't need any sources to be cached, so discard them aggressively
CC.transform_result_for_cache(::REPLInterpreter, ::CC.InferenceResult) = nothing
CC.transform_result_for_cache(::REPLInterpreter, ::CC.InferenceResult, edges::Core.SimpleVector) = nothing

# REPLInterpreter analyzes a top-level frame, so better to not bail out from it
CC.bail_out_toplevel_call(::REPLInterpreter, ::CC.InferenceLoopState, ::CC.InferenceState) = false
Expand Down
4 changes: 2 additions & 2 deletions test/precompile_absint2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ precompile_test_harness() do load_path
inferred
CustomData(@nospecialize inferred) = new(inferred)
end
function Compiler.transform_result_for_cache(interp::PrecompileInterpreter, result::Compiler.InferenceResult)
function Compiler.transform_result_for_cache(interp::PrecompileInterpreter, result::Compiler.InferenceResult, edges::Core.SimpleVector)
inferred_result = @invoke Compiler.transform_result_for_cache(
interp::Compiler.AbstractInterpreter, result::Compiler.InferenceResult)
interp::Compiler.AbstractInterpreter, result::Compiler.InferenceResult, edges::Core.SimpleVector)
return CustomData(inferred_result)
end
function Compiler.src_inlining_policy(interp::PrecompileInterpreter, @nospecialize(src),
Expand Down

0 comments on commit 3d708e3

Please sign in to comment.