Проверка целочисленного переполнения SSE2

При использовании инструкций SSE2, таких как PADDD (т.е. _mm_add_epi32 intrinsic), есть ли способ проверить, не переполнена ли какая-либо из операций?

Я думал, что, возможно, флаг в регистре управления MXCSR может быть установлен после переполнения, но я не вижу, чтобы это произошло. Например, _mm_getcsr() печатает одно и то же значение в обоих случаях ниже (8064):

#include <iostream>
#include <emmintrin.h>

using namespace std;

void main()
{
    __m128i a = _mm_set_epi32(1, 0, 0, 0);
    __m128i b = _mm_add_epi32(a, a);
    cout << "MXCSR:  " << _mm_getcsr() << endl;
    cout << "Result: " << b.m128i_i32[3] << endl;

    __m128i c = _mm_set_epi32((1<<31)-1, 3, 2, 1);
    __m128i d = _mm_add_epi32(c, c);
    cout << "MXCSR:  " << _mm_getcsr() << endl;
    cout << "Result: " << d.m128i_i32[3] << endl;
}

Есть ли другой способ проверить переполнение с помощью SSE2?

4 ответа

Решение

Вот несколько более эффективная версия Gunther Piez sum_and_overflow функция:

void sum_and_overflow(__v4si a, __v4si b, __v4si& sum, __v4si& overflow)
{
   __v4si sa, sb;

    sum = _mm_add_epi32(a, b);                  // calculate sum
    sa = _mm_xor_si128(sum, a);                 // compare sign of sum with sign of a
    sb = _mm_xor_si128(sum, b);                 // compare sign of sum with sign of b
    overflow = _mm_and_si128(sa, sb);           // get overflow in sign bit
    overflow = _mm_srai_epi32(overflow, 31);    // convert to SIMD boolean (-1 == TRUE, 0 == FALSE)
}

Он использует выражение для обнаружения переполнения со страницы Хакер Восторг 27:

sum = a + b;
overflow = (sum ^ a) & (sum ^ b);               // overflow flag in sign bit

Обратите внимание, что вектор переполнения будет содержать более обычные логические значения SIMD -1 для TRUE (переполнение) и 0 для FALSE (без переполнения). Если вам нужно только переполнение в знаковом бите, а другие биты "не заботятся", то вы можете опустить последнюю строку функции, сократив количество инструкций SIMD с 5 до 4.

Примечание: это решение, а также предыдущее решение, на котором оно основано, предназначены для целочисленных значений со знаком. Решение для значений без знака потребует немного другого подхода (см. Ответ Stephen Canon).

Поскольку у вас есть 4 возможных переполнения, регистр управления очень быстро исчерпает биты, особенно если вы хотите переносы, знаки и т. Д. И даже для сложения вектора, состоящего из 16 байтов:-)

Флаг переполнения устанавливается, если биты входного знака равны, а бит знака результата отличается от бита входного знака.

Эта функция рассчитывает sum = a+b и переполнить вручную. Для каждого переполнения 0x80000000 сохраняется в overflow,

void sum_and_overflow(__v4si a, __v4si b, __v4si& sum, __v4si& overflow) {
    __v4si signmask = _mm_set1_epi32(0x80000000);
    sum = a+b;
    a &= signmask;
    b &= signmask;
    overflow = sum & signmask;
    overflow = ~(a^b) & (overflow^a); // overflow is 1 if (a==b) and (resultbit has changed)
}

Примечание: если у вас нет gcc, вы должны заменить ^&+ операторы соответствующими встроенными SSE, такими как _mm_and_si128(), _mm_add_epi32() и т.п.

Изменить: я только что заметил and с маской, конечно, можно сделать в самом конце функции, сохранив два and операции. Но компилятор, скорее всего, будет достаточно умен, чтобы сделать это сам по себе.

Я заметил, что вы просили решение для неподписанных также; к счастью, это тоже довольно просто:

__v4si mask = _mm_set1_epi32(0x80000000);
sum = _mm_add_epi32(a, b);
overflow = _mm_cmpgt_epi32(_mm_xor_si128(mask, a), _mm_xor_si128(mask, sum));

Обычно, чтобы обнаружить неподписанное переполнение, вы просто проверяете либо sum < a или же sum < b, Однако SSE не имеет неподписанных сравнений; xorаргументы с 0x80000000 позволяет использовать сравнение со знаком, чтобы получить тот же результат.

Никакие флаги не затрагиваются базовой инструкцией PADDD.

Таким образом, чтобы проверить это, вы должны написать дополнительный код, в зависимости от того, что вы хотите сделать.

Примечание: вам немного мешает отсутствие epi32 intrisics

Другие вопросы по тегам