Last active
February 24, 2017 01:15
-
-
Save andyferris/67c5c163160efeea20a9ada49fdb6fba to your computer and use it in GitHub Desktop.
Comparison of direct generated functions vs. `unroll_tuple` as a utility function to unroll expressions
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
# "bespoke" generated functions | |
Pkg.checkout("StaticArrays","master") | |
using StaticArrays | |
f(v) = @inbounds return v[v] | |
v = SVector{3,Int}((1,2,3)) | |
# results: | |
julia> @code_native f(v) | |
.text | |
Filename: REPL[3] | |
pushq %rbp | |
movq %rsp, %rbp | |
Source line: 25 | |
movq (%rsi), %rax | |
movq 8(%rsi), %rcx | |
movq -8(%rsi,%rax,8), %rax | |
movq -8(%rsi,%rcx,8), %rcx | |
movq 16(%rsi), %rdx | |
movq -8(%rsi,%rdx,8), %rdx | |
Source line: 1 | |
movq %rax, (%rdi) | |
movq %rcx, 8(%rdi) | |
movq %rdx, 16(%rdi) | |
movq %rdi, %rax | |
popq %rbp | |
retq | |
nop | |
julia> @code_warntype f(v) | |
Variables: | |
#self#::#f | |
v::StaticArrays.SVector{3,Int64} | |
Body: | |
begin | |
$(Expr(:inbounds, true)) | |
# meta: location /home/ferris/.julia/v0.6/StaticArrays/src/indexing.jl getindex 20 | |
# meta: location /home/ferris/.julia/v0.6/StaticArrays/src/indexing.jl # line 25: | |
SSAValue(0) = $(Expr(:new, :($(QuoteNode(StaticArrays.SVector{3,Int64}))), :((Core.tuple)((Base.getfield)((Core.getfield)(v, :data)::Tuple{Int64,Int64,Int64}, (Base.getfield)((Core.getfield)(v, :data)::Tuple{Int64,Int64,Int64}, 1)::Int64)::Int64, (Base.getfield)((Core.getfield)(v, :data)::Tuple{Int64,Int64,Int64}, (Base.getfield)((Core.getfield)(v, :data)::Tuple{Int64,Int64,Int64}, 2)::Int64)::Int64, (Base.getfield)((Core.getfield)(v, :data)::Tuple{Int64,Int64,Int64}, (Base.getfield)((Core.getfield)(v, :data)::Tuple{Int64,Int64,Int64}, 3)::Int64)::Int64)::Tuple{Int64,Int64,Int64}))) | |
# meta: pop location | |
# meta: pop location | |
return SSAValue(0) | |
$(Expr(:inbounds, :pop)) | |
end::StaticArrays.SVector{3,Int64} | |
# "centralized" generated functions | |
Pkg.checkout("StaticArrays","julia-0.6") | |
using StaticArrays | |
f(v) = @inbounds return v[v] | |
v = SVector{3,Int}((1,2,3)) | |
# results: | |
julia> @code_native f(v) | |
.text | |
Filename: REPL[3] | |
pushq %rbp | |
movq %rsp, %rbp | |
Source line: 7 | |
movq 16(%rsi), %rax | |
movq %rax, -80(%rbp) | |
vmovups (%rsi), %xmm0 | |
vmovaps %xmm0, -96(%rbp) | |
movq 16(%rsi), %rax | |
movq %rax, -56(%rbp) | |
vmovups (%rsi), %xmm0 | |
vmovups %xmm0, -72(%rbp) | |
vmovups -96(%rbp), %ymm0 | |
vmovups -80(%rbp), %ymm1 | |
vmovups %ymm1, -32(%rbp) | |
vmovups %ymm0, -48(%rbp) | |
Source line: 13 | |
movq -24(%rbp), %rax | |
movq -16(%rbp), %rcx | |
movq -56(%rbp,%rax,8), %rax | |
movq -56(%rbp,%rcx,8), %rcx | |
movq -8(%rbp), %rdx | |
movq -56(%rbp,%rdx,8), %rdx | |
Source line: 1 | |
movq %rax, (%rdi) | |
movq %rcx, 8(%rdi) | |
movq %rdx, 16(%rdi) | |
movq %rdi, %rax | |
popq %rbp | |
vzeroupper | |
retq | |
nopl (%rax,%rax) | |
julia> @code_warntype f(v) | |
Variables: | |
#self#::#f | |
v::StaticArrays.SVector{3,Int64} | |
#151::StaticArrays.##151#152{StaticArrays.SVector{3,Int64},StaticArrays.SVector{3,Int64}} | |
Body: | |
begin | |
$(Expr(:inbounds, true)) | |
# meta: location /home/ferris/.julia/v0.6/StaticArrays/src/indexing.jl getindex 7 | |
SSAValue(0) = $(QuoteNode(StaticArrays.SVector{3,Int64})) | |
#151::StaticArrays.##151#152{StaticArrays.SVector{3,Int64},StaticArrays.SVector{3,Int64}} = $(Expr(:new, :($(QuoteNode(StaticArrays.##151#152{StaticArrays.SVector{3,Int64},StaticArrays.SVector{3,Int64}}))), :(v), :(v))) | |
SSAValue(1) = #151::StaticArrays.##151#152{StaticArrays.SVector{3,Int64},StaticArrays.SVector{3,Int64}} | |
SSAValue(2) = $(QuoteNode(Length(3))) | |
# meta: location /home/ferris/.julia/v0.6/StaticArrays/src/traits.jl unroll_tuple 105 | |
# meta: location /home/ferris/.julia/v0.6/StaticArrays/src/generated.jl unroll_tuple 9 | |
# meta: location /home/ferris/.julia/v0.6/StaticArrays/src/generated.jl # line 13: | |
SSAValue(4) = (Core.tuple)((Base.getfield)((Core.getfield)((Core.getfield)(SSAValue(1), :a)::StaticArrays.SVector{3,Int64}, :data)::Tuple{Int64,Int64,Int64}, (Base.getfield)((Core.getfield)((Core.getfield)(SSAValue(1), :inds)::StaticArrays.SVector{3,Int64}, :data)::Tuple{Int64,Int64,Int64}, 1)::Int64)::Int64, (Base.getfield)((Core.getfield)((Core.getfield)(SSAValue(1), :a)::StaticArrays.SVector{3,Int64}, :data)::Tuple{Int64,Int64,Int64}, (Base.getfield)((Core.getfield)((Core.getfield)(SSAValue(1), :inds)::StaticArrays.SVector{3,Int64}, :data)::Tuple{Int64,Int64,Int64}, 2)::Int64)::Int64, (Base.getfield)((Core.getfield)((Core.getfield)(SSAValue(1), :a)::StaticArrays.SVector{3,Int64}, :data)::Tuple{Int64,Int64,Int64}, (Base.getfield)((Core.getfield)((Core.getfield)(SSAValue(1), :inds)::StaticArrays.SVector{3,Int64}, :data)::Tuple{Int64,Int64,Int64}, 3)::Int64)::Int64)::Tuple{Int64,Int64,Int64} | |
# meta: pop location | |
# meta: pop location | |
# meta: pop location | |
SSAValue(3) = SSAValue(4) | |
# meta: pop location | |
return $(Expr(:new, :($(QuoteNode(StaticArrays.SVector{3,Int64}))), SSAValue(3))) | |
$(Expr(:inbounds, :pop)) | |
end::StaticArrays.SVector{3,Int64} |
For reference, this is the "thunk-based" system that does generate good code:
@propagate_inbounds function getindex(a::AbstractArray, inds::StaticVector{<:Integer})
_getindex(Size(inds), a, inds)
end
@generated function _getindex(s::Size{S}, a::AbstractArray, inds::StaticVector{<:Integer}) where S
@assert(S isa Tuple{Int})
exprs = [:(a[inds[$i]]) for i = 1:S[1]]
return quote
@_propagate_inbounds_meta
return similar_type(a, eltype(a), s)($(Expr(:tuple, exprs...)))
end
end
This just takes what is on master and moves the Size
computation to a thunk and moves similar_type
to the generated body.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The new methods in question are this
getindex
andunroll_tuple
.There seems to be enough inbounds propagation, so it's nice to see that working.