Skip to content

Commit e40fd27

Browse files
Merge #1156: Followups to int128_struct arithmetic
99bd335 Make int128 overflow test use secp256k1_[ui]128_mul (Pieter Wuille) 3afce0a Avoid signed overflow in MSVC AMR64 secp256k1_mul128 (Pieter Wuille) 9b5f589 Heuristically decide whether to use int128_struct (Pieter Wuille) 63ff064 int128: Add test override for testing __(u)mulh on MSVC X64 (Tim Ruffing) f2b7e88 Add int128 randomized tests (Pieter Wuille) Pull request description: This is a follow-up to #1000: * Add randomized unit tests for int128 logic. * Add CI for the `_(u)mulh` code path (on non-ARM64 MSVC). * Add heuristic logic to enable int128_struct based arithmetic on 64-bit MSVC, or systems with pointers wider than 32 bits. * Fix signed overflow in ARM64 MSVC code. ACKs for top commit: roconnor-blockstream: utACK 99bd335 real-or-random: ACK 99bd335 tested this also on MSVC locally with the override, including all the benchmark binaries jonasnick: utACK 99bd335 Tree-SHA512: 5ea897362293b45a86650593e1fdc8c4004a1d9452eed2fa070d22dffc7ed7ca1ec50a4df61e3a33dbe35e08132ad9686286ac44af6742b32b82f11c9d3341c6
2 parents 6138d73 + 99bd335 commit e40fd27

6 files changed

+391
-85
lines changed

.cirrus.yml

+4
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ task:
288288
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
289289
env:
290290
WIDEMUL: int128_struct
291+
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)"
292+
env:
293+
WIDEMUL: int128_struct
294+
CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE
291295
- name: "i686 (MSVC): Windows (Debian stable, Wine)"
292296
env:
293297
HOST: i686-w64-mingw32

src/int128.h

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
# error "Please select int128 implementation"
1313
# endif
1414

15+
/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */
16+
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo);
17+
1518
/* Multiply two unsigned 64-bit values a and b and write the result to r. */
1619
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
1720

@@ -44,6 +47,9 @@ static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint6
4447
*/
4548
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n);
4649

50+
/* Construct an signed 128-bit value from a high and a low 64-bit value. */
51+
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo);
52+
4753
/* Multiply two signed 64-bit values a and b and write the result to r. */
4854
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b);
4955

src/int128_native_impl.h

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
#include "int128.h"
55

6+
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
7+
*r = (((uint128_t)hi) << 64) + lo;
8+
}
9+
610
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
711
*r = (uint128_t)a * b;
812
}
@@ -37,6 +41,10 @@ static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r
3741
return (*r >> n == 0);
3842
}
3943

44+
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
45+
*r = (((uint128_t)(uint64_t)hi) << 64) + lo;
46+
}
47+
4048
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
4149
*r = (int128_t)a * b;
4250
}

src/int128_struct_impl.h

+22-7
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,26 @@
55

66
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
77
# include <intrin.h>
8-
# if defined(_M_X64)
9-
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
10-
# define secp256k1_umul128 _umul128
11-
# define secp256k1_mul128 _mul128
12-
# else
13-
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications. */
8+
# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
9+
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications.
10+
(Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64,
11+
which supports both __(u)mulh and _umul128.) */
12+
# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
13+
# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.")
14+
# endif
1415
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
1516
*hi = __umulh(a, b);
1617
return a * b;
1718
}
1819

1920
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
2021
*hi = __mulh(a, b);
21-
return a * b;
22+
return (uint64_t)a * (uint64_t)b;
2223
}
24+
# else
25+
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
26+
# define secp256k1_umul128 _umul128
27+
# define secp256k1_mul128 _mul128
2328
# endif
2429
#else
2530
/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
@@ -44,6 +49,11 @@ static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t*
4449
}
4550
#endif
4651

52+
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
53+
r->hi = hi;
54+
r->lo = lo;
55+
}
56+
4757
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
4858
r->lo = secp256k1_umul128(a, b, &r->hi);
4959
}
@@ -93,6 +103,11 @@ static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r
93103
: r->hi == 0 && r->lo >> n == 0;
94104
}
95105

106+
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
107+
r->hi = hi;
108+
r->lo = lo;
109+
}
110+
96111
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
97112
int64_t hi;
98113
r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);

0 commit comments

Comments
 (0)