@@ -3706,6 +3706,107 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
37063706 return typ
37073707end
37083708
3709+ struct AbstractEvalBasicStatementResult
3710+ rt
3711+ exct
3712+ effects:: Union{Nothing,Effects}
3713+ changes:: Union{Nothing,StateUpdate}
3714+ refinements # ::Union{Nothing,SlotRefinement,Vector{Any}}
3715+ currsaw_latestworld:: Bool
3716+ function AbstractEvalBasicStatementResult (rt, exct, effects:: Union{Nothing,Effects} ,
3717+ changes:: Union{Nothing,StateUpdate} , refinements, currsaw_latestworld:: Bool )
3718+ @nospecialize rt exct refinements
3719+ return new (rt, exct, effects, changes, refinements, currsaw_latestworld)
3720+ end
3721+ end
3722+
3723+ function abstract_eval_basic_statement (interp:: AbstractInterpreter , @nospecialize (stmt), sstate:: StatementState , frame:: InferenceState ,
3724+ result:: Union{Nothing,Future{RTEffects}} = nothing )
3725+ rt = nothing
3726+ exct = Bottom
3727+ changes = nothing
3728+ refinements = nothing
3729+ effects = nothing
3730+ currsaw_latestworld = sstate. saw_latestworld
3731+ if result != = nothing
3732+ @goto injectresult
3733+ end
3734+ if isa (stmt, NewvarNode)
3735+ changes = StateUpdate (stmt. slot, VarState (Bottom, true ))
3736+ elseif isa (stmt, PhiNode)
3737+ add_curr_ssaflag! (frame, IR_FLAGS_REMOVABLE)
3738+ # Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
3739+ # the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
3740+ # over the first and last iterations. By tmerging in the current old_rt, we ensure that
3741+ # we will not lose an intermediate value.
3742+ rt = abstract_eval_phi (interp, stmt, sstate, frame)
3743+ old_rt = frame. ssavaluetypes[frame. currpc]
3744+ rt = old_rt === NOT_FOUND ? rt : tmerge (typeinf_lattice (interp), old_rt, rt)
3745+ else
3746+ lhs = nothing
3747+ if isexpr (stmt, :(= ))
3748+ lhs = stmt. args[1 ]
3749+ stmt = stmt. args[2 ]
3750+ end
3751+ if ! isa (stmt, Expr)
3752+ (; rt, exct, effects, refinements) = abstract_eval_special_value (interp, stmt, sstate, frame)
3753+ else
3754+ hd = stmt. head
3755+ if hd === :method
3756+ fname = stmt. args[1 ]
3757+ if isa (fname, SlotNumber)
3758+ changes = StateUpdate (fname, VarState (Any, false ))
3759+ end
3760+ elseif (hd === :code_coverage_effect ||
3761+ # :boundscheck can be narrowed to Bool
3762+ (hd != = :boundscheck && is_meta_expr (stmt)))
3763+ rt = Nothing
3764+ elseif hd === :latestworld
3765+ currsaw_latestworld = true
3766+ rt = Nothing
3767+ else
3768+ result = abstract_eval_statement_expr (interp, stmt, sstate, frame):: Future{RTEffects}
3769+ if ! isready (result) || ! isempty (frame. tasks)
3770+ return result
3771+
3772+ @label injectresult
3773+ # reload local variables
3774+ lhs = nothing
3775+ if isexpr (stmt, :(= ))
3776+ lhs = stmt. args[1 ]
3777+ stmt = stmt. args[2 ]
3778+ end
3779+ end
3780+ result = result[]
3781+ (; rt, exct, effects, refinements) = result
3782+ if effects. noub === NOUB_IF_NOINBOUNDS
3783+ if has_curr_ssaflag (frame, IR_FLAG_INBOUNDS)
3784+ effects = Effects (effects; noub= ALWAYS_FALSE)
3785+ elseif ! propagate_inbounds (frame)
3786+ # The callee read our inbounds flag, but unless we propagate inbounds,
3787+ # we ourselves don't read our parent's inbounds.
3788+ effects = Effects (effects; noub= ALWAYS_TRUE)
3789+ end
3790+ end
3791+ @assert ! isa (rt, TypeVar) " unhandled TypeVar"
3792+ rt = maybe_singleton_const (rt)
3793+ if ! isempty (frame. pclimitations)
3794+ if rt isa Const || rt === Union{}
3795+ empty! (frame. pclimitations)
3796+ else
3797+ rt = LimitedAccuracy (rt, frame. pclimitations)
3798+ frame. pclimitations = IdSet {InferenceState} ()
3799+ end
3800+ end
3801+ end
3802+ end
3803+ if lhs != = nothing && rt != = Bottom
3804+ changes = StateUpdate (lhs:: SlotNumber , VarState (rt, false ))
3805+ end
3806+ end
3807+ return AbstractEvalBasicStatementResult (rt, exct, effects, changes, refinements, currsaw_latestworld)
3808+ end
3809+
37093810struct BestguessInfo{Interp<: AbstractInterpreter }
37103811 interp:: Interp
37113812 bestguess
@@ -3986,14 +4087,16 @@ end
39864087
39874088# make as much progress on `frame` as possible (without handling cycles)
39884089struct CurrentState
3989- result:: Future
4090+ result:: Future{RTEffects}
39904091 currstate:: VarTable
39914092 currsaw_latestworld:: Bool
39924093 bbstart:: Int
39934094 bbend:: Int
3994- CurrentState (result:: Future , currstate:: VarTable , currsaw_latestworld:: Bool , bbstart:: Int , bbend:: Int ) = new (result, currstate, currsaw_latestworld, bbstart, bbend)
4095+ CurrentState (result:: Future{RTEffects} , currstate:: VarTable , currsaw_latestworld:: Bool , bbstart:: Int , bbend:: Int ) =
4096+ new (result, currstate, currsaw_latestworld, bbstart, bbend)
39954097 CurrentState () = new ()
39964098end
4099+
39974100function typeinf_local (interp:: AbstractInterpreter , frame:: InferenceState , nextresult:: CurrentState )
39984101 @assert ! is_inferred (frame)
39994102 W = frame. ip
@@ -4012,7 +4115,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
40124115 bbend = nextresult. bbend
40134116 currstate = nextresult. currstate
40144117 currsaw_latestworld = nextresult. currsaw_latestworld
4015- @goto injectresult
4118+ stmt = frame. src. code[currpc]
4119+ result = abstract_eval_basic_statement (interp, stmt, StatementState (currstate, currsaw_latestworld), frame, nextresult. result)
4120+ @goto injected_result
40164121 end
40174122
40184123 if currbb != 1
@@ -4165,87 +4270,15 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState, nextr
41654270 end
41664271 # Process non control-flow statements
41674272 @assert isempty (frame. tasks)
4168- rt = nothing
4169- exct = Bottom
4170- changes = nothing
4171- refinements = nothing
4172- effects = nothing
4173- if isa (stmt, NewvarNode)
4174- changes = StateUpdate (stmt. slot, VarState (Bottom, true ))
4175- elseif isa (stmt, PhiNode)
4176- add_curr_ssaflag! (frame, IR_FLAGS_REMOVABLE)
4177- # Implement convergence for PhiNodes. In particular, PhiNodes need to tmerge over
4178- # the incoming values from all iterations, but `abstract_eval_phi` will only tmerge
4179- # over the first and last iterations. By tmerging in the current old_rt, we ensure that
4180- # we will not lose an intermediate value.
4181- rt = abstract_eval_phi (interp, stmt, StatementState (currstate, currsaw_latestworld), frame)
4182- old_rt = frame. ssavaluetypes[currpc]
4183- rt = old_rt === NOT_FOUND ? rt : tmerge (typeinf_lattice (interp), old_rt, rt)
4273+ sstate = StatementState (currstate, currsaw_latestworld)
4274+ result = abstract_eval_basic_statement (interp, stmt, sstate, frame)
4275+ if result isa Future{RTEffects}
4276+ return CurrentState (result, currstate, currsaw_latestworld, bbstart, bbend)
41844277 else
4185- lhs = nothing
4186- if isexpr (stmt, :(= ))
4187- lhs = stmt. args[1 ]
4188- stmt = stmt. args[2 ]
4189- end
4190- if ! isa (stmt, Expr)
4191- (; rt, exct, effects, refinements) = abstract_eval_special_value (interp, stmt, StatementState (currstate, currsaw_latestworld), frame)
4192- else
4193- hd = stmt. head
4194- if hd === :method
4195- fname = stmt. args[1 ]
4196- if isa (fname, SlotNumber)
4197- changes = StateUpdate (fname, VarState (Any, false ))
4198- end
4199- elseif (hd === :code_coverage_effect || (
4200- hd != = :boundscheck && # :boundscheck can be narrowed to Bool
4201- is_meta_expr (stmt)))
4202- rt = Nothing
4203- elseif hd === :latestworld
4204- currsaw_latestworld = true
4205- rt = Nothing
4206- else
4207- result = abstract_eval_statement_expr (interp, stmt, StatementState (currstate, currsaw_latestworld), frame):: Future
4208- if ! isready (result) || ! isempty (frame. tasks)
4209- return CurrentState (result, currstate, currsaw_latestworld, bbstart, bbend)
4210- @label injectresult
4211- # reload local variables
4212- stmt = frame. src. code[currpc]
4213- changes = nothing
4214- lhs = nothing
4215- if isexpr (stmt, :(= ))
4216- lhs = stmt. args[1 ]
4217- stmt = stmt. args[2 ]
4218- end
4219- result = nextresult. result:: Future{RTEffects}
4220- end
4221- result = result[]
4222- (; rt, exct, effects, refinements) = result
4223- if effects. noub === NOUB_IF_NOINBOUNDS
4224- if has_curr_ssaflag (frame, IR_FLAG_INBOUNDS)
4225- effects = Effects (effects; noub= ALWAYS_FALSE)
4226- elseif ! propagate_inbounds (frame)
4227- # The callee read our inbounds flag, but unless we propagate inbounds,
4228- # we ourselves don't read our parent's inbounds.
4229- effects = Effects (effects; noub= ALWAYS_TRUE)
4230- end
4231- end
4232- @assert ! isa (rt, TypeVar) " unhandled TypeVar"
4233- rt = maybe_singleton_const (rt)
4234- if ! isempty (frame. pclimitations)
4235- if rt isa Const || rt === Union{}
4236- empty! (frame. pclimitations)
4237- else
4238- rt = LimitedAccuracy (rt, frame. pclimitations)
4239- frame. pclimitations = IdSet {InferenceState} ()
4240- end
4241- end
4242- end
4243- end
4244- effects === nothing || merge_override_effects! (interp, effects, frame)
4245- if lhs != = nothing && rt != = Bottom
4246- changes = StateUpdate (lhs:: SlotNumber , VarState (rt, false ))
4247- end
4278+ @label injected_result
4279+ (; rt, exct, effects, changes, refinements, currsaw_latestworld) = result
42484280 end
4281+ effects === nothing || merge_override_effects! (interp, effects, frame)
42494282 if ! has_curr_ssaflag (frame, IR_FLAG_NOTHROW)
42504283 if exct != = Union{}
42514284 update_exc_bestguess! (interp, exct, frame)
0 commit comments