仅在C中存储__m128变量的2个第一个浮点数

时间:2013-10-13 18:13:00

标签: c storage sse intrinsics

我有一个数组,有两个浮点数的空间,我有一个__m128变量。我想只存储__m128变量的两个第一个浮点数。

我现在正在做的是

_mm_storeu_ps((float*)a, m0); //a is the array, m0 is the __m128 variable

这会将m0的前两个浮点数放入a中,但它也会继续将最后两个浮点数存储在a的内存之外。

2 个答案:

答案 0 :(得分:2)

您可以使用_mm_storel_pi内在函数。此内在函数生成单个movlps指令。这是一个例子。函数sample1-sample4到目前为止已经展示了建议。 Sample5演示了_mm_storel_pi方法。

#include <stdio.h>
#include <intrin.h>

//-----------------------------------------

void sample1 (float *a, __m128 m0)
    {
    _mm_storeu_ps(a, m0); //a is the array, m0 is the __m128 variable
    }

//-----------------------------------------

void sample2 (float *a, __m128 m0)
    {
    float *p = (float *)&m0;
    a[0] = p[0];
    a[1] = p[1];
    }

//-----------------------------------------

void sample3 (float *a, __m128 m0)
    {
    _mm_store_ss(&a[0], m0);
    _mm_store_ss(&a[1], _mm_shuffle_ps(m0, m0, _MM_SHUFFLE(1,1,1,1)));
    }

//-----------------------------------------

void sample4 (float *a, __m128 m0)
    {
    union { __m128 i; float f[4]; } u;
    u.i = m0;
    a [0] = u.f[0];
    a [1] = u.f[1];
    }

//-----------------------------------------

void sample5 (float *a, __m128 m0)
    {
    _mm_storel_pi ((__m64 *)a, m0);
    }

//-----------------------------------------

void printa (float *a)
    {
    printf ("%g %g %g %g\n", a [0], a [1], a [2], a [3]);
    }

//-----------------------------------------

int main (void)
    {
    __m128 m0 = _mm_set_ps (1.0, 2.0, 3.0, 4.0);
    float a [4];

    memset (a, 0, sizeof a);
    sample1 (a, m0);
    printa (a);

    memset (a, 0, sizeof a);
    sample2 (a, m0);
    printa (a);

    memset (a, 0, sizeof a);
    sample3 (a, m0);
    printa (a);

    memset (a, 0, sizeof a);
    sample4 (a, m0);
    printa (a);

    memset (a, 0, sizeof a);
    sample5 (a, m0);
    printa (a);

    return 0;
    }

//-------------------------------------

输出:

4 3 2 1
4 3 0 0
4 3 0 0
4 3 0 0
4 3 0 0

这是函数的gcc 4.8.1 x64代码生成:

0000000000401510 <sample1>:
 401510:    0f 28 02                movaps xmm0,XMMWORD PTR [rdx]
 401513:    0f 11 01                movups XMMWORD PTR [rcx],xmm0
 401516:    c3                      ret    

0000000000401520 <sample2>:
 401520:    0f 28 02                movaps xmm0,XMMWORD PTR [rdx]
 401523:    f3 0f 11 01             movss  DWORD PTR [rcx],xmm0
 401527:    0f c6 c0 55             shufps xmm0,xmm0,0x55
 40152b:    f3 0f 11 41 04          movss  DWORD PTR [rcx+0x4],xmm0
 401530:    c3                      ret    

0000000000401540 <sample3>:
 401540:    0f 28 02                movaps xmm0,XMMWORD PTR [rdx]
 401543:    f3 0f 11 01             movss  DWORD PTR [rcx],xmm0
 401547:    0f c6 c0 55             shufps xmm0,xmm0,0x55
 40154b:    f3 0f 11 41 04          movss  DWORD PTR [rcx+0x4],xmm0
 401550:    c3                      ret    

0000000000401560 <sample4>:
 401560:    48 8b 02                mov    rax,QWORD PTR [rdx]
 401563:    89 01                   mov    DWORD PTR [rcx],eax
 401565:    48 c1 e8 20             shr    rax,0x20
 401569:    89 41 04                mov    DWORD PTR [rcx+0x4],eax
 40156c:    c3                      ret    

0000000000401570 <sample5>:
 401570:    0f 28 02                movaps xmm0,XMMWORD PTR [rdx]
 401573:    0f 13 01                movlps QWORD PTR [rcx],xmm0
 401576:    c3                      ret    

答案 1 :(得分:0)

您有几个选择:

选项1

您可以将指向__m128的指针投射到float*并对其进行索引:

float *p = (float *)&m0;
a[0] = p[0];
a[1] = p[1];

有些人更喜欢创建一个包含4个浮点数和__m128的数组的并集,其性能非常相似。

选项2

如果您只想使用SSE内在函数,则可以使用_mm_store_ss_mm_shuffle_ps

_mm_store_ss(&a[0], m0);
_mm_store_ss(&a[1], _mm_shuffle_ps(m0, m0, _MM_SHUFFLE(1,1,1,1)));

SSE中的随机播放说明非常有用,请详细了解here