-
Notifications
You must be signed in to change notification settings - Fork 6
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
builtin: add ifelse
handling
#4
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Only one minor comment or confusion.
@@ -216,6 +217,20 @@ function find_escapes(ir::IRCode, nargs::Int) | |||
continue | |||
elseif ft === typeof(isa) || ft === typeof(typeof) || ft === typeof(Core.sizeof) | |||
continue | |||
elseif ft === typeof(ifelse) && length(stmt.args) === 4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if length(stmt.args) == 4
would be faster than this and if this check has already done before our analysis (i.e. any ifelse
call without 4 args will fail)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I think we can remove this kind of check once we tackle #6 (, where we will assert a call won't throw at runtime ahead of this check, and it will have filtered out those malformed builtin calls).
For now, I'd like to preserve this since otherwise we may encounter BoundsError
in the next line.
1e6418b
to
d31a460
Compare
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, although it is still analyzed as `ThrownEscape`.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, although it is still analyzed as `ThrownEscape`.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
This commit implements a simple, flow-insensitive alias analysis using an approach inspired by the escape analysis algorithm explained in the old JVM paper [^JVM05]. `EscapeLattice` is extended so that it also keeps track of possible field values. In more detail, `x::EscapeLattice` has the new field called `x.FieldSet::Union{Vector{IdSet{Any}},Bool}`, where: - `x.FieldSets === false` indicates the fields of `x` isn't analyzed yet - `x.FieldSets === true` indicates the fields of `x` can't be analyzed, e.g. the type of `x` is not concrete and thus the number of its fields can't known precisely - otherwise `x.FieldSets::Vector{IdSet{Any}}` holds all the possible values of each field, where `x.FieldSets[i]` keeps all possibilities that the `i`th field can be And now, in addition to managing escape lattice elements, the analysis state also maintains an "alias set" `state.aliasset::IntDisjointSet{Int}`, which is implemented as a disjoint set of aliased arguments and SSA statements. When the fields of object `x` are known precisely (i.e. `x.FieldSets isa Vector{IdSet{Any}}` holds), the alias set is updated each time `z = getfield(x, y)` is encountered in a way that `z` is aliased to all values of `x.FieldSets[y]`, so that escape information imposed on `z` will be propagated to all the aliased values and `z` can be replaced with an aliased value later. Note that in a case when the fields of object `x` can't known precisely (i.e. `x.FieldSets` is `true`), when `z = getfield(x, y)` is analyzed, escape information of `z` is propagated to `x` rather than any of `x`'s fields, which is the most conservative propagation since escape information imposed on `x` will end up being propagated to all of its fields anyway at definitions of `x` (i.e. `:new` expression or `setfield!` call). [^JVM05]: Escape Analysis in the Context of Dynamic Compilation and Deoptimization. Thomas Kotzmann and Hanspeter Mössenböck, 2005, June. <https://dl.acm.org/doi/10.1145/1064979.1064996>. Now this alias analysis should allow us to implement a "stronger" SROA, which eliminates the allocation of `r` within the following code: ```julia julia> result = analyze_escapes((String,)) do s r = Ref(s) broadcast(identity, r) end \#3(_2::String *, _3::Base.RefValue{String} ◌) in Main at REPL[2]:2 2 ↓ 1 ─ %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref 3 ✓ │ %2 = Core.tuple(%1)::Tuple{Base.RefValue{String}} │╻ broadcast ↓ │ %3 = Core.getfield(%2, 1)::Base.RefValue{String} ││ ◌ └── goto #3 if not true ││╻╷ materialize ◌ 2 ─ nothing::Nothing │ * 3 ┄ %6 = Base.getfield(%3, :x)::String │││╻╷╷╷╷ copy ◌ └── goto #4 ││││┃ getindex ◌ 4 ─ goto #5 ││││ ◌ 5 ─ goto #6 │││ ◌ 6 ─ goto #7 ││ ◌ 7 ─ return %6 │ julia> EscapeAnalysis.get_aliases(result.state.aliasset, Core.SSAValue(6), result.ir) 2-element Vector{Union{Core.Argument, Core.SSAValue}}: Core.Argument(2) :(%6) ``` Note that the allocation `%1` isn't analyzed as `ReturnEscape`, still `_2` is analyzed so.
No description provided.