Hello,
I encountered this behavior that I don’t understand. I am defining a wrapper around an array and using the AbstractArray
interface:
abstract type aw{T,N} <: AbstractArray{T,N} end
struct wrap2{T,N} <: aw{T,N}
v::Array{T,N}
end
Base.size(w::wrap2)=size(w.v)
@inline Base.getindex(w::wrap2,i)=(@boundscheck checkbounds(w,i);@inbounds w.v[i])
@inline Base.setindex!(w::wrap2,v,i)=(@boundscheck checkbounds(w,i);@inbounds w.v[i]=v)
#@inline Base.similar(w::wrap2,::Type{T},dims::Dims{N}) where {T,N}=wrap2{T,N}(similar(w.v,T,dims))
Now, I define a function that can be optimized to a no-op:
bb(x)=(x.=x.*1.0)
rrr=rand(10^7);wwr=wrap2(copy(rrr));
@time bb(rrr);
@time bb(wwr);
0.000002 seconds (4 allocations: 160 bytes)
0.000001 seconds (3 allocations: 144 bytes)
The compiler is smart enough to optimize this function call (timing is independent of the size.
However, if I uncomment the definition of similar
above, The optimization does not happen for wrap2
. I cannot understand why, and similar is never called!
I looked at the output of code_typed
(don’t trust me, I am no expert on this) and the only place where I saw some significant difference is:
With similar
defined:
│││││││││ 18 ─ %49 = invoke Base.unaliascopy(_2::wrap2{Float64,1})::wrap2{Float64,1}
│││││││││ └─── goto #20
Without similar
:
│││││││││ 18 ─ invoke Base.unaliascopy(_2::wrap2{Float64,1})::Union{}
│││││││││ └─── $(Expr(:unreachable))::Union{}
Can someone please help me understand what is going on, and how to fix it?
Thanks!