Skip to content

Commit 06425ef

Browse files
perf(math): Add #[inline] attributes to hot field arithmetic paths (#1128)
Add inline attributes to performance-critical field arithmetic functions to improve optimization opportunities for the compiler: - element.rs: Add #[inline] to From conversions, PartialEq, Div trait implementations, Default, from_raw(), and to_raw() - mersenne31/field.rs: Add #[inline(always)] to all IsField and IsPrimeField implementations including add, sub, mul, neg, inv, div, eq, zero, one, from_u64, from_base_type, double, representative. Also add inline to helper methods weak_reduce, as_representative, mul_power_two, pow_2, two_square_minus_one. - u64_goldilocks_field.rs: Add #[inline] to inv and div for both Goldilocks64Field and Degree2GoldilocksExtensionField, plus #[inline(always)] to eq, zero, one for the extension field. These inline hints help the compiler make better inlining decisions for small, frequently-called functions in hot loops like FFT and polynomial operations.
1 parent 1aa37a2 commit 06425ef

File tree

3 files changed

+36
-0
lines changed

3 files changed

+36
-0
lines changed

crates/math/src/field/element.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ where
120120
F::BaseType: Clone,
121121
F: IsField,
122122
{
123+
#[inline]
123124
fn from(value: &F::BaseType) -> Self {
124125
Self {
125126
value: F::from_base_type(value.clone()),
@@ -132,6 +133,7 @@ impl<F> From<u64> for FieldElement<F>
132133
where
133134
F: IsField,
134135
{
136+
#[inline]
135137
fn from(value: u64) -> Self {
136138
Self {
137139
value: F::from_u64(value),
@@ -159,6 +161,7 @@ where
159161
F::BaseType: Clone,
160162
F: IsField,
161163
{
164+
#[inline(always)]
162165
pub fn from_raw(value: F::BaseType) -> Self {
163166
Self { value }
164167
}
@@ -173,6 +176,7 @@ impl<F> PartialEq<FieldElement<F>> for FieldElement<F>
173176
where
174177
F: IsField,
175178
{
179+
#[inline]
176180
fn eq(&self, other: &FieldElement<F>) -> bool {
177181
F::eq(&self.value, &other.value)
178182
}
@@ -399,6 +403,7 @@ where
399403
{
400404
type Output = Result<FieldElement<L>, FieldError>;
401405

406+
#[inline]
402407
fn div(self, rhs: &FieldElement<L>) -> Self::Output {
403408
let value = <F as IsSubFieldOf<L>>::div(&self.value, &rhs.value)?;
404409
Ok(FieldElement::<L> { value })
@@ -412,6 +417,7 @@ where
412417
{
413418
type Output = Result<FieldElement<L>, FieldError>;
414419

420+
#[inline]
415421
fn div(self, rhs: FieldElement<L>) -> Self::Output {
416422
&self / &rhs
417423
}
@@ -424,6 +430,7 @@ where
424430
{
425431
type Output = Result<FieldElement<L>, FieldError>;
426432

433+
#[inline]
427434
fn div(self, rhs: &FieldElement<L>) -> Self::Output {
428435
&self / rhs
429436
}
@@ -436,6 +443,7 @@ where
436443
{
437444
type Output = Result<FieldElement<L>, FieldError>;
438445

446+
#[inline]
439447
fn div(self, rhs: FieldElement<L>) -> Self::Output {
440448
self / &rhs
441449
}
@@ -472,6 +480,7 @@ impl<F> Default for FieldElement<F>
472480
where
473481
F: IsField,
474482
{
483+
#[inline]
475484
fn default() -> Self {
476485
Self { value: F::zero() }
477486
}
@@ -545,6 +554,7 @@ where
545554
}
546555

547556
/// Returns the raw base type
557+
#[inline(always)]
548558
pub fn to_raw(self) -> F::BaseType {
549559
self.value
550560
}

crates/math/src/field/fields/mersenne31/field.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use core::fmt::{self, Display};
1616
pub struct Mersenne31Field;
1717

1818
impl Mersenne31Field {
19+
#[inline(always)]
1920
fn weak_reduce(n: u32) -> u32 {
2021
// To reduce 'n' to 31 bits we clear its MSB, then add it back in its reduced form.
2122
let msb = n & (1 << 31);
@@ -27,6 +28,7 @@ impl Mersenne31Field {
2728
res + msb_reduced
2829
}
2930

31+
#[inline(always)]
3032
fn as_representative(n: &u32) -> u32 {
3133
if *n == MERSENNE_31_PRIME_FIELD_ORDER {
3234
0
@@ -44,12 +46,14 @@ impl Mersenne31Field {
4446
}
4547

4648
/// Computes a * 2^k, with 0 < k < 31
49+
#[inline(always)]
4750
pub fn mul_power_two(a: u32, k: u32) -> u32 {
4851
let msb = (a & (u32::MAX << (31 - k))) >> (31 - k); // The k + 1 msf shifted right .
4952
let lsb = (a & (u32::MAX >> (k + 1))) << k; // The 31 - k lsb shifted left.
5053
Self::weak_reduce(msb + lsb)
5154
}
5255

56+
#[inline]
5357
pub fn pow_2(a: &u32, order: u32) -> u32 {
5458
let mut res = *a;
5559
(0..order).for_each(|_| res = Self::square(&res));
@@ -58,6 +62,7 @@ impl Mersenne31Field {
5862

5963
/// TODO: See if we can optimize this function.
6064
/// Computes 2a^2 - 1
65+
#[inline(always)]
6166
pub fn two_square_minus_one(a: &u32) -> u32 {
6267
if *a == 0 {
6368
MERSENNE_31_PRIME_FIELD_ORDER - 1
@@ -76,6 +81,7 @@ impl IsField for Mersenne31Field {
7681
type BaseType = u32;
7782

7883
/// Returns the sum of `a` and `b`.
84+
#[inline(always)]
7985
fn add(a: &u32, b: &u32) -> u32 {
8086
// We are using that if a and b are field elements of Mersenne31, then
8187
// a + b has at most 32 bits, so we can use the weak_reduce function to take mudulus p.
@@ -84,21 +90,25 @@ impl IsField for Mersenne31Field {
8490

8591
/// Returns the multiplication of `a` and `b`.
8692
// Note: for powers of 2 we can perform bit shifting this would involve overriding the trait implementation
93+
#[inline(always)]
8794
fn mul(a: &u32, b: &u32) -> u32 {
8895
Self::from_u64(u64::from(*a) * u64::from(*b))
8996
}
9097

98+
#[inline(always)]
9199
fn sub(a: &u32, b: &u32) -> u32 {
92100
Self::weak_reduce(a + MERSENNE_31_PRIME_FIELD_ORDER - b)
93101
}
94102

95103
/// Returns the additive inverse of `a`.
104+
#[inline(always)]
96105
fn neg(a: &u32) -> u32 {
97106
// NOTE: MODULUS known to have 31 bit clear
98107
MERSENNE_31_PRIME_FIELD_ORDER - a
99108
}
100109

101110
/// Returns the multiplicative inverse of `a`.
111+
#[inline]
102112
fn inv(x: &u32) -> Result<u32, FieldError> {
103113
if *x == Self::zero() || *x == MERSENNE_31_PRIME_FIELD_ORDER {
104114
return Err(FieldError::InvZeroError);
@@ -117,36 +127,44 @@ impl IsField for Mersenne31Field {
117127
}
118128

119129
/// Returns the division of `a` and `b`.
130+
#[inline]
120131
fn div(a: &u32, b: &u32) -> Result<u32, FieldError> {
121132
let b_inv = Self::inv(b).map_err(|_| FieldError::DivisionByZero)?;
122133
Ok(Self::mul(a, &b_inv))
123134
}
124135

125136
/// Returns a boolean indicating whether `a` and `b` are equal or not.
137+
#[inline(always)]
126138
fn eq(a: &u32, b: &u32) -> bool {
127139
Self::as_representative(a) == Self::representative(b)
128140
}
129141

130142
/// Returns the additive neutral element.
143+
#[inline(always)]
131144
fn zero() -> u32 {
132145
0u32
133146
}
134147

135148
/// Returns the multiplicative neutral element.
149+
#[inline(always)]
136150
fn one() -> u32 {
137151
1u32
138152
}
139153

140154
/// Returns the element `x * 1` where 1 is the multiplicative neutral element.
155+
#[inline(always)]
141156
fn from_u64(x: u64) -> u32 {
142157
(((((x >> 31) + x + 1) >> 31) + x) & (MERSENNE_31_PRIME_FIELD_ORDER as u64)) as u32
143158
}
144159

145160
/// Takes as input an element of BaseType and returns the internal representation
146161
/// of that element in the field.
162+
#[inline(always)]
147163
fn from_base_type(x: u32) -> u32 {
148164
Self::weak_reduce(x)
149165
}
166+
167+
#[inline(always)]
150168
fn double(a: &u32) -> u32 {
151169
Self::weak_reduce(a << 1)
152170
}
@@ -157,6 +175,7 @@ impl IsPrimeField for Mersenne31Field {
157175

158176
// Since our invariant guarantees that `value` fits in 31 bits, there is only one possible value
159177
// `value` that is not canonical, namely 2^31 - 1 = p = 0.
178+
#[inline(always)]
160179
fn representative(x: &u32) -> u32 {
161180
debug_assert!((x >> 31) == 0);
162181
Self::as_representative(x)

crates/math/src/field/fields/u64_goldilocks_field.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ impl IsField for Goldilocks64Field {
168168
}
169169

170170
/// Returns the multiplicative inverse of `a` using optimized addition chain.
171+
#[inline]
171172
fn inv(a: &u64) -> Result<u64, FieldError> {
172173
let canonical = canonicalize(*a);
173174
if canonical == 0 {
@@ -177,6 +178,7 @@ impl IsField for Goldilocks64Field {
177178
}
178179

179180
/// Returns the division of `a` and `b`.
181+
#[inline]
180182
fn div(a: &u64, b: &u64) -> Result<u64, FieldError> {
181183
let b_inv = <Self as IsField>::inv(b)?;
182184
Ok(<Self as IsField>::mul(a, &b_inv))
@@ -752,6 +754,7 @@ impl IsField for Degree2GoldilocksExtensionField {
752754

753755
/// Returns the multiplicative inverse of `a`:
754756
/// (a0 + a1*w)^-1 = (a0 - a1*w) / (a0^2 - 7*a1^2)
757+
#[inline]
755758
fn inv(a: &Self::BaseType) -> Result<Self::BaseType, FieldError> {
756759
let a0_sq = a[0].square();
757760
let a1_sq = a[1].square();
@@ -761,19 +764,23 @@ impl IsField for Degree2GoldilocksExtensionField {
761764
Ok([a[0] * norm_inv, -a[1] * norm_inv])
762765
}
763766

767+
#[inline]
764768
fn div(a: &Self::BaseType, b: &Self::BaseType) -> Result<Self::BaseType, FieldError> {
765769
let b_inv = Self::inv(b)?;
766770
Ok(<Self as IsField>::mul(a, &b_inv))
767771
}
768772

773+
#[inline(always)]
769774
fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool {
770775
a[0] == b[0] && a[1] == b[1]
771776
}
772777

778+
#[inline(always)]
773779
fn zero() -> Self::BaseType {
774780
[FpE::zero(), FpE::zero()]
775781
}
776782

783+
#[inline(always)]
777784
fn one() -> Self::BaseType {
778785
[FpE::one(), FpE::zero()]
779786
}

0 commit comments

Comments
 (0)