Skip to content

Commit

Permalink
irinterp: make sure to use optimizer_lattice when performing irinte…
Browse files Browse the repository at this point in the history
…rp (#49024)

While the base abstract interpretation routine uses `typeinf_lattice`,
irinterp only needs `optimizer_lattice`. Therefore, there are unnecessary
computations involved in handling `Conditional` in irinterp.
This commit adds `irinterp::Bool` field to `NativeInterpreter`,
indicating if a native interpreter is performing irinterp. This allows
it to switch its lattice to `optimizer_lattice` during irinterp.
  • Loading branch information
aviatesk authored Mar 17, 2023
1 parent 403e4e2 commit 7723134
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 27 deletions.
5 changes: 3 additions & 2 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -979,8 +979,9 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter,
if code !== nothing
ir = codeinst_to_ir(interp, code)
if isa(ir, IRCode)
irsv = IRInterpretationState(interp, ir, mi, sv.world, arginfo.argtypes)
rt, nothrow = ir_abstract_constant_propagation(interp, irsv)
irinterp = switch_to_irinterp(interp)
irsv = IRInterpretationState(irinterp, ir, mi, sv.world, arginfo.argtypes)
rt, nothrow = ir_abstract_constant_propagation(irinterp, irsv)
@assert !(rt isa Conditional || rt isa MustAlias) "invalid lattice element returned from IR interpretation"
if !isa(rt, Type) || typeintersect(rt, Bool) === Union{}
new_effects = Effects(result.effects; nothrow=nothrow)
Expand Down
77 changes: 52 additions & 25 deletions base/compiler/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -312,51 +312,64 @@ function OptimizationParams(
end

"""
NativeInterpreter
NativeInterpreter <: AbstractInterpreter
This represents Julia's native type inference algorithm and the Julia-LLVM codegen backend.
It contains many parameters used by the compilation pipeline.
"""
struct NativeInterpreter <: AbstractInterpreter
# Cache of inference results for this particular interpreter
cache::Vector{InferenceResult}
# The world age we're working inside of
world::UInt

# method table to lookup for during inference on this world age
method_table::CachedMethodTable{InternalMethodTable}

# Cache of inference results for this particular interpreter
inf_cache::Vector{InferenceResult}

# Parameters for inference and optimization
inf_params::InferenceParams
opt_params::OptimizationParams

function NativeInterpreter(world::UInt = get_world_counter();
inf_params = InferenceParams(),
opt_params = OptimizationParams(),
)
cache = Vector{InferenceResult}() # Initially empty cache
# a boolean flag to indicate if this interpreter is performing semi concrete interpretation
irinterp::Bool
end

function NativeInterpreter(world::UInt = get_world_counter();
inf_params::InferenceParams = InferenceParams(),
opt_params::OptimizationParams = OptimizationParams())
# Sometimes the caller is lazy and passes typemax(UInt).
# we cap it to the current world age
if world == typemax(UInt)
world = get_world_counter()
end

# Sometimes the caller is lazy and passes typemax(UInt).
# we cap it to the current world age
if world == typemax(UInt)
world = get_world_counter()
end
# If they didn't pass typemax(UInt) but passed something more subtly
# incorrect, fail out loudly.
@assert world <= get_world_counter()

method_table = CachedMethodTable(InternalMethodTable(world))
method_table = CachedMethodTable(InternalMethodTable(world))

# If they didn't pass typemax(UInt) but passed something more subtly
# incorrect, fail out loudly.
@assert world <= get_world_counter()
inf_cache = Vector{InferenceResult}() # Initially empty cache

return new(cache, world, method_table, inf_params, opt_params)
end
return NativeInterpreter(world, method_table, inf_cache, inf_params, opt_params, #=irinterp=#false)
end

function NativeInterpreter(interp::NativeInterpreter;
world::UInt = interp.world,
method_table::CachedMethodTable{InternalMethodTable} = interp.method_table,
inf_cache::Vector{InferenceResult} = interp.inf_cache,
inf_params::InferenceParams = interp.inf_params,
opt_params::OptimizationParams = interp.opt_params,
irinterp::Bool = interp.irinterp)
return NativeInterpreter(world, method_table, inf_cache, inf_params, opt_params, irinterp)
end

# Quickly and easily satisfy the AbstractInterpreter API contract
InferenceParams(ni::NativeInterpreter) = ni.inf_params
OptimizationParams(ni::NativeInterpreter) = ni.opt_params
get_world_counter(ni::NativeInterpreter) = ni.world
get_inference_cache(ni::NativeInterpreter) = ni.cache
code_cache(ni::NativeInterpreter) = WorldView(GLOBAL_CI_CACHE, get_world_counter(ni))
InferenceParams(interp::NativeInterpreter) = interp.inf_params
OptimizationParams(interp::NativeInterpreter) = interp.opt_params
get_world_counter(interp::NativeInterpreter) = interp.world
get_inference_cache(interp::NativeInterpreter) = interp.inf_cache
code_cache(interp::NativeInterpreter) = WorldView(GLOBAL_CI_CACHE, get_world_counter(interp))

"""
already_inferred_quick_test(::AbstractInterpreter, ::MethodInstance)
Expand Down Expand Up @@ -442,6 +455,20 @@ typeinf_lattice(::AbstractInterpreter) = InferenceLattice(BaseInferenceLattice.i
ipo_lattice(::AbstractInterpreter) = InferenceLattice(IPOResultLattice.instance)
optimizer_lattice(::AbstractInterpreter) = OptimizerLattice(SimpleInferenceLattice.instance)

typeinf_lattice(interp::NativeInterpreter) = interp.irinterp ? optimizer_lattice(interp) : InferenceLattice(BaseInferenceLattice.instance)
ipo_lattice(interp::NativeInterpreter) = interp.irinterp ? optimizer_lattice(interp) : InferenceLattice(IPOResultLattice.instance)
optimizer_lattice(interp::NativeInterpreter) = OptimizerLattice(SimpleInferenceLattice.instance)

"""
switch_to_irinterp(interp::AbstractInterpreter) -> irinterp::AbstractInterpreter
Optionally convert `interp` to new `irinterp::AbstractInterpreter` to perform semi-concrete
interpretation. `NativeInterpreter` uses this interface to switch its lattice to
`optimizer_lattice` during semi-concrete interpretation on `IRCode`.
"""
switch_to_irinterp(interp::AbstractInterpreter) = interp
switch_to_irinterp(interp::NativeInterpreter) = NativeInterpreter(interp; irinterp=true)

abstract type CallInfo end

@nospecialize
Expand Down

0 comments on commit 7723134

Please sign in to comment.