perf: inline fe_mul into point operations — 10% faster verify
Move fe_mul/fe_sqr to static inline in field.h when ASM is available (FE_MUL_ASM=1). This allows the compiler to inline the entire field multiply directly into gej_double and gej_add_ge, eliminating function call boundaries. Before: gej_double had 9 function calls (to fe_mul/fe_sqr) After: gej_double has 2 function calls (fe_half only) The compiler can now: - Keep intermediate results in registers across multiply boundaries - Schedule MULX instructions across adjacent field operations - Eliminate push/pop register saves at call boundaries gej_double: 738 → 1311 instructions (larger but no call overhead) Impact: verifyFast: 35.1µs → 31.6µs (10% faster, 1.19x vs ACINQ) verify: 39.7µs → 38.4µs (0.98x vs ACINQ — essentially tied!) sign: 15.2µs → 14.2µs (1.48x vs ACINQ) batch(200): 6.2µs → 4.5µs per event (7.9x vs ACINQ) https://claude.ai/code/session_011KVZhDcV2G7idNWEBz12GY
This commit is contained in:
@@ -125,11 +125,13 @@ void reduce_wide(secp256k1_fe *r, const uint64_t w[8]) {
|
||||
* Only neg/half/isZero/cmp/toBytes need explicit normalize. */
|
||||
}
|
||||
|
||||
void fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
#if FE_MUL_ASM
|
||||
fe_mul_asm(r, a, b);
|
||||
return;
|
||||
#elif HAVE_INT128
|
||||
/* fe_mul and fe_sqr are static inline in field.h when ASM is available.
|
||||
* They get inlined directly into gej_double/gej_add_ge callers,
|
||||
* eliminating ~9 function call boundaries per doublePoint. */
|
||||
#else
|
||||
void fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
#if HAVE_INT128
|
||||
/* Inline mul + reduce to avoid function call overhead and enable
|
||||
* the compiler to keep intermediates in registers. */
|
||||
uint64_t a0=a->d[0], a1=a->d[1], a2=a->d[2], a3=a->d[3];
|
||||
@@ -209,8 +211,9 @@ void fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
void fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
fe_mul(r, a, a);
|
||||
}
|
||||
#endif /* !FE_MUL_ASM */
|
||||
|
||||
#else /* Portable fallback */
|
||||
#else /* Portable fallback (no HAVE_INT128) */
|
||||
|
||||
static inline void mul64(uint64_t *hi, uint64_t *lo, uint64_t a, uint64_t b) {
|
||||
uint64_t a_lo = a & 0xFFFFFFFF, a_hi = a >> 32;
|
||||
|
||||
Reference in New Issue
Block a user