为什么世界上有_mm_crc32_u64(...)
像这样定义?
unsigned int64 _mm_crc32_u64( unsigned __int64 crc, unsigned __int64 v );
“crc32”指令always累积 32 位 CRC,never64 位 CRC(毕竟是 CRC32,而不是 CRC64)。如果机器指令CRC32happens为了拥有 64 位目标操作数,高 32 位将被忽略,并在完成时用 0 填充,因此永远没有 64 位目标的用处。我理解为什么 Intel 允许在指令上使用 64 位目标操作数(为了统一),但如果我想快速处理数据,我需要一个尽可能大的源操作数(即 64 位,如果我还剩下那么多数据,尾部较小)并且始终是 32 位目标操作数。但内在函数不允许 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 );
? Intel指令支持这一点,并且that是最有意义的内在。
有人有可移植代码(Visual Studio 和 GCC)来实现后一个内在函数吗?谢谢。我的猜测是这样的:
#define CRC32(D32,S) __asm__("crc32 %0, %1" : "+xrm" (D32) : ">xrm" (S))
对于海湾合作委员会,以及
#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;
请注意最后一个宏语句有多么不同。缺乏统一性无疑表明内在的定义还没有被合理地定义。虽然没有必要明确地输入(uint64)
在最后一个宏中强制转换,它是隐式的并且确实发生了。反汇编生成的代码会显示 32->64 和 64->32 转换的代码,这两者都是不必要的。
换句话说,就是_mm_crc32_u64
, not _mm_crc64_u64
,但他们已经像后者一样实现了它。
如果我能得到的定义CRC32
以上正确,那么我想将我的宏更改为
#define DO1_HW(CR,P) CR = CRC32(CR, GET_INT8 (P))
#define DO2_HW(CR,P) CR = CRC32(CR, GET_INT16(P))
#define DO4_HW(CR,P) CR = CRC32(CR, GET_INT32(P))
#define DO8_HW(CR,P) CR = CRC32(CR, GET_INT64(P))