繁体   English   中英

使用SSE内在函数存储四个16位整数

[英]Store four 16bit integers with SSE intrinsics

我将四个32位浮点数相乘并四舍五入,然后使用SSE内在函数将其转换为四个16位整数。 我想将四个整数结果存储到数组中。 使用浮点数很容易: _mm_store_ps(float_ptr, m128value) 但是我还没有找到使用16位(__m64)整数来执行此操作的指令。

void process(float *fptr, int16_t *sptr, __m128 factor)
{
  __m128 a = _mm_load_ps(fptr);
  __m128 b = _mm_mul_ps(a, factor);
  __m128 c = _mm_round_ps(b, _MM_FROUND_TO_NEAREST_INT);
  __m64 s =_mm_cvtps_pi16(c);
  // now store the values to sptr
}

任何帮助,将不胜感激。

我个人将避免使用MMX。 另外,我将使用显式存储而不是隐式存储,后者通常仅在某些编译器上有效。 以下代码可在MSVC2012和SSE 4.1中找到。

请注意, fptr必须为16字节对齐。 如果在64位模式下进行编译,这不是问题,但是在32位模式下,则应确保其对齐。

#include <stdio.h>
#include <stdint.h>
#include <smmintrin.h>

void process(float *fptr, int16_t *sptr, __m128 factor)
{
  __m128 a = _mm_load_ps(fptr);
  __m128 b = _mm_mul_ps(a, factor);
  __m128i c = _mm_cvttps_epi32(b);
  __m128i d = _mm_packs_epi32(c,c);
  _mm_storel_epi64((__m128i*)sptr, d);
}

int main() {
    float x[] = {1.0, 2.0, 3.0, 4.0};
    int16_t y[4];
    __m128 factor = _mm_set1_ps(3.14159f);
    process(x, y, factor);
    printf("%d %d %d %d\n", y[0], y[1], y[2], y[3]);
}

请注意, _mm_cvtps_pi16不是简单的内在指令,《英特尔内在指令》说:“此内在指令会创建两个或更多指令的序列,并且可能比本机指令执行得差。请考虑此内在指令对性能的影响。”

这是使用MMX版本的程序集输出

mulps   (%rdi), %xmm0
roundps $0, %xmm0, %xmm0
movaps  %xmm0, %xmm1
cvtps2pi    %xmm0, %mm0
movhlps %xmm0, %xmm1
cvtps2pi    %xmm1, %mm1
packssdw    %mm1, %mm0
movq    %mm0, (%rsi)
ret

这是使用仅SSE版本的程序集输出

mulps   (%rdi), %xmm0
cvttps2dq   %xmm0, %xmm0
packssdw    %xmm0, %xmm0
movq    %xmm0, (%rsi)
ret

使用__m64类型,您可以适当地__m64目标指针:

void process(float *fptr, int16_t *sptr, __m128 factor)
{
  __m128 a = _mm_load_ps(fptr);
  __m128 b = _mm_mul_ps(a, factor);
  __m128 c = _mm_round_ps(b, _MM_FROUND_TO_NEAREST_INT);
  __m64 s =_mm_cvtps_pi16(c);
  *((__m64 *) sptr) = s;
}

使用MMX指令的对齐存储和不对齐存储没有区别,就像SSE / AVX一样。 因此,您不需要内部函数即可执行存储。

我认为您可以安全地将其移至通用的64位寄存器( long long对Linux LLP64和Windows LP64均适用)并自行复制。

从我在xmmintrin.h阅读的内容xmmintrin.h ,gcc可以很好地处理从__m64到很long long 可以肯定的是,您可以使用_mm_cvtsi64_si64x

short* f;
long long b = _mm_cvtsi64_si64x(s);
f[0] = b >> 48;
f[1] = b >> 32 & 0x0000FFFFLL;
f[2] = b >> 16 & 0x000000000FFFFLL;
f[3] = b & 0x000000000000FFFFLL;

您可以使用union键入pune以使其看起来更好,但我想这会属于未定义的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM