Skip to content

Commit

Permalink
Merge pull request #33955 from JuliaLang/sf/abstract_interpretation_p…
Browse files Browse the repository at this point in the history
…lumbing

Add `AbstractInterpreter` to parameterize compilation pipeline
  • Loading branch information
Keno authored May 10, 2020
2 parents 8f512f3 + 10b572c commit 65869b1
Show file tree
Hide file tree
Showing 18 changed files with 394 additions and 271 deletions.
147 changes: 75 additions & 72 deletions base/compiler/abstractinterpretation.jl

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions base/compiler/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
# since we won't be able to specialize & infer them at runtime

let fs = Any[typeinf_ext, typeinf, typeinf_edge, pure_eval_call, run_passes],
world = get_world_counter()
world = get_world_counter(),
interp = NativeInterpreter(world)

for x in T_FFUNC_VAL
push!(fs, x[3])
end
Expand All @@ -27,7 +29,7 @@ let fs = Any[typeinf_ext, typeinf, typeinf_edge, pure_eval_call, run_passes],
typ[i] = typ[i].ub
end
end
typeinf_type(m[3], Tuple{typ...}, m[2], Params(world))
typeinf_type(interp, m[3], Tuple{typ...}, m[2])
end
end
end
4 changes: 2 additions & 2 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ using .Sort
# compiler #
############

include("compiler/types.jl")
include("compiler/utilities.jl")
include("compiler/validation.jl")

include("compiler/inferenceresult.jl")
include("compiler/params.jl")
include("compiler/inferencestate.jl")

include("compiler/typeutils.jl")
Expand All @@ -111,7 +111,7 @@ include("compiler/typeinfer.jl")
include("compiler/optimize.jl") # TODO: break this up further + extract utilities

include("compiler/bootstrap.jl")
ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext)
ccall(:jl_set_typeinf_func, Cvoid, (Any,), typeinf_ext_toplevel)

end # baremodule Compiler
))
12 changes: 0 additions & 12 deletions base/compiler/inferenceresult.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@

const EMPTY_VECTOR = Vector{Any}()

mutable struct InferenceResult
linfo::MethodInstance
argtypes::Vector{Any}
overridden_by_const::BitVector
result # ::Type, or InferenceState if WIP
src #::Union{CodeInfo, OptimizationState, Nothing} # if inferred copy is available
function InferenceResult(linfo::MethodInstance, given_argtypes = nothing)
argtypes, overridden_by_const = matching_cache_argtypes(linfo, given_argtypes)
return new(linfo, argtypes, overridden_by_const, Any, nothing)
end
end

function is_argtype_match(@nospecialize(given_argtype),
@nospecialize(cache_argtype),
overridden_by_const::Bool)
Expand Down
18 changes: 9 additions & 9 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const LineNum = Int

mutable struct InferenceState
params::Params # describes how to compute the result
params::InferenceParams
result::InferenceResult # remember where to put the result
linfo::MethodInstance
sptypes::Vector{Any} # types of static parameter
Expand All @@ -13,6 +13,7 @@ mutable struct InferenceState

# info on the state of inference and the linfo
src::CodeInfo
world::UInt
min_valid::UInt
max_valid::UInt
nargs::Int
Expand Down Expand Up @@ -47,7 +48,7 @@ mutable struct InferenceState

# src is assumed to be a newly-allocated CodeInfo, that can be modified in-place to contain intermediate results
function InferenceState(result::InferenceResult, src::CodeInfo,
cached::Bool, params::Params)
cached::Bool, interp::AbstractInterpreter)
linfo = result.linfo
code = src.code::Array{Any,1}
toplevel = !isa(linfo.def, Method)
Expand Down Expand Up @@ -95,9 +96,9 @@ mutable struct InferenceState
max_valid = src.max_world == typemax(UInt) ?
get_world_counter() : src.max_world
frame = new(
params, result, linfo,
InferenceParams(interp), result, linfo,
sp, slottypes, inmodule, 0,
src, min_valid, max_valid,
src, get_world_counter(interp), min_valid, max_valid,
nargs, s_types, s_edges,
Union{}, W, 1, n,
cur_hand, handler_at, n_handlers,
Expand All @@ -108,17 +109,17 @@ mutable struct InferenceState
cached, false, false, false,
IdDict{Any, Tuple{Any, UInt, UInt}}())
result.result = frame
cached && push!(params.cache, result)
cached && push!(get_inference_cache(interp), result)
return frame
end
end

function InferenceState(result::InferenceResult, cached::Bool, params::Params)
function InferenceState(result::InferenceResult, cached::Bool, interp::AbstractInterpreter)
# prepare an InferenceState object for inferring lambda
src = retrieve_code_info(result.linfo)
src === nothing && return nothing
validate_code_in_debug_mode(result.linfo, src, "lowered")
return InferenceState(result, src, cached, params)
return InferenceState(result, src, cached, interp)
end

function sptypes_from_meth_instance(linfo::MethodInstance)
Expand Down Expand Up @@ -195,8 +196,7 @@ _topmod(sv::InferenceState) = _topmod(sv.mod)
function update_valid_age!(min_valid::UInt, max_valid::UInt, sv::InferenceState)
sv.min_valid = max(sv.min_valid, min_valid)
sv.max_valid = min(sv.max_valid, max_valid)
@assert(sv.min_valid <= sv.params.world <= sv.max_valid,
"invalid age range update")
@assert(sv.min_valid <= sv.world <= sv.max_valid, "invalid age range update")
nothing
end

Expand Down
50 changes: 26 additions & 24 deletions base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,38 @@
#####################

mutable struct OptimizationState
params::OptimizationParams
linfo::MethodInstance
calledges::Vector{Any}
src::CodeInfo
mod::Module
nargs::Int
world::UInt
min_valid::UInt
max_valid::UInt
params::Params
sptypes::Vector{Any} # static parameters
slottypes::Vector{Any}
const_api::Bool
# cached results of calling `_methods_by_ftype` from inference, including
# `min_valid` and `max_valid`
matching_methods_cache::IdDict{Any, Tuple{Any, UInt, UInt}}
function OptimizationState(frame::InferenceState)
# TODO: This will be eliminated once optimization no longer needs to do method lookups
interp::AbstractInterpreter
function OptimizationState(frame::InferenceState, params::OptimizationParams, interp::AbstractInterpreter)
s_edges = frame.stmt_edges[1]
if s_edges === nothing
s_edges = []
frame.stmt_edges[1] = s_edges
end
src = frame.src
return new(frame.linfo,
return new(params, frame.linfo,
s_edges::Vector{Any},
src, frame.mod, frame.nargs,
frame.min_valid, frame.max_valid,
frame.params, frame.sptypes, frame.slottypes, false,
frame.matching_methods_cache)
frame.world, frame.min_valid, frame.max_valid,
frame.sptypes, frame.slottypes, false,
frame.matching_methods_cache, interp)
end
function OptimizationState(linfo::MethodInstance, src::CodeInfo,
params::Params)
function OptimizationState(linfo::MethodInstance, src::CodeInfo, params::OptimizationParams, interp::AbstractInterpreter)
# prepare src for running optimization passes
# if it isn't already
nssavalues = src.ssavaluetypes
Expand All @@ -57,19 +59,19 @@ mutable struct OptimizationState
inmodule = linfo.def::Module
nargs = 0
end
return new(linfo,
return new(params, linfo,
s_edges::Vector{Any},
src, inmodule, nargs,
UInt(1), get_world_counter(),
params, sptypes_from_meth_instance(linfo), slottypes, false,
IdDict{Any, Tuple{Any, UInt, UInt}}())
get_world_counter(), UInt(1), get_world_counter(),
sptypes_from_meth_instance(linfo), slottypes, false,
IdDict{Any, Tuple{Any, UInt, UInt}}(), interp)
end
end

function OptimizationState(linfo::MethodInstance, params::Params)
function OptimizationState(linfo::MethodInstance, params::OptimizationParams, interp::AbstractInterpreter)
src = retrieve_code_info(linfo)
src === nothing && return nothing
return OptimizationState(linfo, src, params)
return OptimizationState(linfo, src, params, interp)
end


Expand Down Expand Up @@ -109,7 +111,7 @@ _topmod(sv::OptimizationState) = _topmod(sv.mod)
function update_valid_age!(min_valid::UInt, max_valid::UInt, sv::OptimizationState)
sv.min_valid = max(sv.min_valid, min_valid)
sv.max_valid = min(sv.max_valid, max_valid)
@assert(sv.min_valid <= sv.params.world <= sv.max_valid,
@assert(sv.min_valid <= sv.world <= sv.max_valid,
"invalid age range update")
nothing
end
Expand All @@ -127,10 +129,10 @@ function add_backedge!(li::CodeInstance, caller::OptimizationState)
nothing
end

function isinlineable(m::Method, me::OptimizationState, bonus::Int=0)
function isinlineable(m::Method, me::OptimizationState, params::OptimizationParams, bonus::Int=0)
# compute the cost (size) of inlining this code
inlineable = false
cost_threshold = me.params.inline_cost_threshold
cost_threshold = params.inline_cost_threshold
if m.module === _topmod(m.module)
# a few functions get special treatment
name = m.name
Expand All @@ -145,7 +147,7 @@ function isinlineable(m::Method, me::OptimizationState, bonus::Int=0)
end
end
if !inlineable
inlineable = inline_worthy(me.src.code, me.src, me.sptypes, me.slottypes, me.params, cost_threshold + bonus)
inlineable = inline_worthy(me.src.code, me.src, me.sptypes, me.slottypes, params, cost_threshold + bonus)
end
return inlineable
end
Expand All @@ -168,7 +170,7 @@ function stmt_affects_purity(@nospecialize(stmt), ir)
end

# run the optimization work
function optimize(opt::OptimizationState, @nospecialize(result))
function optimize(opt::OptimizationState, params::OptimizationParams, @nospecialize(result))
def = opt.linfo.def
nargs = Int(opt.nargs) - 1
@timeit "optimizer" ir = run_passes(opt.src, nargs, opt)
Expand Down Expand Up @@ -247,13 +249,13 @@ function optimize(opt::OptimizationState, @nospecialize(result))
else
bonus = 0
if result Tuple && !isbitstype(widenconst(result))
bonus = opt.params.inline_tupleret_bonus
bonus = params.inline_tupleret_bonus
end
if opt.src.inlineable
# For functions declared @inline, increase the cost threshold 20x
bonus += opt.params.inline_cost_threshold*19
bonus += params.inline_cost_threshold*19
end
opt.src.inlineable = isinlineable(def, opt, bonus)
opt.src.inlineable = isinlineable(def, opt, params, bonus)
end
end
nothing
Expand Down Expand Up @@ -282,7 +284,7 @@ plus_saturate(x::Int, y::Int) = max(x, y, x+y)
# known return type
isknowntype(@nospecialize T) = (T === Union{}) || isa(T, Const) || isconcretetype(widenconst(T))

function statement_cost(ex::Expr, line::Int, src::CodeInfo, sptypes::Vector{Any}, slottypes::Vector{Any}, params::Params)
function statement_cost(ex::Expr, line::Int, src::CodeInfo, sptypes::Vector{Any}, slottypes::Vector{Any}, params::OptimizationParams)
head = ex.head
if is_meta_expr_head(head)
return 0
Expand Down Expand Up @@ -372,7 +374,7 @@ function statement_cost(ex::Expr, line::Int, src::CodeInfo, sptypes::Vector{Any}
end

function inline_worthy(body::Array{Any,1}, src::CodeInfo, sptypes::Vector{Any}, slottypes::Vector{Any},
params::Params, cost_threshold::Integer=params.inline_cost_threshold)
params::OptimizationParams, cost_threshold::Integer=params.inline_cost_threshold)
bodycost::Int = 0
for line = 1:length(body)
stmt = body[line]
Expand Down
72 changes: 0 additions & 72 deletions base/compiler/params.jl

This file was deleted.

Loading

2 comments on commit 65869b1

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Executing the daily benchmark build, I will reply here when finished:

@nanosoldier runbenchmarks(ALL, isdaily = true)

@nanosoldier
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. cc @ararslan

Please sign in to comment.