My purpose is to add two __m512i
variables (c = a + b
) as efficiently as possible. To do so, I'd like to use the _addcarryx_u64 function which takes uint64_t
as inputs.
unsigned char _addcarryx_u64 (unsigned char c_in,
unsigned __int64 a,
unsigned __int64 b,
unsigned __int64 * out)
I manage to obtain a working function based on buffers:
__m512i _m512_add(const __m512i a, const __m512i b)
{
const size_t n = sizeof(__m512i) / sizeof(uint64_t);
uint64_t buf_a[n], buf_b[n], buf_c[n];
_mm512_storeu_si512((__m512i *)buf_a, a);
_mm512_storeu_si512((__m512i *)buf_b, b);
unsigned char c_in = 0;
for (unsigned i = n-1; i < n; --i)
c_in = _addcarryx_u64(c_in, buf_a[i], buf_b[i], &(buf_c[i]));
return _mm512_setr_epi64(buf_c[0], buf_c[1], buf_c[2], buf_c[3],
buf_c[4], buf_c[5], buf_c[6], buf_c[7]);
}
But it is not as efficient as I expected. Note that I compare timing and result with the GMP library and another function (based on intrinsics functions but not _addcarryx_u64
) that I previously wrote.
My question is the following, is there a more efficient way to access the different uint64_t
than using some buffers?
I was thinking like a table (a[i]
) or using extraction functions but didn't find anything satisfying my needs / didn't manage to do it.
al
and then turns it back into a carry flag again), but Clang doesn't \$\endgroup\$ – harold Nov 7 '18 at 15:34