解决 Clang 下缺乏 Yz 机器约束的问题?

2024-01-14

我们使用内联汇编来使 SHA 指令可用,如果__SHA__没有定义。在 GCC 下我们使用:

GCC_INLINE __m128i GCC_INLINE_ATTRIB
MM_SHA256RNDS2_EPU32(__m128i a, const __m128i b, const __m128i c)
{
    asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "Yz" (c));
    return a;
}

Clang 不消耗 GCCYz约束 https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html (see Clang 3.2 问题 13199 https://bugs.llvm.org/show_bug.cgi?id=13199 and Clang 3.9 问题 32727 https://bugs.llvm.org/show_bug.cgi?id=32727),这是由sha256rnds2操作说明:

Yz

    First SSE register (%xmm0).

我们添加了一个mov对于铿锵:

asm ("mov %2, %%xmm0; sha256rnds2 %%xmm0, %1, %0" : "+x"(a) : "xm"(b), "x" (c) : "xmm0");

每字节性能下降约 3 个周期。在我的 2.2 GHz Celeron J3455 测试机(带有 SHA 扩展的 Goldmont)上,大约为 230 MiB/s。这并不平凡。

从反汇编来看,Clang 并没有围绕 SHA 进行优化k当进行两轮时:

Breakpoint 2, SHA256_SSE_SHA_HashBlocks (state=0xaaa3a0,
    data=0xaaa340, length=0x40) at sha.cpp:1101
1101        STATE1 = _mm_loadu_si128((__m128i*) &state[4]);
(gdb) disass
Dump of assembler code for function SHA256_SSE_SHA_HashBlocks(unsigned int*, unsigned int const*, unsigned long):
   0x000000000068cdd0 <+0>:     sub    $0x308,%rsp
   0x000000000068cdd7 <+7>:     movdqu (%rdi),%xmm0
   0x000000000068cddb <+11>:    movdqu 0x10(%rdi),%xmm1
   ...
   0x000000000068ce49 <+121>:   movq   %xmm2,%xmm0
   0x000000000068ce4d <+125>:   sha256rnds2 %xmm0,0x2f0(%rsp),%xmm1
   0x000000000068ce56 <+134>:   pshufd $0xe,%xmm2,%xmm3
   0x000000000068ce5b <+139>:   movdqa %xmm13,%xmm2
   0x000000000068ce60 <+144>:   movaps %xmm1,0x2e0(%rsp)
   0x000000000068ce68 <+152>:   movq   %xmm3,%xmm0
   0x000000000068ce6c <+156>:   sha256rnds2 %xmm0,0x2e0(%rsp),%xmm2
   0x000000000068ce75 <+165>:   movdqu 0x10(%rsi),%xmm3
   0x000000000068ce7a <+170>:   pshufb %xmm8,%xmm3
   0x000000000068ce80 <+176>:   movaps %xmm2,0x2d0(%rsp)
   0x000000000068ce88 <+184>:   movdqa %xmm3,%xmm4
   0x000000000068ce8c <+188>:   paddd  0x6729c(%rip),%xmm4        # 0x6f4130
   0x000000000068ce94 <+196>:   movq   %xmm4,%xmm0
   0x000000000068ce98 <+200>:   sha256rnds2 %xmm0,0x2d0(%rsp),%xmm1
   ...

例如,0068ce8c though 0068ce98本来应该:

paddd  0x6729c(%rip),%xmm0        # 0x6f4130
sha256rnds2 %xmm0,0x2d0(%rsp),%xmm1

我猜我们选择的内联汇编指令有点不对劲。

我们如何解决缺乏YzClang 下的机器约束?什么模式可以避免优化代码中的中间移动?


尝试使用显式寄存器变量 https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables:

const __m128i k asm("xmm0") = c;
asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "x" (k));
return a;

结果是:

In file included from sha.cpp:24:
./cpu.h:831:22: warning: ignored asm label 'xmm0' on automatic variable
        const __m128i k asm("xmm0") = c;
                            ^
./cpu.h:833:7: error: invalid operand for instruction
        asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "x" (k));
             ^
<inline asm>:1:21: note: instantiated into assembly here
        sha256rnds2 %xmm1, 752(%rsp), %xmm0
                           ^~~~~~~~~~
In file included from sha.cpp:24:
./cpu.h:833:7: error: invalid operand for instruction
        asm ("sha256rnds2 %2, %1, %0" : "+x"(a) : "xm"(b), "x" (k));
             ^
<inline asm>:1:21: note: instantiated into assembly here
        sha256rnds2 %xmm3, 736(%rsp), %xmm1
                           ^~~~~~~~~~
...

我根据标签创建了这个答案inline assembly没有提到具体的语言。扩展装配模板 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html已经假设使用语言扩展。

If the Yz约束不可用,您可以尝试创建一个临时变量来告诉CLANG使用什么寄存器而不是约束。您可以通过所谓的显式寄存器变量 https://web.archive.org/web/20160821083608/https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables:

您可以定义一个局部寄存器变量并将其与指定的寄存器关联,如下所示:

 register int *foo asm ("r12");

这里 r12 是应该使用的寄存器的名称。请注意,这与定义全局寄存器变量的语法相同,但对于局部变量,声明出现在函数内。 register 关键字是必需的,并且不能与 static 组合。寄存器名称必须是目标平台的有效寄存器名称。

在您的情况下,您希望强制使用xmm0登记。您可以分配c使用显式寄存器将参数传递给临时变量,并将该临时变量用作扩展内联程序集的参数。这是显式寄存器的主要目的海湾合作委员会/CLANG.

GCC_INLINE __m128i GCC_INLINE_ATTRIB
MM_SHA256RNDS2_EPU32(__m128i a, const __m128i b, const __m128i c)
{
   register const __m128i tmpc asm("xmm0") = c;
   __asm__("sha256rnds2 %2, %1, %0" : "+x"(a) : "x"(b), "x" (tmpc));
    return a;
}

编译器现在应该能够提供一些优化,因为它有更多关于如何xmm0寄存器将被使用。

当你放置mov %2, %%xmm0;进入模板CLANG (and GCC)不对指令做任何优化。基本装配和扩展装配模板是一个黑盒子,它只知道如何根据约束进行基本替换。


这是使用上面方法的反汇编。它是用clang++ and -std=c++03。额外的动作不再存在:

Breakpoint 1, SHA256_SSE_SHA_HashBlocks (state=0x7fffffffae60,
    data=0x7fffffffae00, length=0x40) at sha.cpp:1101
1101        STATE1 = _mm_loadu_si128((__m128i*) &state[4]);
(gdb) disass
Dump of assembler code for function SHA256_SSE_SHA_HashBlocks(unsigned int*, unsigned int const*, unsigned long):
   0x000000000068cf60 <+0>:     sub    $0x308,%rsp
   0x000000000068cf67 <+7>:     movdqu (%rdi),%xmm0
   0x000000000068cf6b <+11>:    movdqu 0x10(%rdi),%xmm1
...
   0x000000000068cfe6 <+134>:   paddd  0x670e2(%rip),%xmm0        # 0x6f40d0
   0x000000000068cfee <+142>:   sha256rnds2 %xmm0,0x2f0(%rsp),%xmm2
   0x000000000068cff7 <+151>:   pshufd $0xe,%xmm0,%xmm1
   0x000000000068cffc <+156>:   movdqa %xmm1,%xmm0
   0x000000000068d000 <+160>:   movaps %xmm2,0x2e0(%rsp)
   0x000000000068d008 <+168>:   sha256rnds2 %xmm0,0x2e0(%rsp),%xmm3
   0x000000000068d011 <+177>:   movdqu 0x10(%rsi),%xmm5
   0x000000000068d016 <+182>:   pshufb %xmm9,%xmm5
   0x000000000068d01c <+188>:   movaps %xmm3,0x2d0(%rsp)
   0x000000000068d024 <+196>:   movdqa %xmm5,%xmm0
   0x000000000068d028 <+200>:   paddd  0x670b0(%rip),%xmm0        # 0x6f40e0
   0x000000000068d030 <+208>:   sha256rnds2 %xmm0,0x2d0(%rsp),%xmm2
...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决 Clang 下缺乏 Yz 机器约束的问题? 的相关文章

  • 如何验证文件名称在 Windows 中是否有效?

    是否有一个 Windows API 函数可以将字符串值传递给该函数 该函数将返回一个指示文件名是否有效的值 我需要验证文件名是否有效 并且我正在寻找一种简单的方法来完成此操作 而无需重新发明轮子 我正在直接使用 C 但针对的是 Win32
  • UML类图:抽象方法和属性是这样写的吗?

    当我第一次为一个小型 C 项目创建 uml 类图时 我在属性方面遇到了一些麻烦 最后我只是将属性添加为变量 lt
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • gcc 与 clang:符号剥离

    gcc 和 AMD Open64 opencc 都有一个 s选项 剥离符号表和重定位信息 到目前为止我还没能在 Clang LLVM 中找到相同的选项 它存在吗 您可以使用stripbinutils 中的实用程序 实际上 llvm ld 有
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 如何将图像和 POST 数据上传到 Azure 移动服务 ApiController 终结点?

    我正在尝试上传图片and POST表单数据 尽管理想情况下我希望它是json 到我的端点Azure 移动服务应用 我有ApiController method HttpPost Route api upload databaseId sea
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • WPF TabControl,用C#代码更改TabItem的背景颜色

    嗨 我认为这是一个初学者的问题 我搜索了所有相关问题 但所有这些都由 xaml 回答 但是 我需要的是后台代码 我有一个 TabControl 我需要设置其项目的背景颜色 我需要在选择 取消选择和悬停时为项目设置不同的颜色 非常感谢你的帮助
  • Qt moc 在头文件中实现?

    是否可以告诉 Qt MOC 我想声明该类并在单个文件中实现它 而不是将它们拆分为 h 和 cpp 文件 如果要在 cpp 文件中声明并实现 QObject 子类 则必须手动包含 moc 文件 例如 文件main cpp struct Sub
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • 为什么我收到“找不到编译动态表达式所需的一种或多种类型。”?

    我有一个已更新的项目 NET 3 5 MVC v2 到 NET 4 0 MVC v3 当我尝试使用或设置时编译出现错误 ViewBag Title财产 找不到编译动态表达式所需的一种或多种类型 您是否缺少对 Microsoft CSharp
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我

随机推荐