Skip to content

Compare inline Repr as a DoubleWord in PartialEq#71

Open
DRMacIver wants to merge 3 commits into
cmpute:masterfrom
DRMacIver:opt/p9-eq-doubleword
Open

Compare inline Repr as a DoubleWord in PartialEq#71
DRMacIver wants to merge 3 commits into
cmpute:masterfrom
DRMacIver:opt/p9-eq-doubleword

Conversation

@DRMacIver

@DRMacIver DRMacIver commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Optimisations for comparison, specifically designed to speed up small value comparisons by giving them a fast path. Gives ~30% speedup for eq on integers that are <= 2 words, at a cost of about 1% slowdown for larger integers (should be negligible for genuinely large integers, it's just at the crossover point where comparison is still fast enough that a little bit of extra work is noticeable).

Benchmarks (layout-sampled, K=11)

Wall-clock, dashu-only, vs the merge base, measured under 11 randomised function layouts (ld64 -order_file) and reported as the median — to average out the ±10% code-placement noise that otherwise swamps these small-value micro-benchmarks. The untouched ubig_mul control reads 0.0% ± 0.0%, confirming a clean run.

Benchmark Δ
ubig_eq inline (zero/one/two-word) −29% to −34%
ubig_eq heap (mid/large) +1.3% to +1.6% (tiny; new heap path does slightly more)
ubig_mul (control) 0.0%

DRMacIver and others added 2 commits June 1, 2026 11:58
Repr::eq went through as_sign_slice() == as_sign_slice(), materialising
two slice references even for inline (<= DoubleWord) values. Compare
directly off the capacity + union instead: a sign or scale (inline vs
heap) mismatch is immediately unequal, inline values compare as a single
DoubleWord, and same-length heap values compare their word slices.

This makes the inline encoding's canonicality load-bearing, so also route
Repr::ones through from_buffer: a 128-bit ones value is built as a
length-2 buffer and must be promoted to the inline DoubleWord form rather
than left heap-encoded, otherwise it would no longer compare equal to its
inline counterpart. test_ones (ones(128) == u128::MAX) covers this.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Exercises Repr::eq's inline-DoubleWord path, the sign/scale short-circuits,
and the cross-representation canonical equality (ones vs the inline form),
rather than relying on incidental coverage from existing eq tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@DRMacIver DRMacIver marked this pull request as ready for review June 2, 2026 08:19
Comment thread integer/src/repr.rs
// SAFETY: the bit length has been checked and capacity >= length,
// so capacity is nonzero and larger than 2
unsafe { mem::transmute::<Buffer, Repr>(buffer) }
// Route through `from_buffer` to canonicalise: a 128-bit ones value

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that we can just change the conditions for the branchs above to n <= WORD_BITS_USIZE and n <= DWORD_BITS_USIZE.

Comment thread integer/src/repr.rs
// The encoding is canonical, so a sign or scale (inline vs heap)
// mismatch is immediately unequal; otherwise compare the words directly
// instead of materialising slices via `as_sign_slice`.
let cap_a = self.capacity.get();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I suggest using let (cap_a, sign_) = self.sign_capacity();, then there is no need for let abs_a = cap_a.unsigned_abs();` below.

Comment thread integer/src/repr.rs
}
// SAFETY: capacity tells us which union variant is live.
unsafe {
if inline_a {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be even more optimized:

match cap_a {
  0..1 => {}, // compare as single words
  2 => {}, // compare as double words
  _ => {}, // compare as slices
}

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

Successfully merging this pull request may close these issues.

2 participants