【发布时间】:2020-01-19 21:47:42
【问题描述】:
我找到的答案解释了在 x86 平台上,如果没有将值存储在两者之间的某处,则无法直接进行内存到内存复制。
mov rax,[RSI]
mov [RDI],rax
我使用 pop 大量使用 64 位写入内存,这似乎直接将值从内存复制到内存,没有任何明显的“中间人”。
在写入之前,读取之后的值在哪里?
【问题讨论】:
标签: assembly x86 x86-64 cpu-architecture
我找到的答案解释了在 x86 平台上,如果没有将值存储在两者之间的某处,则无法直接进行内存到内存复制。
mov rax,[RSI]
mov [RDI],rax
我使用 pop 大量使用 64 位写入内存,这似乎直接将值从内存复制到内存,没有任何明显的“中间人”。
在写入之前,读取之后的值在哪里?
【问题讨论】:
标签: assembly x86 x86-64 cpu-architecture
临时位置是 CPU 内部某个不属于架构状态的缓冲区。
在像 Skylake 这样的现代 x86 上,pop [mem] 解码为 2 个 uop,所以大概第一个 uop 是一个内部寄存器的 pop,第二个是一个存储。
我们知道现代 x86 CPU 确实有一些额外的逻辑寄存器保留供微码和多微指令指令使用,如此类。它们以与体系结构寄存器相同的方式重命名到物理寄存器文件中。例如http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/ 提到“一些额外的架构寄存器供内部使用”。亨利称它们为“建筑”寄存器,但这可能会引起混淆。他只是指逻辑而不是物理,像架构寄存器。这些临时寄存器不(AFAIK)跨指令边界使用,仅在一条 x86 指令中使用。
原始 8086 是非流水线的(指令预取除外),因此实现 pop [mem] 的内部微代码或逻辑可能只是从某个特殊用途的缓冲区加载然后存储。与 add [mem], reg 类似,但加载与存储的地址不同,并且没有通过 ALU 提供。
在 x86 上无法进行内存到内存的直接复制。
您可能指的是Why IA32 does not allow memory to memory mov? 上已接受的答案之类的东西,不幸的是,对原因的解释完全是错误的并且非常具有误导性。
这是使mov [mem], [mem] 不可能的指令编码 限制,而不是CPU 内部的限制。请参阅What x86 instructions take two (or more) memory operands?pop [mem] 是其中之一,因为其中一个内存操作数是隐式。即使是原始的 8086 也可以做到这一点。
我使用 pop 大量使用 64 位写入内存
如果前端 uop 吞吐量或端口 2/3 压力是瓶颈,请考虑使用堆栈中的 128 位 SSE 负载,然后使用 movlps 和 movhps 存储 64 位一半。在当前的 Intel CPU(如 Skylake)上,movhps [mem], xmm0 是一条单指令。 (实际上是微融合的;所有存储都是存储地址 + 存储数据。但无论如何,不需要像 pextrq 的无用内存目标形式那样的端口 5 shuffle uop。
或者,如果您的目的地是连续的,请执行 128 位或 256 位副本。
pop [mem] 有一些用例,但它并不出色,而且在主流 Intel 上通常不会比 pop reg / mov [mem], reg 快,因为它仍然是 2 微秒。它确实有安全的代码大小,但不需要 tmp reg。
【讨论】:
pop [rax] 是执行内存到内存操作的方法之一。弹出的值可能存储在两者之间的某个位置,但这是一个实现细节。这些答案的意思是,使用 modr/m 字节作为其操作数的指令最多可以有一个内存操作数。这些是大多数指令,但不是像 movsb [rdi], [rsi] 这样的指令,它们的操作数内置在指令中。
【讨论】: