REP MOVSB用于重叠内存



我想知道rdirsi中重叠和非重叠内存指针的指令rep movsb是否存在差异
即通过rep movsb指令实现memcpymemmove有什么不同吗?

在本文档中https://www.amd.com/system/files/TechDocs/24594.pdf阅读以下内容:

根据硬件实现,字符串随方向标志(DF(清除为0(向上(可能比字符串移动更快DF设置为1(向下(。DF=1仅适用于重叠REP MOVS,例如当源和目标重叠

rep movsb的行为总是与完全一样。有时它可以运行得很快(宽加载/存储(,并且仍然是等效的;有时,在dst向DF方向接近src的情况下,它必须运行缓慢才能保持确切的语义。

char *rdi, *rsi;
size_t rcx;         // incoming register "args"
for( ; rcx != 0 ; rcx--) {       // rep movsb.  Interruptible after a complete iteration
*rdi = *rsi;
rdi += (DF == 0 ? 1 : -1);
rsi += (DF == 0 ? 1 : -1);
}

例如,如果使用dst = src+1、DF=0和count=16运行,则该循环(以及rep movsb(将重复第一个字节16次。每次加载都将读取上一个存储区存储的值。

这是memcpy的有效实现,因为ISO C没有定义重叠情况下的行为。

不是memmove的有效实现,在覆盖目标之前,需要将其复制为读取所有源。(cppreference(。因此,在这种情况下,将所有字节向前复制1。

实现这一点的标准方法是检测重叠是否会成为前进的问题,如果是,则从缓冲区的末端向后工作。

或者,在向后复制同样有效的系统上,只需基于dst > src无符号比较进行分支,而不必考虑大小。请参阅指针比较在64位x86中是有符号的还是无符号的?re:如何对可能的重叠进行比较的细节,如dst+size > src


性能

是的,正如AMD所说,在AMD和英特尔的当前CPU中,DF=0的速度要快得多,DF=1会回落到一个实际的逐字节微码循环,而不是使用一次16、32或64字节的快速字符串/ERMSB微码。

对于中等大小和更大的副本(两个KiB或更多(,DF=0的对齐src和dst上的rep movsb与CPU支持的矢量最宽的展开SIMD循环的速度相似,在大多数CPU上,可能在10%或20%以内。(还假设dst远远领先于src,不会导致与微码中的宽SIMD负载重叠,或者它低于src。您可以测试什么距离会导致回退到慢速路径。(

最新更新