繁体   English   中英

微融合和寻址模式

[英]Micro fusion and addressing modes

我使用英特尔® 架构代码分析器(IACA) 发现了一些意外(对我而言)。

以下指令使用[base+index]寻址

addps xmm1, xmmword ptr [rsi+rax*1]

根据 IACA,它没有微型保险丝。 但是,如果我像这样使用[base+offset]

addps xmm1, xmmword ptr [rsi]

IACA 报告说它确实熔断了。

Intel 优化参考手册的第 2-11 节给出了以下作为“所有解码器都可以处理的微融合微操作”的示例

FADD DOUBLE PTR [RDI + RSI*8]

Agner Fog 的优化汇编手册也给出了使用[base+index]寻址的微操作融合的例子。 例如,参见第 12.2 节“Core2 上的相同示例”。 那么正确答案是什么呢?

在解码器和 uop-cache 中,寻址模式不影响微融合(除了带有立即操作数的指令不能微融合 RIP 相对寻址模式)。

但是某些 uop 和寻址模式的组合无法在 ROB 中保持微融合(在乱序内核中),因此英特尔 SnB 系列 CPU 在必要时会在问题发生之前的某个时间点“取消层压”/重命名阶段。 对于问题吞吐量和乱序窗口大小(ROB 大小),取消层压后的融合域 uop 计数很重要。

Intel 的优化手册第 2.5.2.4 节:微操作队列和循环流检测器 (LSD)中描述了 Sandybridge 的取消层压,但没有描述任何后续微架构的更改。

更新:现在英特尔手册有一个详细的部分来描述 Haswell 的取消层压。 参见章节 2.4.5 拆层。 SandyBridge 的简要说明在第 2.5.2.4 节。


这些规则,我从 SnB、HSW 和 SKL 的实验中可以看出:

  • SnB(我也假设 IvB):索引寻址模式总是未分层,其他保持微融合。 IACA(大部分?)是正确的。
  • HSW、SKL:如果索引 ALU 指令有 2 个操作数并将 dst 寄存器视为读-修改-写,则它们仅保留微融合的索引 ALU 指令。 这里的“操作数”包括标志,意味着adccmov不会微熔断器。 大多数 VEX 编码指令也不融合,因为它们通常具有三个操作数(因此paddb xmm0, [rdi+rbx]融合但vpaddb xmm0, xmm0, [rdi+rbx]没有)。 最后,偶尔第一个操作数为只写的2-操作数指令,如pabsb xmm0, [rax + rbx]也不熔断。 IACA 是错误的,应用了 SnB 规则。

相关:简单(非索引)寻址模式是端口 7(Haswell 及更高版本)上的专用存储地址单元可以处理的唯一模式,因此避免存储的索引寻址模式仍然可能有用。 (对此的一个好技巧是使用单个寄存器处理您的 dst,但使用dst+(initial_src-initial_dst) src。然后您只需在循环内增加 dst 寄存器。)

请注意,某些指令根本不会进行微熔断器(即使在解码器/uop 缓存中)。 例如shufps xmm, [mem], imm8vinsertf128 ymm, ymm, [mem], imm8在 SnB 上通过 Skylake 总是 2 uop,即使它们的寄存器源版本只有 1 uop。 这对于具有 imm8 控制操作数加上通常的 dest/src1、src2 寄存器/内存操作数的指令来说是典型的,但还有一些其他情况。 例如, PSRLW/D/Q xmm,[mem] (来自内存操作数的向量移位计数)没有微熔丝,PMULLD 也没有。

另请参阅Agner Fog 博客上的这篇文章,讨论当您阅读大量寄存器时对 HSW/SKL 的吞吐量限制问题:与使用较少寄存器操作数的相同指令相比,使用索引寻址模式的大量微融合会导致速度变慢:一-寄存器寻址模式和立即数。 我们还不知道原因,但我怀疑某种寄存器读取限制,可能与从 PRF 读取大量冷寄存器有关。


测试用例,来自实际测量的数字:这些都是解码器中的微型保险丝,AFAIK,即使它们后来未层压。

# store
mov        [rax], edi  SnB/HSW/SKL: 1 fused-domain, 2 unfused.  The store-address uop can run on port7.
mov    [rax+rsi], edi  SnB: unlaminated.  HSW/SKL: stays micro-fused.  (The store-address can't use port7, though).
mov [buf +rax*4], edi  SnB: unlaminated.  HSW/SKL: stays micro-fused.

# normal ALU stuff
add    edx, [rsp+rsi]  SnB: unlaminated.  HSW/SKL: stays micro-fused.  
# I assume the majority of traditional/normal ALU insns are like add

HSW/SKL 可能必须取消层压的三输入指令

vfmadd213ps xmm0,xmm0,[rel buf] HSW/SKL: stays micro-fused: 1 fused, 2 unfused.
vfmadd213ps xmm0,xmm0,[rdi]     HSW/SKL: stays micro-fused
vfmadd213ps xmm0,xmm0,[0+rdi*4] HSW/SKL: un-laminated: 2 uops in fused & unfused-domains.
     (So indexed addressing mode is still the condition for HSW/SKL, same as documented by Intel for SnB)

# no idea why this one-source BMI2 instruction is unlaminated
# It's different from ADD in that its destination is write-only (and it uses a VEX encoding)
blsi   edi, [rdi]       HSW/SKL: 1 fused-domain, 2 unfused.
blsi   edi, [rdi+rsi]   HSW/SKL: 2 fused & unfused-domain.


adc         eax, [rdi] same as cmov r, [rdi]
cmove       ebx, [rdi]   Stays micro-fused.  (SnB?)/HSW: 2 fused-domain, 3 unfused domain.  
                         SKL: 1 fused-domain, 2 unfused.

# I haven't confirmed that this micro-fuses in the decoders, but I'm assuming it does since a one-register addressing mode does.

adc   eax, [rdi+rsi] same as cmov r, [rdi+rsi]
cmove ebx, [rdi+rax]  SnB: untested, probably 3 fused&unfused-domain.
                      HSW: un-laminated to 3 fused&unfused-domain.  
                      SKL: un-laminated to 2 fused&unfused-domain.

我假设 Broadwell 在 adc/cmov 中表现得像 Skylake。

奇怪的是,HSW 未对存储器源 ADC 和 CMOV 进行层压。 也许英特尔在到达交付 Haswell 的最后期限之前没有从 SnB 改变它。

Agner 的 insn 表说cmovcc r,madc r,m在 HSW/SKL 上根本没有微保险丝,但这与我的实验不符。 我正在测量的周期计数与融合域 uop 问题计数相匹配,对于 4 uop/时钟问题瓶颈。 希望他会仔细检查并更正表格。

内存目标整数 ALU

add        [rdi], eax  SnB: untested (Agner says 2 fused-domain, 4 unfused-domain (load + ALU  + store-address + store-data)
                       HSW/SKL: 2 fused-domain, 4 unfused.
add    [rdi+rsi], eax  SnB: untested, probably 4 fused & unfused-domain
                       HSW/SKL: 3 fused-domain, 4 unfused.  (I don't know which uop stays fused).
                  HSW: About 0.95 cycles extra store-forwarding latency vs. [rdi] for the same address used repeatedly.  (6.98c per iter, up from 6.04c for [rdi])
                  SKL: 0.02c extra latency (5.45c per iter, up from 5.43c for [rdi]), again in a tiny loop with dec ecx/jnz


adc     [rdi], eax      SnB: untested
                        HSW: 4 fused-domain, 6 unfused-domain.  (same-address throughput 7.23c with dec, 7.19c with sub ecx,1)
                        SKL: 4 fused-domain, 6 unfused-domain.  (same-address throughput ~5.25c with dec, 5.28c with sub)
adc     [rdi+rsi], eax  SnB: untested
                        HSW: 5 fused-domain, 6 unfused-domain.  (same-address throughput = 7.03c)
                        SKL: 5 fused-domain, 6 unfused-domain.  (same-address throughput = ~5.4c with sub ecx,1 for the loop branch, or 5.23c with dec ecx for the loop branch.)

是的,没错, adc [rdi],eax / dec ecx / jnz比在 SKL 上使用add而不是adc的相同循环运行得更快 我没有尝试使用不同的地址,因为显然 SKL 不喜欢重复重写同一地址(存储转发延迟高于预期。另见这篇关于重复存储/重新加载到相同地址的文章比 SKL 上的预期慢.

内存目标adc有很多 uop,因为 Intel P6 系列(显然是 SnB 系列)无法为多 uop 指令的所有 uops 保留相同的 TLB 条目,因此需要额外的 uop 来解决该问题- 在加载和添加完成,然后存储出现故障的情况下,但不能重新启动 insn,因为 CF 已经更新 来自 Andy Glew (@krazyglew) 的一系列有趣评论。

据推测,解码器中的融合和稍后的取消层压使我们无需使用微码 ROMadc [base+idx], reg的单个指令生成超过 4 个融合域 uops。


为什么 SnB 系列不分层

Sandybridge 简化了内部 uop 格式以节省功率和晶体管(同时对使用物理寄存器文件进行了重大更改,而不是将输入/输出数据保存在 ROB 中)。 SnB 系列 CPU 在乱序内核中只允许有限数量的输入寄存器用于融合域 uop。 对于 SnB/IvB,该限制为 2 个输入(包括标志)。 对于 HSW 及更高版本,一个 uop 的限制为 3 个输入。 我不确定 memory-destination addadc是否充分利用了这一点,或者英特尔是否必须通过一些说明让 Haswell 走出门外

Nehalem 及更早版本的未融合域 uop 限制为 2 个输入,但 ROB 显然可以使用 3 个输入寄存器(非内存寄存器操作数、基址和索引)跟踪微融合 uops。


所以索引存储和 ALU+加载指令仍然可以高效解码(不必是组中的第一个 uop),并且不会在 uop 缓存中占用额外的空间,否则微融合的优势在调优上基本上就没有了紧密的循环。 “un-lamination”发生在 4-fused-domain-uops-per-cycle issue/retire width out-of-order core 之前 融合域性能计数器 (uops_issued / uops_retired.retire_slots) 在取消层压后计算融合域 uops。

英特尔对重命名器的描述(第 2.3.3.1 节:重命名器)暗示它是问题/重命名阶段实际执行取消层压,因此用于取消层压的 uops 可能仍会在 28/56/64 融合中微融合-domain uop 问题队列/循环缓冲区(又名 IDQ)。

TODO:测试一下。 制作一个几乎适合循环缓冲区的循环。 更改某些内容,以便其中一个 uops 将在发布前取消层压,并查看它是否仍从循环缓冲区 (LSD) 运行,或者所有 uops 现在是否都从 uop 缓存 (DSB) 中重新获取。 有 perf 计数器来跟踪 uops 的来源,所以这应该很容易。

更难的 TODO:如果在从 uop 缓存读取和添加到 IDQ 之间发生未分层,请测试它是否可以减少 uop 缓存带宽。 或者,如果在发行阶段发生未层压,是否会影响发行吞吐量? (即在发出第一个 4 之后它如何处理剩余的 uops。)


(有关基于调整某些 LUT 代码的一些猜测,请参阅此答案的先前版本,其中关于vpgatherdd一些注释比pinsrw循环多出pinsrw周期。)

SnB 的实验测试

HSW/SKL 数值是在 i5-4210U 和 i7-6700k 上测量的。 两者都启用了 HT(但系统空闲,因此线程拥有整个内核)。 我使用ocperf.py在两个系统上运行相同的静态二进制文件,SKL 上的 Linux 4.10 和 HSW 上的 Linux 4.8。 (HSW 笔记本电脑 NFS 安装在我的 SKL 桌面的 /home 上。)

SnB 数量的测量如下所述,在不再工作的 i5-2500k 上。

通过对 uops 和周期的性能计数器进行测试来确认。

我找到了一张英特尔 Sandybridge 的 PMU 事件表,用于 Linux 的perf命令。 (遗憾的是,标准perf没有大多数特定于硬件的 PMU 事件的符号名称,例如 uops。)我在最近的答案中使用了它。

ocperf.py为这些特定于 uarch 的 PMU 事件提供符号名称,因此您不必查找表。 此外,相同的符号名称适用于多个 uarch。 当我第一次写这个答案时,我并不知道。

为了测试 uop 微融合,我构建了一个测试程序,该程序在 Intel CPU 的每周期 4 uop 融合域限制上存在瓶颈。 为了避免任何执行端口争用,这些 uop 中的许多都是nop ,它们仍然位于 uop 缓存中,并与任何其他 uop 一样通过管道,只是它们不会被分派到执行端口。 xor x, samexor x, same或消除的移动,将是相同的。)

测试程序: yasm -f elf64 uop-test.s && ld uop-test.o -o uop-test

GLOBAL _start
_start:
    xor eax, eax
    xor ebx, ebx
    xor edx, edx
    xor edi, edi
    lea rsi, [rel mydata]   ; load pointer
    mov ecx, 10000000
    cmp dword [rsp], 2      ; argc >= 2
    jge .loop_2reg

ALIGN 32
.loop_1reg:
    or eax, [rsi + 0]
    or ebx, [rsi + 4]
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_1reg
;   xchg r8, r9     ; no effect on flags; decided to use NOPs instead

    jmp .out

ALIGN 32
.loop_2reg:
    or eax, [rsi + 0 + rdi]
    or ebx, [rsi + 4 + rdi]
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_2reg

.out:
    xor edi, edi
    mov eax, 231    ;  exit(0)
    syscall

SECTION .rodata
mydata:
db 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff

我还发现,如果循环不是 4 uop 的倍数,则循环缓冲区外的 uop 带宽不是每个周期的常数 4。 (即它是abcabc ,...;不是abcabcab ,...)。 不幸的是,Agner Fog 的微架构文档并不清楚循环缓冲区的这种限制。 请参阅执行 uop 计数不是处理器宽度倍数的循环时性能是否会降低? 有关 HSW/SKL 的更多调查。 在这种情况下,SnB 可能比 HSW 更糟糕,但我不确定,也没有可用的 SnB 硬件。

我想将宏融合(比较和分支)排除在图片之外,所以我在dec和分支之间使用了nop 我使用了 4 个nop ,因此使用微融合,循环将是 8 个 uops,并且每 1 次迭代以 2 个周期填充管道。

在另一个版本的循环中,使用不使用微融合的 2 操作数寻址模式,循环将是 10 个融合域 uops,运行 3 个周期。

来自我的 3.3GHz Intel Sandybridge (i5 2500k) 的结果。 我没有做任何事情来让 cpufreq 调控器在测试之前提高时钟速度,因为周期是您不与内存交互时的周期。 我为必须以十六进制输入的性能计数器事件添加了注释。

测试 1-reg 寻址模式:无 cmdline arg

$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test

Performance counter stats for './uop-test':

     11.489620      task-clock (msec)         #    0.961 CPUs utilized
    20,288,530      cycles                    #    1.766 GHz
    80,082,993      instructions              #    3.95  insns per cycle
                                              #    0.00  stalled cycles per insn
    60,190,182      r1b1  ; UOPS_DISPATCHED: (unfused-domain.  1->umask 02 -> uops sent to execution ports from this thread)
    80,203,853      r10e  ; UOPS_ISSUED: fused-domain
    80,118,315      r2c2  ; UOPS_RETIRED: retirement slots used (fused-domain)
   100,136,097      r1c2  ; UOPS_RETIRED: ALL (unfused-domain)
       220,440      stalled-cycles-frontend   #    1.09% frontend cycles idle
       193,887      stalled-cycles-backend    #    0.96% backend  cycles idle

   0.011949917 seconds time elapsed

测试 2-reg 寻址模式:使用 cmdline arg

$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test x

 Performance counter stats for './uop-test x':

         18.756134      task-clock (msec)         #    0.981 CPUs utilized
        30,377,306      cycles                    #    1.620 GHz
        80,105,553      instructions              #    2.64  insns per cycle
                                                  #    0.01  stalled cycles per insn
        60,218,693      r1b1  ; UOPS_DISPATCHED: (unfused-domain.  1->umask 02 -> uops sent to execution ports from this thread)
       100,224,654      r10e  ; UOPS_ISSUED: fused-domain
       100,148,591      r2c2  ; UOPS_RETIRED: retirement slots used (fused-domain)
       100,172,151      r1c2  ; UOPS_RETIRED: ALL (unfused-domain)
           307,712      stalled-cycles-frontend   #    1.01% frontend cycles idle
         1,100,168      stalled-cycles-backend    #    3.62% backend  cycles idle

       0.019114911 seconds time elapsed

因此,两个版本都运行 80M 指令,并将 60M uop 分派到执行端口。 or使用内存源为or分派到 ALU,并为负载分配一个加载端口,无论它是否在管道的其余部分进行微融合nop根本不分派到执行端口.) 同样,两个版本都停用了 100M 未融合域 uops,因为 40M nops 在这里也算在内。

不同之处在于融合域的计数器。

  1. 1 寄存器地址版本仅发布和停用 80M 融合域 uops。 这与指令数相同。 每个insn变成一个融合域uop。
  2. 2 寄存器地址版本发布 100M 融合域 uops。 这与未融合域 uops 的数量相同,表明没有发生微融合。

我怀疑如果分支错误预测导致 uops 在发布后被取消,但在退休之前,您只会看到 UOPS_ISSUED 和 UOPS_RETIRED(已使用退休槽)之间的区别。

最后,性能影响是真实的。 非融合版本需要 1.5 倍的时钟周期。 与大多数实际情况相比,这夸大了性能差异。 循环必须在整数个周期内运行( 在 LSD 不太复杂的 Sandybridge 上),并且 2 个额外的 uops 将它从 2 推到 3。通常,额外的 2 个融合域 uops 会产生较小的差异。 如果代码受到 4-fused-domain-uops-per-cycle 以外的其他东西的阻碍,则可能没有区别。

尽管如此,在循环中进行大量内存引用的代码可能会更快,如果使用适度的展开和递增多个指针来实现,这些指针与简单的[base + immediate offset]寻址一起使用,而不是使用[base + index]寻址模式。

进一步的东西


RIP-relative 与直接不能 micro-fuse Agner Fog 的测试表明,即使在解码器 / uop 缓存中也是如此,因此它们从一开始就不会融合(而不是未层压)。

IACA 弄错了,并声称这两个微型保险丝:

cmp dword  [abs mydata], 0x1b   ; fused counters != unfused counters (micro-fusion happened, and wasn't un-laminated).  Uses 2 entries in the uop-cache, according to Agner Fog's testing
cmp dword  [rel mydata], 0x1b   ; fused counters ~= unfused counters (micro-fusion didn't happen)

(对于cmp / jcc ,微+宏融合还有更多限制jcc :写下它以测试内存位置。)

RIP-rel 在没有直接熔断时会进行微熔断(并保持熔断),例如:

or  eax, dword  [rel mydata]    ; fused counters != unfused counters, i.e. micro-fusion happens

微融合不会增加指令的延迟 负载可以在另一个输入准备好之前发出。

ALIGN 32
.dep_fuse:
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    dec ecx
    jg .dep_fuse

由于eax dep 链,此循环每次迭代运行 5 个周期。 不比or eax, [rsi + 0 + rdi]mov ebx, [rsi + 0 + rdi] / or eax, ebx的序列快。 (unfused 和mov版本都运行相同数量的 uops。)调度/dep 检查发生在 unfused 域中。 新发布的 uops 进入调度程序(又名预订站 (RS))和 ROB。 他们在分派后离开调度程序(也就是被发送到执行单元),但留在 ROB 中直到退休。 因此,用于隐藏负载延迟的无序窗口至少是调度程序大小( Sandybridge 中为 54 个未融合域 uops,Haswell 中为 60 ,Skylake 中为 97)。

微融合没有基址和偏移量是同一个寄存器的快捷方式。 带有or eax, [mydata + rdi+4*rdi]循环(其中 rdi 为零)运行的循环与带有or eax, [rsi+rdi]的循环一样多。 这种寻址模式可用于迭代从固定地址开始的奇数大小结构数组。 这在大多数程序中可能从未使用过,因此英特尔没有花费晶体管来允许这种特殊情况的 2 寄存器模式进行微熔断也就不足为奇了。 (无论如何,英特尔将其记录为“索引寻址模式”,其中需要寄存器和比例因子。)


cmp / jccdec / jcc宏融合创建了一个 uop,即使在未融合域中也保持为单个 uop。 dec / nop / jge仍然可以在一个循环中运行,但它是三个 uops 而不是一个。

注意:自从我写了这个答案,彼得也测试了 Haswell 和 Skylake,并将结果整合到上面接受的答案中(特别是,我认为下面的 Skylake 的大部分改进似乎实际上已经出现在 Haswell 中)。 您应该看到有关跨 CPU 的行为纲要的答案,并且这个答案(尽管不是错误的)主要具有历史意义。

我的测试表明,与 Sandybridge 不同,在Skylake至少1 上,处理器甚至完全融合了复杂的寻址模式。

也就是说,上面由 Peter 发布的代码的1-arg2-arg版本在相同数量的循环中运行,具有相同数量的 uops 调度和退出。

我的结果:

./uop-test性能计数器统计信息:

     23.718772      task-clock (msec)         #    0.973 CPUs utilized          
    20,642,233      cycles                    #    0.870 GHz                    
    80,111,957      instructions              #    3.88  insns per cycle        
    60,253,831      uops_executed_thread      # 2540.344 M/sec                  
    80,295,685      uops_issued_any           # 3385.322 M/sec                  
    80,176,940      uops_retired_retire_slots # 3380.316 M/sec                  

   0.024376698 seconds time elapsed

./uop-test x性能计数器统计信息:

     13.532440      task-clock (msec)         #    0.967 CPUs utilized          
    21,592,044      cycles                    #    1.596 GHz                    
    80,073,676      instructions              #    3.71  insns per cycle        
    60,144,749      uops_executed_thread      # 4444.487 M/sec                  
    80,162,360      uops_issued_any           # 5923.718 M/sec                  
    80,104,978      uops_retired_retire_slots # 5919.478 M/sec                  

   0.013997088 seconds time elapsed

./uop-test xx性能计数器统计信息:

     16.672198      task-clock (msec)         #    0.981 CPUs utilized          
    27,056,453      cycles                    #    1.623 GHz                    
    80,083,140      instructions              #    2.96  insns per cycle        
    60,164,049      uops_executed_thread      # 3608.645 M/sec                  
   100,187,390      uops_issued_any           # 6009.249 M/sec                  
   100,118,409      uops_retired_retire_slots # 6005.112 M/sec                  

   0.016997874 seconds time elapsed

我没有在 Skylake 上找到任何 UOPS_RETIRED_ANY 指令,只有显然是融合域的“退休插槽”家伙。

最后的测试 ( uop-test xx ) 是 Peter 建议的一个变体,它使用 RIP 相关的cmp和即时,已知不会微熔:

.loop_riprel
    cmp dword [rel mydata], 1
    cmp dword [rel mydata], 2
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_riprel

结果表明,每个周期额外的 2 个 uops 被发出和退出的 uops 计数器接收(因此该测试可以区分融合发生与否)。

欢迎对其他架构进行更多测试! 您可以在 github 中找到代码(从上面的 Peter 复制)。


[1] ...也许还有一些介于 Skylake 和 Sandybridge 之间的其他架构,因为 Peter 只测试了 SB,而我只测试了 SKL。

没有 uop 缓存的较旧的 Intel 处理器可以进行融合,所以这可能是 uop 缓存的一个缺点。 我现在没有时间对此进行测试,但是下次更新我的测试脚本时,我会为 uop fusion 添加一个测试。 您是否尝试过 FMA 指令? 它们是唯一允许在未融合 uop 中包含 3 个输入依赖项的指令。

我现在已经查看了 Intel Sandy Bridge、Ivy Bridge、Haswell 和 Broadwell 的测试结果。 我还没有机会在 Skylake 上进行测试。 结果是:

  • 具有两个寄存器寻址和三个输入依赖项的指令融合得很好。 只要它们包含的数据不超过 32 位(或 2 * 16 位),它们就只取微操作缓存中的一项。
  • 可以使用 Haswell 和 Broadwell 上的融合乘加指令生成具有四个输入依赖项的指令。 这些指令仍然融合成一个微操作,并且只占用微操作缓存中的一个条目。
  • 超过32位数据的指令,例如32位地址和8位立即数数据仍然可以融合,但使用微操作缓存中的两个条目(除非32位可以压缩成16位有符号整数)
  • 具有 rip 相对寻址和立即数常量的指令不会融合,即使偏移量和立即数常量都非常小。
  • 在测试的四台机器上,所有结果都相同。
  • 这些测试是使用我自己的测试程序在循环上使用性能监控计数器进行的,这些计数器足够小以适合微操作缓存。

您的结果可能是由于其他因素造成的。 我没有尝试使用 IACA。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM