Векторные переменные SIMD обычно находятся в регистрах XMM, а не в памяти. Хранение вектора / скалярная перезагрузка - одна из стратегий компилятора для реализации чтения целочисленного элемента вектора, но определенно не единственного. И обычно это не лучший выбор.
Смысл этого совета в том, что если вы хотите получить горизонтальную сумму, напишите ее с помощью встроенных функций shuffle / add, вместо того, чтобы обращаться к элементам и заставить компилятор производить, вероятно, худший asm, чем вы получили бы из правильно выбранных случайных чисел. См. Самый быстрый способ сделать горизонтальную векторную сумму с плавающей запятой на x86 для реализаций C с генерируемым компилятором asm.
Запись в элемент вектора через память будет хуже, потому что векторное хранилище / перекрывающийся скалярный магазин / перезагрузка вектора вызовут остановку пересылки магазина. Но вместо этого компиляторы не настолько глупы, и могут использовать movd xmm0, eax
и использовать векторное перемешивание для объединения нового элемента в вектор.
Ваш конкретный пример чтения __m128.m128_f32[0]
не очень хороший: он буквально бесплатен, потому что скаляр float
обычно хранится в младшем элементе регистра XMM (если вы не компилируете 32-битный код с устаревшим x87). с плавающей точкой для скаляров). Таким образом, нижний элемент вектора __m128
в регистре XMM уже - это скалярное число с плавающей запятой, которое компилятор может использовать с инструкциями addss
. Соглашения о вызовах передаются float
в регистрах XMM и не требуют обнуления верхних элементов, поэтому там нет никаких дополнительных затрат.
На x86 это не катастрофически дорого, но вы определенно хотите избежать этого во внутренних циклах. Что касается float, хороший компилятор превратит его в случайные числа, которые вы могли бы написать сами с помощью встроенных функций, которые в конечном итоге выполняют float _mm_cvtss_f32 (__m128 a)
(что компилируется в ноль инструкций, как описано выше).
Для целых чисел, с SSE4.1, мы надеемся, вы получите pextrd eax, xmm0, 3
или что-то еще (или более дешевый movd eax, xmm0
для младшего элемента).
В ARM передачи между целочисленным и векторным регистрами намного дороже, чем в x86 . По крайней мере, большая задержка, если не плохая пропускная способность. В некоторых процессорах ARM целочисленная и векторная части ЦП вообще не связаны друг с другом, и возникают задержки, когда одной стороне приходится ждать результата от другой. (Я думаю, что я читал, что последние ARM, такие как процессоры, которые поддерживают AArch64, обычно имеют намного меньшую задержку int <-> SIMD.)
(вы не пометили x86 или SSE, но упомянули __m128
для MSVC, поэтому я в основном отвечал за x86.