From 8dd0cf5c43af7fe401157c6a5ff6704b71f8fd48 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Mon, 20 Nov 2023 18:19:27 +0900 Subject: [PATCH] inference: refine `exct` information if `:nothrow` is proven --- base/compiler/abstractinterpretation.jl | 9 ++++---- base/compiler/typeinfer.jl | 16 ++++++++++---- test/compiler/inference.jl | 29 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index b14ebe04796c6..d99243a56e969 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -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 diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index 55026e54f777d..de296089f43be 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -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) @@ -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: @@ -862,12 +867,13 @@ 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()) @@ -875,7 +881,9 @@ function typeinf_edge(interp::AbstractInterpreter, method::Method, @nospecialize # 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) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index b75e5e5fe87f0..8cdee8baa90e6 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5558,3 +5558,32 @@ function foo_typed_throw_metherr() return 1 end @test Base.return_types(foo_typed_throw_metherr) |> only === Float64 + +# using `exct` information if `:nothrow` is proven +Base.@assume_effects :nothrow function sin_nothrow(x::Float64) + x == Inf && return zero(x) + return sin(x) +end +@test Base.infer_exception_type(sin_nothrow, (Float64,)) == Union{} +@test Base.return_types((Float64,)) do x + try + return sin_nothrow(x) + catch err + return err + end +end |> only === Float64 +# for semi-concrete interpretation result too +Base.@constprop :aggressive function sin_maythrow(x::Float64, maythrow::Bool) + if maythrow + return sin(x) + else + return @noinline sin_nothrow(x) + end +end +@test Base.return_types((Float64,)) do x + try + return sin_maythrow(x, false) + catch err + return err + end +end |> only === Float64