我使用英特尔编译器使用选项-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
答案 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
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机器上发生了非法指令错误。