-xSSE4.1指定

时间:2015-12-29 10:52:04

标签: sse avx icc

我使用英特尔编译器使用选项-xSSE4.1编译了一段代码。当我查看生成的汇编文件时,我看到已插入AVX指令,例如'vpmovzxbw'。但是,可执行文件似乎仍然在不支持AVX指令集的机器上运行。是什么解释了这个?

这是特定的代码段 -

C -> src0_8x16b  = _mm_cvtepu8_epi16 (src0_8x16b);

Assembly -> vpmovzxbw xmm4, QWORD PTR [rcx]

Binary -> 00066 c4 62 79 30 29   

这是汇编指令使用3个操作数的另一个片段 -

C -> src0_8x16b = _mm_sub_epi16 (src0_8x16b, src1_8x16b);

Assembly -> vpsubw xmm1, xmm13, xmm11              

Binary -> 000bc c4 c1 11 f9 cb   

为了比较,这里是由icc为函数'foo'生成的反汇编(上面的函数foo和代码片段之间的唯一区别是代码片段是使用内在函数编码的) - < / p>

Compiler commands used - 
icc -S -xSSE4.1 -axavx -O3 foo.c

Function foo -
void foo(float *x, int n) 
{
    int i;

    for(i=0; i<n; i++) x[i] *= 2.0;
}

Autodispatch code - 
testl     $-131072, __intel_cpu_indicator(%rip)         #1.27
jne       foo.R                                         #1.27
testl     $-1, __intel_cpu_indicator(%rip)              #1.27
jne       foo.A

Loop in foo.R (AVX variant) - 
vmulps    (%rdi,%rcx,4), %ymm0, %ymm1                   #3.24
vmulps    32(%rdi,%rcx,4), %ymm0, %ymm2                 #3.24
vmovups   %ymm1, (%rdi,%rcx,4)                          #3.24
vmovups   %ymm2, 32(%rdi,%rcx,4)                        #3.24
addq      $16, %rcx                                     #3.5
cmpq      %rdx, %rcx                                    #3.5
jb        ..B2.12       # Prob 82%                      #3.5

Loop in foo.A (SSE variant) - 
movaps    (%rdi,%r8,4), %xmm1                           #3.24
movaps    16(%rdi,%r8,4), %xmm2                         #3.24
mulps     %xmm0, %xmm1                                  #3.24
mulps     %xmm0, %xmm2                                  #3.24
movaps    %xmm1, (%rdi,%r8,4)                           #3.24
movaps    %xmm2, 16(%rdi,%r8,4)                         #3.24
addq      $8, %r8                                       #3.5
cmpq      %rsi, %r8                                     #3.5
jb        ..B3.12       # Prob 82%                      #3.5

2 个答案:

答案 0 :(得分:2)

英特尔编译器can

  

使用-ax标志

生成具有多个矢量化级别的单个可执行文件

例如,生成与AVX兼容的代码,SSE4.1和SSE2以使用-axAVX -axSSE4.2 -xSSE2

由于您使用-axAVX -xSSE4.1编译,因此英特尔生成了AVX分支和SSE4.1分支,并且在运行时它确定哪个指令集可用并选择它。

Agner Fog在他的Optimizing C++ manaul中很好地描述了英特尔的CPU调度程序。请参见“13.7英特尔编译器中的CPU调度”一节。英特尔的CPU调度程序由于多种原因并不理想,其中一个原因是它在AMD上表现不佳,Agner详细描述了这一点。我个人会自己做调度员。

我使用选项-O3 -axavx -xsse2

在ICC 13.0中编译了以下代码
void foo(float *x, int n) {
    for(int i=0; i<n; i++) x[i] *= 2.0;
}

并且程序集的开始是

    test      DWORD PTR __intel_cpu_indicator[rip], -131072 #1.27
    jne       _Z3fooPfi.R                                   #1.27
    test      DWORD PTR __intel_cpu_indicator[rip], -1      #1.27
    jne       _Z3fooPfi.A 

转到_Z3fooPfi.R分支找到主AVX循环

..B2.12:                        # Preds ..B2.12 ..B2.11
vmulps    ymm1, ymm0, YMMWORD PTR [rdi+rcx*4]           #2.25
vmulps    ymm2, ymm0, YMMWORD PTR [32+rdi+rcx*4]        #2.25
vmovups   YMMWORD PTR [rdi+rcx*4], ymm1                 #2.25
vmovups   YMMWORD PTR [32+rdi+rcx*4], ymm2              #2.25
add       rcx, 16                                       #2.2
cmp       rcx, rdx                                      #2.2
jb        ..B2.12       # Prob 82%                      #2.2

转到_Z3fooPfi.A分支有主要的SSE循环

movaps    xmm1, XMMWORD PTR [rdi+r8*4]                  #2.25
movaps    xmm2, XMMWORD PTR [16+rdi+r8*4]               #2.25
mulps     xmm1, xmm0                                    #2.25
mulps     xmm2, xmm0                                    #2.25
movaps    XMMWORD PTR [rdi+r8*4], xmm1                  #2.25
movaps    XMMWORD PTR [16+rdi+r8*4], xmm2               #2.25
add       r8, 8                                         #2.2
cmp       r8, rsi                                       #2.2
jb        ..B3.12       # Prob 82%                      #2.2

答案 1 :(得分:2)

我试图在其他两个编译器上复制结果,即gcc和Microsoft Visual Studio的v100编译器。我无法这样做,即gcc和v100编译器似乎正在生成正确的反汇编。作为进一步的步骤,我仔细研究了我在每种情况下指定的编译器参数之间存在的差异(如果有的话)。事实证明,在使用icc编译器时,我启用了选项来继承用于编译此特定文件的项目默认值。项目设置已配置为包含此选项 -

-xavx

因此,在编译此文件时,我提供的设置 -

-xSSE4.1 -axavx

被前者所取代。这是我在我的问题中详述的行为的原因。

我很抱歉这个错误,但我不会删除这个问题,因为@Zboson的 答案很特别。

PS - 我在其中一条评论中提到我能够在SSE42机器上运行此代码。那是因为我在那台机器上运行的exe确实是SSE41兼容的,因为我显然使用了使用gcc编译器生成的exe。我运行了icc生成的exe,它确实在SSE42机器上发生了非法指令错误。