37inline bool ct_equal(
const void* a,
const void* b, std::size_t len)
noexcept {
38 const auto* pa =
static_cast<const std::uint8_t*
>(a);
39 const auto* pb =
static_cast<const std::uint8_t*
>(b);
41 std::uint64_t diff = 0;
44 for (; i + 8 <= len; i += 8) {
45 std::uint64_t va = 0, vb = 0;
46 std::memcpy(&va, pa + i, 8);
47 std::memcpy(&vb, pb + i, 8);
51 for (; i < len; ++i) {
52 diff |=
static_cast<std::uint64_t
>(pa[i] ^ pb[i]);
201inline int ct_compare(
const void* a,
const void* b, std::size_t len)
noexcept {
202 const auto* pa =
static_cast<const std::uint8_t*
>(a);
203 const auto* pb =
static_cast<const std::uint8_t*
>(b);
213 using namespace ct_compare_detail;
216 const std::uint64_t w0a = ct_load_be(pa + 0), w0b = ct_load_be(pb + 0);
217 const std::uint64_t w1a = ct_load_be(pa + 8), w1b = ct_load_be(pb + 8);
218 const std::uint64_t w2a = ct_load_be(pa + 16), w2b = ct_load_be(pb + 16);
219 const std::uint64_t w3a = ct_load_be(pa + 24), w3b = ct_load_be(pb + 24);
221 std::uint64_t result = 0;
225 std::uint64_t gt = 0, lt = 0;
226 ct_cmp_pair(w3a, w3b, gt, lt);
227 std::uint64_t differs = gt | lt;
229 std::uint64_t mask = 0ULL - differs;
231 result = (gt - lt) & mask;
237 std::uint64_t gt = 0, lt = 0;
238 ct_cmp_pair(w2a, w2b, gt, lt);
239 std::uint64_t differs = gt | lt;
241 std::uint64_t mask = 0ULL - differs;
243 result = ((gt - lt) & mask) | (result & ~mask);
249 std::uint64_t gt = 0, lt = 0;
250 ct_cmp_pair(w1a, w1b, gt, lt);
251 std::uint64_t differs = gt | lt;
253 std::uint64_t mask = 0ULL - differs;
255 result = ((gt - lt) & mask) | (result & ~mask);
261 std::uint64_t gt = 0, lt = 0;
262 ct_cmp_pair(w0a, w0b, gt, lt);
263 std::uint64_t differs = gt | lt;
265 std::uint64_t mask = 0ULL - differs;
267 result = ((gt - lt) & mask) | (result & ~mask);
270#if defined(__GNUC__) || defined(__clang__)
271 asm volatile(
"" :
"+r"(result));
273 return static_cast<int>(
static_cast<std::int64_t
>(result));
277 std::uint64_t result = 0;
278 std::uint64_t decided = 0;
281 for (; i + 8 <= len; i += 8) {
288 std::uint64_t
const xor_val = wa ^ wb;
290#if defined(__riscv) && (__riscv_xlen == 64)
292 asm volatile(
"snez %0, %1" :
"=r"(nz) :
"r"(xor_val));
294 std::uint64_t
const nz = ((xor_val | (0ULL - xor_val)) >> 63) & 1ULL;
301 std::uint64_t
const take = nz & (1ULL - decided);
304 std::uint64_t mask = 0ULL - take;
308 std::uint64_t gt = 0, lt = 0;
311#if defined(__riscv) && (__riscv_xlen == 64)
312 asm volatile(
"sltu %0, %2, %1" :
"=r"(gt) :
"r"(wa),
"r"(wb));
313 asm volatile(
"sltu %0, %2, %1" :
"=r"(lt) :
"r"(wb),
"r"(wa));
315 gt =
static_cast<std::uint64_t
>(wa > wb);
316 lt =
static_cast<std::uint64_t
>(wa < wb);
319 std::uint64_t
const diff_sign = gt - lt;
321 result = (diff_sign & mask) | (result & ~mask);
324#if defined(__GNUC__) || defined(__clang__)
325 asm volatile(
"" :
"+r"(result),
"+r"(decided));
330 for (; i < len; ++i) {
331 std::uint64_t ai = pa[i];
332 std::uint64_t bi = pb[i];
333 std::uint64_t
const diff = ai ^ bi;
335#if defined(__riscv) && (__riscv_xlen == 64)
337 asm volatile(
"snez %0, %1" :
"=r"(nz) :
"r"(diff));
339 std::uint64_t
const nz = ((diff | (0ULL - diff)) >> 63) & 1ULL;
342 std::uint64_t
const take = nz & (1ULL - decided);
343 std::uint64_t mask = 0ULL - take;
346 std::uint64_t gt_b = 0, lt_b = 0;
349#if defined(__riscv) && (__riscv_xlen == 64)
350 asm volatile(
"sltu %0, %2, %1" :
"=r"(gt_b) :
"r"(ai),
"r"(bi));
351 asm volatile(
"sltu %0, %2, %1" :
"=r"(lt_b) :
"r"(bi),
"r"(ai));
353 gt_b =
static_cast<std::uint64_t
>(ai > bi);
354 lt_b =
static_cast<std::uint64_t
>(ai < bi);
356 std::uint64_t
const diff_sign = gt_b - lt_b;
358 result = (diff_sign & mask) | (result & ~mask);
361#if defined(__GNUC__) || defined(__clang__)
362 asm volatile(
"" :
"+r"(result),
"+r"(decided));
368 return static_cast<int>(
static_cast<std::int64_t
>(result));