Skip to content

Commit b2947aa

Browse files
committed
inference: simplify abstract_eval_globalref
By moving the optional `assume_bindings_static` refinement logic into `abstract_eval_globalref_partition` and removing the redirect via `abstract_eval_globalref_partition`. Also adds test cases with `assume_bindings_static=true`.
1 parent edbad8b commit b2947aa

File tree

3 files changed

+42
-32
lines changed

3 files changed

+42
-32
lines changed

Compiler/src/abstractinterpretation.jl

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,9 +2574,9 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta
25742574
M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25752575
s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25762576
gr = GlobalRef(M, s)
2577-
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp, _, partition
2577+
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp, binding, partition
25782578
partition_T = nothing
2579-
partition_rte = abstract_eval_partition_load(interp, partition)
2579+
partition_rte = abstract_eval_partition_load(interp, binding, partition)
25802580
if binding_kind(partition) == PARTITION_KIND_GLOBAL
25812581
partition_T = partition_restriction(partition)
25822582
end
@@ -3558,13 +3558,11 @@ function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::Global
35583558
return partition
35593559
end
35603560

3561-
abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, ::Core.Binding, partition::Core.BindingPartition) =
3562-
abstract_eval_partition_load(interp, partition)
3563-
function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, partition::Core.BindingPartition)
3561+
function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, binding::Core.Binding, partition::Core.BindingPartition)
35643562
kind = binding_kind(partition)
35653563
isdepwarn = (partition.kind & PARTITION_FLAG_DEPWARN) != 0
35663564
local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
3567-
if is_some_guard(kind) || kind == PARTITION_KIND_UNDEF_CONST
3565+
if is_some_guard(kind)
35683566
if interp !== nothing && InferenceParams(interp).assume_bindings_static
35693567
return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
35703568
else
@@ -3590,12 +3588,23 @@ function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing
35903588
# Could be replaced by a backdated const which has an effect, so we can't assume it won't.
35913589
# Besides, we would prefer not to merge the world range for this into the world range for
35923590
# _GLOBAL, because that would pessimize codegen.
3593-
local_getglobal_effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
3591+
effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
35943592
rt = Any
35953593
else
35963594
rt = partition_restriction(partition)
3595+
effects = local_getglobal_effects
3596+
end
3597+
if (interp !== nothing && InferenceParams(interp).assume_bindings_static &&
3598+
kind in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) &&
3599+
isdefined(binding, :value))
3600+
exct = Union{}
3601+
effects = Effects(generic_getglobal_effects; nothrow=true)
3602+
else
3603+
# We do not assume in general that assigned global bindings remain assigned.
3604+
# The existence of pkgimages allows them to revert in practice.
3605+
exct = UndefVarError
35973606
end
3598-
return RTEffects(rt, UndefVarError, local_getglobal_effects)
3607+
return RTEffects(rt, exct, effects)
35993608
end
36003609

36013610
function scan_specified_partitions(query::Function, walk_binding_partition::Function, interp, g::GlobalRef, wwr::WorldWithRange)
@@ -3643,28 +3652,15 @@ scan_partitions(query::Function, interp, g::GlobalRef, wwr::WorldWithRange) =
36433652
abstract_load_all_consistent_leaf_partitions(interp, g::GlobalRef, wwr::WorldWithRange) =
36443653
scan_leaf_partitions(abstract_eval_partition_load, interp, g, wwr)
36453654

3646-
function abstract_eval_globalref_partition(interp, binding::Core.Binding, partition::Core.BindingPartition)
3647-
# For inference purposes, we don't particularly care which global binding we end up loading, we only
3648-
# care about its type. However, we would still like to terminate the world range for the particular
3649-
# binding we end up reaching such that codegen can emit a simpler pointer load.
3650-
Pair{RTEffects, Union{Nothing, Core.Binding}}(
3651-
abstract_eval_partition_load(interp, partition),
3652-
binding_kind(partition) in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) ? binding : nothing)
3653-
end
3654-
36553655
function abstract_eval_globalref(interp, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)
36563656
if saw_latestworld
36573657
return RTEffects(Any, Any, generic_getglobal_effects)
36583658
end
3659-
(valid_worlds, (ret, binding_if_global)) = scan_leaf_partitions(abstract_eval_globalref_partition, interp, g, sv.world)
3659+
# For inference purposes, we don't particularly care which global binding we end up loading, we only
3660+
# care about its type. However, we would still like to terminate the world range for the particular
3661+
# binding we end up reaching such that codegen can emit a simpler pointer load.
3662+
(valid_worlds, ret) = scan_leaf_partitions(abstract_eval_partition_load, interp, g, sv.world)
36603663
update_valid_age!(sv, valid_worlds)
3661-
if ret.rt !== Union{} && ret.exct === UndefVarError && binding_if_global !== nothing && InferenceParams(interp).assume_bindings_static
3662-
if isdefined(binding_if_global, :value)
3663-
ret = RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true))
3664-
end
3665-
# We do not assume in general that assigned global bindings remain assigned.
3666-
# The existence of pkgimages allows them to revert in practice.
3667-
end
36683664
return ret
36693665
end
36703666

Compiler/test/inference.jl

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6348,14 +6348,28 @@ end === Int
63486348
swapglobal!(@__MODULE__, :swapglobal!_xxx, x)
63496349
end === Union{}
63506350

6351+
@newinterp AssumeBindingsStaticInterp
6352+
Compiler.InferenceParams(::AssumeBindingsStaticInterp) = Compiler.InferenceParams(; assume_bindings_static=true)
6353+
63516354
eval(Expr(:const, :swapglobal!_must_throw))
6352-
@newinterp SwapGlobalInterp
6353-
Compiler.InferenceParams(::SwapGlobalInterp) = Compiler.InferenceParams(; assume_bindings_static=true)
63546355
function func_swapglobal!_must_throw(x)
63556356
swapglobal!(@__MODULE__, :swapglobal!_must_throw, x)
63566357
end
6357-
@test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) === Union{}
6358-
@test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) )
6358+
@test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=AssumeBindingsStaticInterp()) === Union{}
6359+
@test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=AssumeBindingsStaticInterp()) )
6360+
6361+
global global_decl_defined
6362+
global_decl_defined = 42
6363+
@test Base.infer_effects(; interp=AssumeBindingsStaticInterp()) do
6364+
global global_decl_defined
6365+
return global_decl_defined
6366+
end |> Compiler.is_nothrow
6367+
global global_decl_defined2::Int
6368+
global_decl_defined2 = 42
6369+
@test Base.infer_effects(; interp=AssumeBindingsStaticInterp()) do
6370+
global global_decl_defined2
6371+
return global_decl_defined2
6372+
end |> Compiler.is_nothrow
63596373

63606374
@eval get_exception() = $(Expr(:the_exception))
63616375
@test Base.infer_return_type() do

base/invalidation.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ function invalidate_code_for_globalref!(b::Core.Binding, invalidated_bpart::Core
124124
(_, (ib, ibpart)) = Compiler.walk_binding_partition(b, invalidated_bpart, new_max_world)
125125
(_, (nb, nbpart)) = Compiler.walk_binding_partition(b, new_bpart, new_max_world+1)
126126

127-
# abstract_eval_globalref_partition is the maximum amount of information that inference
127+
# `abstract_eval_partition_load` is the maximum amount of information that inference
128128
# reads from a binding partition. If this information does not change - we do not need to
129129
# invalidate any code that inference created, because we know that the result will not change.
130130
need_to_invalidate_code =
131-
Compiler.abstract_eval_globalref_partition(nothing, ib, ibpart) !==
132-
Compiler.abstract_eval_globalref_partition(nothing, nb, nbpart)
131+
Compiler.abstract_eval_partition_load(nothing, ib, ibpart) !==
132+
Compiler.abstract_eval_partition_load(nothing, nb, nbpart)
133133

134134
need_to_invalidate_export = export_affecting_partition_flags(invalidated_bpart) !==
135135
export_affecting_partition_flags(new_bpart)

0 commit comments

Comments
 (0)