Inference: propagate struct initialization info on setfield!#57222
Merged
aviatesk merged 8 commits intoJuliaLang:masterfrom Feb 8, 2025
Merged
Inference: propagate struct initialization info on setfield!#57222aviatesk merged 8 commits intoJuliaLang:masterfrom
setfield!#57222aviatesk merged 8 commits intoJuliaLang:masterfrom
Conversation
Member
Author
|
The mechanism used to propagate |
b6aeb98 to
9906616
Compare
Member
Author
|
This should be ready (if no new issues are detected in tests) @aviatesk |
Member
|
Restarted |
topolarity
pushed a commit
that referenced
this pull request
Feb 25, 2025
…57304) So far, `PartialStruct` has been unable to represent non-contiguously defined fields, where e.g. a struct would have fields 1 and 3 defined but not field 2. This PR extends it so that such information may be represented with `PartialStruct`, extending the applicability of optimizations e.g. introduced in #55297 by @aviatesk or #57222. The semantics of `new` prevent the creation of a struct with non-contiguously defined fields, therefore this change is mostly relevant to model mutable structs whose fields may be previously set or assumed to be defined after creation, or immutable structs whose creation is opaque. Notably, with this change we may now infer information about structs in the following case: ```julia mutable struct A; x; y; z; A() = new(); end function f() mut = A() # some opaque call preventing optimizations # who knows, maybe `identity` will set fields from `mut` in a future world age! invokelatest(identity, mut) isdefined(mut, :z) && isdefined(mut, :x) || return isdefined(mut, :x) & isdefined(mut, :z) # this now infers as `true` isdefined(mut, :y) # this does not end ``` whereas previously, only information gained successively with `isdefined(mut, :x) && isdefined(mut, :y) && isdefined(mut, :z)` could allow inference to model `mut` having its `z` field defined. --------- Co-authored-by: Cédric Belmant <cedric.belmant@juliahub.com> Co-authored-by: Shuhei Kadowaki <aviatesk@gmail.com>
serenity4
added a commit
to serenity4/julia
that referenced
this pull request
May 1, 2025
…Lang#57222) When a variable has a field set with `setfield!(var, field, value)`, inference now assumes that this specific field is defined and may for example constant-propagate `isdefined(var, field)` as `true`. `PartialStruct`, the lattice element used to encode this information, still has a few limitations in terms of what it may represent (it cannot represent mutable structs with non-contiguously defined fields yet), further work on extending it would increase the impact of this change. Consider the following function: ```julia julia> function f() a = A(1) setfield!(a, :y, 2) invokelatest(identity, a) isdefined(a, :y) && return 1.0 a end f (generic function with 1 method) ``` Here is before on `master`: ```julia julia> @code_typed f() CodeInfo( 1 ─ %1 = %new(Main.A, 1)::A │ builtin Main.setfield!(%1, :y, 2)::Int64 │ dynamic builtin (Core._call_latest)(identity, %1)::Any │ %4 = builtin Main.isdefined(%1, :y)::Bool └── goto JuliaLang#3 if not %4 2 ─ return 1.0 3 ─ return %1 ) => Union{Float64, A} ``` And after this PR: ```julia julia> @code_typed f() CodeInfo( 1 ─ %1 = %new(Main.A, 1)::A │ builtin Main.setfield!(%1, :y, 2)::Int64 │ dynamic builtin (Core._call_latest)(identity, %1)::Any └── return 1.0 ) => Float64 ``` --------- Co-authored-by: Cédric Belmant <cedric.belmant@juliahub.com>
serenity4
added a commit
to serenity4/julia
that referenced
this pull request
May 1, 2025
…uliaLang#57304) So far, `PartialStruct` has been unable to represent non-contiguously defined fields, where e.g. a struct would have fields 1 and 3 defined but not field 2. This PR extends it so that such information may be represented with `PartialStruct`, extending the applicability of optimizations e.g. introduced in JuliaLang#55297 by @aviatesk or JuliaLang#57222. The semantics of `new` prevent the creation of a struct with non-contiguously defined fields, therefore this change is mostly relevant to model mutable structs whose fields may be previously set or assumed to be defined after creation, or immutable structs whose creation is opaque. Notably, with this change we may now infer information about structs in the following case: ```julia mutable struct A; x; y; z; A() = new(); end function f() mut = A() # some opaque call preventing optimizations # who knows, maybe `identity` will set fields from `mut` in a future world age! invokelatest(identity, mut) isdefined(mut, :z) && isdefined(mut, :x) || return isdefined(mut, :x) & isdefined(mut, :z) # this now infers as `true` isdefined(mut, :y) # this does not end ``` whereas previously, only information gained successively with `isdefined(mut, :x) && isdefined(mut, :y) && isdefined(mut, :z)` could allow inference to model `mut` having its `z` field defined. --------- Co-authored-by: Cédric Belmant <cedric.belmant@juliahub.com> Co-authored-by: Shuhei Kadowaki <aviatesk@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When a variable has a field set with
setfield!(var, field, value), inference now assumes that this specific field is defined and may for example constant-propagateisdefined(var, field)astrue.PartialStruct, the lattice element used to encode this information, still has a few limitations in terms of what it may represent (it cannot represent mutable structs with non-contiguously defined fields yet), further work on extending it would increase the impact of this change.Consider the following function:
Here is before on
master:And after this PR: