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

Propagate @inbounds over boundaries from lambdas, generators and broadcasts #40099

Closed
Uroc327 opened this issue Mar 18, 2021 · 1 comment
Closed

Comments

@Uroc327
Copy link

Uroc327 commented Mar 18, 2021

AFAICT, the @inbounds macro is not propagated into lambdas, generators and broadcasts.

using Base: @propagate_bounds
using LinearAlgebra

@propagate_inbounds f(a, i, x) = a[i+1] - x

function foo(a)
	ret = zero(eltype(a))
	@inbounds for i in axes(a, 1)
		ret += f(a, i, 0)
	end
	ret
end

function fooG(a)
	@inbounds sum(f(a, i, 0) for i in axes(a, 1))
end

function fooλ(a)
	@inbounds sum(i -> f(a, i, 0), a)
end

function fooB(a)
	la = length(a)
	@inbounds dot([1,2,3], f.(Ref(a), la, [1,2,3]))
end
julia> a = 1:5
1:5

julia> foo(a)
20

julia> fooG(a)
ERROR: BoundsError: attempt to access 5-element UnitRange{Int64} at index [6]
Stacktrace:
 [1] getindex at ./range.jl:646 [inlined]
 [2] f at ./REPL[28]:1 [inlined]
 [3] #9 at ./none:0 [inlined]
 [4] MappingRF at ./reduce.jl:93 [inlined]
 [5] _foldl_impl at ./reduce.jl:62 [inlined]
 [6] foldl_impl at ./reduce.jl:48 [inlined]
 [7] mapfoldl_impl at ./reduce.jl:44 [inlined]
 [8] #mapfoldl#204 at ./reduce.jl:160 [inlined]
 [9] mapfoldl at ./reduce.jl:160 [inlined]
 [10] #mapreduce#208 at ./reduce.jl:287 [inlined]
 [11] mapreduce at ./reduce.jl:287 [inlined]
 [12] sum at ./reduce.jl:494 [inlined]
 [13] sum at ./reduce.jl:511 [inlined]
 [14] fooG(::UnitRange{Int64}) at ./REPL[16]:2
 [15] top-level scope at REPL[35]:1
 [16] run_repl(::REPL.AbstractREPL, ::Any) at /tmp/portage/dev-lang/julia-1.5.3/work/julia-1.5.3/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288

julia> fooλ(a)
ERROR: BoundsError: attempt to access 5-element UnitRange{Int64} at index [6]
Stacktrace:
 [1] getindex at ./range.jl:646 [inlined]
 [2] f at ./REPL[28]:1 [inlined]
 [3] #11 at ./REPL[17]:2 [inlined]
 [4] _mapreduce(::var"#11#12"{UnitRange{Int64}}, ::typeof(Base.add_sum), ::IndexLinear, ::UnitRange{Int64}) at ./reduce.jl:411
 [5] _mapreduce_dim at ./reducedim.jl:318 [inlined]
 [6] #mapreduce#620 at ./reducedim.jl:310 [inlined]
 [7] mapreduce at ./reducedim.jl:310 [inlined]
 [8] _sum at ./reducedim.jl:727 [inlined]
 [9] #sum#628 at ./reducedim.jl:723 [inlined]
 [10] sum at ./reducedim.jl:723 [inlined]
 [11] fooλ(::UnitRange{Int64}) at ./REPL[17]:2
 [12] top-level scope at REPL[36]:1
 [13] run_repl(::REPL.AbstractREPL, ::Any) at /tmp/portage/dev-lang/julia-1.5.3/work/julia-1.5.3/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288

julia> fooB(a)
ERROR: BoundsError: attempt to access 5-element UnitRange{Int64} at index [6]
Stacktrace:
 [1] getindex at ./range.jl:646 [inlined]
 [2] f at ./REPL[28]:1 [inlined]
 [3] _broadcast_getindex_evalf at ./broadcast.jl:648 [inlined]
 [4] _broadcast_getindex at ./broadcast.jl:621 [inlined]
 [5] getindex at ./broadcast.jl:575 [inlined]
 [6] macro expansion at ./broadcast.jl:932 [inlined]
 [7] macro expansion at ./simdloop.jl:77 [inlined]
 [8] copyto! at ./broadcast.jl:931 [inlined]
 [9] copyto! at ./broadcast.jl:886 [inlined]
 [10] copy at ./broadcast.jl:862 [inlined]
 [11] materialize at ./broadcast.jl:837 [inlined]
 [12] fooB(::UnitRange{Int64}) at ./REPL[18]:3
 [13] top-level scope at REPL[37]:1
 [14] run_repl(::REPL.AbstractREPL, ::Any) at /tmp/portage/dev-lang/julia-1.5.3/work/julia-1.5.3/usr/share/julia/stdlib/v1.5/REPL/src/REPL.jl:288

Although this can be circumvented for Generators and Lambdas by moving the @inbounds macro into the Generator/Lambda, this is rather unpractical in functions which are @propagate_inbounds themselves. The developer does not know, if he needs to add a @inbounds macro statically.

The only workaround I know for the broadcasting part is to add an explicit @inbounds inside the broadcasted function. This is hard if the function shouldn't/can't change and the same problem in propagated contexts applies.

How can I propagate disabled bounds checks into generators, lambdas and broadcasts. And how can I do this, when the foo functions are not explicitely marked @inbounds, but are @propagate_inbounds marked themselves?

@mbauman
Copy link
Sponsor Member

mbauman commented Mar 18, 2021

Discussion on discourse here, somewhat related to #18773. I'm afraid this isn't something we want in general.

@brenhinkeller brenhinkeller closed this as not planned Won't fix, can't repro, duplicate, stale Nov 19, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants