【问题标题】:AVX instructions generated when -xSSE4.1 specified指定 -xSSE4.1 时生成的 AVX 指令
【发布时间】:2015-12-29 10:52:03
【问题描述】:

我使用英特尔编译器编译了一段带有选项 -xSSE4.1 的代码。当我查看生成的程序集文件时,我看到已经插入了诸如“vpmovzxbw”之类的 AVX 指令。但是,可执行文件似乎仍然可以在不支持 AVX 指令集的机器上运行。这是什么原因?

这是特定的代码 sn-p -

C -> src0_8x16b  = _mm_cvtepu8_epi16 (src0_8x16b);

Assembly -> vpmovzxbw xmm4, QWORD PTR [rcx]

Binary -> 00066 c4 62 79 30 29   

这是另一个 sn-p,其中汇编指令使用 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 和上面的代码 sn-p 的唯一区别是代码 sn-p 是使用内在函数编码的) em> -

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

【问题讨论】:

  • felixcloutier.com/x86/PMOVZX.html你可能和VPMOVZXBW混淆了
  • pmovzx 是 sse41。 vpmovzxbw 是 avx。检查link
  • 也许它会生成一些东西的 AVX 版本,但只有在运行时检查系统支持 AVX 后才会运行它?发布一个反汇编的片段,包括二进制机器代码,这样我们就可以确保它真的是 VEX 编码。理想情况下,如果您在 AVX 之前的机器上有调试器,请在该指令处设置断点并确保它也确实运行过。
  • 能否请您显示您的代码、编译器选项、编译器版本和生成的程序集。
  • ICC根据Agner Fog生成一个CPU调度器。他对此进行了很多详细说明。我不知道它是如何工作的。我认为它适用于库而不是您自己的代码。但我过去在 ICC 的经验是 trouble getting ICC to generated the code I told it to

标签: sse avx icc


【解决方案1】:

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

-xavx

结果在编译这个文件时,我提供的设置 -

-xSSE4.1 -axavx

被前者覆盖。这就是我在问题中详述的行为的原因。

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

PS - 我曾在我的一个 cmets 中提到我能够在 SSE42 机器上运行此代码。那是因为我在那台机器上运行的 exe 确实符合 SSE41,因为我显然使用了使用 gcc 编译器生成的 exe。我运行了 icc 生成的 exe,它确实在 SSE42 机器上因非法指令错误而崩溃。

【讨论】:

  • 感谢您的解释。这是有道理的。
【解决方案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 Intel 编译器中的 CPU 调度”一节。 Intel 的 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

【讨论】:

  • 但是当我使用 SSE41 内在函数时,我希望使用 SSE41 汇编指令!我使用的选项只会告诉编译器在适用的情况下创建同一函数的两个变体,并在它们之间切换运行时。
  • @ashwin,如果只在没有 AVX 的机器上生成 AVX 指令,您的代码将会崩溃。它一定是在生成 SSE 代码,但你还没有找到它。
  • 我知道代码应该会崩溃。因此,我的问题:)。如果您筛选我以前的 cmets,您应该已经注意到我已经在 SSE42 机器上测试过它并且运行良好。可能正如你所说,我还没有找到 SSE 代码,但我对此表示怀疑,因为我查看了 Windows 和 Linux 上生成的反汇编(顺便说一句,它们在两个不同版本的 icc 编译器上),这些是我发现的唯一说明在函数 beginend 之间
  • @ashwin,我说它必须有 SSE 代码的原因是因为你说你之前在没有 AVX 的机器上测试过的 n 个 cmets。这就是为什么我要求你发布你的代码(不仅仅是一行/指令)。你为什么不写一个简短的简单版本来重现你的结果。制作一个小foo 函数应该很容易做到这一点。
  • @ashwin 您也可以只使用-xSSE4.1 进行编译并查看程序集,然后与-axAVX -xSSE4.1 进行比较。
猜你喜欢
  • 2014-03-17
  • 1970-01-01
  • 1970-01-01
  • 2016-11-06
  • 2014-08-15
  • 2016-03-16
  • 1970-01-01
  • 2014-08-10
  • 1970-01-01
相关资源
最近更新 更多