Simplify non-native 64x64-bit multiplication in int128.h.

In the non-native code in int128_add_int64_mul_int64(), use signed
64-bit integer multiplication instead of unsigned multiplication for
the first three product terms. This simplifies the code needed to add
each product term to the result, leading to more compact and efficient
code. The actual performance gain is quite modest, but it seems worth
it to improve the code's readability.

Author: Dean Rasheed <dean.a.rasheed@gmail.com>
Reviewed-by: John Naylor <johncnaylorls@gmail.com>
Discussion: https://postgr.es/m/CAEZATCWgBMc9ZwKMYqQpaQz2X6gaamYRB+RnMsUNcdMcL2Mj_w@mail.gmail.com
pull/239/head
Dean Rasheed 1 month ago
parent d9bb8ef093
commit d8a08dbee4
  1. 48
      src/include/common/int128.h

@ -110,11 +110,11 @@ int128_add_int64(INT128 *i128, int64 v)
}
/*
* INT64_AU32 extracts the most significant 32 bits of int64 as int64, while
* INT64_AL32 extracts the least significant 32 bits as uint64.
* INT64_HI_INT32 extracts the most significant 32 bits of int64 as int32.
* INT64_LO_UINT32 extracts the least significant 32 bits as uint32.
*/
#define INT64_AU32(i64) ((i64) >> 32)
#define INT64_AL32(i64) ((i64) & UINT64CONST(0xFFFFFFFF))
#define INT64_HI_INT32(i64) ((int32) ((i64) >> 32))
#define INT64_LO_UINT32(i64) ((uint32) (i64))
/*
* Add the 128-bit product of two int64 values into an INT128 variable.
@ -129,7 +129,7 @@ int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
*/
*i128 += (int128) x * (int128) y;
#else
/* INT64_AU32 must use arithmetic right shift */
/* INT64_HI_INT32 must use arithmetic right shift */
StaticAssertDecl(((int64) -1 >> 1) == (int64) -1,
"arithmetic right shift is needed");
@ -154,33 +154,27 @@ int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
/* No need to work hard if product must be zero */
if (x != 0 && y != 0)
{
int64 x_u32 = INT64_AU32(x);
uint64 x_l32 = INT64_AL32(x);
int64 y_u32 = INT64_AU32(y);
uint64 y_l32 = INT64_AL32(y);
int32 x_hi = INT64_HI_INT32(x);
uint32 x_lo = INT64_LO_UINT32(x);
int32 y_hi = INT64_HI_INT32(y);
uint32 y_lo = INT64_LO_UINT32(y);
int64 tmp;
/* the first term */
i128->hi += x_u32 * y_u32;
/* the second term: sign-extend it only if x is negative */
tmp = x_u32 * y_l32;
if (x < 0)
i128->hi += INT64_AU32(tmp);
else
i128->hi += ((uint64) tmp) >> 32;
int128_add_uint64(i128, ((uint64) INT64_AL32(tmp)) << 32);
/* the third term: sign-extend it only if y is negative */
tmp = x_l32 * y_u32;
if (y < 0)
i128->hi += INT64_AU32(tmp);
else
i128->hi += ((uint64) tmp) >> 32;
int128_add_uint64(i128, ((uint64) INT64_AL32(tmp)) << 32);
i128->hi += (int64) x_hi * (int64) y_hi;
/* the second term: sign-extended with the sign of x */
tmp = (int64) x_hi * (int64) y_lo;
i128->hi += INT64_HI_INT32(tmp);
int128_add_uint64(i128, ((uint64) INT64_LO_UINT32(tmp)) << 32);
/* the third term: sign-extended with the sign of y */
tmp = (int64) x_lo * (int64) y_hi;
i128->hi += INT64_HI_INT32(tmp);
int128_add_uint64(i128, ((uint64) INT64_LO_UINT32(tmp)) << 32);
/* the fourth term: always unsigned */
int128_add_uint64(i128, x_l32 * y_l32);
int128_add_uint64(i128, (uint64) x_lo * (uint64) y_lo);
}
#endif
}

Loading…
Cancel
Save