diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 3c722834fd88c..6e24f3bae2de5 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -917,6 +917,8 @@ struct ConstCallResults new(rt, const_result, effects, edge) end +# TODO MustAlias forwarding + struct ConditionalArgtypes <: ForwardableArgtypes arginfo::ArgInfo sv::InferenceState @@ -1069,7 +1071,7 @@ function maybe_get_const_prop_profitable(interp::AbstractInterpreter, add_remark!(interp, sv, "[constprop] Disabled by argument and rettype heuristics") return nothing end - all_overridden = is_all_overridden(arginfo, sv) + all_overridden = is_all_overridden(interp, arginfo, sv) if !force && !const_prop_function_heuristic(interp, f, arginfo, nargs, all_overridden, is_nothrow(sv.ipo_effects), sv) add_remark!(interp, sv, "[constprop] Disabled by function heuristic") @@ -1128,46 +1130,28 @@ end # determines heuristically whether if constant propagation can be worthwhile # by checking if any of given `argtypes` is "interesting" enough to be propagated -function const_prop_argument_heuristic(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::InferenceState) +function const_prop_argument_heuristic(interp::AbstractInterpreter, arginfo::ArgInfo, sv::InferenceState) + ๐•ƒแตข = typeinf_lattice(interp) + argtypes = arginfo.argtypes for i in 1:length(argtypes) a = argtypes[i] - if isa(a, Conditional) && fargs !== nothing - is_const_prop_profitable_conditional(a, fargs, sv) && return true + if has_conditional(๐•ƒแตข) && isa(a, Conditional) && arginfo.fargs !== nothing + is_const_prop_profitable_conditional(a, arginfo.fargs, sv) && return true else a = widenslotwrapper(a) - has_nontrivial_const_info(typeinf_lattice(interp), a) && is_const_prop_profitable_arg(a) && return true + has_nontrivial_extended_info(๐•ƒแตข, a) && is_const_prop_profitable_arg(๐•ƒแตข, a) && return true end end return false end -function is_const_prop_profitable_arg(@nospecialize(arg)) - # have new information from argtypes that wasn't available from the signature - if isa(arg, PartialStruct) - return true # might be a bit aggressive, may want to enable some check like follows: - # for i = 1:length(arg.fields) - # fld = arg.fields[i] - # isconstType(fld) && return true - # is_const_prop_profitable_arg(fld) && return true - # fld โŠ fieldtype(arg.typ, i) && return true - # end - # return false - end - isa(arg, PartialOpaque) && return true - isa(arg, PartialTypeVar) && return false # this isn't forwardable - isa(arg, Const) || return true - val = arg.val - # don't consider mutable values useful constants - return isa(val, Symbol) || isa(val, Type) || !ismutable(val) -end - function is_const_prop_profitable_conditional(cnd::Conditional, fargs::Vector{Any}, sv::InferenceState) slotid = find_constrained_arg(cnd, fargs, sv) if slotid !== nothing return true end # as a minor optimization, we just check the result is a constant or not, - # since both `has_nontrivial_const_info`/`is_const_prop_profitable_arg` return `true` + # since both `has_nontrivial_extended_info`/`is_const_prop_profitable_arg` return `true` # for `Const(::Bool)` return isa(widenconditional(cnd), Const) end @@ -1184,14 +1168,14 @@ function find_constrained_arg(cnd::Conditional, fargs::Vector{Any}, sv::Inferenc end # checks if all argtypes has additional information other than what `Type` can provide -function is_all_overridden((; fargs, argtypes)::ArgInfo, sv::InferenceState) +function is_all_overridden(interp::AbstractInterpreter, (; fargs, argtypes)::ArgInfo, sv::InferenceState) + ๐•ƒแตข = typeinf_lattice(interp) for i in 1:length(argtypes) a = argtypes[i] - if isa(a, Conditional) && fargs !== nothing + if has_conditional(๐•ƒแตข) && isa(a, Conditional) && fargs !== nothing is_const_prop_profitable_conditional(a, fargs, sv) || return false else - a = widenslotwrapper(a) - is_forwardable_argtype(a) || return false + is_forwardable_argtype(๐•ƒแตข, widenslotwrapper(a)) || return false end end return true @@ -1204,11 +1188,11 @@ function force_const_prop(interp::AbstractInterpreter, @nospecialize(f), method: istopfunction(f, :setproperty!) end -function const_prop_function_heuristic( - interp::AbstractInterpreter, @nospecialize(f), (; argtypes)::ArgInfo, +function const_prop_function_heuristic(interp::AbstractInterpreter, @nospecialize(f), arginfo::ArgInfo, nargs::Int, all_overridden::Bool, still_nothrow::Bool, _::InferenceState) - โŠ‘แตข = โŠ‘(typeinf_lattice(interp)) + argtypes = arginfo.argtypes if nargs > 1 + ๐•ƒแตข = typeinf_lattice(interp) if istopfunction(f, :getindex) || istopfunction(f, :setindex!) arrty = argtypes[2] # don't propagate constant index into indexing of non-constant array @@ -1218,12 +1202,12 @@ function const_prop_function_heuristic( if !still_nothrow || ismutabletype(arrty) return false end - elseif arrty โŠ‘แตข Array + elseif โŠ‘(๐•ƒแตข, arrty, Array) return false end elseif istopfunction(f, :iterate) itrty = argtypes[2] - if itrty โŠ‘แตข Array + if โŠ‘(๐•ƒแตข, itrty, Array) return false end end @@ -2294,7 +2278,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp end allconst &= isa(at, Const) if !anyrefine - anyrefine = has_nontrivial_const_info(๐•ƒแตข, at) || # constant information + anyrefine = has_nontrivial_extended_info(๐•ƒแตข, at) || # extended lattice information โ‹ค(๐•ƒแตข, at, ft) # just a type-level information, but more precise than the declared type end ats[i] = at @@ -2566,18 +2550,6 @@ struct BestguessInfo{Interp<:AbstractInterpreter} end end -""" - widenreturn(@nospecialize(rt), info::BestguessInfo) -> new_bestguess - -Appropriately converts inferred type of a return value `rt` to such a type -that we know we can store in the cache and is valid and good inter-procedurally, -E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional` -or the other cachable lattice element. - -External lattice `๐•ƒโ‚‘::ExternalLattice` may overload: -- `widenreturn(๐•ƒโ‚‘::ExternalLattice, @nospecialize(rt), info::BestguessInfo)` -- `widenreturn_noslotwrapper(๐•ƒโ‚‘::ExternalLattice, @nospecialize(rt), info::BestguessInfo)` -""" function widenreturn(@nospecialize(rt), info::BestguessInfo) return widenreturn(typeinf_lattice(info.interp), rt, info) end @@ -2691,7 +2663,7 @@ function widenreturn_partials(๐•ƒแตข::PartialsLattice, @nospecialize(rt), info: a = isvarargtype(a) ? a : widenreturn_noslotwrapper(๐•ƒ, a, info) if !anyrefine # TODO: consider adding && const_prop_profitable(a) here? - anyrefine = has_const_info(a) || + anyrefine = has_extended_info(a) || โŠ(๐•ƒ, a, fieldtype(rt.typ, i)) end fields[i] = a diff --git a/base/compiler/abstractlattice.jl b/base/compiler/abstractlattice.jl index 5e92aea1c81b3..d98c2b818b649 100644 --- a/base/compiler/abstractlattice.jl +++ b/base/compiler/abstractlattice.jl @@ -1,53 +1,54 @@ -abstract type AbstractLattice; end +# TODO add more documentations + +abstract type AbstractLattice end function widenlattice end +function is_valid_lattice_norec end """ - struct JLTypeLattice + struct JLTypeLattice <: AbstractLattice -A singleton type representing the lattice of Julia types, without any inference -extensions. +A singleton type representing the lattice of Julia types, without any inference extensions. """ struct JLTypeLattice <: AbstractLattice; end widenlattice(::JLTypeLattice) = error("Type lattice is the least-precise lattice available") -is_valid_lattice(lattice::JLTypeLattice, @nospecialize(elem)) = is_valid_lattice_norec(lattice, elem) is_valid_lattice_norec(::JLTypeLattice, @nospecialize(elem)) = isa(elem, Type) """ - struct ConstsLattice + struct ConstsLattice <: AbstractLattice A lattice extending `JLTypeLattice` and adjoining `Const` and `PartialTypeVar`. """ struct ConstsLattice <: AbstractLattice; end widenlattice(::ConstsLattice) = JLTypeLattice() -is_valid_lattice_norec(lattice::ConstsLattice, @nospecialize(elem)) = isa(elem, Const) || isa(elem, PartialTypeVar) +is_valid_lattice_norec(::ConstsLattice, @nospecialize(elem)) = isa(elem, Const) || isa(elem, PartialTypeVar) """ - struct PartialsLattice{L} + struct PartialsLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice -A lattice extending lattice `L` and adjoining `PartialStruct` and `PartialOpaque`. +A lattice extending a base lattice `๐•ƒ` and adjoining `PartialStruct` and `PartialOpaque`. """ -struct PartialsLattice{L <: AbstractLattice} <: AbstractLattice - parent::L +struct PartialsLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice + parent::๐•ƒ end -widenlattice(L::PartialsLattice) = L.parent -is_valid_lattice_norec(lattice::PartialsLattice, @nospecialize(elem)) = isa(elem, PartialStruct) || isa(elem, PartialOpaque) +widenlattice(๐•ƒ::PartialsLattice) = ๐•ƒ.parent +is_valid_lattice_norec(::PartialsLattice, @nospecialize(elem)) = isa(elem, PartialStruct) || isa(elem, PartialOpaque) """ - struct ConditionalsLattice{L} + struct ConditionalsLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice -A lattice extending lattice `L` and adjoining `Conditional`. +A lattice extending a base lattice `๐•ƒ` and adjoining `Conditional`. """ -struct ConditionalsLattice{L <: AbstractLattice} <: AbstractLattice - parent::L +struct ConditionalsLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice + parent::๐•ƒ end -widenlattice(L::ConditionalsLattice) = L.parent -is_valid_lattice_norec(lattice::ConditionalsLattice, @nospecialize(elem)) = isa(elem, Conditional) +widenlattice(๐•ƒ::ConditionalsLattice) = ๐•ƒ.parent +is_valid_lattice_norec(::ConditionalsLattice, @nospecialize(elem)) = isa(elem, Conditional) -struct InterConditionalsLattice{L <: AbstractLattice} <: AbstractLattice - parent::L +struct InterConditionalsLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice + parent::๐•ƒ end -widenlattice(L::InterConditionalsLattice) = L.parent -is_valid_lattice_norec(lattice::InterConditionalsLattice, @nospecialize(elem)) = isa(elem, InterConditional) +widenlattice(๐•ƒ::InterConditionalsLattice) = ๐•ƒ.parent +is_valid_lattice_norec(::InterConditionalsLattice, @nospecialize(elem)) = isa(elem, InterConditional) """ struct MustAliasesLattice{๐•ƒ} @@ -79,37 +80,37 @@ const BaseInferenceLattice = typeof(ConditionalsLattice(SimpleInferenceLattice.i const IPOResultLattice = typeof(InterConditionalsLattice(SimpleInferenceLattice.instance)) """ - struct InferenceLattice{L} + struct InferenceLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice -The full lattice used for abstract interpretation during inference. Takes -a base lattice and adjoins `LimitedAccuracy`. +The full lattice used for abstract interpretation during inference. +Takes a base lattice `๐•ƒ` and adjoins `LimitedAccuracy`. """ -struct InferenceLattice{L} <: AbstractLattice - parent::L +struct InferenceLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice + parent::๐•ƒ end -widenlattice(L::InferenceLattice) = L.parent -is_valid_lattice_norec(lattice::InferenceLattice, @nospecialize(elem)) = isa(elem, LimitedAccuracy) +widenlattice(๐•ƒ::InferenceLattice) = ๐•ƒ.parent +is_valid_lattice_norec(::InferenceLattice, @nospecialize(elem)) = isa(elem, LimitedAccuracy) """ - struct OptimizerLattice + struct OptimizerLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice The lattice used by the optimizer. Extends `BaseInferenceLattice` with `MaybeUndef`. """ -struct OptimizerLattice{L} <: AbstractLattice - parent::L +struct OptimizerLattice{๐•ƒ<:AbstractLattice} <: AbstractLattice + parent::๐•ƒ end OptimizerLattice() = OptimizerLattice(SimpleInferenceLattice.instance) -widenlattice(L::OptimizerLattice) = L.parent -is_valid_lattice_norec(lattice::OptimizerLattice, @nospecialize(elem)) = isa(elem, MaybeUndef) +widenlattice(๐•ƒ::OptimizerLattice) = ๐•ƒ.parent +is_valid_lattice_norec(::OptimizerLattice, @nospecialize(elem)) = isa(elem, MaybeUndef) """ - tmeet(lattice, a, b::Type) + tmeet(๐•ƒ::AbstractLattice, a, b::Type) -Compute the lattice meet of lattice elements `a` and `b` over the lattice -`lattice`. If `lattice` is `JLTypeLattice`, this is equivalent to type -intersection. Note that currently `b` is restricted to being a type (interpreted -as a lattice element in the JLTypeLattice sub-lattice of `lattice`). +Compute the lattice meet of lattice elements `a` and `b` over the lattice `๐•ƒ`. +If `๐•ƒ` is `JLTypeLattice`, this is equivalent to type intersection. +Note that currently `b` is restricted to being a type +(interpreted as a lattice element in the `JLTypeLattice` sub-lattice of `๐•ƒ`). """ function tmeet end @@ -120,9 +121,9 @@ function tmeet(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type)) end """ - tmerge(lattice, a, b) + tmerge(๐•ƒ::AbstractLattice, a, b) -Compute a lattice join of elements `a` and `b` over the lattice `lattice`. +Compute a lattice join of elements `a` and `b` over the lattice `๐•ƒ`. Note that the computed element need not be the least upper bound of `a` and `b`, but rather, we impose additional limitations on the complexity of the joined element, ideally without losing too much precision in common cases and @@ -131,52 +132,137 @@ remaining mostly associative and commutative. function tmerge end """ - โŠ‘(lattice, a, b) + โŠ‘(๐•ƒ::AbstractLattice, a, b) Compute the lattice ordering (i.e. less-than-or-equal) relationship between -lattice elements `a` and `b` over the lattice `lattice`. If `lattice` is -`JLTypeLattice`, this is equivalent to subtyping. +lattice elements `a` and `b` over the lattice `๐•ƒ`. +If `๐•ƒ` is `JLTypeLattice`, this is equivalent to subtyping. """ function โŠ‘ end โŠ‘(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type)) = a <: b """ - โŠ(lattice, a, b) -> Bool + โŠ(๐•ƒ::AbstractLattice, a, b) -> Bool The strict partial order over the type inference lattice. This is defined as the irreflexive kernel of `โŠ‘`. """ -โŠ(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) = โŠ‘(lattice, a, b) && !โŠ‘(lattice, b, a) +โŠ(๐•ƒ::AbstractLattice, @nospecialize(a), @nospecialize(b)) = โŠ‘(๐•ƒ, a, b) && !โŠ‘(๐•ƒ, b, a) """ - โ‹ค(lattice, a, b) -> Bool + โ‹ค(๐•ƒ::AbstractLattice, a, b) -> Bool This order could be used as a slightly more efficient version of the strict order `โŠ`, where we can safely assume `a โŠ‘ b` holds. """ -โ‹ค(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) = !โŠ‘(lattice, b, a) +โ‹ค(๐•ƒ::AbstractLattice, @nospecialize(a), @nospecialize(b)) = !โŠ‘(๐•ƒ, b, a) """ - is_lattice_equal(lattice, a, b) -> Bool + is_lattice_equal(๐•ƒ::AbstractLattice, a, b) -> Bool Check if two lattice elements are partial order equivalent. -This is basically `a โŠ‘ b && b โŠ‘ a` but (optionally) with extra performance optimizations. +This is basically `a โŠ‘ b && b โŠ‘ a` in the lattice of `๐•ƒ` +but (optionally) with extra performance optimizations. """ -function is_lattice_equal(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) +function is_lattice_equal(๐•ƒ::AbstractLattice, @nospecialize(a), @nospecialize(b)) a === b && return true - โŠ‘(lattice, a, b) && โŠ‘(lattice, b, a) + return โŠ‘(๐•ƒ, a, b) && โŠ‘(๐•ƒ, b, a) +end + +""" + has_nontrivial_extended_info(๐•ƒ::AbstractLattice, t) -> Bool + +Determines whether the given lattice element `t` of `๐•ƒ` has non-trivial extended lattice +information that would not be available from the type itself. +""" +has_nontrivial_extended_info(๐•ƒ::AbstractLattice, @nospecialize t) = + has_nontrivial_extended_info(widenlattice(๐•ƒ), t) +function has_nontrivial_extended_info(๐•ƒ::PartialsLattice, @nospecialize t) + isa(t, PartialStruct) && return true + isa(t, PartialOpaque) && return true + return has_nontrivial_extended_info(widenlattice(๐•ƒ), t) +end +function has_nontrivial_extended_info(๐•ƒ::ConstsLattice, @nospecialize t) + isa(t, PartialTypeVar) && return true + if isa(t, Const) + val = t.val + return !issingletontype(typeof(val)) && !(isa(val, Type) && hasuniquerep(val)) + end + return has_nontrivial_extended_info(widenlattice(๐•ƒ), t) +end +has_nontrivial_extended_info(::JLTypeLattice, @nospecialize(t)) = false + +""" + is_const_prop_profitable_arg(๐•ƒ::AbstractLattice, t) -> Bool + +Determines whether the given lattice element `t` of `๐•ƒ` has new extended lattice information +that should be forwarded along with constant propagation. +""" +is_const_prop_profitable_arg(๐•ƒ::AbstractLattice, @nospecialize t) = + is_const_prop_profitable_arg(widenlattice(๐•ƒ), t) +function is_const_prop_profitable_arg(๐•ƒ::PartialsLattice, @nospecialize t) + if isa(t, PartialStruct) + return true # might be a bit aggressive, may want to enable some check like follows: + # for i = 1:length(t.fields) + # fld = t.fields[i] + # isconstType(fld) && return true + # is_const_prop_profitable_arg(fld) && return true + # fld โŠ fieldtype(t.typ, i) && return true + # end + # return false + end + isa(t, PartialOpaque) && return true + return is_const_prop_profitable_arg(widenlattice(๐•ƒ), t) +end +function is_const_prop_profitable_arg(๐•ƒ::ConstsLattice, @nospecialize t) + if isa(t, Const) + # don't consider mutable values useful constants + val = t.val + return isa(val, Symbol) || isa(val, Type) || !ismutable(val) + end + isa(t, PartialTypeVar) && return false # this isn't forwardable + return is_const_prop_profitable_arg(widenlattice(๐•ƒ), t) +end +is_const_prop_profitable_arg(::JLTypeLattice, @nospecialize t) = false + +is_forwardable_argtype(๐•ƒ::AbstractLattice, @nospecialize(x)) = + is_forwardable_argtype(widenlattice(๐•ƒ), x) +function is_forwardable_argtype(๐•ƒ::ConditionalsLattice, @nospecialize x) + isa(x, Conditional) && return true + return is_forwardable_argtype(widenlattice(๐•ƒ), x) +end +function is_forwardable_argtype(๐•ƒ::PartialsLattice, @nospecialize x) + isa(x, PartialStruct) && return true + isa(x, PartialOpaque) && return true + return is_forwardable_argtype(widenlattice(๐•ƒ), x) +end +function is_forwardable_argtype(๐•ƒ::ConstsLattice, @nospecialize x) + isa(x, Const) && return true + return is_forwardable_argtype(widenlattice(๐•ƒ), x) +end +function is_forwardable_argtype(::JLTypeLattice, @nospecialize x) + return false end """ - has_nontrivial_const_info(lattice, t) -> Bool + widenreturn(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo) -> new_bestguess + widenreturn_noslotwrapper(๐•ƒแตข::AbstractLattice, @nospecialize(rt), info::BestguessInfo) -> new_bestguess -Determine whether the given lattice element `t` of `lattice` has non-trivial -constant information that would not be available from the type itself. +Appropriately converts inferred type of a return value `rt` to such a type +that we know we can store in the cache and is valid and good inter-procedurally, +E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional` +or the other cachable lattice element. + +External lattice `๐•ƒแตข::ExternalLattice` may overload: +- `widenreturn(๐•ƒแตข::ExternalLattice, @nospecialize(rt), info::BestguessInfo)` +- `widenreturn_noslotwrapper(๐•ƒแตข::ExternalLattice, @nospecialize(rt), info::BestguessInfo)` """ -has_nontrivial_const_info(lattice::AbstractLattice, @nospecialize t) = - has_nontrivial_const_info(widenlattice(lattice), t) -has_nontrivial_const_info(::JLTypeLattice, @nospecialize(t)) = false +function widenreturn end, function widenreturn_noslotwrapper end + +is_valid_lattice(๐•ƒ::AbstractLattice, @nospecialize(elem)) = + is_valid_lattice_norec(๐•ƒ, elem) && is_valid_lattice(widenlattice(๐•ƒ), elem) +is_valid_lattice(๐•ƒ::JLTypeLattice, @nospecialize(elem)) = is_valid_lattice_norec(๐•ƒ, elem) has_conditional(๐•ƒ::AbstractLattice) = has_conditional(widenlattice(๐•ƒ)) has_conditional(::AnyConditionalsLattice) = true @@ -202,12 +288,9 @@ tmerge(@nospecialize(a), @nospecialize(b)) = tmerge(fallback_lattice, a, b) โ‹ค(@nospecialize(a), @nospecialize(b)) = โ‹ค(fallback_lattice, a, b) is_lattice_equal(@nospecialize(a), @nospecialize(b)) = is_lattice_equal(fallback_lattice, a, b) -is_valid_lattice(lattice::AbstractLattice, @nospecialize(elem)) = is_valid_lattice_norec(lattice, elem) && - is_valid_lattice(widenlattice(lattice), elem) - # Widenlattice with argument widenlattice(::JLTypeLattice, @nospecialize(t)) = widenconst(t) -function widenlattice(lattice::AbstractLattice, @nospecialize(t)) - is_valid_lattice_norec(lattice, t) && return t - widenlattice(widenlattice(lattice), t) +function widenlattice(๐•ƒ::AbstractLattice, @nospecialize(t)) + is_valid_lattice_norec(๐•ƒ, t) && return t + widenlattice(widenlattice(๐•ƒ), t) end diff --git a/base/compiler/inferenceresult.jl b/base/compiler/inferenceresult.jl index f54173c899cbc..5001be9cc3601 100644 --- a/base/compiler/inferenceresult.jl +++ b/base/compiler/inferenceresult.jl @@ -68,24 +68,16 @@ function pick_const_args!(cache_argtypes::Vector{Any}, overridden_by_const::BitV return cache_argtypes, overridden_by_const end -function is_argtype_match(lattice::AbstractLattice, +function is_argtype_match(๐•ƒ::AbstractLattice, @nospecialize(given_argtype), @nospecialize(cache_argtype), overridden_by_const::Bool) - if is_forwardable_argtype(given_argtype) - return is_lattice_equal(lattice, given_argtype, cache_argtype) + if is_forwardable_argtype(๐•ƒ, given_argtype) + return is_lattice_equal(๐•ƒ, given_argtype, cache_argtype) end return !overridden_by_const end -# TODO MustAlias forwarding -function is_forwardable_argtype(@nospecialize x) - return isa(x, Const) || - isa(x, Conditional) || - isa(x, PartialStruct) || - isa(x, PartialOpaque) -end - va_process_argtypes(given_argtypes::Vector{Any}, linfo::MethodInstance) = va_process_argtypes(Returns(nothing), given_argtypes, linfo) function va_process_argtypes(@nospecialize(va_handler!), given_argtypes::Vector{Any}, linfo::MethodInstance) diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index f804bd5461019..5dac285de6933 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -1330,7 +1330,7 @@ function abstract_modifyfield!(interp::AbstractInterpreter, argtypes::Vector{Any TF2 = tmeet(callinfo.rt, widenconst(TF)) if TF2 === Bottom RT = Bottom - elseif isconcretetype(RT) && has_nontrivial_const_info(๐•ƒแตข, TF2) # isconcrete condition required to form a PartialStruct + elseif isconcretetype(RT) && has_nontrivial_extended_info(๐•ƒแตข, TF2) # isconcrete condition required to form a PartialStruct RT = PartialStruct(RT, Any[TF, TF2]) end info = ModifyFieldInfo(callinfo.info) @@ -1799,7 +1799,7 @@ function tuple_tfunc(๐•ƒ::AbstractLattice, argtypes::Vector{Any}) anyinfo = false for i in 1:length(argtypes) x = argtypes[i] - if has_nontrivial_const_info(๐•ƒ, x) + if has_nontrivial_extended_info(๐•ƒ, x) anyinfo = true else if !isvarargtype(x) diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index 845e46ab01ed7..e470c4711110c 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -6,7 +6,6 @@ const MAX_TYPEUNION_COMPLEXITY = 3 const MAX_TYPEUNION_LENGTH = 3 -const MAX_INLINE_CONST_SIZE = 256 ######################### # limitation heuristics # @@ -534,7 +533,7 @@ function tmerge(lattice::PartialsLattice, @nospecialize(typea), @nospecialize(ty end fields[i] = tyi if !anyrefine - anyrefine = has_nontrivial_const_info(lattice, tyi) || # constant information + anyrefine = has_nontrivial_extended_info(lattice, tyi) || # extended information โ‹ค(lattice, tyi, ft) # just a type-level information, but more precise than the declared type end end @@ -542,7 +541,6 @@ function tmerge(lattice::PartialsLattice, @nospecialize(typea), @nospecialize(ty end end - # Don't widen const here - external AbstractInterpreter might insert lattice # layers between us and `ConstsLattice`. wl = widenlattice(lattice) diff --git a/base/compiler/typeutils.jl b/base/compiler/typeutils.jl index 9a282da101d02..0950150637b0a 100644 --- a/base/compiler/typeutils.jl +++ b/base/compiler/typeutils.jl @@ -46,21 +46,7 @@ function isTypeDataType(@nospecialize t) return true end -function has_nontrivial_const_info(lattice::PartialsLattice, @nospecialize t) - isa(t, PartialStruct) && return true - isa(t, PartialOpaque) && return true - return has_nontrivial_const_info(widenlattice(lattice), t) -end -function has_nontrivial_const_info(lattice::ConstsLattice, @nospecialize t) - isa(t, PartialTypeVar) && return true - if isa(t, Const) - val = t.val - return !issingletontype(typeof(val)) && !(isa(val, Type) && hasuniquerep(val)) - end - return has_nontrivial_const_info(widenlattice(lattice), t) -end - -has_const_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x) +has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isType(x) # Subtyping currently intentionally answers certain queries incorrectly for kind types. For # some of these queries, this check can be used to somewhat protect against making incorrect diff --git a/base/compiler/utilities.jl b/base/compiler/utilities.jl index 2915870ae2ea5..a12b8c7fb6db1 100644 --- a/base/compiler/utilities.jl +++ b/base/compiler/utilities.jl @@ -77,6 +77,12 @@ function quoted(@nospecialize(x)) return is_self_quoting(x) ? x : QuoteNode(x) end +############ +# inlining # +############ + +const MAX_INLINE_CONST_SIZE = 256 + function count_const_size(@nospecialize(x), count_self::Bool = true) (x isa Type || x isa Symbol) && return 0 ismutable(x) && return MAX_INLINE_CONST_SIZE + 1 diff --git a/test/compiler/AbstractInterpreter.jl b/test/compiler/AbstractInterpreter.jl index 6499d9d24a518..ac1f34743e18e 100644 --- a/test/compiler/AbstractInterpreter.jl +++ b/test/compiler/AbstractInterpreter.jl @@ -127,24 +127,21 @@ using Core: SlotNumber, Argument using Core.Compiler: slot_id, tmerge_fast_path import .CC: AbstractLattice, BaseInferenceLattice, IPOResultLattice, InferenceLattice, OptimizerLattice, - widen, is_valid_lattice, typeinf_lattice, ipo_lattice, optimizer_lattice, - widenconst, tmeet, tmerge, โŠ‘, abstract_eval_special_value, widenreturn, - widenlattice + widenlattice, is_valid_lattice_norec, typeinf_lattice, ipo_lattice, optimizer_lattice, + widenconst, tmeet, tmerge, โŠ‘, abstract_eval_special_value, widenreturn @newinterp TaintInterpreter struct TaintLattice{PL<:AbstractLattice} <: CC.AbstractLattice parent::PL end CC.widenlattice(๐•ƒ::TaintLattice) = ๐•ƒ.parent -CC.is_valid_lattice(๐•ƒ::TaintLattice, @nospecialize(elm)) = - is_valid_lattice(widenlattice(๐•ƒ), elem) || isa(elm, Taint) +CC.is_valid_lattice_norec(::TaintLattice, @nospecialize(elm)) = isa(elm, Taint) struct InterTaintLattice{PL<:AbstractLattice} <: CC.AbstractLattice parent::PL end CC.widenlattice(๐•ƒ::InterTaintLattice) = ๐•ƒ.parent -CC.is_valid_lattice(๐•ƒ::InterTaintLattice, @nospecialize(elm)) = - is_valid_lattice(widenlattice(๐•ƒ), elem) || isa(elm, InterTaint) +CC.is_valid_lattice_norec(::InterTaintLattice, @nospecialize(elm)) = isa(elm, InterTaint) const AnyTaintLattice{L} = Union{TaintLattice{L},InterTaintLattice{L}}