1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
use cairo_lang_sierra::extensions::utils::Range;
use num_bigint::{BigInt, BigUint, Sign};
use num_traits::One;
pub trait RangeExt {
/// Width in bits when the offset is zero (aka. the natural representation).
fn zero_based_bit_width(&self) -> u32;
/// Width in bits when the offset is not necessarily zero (aka. the compact representation).
fn offset_bit_width(&self) -> u32;
}
impl RangeExt for Range {
fn zero_based_bit_width(&self) -> u32 {
// Formula for unsigned integers:
// x.bits()
//
// Formula for signed values:
// - Positive: (x.magnitude() + BigUint::one()).bits()
// - Negative: (x.magnitude() - BigUint::one()).bits() + 1
// - Zero: 0
let width = if self.lower.sign() == Sign::Minus {
let lower_width = (self.lower.magnitude() - BigUint::one()).bits() + 1;
let upper_width = {
let upper = &self.upper - &BigInt::one();
match upper.sign() {
Sign::Minus => (upper.magnitude() - BigUint::one()).bits() + 1,
Sign::NoSign => 0,
Sign::Plus => (upper.magnitude() + BigUint::one()).bits(),
}
};
lower_width.max(upper_width) as u32
} else {
(&self.upper - &BigInt::one()).bits() as u32
};
// FIXME: Workaround for segfault in canonicalization (including LLVM 19).
width.max(1)
}
fn offset_bit_width(&self) -> u32 {
// FIXME: Workaround for segfault in canonicalization (including LLVM 19).
((self.size() - BigInt::one()).bits() as u32).max(1)
}
}