Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AbstractInterpreter: remove method_table(::AbstractInterpreter, ::InferenceState) interface #44389

Merged
merged 2 commits into from
Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
end

argtypes = arginfo.argtypes
matches = find_matching_methods(argtypes, atype, method_table(interp, sv), InferenceParams(interp).MAX_UNION_SPLITTING, max_methods)
matches = find_matching_methods(argtypes, atype, method_table(interp), InferenceParams(interp).MAX_UNION_SPLITTING, max_methods)
if isa(matches, FailedMethodMatch)
add_remark!(interp, sv, matches.reason)
tristate_merge!(sv, Effects())
Expand Down Expand Up @@ -637,7 +637,7 @@ end

function pure_eval_eligible(interp::AbstractInterpreter,
@nospecialize(f), applicable::Vector{Any}, arginfo::ArgInfo, sv::InferenceState)
return !isoverlayed(method_table(interp, sv)) &&
return !isoverlayed(method_table(interp)) &&
f !== nothing &&
length(applicable) == 1 &&
is_method_pure(applicable[1]::MethodMatch) &&
Expand Down Expand Up @@ -674,7 +674,7 @@ end

function concrete_eval_eligible(interp::AbstractInterpreter,
@nospecialize(f), result::MethodCallResult, arginfo::ArgInfo, sv::InferenceState)
return !isoverlayed(method_table(interp, sv)) &&
return !isoverlayed(method_table(interp)) &&
f !== nothing &&
result.edge !== nothing &&
is_total_or_error(result.edge_effects) &&
Expand Down Expand Up @@ -2110,14 +2110,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
frame.dont_work_on_me = true # mark that this function is currently on the stack
W = frame.ip
states = frame.stmt_types
n = frame.nstmts
nstmts = frame.nstmts
nargs = frame.nargs
def = frame.linfo.def
isva = isa(def, Method) && def.isva
nslots = nargs - isva
slottypes = frame.slottypes
ssavaluetypes = frame.src.ssavaluetypes::Vector{Any}
while frame.pc´´ <= n
while frame.pc´´ <= nstmts
# make progress on the active ip set
local pc::Int = frame.pc´´
while true # inner loop optimizes the common case where it can run straight from pc to pc + 1
Expand Down Expand Up @@ -2189,7 +2189,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
end
end
elseif isa(stmt, ReturnNode)
pc´ = n + 1
pc´ = nstmts + 1
bestguess = frame.bestguess
rt = abstract_eval_value(interp, stmt.val, changes, frame)
rt = widenreturn(rt, bestguess, nslots, slottypes, changes)
Expand Down Expand Up @@ -2310,7 +2310,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
ssavaluetypes[pc] = Any
end

pc´ > n && break # can't proceed with the fast-path fall-through
pc´ > nstmts && break # can't proceed with the fast-path fall-through
newstate = stupdate!(states[pc´], changes)
if isa(stmt, GotoNode) && frame.pc´´ < pc´
# if we are processing a goto node anyways,
Expand Down
31 changes: 11 additions & 20 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ mutable struct InferenceState
# Inferred purity flags
ipo_effects::Effects

# The place to look up methods while working on this function.
# In particular, we cache method lookup results for the same function to
# fast path repeated queries.
method_table::InternalMethodTable

# The interpreter that created this inference state. Not looked at by
# NativeInterpreter. But other interpreters may use this to detect cycles
interp::AbstractInterpreter
Expand All @@ -85,9 +80,9 @@ mutable struct InferenceState
src.ssavaluetypes = Any[ NOT_FOUND for i = 1:nssavalues ]
stmt_info = Any[ nothing for i = 1:length(code) ]

n = length(code)
s_types = Union{Nothing, VarTable}[ nothing for i = 1:n ]
s_edges = Union{Nothing, Vector{Any}}[ nothing for i = 1:n ]
nstmts = length(code)
s_types = Union{Nothing, VarTable}[ nothing for i = 1:nstmts ]
s_edges = Union{Nothing, Vector{Any}}[ nothing for i = 1:nstmts ]

# initial types
nslots = length(src.slotflags)
Expand Down Expand Up @@ -129,19 +124,17 @@ mutable struct InferenceState
@assert cache === :no || cache === :local || cache === :global
frame = new(
params, result, linfo,
sp, slottypes, mod, 0,
IdSet{InferenceState}(), IdSet{InferenceState}(),
sp, slottypes, mod, #=currpc=#0,
#=pclimitations=#IdSet{InferenceState}(), #=limitations=#IdSet{InferenceState}(),
src, get_world_counter(interp), valid_worlds,
nargs, s_types, s_edges, stmt_info,
Union{}, ip, 1, n, handler_at,
ssavalue_uses,
Vector{Tuple{InferenceState,LineNum}}(), # cycle_backedges
Vector{InferenceState}(), # callers_in_cycle
#=bestguess=#Union{}, ip, #=pc´´=#1, nstmts, handler_at, ssavalue_uses,
#=cycle_backedges=#Vector{Tuple{InferenceState,LineNum}}(),
#=callers_in_cycle=#Vector{InferenceState}(),
#=parent=#nothing,
cache === :global, false, false,
Effects(consistent, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE,
inbounds_taints_consistency),
method_table(interp),
#=cached=#cache === :global,
#=inferred=#false, #=dont_work_on_me=#false,
#=ipo_effects=#Effects(consistent, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, inbounds_taints_consistency),
interp)
result.result = frame
cache !== :no && push!(get_inference_cache(interp), result)
Expand Down Expand Up @@ -267,8 +260,6 @@ function iterate(unw::InfStackUnwind, (infstate, cyclei)::Tuple{InferenceState,
(infstate::InferenceState, (infstate, cyclei))
end

method_table(interp::AbstractInterpreter, sv::InferenceState) = sv.method_table

function InferenceState(result::InferenceResult, cache::Symbol, interp::AbstractInterpreter)
# prepare an InferenceState object for inferring lambda
src = retrieve_code_info(result.linfo)
Expand Down
7 changes: 7 additions & 0 deletions base/compiler/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@ may_compress(::AbstractInterpreter) = true
may_discard_trees(::AbstractInterpreter) = true
verbose_stmt_info(::AbstractInterpreter) = false

"""
method_table(interp::AbstractInterpreter) -> MethodTableView

Returns a method table this `interp` uses for method lookup.
External `AbstractInterpreter` can optionally return `OverlayMethodTable` here
to incorporate customized dispatches for the overridden methods.
"""
method_table(interp::AbstractInterpreter) = InternalMethodTable(get_world_counter(interp))

"""
Expand Down
2 changes: 1 addition & 1 deletion test/choosetests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function choosetests(choices = [])
filtertests!(tests, "subarray")
filtertests!(tests, "compiler", ["compiler/inference", "compiler/validation",
"compiler/ssair", "compiler/irpasses", "compiler/codegen",
"compiler/inline", "compiler/contextual",
"compiler/inline", "compiler/contextual", "compiler/AbstractInterpreter",
"compiler/EscapeAnalysis/local", "compiler/EscapeAnalysis/interprocedural"])
filtertests!(tests, "compiler/EscapeAnalysis", [
"compiler/EscapeAnalysis/local", "compiler/EscapeAnalysis/interprocedural"])
Expand Down
47 changes: 47 additions & 0 deletions test/compiler/AbstractInterpreter.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

const CC = Core.Compiler
import Core: MethodInstance, CodeInstance
import .CC: WorldRange, WorldView

# define new `AbstractInterpreter` that satisfies the minimum interface requirements
# while managing its cache independently
macro newinterp(name)
cachename = gensym(string(name, "Cache"))
name = esc(name)
quote
struct $cachename
dict::IdDict{MethodInstance,CodeInstance}
end
struct $name <: CC.AbstractInterpreter
interp::CC.NativeInterpreter
cache::$cachename
$name(world = Base.get_world_counter();
interp = CC.NativeInterpreter(world),
cache = $cachename(IdDict{MethodInstance,CodeInstance}())
) = new(interp, cache)
end
CC.InferenceParams(interp::$name) = CC.InferenceParams(interp.interp)
CC.OptimizationParams(interp::$name) = CC.OptimizationParams(interp.interp)
CC.get_world_counter(interp::$name) = CC.get_world_counter(interp.interp)
CC.get_inference_cache(interp::$name) = CC.get_inference_cache(interp.interp)
CC.code_cache(interp::$name) = WorldView(interp.cache, WorldRange(CC.get_world_counter(interp)))
CC.get(wvc::WorldView{<:$cachename}, mi::MethodInstance, default) = get(wvc.cache.dict, mi, default)
CC.getindex(wvc::WorldView{<:$cachename}, mi::MethodInstance) = getindex(wvc.cache.dict, mi)
CC.haskey(wvc::WorldView{<:$cachename}, mi::MethodInstance) = haskey(wvc.cache.dict, mi)
CC.setindex!(wvc::WorldView{<:$cachename}, ci::CodeInstance, mi::MethodInstance) = setindex!(wvc.cache.dict, ci, mi)
end
end

# `OverlayMethodTable`
# --------------------
import Base.Experimental: @MethodTable, @overlay

@newinterp MTOverlayInterp
@MethodTable(OverlayedMT)
CC.method_table(interp::MTOverlayInterp) = CC.OverlayMethodTable(CC.get_world_counter(interp), OverlayedMT)

@overlay OverlayedMT sin(x::Float64) = 1
@test Base.return_types((Int,), MTOverlayInterp()) do x
sin(x)
end == Any[Int]