@@ -3659,6 +3659,107 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
36593659 return typ
36603660end
36613661
3662+ struct AbstractEvalBasicStatementResult
3663+ rt
3664+ exct
3665+ effects:: Union{Nothing,Effects}
3666+ changes:: Union{Nothing,StateUpdate}
3667+ refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3668+ currsaw_latestworld:: Bool
3669+ function AbstractEvalBasicStatementResult (rt, exct, effects:: Union{Nothing,Effects} ,
3670+ changes:: Union{Nothing,StateUpdate} , refinements, currsaw_latestworld:: Bool )
3671+ @nospecialize rt exct refinements
3672+ return new (rt, exct, effects, changes, refinements, currsaw_latestworld)
3673+ end
3674+ end
3675+
3676+ function abstract_eval_basic_statement (interp:: AbstractInterpreter , @nospecialize (stmt), sstate:: StatementState , frame:: InferenceState ,
3677+ result:: Union{Nothing,Future{RTEffects}} = nothing )
3678+ rt = nothing
3679+ exct = Bottom
3680+ changes = nothing
3681+ refinements = nothing
3682+ effects = nothing
3683+ currsaw_latestworld = sstate. saw_latestworld
3684+ if result != = nothing
3685+ @goto injectresult
3686+ end
3687+ if isa (stmt, NewvarNode)
3688+ changes = StateUpdate (stmt. slot, VarState (Bottom, true ))
3689+ elseif isa (stmt, PhiNode)
3690+ add_curr_ssaflag! (frame, IR_FLAGS_REMOVABLE)
3691+ # Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
3692+ # the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
3693+ # over the first and last iterations. By tmerging in the current old_rt, we ensure that
3694+ # we will not lose an intermediate value.
3695+ rt = abstract_eval_phi (interp, stmt, sstate, frame)
3696+ old_rt = frame. ssavaluetypes[frame. currpc]
3697+ rt = old_rt === NOT_FOUND ? rt : tmerge (typeinf_lattice (interp), old_rt, rt)
3698+ else
3699+ lhs = nothing
3700+ if isexpr (stmt, :(= ))
3701+ lhs = stmt. args[1 ]
3702+ stmt = stmt. args[2 ]
3703+ end
3704+ if ! isa (stmt, Expr)
3705+ (; rt, exct, effects, refinements) = abstract_eval_special_value (interp, stmt, sstate, frame)
3706+ else
3707+ hd = stmt. head
3708+ if hd === :method
3709+ fname = stmt. args[1 ]
3710+ if isa (fname, SlotNumber)
3711+ changes = StateUpdate (fname, VarState (Any, false ))
3712+ end
3713+ elseif (hd === :code_coverage_effect ||
3714+ # :boundscheck can be narrowed to Bool
3715+ (hd != = :boundscheck && is_meta_expr (stmt)))
3716+ rt = Nothing
3717+ elseif hd === :latestworld
3718+ currsaw_latestworld = true
3719+ rt = Nothing
3720+ else
3721+ result = abstract_eval_statement_expr (interp, stmt, sstate, frame):: Future{RTEffects}
3722+ if ! isready (result) || ! isempty (frame. tasks)
3723+ return result
3724+
3725+ @label injectresult
3726+ # reload local variables
3727+ lhs = nothing
3728+ if isexpr (stmt, :(= ))
3729+ lhs = stmt. args[1 ]
3730+ stmt = stmt. args[2 ]
3731+ end
3732+ end
3733+ result = result[]
3734+ (; rt, exct, effects, refinements) = result
3735+ if effects. noub === NOUB_IF_NOINBOUNDS
3736+ if has_curr_ssaflag (frame, IR_FLAG_INBOUNDS)
3737+ effects = Effects (effects; noub= ALWAYS_FALSE)
3738+ elseif ! propagate_inbounds (frame)
3739+ # The callee read our inbounds flag, but unless we propagate inbounds,
3740+ # we ourselves don't read our parent's inbounds.
3741+ effects = Effects (effects; noub= ALWAYS_TRUE)
3742+ end
3743+ end
3744+ @assert ! isa (rt, TypeVar) " unhandled TypeVar"
3745+ rt = maybe_singleton_const (rt)
3746+ if ! isempty (frame. pclimitations)
3747+ if rt isa Const || rt === Union{}
3748+ empty! (frame. pclimitations)
3749+ else
3750+ rt = LimitedAccuracy (rt, frame. pclimitations)
3751+ frame. pclimitations = IdSet {InferenceState} ()
3752+ end
3753+ end
3754+ end
3755+ end
3756+ if lhs != = nothing && rt != = Bottom
3757+ changes = StateUpdate (lhs:: SlotNumber , VarState (rt, false ))
3758+ end
3759+ end
3760+ return AbstractEvalBasicStatementResult (rt, exct, effects, changes, refinements, currsaw_latestworld)
3761+ end
3762+
36623763struct BestguessInfo{Interp<: AbstractInterpreter }
36633764 interp:: Interp
36643765 bestguess
@@ -3940,14 +4041,16 @@ end
39404041
39414042# make as much progress on `frame` as possible (without handling cycles)
39424043struct CurrentState
3943- result:: Future
4044+ result:: Future{RTEffects}
39444045 currstate:: VarTable
39454046 currsaw_latestworld:: Bool
39464047 bbstart:: Int
39474048 bbend:: Int
3948- CurrentState (result:: Future , currstate:: VarTable , currsaw_latestworld:: Bool , bbstart:: Int , bbend:: Int ) = new (result, currstate, currsaw_latestworld, bbstart, bbend)
4049+ CurrentState (result:: Future{RTEffects} , currstate:: VarTable , currsaw_latestworld:: Bool , bbstart:: Int , bbend:: Int ) =
4050+ new (result, currstate, currsaw_latestworld, bbstart, bbend)
39494051 CurrentState () = new ()
39504052end
4053+
39514054function typeinf_local (interp:: AbstractInterpreter , frame:: InferenceState , nextresult:: CurrentState )
39524055 @assert ! is_inferred (frame)
39534056 W = frame. ip
@@ -3966,7 +4069,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
39664069 bbend = nextresult. bbend
39674070 currstate = nextresult. currstate
39684071 currsaw_latestworld = nextresult. currsaw_latestworld
3969- @goto injectresult
4072+ stmt = frame. src. code[currpc]
4073+ result = abstract_eval_basic_statement (interp, stmt, StatementState (currstate, currsaw_latestworld), frame, nextresult. result)
4074+ @goto injected_result
39704075 end
39714076
39724077 if currbb != 1
@@ -4119,87 +4224,15 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
41194224 end
41204225 # Process non control-flow statements
41214226 @assert isempty (frame. tasks)
4122- rt = nothing
4123- exct = Bottom
4124- changes = nothing
4125- refinements = nothing
4126- effects = nothing
4127- if isa (stmt, NewvarNode)
4128- changes = StateUpdate (stmt. slot, VarState (Bottom, true ))
4129- elseif isa (stmt, PhiNode)
4130- add_curr_ssaflag! (frame, IR_FLAGS_REMOVABLE)
4131- # Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
4132- # the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
4133- # over the first and last iterations. By tmerging in the current old_rt, we ensure that
4134- # we will not lose an intermediate value.
4135- rt = abstract_eval_phi (interp, stmt, StatementState (currstate, currsaw_latestworld), frame)
4136- old_rt = frame. ssavaluetypes[currpc]
4137- rt = old_rt === NOT_FOUND ? rt : tmerge (typeinf_lattice (interp), old_rt, rt)
4227+ sstate = StatementState (currstate, currsaw_latestworld)
4228+ result = abstract_eval_basic_statement (interp, stmt, sstate, frame)
4229+ if result isa Future{RTEffects}
4230+ return CurrentState (result, currstate, currsaw_latestworld, bbstart, bbend)
41384231 else
4139- lhs = nothing
4140- if isexpr (stmt, :(= ))
4141- lhs = stmt. args[1 ]
4142- stmt = stmt. args[2 ]
4143- end
4144- if ! isa (stmt, Expr)
4145- (; rt, exct, effects, refinements) = abstract_eval_special_value (interp, stmt, StatementState (currstate, currsaw_latestworld), frame)
4146- else
4147- hd = stmt. head
4148- if hd === :method
4149- fname = stmt. args[1 ]
4150- if isa (fname, SlotNumber)
4151- changes = StateUpdate (fname, VarState (Any, false ))
4152- end
4153- elseif (hd === :code_coverage_effect || (
4154- hd != = :boundscheck && # :boundscheck can be narrowed to Bool
4155- is_meta_expr (stmt)))
4156- rt = Nothing
4157- elseif hd === :latestworld
4158- currsaw_latestworld = true
4159- rt = Nothing
4160- else
4161- result = abstract_eval_statement_expr (interp, stmt, StatementState (currstate, currsaw_latestworld), frame):: Future
4162- if ! isready (result) || ! isempty (frame. tasks)
4163- return CurrentState (result, currstate, currsaw_latestworld, bbstart, bbend)
4164- @label injectresult
4165- # reload local variables
4166- stmt = frame. src. code[currpc]
4167- changes = nothing
4168- lhs = nothing
4169- if isexpr (stmt, :(= ))
4170- lhs = stmt. args[1 ]
4171- stmt = stmt. args[2 ]
4172- end
4173- result = nextresult. result:: Future{RTEffects}
4174- end
4175- result = result[]
4176- (; rt, exct, effects, refinements) = result
4177- if effects. noub === NOUB_IF_NOINBOUNDS
4178- if has_curr_ssaflag (frame, IR_FLAG_INBOUNDS)
4179- effects = Effects (effects; noub= ALWAYS_FALSE)
4180- elseif ! propagate_inbounds (frame)
4181- # The callee read our inbounds flag, but unless we propagate inbounds,
4182- # we ourselves don't read our parent's inbounds.
4183- effects = Effects (effects; noub= ALWAYS_TRUE)
4184- end
4185- end
4186- @assert ! isa (rt, TypeVar) " unhandled TypeVar"
4187- rt = maybe_singleton_const (rt)
4188- if ! isempty (frame. pclimitations)
4189- if rt isa Const || rt === Union{}
4190- empty! (frame. pclimitations)
4191- else
4192- rt = LimitedAccuracy (rt, frame. pclimitations)
4193- frame. pclimitations = IdSet {InferenceState} ()
4194- end
4195- end
4196- end
4197- end
4198- effects === nothing || merge_override_effects! (interp, effects, frame)
4199- if lhs != = nothing && rt != = Bottom
4200- changes = StateUpdate (lhs:: SlotNumber , VarState (rt, false ))
4201- end
4232+ @label injected_result
4233+ (; rt, exct, effects, changes, refinements, currsaw_latestworld) = result
42024234 end
4235+ effects === nothing || merge_override_effects! (interp, effects, frame)
42034236 if ! has_curr_ssaflag (frame, IR_FLAG_NOTHROW)
42044237 if exct != = Union{}
42054238 update_exc_bestguess! (interp, exct, frame)
0 commit comments