File size: 1,309 Bytes
75e8855
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* alp-carry — carry-chain proof kernel
 * Copyright (C) 2026 Ahmad Ali Parr
 * SPDX-License-Identifier: AGPL-3.0-only
 */

/* One public symbol. Resolved once, then an indirect call. */
#include <stdatomic.h>
#include "cpu_dispatch.h"

typedef void (*carry_fn)(const uint64_t *words, uint64_t *out, int n);

extern void alp_carry_prove_adx(const uint64_t *, uint64_t *, int);
extern void alp_carry_prove_portable(const uint64_t *, uint64_t *, int);

int cpu_has_adx(void) {
#if defined(__GNUC__) || defined(__clang__)
    __builtin_cpu_init();
    return __builtin_cpu_supports("adx");
#else
    uint32_t a, b, c, d;
    __asm__ __volatile__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(0), "c"(0));
    if (a < 7) return 0;
    __asm__ __volatile__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(7), "c"(0));
    return (b >> 19) & 1;
#endif
}

static carry_fn resolve(void) {
    return cpu_has_adx() ? alp_carry_prove_adx : alp_carry_prove_portable;
}

static _Atomic(carry_fn) g_kernel;

void alp_carry_prove(const uint64_t *words, uint64_t *out, int n) {
    carry_fn fn = atomic_load_explicit(&g_kernel, memory_order_acquire);
    if (__builtin_expect(fn == 0, 0)) {
        fn = resolve();
        atomic_store_explicit(&g_kernel, fn, memory_order_release);
    }
    fn(words, out, n);
}