c - 在 Visual Studio 上使用 Keccak 代码包

标签 c visual-studio sse

我下载了 Keccak 代码包(现在的 XKCP),因为我对它带来的所有功能很感兴趣,并且我想在我的“项目”中使用它们,我们就是这样调用它的。

问题是我正在使用 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.

问题是,当没有打开编译器优化时,代码运行良好,没有错误,但一旦打开全速优化,就会弹出访问冲突读取冲突。更不用说无论优化如何,这段代码都在 GCC 上运行。

您可能有一些解决读取冲突的解决方案,甚至有一些关于如何将此“仅限 GCC 代码”转换为 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 上运行得比必要的速度慢。

关于c - 在 Visual Studio 上使用 Keccak 代码包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53136953/

相关文章:

c++ - 严格的别名,-ffast-math 和 SSE

c++ - char * 的 _mm_loadu_ps 是否有等效项?

c - 文件读取和字符计数

c++ - 在 C++ 代码中返回 Obj-C block

c - 使用 _Generic 关键字的宏的 Eclipse CDT 语法错误

c++ - 线程执行顺序

c# - 在 LINQ 中采用所有三元运算符?

c# - 如何在 C# 中刷新表单?

c++ - SSE 64 位寄存器

c - 使用 libcURL 发送不带数据的 PUT 请求