-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Eliminate most invalidations from loading FixedPointNumbers #35733
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
Changes from all commits
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 |
---|---|---|
|
@@ -166,13 +166,16 @@ true | |
""" | ||
function convert end | ||
|
||
convert(::Type{Union{}}, x::Union{}) = throw(MethodError(convert, (Union{}, x))) | ||
convert(::Type{Union{}}, x) = throw(MethodError(convert, (Union{}, x))) | ||
convert(::Type{Any}, x) = x | ||
convert(::Type{T}, x::T) where {T} = x | ||
convert(::Type{Type}, x::Type) = x # the ssair optimizer is strongly dependent on this method existing to avoid over-specialization | ||
# in the absence of inlining-enabled | ||
# (due to fields typed as `Type`, which is generally a bad idea) | ||
|
||
Union{}(x::Union{}) = throw(MethodError(convert, (Union{}, x))) | ||
|
||
""" | ||
@eval [mod,] ex | ||
|
||
|
@@ -447,6 +450,9 @@ Stacktrace: | |
``` | ||
""" | ||
sizeof(x) = Core.sizeof(x) | ||
# The next two methods prevent invalidation | ||
sizeof(::Type{Union{}}) = Core.sizeof(Union{}) | ||
sizeof(::Type{T}) where T = Core.sizeof(T) | ||
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. This'll force us to generate code for each type, and forces us to add a dispatch, which I believe we don't want for it? |
||
|
||
# simple Array{Any} operations needed for bootstrap | ||
@eval setindex!(A::Array{Any}, @nospecialize(x), i::Int) = arrayset($(Expr(:boundscheck)), A, x, i) | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -2,6 +2,10 @@ | |||||
|
||||||
## generic operations on numbers ## | ||||||
|
||||||
# prevent invalidation | ||||||
Union{}(x::Number) = throw(MethodError(convert, (Union{}, x))) | ||||||
convert(::Type{Union{}}, x::Number) = throw(MethodError(convert, (Union{}, x))) | ||||||
|
||||||
# Numbers are convertible | ||||||
convert(::Type{T}, x::T) where {T<:Number} = x | ||||||
convert(::Type{T}, x::Number) where {T<:Number} = T(x) | ||||||
|
@@ -240,6 +244,9 @@ julia> zero(rand(2,2)) | |||||
""" | ||||||
zero(x::Number) = oftype(x,0) | ||||||
zero(::Type{T}) where {T<:Number} = convert(T,0) | ||||||
# prevent invalidation | ||||||
zero(x::Union{}) = throw(MethodError(zero, (x,))) | ||||||
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.
Suggested change
Though I can't promise that defining these might not cause other, unintended, side-effects. 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. 💯 Agreed, I would hold off on adding these --- they could cause problems, and they're the kind of thing we should be able to handle automatically (i.e. if an argument is bottom, obviously the code is unreachable). |
||||||
zero(::Type{Union{}}) = throw(MethodError(zero, (Union{},))) | ||||||
|
||||||
""" | ||||||
one(x) | ||||||
|
@@ -275,6 +282,9 @@ julia> import Dates; one(Dates.Day(1)) | |||||
""" | ||||||
one(::Type{T}) where {T<:Number} = convert(T,1) | ||||||
one(x::T) where {T<:Number} = one(T) | ||||||
# prevent invalidation | ||||||
one(x::Union{}) = throw(MethodError(one, (x,))) | ||||||
one(::Type{Union{}}) = throw(MethodError(one, (Union{},))) | ||||||
# note that convert(T, 1) should throw an error if T is dimensionful, | ||||||
# so this fallback definition should be okay. | ||||||
|
||||||
|
@@ -298,6 +308,9 @@ julia> import Dates; oneunit(Dates.Day) | |||||
""" | ||||||
oneunit(x::T) where {T} = T(one(x)) | ||||||
oneunit(::Type{T}) where {T} = T(one(T)) | ||||||
# prevent invalidation | ||||||
oneunit(x::Union{}) = throw(MethodError(oneunit, (x,))) | ||||||
oneunit(::Type{Union{}}) = throw(MethodError(oneunit, (Union{},))) | ||||||
|
||||||
""" | ||||||
big(T::Type) | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -306,25 +306,29 @@ with reduction `op` over an empty array with element type of `T`. | |||||
|
||||||
If not defined, this will throw an `ArgumentError`. | ||||||
""" | ||||||
reduce_empty(op, T) = _empty_reduce_error() | ||||||
reduce_empty(::typeof(+), T) = zero(T) | ||||||
reduce_empty(op, ::Type{T}) where T = _empty_reduce_error() | ||||||
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. Style nit: I think we usually write short form functions with the braces
Suggested change
|
||||||
reduce_empty(::typeof(+), ::Type{Union{}}) = _empty_reduce_error() # avoid invalidation | ||||||
Member
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. I think we should have this. It is not for avoiding invalidation but for "correctness." I think it's better to do |
||||||
reduce_empty(::typeof(+), ::Type{T}) where T = zero(T) | ||||||
reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int) | ||||||
reduce_empty(::typeof(*), T) = one(T) | ||||||
reduce_empty(::typeof(*), ::Type{Union{}}) = _empty_reduce_error() | ||||||
reduce_empty(::typeof(*), ::Type{T}) where T = one(T) | ||||||
reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = "" | ||||||
reduce_empty(::typeof(&), ::Type{Bool}) = true | ||||||
reduce_empty(::typeof(|), ::Type{Bool}) = false | ||||||
|
||||||
reduce_empty(::typeof(add_sum), T) = reduce_empty(+, T) | ||||||
reduce_empty(::typeof(add_sum), ::Type{Union{}}) = _empty_reduce_error() | ||||||
reduce_empty(::typeof(add_sum), ::Type{T}) where T = reduce_empty(+, T) | ||||||
reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:SmallSigned} = zero(Int) | ||||||
reduce_empty(::typeof(add_sum), ::Type{T}) where {T<:SmallUnsigned} = zero(UInt) | ||||||
reduce_empty(::typeof(mul_prod), T) = reduce_empty(*, T) | ||||||
reduce_empty(::typeof(mul_prod), ::Type{Union{}}) = _empty_reduce_error() | ||||||
reduce_empty(::typeof(mul_prod), ::Type{T}) where T = reduce_empty(*, T) | ||||||
reduce_empty(::typeof(mul_prod), ::Type{T}) where {T<:SmallSigned} = one(Int) | ||||||
reduce_empty(::typeof(mul_prod), ::Type{T}) where {T<:SmallUnsigned} = one(UInt) | ||||||
|
||||||
reduce_empty(op::BottomRF, T) = reduce_empty(op.rf, T) | ||||||
reduce_empty(op::MappingRF, T) = mapreduce_empty(op.f, op.rf, T) | ||||||
reduce_empty(op::FilteringRF, T) = reduce_empty(op.rf, T) | ||||||
reduce_empty(op::FlipArgs, T) = reduce_empty(op.f, T) | ||||||
reduce_empty(op::BottomRF, ::Type{T}) where T = reduce_empty(op.rf, T) | ||||||
reduce_empty(op::MappingRF, ::Type{T}) where T = mapreduce_empty(op.f, op.rf, T) | ||||||
reduce_empty(op::FilteringRF, ::Type{T}) where T = reduce_empty(op.rf, T) | ||||||
reduce_empty(op::FlipArgs, ::Type{T}) where T = reduce_empty(op.f, T) | ||||||
|
||||||
""" | ||||||
Base.mapreduce_empty(f, op, T) | ||||||
|
@@ -336,12 +340,12 @@ of `T`. | |||||
If not defined, this will throw an `ArgumentError`. | ||||||
""" | ||||||
mapreduce_empty(f, op, T) = _empty_reduce_error() | ||||||
mapreduce_empty(::typeof(identity), op, T) = reduce_empty(op, T) | ||||||
mapreduce_empty(::typeof(abs), op, T) = abs(reduce_empty(op, T)) | ||||||
mapreduce_empty(::typeof(abs2), op, T) = abs2(reduce_empty(op, T)) | ||||||
mapreduce_empty(::typeof(identity), op, ::Type{T}) where T = reduce_empty(op, T) | ||||||
mapreduce_empty(::typeof(abs), op, ::Type{T}) where T = abs(reduce_empty(op, T)) | ||||||
mapreduce_empty(::typeof(abs2), op, ::Type{T}) where T = abs2(reduce_empty(op, T)) | ||||||
|
||||||
mapreduce_empty(f::typeof(abs), ::typeof(max), T) = abs(zero(T)) | ||||||
mapreduce_empty(f::typeof(abs2), ::typeof(max), T) = abs2(zero(T)) | ||||||
mapreduce_empty(::typeof(abs), ::typeof(max), ::Type{T}) where T = abs(zero(T)) | ||||||
mapreduce_empty(::typeof(abs2), ::typeof(max), ::Type{T}) where T = abs2(zero(T)) | ||||||
|
||||||
# For backward compatibility: | ||||||
mapreduce_empty_iter(f, op, itr, ItrEltype) = | ||||||
|
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.
This is my favorite method.
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.
Yes, this PR has been an exercise in "how on earth can inference discover an ambiguity here?"