Почему существуют 128-битные функции загрузки для SSE?
Я копаюсь в чужом коде и в данный момент пытаюсь понять, почему _mm_load_si128 существует.
По существу, я попытался заменить
_ra = _mm_load_si128(reinterpret_cast<__m128i*>(&cd->data[idx]));
С
_ra = *reinterpret_cast<__m128i*>(&cd->data[idx]);
И он работает и выполняет точно так же.
Я решил, что функции загрузки существуют для небольших типов просто для удобства, чтобы людям не приходилось вручную упаковывать их в непрерывную память, но для данных, которые уже находятся в правильном порядке, зачем беспокоиться?
Есть ли что-нибудь еще что _mm_load_si128 делает? Или это, по сути, просто окольный способ присвоения ценности?
1 ответ:
В SSE существуют явные и неявные нагрузки.
_mm_load_si128(reinterpret_cast<__m128i*>(&cd->data[idx]));- явная нагрузка*reinterpret_cast<__m128i*>(&cd->data[idx]);- неявная нагрузкаПри явной загрузке вы явно поручаете компилятору загрузить данные в регистр XMM - это" официальный " способ Intel сделать это. Вы также можете контролировать, является ли нагрузка выровненной или несогласованной, используя
_mm_load_si128или_mm_loadu_si128.Хотя в качестве расширения большинство компиляторов также могут автоматически генерируйте нагрузки XMM, когда вы делаете Type-punning , но таким образом вы не можете контролировать, выровнена ли нагрузка или нет. В этом случае, так как на современных процессорах нет никакого снижения производительности при использовании несогласованных нагрузок при выравнивании данных, компиляторы, как правило, используют несогласованные нагрузки повсеместно.
Другой, более важный аспект заключается в том, что при неявных нагрузках вы нарушаете строгие правила псевдонимирования, что может привести к неопределенному поведению. Хотя оно того стоит учтите, что в рамках расширения компиляторов, которые поддерживают Intel встроенные функции не стремятся обеспечить строгое нарушает правила на данные заполнитель типов, таких как__m128,__m128d,__m128i. Тем не менее, я думаю, что явные нагрузки чище и пуленепробиваемее.
Почему составители не стремятся обеспечить строгое сглаживание правила о видах ГСП заполнитель?
Первая причина лежит в конструкции внутренних элементов SSE: есть очевидные случаи, когда вы придется использовать тип-каламбур, так как нет другого способа использовать некоторые внутренние свойства. ответ Мистициала прекрасно резюмирует его.
Как отметил Коди Грей в комментариях, стоит отметить, что исторически MMX instrinsics (которые теперь в основном заменены SSE2) даже не предоставляли явных нагрузок или хранилищ - вам пришлось использовать type-punning.
Вторая причина (несколько связанная с первой) лежит в определениях типов этих типы.
GCC
typedefs для типов заполнителей SSE/SSE2 в<xmmintrin.h >и<emmintrin.h>:/* The Intel API is flexible enough that we must allow aliasing with other vector types, and their scalar components. */ typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__)); typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__)); typedef double __m128d __attribute__ ((__vector_size__ (16), __may_alias__));Ключевым здесь является атрибут
__may_alias__, который позволяет работать с этими типами, даже если строгое алиасирование включено с флагом-fstrict-aliasing.Теперь, поскольку лязг и еще ICC совместимы с GCC , они должны следовать той же Конвенции. Таким образом, в настоящее время в этих 3 компиляторах неявные нагрузки / хранилища несколько гарантированы. работайте даже с флагом
Тем не менее, это не означает, что вы должны предпочесть неявные загрузки/хранилища явным.-fstrict-aliasing. Наконец-то, MSVC не поддерживает строгое сглаживание вообще, так что это даже не может быть проблемой там.