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

Code before:
ATTRIBUTE_TARGET_AVX512
static int string2llAVX512(const char *s, unsigned long slen, long long *value) {
    const char *p = s;
    unsigned long plen = 0;
    int negative = 0;

    /* Abort if length indicates this cannot possibly be an int */
    if (slen == 0 || slen >= LONG_STR_SIZE) return 0;

    /* Special case: first and only digit is 0. */
    if (slen == 1 && p[0] == '0') {
        if (value != NULL) *value = 0;
        return 1;
    }

    if (p[0] == '-') {
        negative = 1;
        p++;
        plen++;

        /* Abort on only a negative sign. */
        if (plen == slen) return 0;
    }

    /* If first digit is 0, the string should just be 0. */
    if (p[0] == '0') {
        return 0;
    }
    const __m256i ascii0 = _mm256_set1_epi8('0');
    const __m256i nine = _mm256_set1_epi8(9);
    uint32_t mask = (uint32_t)(0xFFFFFFFF << (32 - slen + plen));
    __m256i input = _mm256_maskz_loadu_epi8(mask, s + slen - 32);
    /* Load the string into SIMD registers and subtract '0' to convert ASCII to integers */
    __m256i ascii_digits = _mm256_maskz_sub_epi8(mask, input, ascii0);
    /* Validate that all characters are digits (0-9) */
    uint32_t nondigits = _mm256_mask_cmpgt_epu8_mask(mask, ascii_digits, nine);
    if (nondigits) {
        return 0;
    }

    const __m256i mul_1_10 = _mm256_set_epi8(1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10);
    /* Multiply by 10 and horizontally add adjacent pairs of intermediate values. */
    __m256i multiplied_by_10 = _mm256_maddubs_epi16(ascii_digits, mul_1_10);
    __m128i reduced_to_16bit = _mm256_cvtepi16_epi8(multiplied_by_10);

    const __m128i mul_1_100 = _mm_set_epi8(1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100);
    /* Multiply by 100 and horizontally add adjacent pairs of intermediate values. */
    __m128i multiplied_by_100 = _mm_maddubs_epi16(reduced_to_16bit, mul_1_100);

    const __m128i mul_1_10000 = _mm_set_epi16(1, 10000, 1, 10000, 1, 10000, 1, 10000);
    /* Multiply by 10000 and horizontally add adjacent pairs of intermediate values. */

Review comment (performance):
We don't use the *unlikely* annotation much, but in highly optimized code like this, would it make sense to use it to optimize branch prediction for the success cases?

```suggestion
    if (unlikely(p[0] == '0')) {
```

Code after:
ATTRIBUTE_TARGET_AVX512
static int string2llAVX512(const char *s, unsigned long slen, long long *value) {
    const char *p = s;
    unsigned long plen = 0;
    int negative = 0;

    /* Abort if length indicates this cannot possibly be an int */
    if (slen == 0 || slen >= LONG_STR_SIZE) return 0;

    /* Special case: first and only digit is 0. Also handle single-digit 1-9 here. */
    if (slen == 1 && p[0] >= '0' && p[0] <= '9') {
        if (value != NULL) *value = p[0] - '0';
        return 1;
    }

    if (p[0] == '-') {
        negative = 1;
        p++;
        plen++;

        /* Abort on only a negative sign. */
        if (plen == slen) return 0;
    }

    /* If first digit is 0, the string should just be 0. */
    if (unlikely(p[0] == '0')) {
        return 0;
    }

    const __m256i ascii0 = _mm256_set1_epi8('0');
    const __m256i nine = _mm256_set1_epi8(9);
    uint32_t mask = (uint32_t)(0xFFFFFFFF << (32 - slen + plen));
    __m256i input = _mm256_maskz_loadu_epi8(mask, s + slen - 32);
    /* Load the string into SIMD registers and subtract '0' to convert ASCII to integers */
    __m256i ascii_digits = _mm256_maskz_sub_epi8(mask, input, ascii0);
    /* Validate that all characters are digits (0-9) */
    uint32_t nondigits = _mm256_mask_cmpgt_epu8_mask(mask, ascii_digits, nine);
    if (nondigits) {
        return 0;
    }

    const __m256i mul_1_10 = _mm256_set_epi8(1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10);
    /* Multiply by 10 and horizontally add adjacent pairs of intermediate values. */
    __m256i multiplied_by_10 = _mm256_maddubs_epi16(ascii_digits, mul_1_10);
    __m128i reduced_to_16bit = _mm256_cvtepi16_epi8(multiplied_by_10);

    const __m128i mul_1_100 = _mm_set_epi8(1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100);
    /* Multiply by 100 and horizontally add adjacent pairs of intermediate values. */
    __m128i multiplied_by_100 = _mm_maddubs_epi16(reduced_to_16bit, mul_1_100);

    const __m128i mul_1_10000 = _mm_set_epi16(1, 10000, 1, 10000, 1, 10000, 1, 10000);