Repository: valkey-io/valkey
File: src/util.c (C)

Code before:
    max_level = __get_cpuid_max(0, NULL);
    if (max_level < 7) {
        return 0; /* CPUID leaf 7 not supported, return 0. */
    }

    /* Call CPUID with leaf 7, subleaf 0 to get advanced feature flags */
    if (!__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx)) {
        return 0; /* CPUID failed */
    }

    /* The AVX-512 feature bits are in the EBX register.*/
    int has_avx512f = (ebx & bit_AVX512F) != 0;
    int has_avx512vl = (ebx & bit_AVX512VL) != 0;
    int has_avx512bw = (ebx & bit_AVX512BW) != 0;
    return has_avx512f && has_avx512vl && has_avx512bw;
}

static int (*string2ll_ifunc(void))(const char *, size_t, long long *) {
    if (cpu_has_avx512_features()) {
        return string2llAVX512;
    }
    return string2llScalar;
}

int string2ll(const char *s, size_t slen, long long *value)
    __attribute__((ifunc("string2ll_ifunc")));
#else
/* Fallback for platforms without IFUNC support */
int string2ll(const char *s, size_t slen, long long *value) {
#if HAVE_X86_SIMD
    if (__builtin_cpu_supports("avx512f") &&
        __builtin_cpu_supports("avx512vl") &&
        __builtin_cpu_supports("avx512bw"))
        return string2llAVX512(s, slen, value);
#endif
    return string2llScalar(s, slen, value);
}
#endif

/* Helper function to convert a string to an unsigned long long value.
 * The function attempts to use the faster string2ll() function inside
 * Valkey: if it fails, strtoull() is used instead. The function returns
 * 1 if the conversion happened successfully or 0 if the number is
 * invalid or out of range. */
int string2ull(const char *s, size_t slen, unsigned long long *value) {
    long long ll;
    if (string2ll(s, slen, &ll)) {
        if (ll < 0) return 0; /* Negative values are out of range. */
        *value = ll;
        return 1;
    }

Review comment (bug):
Have you considered using `__attribute__((constructor))` + ptr approach instead of `ifunc`? I find that usually more portable and easier to debug. It also enables you to continue using the `__builtin_cpu_supports` feature and avoid having to maintain low level cpuid code. 

Code after:
}
#endif /* HAVE_IFUNC && HAVE_X86_SIMD */

/* Helper function to convert a string to an unsigned long long value.
 * The function attempts to use the faster string2ll() function inside
 * Valkey: if it fails, strtoull() is used instead. The function returns
 * 1 if the conversion happened successfully or 0 if the number is
 * invalid or out of range. */
int string2ull(const char *s, size_t slen, unsigned long long *value) {
    long long ll;
    if (string2ll(s, slen, &ll)) {
        if (ll < 0) return 0; /* Negative values are out of range. */
        *value = ll;
        return 1;
    }
    errno = 0;
    char *endptr = NULL;
    *value = strtoull(s, &endptr, 10);
    if (errno == EINVAL || errno == ERANGE || !(*s != '\0' && *endptr == '\0')) return 0; /* strtoull() failed. */
    return 1;                                                                             /* Conversion done! */
}

/* Convert a string into a long. Returns 1 if the string could be parsed into a
 * (non-overflowing) long, 0 otherwise. The value will be set to the parsed
 * value when appropriate. */
int string2l(const char *s, size_t slen, long *lval) {
    long long llval;

    if (!string2ll(s, slen, &llval)) return 0;

    if (llval < LONG_MIN || llval > LONG_MAX) return 0;

    *lval = (long)llval;
    return 1;
}

/* return 1 if c>= start && c <= end, 0 otherwise*/
static int safe_is_c_in_range(char c, char start, char end) {
    if (c >= start && c <= end) return 1;
    return 0;
}

static int base_16_char_type(char c) {
    if (safe_is_c_in_range(c, '0', '9')) return 0;
    if (safe_is_c_in_range(c, 'a', 'f')) return 1;
    if (safe_is_c_in_range(c, 'A', 'F')) return 2;
    return -1;
}

/** This is an async-signal safe version of string2l to convert unsigned long to string.
 * The function translates @param src until it reaches a value that is not 0-9, a-f or A-F, or @param we read slen