AMD CPU通过解码为两个128b操作来处理256b AVX指令.例如,vaddps ymm0, ymm1,ymm1在AMD上,Steamroller解码为2个宏操作,吞吐量的一半vaddps xmm0, xmm1,xmm1.
XOR归零是一种特殊情况(没有输入依赖性,并且在Jaguar上至少避免消耗物理寄存器文件条目,并且使得来自该寄存器的movdqa在发出/重命名时被消除,就像Bulldozer一直在做非零的REG)中. 但它是否足够vxorps ymm0,ymm0,ymm0早被检测到仍然只能解码为1个具有相同性能的宏操作 vxorps xmm0,xmm0,xmm0?(不像vxorps ymm3, ymm2,ymm1)
或者,在已经解码为两个uop之后,独立检测是否会发生?此外,AMD CPU上的向量xor-zeroing是否仍然使用执行端口?在Intel-CPU上,Nehalem需要一个端口,但Sandybridge系列在发布/重命名阶段处理它.
Agner Fog的指令表没有列出这个特例,他的微指南没有提到uop的数量.
这可能意味着vxorps xmm0,xmm0,xmm0更好的实施方式_mm256_setzero_ps().
对于AVX512 _mm512_setzero_ps(),如果可能的话,也只使用VEX编码的归零惯用语而不是EVEX来保存字节.(即对于zmm0-15. vxorps xmm31,xmm31,xmm31仍然需要EVEX).gcc/clang目前使用他们想要的任何寄存器宽度的xor-zeroing习语,而不是总是使用AVX-128.
报告为clang bug 32862和gcc bug 80636.MSVC已经使用了xmm.尚未向ICC报告,ICC也使用zmm regs进行AVX512归零.(虽然英特尔可能不会改变,因为目前任何英特尔CPU都没有任何好处,只有AMD.如果他们发布的低功耗CPU将矢量分成两半,他们可能.他们目前的低功耗设计(Silvermont)没有t支持AVX,只支持SSE4.)
我知道使用AVX-128指令清零256b寄存器唯一可能的缺点是它不会触发Intel CPU上256b执行单元的预热.可能会破坏试图加热它们的C或C++黑客攻击.
(在第一个256b指令之后的第一个~56k周期内,256b向量指令较慢.请参阅Agner Fog微格式pdf中的Skylake部分).如果调用noinline返回的函数_mm256_setzero_ps不是预热执行单元的可靠方法,那可能没问题.(一个仍然可以在没有AVX2的情况下工作,并且避免任何负载(可以缓存未命中)是__m128 onebits = _mm_castsi128_ps(_mm_set1_epi8(0xff));
return _mm256_insertf128_ps(_mm256_castps128_ps256(onebits), onebits)应该编译为pcmpeqd xmm0,xmm0,xmm0/ vinsertf128 ymm0,xmm0,1.对于你曾经呼叫一次预热(或保持)执行单元的事情,这仍然是非常微不足道的.关键循环.如果你想要内联的东西,你可能需要inline-asm.)
我没有AMD硬件所以我无法测试这个.
如果有人拥有AMD硬件但不知道如何测试,请使用perf计数器来计算周期(最好是m-ops或uops或AMD称之为的任何内容).
这是我用来测试短序列的NASM/YASM源:
section .text
global _start …Run Code Online (Sandbox Code Playgroud) 我正在对代码的性能关键部分进行微优化,并且遇到了指令序列(在AT&T语法中):
add %rax, %rbx
mov %rdx, %rax
mov %rbx, %rdx
Run Code Online (Sandbox Code Playgroud)
我以为我终于有一个用例xchg可以让我刮一个指令并写:
add %rbx, %rax
xchg %rax, %rdx
Run Code Online (Sandbox Code Playgroud)
然而,根据Agner Fog的指令表,我发现这xchg是一个3微操作指令,在Sandy Bridge,Ivy Bridge,Broadwell,Haswell甚至Skylake上有2个周期延迟.3个完整的微操作和2个周期的延迟!3微操作抛出了我的4-1-1-1的节奏和2周期延迟使得它比在最好的情况下原来的,因为在原来的并行执行可能最后2条指令差.
现在......我得知CPU可能会将指令分解为相当于以下内容的微操作:
mov %rax, %tmp
mov %rdx, %rax
mov %tmp, %rdx
Run Code Online (Sandbox Code Playgroud)
哪里tmp是匿名内部寄存器,我想最后两个微操作可以并行运行,因此延迟是2个周期.
鉴于寄存器重命名发生在这些微架构上,但对我来说这是以这种方式完成的.为什么寄存器重命名器不会交换标签?理论上,这将只有1个周期(可能是0?)的延迟,并且可以表示为单个微操作,因此它会便宜得多.
为什么_mm_extract_ps返回int而不是float?
float从C中的XMM寄存器读取单个数据的正确方法是什么?
或者更确切地说,一种不同的方式是:与_mm_set_ps指令相反的是什么?
我想要一个简单的C方法,以便能够在Linux 64位机器上运行十六进制字节码.这是我的C程序:
char code[] = "\x48\x31\xc0";
#include <stdio.h>
int main(int argc, char **argv)
{
int (*func) ();
func = (int (*)()) code;
(int)(*func)();
printf("%s\n","DONE");
}
Run Code Online (Sandbox Code Playgroud)
我试图运行的代码("\x48\x31\xc0")我通过编写这个简单的汇编程序获得(它不应该真的做任何事情)
.text
.globl _start
_start:
xorq %rax, %rax
Run Code Online (Sandbox Code Playgroud)
然后编译并objdump它以获取字节码.
但是,当我运行我的C程序时,我得到了一个分段错误.有任何想法吗?
vextracti128并vextractf128具有相同的功能,参数和返回值.另外一个是AVX指令集,而另一个是AVX2.有什么不同?
我想用英特尔I64汇编程序做一些长整数数学运算(128位),需要创建一个2的补码.让我们说我的正面价值在于RDX:RAX.
2的补码是通过"翻转位并加1"来完成的.所以最天真的实现是(4条指令和14个字节的代码):
NOT RAX
NOT RDX
ADD RAX,1 ; Can't use INC, it doesn't set Carry
ADC RDX,0
Run Code Online (Sandbox Code Playgroud)
当我在RAX而不是NOT上使用NEG指令时,它对我来说是"+1"但是Carry是错误的,当RAX为零时NEG RAX清除了Carry,但是我需要携带JUST IN THIS CASE.所以下一个最好的方法可能是(4条指令和11个字节的代码):
NOT RDX
NEG RAX
CMC
ADC RDX,0 ; fixed, thanks lurker
Run Code Online (Sandbox Code Playgroud)
还有4条说明.但是不是加+1,我可以减去-1,因为SBB将Carry-Bit加到减数上,当Carry清零时我会加+1.所以我的下一个最好的尝试是这个,有3个指令和10个字节的代码:
NOT RDX
NEG RAX
SBB RDX,-1
Run Code Online (Sandbox Code Playgroud)
从我冗长的文字中可以看出,这一点并不明显.是否有一种更好,更易理解的方法来在汇编程序中进行级联2的补码?
可能这甚至都不是微观但纳米优化,但主题让我感兴趣,我想知道在长模式下使用非本机寄存器大小时是否存在任何惩罚?
我从各种来源了解到,部分寄存器更新(比如ax代替eax)会导致eflags停顿并降低性能.但我不确定长模式.对于此处理器操作模式,哪个寄存器大小被视为原生?x86-64仍然是x86架构的扩展,因此我相信32位仍然是原生的.还是我错了?
例如,像
sub eax, r14d
Run Code Online (Sandbox Code Playgroud)
要么
sub rax, r14
Run Code Online (Sandbox Code Playgroud)
具有相同的尺寸,但在使用其中任何一种时可能会有任何处罚吗?在如下连续指令中混合寄存器大小时可能会有任何处罚吗?(假设高dword在所有情况下均为零)
sub ecx, eax
sub r14, rax
Run Code Online (Sandbox Code Playgroud) 有没有优化此代码(x86-64)的好方法?
mov dword ptr[rsp], 0;
mov dword ptr[rsp+4], 0
Run Code Online (Sandbox Code Playgroud)
其中立即数可以是任何值,不一定是零,但在这种情况下总是立即数。
原来的那对店还慢吗?硬件中的写入组合和 ?ops 的并行操作可能会使一切变得非常快?我想知道有没有问题可以解决。
我正在考虑类似的事情(不知道以下说明是否存在)
mov qword ptr[rsp], 0
Run Code Online (Sandbox Code Playgroud)
或者
mov eax, 0;
mov qword ptr[rsp], rax ; assuming we can spare a register, a bad idea to corrupt one though
Run Code Online (Sandbox Code Playgroud) 昨天我看了VC++ 2010生成的一些32位代码(很可能;不知道具体的选项,对不起),我对一个奇怪的反复出现的细节很感兴趣:在许多功能中,它ebx在序言中归零,它总是像"零寄存器"一样使用它(想想$zeroMIPS).特别是,经常:
mov mem,imm大于1到4个字节mov mem,reg(即使对于0也必须编码完整的立即值大小),但通常(gcc)必要的寄存器被"按需"清零,并保持不变为了更有用的目的;cmp reg,ebx.这就是让我感到非常不寻常的事情,因为它应该完全相同test reg,reg,但是增加了对额外寄存器的依赖.现在,请记住,这发生在非叶子函数中,ebx经常被(被调用者)推入堆栈,因此我不相信这种依赖总是完全免费的.此外,它也用于test reg,reg在完全相同的方式(test/ cmp=> jg).最重要的是,"经典"x86上的寄存器是一种稀缺资源,如果你开始泄漏寄存器,你会浪费很多时间没有充分的理由; 为什么要浪费一个通过所有的功能只是为了保持零?(仍然,考虑一下,我不记得在使用这种"零寄存器"模式的函数中看到很多寄存器溢出).
那么:我错过了什么?它是一个编译器blooper还是一些令人难以置信的智能优化,在2010年特别有趣?
这是一段摘录:
; standard prologue: ebp/esp, SEH, overflow protection, ... then:
xor ebx, ebx
mov [ebp+4], ebx ; zero out some locals
mov [ebp], ebx
call function_1
xor ecx, ecx ; ebx _not_ used to zero registers
cmp eax, ebx ; ... …Run Code Online (Sandbox Code Playgroud) 说,我想清除4个zmm寄存器.
以下代码是否会提供最快的速度?
vpxorq zmm0, zmm0, zmm0
vpxorq zmm1, zmm1, zmm1
vpxorq zmm2, zmm2, zmm2
vpxorq zmm3, zmm3, zmm3
Run Code Online (Sandbox Code Playgroud)
在AVX2上,如果我想清除ymm寄存器,vpxor比vxorps更快,速度更快,因为vpxor可以在多个单元上运行.
在AVX512上,我们没有用于zmm寄存器的vpxor,只有vpxorq和vpxord.这是清除寄存器的有效方法吗?当我使用vpxorq清除zmm寄存器时,CPU是否足够智能,不会对zmm寄存器的先前值产生错误依赖?
在没有物理AVX512 CPU测试的情况下 - 也许有人在Knights Landing上测试过?是否有任何延迟发布?
assembly ×8
x86 ×6
avx ×3
x86-64 ×3
c ×2
optimization ×2
simd ×2
avx2 ×1
avx512 ×1
intel ×1
performance ×1
shellcode ×1
sse ×1
visual-c++ ×1
xeon-phi ×1