-
-
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
RFC: Fix #31392, unaliasing of broadcast arguments against destinations with repeated indices #31407
base: master
Are you sure you want to change the base?
RFC: Fix #31392, unaliasing of broadcast arguments against destinations with repeated indices #31407
Changes from all commits
7a3cdb1
55e10b2
347cabf
e4f54ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -969,15 +969,34 @@ end | |
end | ||
end | ||
|
||
# For broadcasted assignments like `broadcast!(f, A, ..., A, ...)`, where `A` | ||
# appears on both the LHS and the RHS of the `.=`, then we know we're only | ||
# going to make one pass through the array, and even though `A` is aliasing | ||
# against itself, the mutations won't affect the result as the indices on the | ||
# LHS and RHS will always match. This is not true in general, but with the `.op=` | ||
# syntax it's fairly common for an argument to be `===` a source. | ||
broadcast_unalias(dest, src) = dest === src ? src : unalias(dest, src) | ||
""" | ||
broadcast_unalias(dest, src) | ||
|
||
`broadcast_unalias` is a simple extension of `Base.unalias` to enable an important | ||
performance optimization specific to the semantics of broadcasting. | ||
|
||
For broadcasted assignments like `broadcast!(f, A, ..., A, ...)`, where `A` | ||
appears on both the LHS and the RHS of the `.=`, then we know we're only | ||
going to make one pass through the array, and even though `A` is aliasing | ||
against itself, the mutations won't affect the result as the indices on the | ||
LHS and RHS will always match. As long as the indices do not repeat, the | ||
RHS does not need to be unaliased. This is particuclarly valuable with the `.op=` | ||
syntax since that makes it fairly common for an argument to be `===` a source. | ||
""" | ||
broadcast_unalias(dest, src) = dest === src && !potentially_self_aliased(dest) ? src : unalias(dest, src) | ||
broadcast_unalias(::Nothing, src) = src | ||
|
||
""" | ||
potentially_self_aliased(A) | ||
|
||
Returns true if multiple locations in `A` reference the same memory | ||
""" | ||
potentially_self_aliased(::DenseArray) = false | ||
potentially_self_aliased(A::StridedArray) = any(==(0), strides(A)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can do better than this, but doing better is NP-hard. Ref: |
||
potentially_self_aliased(A::SubArray) = any(map(!allunique, A.indices)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a note for posterity: |
||
potentially_self_aliased(A::Union{Base.ReshapedArray,Base.ReinterpretArray}) = potentially_self_aliased(A.parent) | ||
potentially_self_aliased(::Any) = false | ||
|
||
# Preprocessing a `Broadcasted` does two things: | ||
# * unaliases any arguments from `dest` | ||
# * "extrudes" the arguments where it is advantageous to pre-compute the broadcasted indices | ||
|
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.
A yearTwo years later, I'm not a big fan of this name. I'm guessing I usedpotentially
as an attempt to say thattrue
s are conclusive butfalse
s are not... but I don't think it actually reads that way.mightalias
documents itself as a "conservative" test for sharing the same memory, but I don't even know what that means on its face. Is it more likely to have false positive or a false negative?In both cases, I used a different word than my usual go-to "maybe_foo" as an attempt to do some work in one direction or the other, but I don't think it was successful because I'm having a hard time piecing together what they mean right now. In short, here's what we have between these two systems:
mightalias
true
mightalias
false
dataids
and one of those aliasespotentially_self_aliased
true
potentially_self_aliased
false
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.
Numpy calls this
may_have_internal_overlap
with tri-state output (known to not overlap, known to overlap, and unknown).