用户可轻松在不同架构硬件上运行特定SIMD指令集代码,无需重写。该项目提供快速、可移植的SIMD内在函数实现,支持多指令集,原生硬件支持时无性能损失,助力代码跨架构移植与优化。【此简介由AI生成】
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 11 个月前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 11 个月前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 | ||
| 1 年前 |
SIMD 到处都是
SIMDe 头文件库提供了快速的、可移植的 SIMD 内联函数实现,适用于不支持它们的硬件,例如在 ARM 上调用 SSE 函数。如果硬件支持本地实现,则没有性能损失(例如,SSE/AVX 在 x86 上,NEON 在 ARM 上运行速度全速)。
这使得将代码移植到其他架构变得更加容易,主要体现在以下几个方面:
首先,SIMDe 允许您几乎不费力地将端口搭建起来并运行,而不是强迫您为每个架构重写所有内容。然后,您可以开始将性能最关键的部分切换到本地内联函数,逐渐提高性能。SIMDe 使得(例如)SSE/AVX 和 NEON 代码可以并存在同一实现中。
其次,SIMDe 使得编写针对您无法方便访问的 ISA 扩展的代码变得更加容易。您可以在没有模拟器的情况下在 x86 机器上运行 NEON 代码。显然,您最终需要在目标硬件上进行测试,但对于大多数开发工作,SIMDe 可以提供一条更轻松的路径。
SIMDe 与大多数其他 SIMD 抽象层不同的地方在于,它旨在暴露底层指令集的完整功能。SIMDe 试图在保持可移植性的同时,减少移植所需的工作量,同时给您留出优化的空间。
当前的重点是编写完整的可移植实现,尽管已经有大量函数使用以下一种或多种方法实现了加速:
- 其他 ISA 扩展的 SIMD 内联函数(例如,使用 NEON 实现 SSE)。
- 编译器特定的向量扩展和内置函数,如
__builtin_shufflevector和__builtin_convertvector。 - 使用以下方法提供的编译器自动向量化提示:
您可以使用 Compiler Explorer 和一个混合的 SIMDe 头文件在线尝试 SIMDe。
当前状态
目前以下指令集扩展已有完整的实现:
- ARM
- x86 / x86_64
- WebAssembly
以及其他许多指令集扩展的部分支持,包括 AES-ni、CLMUL、SSE4.2、SVE、MSA 以及几个 AVX-512 扩展。有关进展详情,请查看问题跟踪器中的 指令集支持 标签。如果您希望收到某个指令集可用时的通知,您可以通过订阅相关问题来做到这一点。
如果您有兴趣使用 SIMDe 但我们尚未支持您需要的所有函数,请提交一个包含所需内容的列表的问题,以便我们知道要优先处理哪些内容。
默认分支受到保护,除非经过广泛的 CI 检查,否则提交不会到达该分支。状态徽章实际上没有意义,因为它们始终为绿色,但以下是链接:
- GitHub Actions
- Cirrus CI
- Semaphore CI
- Circle CI
- AppVeyor
- Azure Pipelines
- Drone CI
- Travis CI
- Packit CI
如果您正在添加新的构建,我建议使用 Cirrus CI,因为我们目前在平台上拥有最多的空间,考虑到当前构建数量和免费/开源使用的配额。或者,您可以自由设置其他提供者(例如 Codefresh、Shippable、Bitrise、Werkaer 等)。
注意:我们计划将默认分支的名称从“master”更改为其他名称,我们只是在等待 git 确定名称,以便我们可以保持一致性。
贡献指南
首先,非常感谢您阅读这一部分内容。考虑到为 SIMDe 项目做出贡献,本身就已经是非常宝贵的!
SIMDe 是一个相当庞大的项目;有大量的函数需要处理,并且在不同平台上有很多优化机会,所以我们非常欢迎您提供的任何帮助。
欢迎各技能水平的程序员参与,有很多任务相对直接明了,不需要任何特殊专长。
如果您不确定要以何种方式贡献,请考虑查看 问题追踪器。有一个 好的第一个问题 标签,如果您想逐步开始您的首次贡献,但如果您对其他方面感兴趣,请通过问题追踪器与我们联系;我们很乐意帮助您了解您感兴趣的任何内容。
如果您对实现当前未实现的函数感兴趣,有一个 指南 解释了如何添加新函数以及如何快速轻松地设置测试用例。目前这个指南还比较粗糙,但如果有什么不清楚的地方,请随时使用问题追踪器询问任何您不清楚的问题。
使用说明
首先,重要的是要注意,您 不需要两个独立的版本(一个使用 SIMDe,另一个是原生版本)。如果原生函数可用,SIMDe 将使用它们,编译器可以轻松地优化掉 SIMDe 的任何开销;它们需要做的只是基本的内联。-O2 应该就足够了,但我们强烈推荐 -O3(或任何指示编译器进行积极优化的标志),因为许多可移植回退在启用积极自动矢量化时(在较低的优化级别下不启用)速度会更快。
每个指令集都有一个单独的文件;例如 x86/mmx.h 对应 MMX,x86/sse.h 对应 SSE,x86/sse2.h 对应 SSE2,依此类推。只需包含您想要使用的指令集的头文件 而不是原生版本(如果您在包含 SIMDe 之后包含原生版本,如果启用了原生别名,将导致编译时错误)。SIMDe 将根据您在编译器中启用的扩展提供最快的实现(例如,如果您想使用 NEON 来实现 SSE,您可能需要传递类似 -mfpu=neon 或 -march=armv8-a+simd 的参数。更多信息请参见 GCC ARM 选项)。
如果您在包含 SIMDe 之前定义了 SIMDE_ENABLE_NATIVE_ALIASES,您可以使用与原生函数相同的名称。不幸的是,由于 API 的可移植性问题,这有点容易出错,因此建议只将此选项用于测试。当未定义 SIMDE_ENABLE_NATIVE_ALIASES 时,只有以 simde_ 前缀的版本可用;例如,MMX 的 _mm_add_pi8 内部函数变为 simde_mm_add_pi8,__m64 变为 simde__m64。
由于 SIMDe 是为了可移植性而设计,许多假设类型具有特定大小的函数已被修改为使用固定宽度类型。例如,Intel 的 API 使用 char 表示有符号 8 位整数,但在 ARM 上 char 通常是无符号的。SIMDe 使用 int8_t 来使 API 可移植,这意味着您的代码可能需要进行一些小的更改(例如,使用 int8_t 而不是 char)才能在其他平台上工作。
尽管如此,这些更改通常非常小。通常只需使用搜索和替换即可,很少需要手动更改。
OpenMP 4 SIMD
SIMDe 大量使用注释来帮助编译器向量化代码。到目前为止,最佳的注释是内置于 OpenMP 4 的 SIMD 支持,所以如果您的编译器支持这些注释,我们强烈建议您启用它们。
如果您已经在使用 OpenMP,SIMDe 将自动使用 _OPENMP 宏检测它,无需进一步操作。
有些编译器允许您在没有启用完整 OpenMP 的情况下启用 OpenMP SIMD。在这种情况下,SIMDe 没有运行时依赖性,也没有运行时开销;SIMDe 只会更快。不幸的是,SIMDe 没有办法检测这种情况(_OPENMP 宏未定义),所以您在编译器中启用它后,需要定义 SIMDE_ENABLE_OPENMP(例如,通过传递 -DSIMDE_ENABLE_OPENMP)以让 SIMDe 输出相关的编译指示。
启用 OpenMP SIMD 支持的方法因编译器而异:
- GCC 4.9+ 和 clang 6+ 支持
-fopenmp-simd命令行标志。 - ICC 支持
-qopenmp-simd命令行标志。 - MCST 的 LCC 默认启用 OpenMP SIMD,因此不需要任何标志(技术上您甚至不需要传递
-DSIMDE_ENABLE_OPENMP)。
我们目前不知道还有哪些编译器允许您在不启用完整 OpenMP 的情况下启用 OpenMP SIMD 支持(如果您知道,请提交一个问题告诉我们)。您应该根据具体情况决定是否要启用完整的 OpenMP 支持,但很可能链接到(但不使用)OpenMP 运行时库的开销会被使用 OpenMP SIMD 注释在 SIMDe 中获得的性能提升所抵消。
如果您选择不使用 OpenMP SIMD,SIMDe 还支持使用 Cilk Plus、GCC 循环特定编译指示 或 clang 循环提示编译指示,尽管这些不如 OpenMP SIMD 有效,且依赖它们可能会导致代码效率较低。所有这些都会被 SIMDe 自动检测,所以如果它们在您的编译器中已启用,则无需采取进一步措施。
如果出于某种原因您不希望启用 OpenMP 4 SIMD 支持,即使 SIMDe 检测到它,您也应该在包含 SIMDe 之前定义 SIMDE_DISABLE_OPENMP。
可移植性
编译器
SIMDe 依赖于一些 C99 特性,尽管 MSVC 支持的子集也能正常工作。虽然我们尽力确保在支持的地方提供优化的实现,但 SIMDe 包含了旨在在任何 C99 编译器上工作的可移植回退。
每个提交都会在持续集成中测试多个编译器、平台和配置,我们的测试覆盖率非常广泛。目前测试的编译器包括:
- GCC 版本回溯至 4.8
- Clang 版本回溯至 3.8
- Microsoft Visual Studio 版本回溯至 12(2013)
- IBM XL C/C++
- Intel C/C++ 编译器(ICC)
我通常愿意接受添加其他编译器支持的补丁,只要它们不是太破坏性的,特别是如果我们能够开始 CI 支持。如果使用我们现有的 CI 提供商不可行,那么可以添加其他 CI 平台。
硬件
以下架构在每次提交时都会在持续集成中测试:
- x86_64/amd64
- x86
- AArch64
- ARMv8
- ARMv7 支持 VFPv3-D16 浮点数
- ARMv5 EABI
- PPC64
- z/Architecture(带有 "-mzvector")
- MIPS Loongson 64
- RISC-V 64
- emscripten 32位和64位;标准和宽松
我们非常愿意添加更多架构,所以补丁是非常受欢迎的!
相关项目
- 在 portable-snippets 中的 "builtins" 模块与 SIMDe 做得非常相似,但它针对的是编译器特定的内联函数(例如
__builtin_clz和_BitScanForward),不是 SIMD 内联函数。 - 英特尔提供了一个模拟器,即 Intel® Software Development Emulator,可以用来开发使用英特尔内联函数的软件,而无需拥有支持它们的硬件,尽管它在部署方面无能为力。
- Iris 是我所知的唯一另一个尝试创建类似 SIMDe 的可移植实现的项目。SIMDe 在英特尔方面的进展要远些,但 Iris 在 ARM 上看起来更完善。仅支持 C++,采用 Apache 2.0 许可证。据我所知,它没有加速的备用方案,也没有简单的方法添加它们,因为它严重依赖模板。
- 有几个项目尝试使用另一个集合实现:
- ARM_NEON_2_x86_SSE — 使用 SSE 实现 NEON。相当广泛,采用 Apache 2.0 许可证。
- sse2neon — 使用 NEON 实现 SSE。这部分代码已经被合并到 SIMDe 中。
- veclib — 使用 AltiVec/VMX 实现 SSE2,使用非自由的 IBM 库 powerveclib。
- SSE-to-NEON — 使用 NEON 实现 SSE。非自由,采用 C++。
- AvxToNeon — 用 NEON 实现流行的 AVX+ 内联函数。采用 C 语言,Apache 2.0 许可证。
- neon2rvv - 一个 C/C++ 头文件,将 Arm/Aarch64 NEON 内联函数转换为 RISC-V Vector (RVV) 扩展,MIT 许可证。
- sse2rvv - 一个 C/C++ 头文件,将英特尔 SSE 内联函数转换为 RISCV-V 扩展内联函数,MIT 许可证。
- arm-neon-tests 包含用于验证 NEON 实现的测试。
如果你知道其他相关项目,请 告诉我们!
注意事项
有时特性无法模拟。如果 SIMDe 处于原生模式,函数将按预期工作,但如果没有原生支持,则有一些注意事项:
- 许多函数需要
<math.h>和/或<fenv.h>。SIMDe 在没有这些头文件的情况下仍然可以工作,但这些函数的结果是未定义的。 - x86 / x86_64
- SSE
SIMDE_MM_SET_ROUNDING_MODE()将使用fesetround(),改变全局舍入模式。simde_mm_getcsr和simde_mm_setcsr只实现了位 13 和 14(舍入模式)。
- AVX
simde_mm256_test*不设置 CF/ZF 寄存器,因为没有可移植的方法实现该功能。simde_mm256_zeroall和simde_mm256_zeroupper没有实现,因为没有可移植的方法实现该功能。
- SSE
另外,使用原生别名 (SIMDE_ENABLE_NATIVE_ALIASES) 时也有一些已知的限制:
- 在 Windows x86(而非 x86_64)上,一些 MMX 函数和 SSE/SSE2 使用 MMX 类型 (__m64)(除指针外)的函数可能会返回不正确的结果。
如前所述,尽管一些 API 假设基本类型(例如,int 为 32 位),SIMDe 并没有这样做,因此许多类型已被修改为使用可移植的固定宽度版本,如 int32_t。
如果你发现任何其他差异,请提交一个 issue,以便我们可以修复或将其添加到上面的列表中。
捐助者
SIMDe 使用一些组织免费提供的资源。虽然这不应该被理解为对 SIMDe 的认可,但我们非常感激他们的支持:
- IntegriCloud — 提供快速 POWER9 服务器访问权限以开发 AltiVec/VMX 支持。
- GCC 编译农场 — 提供不同架构的机器访问权限以开发各种 ISA 扩展支持。
- CodeCov.io — 为我们的测试用例提供代码覆盖率分析。
- Google — 赞助 Google Summer of Code,大量代码(Sean Maher 的贡献),以及 开源同行奖金。
如果没有这些组织捐赠资源,SIMDe 将不会像今天这样有用或易于使用。
我们还感谢任何帮助开发 SIMDe 依赖的众多软件的人,包括编译器和分析工具。
最后,特别感谢 任何贡献者 对 SIMDe 的贡献,提交 bug,提供建议,或以任何方式帮助 SIMDe 开发。
许可
SIMDe 采用 MIT 风格的许可证;请参阅 COPYING 文件了解详情。
贡献者 ✨
感谢以下出色的人(表情关键词):
Evan Nemerson 💻 🖋 📖 💡 🤔 💬 👀 ⚠️ ✅ 📢 🐛 🚇 🚧 📆 |
Michael R. Crusoe 🐛 💻 📋 🔍 🤔 🚇 📦 ⚠️ 🚧 📆 👀 |
HIMANSHI MATHUR 💻 ⚠️ |
Hidayat Khan 💻 ⚠️ |
rosbif 💻 ⚠️ 🐛 🤔 📖 |
Jun Aruga 💻 🤔 📦 🚇 🚧 ⚠️ 🐛 |
Élie ROUDNINSKI
💻 ⚠️
Jesper Storm Bache
💻
Jeff Daily
💻 🚇
Pavel
💻
Sabarish Bollapragada
💻
Gavin Li
💻
Yining Karl Li
💻
Anirban Dey
📖
Darren Ng
📖
FaresSalem
📖
Pradnyesh Gore
💻
Sean Maher
💻
Mingye Wang
📖
Ng Zhi An
💻 📖
Atharva Nimbalkar
💻 ⚠️
simba611
💻 ⚠️
Ashleigh Newman-Jones
💻 ⚠️
Willy R. Vasquez
💻 🚧 ⚠️
Keith Winstein
💻 🚧 ⚠️
David Seifert
🚧
Milot Mirdita
💻 🚧 ⚠️
aqrit
💻 🚧
Décio Luiz Gazzoni Filho
💻 🚧 ⚠️
Igor Molchanov
💻 🚧 📦
Andrew Rodriguez
💻 🚧 ⚠️
Changqing Jing
🚧
JP Cimalando
💻 🚇
Jiaxun Yang
💻 📦
| Masahiro Kitagawa | Pavel Iatchenii | Tommy Vercetti | Robert Cohn | Adam Novak | boris-kuz |
| 📦💻⚠️ | 📦💻⚠️ | 🚧 | 🚧 | 📖 | 🚧 |
| Dimo Markov | dblue | zekehul | Laurent Thomas | Sam Clegg | Thomas Lively |
| 🚧 | 🚧 | 💻🚧 | 💻 | 🚧 | 🐛🤔🚧 |
| coderzh | Dominik Kutra | Lithrein | Nick | Stephen | John Platts |
| 💻⚠️ | 💻⚠️ | 🚧 | 🚧 | 🐛 | 🐛 |
| Steven Noonan | p0nce | Paul Wise | Devin (easyaspi314) | JonLiu1993 | Cheney Wang |
| 🐛 | 🐛 | 🐛 | 🐛💻 | 📦 | 📦 |
| myd7349 | chausner | Yi-Yen Chung | Chi-Wei Chu | M-HT | Simon Gene Gottlieb |
| 📦 | 📦 | 💻⚠️ | 💻⚠️ | 💻 | 💻 |
| --------------------------- | --------------------------- | --------------------------- | |||
| Chris Bielow | gu xiwei | George Vinokhodov | |||
| 💻 代码贡献 | 📦 新平台打包/移植 ⚠️ 测试 | 💻 代码贡献 | |||
| Cœur | Florian @Proudsalsa | Thomas Schlichter | |||
| 💻 代码贡献 | 💻 代码贡献 | 🐛 错误报告 💻 代码贡献 |
本项目遵循 all-contributors 规范。欢迎各种类型的贡献!
