Skip to content

Commit 29aa4d1

Browse files
author
Patrick Häcker
committed
Don't define functionally equivalent methods to Base
This avoids invalidations.
1 parent 87390f8 commit 29aa4d1

2 files changed

Lines changed: 5 additions & 3 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
],
6262
"cSpell.words": [
6363
"arities",
64+
"backedge",
6465
"Bestie",
6566
"branchlessly",
6667
"Gaure",

src/methods.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ for RM in (RoundingMode{:Up}, RoundingMode{:Down}, RoundingMode{:ToZero}, Roundi
5757
end
5858

5959
Base.:-(x::T) where T<:EmulatedInteger = -x[] % T
60-
# `abs` on an unsigned is the identity; `% T` would add a useless `& maxvalue` the compiler can't elide. Signed `abs` lowers to the storage intrinsic + modular re-clean.
61-
Base.abs(x::EmulatedUnsigned) = x
60+
# Signed `abs` lowers to the storage intrinsic + modular re-clean. Unsigned needs no method: `EmulatedUnsigned <: Unsigned`, so `Base.abs(::Unsigned)` (the identity) already applies; adding one would only supersede it and widen invalidations.
6261
Base.abs(x::T) where T<:EmulatedSigned = abs(x[]) % T
6362

6463
# Storage-level `-x[]` already produces the bit pattern of the flipped sign value (no overflow for non-`typemin` inputs and the same wraparound as 2's complement for `typemin`); the `% T` cast re-cleans the wasted bits.
@@ -120,6 +119,7 @@ end
120119
# `minvalue`/`maxvalue` return literals of the storage type, so `reinterpret` suffices.
121120
Base.typemin(::Type{T}) where T<:EmulatedInteger = reinterpret(T, minvalue(T))
122121
Base.typemax(::Type{T}) where T<:EmulatedInteger = reinterpret(T, maxvalue(T))
122+
# Anchor the multiplicative identity on `oneunit` rather than `one`. Both break the `one`/`oneunit` mutual recursion, but `oneunit` has far fewer precompiled callers in Base's numeric code, so it invalidates a much smaller backedge set.
123123
Base.oneunit(::Type{T}) where T<:EmulatedInteger = reinterpret(T, T |> storagetypeof |> one)
124124

125125
# Storage has `wastedbits(T)` extra zero (unsigned) or sign-extension (signed) bits at the top; subtract them to get the logical leading-zero count.
@@ -159,7 +159,8 @@ for B in Union{Base.BitInteger, Base.IEEEFloat} |> Base.uniontypes .|> Symbol
159159
@eval Base.$B(x::EmulatedInteger) = x[] |> $B
160160
end
161161

162-
for f in (:<, :<=, :>, :>=)
162+
# Only `<` and `<=` are defined; Base derives `>`/`>=` from them (`>(x, y) = y < x`). Defining `>`/`>=` here would supersede their universal `Any` fallbacks and invalidate a large amount of precompiled Base code for no behavioral gain.
163+
for f in (:<, :<=)
163164
@eval Base.$f(x::EmulatedInteger, y::EmulatedInteger) = $f(x[], y[])
164165
end
165166

0 commit comments

Comments
 (0)