Оптимальный способ хранения двойных SSE2/AVX/AVX512 как плавающих с использованием встроенных функций

Мне часто нужно использовать double по соображениям точности, но я хочу сохранить результаты как плавающие. Какой оптимальный способ? Я в настоящее время использую:

SSE2: _mm_store_sd((double*)dst, _mm_castps_pd(_mm_cvtpd_ps(xmm)));

AVX: _mm_storeu_ps(dst, _mm256_cvtpd_ps(ymm));

AVX512: _mm256_storeu_ps(dst, _mm512_cvtpd_ps(zmm));

Есть идеи по улучшению?

1 ответ

Решение

Преобразование из упакованного двойного в упакованное плавание доступно только в сужающейся форме, но не в версии, которая принимает 2 вектора двойного и упаковывает в 1 вектор плавания. Так что да, присущие [v]cvtpd2ps ваш единственный вариант. Эти инструкции декодируют до 2 мопов на современном Intel; один для порта (ов) FMA и один для порта в случайном порядке. ( https://agner.org/optimize/)

Сохранение результата является простым, некоторая форма _mm_store/storeu это то, что вы хотите.


Для 128-битных векторов (в результате 2x float = 64 бита), у вас нет целого 128-битного вектора результатов. Вы можете перетасовать два вместе в 128-битный вектор, но с пропускной способностью FP, равной 1 за такт на Intel, начиная с Sandybridge, вероятно, лучше всего хранить их оба отдельно.

Ты хочешь movlps вместо movsd хранить младшие 64 бита float вектор; Он сохраняет один байт инструкции, а для встроенной функции C требуется меньше приведения. Но, к сожалению, это занимает __m64* вместо float* так что вам все еще нужен один актерский состав:

_mm_storel_pi((__m64*)dst,   _mm_cvtpd_ps(xmm) );

Но для загрузки, вы определенно хотите movsd чтобы избежать ложной зависимости от старого значения. movlps нагрузки сливаются в реестр; movsd загружает ноль-удлинить. На самом деле, cvtps2pd xmm, qword [mem] позаботится об этом за вас, если вы можете заставить компилятор испускать это из встроенных функций.

Это может быть трудно сделать это безопасно, по аналогичным причинам pmovzxbw xmm, qword [mem]: компиляторам не удается сложить загрузку qword в операнд памяти для pmovzx/sx: ( загрузка 8 символов из памяти в переменную __m256 как упакованные числа с плавающей запятой одинарной точности)

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