-
-
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
at-views macro to convert a whole block of code to slices=views #20164
Conversation
# don't use view on the lhs of an assignment | ||
Expr(ex.head, esc(ex.args[1]), _views(ex.args[2])) | ||
elseif ex.head == :ref | ||
Expr(:call, :maybeview, map(_views, ex.args)...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace_ref_end!
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thanks.
@propagate_inbounds maybeview(A::AbstractArray, args::Number...) = getindex(A, args...) | ||
@propagate_inbounds maybeview(A) = getindex(A) | ||
@propagate_inbounds maybeview(A::AbstractArray) = getindex(A) | ||
# avoid splatting penalty in common cases: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was this really necessary in your testing? I'd be surprised if the @propagate_inbounds
definitions above have a splatting penalty since they get inlined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried a simple test case
f(x) = 1
f(x,y) = 2
g(x...) = f(x...)
and it wasn't getting inlined, but I guess I should try again with @propagate_inbounds
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I think I was getting deceived: @code_llvm g(3)
looks more complicated than @code_llvm f(3)
, but foo() = g(3) + g(4) - g(6,7) + g(8)
is definitely inlining g
(and simplifies to ret i64 1
).
Great, that will simply things. The dotview
function in broadcast.jl
can be similarly simplified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, @code_llvm
can be deceiving with splatted @inline
functions because it shows the LLVM function for them... but that's not at all what happens when they get inlined into another function. I almost always will define simple fixed-argument wrapper functions when I'm trying to test these guys.
…s...) = getindex(A, args...), and similarly for dotview
# maybeview is like getindex, but returns a view for slicing operations | ||
# (while remaining equivalent to getindex for scalar indices and non-array types) | ||
@propagate_inbounds maybeview(A, args...) = getindex(A, args...) | ||
@propagate_inbounds maybeview(A::AbstractArray, args...) = view(A, args...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does this need an array-of-arrays special case like dotview
has?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because for scalar indexing it already gives getindex
Okay to merge? @StefanKarpinski, any thoughts on this? |
Since it seems everyone likes this, I'll merge in a day or so if there are no further objections. |
Sorry, I was traveling but I do have one thought: why not just fold this into the existing @view begin
# in here all indexing expressions create views
end Grammatically, having |
Well, they aren't quite the same. That being said, I suspect that |
They (also) behave differently in the scalar case. |
It seems like having both |
This PR provides an
@views
macro that you can apply to a whole block of code (e.g. a whole function definition) to convert every array-slicing operation into a view. Scalar indexing is not affected.This allows you to opt-in to slices=views with minimal effort, a lot easier than adding
@view
or calls toview
everywhere. This is especially easier for updating operations like.+=
, where you can't putview
on the left-hand side (as discussed on discourse).