Skip to content

Commit

Permalink
compiler: setup CallInfo interface type
Browse files Browse the repository at this point in the history
This commit defines new `CallInfo` abstract type that is supposed to be
interfaced by all callinfos like `MethodMatchInfo`.
Actual interface features will be added in follow commits.
  • Loading branch information
aviatesk committed Oct 4, 2022
1 parent 70604d7 commit e15304a
Show file tree
Hide file tree
Showing 14 changed files with 107 additions and 102 deletions.
52 changes: 26 additions & 26 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
# which is all that's required for :consistent-cy. Of course, we don't
# know anything else about this statement.
effects = Effects(; consistent=ALWAYS_TRUE, nonoverlayed)
return CallMeta(Any, effects, false)
return CallMeta(Any, effects, NoCallInfo())
end

argtypes = arginfo.argtypes
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)
return CallMeta(Any, Effects(), false)
return CallMeta(Any, Effects(), NoCallInfo())
end

(; valid_worlds, applicable, info) = matches
Expand Down Expand Up @@ -220,7 +220,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
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)
if mi !== nothing && !const_prop_methodinstance_heuristic(interp, match, mi, arginfo, sv)
csig = get_compileable_sig(method, sig, match.sparams)
if csig !== nothing && csig !== sig
abstract_call_method(interp, method, csig, match.sparams, multiple_matches, StmtInfo(false), sv)
Expand Down Expand Up @@ -1385,15 +1385,15 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, si::
max_methods::Int = get_max_methods(sv.mod, interp))
itft = argtype_by_index(argtypes, 2)
aft = argtype_by_index(argtypes, 3)
(itft === Bottom || aft === Bottom) && return CallMeta(Bottom, EFFECTS_THROWS, false)
(itft === Bottom || aft === Bottom) && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
aargtypes = argtype_tail(argtypes, 4)
aftw = widenconst(aft)
if !isa(aft, Const) && !isa(aft, PartialOpaque) && (!isType(aftw) || has_free_typevars(aftw))
if !isconcretetype(aftw) || (aftw <: Builtin)
add_remark!(interp, sv, "Core._apply_iterate called on a function of a non-concrete type")
# bail now, since it seems unlikely that abstract_call will be able to do any better after splitting
# this also ensures we don't call abstract_call_gf_by_type below on an IntrinsicFunction or Builtin
return CallMeta(Any, Effects(), false)
return CallMeta(Any, Effects(), NoCallInfo())
end
end
res = Union{}
Expand Down Expand Up @@ -1468,7 +1468,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, si::
if bail_out_apply(interp, res, sv)
if i != length(ctypes)
# No point carrying forward the info, we're not gonna inline it anyway
retinfo = false
retinfo = NoCallInfo()
end
break
end
Expand Down Expand Up @@ -1668,21 +1668,21 @@ end
function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, si::StmtInfo, sv::InferenceState)
ft′ = argtype_by_index(argtypes, 2)
ft = widenconst(ft′)
ft === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, false)
ft === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
(types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3))
types === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, false)
isexact || return CallMeta(Any, Effects(), false)
types === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
isexact || return CallMeta(Any, Effects(), NoCallInfo())
argtype = argtypes_to_type(argtype_tail(argtypes, 4))
nargtype = typeintersect(types, argtype)
nargtype === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, false)
nargtype isa DataType || return CallMeta(Any, Effects(), false) # other cases are not implemented below
isdispatchelem(ft) || return CallMeta(Any, Effects(), false) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
nargtype === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo())
nargtype isa DataType || return CallMeta(Any, Effects(), NoCallInfo()) # other cases are not implemented below
isdispatchelem(ft) || return CallMeta(Any, Effects(), NoCallInfo()) # check that we might not have a subtype of `ft` at runtime, before doing supertype lookup below
ft = ft::DataType
lookupsig = rewrap_unionall(Tuple{ft, unwrap_unionall(types).parameters...}, types)::Type
nargtype = Tuple{ft, nargtype.parameters...}
argtype = Tuple{ft, argtype.parameters...}
match, valid_worlds, overlayed = findsup(lookupsig, method_table(interp))
match === nothing && return CallMeta(Any, Effects(), false)
match === nothing && return CallMeta(Any, Effects(), NoCallInfo())
update_valid_age!(sv, valid_worlds)
method = match.method
tienv = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector
Expand Down Expand Up @@ -1728,7 +1728,7 @@ function abstract_finalizer(interp::AbstractInterpreter, argtypes::Vector{Any},
call = abstract_call(interp, ArgInfo(nothing, finalizer_argvec), StmtInfo(false), sv, 1)
return CallMeta(Nothing, Effects(), FinalizerInfo(call.info, call.effects))
end
return CallMeta(Nothing, Effects(), false)
return CallMeta(Nothing, Effects(), NoCallInfo())
end

# call where the function is known exactly
Expand All @@ -1750,10 +1750,10 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
end
rt = abstract_call_builtin(interp, f, arginfo, sv, max_methods)
effects = builtin_effects(typeinf_lattice(interp), f, argtypes[2:end], rt)
return CallMeta(rt, effects, false)
return CallMeta(rt, effects, NoCallInfo())
elseif isa(f, Core.OpaqueClosure)
# calling an OpaqueClosure about which we have no information returns no information
return CallMeta(Any, Effects(), false)
return CallMeta(Any, Effects(), NoCallInfo())
elseif f === Core.kwfunc
if la == 2
aty = argtypes[2]
Expand All @@ -1764,11 +1764,11 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
end
end
end
return CallMeta(Any, EFFECTS_UNKNOWN, false)
return CallMeta(Any, EFFECTS_UNKNOWN, NoCallInfo())
elseif f === TypeVar
# Manually look through the definition of TypeVar to
# make sure to be able to get `PartialTypeVar`s out.
(la < 2 || la > 4) && return CallMeta(Union{}, EFFECTS_UNKNOWN, false)
(la < 2 || la > 4) && return CallMeta(Union{}, EFFECTS_UNKNOWN, NoCallInfo())
n = argtypes[2]
ub_var = Const(Any)
lb_var = Const(Union{})
Expand All @@ -1778,14 +1778,14 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
elseif la == 3
ub_var = argtypes[3]
end
return CallMeta(typevar_tfunc(n, lb_var, ub_var), EFFECTS_UNKNOWN, false)
return CallMeta(typevar_tfunc(n, lb_var, ub_var), EFFECTS_UNKNOWN, NoCallInfo())
elseif f === UnionAll
return CallMeta(abstract_call_unionall(argtypes), EFFECTS_UNKNOWN, false)
return CallMeta(abstract_call_unionall(argtypes), EFFECTS_UNKNOWN, NoCallInfo())
elseif f === Tuple && la == 2
aty = argtypes[2]
ty = isvarargtype(aty) ? unwrapva(aty) : widenconst(aty)
if !isconcretetype(ty)
return CallMeta(Tuple, EFFECTS_UNKNOWN, false)
return CallMeta(Tuple, EFFECTS_UNKNOWN, NoCallInfo())
end
elseif is_return_type(f)
return return_type_tfunc(interp, argtypes, si, sv)
Expand All @@ -1800,11 +1800,11 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
# mark !== as exactly a negated call to ===
rty = abstract_call_known(interp, (===), arginfo, si, sv, max_methods).rt
if isa(rty, Conditional)
return CallMeta(Conditional(rty.slot, rty.elsetype, rty.thentype), EFFECTS_TOTAL, false) # swap if-else
return CallMeta(Conditional(rty.slot, rty.elsetype, rty.thentype), EFFECTS_TOTAL, NoCallInfo()) # swap if-else
elseif isa(rty, Const)
return CallMeta(Const(rty.val === false), EFFECTS_TOTAL, MethodResultPure())
end
return CallMeta(rty, EFFECTS_TOTAL, false)
return CallMeta(rty, EFFECTS_TOTAL, NoCallInfo())
elseif la == 3 && istopfunction(f, :(>:))
# mark issupertype as a exact alias for issubtype
# swap T1 and T2 arguments and call <:
Expand All @@ -1814,7 +1814,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
fargs = nothing
end
argtypes = Any[typeof(<:), argtypes[3], argtypes[2]]
return CallMeta(abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods).rt, EFFECTS_TOTAL, false)
return CallMeta(abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods).rt, EFFECTS_TOTAL, NoCallInfo())
elseif la == 2 &&
(a2 = argtypes[2]; isa(a2, Const)) && (svecval = a2.val; isa(svecval, SimpleVector)) &&
istopfunction(f, :length)
Expand Down Expand Up @@ -1896,13 +1896,13 @@ function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, si::StmtIn
return abstract_call_opaque_closure(interp,
ft, ArgInfo(arginfo.fargs, newargtypes), si, sv, #=check=#true)
elseif (uft = unwrap_unionall(widenconst(ft)); isa(uft, DataType) && uft.name === typename(Core.OpaqueClosure))
return CallMeta(rewrap_unionall((uft::DataType).parameters[2], widenconst(ft)), Effects(), false)
return CallMeta(rewrap_unionall((uft::DataType).parameters[2], widenconst(ft)), Effects(), NoCallInfo())
elseif f === nothing
# non-constant function, but the number of arguments is known
# and the ft is not a Builtin or IntrinsicFunction
if hasintersect(widenconst(ft), Union{Builtin, Core.OpaqueClosure})
add_remark!(interp, sv, "Could not identify method table for call")
return CallMeta(Any, Effects(), false)
return CallMeta(Any, Effects(), NoCallInfo())
end
max_methods = max_methods === nothing ? get_max_methods(sv.mod, interp) : max_methods
return abstract_call_gf_by_type(interp, nothing, arginfo, si, argtypes_to_type(argtypes), sv, max_methods)
Expand Down
4 changes: 2 additions & 2 deletions base/compiler/inferencestate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ mutable struct InferenceState
bb_vartables::Vector{Union{Nothing,VarTable}} # nothing if not analyzed yet
ssavaluetypes::Vector{Any}
stmt_edges::Vector{Union{Nothing,Vector{Any}}}
stmt_info::Vector{Any}
stmt_info::Vector{CallInfo}

#= intermediate states for interprocedural abstract interpretation =#
pclimitations::IdSet{InferenceState} # causes of precision restrictions (LimitedAccuracy) on currpc ssavalue
Expand Down Expand Up @@ -152,7 +152,7 @@ mutable struct InferenceState
ssavalue_uses = find_ssavalue_uses(code, nssavalues)
nstmts = length(code)
stmt_edges = Union{Nothing, Vector{Any}}[ nothing for i = 1:nstmts ]
stmt_info = Any[ nothing for i = 1:nstmts ]
stmt_info = CallInfo[ NoCallInfo() for i = 1:nstmts ]

nslots = length(src.slotflags)
slottypes = Vector{Any}(undef, nslots)
Expand Down
8 changes: 4 additions & 4 deletions base/compiler/optimize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ mutable struct OptimizationState
linfo::MethodInstance
src::CodeInfo
ir::Union{Nothing, IRCode}
stmt_info::Vector{Any}
stmt_info::Vector{CallInfo}
mod::Module
sptypes::Vector{Any} # static parameters
slottypes::Vector{Any}
Expand Down Expand Up @@ -146,7 +146,7 @@ mutable struct OptimizationState
if slottypes === nothing
slottypes = Any[ Any for i = 1:nslots ]
end
stmt_info = Any[nothing for i = 1:nssavalues]
stmt_info = CallInfo[ NoCallInfo() for i = 1:nssavalues ]
# cache some useful state computations
def = linfo.def
mod = isa(def, Method) ? def.module : def
Expand Down Expand Up @@ -598,7 +598,7 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
insert!(code, idx, Expr(:code_coverage_effect))
insert!(codelocs, idx, codeloc)
insert!(ssavaluetypes, idx, Nothing)
insert!(stmtinfo, idx, nothing)
insert!(stmtinfo, idx, NoCallInfo())
insert!(ssaflags, idx, IR_FLAG_NULL)
if ssachangemap === nothing
ssachangemap = fill(0, nstmts)
Expand All @@ -619,7 +619,7 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState)
insert!(code, idx + 1, ReturnNode())
insert!(codelocs, idx + 1, codelocs[idx])
insert!(ssavaluetypes, idx + 1, Union{})
insert!(stmtinfo, idx + 1, nothing)
insert!(stmtinfo, idx + 1, NoCallInfo())
insert!(ssaflags, idx + 1, ssaflags[idx])
if ssachangemap === nothing
ssachangemap = fill(0, nstmts)
Expand Down
2 changes: 1 addition & 1 deletion base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ function escape_call!(astate::AnalysisState, pc::Int, args::Vector{Any}, callinf
# now cascade to the builtin handling
escape_call!(astate, pc, args)
return
elseif isa(info, CallInfo)
elseif isa(info, EACallInfo)
for linfo in info.linfos
escape_invoke!(astate, pc, args, linfo, 1)
end
Expand Down
27 changes: 14 additions & 13 deletions base/compiler/ssair/EscapeAnalysis/interprocedural.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
# TODO this file contains many duplications with the inlining analysis code, factor them out

import Core.Compiler:
MethodInstance, InferenceResult, Signature, ConstPropResult, ConcreteResult, SemiConcreteResult,
MethodResultPure, MethodMatchInfo, UnionSplitInfo, ConstCallInfo, InvokeCallInfo,
call_sig, argtypes_to_type, is_builtin, is_return_type, istopfunction, validate_sparams,
specialize_method, invoke_rewrite
MethodInstance, InferenceResult, Signature, ConstPropResult, ConcreteResult,
SemiConcreteResult, CallInfo, NoCallInfo, MethodResultPure, MethodMatchInfo,
UnionSplitInfo, ConstCallInfo, InvokeCallInfo,
call_sig, argtypes_to_type, is_builtin, is_return_type, istopfunction,
validate_sparams, specialize_method, invoke_rewrite

const Linfo = Union{MethodInstance,InferenceResult}
struct CallInfo
struct EACallInfo
linfos::Vector{Linfo}
nothrow::Bool
end

function resolve_call(ir::IRCode, stmt::Expr, @nospecialize(info))
function resolve_call(ir::IRCode, stmt::Expr, @nospecialize(info::CallInfo))
sig = call_sig(ir, stmt)
if sig === nothing
return missing
Expand All @@ -36,7 +37,7 @@ function resolve_call(ir::IRCode, stmt::Expr, @nospecialize(info))
end
if info isa MethodResultPure
return true
elseif info === false
elseif info === NoCallInfo
return missing
end
# TODO handle OpaqueClosureCallInfo
Expand All @@ -63,16 +64,16 @@ function analyze_invoke_call(sig::Signature, info::InvokeCallInfo)
end
result = info.result
if isa(result, ConstPropResult)
return CallInfo(Linfo[result.result], true)
return EACallInfo(Linfo[result.result], true)
elseif isa(result, ConcreteResult)
return CallInfo(Linfo[result.mi], true)
return EACallInfo(Linfo[result.mi], true)
elseif isa(result, SemiConcreteResult)
return CallInfo(Linfo[result.mi], true)
return EACallInfo(Linfo[result.mi], true)
else
argtypes = invoke_rewrite(sig.argtypes)
mi = analyze_match(match, length(argtypes))
mi === nothing && return missing
return CallInfo(Linfo[mi], true)
return EACallInfo(Linfo[mi], true)
end
end

Expand Down Expand Up @@ -110,7 +111,7 @@ function analyze_const_call(sig::Signature, cinfo::ConstCallInfo)
nothrow &= match.fully_covers
end
end
return CallInfo(linfos, nothrow)
return EACallInfo(linfos, nothrow)
end

function analyze_call(sig::Signature, infos::Vector{MethodMatchInfo})
Expand All @@ -133,7 +134,7 @@ function analyze_call(sig::Signature, infos::Vector{MethodMatchInfo})
nothrow &= match.fully_covers
end
end
return CallInfo(linfos, nothrow)
return EACallInfo(linfos, nothrow)
end

function analyze_match(match::MethodMatch, npassedargs::Int)
Expand Down
10 changes: 5 additions & 5 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ function ir_inline_unionsplit!(compact::IncrementalCompact, idx::Int,
elseif isa(case, InvokeCase)
inst = Expr(:invoke, case.invoke, argexprs′...)
flag = flags_for_effects(case.effects)
val = insert_node_here!(compact, NewInstruction(inst, typ, nothing, line, flag, true))
val = insert_node_here!(compact, NewInstruction(inst, typ, NoCallInfo(), line, flag, true))
else
case = case::ConstantCase
val = case.val
Expand Down Expand Up @@ -1138,14 +1138,14 @@ function inline_apply!(
if isa(info, UnionSplitApplyCallInfo)
if length(info.infos) != 1
# TODO: Handle union split applies?
new_info = info = false
new_info = info = NoCallInfo()
else
info = info.infos[1]
new_info = info.call
end
else
@assert info === nothing || info === false
new_info = info = false
@assert info === NoCallInfo()
new_info = info = NoCallInfo()
end
arg_start = 3
argtypes = sig.argtypes
Expand Down Expand Up @@ -1688,7 +1688,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
inline_const_if_inlineable!(ir[SSAValue(idx)]) && continue
info = info.info
end
if info === false
if info === NoCallInfo()
# Inference determined this couldn't be analyzed. Don't question it.
continue
end
Expand Down
Loading

0 comments on commit e15304a

Please sign in to comment.