-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Better document for @inbounds #17702
Comments
What counts as "unsupported"? so |
In other words, the code @inbounds f(a,i) = a[i] should either disable bounds checking in the array access in the defined function |
I don't see how the error can possibly be raised reliably. Examples |
Also |
With unsupported I mean not operating julia> @inbounds function g(x)
return x[2]
end
julia> g([1])
ERROR: BoundsError: attempt to access 1-element Array{Int64,1}:
1
at index [2]
in g at none:2 I'm just grasping now how much I didn't understand about julia> @inbounds if true
[1][2]
end
ERROR: BoundsError: attempt to access 1-element Array{Int64,1} at index [2]
in getindex(::Array{Int64,1}, ::Int64) at ./array.jl:309
in eval(::Module, ::Any) at ./boot.jl:225
in macro expansion at ./REPL.jl:92 [inlined]
in (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:46
julia> function f()
@inbounds if true
[1][2]
end
end
julia> f() Replace if for The problem is that the explanation in performance tips is not very clear about the usage. And not having errors for cases like the one in the description, makes it even more confusing.
The only exception is the for loop, it can be done anywhere @inbounds for i in 1:10
[1][2]
end It is unclear what works and what doesn't. So errors or something more in the docs would make it less mysterious. |
If there are some expressions it can't possibly remove bounds check from, then it must say something |
|
I don't think we should make If it is not in the doc already, it should be mentioned that |
I've added the doc label ~10s before your comment ... ;-p |
I guess #17700 should be closed too, I can try to explain it better but I don't particularly understand fully yet |
I believe you can improve on #17700 by giving an example of operating on a whole function: f() = @inbounds begin
...
end And mentions that the bounds check is only/might only be disabled during the evaluation of it's arguments and therefore @inbounds f() = begin
....
end only disables boundscheck (might not even since it's most likely interpreted rather than compiled) when defining the method for |
Do note that |
I would be grateful if you follow that PR in case I say something out of place. I'll definitely add some "silent error" examples and how to avoid them. It is still kind of weird why the |
A better way to think of |
All of this applies applies to |
The recursive behavior should be the same between the two. The implementation detail is quite different. |
@inbounds f(x) = ... won't work, and neither will function f(x)
@inbounds
... more code here
end But this will work: f(x) = @inbounds begin
... all the code here ...
end and so will this: function f(x)
@inbounds begin
... all the code here
end
end |
@lopezm94 Just to be clear: No, |
Thank you, I think is now much clearer for me to explain julia> macroexpand(:(@fastmath function f() 1+1 end))
:(function f() # none, line 1:
Base.FastMath.add_fast(1,1)
end) julia> macroexpand(:(@inbounds function f() 1+1 end))
quote
$(Expr(:boundscheck, false))
begin
function f() # none, line 1:
1 + 1
end
$(Expr(:boundscheck, :(Base.pop)))
end
end |
Except it does. julia> macro m(f)
:($(esc(f))() = sin(1))
end
@m (macro with 1 method)
julia> macroexpand(:(@fastmath @m(f)))
:(f() = begin # REPL[1], line 2:
sin(1)
end) And it probably shouldn't really operate recursively for consistency. |
I finished the docs, if you guys wanna see |
I ran into an issue with stacking functions, each with @inline unsafe_getindex(data::AbstractMatrix, u::Integer, k::Integer, j::Integer) =
Base.unsafe_getindex(data,u + k - j + 1, j)
# banded get index, used for banded matrices with other data types
@inline function banded_getindex(data::AbstractMatrix, l::Integer, u::Integer, k::Integer, j::Integer)
@boundscheck !(-l ≤ j-k ≤ u) && return zero(eltype(data))
unsafe_getindex(data, u, k, j)
end
# scalar - integer - integer
@inline function getindex(A::AbstractBandedMatrix, k::Integer, j::Integer)
@boundscheck checkbounds(A, k, j)
banded_getindex(A,A.l,A.u,k,j)
end Copy-and-pasting the definition of |
Just realized this code is a bad idea as Base assumes function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N})
@boundscheck checkbounds(dest, indices(src)...)
for I in eachindex(linearindexing(src,dest), src)
@inbounds dest[I] = src[I]
end
dest
end It looks like it's not possible to add my own |
@dlfivefifty inlining can also happen automatically, so we needed to ensure that our bounds check removal strategy would not have surprising effects on code that the user did not write. Therefore, we treat function boundaries as special, even if they are inlined. What you need to get your example to work is |
Thanks! so I don't need to use @propogate_inbounds @inline function ...
end Unfortunately, it doesn't really help for this code as it looks like one shouldn't use Hopefully eventually it will be possible to add an |
|
#19726 enough to close this? |
I think so. |
Recently I opened pull request #17700 due to a confusing statement about
@inbounds
and@fastmath
in the documentation. However even if the documentation is correct, these macros might be better throwing an error when trying to optimize an unsupported expression. If not an error then it could have some kind of warn keyword.Edit (yyc): See here for a list of things to improve.
The text was updated successfully, but these errors were encountered: