是否启用了 SSE2 指令?

Posted

技术标签:

【中文标题】是否启用了 SSE2 指令?【英文标题】:Are SSE2 instructions enabled? 【发布时间】:2018-08-10 15:09:24 【问题描述】:

我有一个使用 sse2 内在函数的非常简单的 c++ 代码(我实际在做的一个最小示例)。

#include <xmmintrin.h>
int main()
    __m128d a = 0,0;
    __m128d b = 1,1;
    __m128d c = a + b;
    int t = c[0] >= 1;
    return t;

我想检查加法是否确实编译为矢量化指令。我用g++ -S test.cpp编译文件

我对这件事的理解是,如果我不将msse2 标志放入g++,则不会启用sse2。好像被g++ -Q --help=target的结果证实了

  -msse                             [disabled]
  -msse2                            [disabled]
  -msse2avx                         [disabled]
  -msse3                            [disabled]
  -msse4                            [disabled]
  -msse4.1                          [disabled]
  -msse4.2                          [disabled]
  -msse4a                           [disabled]

但是,在查看汇编代码时,似乎使用了addpd 指令。

main:
.LFB499:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $80, %rsp
    movq    %fs:40, %rax
    movq    %rax, -8(%rbp)
    xorl    %eax, %eax
    pxor    %xmm0, %xmm0
    movaps  %xmm0, -48(%rbp)
    movapd  .LC0(%rip), %xmm0
    movaps  %xmm0, -32(%rbp)
    movapd  -48(%rbp), %xmm0
    addpd   -32(%rbp), %xmm0
    movaps  %xmm0, -64(%rbp)
    movsd   -64(%rbp), %xmm0
    pxor    %xmm1, %xmm1
    ucomisd %xmm1, %xmm0
    setnb   %al
    movzbl  %al, %eax
    movl    %eax, -68(%rbp)
    movl    -68(%rbp), %eax
    movq    -8(%rbp), %rdx
    xorq    %fs:40, %rdx
    je  .L3
    call    __stack_chk_fail
.L3:
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE499:
    .size   main, .-main
    .section    .rodata
    .align 16
.LC0:
    .long   0
    .long   1072693248
    .long   0
    .long   1072693248
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

我在这里看到了一个矛盾,这让我觉得有些东西我不明白。 sse2 是否启用?

【问题讨论】:

在 64 位模式下它始终处于启用状态。 那我猜问题是我不太明白g++ -Q --help=target 做了什么。 --help=target 选项仅指您传递给 gcc 的命令行选项。见gcc.gnu.org/onlinedocs/gcc/Option-Index.html 您也可以使用-m32 创建 32 位二进制文​​件。不确定-Q --help=target 是否认为不同。 sse2 不是 AMD64 的扩展,它是基本指令集的一部分,因此“-msse”和“-msse2”参数不做任何事情,默认情况下它们可能处于关闭状态,但不会停止 gcc 生成 SSE2 代码 【参考方案1】:

我无法重现您的结果。

x86-64 g++ 确实启用了-msse-msse2。您可以在 64 位模式下使用-mno-sse禁用 SSE 代码生成(即使 SSE2 是 x86-64 的基线),在这种情况下 gcc 使用 x87 fld 实现 + 运算符/faddp.

__m128d 被定义为具有两个 double 元素的 GNU C 本机向量,并且您没有使用任何内在函数。如果您使用_mm_set_pd_mm_add_pd 而不是将它们用作带有 大括号初始化列表和+ 运算符的本机向量的GNU 扩展语法,您会得到:

<source>:5:13: error: SSE register return with SSE disabled
     __m128d c = _mm_add_pd(a, b);

有趣的是,即使禁用了 SSE2,它仍然会解析 xmmintrin.h 而不会出错,但仅限于 -O0。启用优化后,它会注意到所有这些(内联)函数会在 SSE 寄存器中返回且 SSE 已禁用,即使您不调用它们也是如此。

您可以通过自己定义一个矢量类型来解决这个问题,例如typedef double v2d __attribute__((vector_size(16)))


On the Godbolt compiler explorer、gcc8.2 -m32 配置为默认启用 SSE2(尽管 SSE2 通常不是 32 位的基线)。

但 gcc6.3 -m32 默认不启用 SSE2,正如您在 -Q --help=target 输出中看到的那样。

当 SSE2 被禁用(明确地或根本没有使用 -m32 启用)时,我尝试过的任何组合都没有让 gcc 发出 addpd。 AFAIK,那将是一个错误。

【讨论】:

以上是关于是否启用了 SSE2 指令?的主要内容,如果未能解决你的问题,请参考以下文章

#error “SSE2 指令集未启用”通过 pip 安装 scikit-bio 时

启用 arch:SSE2 使程序变慢

在 Visual Studio 中检测 SSE/SSE2 指令集的可用性

如何在 Code::Blocks 上启用 SSE/SSE2?

如何以编程方式检查 CPU 上是不是启用了 fused mul add (FMA) 指令?

为单个函数/文件启用增强指令集