Не определено ли целочисленное переполнение SSE2?

Знаковое целочисленное переполнение не определено в C и C ++. Но как насчет подписанного целочисленного переполнения в отдельных полях __m128i? Другими словами, определено ли такое поведение в стандартах Intel?

#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <emmintrin.h>

union SSE2
{
    __m128i m_vector;
    uint32_t m_dwords[sizeof(__m128i) / sizeof(uint32_t)];
};

int main()
{
    union SSE2 reg = {_mm_set_epi32(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX)};
    reg.m_vector = _mm_add_epi32(reg.m_vector, _mm_set_epi32(1, 1, 1, 1));

    printf("%08" PRIX32 "\n", (uint32_t) reg.m_dwords[0]);
    return 0;
}
[myria@polaris tests]$ gcc -m64 -msse2 -std=c11 -O3 sse2defined.c -o sse2defined
[myria@polaris tests]$ ./sse2defined
80000000

Обратите внимание, что поля размером 4 байта SSE2 __m128i считаются подписанными.


person Myria    schedule 22.10.2014    source источник
comment
Это очень хороший вопрос!   -  person Nils Pipenbrinck    schedule 23.10.2014
comment
На практике эти элементы ведут себя так, как ожидалось, то есть нормальный набор дополнений 2s и т. Д. Я не знаю, найдете ли вы что-нибудь в документации Intel, чтобы гарантировать это.   -  person Paul R    schedule 23.10.2014
comment
SSE2 __mi128i (очевидно) является архитектурно-зависимой концепцией, поэтому стандарты C и C ++ ничего не говорят о типе, его поведении или внутреннем элементе. Вам необходимо изучить документацию поставщика, чтобы узнать о каких-либо гарантиях сверх того, что дают стандарты.   -  person CB Bailey    schedule 23.10.2014
comment
Приложение C @PaulR (внутреннее) перечисляет его как эквивалент paddd (который обертывает), я не уверен, сколько гарантии, которое должно дать, хотя   -  person harold    schedule 23.10.2014
comment
Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32 Таблица 9- 2 перечисляет его как Wrap-around, но я не могу найти явных гарантий, что _mm_add_epi32 никогда не будет эмулироваться простыми оболочками C.   -  person that other guy    schedule 23.10.2014
comment
@harold: Приложения C нет, вы имели в виду приложение c (информативное, точки последовательности)?   -  person Deduplicator    schedule 23.10.2014
comment
@Deduplicator вы ищете в стандарте C? Конечно, там нет ничего о SSE.   -  person harold    schedule 23.10.2014
comment
@CharlesBailey: Да; поэтому вопрос в том, как Intel определила спецификацию.   -  person Myria    schedule 23.10.2014
comment
@Myria Intel определила paddd обернуть.   -  person harold    schedule 23.10.2014
comment
@Myria, пожалуйста, измените заголовок вашего вопроса соответствующим образом.   -  person Jens Gustedt    schedule 23.10.2014
comment
@thatotherguy: Я не знаю, что, по вашему мнению, дает программная эмуляция _mm_add_epi32() лицензии, чтобы давать результаты, отличные от PADDD.   -  person Ben Voigt    schedule 23.10.2014
comment
@BenVoigt Никакой лицензии не требуется, если где-то нет официальной спецификации. Я действительно согласен с тем, что если бы он не вел себя идентично, это было бы ударом ниже пояса. Ответственный способ сделать это - не определять эту функцию и предоставить аналогичную альтернативу.   -  person that other guy    schedule 23.10.2014


Ответы (2)


В этом вопросе есть три ошибки (не из-за того, что голосование "против", типа "вам не хватает понимания" ... поэтому, я думаю, вы пришли сюда).

1) Вы спрашиваете о конкретной проблеме реализации (с использованием SSE2), а не о стандарте. Вы ответили на свой вопрос: «Переполнение целого числа со знаком в C не определено».

2) Когда вы имеете дело с встроенными функциями c, вы даже не программируете на C! Это вставка инструкций по сборке в строку. Он делает это каким-то переносимым способом, но уже неверно, что ваши данные представляют собой целое число со знаком. Это векторный тип, передаваемый встроенной функции SSE. Затем ВЫ преобразовываете это в целое число и говорите C, что хотите увидеть результат этой операции. Какие бы байты ни были при приведении, вы увидите их, и это не имеет ничего общего со знаковой арифметикой в ​​стандарте C.

3) Было всего два неверных предположения. Я сделал предположение о количестве ошибок и ошибся.

Все немного иначе, если компилятор вставляет инструкции SSE (скажем, в цикле). Теперь компилятор гарантирует, что результат такой же, как и для 32-битной операции со знаком ... ЕСЛИ не существует неопределенного поведения (например, переполнения), и в этом случае он может делать все, что захочет.

Также обратите внимание, что undefined не означает неожиданность ... любое поведение, которое вы наблюдаете для автоматической векторизации, может быть согласованным и повторяемым (возможно, оно всегда переносится на вашем компьютере ... это может быть не верно для всех случаев для окружающего кода, или все компиляторы. Или, если компилятор выбирает разные инструкции в зависимости от доступности SSSE3, SSE4 или AVX *, возможно, даже не все процессоры, если он делает разные варианты генерации кода для разных наборов инструкций, которые используют или не используют преимущества подписанного переполнение UB).

РЕДАКТИРОВАТЬ:

Хорошо, теперь, когда мы спрашиваем о «стандартах Intel» (которых не существует, я думаю, вы имеете в виду стандарты x86), я могу кое-что добавить к своему ответу. Все немного запутано.

Во-первых, внутренний _mm_add_epi32 определяется Microsoft для соответствия определению Intel intrinsics API (https://software.intel.com/sites/landingpage/IntrinsicsGuide/ и внутренние примечания в руководствах Intel по сборке x86). Они ловко определяют это как выполнение __m128i того же действия, что и инструкция x86 PADDD с регистром XMM, без дальнейшего обсуждения (например, это ошибка компиляции на ARM или ее следует эмулировать?).

Во-вторых, PADDD - это не только подписанное дополнение! Это 32-битное двоичное сложение. x86 использует дополнение до двух для целых чисел со знаком, и их добавление является той же бинарной операцией, что и беззнаковое основание 2. Так что да, paddd гарантированно переносится. Здесь есть хорошая ссылка на все инструкции x86, здесь.

Итак, что это означает: опять же, предположение в вашем вопросе ошибочно, потому что нет даже переполнения. Таким образом, результат, который вы видите, должен быть определен поведением. Обратите внимание, что он определяется Microsoft и x86 (а не стандартом C).

Другие компиляторы x86 также реализуют API встроенных функций Intel таким же образом, поэтому _mm_add_epi32 гарантированно переносится только на перенос.

person dave    schedule 22.10.2014
comment
Ну да; вопрос в том, как Intel определила стандарт и соответствуют ли ICC, GCC, Clang, MSVC и т. д. стандарту Intel. Это не буквально вопрос стандарта C. - person Myria; 23.10.2014
comment
В этом случае вы можете изменить свой вопрос: вы спрашиваете о наборе инструкций сборки x86 и о том, определены ли переполнения SSE. - person dave; 23.10.2014
comment
@Myria Intel не определяла никаких стандартов. Они просто определили, как ведут себя их процессоры - person jalf; 23.10.2014
comment
Из руководства Intel SSE4: Внутренний эквивалент компилятора Intel C / C ++ PBLENDVB __m128i _mm_blendv_epi8 (__m12 8i v1, __m128i v2, __m128i mask); - person Myria; 24.10.2014

Это не «целое число со знаком в полях __m128i». Это вызов функции. (Быть встроенным компилятором - это просто оптимизация, как встраивание, и это не взаимодействует со стандартом C, пока соблюдается правило as-if)

Его поведение должно соответствовать контракту (предварительные условия, постусловия), который задокументировал разработчик функции. Обычно встроенные функции документируются поставщиком компилятора, хотя они, как правило, координируют именование и контракт встроенных функций, чтобы помочь в переносе кода.

person Ben Voigt    schedule 22.10.2014
comment
Повторная переносимость: в случае _mm... встроенных функций они определены Intel для ICC (программное обеспечение ). intel.com/sites/landingpage/IntrinsicsGuide) и реализованы совместимым образом с помощью MSVC, GCC, clang и некоторых других менее распространенных компиляторов x86, поэтому применима документация Intel. (В некоторых компиляторах иногда отсутствует какая-то версия _mm256_setr_m128 или чего-то еще, или альтернативные имена, такие как _mm_bslli_si128 для байтового сдвига pslldq, но встроенные функции, которые отображаются на одну инструкцию, очень переносимы.) - person Peter Cordes; 23.04.2021