【问题标题】:Only storing 2 first floats of a __m128 variable in C仅在 C 中存储 __m128 变量的 2 个第一个浮点数
【发布时间】:2013-10-21 07:52:27
【问题描述】:

我有一个可以容纳两个浮点数的数组,并且我有一个 __m128 变量。我只想存储 __m128 变量的前两个浮点数。

我现在做的是

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

这会将 m0 的前两个浮点数放入 a,但它还会继续将其后两个浮点数存储到 a 的内存之外。

【问题讨论】:

  • union { __m128 i; float f[4]; } u = { you_var_here };怎么样,然后你可以访问u.f[0]u.f[1]

标签: c storage sse intrinsics


【解决方案1】:

你有几个选择:

选项 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 中的 shuffle 指令非常有用,请阅读更多关于它们的信息here

【讨论】:

    【解决方案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。我倾向于忘记旧的 SSE 指令。伟大的黑客! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    • 2021-11-21
    • 2016-11-24
    相关资源
    最近更新 更多