_mm_crc32_u64定义不清

_mm_crc32_u64定义不清,c,sse,crc,crc32,sse4,C,Sse,Crc,Crc32,Sse4,为什么\u mm\u crc32\u u64(…)的定义是这样的 unsigned int64 _mm_crc32_u64( unsigned __int64 crc, unsigned __int64 v ); “crc32”指令总是累加32位CRC,而不是64位CRC(毕竟crc32不是CRC64)。如果机器指令CRC32碰巧有一个64位目标操作数,则忽略上面的32位,并在完成时用0填充,因此永远没有64位目标。我理解英特尔为什么允许在指令上使用64位目标操作数(为了一致性),但如果我想快

为什么
\u mm\u crc32\u u64(…)
的定义是这样的

unsigned int64 _mm_crc32_u64( unsigned __int64 crc, unsigned __int64 v );
“crc32”指令总是累加32位CRC,而不是64位CRC(毕竟crc32不是CRC64)。如果机器指令CRC32碰巧有一个64位目标操作数,则忽略上面的32位,并在完成时用0填充,因此永远没有64位目标。我理解英特尔为什么允许在指令上使用64位目标操作数(为了一致性),但如果我想快速处理数据,我希望源操作数尽可能大(即,如果我还有那么多数据,则使用64位,尾端使用更小的操作数),并且始终使用32位目标操作数。但是intrinsic不允许64位源和32位目标。请注意其他内在因素:

unsigned int _mm_crc32_u8 ( unsigned int crc, unsigned char v ); 
“crc”的类型不是8位类型,也不是返回类型,它们是32位。为什么没有

unsigned int _mm_crc32_u64 ( unsigned int crc, unsigned __int64 v );
??英特尔指令支持这一点,这是最有意义的内在要求

是否有人拥有可移植代码(Visual Studio和GCC)来实现后者?谢谢。 我猜是这样的:

#define CRC32(D32,S) __asm__("crc32 %0, %1" : "+xrm" (D32) : ">xrm" (S))
对于GCC,以及

#define CRC32(D32,S) __asm { crc32 D32, S }
用于VisualStudio。不幸的是,我对约束的工作原理知之甚少,对汇编级编程的语法和语义也缺乏经验

小编辑:注意我定义的宏:

#define GET_INT64(P) *(reinterpret_cast<const uint64* &>(P))++
#define GET_INT32(P) *(reinterpret_cast<const uint32* &>(P))++
#define GET_INT16(P) *(reinterpret_cast<const uint16* &>(P))++
#define GET_INT8(P)  *(reinterpret_cast<const uint8 * &>(P))++


#define DO1_HW(CR,P) CR =  _mm_crc32_u8 (CR, GET_INT8 (P))
#define DO2_HW(CR,P) CR =  _mm_crc32_u16(CR, GET_INT16(P))
#define DO4_HW(CR,P) CR =  _mm_crc32_u32(CR, GET_INT32(P))
#define DO8_HW(CR,P) CR = (_mm_crc32_u64((uint64)CR, GET_INT64(P))) & 0xFFFFFFFF;

提供的4个内在函数确实允许所有可能的使用英特尔定义的CRC32指令。指令输出始终为32位,因为指令是硬编码的,以使用特定的32位CRC多项式。但是,该指令允许您的代码一次向其提供8、16、32或64位的输入数据。一次处理64位应该使吞吐量最大化。如果限制为32位构建,一次处理32位是最好的。如果输入字节计数为奇数或不是4/8的倍数,一次处理8或16位可以简化代码逻辑

#include <stdio.h>
#include <stdint.h>
#include <intrin.h>

int main (int argc, char *argv [])
    {
    int index;
    uint8_t *data8;
    uint16_t *data16;
    uint32_t *data32;
    uint64_t *data64;
    uint32_t total1, total2, total3;
    uint64_t total4;
    uint64_t input [] = {0x1122334455667788, 0x1111222233334444};

    total1 = total2 = total3 = total4 = 0;
    data8  = (void *) input;
    data16 = (void *) input;
    data32 = (void *) input;
    data64 = (void *) input;

    for (index = 0; index < sizeof input / sizeof *data8; index++)
        total1 = _mm_crc32_u8 (total1, *data8++);

    for (index = 0; index < sizeof input / sizeof *data16; index++)
        total2 = _mm_crc32_u16 (total2, *data16++);

    for (index = 0; index < sizeof input / sizeof *data32; index++)
        total3 = _mm_crc32_u32 (total3, *data32++);

    for (index = 0; index < sizeof input / sizeof *data64; index++)
        total4 = _mm_crc32_u64 (total4, *data64++);

    printf ("CRC32 result using 8-bit chunks: %08X\n", total1);
    printf ("CRC32 result using 16-bit chunks: %08X\n", total2);
    printf ("CRC32 result using 32-bit chunks: %08X\n", total3);
    printf ("CRC32 result using 64-bit chunks: %08X\n", total4);
    return 0;
    }
#包括
#包括
#包括
int main(int argc,char*argv[])
{
整数指数;
uint8_t*数据8;
uint16_t*数据16;
uint32_t*数据32;
uint64_t*数据64;
uint32_t total1、total2、total3;
uint64_t total 4;
uint64_t输入[]={0x112233445667788,0x1111222233334444};
total1=total2=total3=total4=0;
数据8=(void*)输入;
数据16=(void*)输入;
数据32=(void*)输入;
数据64=(void*)输入;
对于(索引=0;索引
是否有人拥有可移植代码(VisualStudio和GCC)来实现后者?谢谢

我和朋友编写了一个C++ SSE内核封装器,它包含了使用64位SRC的CRC32指令的更优选用法。

请参阅i_crc32()指令。
(遗憾的是,在其他指令上,英特尔的sse内部规范甚至存在更多缺陷,请参阅更多有缺陷的内部设计示例)

Nope。请注意,total4的声明与total1、total2和total3的声明不同。如果我们要混合使用_mm_crc32_u64、_mm_crc32_u32、_mm_crc32_u16和_mm_crc32_u64,我们需要在使用_mm_crc32_u64和所有其他类型之间进行数据类型转换。诚然,它们很琐碎,但也完全没有必要——正如我所说,使用64位目标数据类型没有意义;无符号长总计=0xFFFFFFUL;int nSize=输入数据的大小,我可以这样做:
//在4字节边界上对齐内存,以便(;nSize>0&&(data&3)!=0;--nSize)总计=_mm_crc32_u8(总计,*data++);对于(;nSize>=4;nSize-=4)总计=_mm_crc32_u32(总计*(重新解释铸件(数据))++);如果(nSize>=2){total=m_crc32_u16(total,*(reinterpret_cast(data))++);nSize-=2;}如果(nSize>0)total=m_crc32_u8(total,*data++)但我不能这样做:
for(;nSize>0&&(data&3)!=0;--nSize)总计=_mm_crc32_u8(总计,*data++);对于(;nSize>=8;nSize-=8)总计=_mm_crc32_u64(总计*(重新解释铸件(数据))++);如果(nSize>=4){total=\um\u crc32\u u32(total,*(reinterpret\u cast(data))++;nSize-=4;}如果(nSize>=2){total=\um\u crc32\u u16(total,*(reinterpret\u cast(data))++;如果(nSize>0)total=\um\u crc32\u u16(total,*(reinterpret\u cast(data))++);nSize 2;}在第一个for循环之前,将我的32位“total”转换为64位“total64”,这是完全不必要和愚蠢的。也就是说,64位循环需要:
for(;nSize>=8;nSize-=8)total=_mm_crc32_u64(total,*(reinterpret_cast(data))+)&0xFFFFFFFF
还有一个隐式转换,第一个参数从32位转换为64位。@DavidI.McIntosh:为什么你认为这种情况会有任何代价?x86-64零扩展是免费的,因此,除非您的编译器在优化方面做得很差,否则对于累加器/retval来说,64位类型没有实际成本。(编译器可能不“知道”高32位为零,但这仅在您显式编写
1+(uint64_t)(uint32_t)retval
时才重要,它可能会花费一条指令进行零扩展。通常只会将结果反转为后处理,然后
#include <stdio.h>
#include <stdint.h>
#include <intrin.h>

int main (int argc, char *argv [])
    {
    int index;
    uint8_t *data8;
    uint16_t *data16;
    uint32_t *data32;
    uint64_t *data64;
    uint32_t total1, total2, total3;
    uint64_t total4;
    uint64_t input [] = {0x1122334455667788, 0x1111222233334444};

    total1 = total2 = total3 = total4 = 0;
    data8  = (void *) input;
    data16 = (void *) input;
    data32 = (void *) input;
    data64 = (void *) input;

    for (index = 0; index < sizeof input / sizeof *data8; index++)
        total1 = _mm_crc32_u8 (total1, *data8++);

    for (index = 0; index < sizeof input / sizeof *data16; index++)
        total2 = _mm_crc32_u16 (total2, *data16++);

    for (index = 0; index < sizeof input / sizeof *data32; index++)
        total3 = _mm_crc32_u32 (total3, *data32++);

    for (index = 0; index < sizeof input / sizeof *data64; index++)
        total4 = _mm_crc32_u64 (total4, *data64++);

    printf ("CRC32 result using 8-bit chunks: %08X\n", total1);
    printf ("CRC32 result using 16-bit chunks: %08X\n", total2);
    printf ("CRC32 result using 32-bit chunks: %08X\n", total3);
    printf ("CRC32 result using 64-bit chunks: %08X\n", total4);
    return 0;
    }