Skip to content

Commit

Permalink
WIP: Semi-concrete IR interpreter
Browse files Browse the repository at this point in the history
Co-authored-by: Ian Atol <ian.atol@juliacomputing.com>
Co-authored-by: Shuhei Kadowaki <aviatesk@gmail.com>
  • Loading branch information
3 people committed Jul 22, 2022
1 parent 46a6f22 commit 291cad3
Show file tree
Hide file tree
Showing 17 changed files with 708 additions and 96 deletions.
234 changes: 156 additions & 78 deletions base/compiler/abstractinterpretation.jl

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ include("compiler/ssair/ir.jl")
include("compiler/inferenceresult.jl")
include("compiler/inferencestate.jl")

include("compiler/ssair/basicblock.jl")
include("compiler/ssair/domtree.jl")
include("compiler/ssair/ir.jl")

include("compiler/typeutils.jl")
include("compiler/typelimits.jl")
include("compiler/typelattice.jl")
Expand All @@ -164,7 +168,7 @@ include("compiler/stmtinfo.jl")

include("compiler/abstractinterpretation.jl")
include("compiler/typeinfer.jl")
include("compiler/optimize.jl") # TODO: break this up further + extract utilities
include("compiler/optimize.jl")

# required for bootstrap because sort.jl uses extrema
# to decide whether to dispatch to counting sort.
Expand Down
30 changes: 30 additions & 0 deletions base/compiler/inferenceresult.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,36 @@ function is_forwardable_argtype(@nospecialize x)
isa(x, PartialOpaque)
end

function va_process_argtypes(given_argtypes::Vector{Any}, mi::MethodInstance,
condargs::Union{Vector{Tuple{Int,Int}}, Nothing}=nothing)
isva = mi.def.isva
nargs = Int(mi.def.nargs)
if isva || isvarargtype(given_argtypes[end])
isva_given_argtypes = Vector{Any}(undef, nargs)
for i = 1:(nargs - isva)
isva_given_argtypes[i] = argtype_by_index(given_argtypes, i)
end
if isva
if length(given_argtypes) < nargs && isvarargtype(given_argtypes[end])
last = length(given_argtypes)
else
last = nargs
end
isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[last:end])
# invalidate `Conditional` imposed on varargs
if condargs !== nothing
for (slotid, i) in condargs
if slotid last
isva_given_argtypes[i] = widenconditional(isva_given_argtypes[i])
end
end
end
end
return isva_given_argtypes
end
return given_argtypes
end

# In theory, there could be a `cache` containing a matching `InferenceResult`
# for the provided `linfo` and `given_argtypes`. The purpose of this function is
# to return a valid value for `cache_lookup(linfo, argtypes, cache).argtypes`,
Expand Down
6 changes: 6 additions & 0 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ function in(idx::Int, bsbmp::BitSetBoundedMinPrioritySet)
return idx in bsbmp.elems
end

function append!(bsbmp::BitSetBoundedMinPrioritySet, itr)
for val in itr
push!(bsbmp, val)
end
end

mutable struct InferenceState
#= information about this method instance =#
linfo::MethodInstance
Expand Down
3 changes: 2 additions & 1 deletion base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import Core.Compiler: # Core.Compiler specific definitions
isbitstype, isexpr, is_meta_expr_head, println, widenconst, argextype, singleton_type,
fieldcount_noerror, try_compute_field, try_compute_fieldidx, hasintersect, ,
intrinsic_nothrow, array_builtin_common_typecheck, arrayset_typecheck,
setfield!_nothrow, alloc_array_ndims, check_effect_free!
setfield!_nothrow, alloc_array_ndims, stmt_effect_free, check_effect_free!,
SemiConcreteResult

include(x) = _TOP_MOD.include(@__MODULE__, x)
if _TOP_MOD === Core.Compiler
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/ssair/EscapeAnalysis/interprocedural.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Core.Compiler:
call_sig, argtypes_to_type, is_builtin, is_return_type, istopfunction, validate_sparams,
specialize_method, invoke_rewrite

const Linfo = Union{MethodInstance,InferenceResult}
const Linfo = Union{MethodInstance,InferenceResult,SemiConcreteResult}
struct CallInfo
linfos::Vector{Linfo}
nothrow::Bool
Expand Down
1 change: 1 addition & 0 deletions base/compiler/ssair/driver.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ include("compiler/ssair/verify.jl")
include("compiler/ssair/legacy.jl")
include("compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl")
include("compiler/ssair/passes.jl")
include("compiler/ssair/irinterp.jl")
21 changes: 17 additions & 4 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ function inline_invoke!(
end
result = info.result
if isa(result, ConcreteResult)
item = concrete_result_item(result, state)
item = const_result_item(result, state)
else
argtypes = invoke_rewrite(sig.argtypes)
if isa(result, ConstPropResult)
Expand Down Expand Up @@ -1280,10 +1280,14 @@ function compute_inlining_cases(info::ConstCallInfo,
result = results[j]
any_fully_covered |= match.fully_covers
if isa(result, ConcreteResult)
case = concrete_result_item(result, state)
case = const_result_item(result, state)
push!(cases, InliningCase(result.mi.specTypes, case))
elseif isa(result, ConstPropResult)
handled_all_cases &= handle_const_prop_result!(result, argtypes, flag, state, cases, true)
elseif isa(result, InferenceResult)
handled_all_cases &= handle_inf_result!(result, argtypes, flag, state, cases, true)
elseif isa(result, SemiConcreteResult)
handled_all_cases &= handle_semi_concrete_result!(result, cases, true)
else
@assert result === nothing
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true)
Expand Down Expand Up @@ -1347,7 +1351,16 @@ function handle_const_prop_result!(
return true
end

function concrete_result_item(result::ConcreteResult, state::InliningState)
function handle_semi_concrete_result!(result::SemiConcreteResult, cases::Vector{InliningCase}, allow_abstract::Bool = false)
mi = result.mi
spec_types = mi.specTypes
allow_abstract || isdispatchtuple(spec_types) || return false
validate_sparams(mi.sparam_vals) || return false
push!(cases, InliningCase(spec_types, InliningTodo(mi, result.ir, result.effects)))
return true
end

function const_result_item(result::ConstResult, state::InliningState)
if !isdefined(result, :result) || !is_inlineable_constant(result.result)
case = compileable_specialization(state.et, result.mi, result.effects)
@assert case !== nothing "concrete evaluation should never happen for uncompileable callsite"
Expand Down Expand Up @@ -1474,7 +1487,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
sig, state, todo)
else
if isa(result, ConcreteResult)
item = concrete_result_item(result, state)
item = const_result_item(result, state)
else
item = analyze_method!(info.match, sig.argtypes, flag, state)
end
Expand Down
11 changes: 9 additions & 2 deletions base/compiler/ssair/ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1053,15 +1053,22 @@ function renumber_ssa2!(@nospecialize(stmt), ssanums::Vector{Any}, used_ssas::Ve
end

# Used in inlining before we start compacting - Only works at the CFG level
function kill_edge!(bbs::Vector{BasicBlock}, from::Int, to::Int)
function kill_edge!(bbs::Vector{BasicBlock}, from::Int, to::Int, callback=nothing)
preds, succs = bbs[to].preds, bbs[from].succs
deleteat!(preds, findfirst(x->x === from, preds)::Int)
deleteat!(succs, findfirst(x->x === to, succs)::Int)
if length(preds) == 0
for succ in copy(bbs[to].succs)
kill_edge!(bbs, to, succ)
kill_edge!(bbs, to, succ, callback)
end
end
if callback !== nothing
callback(from, to)
end
end

function kill_edge!(ir::IRCode, from::Int, to::Int, callback=nothing)
kill_edge!(ir.cfg.blocks, from, to, callback)
end

# N.B.: from and to are non-renamed indices
Expand Down
Loading

0 comments on commit 291cad3

Please sign in to comment.