Включены ли инструкции sse2?

У меня очень простой код на С ++ (минимальный пример того, что я на самом деле делаю) с использованием встроенных функций sse2.

#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-битном режиме он всегда включен.

Jester 10.08.2018 17:12

Тогда я думаю, проблема в том, что я действительно не понимаю, что делает g++ -Q --help=target.

Raphael D. 10.08.2018 17:13

Параметр --help=target относится только к параметрам командной строки, которые вы передаете в gcc. См. gcc.gnu.org/onlinedocs/gcc/Option-Index.html

Banex 10.08.2018 17:13

Также вы можете использовать -m32 для создания 32-битных двоичных файлов. Не уверен, считает ли -Q --help=target это иначе.

Jester 10.08.2018 17:14

Просто чтобы дать некоторую предысторию, я нашел его в верхнем ответе здесь stackoverflow.com/questions/20150257/…

Raphael D. 10.08.2018 17:15

sse2 не является расширением AMD64, это часть базового набора инструкций, поэтому параметры "-msse" и "-msse2" ничего не делают, они могут быть отключены по умолчанию, но это не остановит gcc, генерирующий код SSE2.

Alan Birtles 10.08.2018 17:18
1
6
611
1

Ответы 1

Я не могу воспроизвести ваши результаты.

x86-64 g ++ действительно включает -msse и -msse2. Вы можете запрещать SSE code-gen в 64-битном режиме с -mno-sse (хотя SSE2 является базовым для x86-64), и в этом случае gcc реализует оператор + с x87 fld / faddp.

__m128d определяется как собственный вектор GNU C с двумя элементами double, и вы не использовали никаких встроенных функций. Если бы вы использовали _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))).


Об обозревателе компилятора Godbolt, gcc8.2 -m32 настроен с включенным SSE2 по умолчанию (даже несмотря на то, что SSE2 является базовой линией нет для 32-битных в целом).

Но gcc6.3 -m32 не включает SSE2 по умолчанию, как вы можете видеть в выводе -Q --help=target.

Никакая комбинация чего-либо, что я пробовал, никогда не заставляла gcc испускать addpd, когда SSE2 был отключен (явно или просто не включен с -m32). AFAIK, это было бы ошибкой.

Другие вопросы по теме