diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index b9fba9af104f1c..102bf190067b03 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -72,7 +72,7 @@ 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 @@ -80,7 +80,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), 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 @@ -219,7 +219,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 # The result of this inference is not directly used, so temporarily empty @@ -1388,7 +1388,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:: 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)) @@ -1396,7 +1396,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:: 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{} @@ -1471,7 +1471,7 @@ function abstract_apply(interp::AbstractInterpreter, argtypes::Vector{Any}, sv:: 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 @@ -1671,21 +1671,21 @@ end function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, 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 @@ -1731,7 +1731,7 @@ function abstract_finalizer(interp::AbstractInterpreter, argtypes::Vector{Any}, call = abstract_call(interp, ArgInfo(nothing, finalizer_argvec), 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 @@ -1753,10 +1753,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] @@ -1767,11 +1767,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{}) @@ -1781,14 +1781,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, sv) @@ -1803,11 +1803,11 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f), # mark !== as exactly a negated call to === rty = abstract_call_known(interp, (===), arginfo, 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 <: @@ -1817,7 +1817,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), sv, max_methods).rt, EFFECTS_TOTAL, false) + return CallMeta(abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), 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) @@ -1899,13 +1899,13 @@ function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, return abstract_call_opaque_closure(interp, ft, ArgInfo(arginfo.fargs, newargtypes), 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, argtypes_to_type(argtypes), sv, max_methods) diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index e1d20f01042c47..6f759475e144bc 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -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 @@ -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) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 3f0f7e45226540..010aaa96c3d1d4 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -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} @@ -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 @@ -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) @@ -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) diff --git a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl index a60cfde597f4c6..8666a837c1c8ff 100644 --- a/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl +++ b/base/compiler/ssair/EscapeAnalysis/EscapeAnalysis.jl @@ -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 diff --git a/base/compiler/ssair/EscapeAnalysis/interprocedural.jl b/base/compiler/ssair/EscapeAnalysis/interprocedural.jl index dcbc37df84635c..74a43e9b9ec8ec 100644 --- a/base/compiler/ssair/EscapeAnalysis/interprocedural.jl +++ b/base/compiler/ssair/EscapeAnalysis/interprocedural.jl @@ -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 @@ -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 @@ -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 @@ -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}) @@ -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) diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index 6508d320e09109..b26ffd0d670903 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -1091,14 +1091,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 @@ -1618,7 +1618,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 diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index a8c832f2ba09a8..ab46e648dd996a 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -188,15 +188,15 @@ const AnySSAValue = Union{SSAValue, OldSSAValue, NewSSAValue} struct InstructionStream inst::Vector{Any} type::Vector{Any} - info::Vector{Any} + info::Vector{CallInfo} line::Vector{Int32} flag::Vector{UInt8} end function InstructionStream(len::Int) - insts = Array{Any}(undef, len) - types = Array{Any}(undef, len) - info = Array{Any}(undef, len) - fill!(info, nothing) + insts = Vector{Any}(undef, len) + types = Vector{Any}(undef, len) + info = Vector{CallInfo}(undef, len) + fill!(info, NoCallInfo()) lines = fill(Int32(0), len) flags = fill(IR_FLAG_NULL, len) return InstructionStream(insts, types, info, lines, flags) @@ -227,7 +227,7 @@ function resize!(stmts::InstructionStream, len) for i in (old_length + 1):len stmts.line[i] = 0 stmts.flag[i] = IR_FLAG_NULL - stmts.info[i] = nothing + stmts.info[i] = NoCallInfo() end return stmts end diff --git a/base/compiler/ssair/irinterp.jl b/base/compiler/ssair/irinterp.jl index 0270f9ba34b06c..d4d8294eac8bb7 100644 --- a/base/compiler/ssair/irinterp.jl +++ b/base/compiler/ssair/irinterp.jl @@ -119,7 +119,7 @@ end function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), arginfo::ArgInfo, @nospecialize(atype), sv::IRCode, max_methods::Int) - return CallMeta(Any, Effects(), false) + return CallMeta(Any, Effects(), NoCallInfo()) end function collect_limitations!(@nospecialize(typ), ::IRCode) diff --git a/base/compiler/ssair/legacy.jl b/base/compiler/ssair/legacy.jl index f8fce66bde49c7..4a8e299179ecbf 100644 --- a/base/compiler/ssair/legacy.jl +++ b/base/compiler/ssair/legacy.jl @@ -39,7 +39,7 @@ function inflate_ir!(ci::CodeInfo, sptypes::Vector{Any}, argtypes::Vector{Any}) if !isa(ssavaluetypes, Vector{Any}) ssavaluetypes = Any[ Any for i = 1:ssavaluetypes::Int ] end - info = Any[nothing for i = 1:nstmts] + info = CallInfo[NoCallInfo() for i = 1:nstmts] stmts = InstructionStream(code, ssavaluetypes, info, ci.codelocs, ci.ssaflags) linetable = ci.linetable if !isa(linetable, Vector{LineInfoNode}) diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 48dea77539111f..d572db2e161fce 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -1116,7 +1116,7 @@ end function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse::SSADefUse, inlining::InliningState, lazydomtree::LazyDomtree, - lazypostdomtree::LazyPostDomtree, info::Union{FinalizerInfo, Nothing}) + lazypostdomtree::LazyPostDomtree, @nospecialize(info::CallInfo)) # For now, require that: # 1. The allocation dominates the finalizer registration # 2. The finalizer registration dominates all uses reachable from the @@ -1212,7 +1212,7 @@ function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse finalizer_stmt = ir[SSAValue(finalizer_idx)][:inst] argexprs = Any[finalizer_stmt.args[2], finalizer_stmt.args[3]] - flags = info === nothing ? UInt8(0) : flags_for_effects(info.effects) + flags = info isa FinalizerInfo ? flags_for_effects(info.effects) : IR_FLAG_NULL if length(finalizer_stmt.args) >= 4 inline = finalizer_stmt.args[4] if inline === nothing diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index 6a9a128104b30f..694333156753ac 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -172,7 +172,7 @@ function rename_uses!(ir::IRCode, ci::CodeInfo, idx::Int, @nospecialize(stmt), r return fixemup!(stmt->true, stmt->renames[slot_id(stmt)], ir, ci, idx, stmt) end -function strip_trailing_junk!(ci::CodeInfo, code::Vector{Any}, info::Vector{Any}) +function strip_trailing_junk!(ci::CodeInfo, code::Vector{Any}, info::Vector{CallInfo}) # Remove `nothing`s at the end, we don't handle them well # (we expect the last instruction to be a terminator) ssavaluetypes = ci.ssavaluetypes::Vector{Any} @@ -194,7 +194,7 @@ function strip_trailing_junk!(ci::CodeInfo, code::Vector{Any}, info::Vector{Any} push!(code, ReturnNode()) push!(ssavaluetypes, Union{}) push!(codelocs, 0) - push!(info, nothing) + push!(info, NoCallInfo()) push!(ssaflags, IR_FLAG_NULL) end nothing diff --git a/base/compiler/stmtinfo.jl b/base/compiler/stmtinfo.jl index 966ee32338b481..1fe64103a3f202 100644 --- a/base/compiler/stmtinfo.jl +++ b/base/compiler/stmtinfo.jl @@ -11,23 +11,25 @@ and any additional information (`call.info`) for a given generic call. struct CallMeta rt::Any effects::Effects - info::Any + info::CallInfo end +struct NoCallInfo <: CallInfo end + """ - info::MethodMatchInfo + info::MethodMatchInfo <: CallInfo Captures the result of a `:jl_matching_methods` lookup for the given call (`info.results`). This info may then be used by the optimizer to inline the matches, without having to re-consult the method table. This info is illegal on any statement that is not a call to a generic function. """ -struct MethodMatchInfo +struct MethodMatchInfo <: CallInfo results::MethodLookupResult end """ - info::UnionSplitInfo + info::UnionSplitInfo <: CallInfo If inference decides to partition the method search space by splitting unions, it will issue a method lookup query for each such partition. This info indicates @@ -35,7 +37,7 @@ that such partitioning happened and wraps the corresponding `MethodMatchInfo` fo each partition (`info.matches::Vector{MethodMatchInfo}`). This info is illegal on any statement that is not a call to a generic function. """ -struct UnionSplitInfo +struct UnionSplitInfo <: CallInfo matches::Vector{MethodMatchInfo} end @@ -69,37 +71,37 @@ end const ConstResult = Union{ConstPropResult,ConcreteResult, SemiConcreteResult} """ - info::ConstCallInfo + info::ConstCallInfo <: CallInfo The precision of this call was improved using constant information. In addition to the original call information `info.call`, this info also keeps the results of constant inference `info.results::Vector{Union{Nothing,ConstResult}}`. """ -struct ConstCallInfo +struct ConstCallInfo <: CallInfo call::Union{MethodMatchInfo,UnionSplitInfo} results::Vector{Union{Nothing,ConstResult}} end """ - info::MethodResultPure + info::MethodResultPure <: CallInfo This struct represents a method result constant was proven to be effect-free, including being no-throw (typically because the value was computed by calling an `@pure` function). """ -struct MethodResultPure - info::Any +struct MethodResultPure <: CallInfo + info::CallInfo end -let instance = MethodResultPure(false) +let instance = MethodResultPure(NoCallInfo()) global MethodResultPure MethodResultPure() = instance end """ - info::AbstractIterationInfo + ainfo::AbstractIterationInfo Captures all the information for abstract iteration analysis of a single value. -Each (abstract) call to `iterate`, corresponds to one entry in `info.each::Vector{CallMeta}`. +Each (abstract) call to `iterate`, corresponds to one entry in `ainfo.each::Vector{CallMeta}`. """ struct AbstractIterationInfo each::Vector{CallMeta} @@ -108,7 +110,7 @@ end const MaybeAbstractIterationInfo = Union{Nothing, AbstractIterationInfo} """ - info::ApplyCallInfo + info::ApplyCallInfo <: CallInfo This info applies to any call of `_apply_iterate(...)` and captures both the info of the actual call being applied and the info for any implicit call @@ -117,7 +119,7 @@ to be yet another `_apply_iterate`, in which case the `info.call` field will be another `ApplyCallInfo`. This info is illegal on any statement that is not an `_apply_iterate` call. """ -struct ApplyCallInfo +struct ApplyCallInfo <: CallInfo # The info for the call itself call::Any # AbstractIterationInfo for each argument, if applicable @@ -125,12 +127,12 @@ struct ApplyCallInfo end """ - info::UnionSplitApplyCallInfo + info::UnionSplitApplyCallInfo <: CallInfo Like `UnionSplitInfo`, but for `ApplyCallInfo` rather than `MethodMatchInfo`. This info is illegal on any statement that is not an `_apply_iterate` call. """ -struct UnionSplitApplyCallInfo +struct UnionSplitApplyCallInfo <: CallInfo infos::Vector{ApplyCallInfo} end @@ -141,7 +143,7 @@ Represents a resolved call to `Core.invoke`, carrying the `info.match::MethodMat the method that has been processed. Optionally keeps `info.result::InferenceResult` that keeps constant information. """ -struct InvokeCallInfo +struct InvokeCallInfo <: CallInfo match::MethodMatch result::Union{Nothing,ConstResult} end @@ -153,20 +155,20 @@ Represents a resolved call of opaque closure, carrying the `info.match::MethodMa the method that has been processed. Optionally keeps `info.result::InferenceResult` that keeps constant information. """ -struct OpaqueClosureCallInfo +struct OpaqueClosureCallInfo <: CallInfo match::MethodMatch result::Union{Nothing,ConstResult} end """ - info::OpaqueClosureCreateInfo + info::OpaqueClosureCreateInfo <: CallInfo This info may be constructed upon opaque closure construction, with `info.unspec::CallMeta` carrying out inference result of an unreal, partially specialized call (i.e. specialized on the closure environment, but not on the argument types of the opaque closure) in order to allow the optimizer to rewrite the return type parameter of the `OpaqueClosure` based on it. """ -struct OpaqueClosureCreateInfo +struct OpaqueClosureCreateInfo <: CallInfo unspec::CallMeta function OpaqueClosureCreateInfo(unspec::CallMeta) @assert isa(unspec.info, OpaqueClosureCallInfo) @@ -179,24 +181,24 @@ end # the AbstractInterpreter. """ - info::ReturnTypeCallInfo + info::ReturnTypeCallInfo <: CallInfo Represents a resolved call of `Core.Compiler.return_type`. `info.call` wraps the info corresponding to the call that `Core.Compiler.return_type` call was supposed to analyze. """ -struct ReturnTypeCallInfo - info::Any +struct ReturnTypeCallInfo <: CallInfo + info::CallInfo end """ - info::FinalizerInfo + info::FinalizerInfo <: CallInfo Represents the information of a potential (later) call to the finalizer on the given object type. """ -struct FinalizerInfo - info::Any +struct FinalizerInfo <: CallInfo + info::CallInfo effects::Effects end diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 60af6a6fdb9b04..a53b2aef2c9b48 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -1148,10 +1148,10 @@ end function abstract_modifyfield!(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::InferenceState) nargs = length(argtypes) if !isempty(argtypes) && isvarargtype(argtypes[nargs]) - nargs - 1 <= 6 || return CallMeta(Bottom, EFFECTS_THROWS, false) - nargs > 3 || return CallMeta(Any, EFFECTS_UNKNOWN, false) + nargs - 1 <= 6 || return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo()) + nargs > 3 || return CallMeta(Any, EFFECTS_UNKNOWN, NoCallInfo()) else - 5 <= nargs <= 6 || return CallMeta(Bottom, EFFECTS_THROWS, false) + 5 <= nargs <= 6 || return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo()) end o = unwrapva(argtypes[2]) f = unwrapva(argtypes[3]) @@ -2237,7 +2237,7 @@ function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, s if isa(af_argtype, DataType) && af_argtype <: Tuple argtypes_vec = Any[aft, af_argtype.parameters...] if contains_is(argtypes_vec, Union{}) - return CallMeta(Const(Union{}), EFFECTS_TOTAL, false) + return CallMeta(Const(Union{}), EFFECTS_TOTAL, NoCallInfo()) end # Run the abstract_call without restricting abstract call # sites. Otherwise, our behavior model of abstract_call @@ -2279,7 +2279,7 @@ function return_type_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, s end end end - return CallMeta(Type, EFFECTS_THROWS, false) + return CallMeta(Type, EFFECTS_THROWS, NoCallInfo()) end # N.B.: typename maps type equivalence classes to a single value diff --git a/base/compiler/types.jl b/base/compiler/types.jl index 1f51cf02ed346c..c066591a3f385b 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -284,3 +284,5 @@ infer_compilation_signature(::NativeInterpreter) = true typeinf_lattice(::AbstractInterpreter) = InferenceLattice(BaseInferenceLattice.instance) ipo_lattice(::AbstractInterpreter) = InferenceLattice(IPOResultLattice.instance) optimizer_lattice(::AbstractInterpreter) = OptimizerLattice() + +abstract type CallInfo end