Skip to content
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

[feature] inference constant propagation even for union-split methods #33655

Closed
rfourquet opened this issue Oct 24, 2019 · 4 comments
Closed
Assignees
Labels
compiler:inference Type inference feature Indicates new feature / enhancement requests

Comments

@rfourquet
Copy link
Member

Consider the following example:

const PairUnion = Union{Pair{Int,Int8},Pair{Int,UInt8}}

array = PairUnion[1=>0x2]

function pair1(a)
    x, y = a[1]
    x => y
end

function pair2(a)
    xy = a[1]
    x = xy.first
    y = xy.second
    x => y
end

function pair3(a)
    xy = a[1]
    x = first(xy)
    y = last(xy)
    x => y
end

Then:

julia> @btime pair1($array)
  73.935 ns (1 allocation: 32 bytes)
1 => 0x02

julia> @btime pair2($array)
  76.299 ns (1 allocation: 32 bytes)
1 => 0x02

julia> @btime pair3($array)
  5.051 ns (0 allocations: 0 bytes)
1 => 0x02

When looking at @code_warntype, it looks like x and y are inferred to be Union{Int,Int8,UInt8} for pair1 and pair2, while in pair3 they are inferred as Int and Union{Int8,UInt8} as expected.

@rfourquet rfourquet added compiler:inference Type inference performance Must go faster labels Oct 24, 2019
@KristofferC
Copy link
Member

Seems to be something with getproperty, rewriting as

julia> function pair4(a)
           xy = a[1]
           x = getfield(xy, :first)
           y = getfield(xy, :second)
           x => y
       end
pair4 (generic function with 1 method)

julia> @code_warntype pair4(array)
Variables
  #self#::Core.Compiler.Const(pair4, false)
  a::Array{Union{Pair{Int64,Int8}, Pair{Int64,UInt8}},1}
  xy::Union{Pair{Int64,Int8}, Pair{Int64,UInt8}}
  x::Int64
  y::Union{Int8, UInt8}

Body::Union{Pair{Int64,Int8}, Pair{Int64,UInt8}}
1 ─      (xy = Base.getindex(a, 1))
│        (x = Main.getfield(xy, :first))
│        (y = Main.getfield(xy, :second))
│   %4 = (x => y)::Union{Pair{Int64,Int8}, Pair{Int64,UInt8}}
└──      return %4

makes it work well again.

@rfourquet
Copy link
Member Author

Seems to be something with getproperty, rewriting as

I had suspected as well, and had tried the exact same pair4 function, but without checking the @code_warntype output, which indeed seems to solve the problem. I had only benchmarked it, which gives:

julia> @btime pair4($array)
  53.924 ns (2 allocations: 64 bytes)
1 => 0x02

So this is still not as nice as with the first/last functions. So this may not be only a problem of inference after all, but also of getfield.

@vtjnash vtjnash added feature Indicates new feature / enhancement requests and removed performance Must go faster labels Jul 13, 2020
@vtjnash vtjnash changed the title pair.first leads to worse inferred code than first(pair) [feature] inference constant propagation even for union-split methods Jul 13, 2020
@vtjnash
Copy link
Member

vtjnash commented Jul 13, 2020

It's just heuristically avoiding constant propagation when one of the arguments is union-split

@aviatesk
Copy link
Member

Duplicate of #37610, and #39305 will fix this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:inference Type inference feature Indicates new feature / enhancement requests
Projects
None yet
Development

No branches or pull requests

4 participants