Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inference: followups for #51754 #52241

Merged
merged 5 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions base/compiler/abstractinterpretation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1196,13 +1196,14 @@ function semi_concrete_eval_call(interp::AbstractInterpreter,
# state = InliningState(interp)
# ir = ssa_inlining_pass!(irsv.ir, state, propagate_inbounds(irsv))
effects = result.effects
if !is_nothrow(effects)
effects = Effects(effects; nothrow)
if nothrow
effects = Effects(effects; nothrow=true)
end
if noub
effects = Effects(effects; noub = ALWAYS_TRUE)
effects = Effects(effects; noub=ALWAYS_TRUE)
end
return ConstCallResults(rt, result.exct, SemiConcreteResult(mi, ir, effects), effects, mi)
exct = refine_exception_type(result.exct, effects)
return ConstCallResults(rt, exct, SemiConcreteResult(mi, ir, effects), effects, mi)
end
end
end
Expand Down Expand Up @@ -2136,7 +2137,7 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
argtypes = Any[typeof(<:), argtypes[3], argtypes[2]]
return abstract_call_known(interp, <:, ArgInfo(fargs, argtypes), si, sv, max_methods)
elseif la == 2 && istopfunction(f, :typename)
return CallMeta(typename_static(argtypes[2]), Any, EFFECTS_TOTAL, MethodResultPure())
return CallMeta(typename_static(argtypes[2]), Bottom, EFFECTS_TOTAL, MethodResultPure())
elseif f === Core._hasmethod
return _hasmethod_tfunc(interp, argtypes, sv)
end
Expand Down Expand Up @@ -3086,6 +3087,14 @@ function propagate_to_error_handler!(frame::InferenceState, currpc::Int, W::BitS
end
end

function update_cycle_worklists!(callback, frame::InferenceState)
for (caller, caller_pc) in frame.cycle_backedges
if callback(caller, caller_pc)
push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
end
end
end

# make as much progress on `frame` as possible (without handling cycles)
function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
@assert !is_inferred(frame)
Expand Down Expand Up @@ -3204,11 +3213,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
elseif isa(stmt, ReturnNode)
rt = abstract_eval_value(interp, stmt.val, currstate, frame)
if update_bestguess!(interp, frame, currstate, rt)
for (caller, caller_pc) in frame.cycle_backedges
if caller.ssavaluetypes[caller_pc] !== Any
# no reason to revisit if that call-site doesn't affect the final result
push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
end
update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
# no reason to revisit if that call-site doesn't affect the final result
return caller.ssavaluetypes[caller_pc] !== Any
end
end
ssavaluetypes[frame.currpc] = Any
Expand All @@ -3231,11 +3238,11 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
if cur_hand == 0
if !⊑(𝕃ₚ, exct, frame.exc_bestguess)
frame.exc_bestguess = tmerge(𝕃ₚ, frame.exc_bestguess, exct)
for (caller, caller_pc) in frame.cycle_backedges
handler = caller.handler_at[caller_pc][1]
if (handler == 0 ? caller.exc_bestguess : caller.handlers[handler].exct) !== Any
push!(caller.ip, block_for_inst(caller.cfg, caller_pc))
end
update_cycle_worklists!(frame) do caller::InferenceState, caller_pc::Int
caller_handler = caller.handler_at[caller_pc][1]
caller_exct = caller_handler == 0 ?
caller.exc_bestguess : caller.handlers[caller_handler].exct
return caller_exct !== Any
end
end
else
Expand Down
3 changes: 1 addition & 2 deletions base/compiler/ssair/irinterp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function abstract_call(interp::AbstractInterpreter, arginfo::ArgInfo, irsv::IRIn
return RTEffects(rt, exct, effects)
end

function kill_block!(ir, bb)
function kill_block!(ir::IRCode, bb::Int)
# Kill the entire block
stmts = ir.cfg.blocks[bb].stmts
for bidx = stmts
Expand All @@ -64,7 +64,6 @@ function kill_block!(ir, bb)
return
end


function update_phi!(irsv::IRInterpretationState, from::Int, to::Int)
ir = irsv.ir
if length(ir.cfg.blocks[to].preds) == 0
Expand Down
16 changes: 12 additions & 4 deletions base/compiler/typeinfer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,11 @@ function adjust_effects(sv::InferenceState)
return ipo_effects
end

function refine_exception_type(@nospecialize(exc_bestguess), ipo_effects::Effects)
ipo_effects.nothrow && return Bottom
return exc_bestguess
end

# inference completed on `me`
# update the MethodInstance
function finish(me::InferenceState, interp::AbstractInterpreter)
Expand Down Expand Up @@ -539,8 +544,8 @@ function finish(me::InferenceState, interp::AbstractInterpreter)
end
me.result.valid_worlds = me.valid_worlds
me.result.result = bestguess
me.result.ipo_effects = me.ipo_effects = adjust_effects(me)
me.result.exc_result = exc_bestguess
ipo_effects = me.result.ipo_effects = me.ipo_effects = adjust_effects(me)
me.result.exc_result = me.exc_bestguess = refine_exception_type(me.exc_bestguess, ipo_effects)

if limited_ret
# a parent may be cached still, but not this intermediate work:
Expand Down Expand Up @@ -862,20 +867,23 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize
isinferred = is_inferred(frame)
edge = isinferred ? mi : nothing
effects = isinferred ? frame.result.ipo_effects : adjust_effects(Effects(), method) # effects are adjusted already within `finish` for ipo_effects
exc_bestguess = refine_exception_type(frame.exc_bestguess, effects)
# propagate newly inferred source to the inliner, allowing efficient inlining w/o deserialization:
# note that this result is cached globally exclusively, we can use this local result destructively
volatile_inf_result = isinferred && let inferred_src = result.src
isa(inferred_src, CodeInfo) && (is_inlineable(inferred_src) || force_inline)
end ? VolatileInferenceResult(result) : nothing
return EdgeCallResult(frame.bestguess, frame.exc_bestguess, edge, effects, volatile_inf_result)
return EdgeCallResult(frame.bestguess, exc_bestguess, edge, effects, volatile_inf_result)
elseif frame === true
# unresolvable cycle
return EdgeCallResult(Any, Any, nothing, Effects())
end
# return the current knowledge about this cycle
frame = frame::InferenceState
update_valid_age!(caller, frame.valid_worlds)
return EdgeCallResult(frame.bestguess, frame.exc_bestguess, nothing, adjust_effects(Effects(), method))
effects = adjust_effects(Effects(), method)
exc_bestguess = refine_exception_type(frame.exc_bestguess, effects)
return EdgeCallResult(frame.bestguess, exc_bestguess, nothing, effects)
end

function cached_return_type(code::CodeInstance)
Expand Down
Loading