Skip to content

libm: Improved integer utilities, implement shifts and bug fixes for i256 and u256 #961

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

Merged
merged 3 commits into from
Jul 1, 2025

Conversation

quaternic
Copy link
Contributor

@quaternic quaternic commented Jun 29, 2025

i256 and u256

  • operators now use the same overflow convention as primitives
  • implement << and - (previously just >> and +)
  • implement Ord correctly (the previous PartialOrd was broken)
  • corrected i256::SIGNED to true

The above mentioned operators are now included in the MinInt-trait.
(Never mind, that would need additional changes in compiler-builtins, so I removed it for now.)

The Int-trait is extended with trailing_zeros, carrying_add, and borrowing_sub.

@quaternic quaternic force-pushed the i256-fixes branch 2 times, most recently from 25c375f to c1c50ee Compare June 29, 2025 11:57
@tgross35
Copy link
Contributor

The implementations all look pretty great to me. Would it be possible to extend the fuzz tests in libm-test/tests/u256.rs to cover these?

There are also some benchmarks, it would be good to basically copy the add and shr benchmarks for sub and shl.

fn setup_u128_mul() -> Vec<(u128, u128)> {
let step = u128::MAX / 300;
let mut x = 0u128;
let mut y = 0u128;
let mut v = Vec::new();
loop {
'inner: loop {
match y.checked_add(step) {
Some(new) => y = new,
None => break 'inner,
}
v.push((x, y))
}
match x.checked_add(step) {
Some(new) => x = new,
None => break,
}
}
v
}
fn setup_u256_add() -> Vec<(u256, u256)> {
let mut v = Vec::new();
for (x, y) in setup_u128_mul() {
// square the u128 inputs to cover most of the u256 range
v.push((x.widen_mul(x), y.widen_mul(y)));
}
// Doesn't get covered by `u128:MAX^2`
v.push((u256::MAX, u256::MAX));
v
}
fn setup_u256_shift() -> Vec<(u256, u32)> {
let mut v = Vec::new();
for (x, _) in setup_u128_mul() {
let x2 = x.widen_mul(x);
for y in 0u32..256 {
v.push((x2, y));
}
}
v
}
#[library_benchmark]
#[bench::linspace(setup_u128_mul())]
fn icount_bench_u128_widen_mul(cases: Vec<(u128, u128)>) {
for (x, y) in cases.iter().copied() {
black_box(black_box(x).zero_widen_mul(black_box(y)));
}
}
#[library_benchmark]
#[bench::linspace(setup_u256_add())]
fn icount_bench_u256_add(cases: Vec<(u256, u256)>) {
for (x, y) in cases.iter().copied() {
black_box(black_box(x) + black_box(y));
}
}
#[library_benchmark]
#[bench::linspace(setup_u256_shift())]
fn icount_bench_u256_shr(cases: Vec<(u256, u32)>) {
for (x, y) in cases.iter().copied() {
black_box(black_box(x) >> black_box(y));
}

@quaternic
Copy link
Contributor Author

I've now added both of those.

Copy link
Contributor

@tgross35 tgross35 left a comment

Choose a reason for hiding this comment

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

Awesome, thanks for the improvements!

@tgross35 tgross35 enabled auto-merge (squash) July 1, 2025 07:28
@tgross35 tgross35 merged commit 95abb0e into rust-lang:master Jul 1, 2025
35 checks passed
@quaternic quaternic deleted the i256-fixes branch July 1, 2025 09:04
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