将单个浮点移动到xmm寄存器

Bas*_*der 4 c++ assembly gcc simd

我想将存储在一个xmm寄存器中的数据与一个浮点值相乘,并将结果保存在xmm寄存器中.我做了一个小图解来解释它好一点.

在此输入图像描述

如你所见,我的数据中有一个xmm0寄存器.例如,它包含:

xmm0 = | 4.0 | 2.5 | 3.5 | 2.0 |

每个浮点存储在4个字节中.我的xmm0寄存器是128位,长16个字节.

这很好用.现在我想将0.5存储在另一个xmm寄存器中,例如xmm1,并将该寄存器与xmm0寄存器相乘,以便存储在xmm0中的每个值乘以0.5.

我完全不知道如何在XMM寄存器中存储0.5.有什么建议?

顺便说一句:它是C++中的内联汇编程序.

void filter(image* src_image, image* dst_image)
{
    float* src = src_image->data;
    float* dst = dst_image->data;

    __asm__ __volatile__ (              
        "movaps (%%esi), %%xmm0\n"      
        // Multiply %xmm0 with a float, e.g. 0.5
        "movaps %%xmm0, (%%edi)\n" 

        :
        : "S"(src), "D"(dst) :  
    );
}
Run Code Online (Sandbox Code Playgroud)

这是我想做的事情的安静简单版本.我得到了一些存储在浮点数组中的图像数据.指向这些数组的指针将传递给程序集.movaps获取数组的前4个浮点值,将这16个字节存储在xmm0寄存器中.在此之后xmm0应该乘以例如0.5.比"新"值应该从edi存储在数组中.

Ste*_*non 8

正如人们在评论中指出的那样,对于这种非常简单的操作,使用内在函数基本上总是更好:

void filter(image* src_image, image* dst_image)
{
    const __m128 data = _mm_load_ps(src_image->data);
    const __m128 scaled = _mm_mul_ps(data, _mm_set1_ps(0.5f));
    _mm_store_ps(dst_image->data, scaled);
}
Run Code Online (Sandbox Code Playgroud)

如果编译器生成错误的代码(并且仅在向编译器供应商提交错误之后),您应该只使用内联ASM.

如果你真的想留在集会中,有很多方法可以完成这项任务.您可以在ASM块之外定义比例向量:

    const __m128 half = _mm_set1_ps(0.5f);
Run Code Online (Sandbox Code Playgroud)

然后就像使用其他操作数一样在ASM中使用它.

如果你真的想要,你可以在没有任何负载的情况下完成:

    "mov    $0x3f000000, %%eax\n"  // encoding of 0.5
    "movd   %%eax,       %%xmm1\n" // move to xmm1
    "shufps $0, %%xmm1,  %%xmm1\n" // splat across all lanes of xmm1
Run Code Online (Sandbox Code Playgroud)

这只是两种方法.还有很多其他方法.您可能会花一些时间使用英特尔指令集参考.

  • @Copa:我碰巧知道这个价值; 我写了很多低级FP代码.IEEE-754单精度数具有8位指数字段和23位有效位字段.指数字段的偏差是127.所以`1.0f = 2 ^ 0`是`127 + 0 << 23`,或`0x3f800000`; `0.5f = 2 ^ -1`是`127 - 1 << 23`,即'0x3f000000`.凡人可能更喜欢使用http://babbage.cs.qc.edu/IEEE-754/ = P. (3认同)