Итак, у меня есть набор данных со смешанными значениями для упаковки, который выглядит следующим образом:
{(Point_x, Point_y, Point_z, Scalar),
(Point_x, Point_y, Point_z, Scalar),
(Point_x, Point_y, Point_z, Scalar),
...}
Где каждый Point_x, Point_y, Point_z и Scalar представляют собой 32-битные числа с плавающей запятой.
Благодаря этому я могу загрузить каждую выровненную точку, но мне нужно переместить точку x,y,z в отдельный регистр для моей операции, а затем установить последнее значение в 1.f
в регистре __m128
(где будет скаляр). Какая инструкция используется, чтобы установить последнее значение в регистре как 1.f
и оставить остальные значения нетронутыми?
в настоящее время я делаю:
__m128 rPointMixed = _mm_load_ps( (float*)pPoint );
__m128 rOne =_mm_set1_ps(1.f);
__m128 rPoint = _mm_blend_ps(rPointMixed,rOne,0x8);
но, возможно, это не самое эффективное решение, меня устраивает инструкция sse4/avx/avx2, хотя если это так, то с ними есть действительно эффективный способ
struct Vec4f
{
float x;
float y;
float z;
float scalar;
};
Vec4f vData[10000];
//in reality this loop is unrolled to do 8 at a time, but rolled up for simplicity sake
for( int i = 0; i < 10000; ++i)
{
__m128 rPointData = _mm_load_ps( (float*)vData[i] );
//math there where it permutes the scalar and does math with it
//3 just cause it is the last value?
__m128 rPoint = [unknownIntrinsic](rPointData ,1.f, 3); //?
//point math here
}
Спасибо за помощь в продвижении
Если вы сделали _mm_blend_ps
сразу после _mm_load_ps
, было бы полезно перевернуть смесь: _mm_blend_ps(rOne,rPointMixed,0x7)
. При включенном AVX компилятор мог сохранить rOne
в регистр сохранения во время цикла и скомпилировать_mm_blend_ps
и _mm_load_ps
в одну инструкцию с операндом памяти. Но с вычисленным операндом это бесполезно.
Если нет инструкции с более высокой пропускной способностью, чем blendps
(0,33 CPI на Intel), то, что вы делаете, уже идеально.
Обратите внимание, что на самом деле вам не нужно вызывать _mm_set1_ps(1.f)
для каждой итерации цикла (поэтому ваш «неизвестный встроенный код» на самом деле просто _mm_blend_ps
), поскольку rOne
является константой. Однако при включенной оптимизации большинство компиляторов будут достаточно умны, чтобы сделать это только один раз перед циклом.
Индекс последнего элемента —
3
, а не4
. Но, как говорит Л.Х.Лаурини,blendps
более эффективен, чемinsertps
или любое другое перемешивание, аset1
бесплатен, поскольку он является константой. Если бы вам нужно было вставить скаляр переменной времени выполнения,insertps
стоило бы рассмотреть. felixcloutier.com/x86/insertps (_mm_insert_ps
принимает векторный источник, поэтому вам придется полагаться на оптимизатор для оптимизации_mm_set
или трансляции.)