Используя встроенные функции SSE, я получил вектор из четырех 32-разрядных чисел с ограничением в диапазоне 0-255 и округленный до ближайшего целого числа. Теперь я хотел бы записать эти четыре в байтах.
Существует встроенная _mm_cvtps_pi8
, которая преобразует 32-разрядное в 8-разрядное знаковое целое, но проблема в том, что любое значение, превышающее 127, оказывается ограниченным до 127. Я не могу найти никаких инструкций, которые ограничивают 8-разрядные значения без знака.
У меня есть интуиция, что я могу захотеть сделать комбинацию _mm_cvtps_pi16
и _mm_shuffle_pi8
последующей инструкцией перемещения, чтобы получить четыре байта, которые мне _mm_shuffle_pi8
в память. Это лучший способ сделать это? Я собираюсь выяснить, смогу ли я выяснить, как кодировать маску управления тасованием.
ОБНОВЛЕНИЕ: следующее, кажется, делает именно то, что я хочу. Есть ли способ лучше?
#include <tmmintrin.h>
#include <stdio.h>
unsigned char out[8];
unsigned char shuf[8] = { 0, 2, 4, 6, 128, 128, 128, 128 };
float ins[4] = {500, 0, 120, 240};
int main()
{
__m128 x = _mm_load_ps(ins); // Load the floats
__m64 y = _mm_cvtps_pi16(x); // Convert them to 16-bit ints
__m64 sh = *(__m64*)shuf; // Get the shuffle mask into a register
y = _mm_shuffle_pi8(y, sh); // Shuffle the lower byte of each into the first four bytes
*(int*)out = _mm_cvtsi64_si32(y); // Store the lower 32 bits
printf("%d\n", out[0]);
printf("%d\n", out[1]);
printf("%d\n", out[2]);
printf("%d\n", out[3]);
return 0;
}
ОБНОВЛЕНИЕ 2: Здесь еще лучшее решение, основанное на ответе Гарольда:
#include <smmintrin.h>
#include <stdio.h>
unsigned char out[8];
float ins[4] = {10.4, 10.6, 120, 100000};
int main()
{
__m128 x = _mm_load_ps(ins); // Load the floats
__m128i y = _mm_cvtps_epi32(x); // Convert them to 32-bit ints
y = _mm_packus_epi32(y, y); // Pack down to 16 bits
y = _mm_packus_epi16(y, y); // Pack down to 8 bits
*(int*)out = _mm_cvtsi128_si32(y); // Store the lower 32 bits
printf("%d\n", out[0]);
printf("%d\n", out[1]);
printf("%d\n", out[2]);
printf("%d\n", out[3]);
return 0;
}