- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我的笔记本电脑 CPU 仅支持 AVX(高级 vector 扩展)但不支持 AVX2。对于 AVX,128 位 xmm* 寄存器已经扩展到 256 位 ymm* 寄存器以进行浮点运算。但是,我测试过所有版本的 Visual Studio(从 2010 年到 2015 年)在/arch:AVX 优化下不使用 ymm* 寄存器,尽管它们在/arch:AVX2 优化下这样做。
下面显示了一个简单的 for 循环的反汇编。该程序在发布版本中使用/arch:AVX 编译,并启用所有优化选项。
float a[10000], b[10000], c[10000];
for (int x = 0; x < 10000; x++)
1000988F xor eax,eax
10009891 mov dword ptr [ebp-9C8Ch],ecx
c[x] = (a[x] + b[x])*b[x];
10009897 vmovups xmm1,xmmword ptr c[eax]
100098A0 vaddps xmm0,xmm1,xmmword ptr c[eax]
100098A9 vmulps xmm0,xmm0,xmm1
100098AD vmovups xmmword ptr c[eax],xmm0
100098B6 vmovups xmm1,xmmword ptr [ebp+eax-9C78h]
100098BF vaddps xmm0,xmm1,xmmword ptr [ebp+eax-9C78h]
100098C8 vmulps xmm0,xmm0,xmm1
100098CC vmovups xmmword ptr [ebp+eax-9C78h],xmm0
100098D5 add eax,20h
100098D8 cmp eax,9C40h
100098DD jl ComputeTempo+67h (10009897h)
const int winpts = (int)(window_size*sr+0.5);
100098DF vxorps xmm1,xmm1,xmm1
100098E3 vcvtsi2ss xmm1,xmm1,ecx
我还测试了我可以使用 ymm* 寄存器来进一步加速我的程序而不会崩溃。我使用 IMM 内在函数来做到这一点,例如_mm256_mul_ps。
有没有微软编译器开发者给个解释?或者这可能是 Visual Studio 提供的代码比 gcc/g++ 编译器慢的原因之一?
=============已编辑==============
原来是因为在32位机器上运行32位操作系统和在64位机器上运行32位操作系统存在一些差异。在后一种情况下,某些操作系统可能不知道 ymm* 寄存器的存在,因此在上下文切换期间不会正确保留上半部分寄存器。因此,如果在 64 位机器上的 32 位操作系统上使用 ymm* 寄存器,如果发生上下文切换,如果另一个程序也在使用 ymm* 寄存器,则上半部分寄存器可能会悄悄损坏。 Visual Studio 在这方面有点保守。
最佳答案
我制作了一个文本文件vec.cpp
//vec.cpp
void foo(float *a, float *b, float *c) {
for (int i = 0; i < 10000; i++) c[i] = (a[i] + b[i])*b[i];
}
在启用 Visual Studio 2015 x86 x64 的情况下转到命令行并执行
cl /c /O2 /arch:AVX /FA vec.cpp
查看文件vec.asm
,我明白了
$LL4@foo:
vmovups ymm0, YMMWORD PTR [rax-32]
lea rax, QWORD PTR [rax+64]
vmovups ymm2, ymm0
vaddps ymm0, ymm0, YMMWORD PTR [rcx+rax-96]
vmulps ymm2, ymm0, ymm2
vmovups YMMWORD PTR [r8+rax-96], ymm2
vmovups ymm0, YMMWORD PTR [rax-64]
vmovups ymm2, ymm0
vaddps ymm0, ymm0, YMMWORD PTR [rcx+rax-64]
vmulps ymm2, ymm0, ymm2
vmovups YMMWORD PTR [r8+rax-64], ymm2
sub rdx, 1
jne SHORT $LL4@foo
vzeroupper
问题是您在 32 位模式下编译。使用上面相同的函数但在 32 位模式下编译我得到
$LL4@foo:
lea eax, DWORD PTR [ebx+esi]
lea ecx, DWORD PTR [ecx+32]
lea esi, DWORD PTR [esi+32]
vmovups xmm1, XMMWORD PTR [esi-48]
vaddps xmm0, xmm1, XMMWORD PTR [ecx-32]
vmulps xmm0, xmm0, xmm1
vmovups XMMWORD PTR [edx+ecx-32], xmm0
vmovups xmm1, XMMWORD PTR [esi-32]
vaddps xmm0, xmm1, XMMWORD PTR [eax]
vmulps xmm0, xmm0, xmm1
vmovups XMMWORD PTR [eax+edx], xmm0
sub edi, 1
jne SHORT $LL4@foo
关于c++ - Visual Studio 2010 - 2015 不使用 ymm* 寄存器进行 AVX 优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34782957/
是否存在任何 SIMD/向量寄存器指令,其中 ymm 寄存器是在通用寄存器(或 SIMD 寄存器)中指定的,而不是在指令本身中指定的? 本质上,我想做的是编写一个函数,将任何一系列连续的 ymm 寄存
从 SIMD 寄存器加载和存储生成用途寄存器的最佳方式是什么?到目前为止,我一直使用堆栈作为临时的。例如, mov [rsp + 0x00], r8 mov [rsp + 0x08], r9 mov
考虑: movdqa xmm0, xmmword ptr [rcx] movdqa xmm1, xmmword ptr [rcx + 16] movdqa xmm2, xmmword ptr [rcx
幸运的是,PTEST 不会影响进位标志,而只会设置(相当尴尬的)ZF。还会影响 CF 和 ZF。 我提出了以下序列来测试大量值,但我对糟糕的运行时间感到不满意。 Laten
考虑: movdqa xmm0, xmmword ptr [rcx] movdqa xmm1, xmmword ptr [rcx + 16] movdqa xmm2, xmmword ptr [rcx
如何在最少的时钟周期内将 YMM 寄存器的最低 64 位设置为某个常数?我知道可以使用 SSE 指令以及 AVX 指令 VBROADCASTSD 执行此操作的各种方法,但我不确定哪种方法会产生最佳结果
我想在 gcc(AT&T 语法)中运行以下代码(Intel 语法)。 ; float a[128], b[128], c[128]; ; for (int i = 0; i : vmovaps -
这个问题适用于 Haswell 上带有 XMM/YMM 寄存器的打包、单精度浮点运算。 所以根据真棒,真棒table由 Agner Fog 汇总,我知道 MUL 可以在端口 p0 和 p1 上完成(r
伙计们,假设我有一个模板函数: template Vector* Vector::overwrite(const Vector* copy) { this->_normalized = co
我有 2 个变量来模拟 X86 XMM 和 YMM,如下所示: uint64_t xmm_value[2]; uint64_t ymm_value[4]; 现在我想使用内联汇编来读写 XMM/YMM
考虑 x86 中的以下循环: ; on entry, rdi has the number of iterations .top: ; some magic happens here to calcu
我有三个 ymm 寄存器 - ymm4、ymm5 和 ymm6 - 包含 double (qword) float : ymm4: 73 144 168 41 ymm5: 144 348 2
我有三个 ymm 寄存器 - ymm4、ymm5 和 ymm6 - 包含 double (qword) float : ymm4: 73 144 168 41 ymm5: 144 348 2
我正在使用英特尔 AVX 内在函数实现粒子系统。当粒子的 Y 位置小于或等于零时,我想重置粒子。 粒子系统按照这样的 SOA 模式排序: class ParticleSystem { priv
如何将单个 32 位浮点加载/转换为 AVX 256 ymm 寄存器,以便所有 8 个 float 都来自单个源 float ? 之前我使用 AVX 128 xmm 寄存器将单个 float 加载到
好像是recurring problem许多英特尔处理器(直到 Skylake,除非我错了)在将 AVX-256 指令与 SSE 指令混合时表现出较差的性能。 根据 Intel's documenta
我有一个 x86_64 例程,如果成功,它最终在 YMM 寄存器中以零结束,如果 YMM 寄存器,我想返回非零值。 我有一种方法可以通过清除另一个 YMM 寄存器,针对那个寄存器对我的寄存器进行 VP
xmm有什么区别和 ymm注册? 我以为xmm用于 SSE,和 ymm用于 AVX,但我写了一些代码: vmovups ymm1, [r9] vcvtss2si rcx, ymm
有什么办法可以交换 256 位 AVX(YMM) 寄存器中的中间两个 64 位吗? 我知道我们可以利用 VPERM2F128 来交换低 128 位和高 128 位,而 vshufps 似乎只能在高 1
几乎就像标题所说的那样,我需要一种方法来将 256-avx-register 寄存器中所有元素的位置移动/混洗 N 个位置。我发现的所有关于此的使用 32 或 64 位值(__builtin_ia32
我是一名优秀的程序员,十分优秀!