如何将SIMD int向量转换为在GCC中浮动?

cYr*_*rus 7 c gcc simd vectorization

我正在为一个项目使用GCC SIMD向量扩展,一切都很好但是转换,它们只是重置向量的所有组件.

手动状态:

可以从一种向量类型转换为另一种向量类型,前提是它们具有相同的大小(实际上,您也可以将向量转换为相同大小的其他数据类型).

这是一个简单的例子:

#include <stdio.h>

typedef int int4 __attribute__ (( vector_size( sizeof( int ) * 4 ) ));
typedef float float4 __attribute__ (( vector_size( sizeof( float ) * 4 ) ));

int main()
{
    int4 i = { 1 , 2 , 3 , 4 };
    float4 f = { 0.1 , 0.2 , 0.3 , 0.4 };

    printf( "%i %i %i %i\n" , i[0] , i[1] , i[2] , i[3] );
    printf( "%f %f %f %f\n" , f[0] , f[1] , f[2] , f[3] );

    f = ( float4 )i;

    printf( "%f %f %f %f\n" , f[0] , f[1] , f[2] , f[3] );
}
Run Code Online (Sandbox Code Playgroud)

gcc cast.c -O3 -o cast在我的机器上编译并运行我得到:

1 2 3 4
0.100000 0.200000 0.300000 0.400000
0.000000 0.000000 0.000000 0.000000 <-- no no no
Run Code Online (Sandbox Code Playgroud)

我不是那个汇编大师,但我只看到一些字节移动:

[...]
400454:       f2 0f 10 1d 1c 02 00    movsd  0x21c(%rip),%xmm3
40045b:       00 
40045c:       bf 49 06 40 00          mov    $0x400649,%edi
400461:       f2 0f 10 15 17 02 00    movsd  0x217(%rip),%xmm2
400468:       00 
400469:       b8 04 00 00 00          mov    $0x4,%eax
40046e:       f2 0f 10 0d 12 02 00    movsd  0x212(%rip),%xmm1
400475:       00 
400476:       f2 0f 10 05 12 02 00    movsd  0x212(%rip),%xmm0
40047d:       00 
40047e:       48 83 c4 08             add    $0x8,%rsp
400482:       e9 59 ff ff ff          jmpq   4003e0 

我怀疑向量等价于标量:

*( int * )&float_value = int_value;
Run Code Online (Sandbox Code Playgroud)

你怎么解释这种行为?

Ste*_*non 9

这就是矢量强制转换定义要做的事情(其他任何东西都会完全疯狂,并且会使标准的矢量编程习惯用起来非常痛苦).如果你想真正获得转换,你可能想要使用某种类型的内在函数,比如_mm_cvtepi32_ps(这会打破你的矢量代码的漂亮的架构独立性,当然,这也很烦人;一种常见的方法是使用一个定义便携式"内在函数"集的翻译标题.

为什么这有用?各种原因,但这里是最大的:

在矢量代码中,您几乎不想分支.相反,如果您需要有条件地执行某些操作,则评估条件的两侧,并使用蒙版来选择适当的结果.这些掩码矢量"自然地"具有整数类型,而您的数据矢量通常是浮点数; 你想要使用逻辑运算来组合这两者.如果矢量转换只是重新解释位,这种非常常见的习惯是最自然的.

当然,可以解决这个案例,或任何其他一些常见的矢量习语,但"矢量是一个包位"视图是非常常见的,并反映了大多数矢量程序员的想法.