使用movsd制作编译器复制字符

Sum*_*uma 7 c++ performance visual-studio-2005 memcpy intrinsics

我想在时间关键函数中复制相对较短的内存序列(小于1 KB,通常为2-200字节).CPU端的最佳代码似乎是rep movsd.但是我不知道怎么能让我的编译器生成这段代码.我希望(我依旧记得这么看)使用memcpy会使用编译器内置的内在函数来做到这一点,但基于反汇编和调试,似乎编译器正在使用调用memcpy/memmove库实现.我也希望编译器可能足够聪明,可以识别以下循环并单独使用rep movsd,但似乎没有.

char *dst;
const char *src;
// ...
for (int r=size; --r>=0; ) *dst++ = *src++;
Run Code Online (Sandbox Code Playgroud)

有没有办法让Visual Studio编译器生成rep movsd序列而不是使用内联汇编?

jal*_*alf 6

想到几个问题.

首先,你怎么知道movsd会更快?你有没有查看它的延迟/吞吐量?x86架构充满了不应该使用的旧指令,因为它们在现代CPU上效率不高.

第二,如果你使用std::copy而不是memcpy 会发生什么?std::copy可能更快,因为它可以在特定数据类型的编译时专用.

第三,你是否在项目属性下启用了内部函数 - > C/C++ - >优化?

当然,我假设也启用了其他优化.


Sum*_*uma 4

使用大小恒定的 memcpy

同时我发现了什么:

当复制的块大小在编译时已知时,编译器将使用内在函数。如果不是,则调用库实现。当大小已知时,生成的代码非常好,根据大小进行选择。根据需要,它可以是单个 mov、或 movsd、或 movsd 后跟 movsb。

看来,如果我真的想始终使用 movsb 或 movsd,即使使用“动态”大小,我也必须使用内联汇编或特殊内在函数(见下文)。我知道大小“相当短”,但编译器不知道,我无法将其传达给它 - 我什至尝试使用 __assume(size<16),但这还不够。

演示代码,使用“-Ob1(仅内联扩展)进行编译:

  #include <memory.h>

  void MemCpyTest(void *tgt, const void *src, size_t size)
  {
    memcpy(tgt,src,size);
  }

  template <int size>
  void MemCpyTestT(void *tgt, const void *src)
  {
    memcpy(tgt,src,size);
  }

  int main ( int argc, char **argv )
  {
    int src;
    int dst;
    MemCpyTest(&dst,&src,sizeof(dst));
    MemCpyTestT<sizeof(dst)>(&dst,&src);
    return 0;
  }
Run Code Online (Sandbox Code Playgroud)

专门的内在函数

我最近发现存在非常简单的方法如何使 Visual Studio 编译器使用 movsd 复制字符 - 非常自然和简单:使用内在函数。以下内在函数可能会派上用场:

  • 在分配中使用固定大小的块怎么样?始终以 32 或 64 字节块进行分配并复制整个内容。我敢打赌,副本中额外的 30 多个字节几乎不会被注意到。 (2认同)