Skip to content

Commit 4f6fbd6

Browse files
committed
inference: simplify abstract_eval_globalref (#58026)
By moving the optional `assume_bindings_static` refinement logic into `abstract_eval_partition_load` and removing the redirect via `abstract_eval_globalref_partition`. Also adds test cases with `assume_bindings_static=true`.
1 parent 3582d8a commit 4f6fbd6

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
@@ -2570,9 +2570,9 @@ function abstract_eval_replaceglobal!(interp::AbstractInterpreter, sv::AbsIntSta
25702570
M isa Module || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25712571
s isa Symbol || return CallMeta(Union{}, TypeError, EFFECTS_THROWS, NoCallInfo())
25722572
gr = GlobalRef(M, s)
2573-
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp, _, partition
2573+
(valid_worlds, (rte, T)) = scan_leaf_partitions(interp, gr, sv.world) do interp, binding, partition
25742574
partition_T = nothing
2575-
partition_rte = abstract_eval_partition_load(interp, partition)
2575+
partition_rte = abstract_eval_partition_load(interp, binding, partition)
25762576
if binding_kind(partition) == PARTITION_KIND_GLOBAL
25772577
partition_T = partition_restriction(partition)
25782578
end
@@ -3511,13 +3511,11 @@ function abstract_eval_binding_partition!(interp::AbstractInterpreter, g::Global
35113511
return partition
35123512
end
35133513

3514-
abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, ::Core.Binding, partition::Core.BindingPartition) =
3515-
abstract_eval_partition_load(interp, partition)
3516-
function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, partition::Core.BindingPartition)
3514+
function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing}, binding::Core.Binding, partition::Core.BindingPartition)
35173515
kind = binding_kind(partition)
35183516
isdepwarn = (partition.kind & PARTITION_FLAG_DEPWARN) != 0
35193517
local_getglobal_effects = Effects(generic_getglobal_effects, effect_free=isdepwarn ? ALWAYS_FALSE : ALWAYS_TRUE)
3520-
if is_some_guard(kind) || kind == PARTITION_KIND_UNDEF_CONST
3518+
if is_some_guard(kind)
35213519
if interp !== nothing && InferenceParams(interp).assume_bindings_static
35223520
return RTEffects(Union{}, UndefVarError, EFFECTS_THROWS)
35233521
else
@@ -3543,12 +3541,23 @@ function abstract_eval_partition_load(interp::Union{AbstractInterpreter, Nothing
35433541
# Could be replaced by a backdated const which has an effect, so we can't assume it won't.
35443542
# Besides, we would prefer not to merge the world range for this into the world range for
35453543
# _GLOBAL, because that would pessimize codegen.
3546-
local_getglobal_effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
3544+
effects = Effects(local_getglobal_effects, effect_free=ALWAYS_FALSE)
35473545
rt = Any
35483546
else
35493547
rt = partition_restriction(partition)
3548+
effects = local_getglobal_effects
3549+
end
3550+
if (interp !== nothing && InferenceParams(interp).assume_bindings_static &&
3551+
kind in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) &&
3552+
isdefined(binding, :value))
3553+
exct = Union{}
3554+
effects = Effects(generic_getglobal_effects; nothrow=true)
3555+
else
3556+
# We do not assume in general that assigned global bindings remain assigned.
3557+
# The existence of pkgimages allows them to revert in practice.
3558+
exct = UndefVarError
35503559
end
3551-
return RTEffects(rt, UndefVarError, local_getglobal_effects)
3560+
return RTEffects(rt, exct, effects)
35523561
end
35533562

35543563
function scan_specified_partitions(query::Function, walk_binding_partition::Function, interp, g::GlobalRef, wwr::WorldWithRange)
@@ -3596,28 +3605,15 @@ scan_partitions(query::Function, interp, g::GlobalRef, wwr::WorldWithRange) =
35963605
abstract_load_all_consistent_leaf_partitions(interp, g::GlobalRef, wwr::WorldWithRange) =
35973606
scan_leaf_partitions(abstract_eval_partition_load, interp, g, wwr)
35983607

3599-
function abstract_eval_globalref_partition(interp, binding::Core.Binding, partition::Core.BindingPartition)
3600-
# For inference purposes, we don't particularly care which global binding we end up loading, we only
3601-
# care about its type. However, we would still like to terminate the world range for the particular
3602-
# binding we end up reaching such that codegen can emit a simpler pointer load.
3603-
Pair{RTEffects, Union{Nothing, Core.Binding}}(
3604-
abstract_eval_partition_load(interp, partition),
3605-
binding_kind(partition) in (PARTITION_KIND_GLOBAL, PARTITION_KIND_DECLARED) ? binding : nothing)
3606-
end
3607-
36083608
function abstract_eval_globalref(interp, g::GlobalRef, saw_latestworld::Bool, sv::AbsIntState)
36093609
if saw_latestworld
36103610
return RTEffects(Any, Any, generic_getglobal_effects)
36113611
end
3612-
(valid_worlds, (ret, binding_if_global)) = scan_leaf_partitions(abstract_eval_globalref_partition, interp, g, sv.world)
3612+
# For inference purposes, we don't particularly care which global binding we end up loading, we only
3613+
# care about its type. However, we would still like to terminate the world range for the particular
3614+
# binding we end up reaching such that codegen can emit a simpler pointer load.
3615+
(valid_worlds, ret) = scan_leaf_partitions(abstract_eval_partition_load, interp, g, sv.world)
36133616
update_valid_age!(sv, valid_worlds)
3614-
if ret.rt !== Union{} && ret.exct === UndefVarError && binding_if_global !== nothing && InferenceParams(interp).assume_bindings_static
3615-
if isdefined(binding_if_global, :value)
3616-
ret = RTEffects(ret.rt, Union{}, Effects(generic_getglobal_effects, nothrow=true))
3617-
end
3618-
# We do not assume in general that assigned global bindings remain assigned.
3619-
# The existence of pkgimages allows them to revert in practice.
3620-
end
36213617
return ret
36223618
end
36233619

Compiler/test/inference.jl

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

6163+
@newinterp AssumeBindingsStaticInterp
6164+
Compiler.InferenceParams(::AssumeBindingsStaticInterp) = Compiler.InferenceParams(; assume_bindings_static=true)
6165+
61636166
eval(Expr(:const, :swapglobal!_must_throw))
6164-
@newinterp SwapGlobalInterp
6165-
Compiler.InferenceParams(::SwapGlobalInterp) = Compiler.InferenceParams(; assume_bindings_static=true)
61666167
function func_swapglobal!_must_throw(x)
61676168
swapglobal!(@__MODULE__, :swapglobal!_must_throw, x)
61686169
end
6169-
@test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) === Union{}
6170-
@test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=SwapGlobalInterp()) )
6170+
@test Base.infer_return_type(func_swapglobal!_must_throw, (Int,); interp=AssumeBindingsStaticInterp()) === Union{}
6171+
@test !Compiler.is_effect_free(Base.infer_effects(func_swapglobal!_must_throw, (Int,); interp=AssumeBindingsStaticInterp()) )
6172+
6173+
global global_decl_defined
6174+
global_decl_defined = 42
6175+
@test Base.infer_effects(; interp=AssumeBindingsStaticInterp()) do
6176+
global global_decl_defined
6177+
return global_decl_defined
6178+
end |> Compiler.is_nothrow
6179+
global global_decl_defined2::Int
6180+
global_decl_defined2 = 42
6181+
@test Base.infer_effects(; interp=AssumeBindingsStaticInterp()) do
6182+
global global_decl_defined2
6183+
return global_decl_defined2
6184+
end |> Compiler.is_nothrow
61716185

61726186
@eval get_exception() = $(Expr(:the_exception))
61736187
@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)