在 Visual Studio 上使用 Keccak 代码包
Using the Keccak Code Package on Visual Studio
我下载了 Keccak 代码包(现在是 XKCP),因为我对它带来的所有功能都很感兴趣,我想在我的 "Project" 中使用它们,我们就是这样称呼它的。
问题是我正在使用 Microsoft Visual Studio Community 2017 编写我的项目...我将解释:
实际上,我正在尝试在我的项目中实施 Keyak Lake,尤其是使用 SIMD 加速的 Keyak Lake 实施。但是,KCP(Keccak 代码包)附带的代码是为 GCC 而不是 VS 设计的,因此,很难让它在 Visual Studio 上编译,主要是因为 (__m128d)和 (__m128i) 在 Keyak Lake SIMD 实现中使用的宏中强制转换。 GCC 允许这种类型的转换,但 Visual Studio 不允许,因此代码无法按原样工作,您必须使用 _mm_castpd_si128 等对其进行返工...
所以这是我尝试过的:
我在 GCC 上使用 -E 将所有宏替换为它们的等效代码。事实上,我在预处理器工作后得到了代码,所以宏都被展开、完全编写,然后我用它们的固有等价物替换了所有 Visual Studio 不接受的强制转换。
最后,我可以让代码在 Visual Studio 上编译,但它仍然没有 运行 好。
这是错误:
void KeccakP1600_Permute_12rounds(void *state)
{
//All the variables like Abae, Cae, Akimo etc... are ALL __m128i variables
//state is an unsigned char[200]
UINT64 *stateAsLanes = (UINT64*)state;
Abae = _mm_load_si128((const __m128i *)&(stateAsLanes[0]));
Aba = Abae;
Abe = _mm_unpackhi_epi64(Abae, Abae);
Cae = Abae;
Abio = _mm_load_si128((const __m128i *)&(stateAsLanes[2]));
Abi = Abio;
Abo = _mm_unpackhi_epi64(Abio, Abio);
Cio = Abio;
Abu = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[4]));
Cua = Abu;
Agae = _mm_loadu_si128((const __m128i *)&(stateAsLanes[5]));
Aga = Agae;
Abuga = _mm_unpacklo_epi64(Abu, Aga);
Age = _mm_unpackhi_epi64(Agae, Agae);
Abage = _mm_unpacklo_epi64(Aba, Age);
Cae = _mm_xor_si128(Cae, Agae);
Agio = _mm_loadu_si128((const __m128i *)&(stateAsLanes[7]));
Agi = Agio;
Abegi = _mm_unpacklo_epi64(Abe, Agi);
Ago = _mm_unpackhi_epi64(Agio, Agio);
Abigo = _mm_unpacklo_epi64(Abi, Ago);
Cio = _mm_xor_si128(Cio, Agio);
Agu = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[9]));
Abogu = _mm_unpacklo_epi64(Abo, Agu);
Cua = _mm_xor_si128(Cua, Agu);
Akae = _mm_load_si128((const __m128i *)&(stateAsLanes[10]));
Aka = Akae;
Ake = _mm_unpackhi_epi64(Akae, Akae);
Cae = _mm_xor_si128(Cae, Akae);
Akio = _mm_load_si128((const __m128i *)&(stateAsLanes[12]));
Aki = Akio;
Ako = _mm_unpackhi_epi64(Akio, Akio);
Cio = _mm_xor_si128(Cio, Akio);
Akuma = _mm_load_si128((const __m128i *)&(stateAsLanes[14]));
Cua = _mm_xor_si128(Cua, Akuma);
Ame = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[16]));
Akame = _mm_unpacklo_epi64(Aka, Ame);
Cae = _mm_xor_si128(Cae, _mm_unpackhi_epi64(Akuma, Akame));
Amio = _mm_loadu_si128((const __m128i *)&(stateAsLanes[17]));
Ami = Amio;
Akemi = _mm_unpacklo_epi64(Ake, Ami);
Amo = _mm_unpackhi_epi64(Amio, Amio);
Akimo = _mm_unpacklo_epi64(Aki, Amo);
Cio = _mm_xor_si128(Cio, Amio);
Amu = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[19]));
Akomu = _mm_unpacklo_epi64(Ako, Amu);
Cua = _mm_xor_si128(Cua, Amu);
Asase = _mm_load_si128((const __m128i *)&(stateAsLanes[20]));
Cae = _mm_xor_si128(Cae, Asase);
Asiso = _mm_load_si128((const __m128i *)&(stateAsLanes[22]));
//Error here, last line. Access violation reading location.
问题是,当没有打开编译器优化时,代码 运行 没问题,没有错误,但是一旦打开全速优化,就会弹出访问冲突读取冲突。更不用说这段代码 运行s 在 GCC 上,无论优化是什么。
您可能有一些读取违规的解决方案,甚至有一些关于如何将此 "GCC code only" 转换为 Visual Studio 可编译代码的解决方案。
据推测 stateAsLanes
按 16 对齐。_mm_load_si128((const __m128i *)&(stateAsLanes[22]));
正在从未对齐的地址执行需要对齐的 128 位加载。
您确定这是原始来源吗?无论如何,它需要是 loadu
,而不是 load
,以告诉编译器它没有对齐。
您没有在此代码中的任何地方使用 _mm_castpd_si128
,因此不清楚您更改了什么或为什么必须更改它。 GCC/clang 也被破坏了,即使在未优化的代码中也会使用 movdqa
。
对于 MSVC,它可能会因优化而中断,因为 MSVC 将负载折叠到内存操作数中以供稍后的 ALU 指令使用; IIRC,当 MSVC 和 ICC 必须使用独立 mov
负载时,它们通常使用 movdqu
未对齐负载。这肯定会解释您看到的行为,即使它会使代码 运行 比 Core 2 上所需的速度慢。
我下载了 Keccak 代码包(现在是 XKCP),因为我对它带来的所有功能都很感兴趣,我想在我的 "Project" 中使用它们,我们就是这样称呼它的。
问题是我正在使用 Microsoft Visual Studio Community 2017 编写我的项目...我将解释:
实际上,我正在尝试在我的项目中实施 Keyak Lake,尤其是使用 SIMD 加速的 Keyak Lake 实施。但是,KCP(Keccak 代码包)附带的代码是为 GCC 而不是 VS 设计的,因此,很难让它在 Visual Studio 上编译,主要是因为 (__m128d)和 (__m128i) 在 Keyak Lake SIMD 实现中使用的宏中强制转换。 GCC 允许这种类型的转换,但 Visual Studio 不允许,因此代码无法按原样工作,您必须使用 _mm_castpd_si128 等对其进行返工...
所以这是我尝试过的: 我在 GCC 上使用 -E 将所有宏替换为它们的等效代码。事实上,我在预处理器工作后得到了代码,所以宏都被展开、完全编写,然后我用它们的固有等价物替换了所有 Visual Studio 不接受的强制转换。 最后,我可以让代码在 Visual Studio 上编译,但它仍然没有 运行 好。
这是错误:
void KeccakP1600_Permute_12rounds(void *state)
{
//All the variables like Abae, Cae, Akimo etc... are ALL __m128i variables
//state is an unsigned char[200]
UINT64 *stateAsLanes = (UINT64*)state;
Abae = _mm_load_si128((const __m128i *)&(stateAsLanes[0]));
Aba = Abae;
Abe = _mm_unpackhi_epi64(Abae, Abae);
Cae = Abae;
Abio = _mm_load_si128((const __m128i *)&(stateAsLanes[2]));
Abi = Abio;
Abo = _mm_unpackhi_epi64(Abio, Abio);
Cio = Abio;
Abu = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[4]));
Cua = Abu;
Agae = _mm_loadu_si128((const __m128i *)&(stateAsLanes[5]));
Aga = Agae;
Abuga = _mm_unpacklo_epi64(Abu, Aga);
Age = _mm_unpackhi_epi64(Agae, Agae);
Abage = _mm_unpacklo_epi64(Aba, Age);
Cae = _mm_xor_si128(Cae, Agae);
Agio = _mm_loadu_si128((const __m128i *)&(stateAsLanes[7]));
Agi = Agio;
Abegi = _mm_unpacklo_epi64(Abe, Agi);
Ago = _mm_unpackhi_epi64(Agio, Agio);
Abigo = _mm_unpacklo_epi64(Abi, Ago);
Cio = _mm_xor_si128(Cio, Agio);
Agu = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[9]));
Abogu = _mm_unpacklo_epi64(Abo, Agu);
Cua = _mm_xor_si128(Cua, Agu);
Akae = _mm_load_si128((const __m128i *)&(stateAsLanes[10]));
Aka = Akae;
Ake = _mm_unpackhi_epi64(Akae, Akae);
Cae = _mm_xor_si128(Cae, Akae);
Akio = _mm_load_si128((const __m128i *)&(stateAsLanes[12]));
Aki = Akio;
Ako = _mm_unpackhi_epi64(Akio, Akio);
Cio = _mm_xor_si128(Cio, Akio);
Akuma = _mm_load_si128((const __m128i *)&(stateAsLanes[14]));
Cua = _mm_xor_si128(Cua, Akuma);
Ame = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[16]));
Akame = _mm_unpacklo_epi64(Aka, Ame);
Cae = _mm_xor_si128(Cae, _mm_unpackhi_epi64(Akuma, Akame));
Amio = _mm_loadu_si128((const __m128i *)&(stateAsLanes[17]));
Ami = Amio;
Akemi = _mm_unpacklo_epi64(Ake, Ami);
Amo = _mm_unpackhi_epi64(Amio, Amio);
Akimo = _mm_unpacklo_epi64(Aki, Amo);
Cio = _mm_xor_si128(Cio, Amio);
Amu = _mm_loadl_epi64((const __m128i *)&(stateAsLanes[19]));
Akomu = _mm_unpacklo_epi64(Ako, Amu);
Cua = _mm_xor_si128(Cua, Amu);
Asase = _mm_load_si128((const __m128i *)&(stateAsLanes[20]));
Cae = _mm_xor_si128(Cae, Asase);
Asiso = _mm_load_si128((const __m128i *)&(stateAsLanes[22]));
//Error here, last line. Access violation reading location.
问题是,当没有打开编译器优化时,代码 运行 没问题,没有错误,但是一旦打开全速优化,就会弹出访问冲突读取冲突。更不用说这段代码 运行s 在 GCC 上,无论优化是什么。
您可能有一些读取违规的解决方案,甚至有一些关于如何将此 "GCC code only" 转换为 Visual Studio 可编译代码的解决方案。
据推测 stateAsLanes
按 16 对齐。_mm_load_si128((const __m128i *)&(stateAsLanes[22]));
正在从未对齐的地址执行需要对齐的 128 位加载。
您确定这是原始来源吗?无论如何,它需要是 loadu
,而不是 load
,以告诉编译器它没有对齐。
您没有在此代码中的任何地方使用 _mm_castpd_si128
,因此不清楚您更改了什么或为什么必须更改它。 GCC/clang 也被破坏了,即使在未优化的代码中也会使用 movdqa
。
对于 MSVC,它可能会因优化而中断,因为 MSVC 将负载折叠到内存操作数中以供稍后的 ALU 指令使用; IIRC,当 MSVC 和 ICC 必须使用独立 mov
负载时,它们通常使用 movdqu
未对齐负载。这肯定会解释您看到的行为,即使它会使代码 运行 比 Core 2 上所需的速度慢。