Есть ли способ вычесть упакованные беззнаковые двойные слова, насыщенные, на x86, используя MMX / SSE? - PullRequest
4 голосов
/ 10 июня 2019

Я смотрю на MMX / SSE и мне интересно.Существуют инструкции для упакованного, насыщенного вычитания байтов и слов без знака, но не двойных слов.

Есть ли способ делать то, что я хочу, или если нет, то почему его нет?

1 Ответ

2 голосов
/ 17 июня 2019

Если у вас есть SSE4.1, я не думаю, что вы можете добиться большего успеха, чем использовать подход pmaxud + psubd, предложенный @harold.С AVX2 вы, конечно, также можете использовать соответствующие 256-битные варианты.

__m128i subs_epu32_sse4(__m128i a, __m128i b){
    __m128i mx = _mm_max_epu32(a,b);
    return _mm_sub_epi32(mx, b);
}

Без SSE4.1 вам нужно каким-то образом сравнить оба аргумента.К сожалению, нет epu32 сравнения (не до AVX512), но вы можете смоделировать его, сначала добавив 0x80000000 (что эквивалентно xoring в этом случае) к обоим аргументам:

__m128i cmpgt_epu32(__m128i a, __m128i b) {
    const __m128i highest = _mm_set1_epi32(0x80000000);
    return _mm_cmpgt_epi32(_mm_xor_si128(a,highest),_mm_xor_si128(b,highest));
}

__m128i subs_epu32(__m128i a, __m128i b){
    __m128i not_saturated = cmpgt_epu32(a,b);
    return _mm_and_si128(not_saturated, _mm_sub_epi32(a,b));
}

В некоторых случаях может быть лучше заменить сравнение некоторым сдвигом битов старшего бита и передачей его каждому биту с использованием сдвига (это заменяет pcmpgtd и три операции битовой логики(и необходимо загрузить 0x80000000 хотя бы один раз) с помощью psrad и пяти операций с битовой логикой):

__m128i subs_epu32_(__m128i a, __m128i b) {
    __m128i r = _mm_sub_epi32(a,b);
    __m128i c = (~a & b) | (r & ~(a^b)); // works with gcc/clang. Replace by corresponding intrinsics, if necessary (note that `andnot` is a single instruction)
    return _mm_srai_epi32(c,31) & r;
}

Godbolt-Link, также включая adds_epu32 варианты: https://godbolt.org/z/n4qaW1 Странно, но для Clang требуется больше регистровых копий, чем для GCC для не-SSE4.1 вариантов.С другой стороны, clang находит оптимизацию pmaxud для варианта cmpgt_epu32 при компиляции с SSE4.1: https://godbolt.org/z/3o5KCm

...