什么C++代码编译成x86 REP指令?

sec*_*lsh 5 c++ arrays assembly machine-instruction

我在C++中将元素从一个数组复制到另一个数组.我发现rep movsx86中的指令似乎将ESI处的数组复制到大小为ECX的EDI的数组.但是,我尝试的fornor while循环都没有编译成rep movsVS 2008中的指令(在Intel Xeon x64处理器上).如何编写将编译为此指令的代码?

Cra*_*rks 11

老实说,你不应该.REP在指令集中是一种过时的保持,实际上非常慢,因为它必须调用CPU内部的微编码子程序,它具有ROM查找延迟并且也是非流水线的.

在几乎每个实现中,您都会发现memcpy()编译器内在函数更易于使用并且运行速度更快.

  • @Michael Foukarakis请参阅"AMD64处理器的AMD软件优化指南",第8.3节."在执行字符串操作时避免使用REP前缀,特别是在复制内存块时.通常,使用REP前缀重复执行字符串指令不如其他方法优化,特别是在复制内存块时." (5认同)
  • @avakar:它可能会有所不同,具体取决于特定的芯片组和步进,但同一文档在第5.13节中有一个最佳算法:一次32个字节,通过发出64位`mov`操作对.GCC,MSVC和ICC中的`memcpy()`instrinsics都足够聪明,可以为给定的块大小发出最佳指令模式. (2认同)
  • @Olof:显然,通过执行较少数量的单独动作(例如Duff的设备)处理<32b剩余部分.单独发出移动操作比击中微编码REP更有效.我建议你阅读关于这个主题的AMD和英特尔的源文档; 他们比互联网上的一些人更清晰,更具权威性. (2认同)

Nec*_*lis 5

在MSVC下,有__movsxxx&__stosxxxintrinsics将生成一个REP前缀指令.

由于crt中的sse2分支,还有一个'hack'强制内在memsetaka REP STOSvc9 +,因为内在不再退出.这是更好的,__stosxxx因为编译器可以优化常量并正确排序.

#define memset(mem,fill,size) memset((DWORD*)mem,((fill) << 24|(fill) << 16|(fill) << 8|(fill)),size)
__forceinline void memset(DWORD* pStart, unsigned long dwFill, size_t nSize)
{
    //credits to Nepharius for finding this
    DWORD* pLast = pStart + (nSize >> 2);
    while(pStart < pLast)
        *pStart++ = dwFill;

    if((nSize &= 3) == 0)
        return;

    if(nSize == 3)
    {
        (((WORD*)pStart))[0]   = WORD(dwFill);
        (((BYTE*)pStart))[2]   = BYTE(dwFill);
    }
    else if(nSize == 2)
        (((WORD*)pStart))[0]   = WORD(dwFill);
    else
        (((BYTE*)pStart))[0]   = BYTE(dwFill);
}
Run Code Online (Sandbox Code Playgroud)

当然REP并非总是用最好的东西,你的IMO方式最好不要使用memcpy,它会跳转到任何SSE2或REPS MOV根据您的系统上(下MSVC),除非你的感觉就像编写自定义组件的"火热"区域.. .


sha*_*oth 3

如果您确实需要该指令 - 使用内置汇编器并手动编写该指令。您不能依赖编译器来生成任何特定的机器代码- 即使它在一次编译中发出它,它也可以决定在下一次编译期间发出其他等效代码。