Skip to content

Commit

Permalink
Merge branch 'master' into remove-sort-allblocks
Browse files Browse the repository at this point in the history
  • Loading branch information
LilithHafner authored Sep 4, 2022
2 parents 7193f4e + e1139e7 commit b6aefba
Show file tree
Hide file tree
Showing 30 changed files with 340 additions and 166 deletions.
40 changes: 23 additions & 17 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
for sig_n in splitsigs
result = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, sv)
(; rt, edge, effects) = result
edge !== nothing && push!(edges, edge)
edge === nothing || push!(edges, edge)
this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i]
this_arginfo = ArgInfo(fargs, this_argtypes)
const_call_result = abstract_call_method_with_const_args(interp, result,
Expand All @@ -149,25 +149,11 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
this_conditional = ignorelimited(this_rt)
this_rt = widenwrappedconditional(this_rt)
else
if infer_compilation_signature(interp)
# Also infer the compilation signature for this method, so it's available
# to the compiler in case it ends up needing it (which is likely).
csig = get_compileable_sig(method, sig, match.sparams)
if csig !== nothing && csig !== sig
# The result of this inference is not directly used, so temporarily empty
# the use set for the current SSA value.
saved_uses = sv.ssavalue_uses[sv.currpc]
sv.ssavalue_uses[sv.currpc] = empty_bitset
abstract_call_method(interp, method, csig, match.sparams, multiple_matches, sv)
sv.ssavalue_uses[sv.currpc] = saved_uses
end
end

result = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, sv)
(; rt, edge, effects) = result
this_conditional = ignorelimited(rt)
this_rt = widenwrappedconditional(rt)
edge !== nothing && push!(edges, edge)
edge === nothing || push!(edges, edge)
# try constant propagation with argtypes for this match
# this is in preparation for inlining, or improving the return result
this_argtypes = isa(matches, MethodMatches) ? argtypes : matches.applicable_argtypes[i]
Expand Down Expand Up @@ -226,6 +212,26 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),

rettype = from_interprocedural!(ipo_lattice(interp), rettype, sv, arginfo, conditionals)

# Also considering inferring the compilation signature for this method, so
# it is available to the compiler in case it ends up needing it.
if infer_compilation_signature(interp) && 1 == seen == napplicable && rettype !== Any && rettype !== Union{} && !is_removable_if_unused(all_effects)
match = applicable[1]::MethodMatch
method = match.method
sig = match.spec_types
mi = specialize_method(match; preexisting=true)
if mi !== nothing && !const_prop_methodinstance_heuristic(interp, match, mi::MethodInstance, arginfo, sv)
csig = get_compileable_sig(method, sig, match.sparams)
if csig !== nothing && csig !== sig
# The result of this inference is not directly used, so temporarily empty
# the use set for the current SSA value.
saved_uses = sv.ssavalue_uses[sv.currpc]
sv.ssavalue_uses[sv.currpc] = empty_bitset
abstract_call_method(interp, method, csig, match.sparams, multiple_matches, sv)
sv.ssavalue_uses[sv.currpc] = saved_uses
end
end
end

if call_result_unused(sv) && !(rettype === Bottom)
add_remark!(interp, sv, "Call result type was widened because the return value is unused")
# We're mainly only here because the optimizer might want this code,
Expand Down Expand Up @@ -2244,7 +2250,7 @@ end
function abstract_eval_phi(interp::AbstractInterpreter, phi::PhiNode, vtypes::Union{VarTable, Nothing}, sv::Union{InferenceState, IRCode})
rt = Union{}
for val in phi.values
rt = tmerge(rt, abstract_eval_special_value(interp, val, vtypes, sv))
rt = tmerge(typeinf_lattice(interp), rt, abstract_eval_special_value(interp, val, vtypes, sv))
end
return rt
end
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,9 @@ function bail_out_apply(::AbstractInterpreter, @nospecialize(rt), sv::Union{Infe
end

function any_inbounds(code::Vector{Any})
for i=1:length(code)
for i = 1:length(code)
stmt = code[i]
if isa(stmt, Expr) && stmt.head === :inbounds
if isexpr(stmt, :inbounds)
return true
end
end
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/methodtable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ function _findall(@nospecialize(sig::Type), mt::Union{Nothing,Core.MethodTable},
return MethodLookupResult(ms::Vector{Any}, WorldRange(_min_val[], _max_val[]), _ambig[] != 0)
end

function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=typemax(Int))
function findall(@nospecialize(sig::Type), table::CachedMethodTable; limit::Int=Int(typemax(Int32)))
if isconcretetype(sig)
# as for concrete types, we cache result at on the next level
return findall(sig, table.table; limit)
Expand Down
29 changes: 18 additions & 11 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -812,22 +812,24 @@ function rewrite_apply_exprargs!(
return new_argtypes
end

function compileable_specialization(et::Union{EdgeTracker, Nothing}, match::MethodMatch, effects::Effects)
mi = specialize_method(match; compilesig=true)
function compileable_specialization(et::Union{EdgeTracker, Nothing},
match::MethodMatch, effects::Effects; compilesig_invokes = true)
mi = specialize_method(match; compilesig=compilesig_invokes)
mi === nothing && return nothing
et !== nothing && push!(et, mi)
return InvokeCase(mi, effects)
end

function compileable_specialization(et::Union{EdgeTracker, Nothing}, linfo::MethodInstance, effects::Effects)
mi = specialize_method(linfo.def::Method, linfo.specTypes, linfo.sparam_vals; compilesig=true)
function compileable_specialization(et::Union{EdgeTracker, Nothing},
linfo::MethodInstance, effects::Effects; compilesig_invokes = true)
mi = specialize_method(linfo.def::Method, linfo.specTypes, linfo.sparam_vals; compilesig=compilesig_invokes)
mi === nothing && return nothing
et !== nothing && push!(et, mi)
return InvokeCase(mi, effects)
end

function compileable_specialization(et::Union{EdgeTracker, Nothing}, result::InferenceResult, effects::Effects)
return compileable_specialization(et, result.linfo, effects)
function compileable_specialization(et::Union{EdgeTracker, Nothing}, result::InferenceResult, effects::Effects; kwargs...)
return compileable_specialization(et, result.linfo, effects; kwargs...)
end

function resolve_todo(todo::InliningTodo, state::InliningState, flag::UInt8)
Expand Down Expand Up @@ -866,12 +868,14 @@ function resolve_todo(todo::InliningTodo, state::InliningState, flag::UInt8)
# the duplicated check might have been done already within `analyze_method!`, but still
# we need it here too since we may come here directly using a constant-prop' result
if !state.params.inlining || is_stmt_noinline(flag)
return compileable_specialization(et, match, effects)
return compileable_specialization(et, match, effects;
compilesig_invokes=state.params.compilesig_invokes)
end

src = inlining_policy(state.interp, src, flag, mi, argtypes)

src === nothing && return compileable_specialization(et, match, effects)
src === nothing && return compileable_specialization(et, match, effects;
compilesig_invokes=state.params.compilesig_invokes)

et !== nothing && add_edge!(et, invokesig, mi)
return InliningTodo(mi, retrieve_ir_for_inlining(mi, src), effects)
Expand Down Expand Up @@ -944,7 +948,8 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any}, invokesig,

# See if there exists a specialization for this method signature
mi = specialize_method(match; preexisting=true) # Union{Nothing, MethodInstance}
isa(mi, MethodInstance) || return compileable_specialization(et, match, Effects())
isa(mi, MethodInstance) || return compileable_specialization(et,
match, Effects(); compilesig_invokes=state.params.compilesig_invokes)

todo = InliningTodo(mi, match, argtypes, invokesig)
# If we don't have caches here, delay resolving this MethodInstance
Expand Down Expand Up @@ -1232,7 +1237,8 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
length(info.results) == 1 || return nothing
match = info.results[1]::MethodMatch
match.fully_covers || return nothing
case = compileable_specialization(state.et, match, Effects())
case = compileable_specialization(state.et, match, Effects();
compilesig_invokes=state.params.compilesig_invokes)
case === nothing && return nothing
stmt.head = :invoke_modify
pushfirst!(stmt.args, case.invoke)
Expand Down Expand Up @@ -1449,7 +1455,8 @@ end

function concrete_result_item(result::ConcreteResult, state::InliningState)
if !isdefined(result, :result) || !is_inlineable_constant(result.result)
case = compileable_specialization(state.et, result.mi, result.effects)
case = compileable_specialization(state.et, result.mi, result.effects;
compilesig_invokes = state.params.compilesig_invokes)
@assert case !== nothing "concrete evaluation should never happen for uncompileable callsite"
return case
end
Expand Down
30 changes: 14 additions & 16 deletions base/compiler/ssair/irinterp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function getindex(tpdum::TwoPhaseDefUseMap, idx::Int)
end

function concrete_eval_invoke(interp::AbstractInterpreter, ir::IRCode, mi_cache,
sv::InferenceState, inst::Expr, mi::MethodInstance)
inst::Expr, mi::MethodInstance)
code = get(mi_cache, mi, nothing)
code === nothing && return nothing
argtypes = collect_argtypes(interp, inst.args[2:end], nothing, ir)
Expand All @@ -118,23 +118,20 @@ function concrete_eval_invoke(interp::AbstractInterpreter, ir::IRCode, mi_cache,
catch
return Union{}
end
if is_inlineable_constant(value) || call_result_unused(sv)
# If the constant is not inlineable, still do the const-prop, since the
# code that led to the creation of the Const may be inlineable in the same
# circumstance and may be optimizable.
if is_inlineable_constant(value)
return Const(value)
end
else
ir′ = codeinst_to_ir(interp, code)
if ir′ !== nothing
return ir_abstract_constant_propagation(interp, mi_cache, sv, mi, ir′, argtypes)
return _ir_abstract_constant_propagation(interp, mi_cache, mi, ir′, argtypes)
end
end
return nothing
end

function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::MethodInstance,
mi_cache, sv::InferenceState,
mi_cache,
tpdum::TwoPhaseDefUseMap, idx::Int, bb::Union{Int, Nothing},
@nospecialize(inst), @nospecialize(typ),
phi_revisit::BitSet)
Expand Down Expand Up @@ -195,7 +192,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::Met
elseif inst.head === :invoke
mi′ = inst.args[1]::MethodInstance
if mi′ !== mi # prevent infinite loop
rr = concrete_eval_invoke(interp, ir, mi_cache, sv, inst, mi′)
rr = concrete_eval_invoke(interp, ir, mi_cache, inst, mi′)
if rr !== nothing
if !(typeinf_lattice(interp), typ, rr)
ir.stmts[idx][:type] = rr
Expand All @@ -212,7 +209,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::Met
return false
elseif isa(inst, PiNode)
rr = tmeet(argextype(inst.val, ir), inst.typ)
if !(typ rr)
if !(typeinf_lattice(interp), typ, rr)
ir.stmts[idx][:type] = rr
return true
end
Expand All @@ -225,7 +222,7 @@ function reprocess_instruction!(interp::AbstractInterpreter, ir::IRCode, mi::Met
end

function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache,
frame::InferenceState, mi::MethodInstance, ir::IRCode, argtypes::Vector{Any})
mi::MethodInstance, ir::IRCode, argtypes::Vector{Any}; extra_reprocess = nothing)
argtypes = va_process_argtypes(argtypes, mi)
argtypes_refined = Bool[!(typeinf_lattice(interp), ir.argtypes[i], argtypes[i]) for i = 1:length(argtypes)]
empty!(ir.argtypes)
Expand Down Expand Up @@ -283,7 +280,7 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache
for idx = stmts
inst = ir.stmts[idx][:inst]
typ = ir.stmts[idx][:type]
any_refined = false
any_refined = extra_reprocess === nothing ? false : (idx in extra_reprocess)
for ur in userefs(inst)
val = ur[]
if isa(val, Argument)
Expand All @@ -298,7 +295,7 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache
delete!(ssa_refined, idx)
end
if any_refined && reprocess_instruction!(interp, ir, mi, mi_cache,
frame, tpdum, idx, bb, inst, typ, ssa_refined)
tpdum, idx, bb, inst, typ, ssa_refined)
push!(ssa_refined, idx)
end
if idx == lstmt && process_terminator!(ip, bb, idx)
Expand Down Expand Up @@ -364,7 +361,7 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache
idx = popfirst!(stmt_ip)
inst = ir.stmts[idx][:inst]
typ = ir.stmts[idx][:type]
if reprocess_instruction!(interp, ir, mi, mi_cache, frame,
if reprocess_instruction!(interp, ir, mi, mi_cache,
tpdum, idx, nothing, inst, typ, ssa_refined)
append!(stmt_ip, tpdum[idx])
end
Expand All @@ -380,8 +377,9 @@ function _ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache
end
inst = ir.stmts[idx][:inst]::ReturnNode
rt = argextype(inst.val, ir)
ultimate_rt = tmerge(ultimate_rt, rt)
ultimate_rt = tmerge(typeinf_lattice(interp), ultimate_rt, rt)
end

return ultimate_rt
end

Expand All @@ -390,12 +388,12 @@ function ir_abstract_constant_propagation(interp::AbstractInterpreter, mi_cache,
if __measure_typeinf__[]
inf_frame = Timings.InferenceFrameInfo(mi, frame.world, Any[], Any[], length(ir.argtypes))
Timings.enter_new_timer(inf_frame)
v = _ir_abstract_constant_propagation(interp, mi_cache, frame, mi, ir, argtypes)
v = _ir_abstract_constant_propagation(interp, mi_cache, mi, ir, argtypes)
append!(inf_frame.slottypes, ir.argtypes)
Timings.exit_current_timer(inf_frame)
return v
else
T = _ir_abstract_constant_propagation(interp, mi_cache, frame, mi, ir, argtypes)
T = _ir_abstract_constant_propagation(interp, mi_cache, mi, ir, argtypes)
return T
end
end
2 changes: 1 addition & 1 deletion base/compiler/ssair/show.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

# This file is not loaded into `Core.Compiler` but rather loaded into the context of
# This file is not loaded into `Core.Compiler` but rather loaded into the context of
# `Base.IRShow` and thus does not participate in bootstrapping.

@nospecialize
Expand Down
3 changes: 3 additions & 0 deletions base/compiler/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct OptimizationParams
inline_tupleret_bonus::Int # extra inlining willingness for non-concrete tuple return types (in hopes of splitting it up)
inline_error_path_cost::Int # cost of (un-optimized) calls in blocks that throw

compilesig_invokes::Bool
trust_inference::Bool

# Duplicating for now because optimizer inlining requires it.
Expand All @@ -77,6 +78,7 @@ struct OptimizationParams
max_methods::Int = 3,
tuple_splat::Int = 32,
union_splitting::Int = 4,
compilesig_invokes::Bool = true,
trust_inference::Bool = false
)
return new(
Expand All @@ -85,6 +87,7 @@ struct OptimizationParams
inline_nonleaf_penalty,
inline_tupleret_bonus,
inline_error_path_cost,
compilesig_invokes,
trust_inference,
max_methods,
tuple_splat,
Expand Down
Loading

0 comments on commit b6aefba

Please sign in to comment.