Assembly 使用xmm寄存器时,vxorps在AMD捷豹/推土机/Zen上的归零速度是否比ymm快?

Assembly 使用xmm寄存器时,vxorps在AMD捷豹/推土机/Zen上的归零速度是否比ymm快?,assembly,x86,avx,micro-optimization,amd-processor,Assembly,X86,Avx,Micro Optimization,Amd Processor,AMD CPU通过解码成两个128b操作来处理256b AVX指令。e、 g.AMD Steamroller上的vaddps ymm0、ymm1、ymm1解码为2个宏操作,吞吐量为vaddps xmm0、xmm1、xmm1的一半 XOR归零是一种特殊情况(没有输入依赖项,和,并使来自该寄存器的movdqa在发出/重命名时被消除,就像推土机一直在做的一样,即使对于非归零的REG也是如此)但是否足够早地检测到vxorps-ymm0,ymm0,ymm0仍然只解码到1个宏操作,其性能与vxorps-xm

AMD CPU通过解码成两个128b操作来处理256b AVX指令。e、 g.
AMD Steamroller上的vaddps ymm0、ymm1、ymm1
解码为2个宏操作,吞吐量为
vaddps xmm0、xmm1、xmm1
的一半

XOR归零是一种特殊情况(没有输入依赖项,和,并使来自该寄存器的movdqa在发出/重命名时被消除,就像推土机一直在做的一样,即使对于非归零的REG也是如此)但是否足够早地检测到
vxorps-ymm0,ymm0,ymm0
仍然只解码到1个宏操作,其性能与
vxorps-xmm0,xmm0,xmm0
相同?(不同于
vxorps的ymm3、ymm2、ymm1

或者独立性检测是在解码成两个UOP之后发生的?另外,AMD CPU上的矢量异或归零是否仍然使用执行端口?在Intel CPU上,Nehalem需要一个端口,但Sandybridge系列在发布/重命名阶段处理该端口

Agner Fog的指令表没有列出这种特殊情况,他的MicroTech指南也没有提到UOP的数量


这可能意味着
vxorps xmm0、xmm0、xmm0
是实现
\u mm256\u setzero\u ps()
的更好方法

对于AVX512,
\u mm512\u setzero\u ps()
也尽可能只使用VEX编码的归零习惯用法而不是EVEX来保存字节。(即,对于zmm0-15。
vxorps xmm31、xmm31、xmm31
仍需要EVEX)。gcc/clang目前使用任意寄存器宽度的xor归零习惯用法,而不是总是使用AVX-128

报告为clang和gcc。MSVC已经在使用
xmm
。尚未向ICC报告,ICC也使用zmm REG进行AVX512调零。(尽管英特尔可能不想改变,因为目前任何英特尔CPU都没有任何好处,只有AMD。如果他们曾经发布过将矢量拆分为两半的低功耗CPU,他们可能会改变。他们目前的低功耗设计(Silvermont)根本不支持AVX,只支持SSE4。)


据我所知,使用AVX-128指令将256b寄存器归零的唯一可能的缺点是它不会触发Intel CPU上256b执行单元的预热。可能会破坏试图使它们升温的C或C++黑客。 (256b矢量指令在第一条256b指令之后的第一个~56k周期内速度较慢。请参阅Agner Fog的Microach pdf中的Skylake部分)。如果调用返回
\u mm256\u setzero\u ps
noinline
函数不是预热执行单元的可靠方法,则可能没有问题。(在没有AVX2的情况下仍能工作,并避免任何加载(可能缓存未命中)的是
\uum128 onebits=\umm\ucastsi128\ups(\umm\uset1\uepi8(0xff));

return\u mm256\u insertf128\u ps(\u mm256\u castps128\u ps256(onebits),onebits)
应该编译成
pcmpeqd xmm0,xmm0,xmm0
/
vinsertf128 ymm0,xmm0,1
。对于您调用一次来预热(或保持温暖)的东西来说,这仍然是非常微不足道的执行单元远远领先于关键循环。如果您想要一些可以内联的东西,您可能需要内联asm。)


我没有AMD的硬件,所以我不能测试这个

如果有人拥有AMD硬件,但不知道如何测试,请使用性能计数器来计数周期(最好是m-ops或UOP或AMD称之为的任何东西)

这是我用来测试短序列的NASM/YASM源:

section .text
global _start
_start:

    mov     ecx, 250000000

align 32  ; shouldn't matter, but just in case
.loop:

    dec     ecx  ; prevent macro-fusion by separating this from jnz, to avoid differences on CPUs that can't macro-fuse

%rep 6
    ;    vxorps  xmm1, xmm1, xmm1
    vxorps  ymm1, ymm1, ymm1
%endrep

    jnz .loop

    xor edi,edi
    mov eax,231    ; exit_group(0) on x86-64 Linux
    syscall
如果您不在Linux上,可以用
ret
替换循环后的内容(exit syscall),并从C
main()调用函数

使用
nasm-felf64 vxor-zero.asm和&ld-o vxor-zero vxor-zero.o进行组装以生成静态二进制文件。(或使用)

i7-6700k(英特尔Skylake)上3.9GHz的输出示例。(IDK为什么我的机器在闲置几分钟后才升到3.9GHz,而高达4.2或4.4GHz的涡轮增压器在开机后即可正常工作)。因为我使用的是性能计数器,所以机器运行的时钟速度实际上并不重要。不涉及加载/存储或代码缓存未命中,因此无论多长时间,所有内容的核心时钟周期数都是恒定的

$ alias disas='objdump -drwC -Mintel'
$ b=vxor-zero;  asm-link "$b.asm" && disas "$b" && ocperf.py stat -etask-clock,cycles,instructions,branches,uops_issued.any,uops_retired.retire_slots,uops_executed.thread -r4 "./$b"
+ yasm -felf64 -Worphan-labels -gdwarf2 vxor-zero.asm
+ ld -o vxor-zero vxor-zero.o

vxor-zero:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:       b9 80 b2 e6 0e          mov    ecx,0xee6b280
  400085:       66 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00    data16 data16 data16 data16 data16 nop WORD PTR cs:[rax+rax*1+0x0]
  400094:       66 66 66 2e 0f 1f 84 00 00 00 00 00     data16 data16 nop WORD PTR cs:[rax+rax*1+0x0]

00000000004000a0 <_start.loop>:
  4000a0:       ff c9                   dec    ecx
  4000a2:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000a6:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000aa:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000ae:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000b2:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000b6:       c5 f4 57 c9             vxorps ymm1,ymm1,ymm1
  4000ba:       75 e4                   jne    4000a0 <_start.loop>
  4000bc:       31 ff                   xor    edi,edi
  4000be:       b8 e7 00 00 00          mov    eax,0xe7
  4000c3:       0f 05                   syscall

(ocperf.py is a wrapper with symbolic names for CPU-specific events.  It prints the perf command it actually ran):

perf stat -etask-clock,cycles,instructions,branches,cpu/event=0xe,umask=0x1,name=uops_issued_any/,cpu/event=0xc2,umask=0x2,name=uops_retired_retire_slots/,cpu/event=0xb1,umask=0x1,name=uops_executed_thread/ -r4 ./vxor-zero

 Performance counter stats for './vxor-zero' (4 runs):

        128.379226      task-clock:u (msec)       #    0.999 CPUs utilized            ( +-  0.07% )
       500,072,741      cycles:u                  #    3.895 GHz                      ( +-  0.01% )
     2,000,000,046      instructions:u            #    4.00  insn per cycle           ( +-  0.00% )
       250,000,040      branches:u                # 1947.356 M/sec                    ( +-  0.00% )
     2,000,012,004      uops_issued_any:u         # 15578.938 M/sec                   ( +-  0.00% )
     2,000,008,576      uops_retired_retire_slots:u # 15578.911 M/sec                   ( +-  0.00% )
       500,009,692      uops_executed_thread:u    # 3894.787 M/sec                    ( +-  0.00% )

       0.128516502 seconds time elapsed                                          ( +-  0.09% )
$alias disas='objdump-drwC-Mintel'
$b=零或零;asm链接“$b.asm”&&disas“$b”&&ocperf.py stat-etask时钟、周期、指令、分支、发出的uops\U。任何,uops\U失效。失效\U插槽,uops\U执行。线程-r4“/$b”
+yasm-felf64-沃芬标签-gdwarf2 vxor-zero.asm
+ld-VxO或零VxO或零.o
vxor zero:文件格式elf64-x86-64
第节的分解。正文:
0000000000400080 :
400080:b9 80 b2 e6 0e mov ecx,0xee6b280
400085:66 66 66 2e 0f 1f 84 00 00 00 00数据16数据16数据16数据16 nop字PTR cs:[rax+rax*1+0x0]
400094:66 66 2e 0f 1f 84 00 00数据16数据16 nop字PTR cs:[rax+rax*1+0x0]
0000000000 4000A0:
4000a0:ff c9十二月ecx
4000a2:c5 f4 57 c9 vxorps ymm1,ymm1,ymm1
4000a6:c5 f4 57 c9 vxorps ymm1,ymm1,ymm1
4000aa:c5 f4 57 c9 vxorps ymm1,ymm1,ymm1
4000ae:c5 f4 57 c9 vxorps ymm1,ymm1,ymm1
4000b2:c5 f4 57 c9 vxorps ymm1,ymm1,ymm1
4000b6:c5 f4 57 c9 vxorps ymm1,ymm1,ymm1
4000ba:75 e4 jne 4000a0
公元前4000年:31 ff xor edi,edi
4000be:b8 e7 00 mov eax,0xe7
4000c3:0f 05系统调用
(ocperf.py是一个包装器,具有CPU特定事件的符号名称。它打印实际运行的perf命令):
perf stat-etask clock、cycles、指令、分支、cpu/event=0xe、umask=0x1、name=uops\u issued\u any/、cpu/event=0xc2、umask=0x2、name=uops\u retired\u retired\u slots/、cpu/event=0xb1、umask=0x1、name=uops\u executed\u\u thread/-r4./vxor zero
“/vx或零”(4次运行)的性能计数器统计信息:
128.379226任务时钟:使用的CPU为u(毫秒)#0.999