inference: refine slot undef info within then branch of @isdefined#55545
inference: refine slot undef info within then branch of @isdefined#55545
then branch of @isdefined#55545Conversation
aa8194c to
8483130
Compare
|
Your benchmark job has completed - possible performance regressions were detected. A full report can be found here. |
| # `isdefined` indicates this `Conditional` is from `@isdefined slot`, implying that | ||
| # the `undef` information of `slot` can be improved in the then branch. | ||
| # Since this is only beneficial for local inference, it is not translated into `InterConditional`. | ||
| isdefined::Bool |
There was a problem hiding this comment.
I'm not sure this works conceptually. isdefined-ness is not a flow property and can be reset by NewvarNode
There was a problem hiding this comment.
Basically to optimize isdefined you need to do ssa construction
There was a problem hiding this comment.
I thought that is a data-flow property. My understanding was that the type/isdefined-ness information for a slot gets reset by NewvarNode, but then both of those get updated along with the abstract interpretation. E.g. within smerge, both typ and undef are being merged.
The purpose of this PR was to eliminate unnecessary :throw_undef_if_not during SSA construction, but I might be making a fundamental mistake.
8483130 to
5e7f92d
Compare
|
@nanosoldier |
|
If the issue is related to |
|
The package evaluation job you requested has completed - possible new issues were detected. |
5e7f92d to
0fcbc16
Compare
|
@nanosoldier |
0fcbc16 to
db19d0a
Compare
|
The package evaluation job you requested has completed - possible new issues were detected. |
By adding some information to `Conditional`, it is possible to improve the `undef` information of `slot` within the `then` branch of `@isdefined slot`. As a result, it's now possible to prove the `:nothrow`-ness in cases like: ```julia @test Base.infer_effects((Bool,Int)) do c, x local val if c val = x end if @isdefined val return val end return zero(Int) end |> Core.Compiler.is_nothrow ```
db19d0a to
3b9dc4b
Compare
|
pkgeval looks just fine, so I believe this PR should be fine to proceed as is, while any issues related to |
As an application of #55545, this commit avoids the insertion of `:throw_undef_if_not` nodes when the defined-ness of a slot is guaranteed by abstract interpretation. ```julia julia> function isdefined_nothrow(c, x) local val if c val = x end if @isdefined val return val end return zero(Int) end; julia> @code_typed isdefined_nothrow(true, 42) ``` ```diff diff --git a/old b/new index c4980a5c9c..3d1d6d30f0 100644 --- a/old +++ b/new @@ -4,7 +4,6 @@ CodeInfo( 3 ┄ %3 = φ (#2 => x, #1 => #undef)::Int64 │ %4 = φ (#2 => true, #1 => false)::Bool └── goto #5 if not %4 -4 ─ $(Expr(:throw_undef_if_not, :val, :(%4)))::Any -└── return %3 +4 ─ return %3 5 ─ return 0 ) => Int64 ```
JuliaLang#55545) By adding some information to `Conditional`, it is possible to improve the `undef` information of `slot` within the `then` branch of `@isdefined slot`. As a result, it's now possible to prove the `:nothrow`-ness in cases like: ```julia @test Base.infer_effects((Bool,Int)) do c, x local val if c val = x end if @isdefined val return val end return zero(Int) end |> Core.Compiler.is_nothrow ```
As an application of #55545, this commit avoids the insertion of `:throw_undef_if_not` nodes when the defined-ness of a slot is guaranteed by abstract interpretation. ```julia julia> function isdefined_nothrow(c, x) local val if c val = x end if @isdefined val return val end return zero(Int) end; julia> @code_typed isdefined_nothrow(true, 42) ``` ```diff diff --git a/old b/new index c4980a5c9c..3d1d6d30f0 100644 --- a/old +++ b/new @@ -4,7 +4,6 @@ CodeInfo( 3 ┄ %3 = φ (#2 => x, #1 => #undef)::Int64 │ %4 = φ (#2 => true, #1 => false)::Bool └── goto #5 if not %4 -4 ─ $(Expr(:throw_undef_if_not, :val, :(%4)))::Any -└── return %3 +4 ─ return %3 5 ─ return 0 ) => Int64 ```
#55545) By adding some information to `Conditional`, it is possible to improve the `undef` information of `slot` within the `then` branch of `@isdefined slot`. As a result, it's now possible to prove the `:nothrow`-ness in cases like: ```julia @test Base.infer_effects((Bool,Int)) do c, x local val if c val = x end if @isdefined val return val end return zero(Int) end |> Core.Compiler.is_nothrow ```
As an application of #55545, this commit avoids the insertion of `:throw_undef_if_not` nodes when the defined-ness of a slot is guaranteed by abstract interpretation. ```julia julia> function isdefined_nothrow(c, x) local val if c val = x end if @isdefined val return val end return zero(Int) end; julia> @code_typed isdefined_nothrow(true, 42) ``` ```diff diff --git a/old b/new index c4980a5c9c..3d1d6d30f0 100644 --- a/old +++ b/new @@ -4,7 +4,6 @@ CodeInfo( 3 ┄ %3 = φ (#2 => x, #1 => #undef)::Int64 │ %4 = φ (#2 => true, #1 => false)::Bool └── goto #5 if not %4 -4 ─ $(Expr(:throw_undef_if_not, :val, :(%4)))::Any -└── return %3 +4 ─ return %3 5 ─ return 0 ) => Int64 ```
By adding some information to
Conditional, it is possible to improve theundefinformation ofslotwithin thethenbranch of@isdefined slot.As a result, it's now possible to prove the
:nothrow-ness in cases like:@nanosoldier
runbenchmarks("inference", vs=":master")