forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inference: inter-procedural conditional constraint back-propagation
This PR propagates `Conditional`s inter-procedurally when a `Conditional` at return site imposes a constraint on the call arguments. When inference exits local frame and the return type is annotated as `Conditional`, it will be converted into `InterConditional` object, which is implemented in `Core` and can be directly put into the global cache. Finally after going back to caller frame, `InterConditional` will be re-converted into `Conditional` in the context of the caller frame. ## improvements So now some simple "is-wrapper" functions will propagate its constraint as expected, e.g.: ```julia isaint(a) = isa(a, Int) @test Base.return_types((Any,)) do a isaint(a) && return a # a::Int return 0 end == Any[Int] isaint2(::Any) = false isaint2(::Int) = true @test Base.return_types((Any,)) do a isaint2(a) && return a # a::Int return 0 end == Any[Int] function isa_int_or_float64(a) isa(a, Int) && return true isa(a, Float64) && return true return false end @test Base.return_types((Any,)) do a isa_int_or_float64(a) && return a # a::Union{Float64,Int} 0 end == Any[Union{Float64,Int}] ``` (and now we don't need something like JuliaLang#38636) ## benchmarks A compile time comparison: > on the current master (82d79ce) ``` Sysimage built. Summary: Total ─────── 55.295376 seconds Base: ─────── 23.359226 seconds 42.2444% Stdlibs: ──── 31.934773 seconds 57.7531% JULIA usr/lib/julia/sys-o.a Generating REPL precompile statements... 29/29 Executing precompile statements... 1283/1283 Precompilation complete. Summary: Total ─────── 91.129162 seconds Generation ── 68.800937 seconds 75.4983% Execution ─── 22.328225 seconds 24.5017% LINK usr/lib/julia/sys.dylib ``` > on this PR (37e279b) ``` Sysimage built. Summary: Total ─────── 51.694730 seconds Base: ─────── 21.943914 seconds 42.449% Stdlibs: ──── 29.748987 seconds 57.5474% JULIA usr/lib/julia/sys-o.a Generating REPL precompile statements... 29/29 Executing precompile statements... 1357/1357 Precompilation complete. Summary: Total ─────── 88.956226 seconds Generation ── 67.077710 seconds 75.4053% Execution ─── 21.878515 seconds 24.5947% LINK usr/lib/julia/sys.dylib ``` Here is a sample code that benefits from this PR: ```julia function summer(ary) r = 0 for a in ary if ispositive(a) r += a end end r end ispositive(a) = isa(a, Int) && a > 0 ary = Any[] for _ in 1:100_000 if rand(Bool) push!(ary, rand(-100:100)) elseif rand(Bool) push!(ary, rand('a':'z')) else push!(ary, nothing) end end using BenchmarkTools @Btime summer($(ary)) ``` > on the current master (82d79ce) ``` ❯ julia summer.jl 1.214 ms (24923 allocations: 389.42 KiB) ``` > on this PR (37e279b) ``` ❯ julia summer.jl 421.223 μs (0 allocations: 0 bytes) ``` ## caveats Within the `Conditional`/`InterConditional` framework, only a single constraint can be back-propagated inter-procedurally. This PR implements a naive heuristic to "pick up" a constraint to be propagated when a return type is a boolean. The heuristic may fail to select an "interesting" constraint in some cases. For example, we may expect `::Expr` constraint to be imposed on the first argument of `Meta.isexpr`, but the current heuristic ends up picking up a constraint on the second argument (i.e. `ex.head === head`). ```julia isexpr(@nospecialize(ex), head::Symbol) = isa(ex, Expr) && ex.head === head @test_broken Base.return_types((Any,)) do x Meta.isexpr(x, :call) && return x # x::Expr, ideally return nothing end == Any[Union{Nothing,Expr}] ``` I think We can get rid of this limitation by extending `Conditional` and `InterConditional` so that they can convey multiple constraints, but I'd like to leave this as a future work. --- - closes JuliaLang#38636 - closes JuliaLang#37342
- Loading branch information
Showing
11 changed files
with
236 additions
and
39 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.