google/highway

GitHub: google/highway

Google 开源的 C++ 跨平台 SIMD 向量化库,提供性能可移植的向量内联函数,一套代码即可在七大架构上自动适配最优指令集并实现显著加速。

Stars: 5489 | Forks: 431

# 高效且具备性能可移植性的向量软件 Highway 是一个提供可移植 SIMD/向量内联函数的 C++ 库。 [文档](https://google.github.io/highway/en/master/) 先前采用 Apache 2 许可,现为 Apache 2 / BSD-3 双重许可。 ## 为什么选择 Highway 我们对高性能软件充满热情。我们看到 CPU(服务器、移动设备、台式机)蕴藏着巨大的未开发潜力。Highway 旨在帮助工程师可靠且经济地拓展软件性能的极限。 ## 如何实现 CPU 提供了 SIMD/向量指令,可将同一操作应用于多个数据项。这可以降低能耗,例如 *五倍* 的降低,因为执行的指令更少了。我们通常也会看到 *5-10倍* 的加速。 Highway 遵循以下指导原则,使 SIMD/向量编程变得实用且可行: **符合预期**:Highway 是一个 C++ 库,经过精心挑选的函数能够很好地映射到 CPU 指令,而无需广泛的编译器转换。与自动向量化相比,生成的代码在面对代码更改/编译器更新时更加可预测和稳健。 **适用于广泛使用的平台**:Highway 支持七种架构;同一应用程序代码可以针对各种指令集,包括具有“可缩放”向量(编译时大小未知)的指令集。Highway 仅需要 C++17(语言特性,不一定需要标准库)并支持四大编译器家族。如果您想在其他平台上使用 Highway,请提出 issue。 **灵活部署**:使用 Highway 的应用程序可以在异构云或客户端设备上运行,并在运行时选择最佳的可用指令集。或者,开发者可以选择针对单一指令集而无需任何运行时开销。在这两种情况下,除了将 `HWY_STATIC_DISPATCH` 替换为 `HWY_DYNAMIC_DISPATCH` 并加上一行代码外,应用程序代码是相同的。另见 @kfjahnke 的 [调度简介](https://github.com/kfjahnke/zimt/blob/main/examples/multi_isa_example/multi_simd_isa.md)。 **适用于多种领域**:Highway 提供了广泛的操作集,用于图像处理(浮点)、压缩、视频分析、线性代数、密码学、排序和随机生成。我们认识到新的用例可能需要额外的操作,并且很乐意在合理的情况下(例如,在某些架构上没有性能断崖)添加它们。如果您想进行讨论,请提交 issue。 **回报数据并行设计**:Highway 提供了 Gather、MaskedLoad 和 FixedTag 等工具,能够为遗留数据结构实现加速。然而,最大的收益来自于为可缩放向量设计的算法和数据结构。有用的技术包括批处理、数组结构布局以及对齐/填充分配。 我们推荐以下资源作为入门: - [Highway SIMD 编程演讲](https://www.youtube.com/watch?v=R57biOOhnJM) - [面向 C++ 开发者的 SIMD](http://const.me/articles/simd/simd.pdf) - [现代硬件算法](https://en.algorithmica.org/hpc/) - [在 C++ 中优化软件](https://agner.org/optimize/optimizing_cpp.pdf) - [在三个用例中使用 SIMD 内联函数提升性能](https://stackoverflow.blog/2020/07/08/improving-performance-with-simd-intrinsics-in-three-use-cases/) ## 示例 使用 Compiler Explorer 的在线演示: - [通过动态调度支持多重目标](https://gcc.godbolt.org/z/KM3ben7ET)(更复杂,但更灵活且能使用最佳的可用 SIMD) - [使用 -m flags 的单一目标](https://gcc.godbolt.org/z/rGnjMevKG)(更简单,但要求/仅使用编译器 flags 启用的指令集) 我们注意到 Highway 被以下开源项目引用,这些项目是通过 sourcegraph.com 发现的。大多数是 GitHub 仓库。如果您想添加您的项目或直接链接到它,请随时提出 issue 或通过下面的电子邮件与我们联系。 * 音频:[Zimtohrli 感知指标](https://github.com/google/zimtohrli) * 浏览器:Chromium(+Vivaldi)、Firefox(+floorp / foxhound / librewolf / Waterfox) * 计算生物学:[RNA 分析](https://github.com/bnprks/BPCells),[长序列预处理](https://github.com/OpenGene/fastplong) * 计算机图形学:ghostty-org/ghostty,[稀疏体素渲染器](https://github.com/rools/voxl),[tgfx 2D 图形库](https://github.com/Tencent/tgfx) * 密码学:google/distributed_point_functions, google/shell-encryption * 数据结构:bkille/BitLib * 图像编解码器:eustas/2im,[Grok JPEG 2000](https://github.com/GrokImageCompression/grok),[JPEG XL](https://github.com/libjxl/libjxl),[JPEGenc](https://github.com/osamu620/JPEGenc),[Jpegli](https://github.com/google/jpegli),[libaom](https://aomedia.googlesource.com/aom/),[OpenHTJ2K](https://github.com/osamu620/OpenHTJ2K) * 图像处理:awxkee/aire, cloudinary/ssimulacra2, [libvips](https://github.com/libvips/libvips),m-ab-s/media-autobuild_suite, * 图像查看器:AlienCowEatCake/ImageViewer, diffractor/diffractor, [Lux 全景/图像查看器](https://bitbucket.org/kfj/pv/),mirillis/jpegxl-wic * 信息检索:[iresearch 数据库索引](https://github.com/iresearch-toolkit/iresearch),michaeljclark/zvec,[nebula 交互式分析 / OLAP](https://github.com/varchar-io/nebula),[`ScaNN` 可扩展最近邻](https://github.com/google-research/google-research/tree/7a269cb2ce0ae1db591fe11b62cbc0be7d72532a/scann) * 机器学习:array2d/deepx,[gemma.cpp](https://github.com/google/gemma.cpp),Tensorflow,Numpy,zpye/SimpleInfer * 编程语言:[AOT 编译的 python](https://github.com/exaloop/codon),oven-sh/bun,V8/V8,yinqiwen/rapidudf * 机器人技术:[MIT 基于模型的设计与验证](https://github.com/RobotLocomotion/drake) * 向量搜索:1yefuwang1/vectorlite, vespa-engine/vespa 其他 * [C++ SIMD 库评估](https://www.mnm-team.org/pub/Fopras/rock23/):“Highway 在多种 SIMD 扩展中表现出卓越的性能 [..]。因此,Highway 目前可能是最适合许多软件项目的 SIMD 库。” * [zimt](https://github.com/kfjahnke/zimt):一个 C++11 模板库,用于使用多线程 SIMD 代码处理 n 维数组 * [向量化快速排序](https://github.com/google/highway/tree/master/hwy/contrib/sort)([论文](https://arxiv.org/abs/2205.05982)) Highway 也可以通过包管理器或从仓库安装:
点击展开 BSD 仓库 * [DragonFlyBSD](https://github.com/DragonFlyBSD/DPorts/tree/master/devel/highway) * [FreeBSD](https://cgit.freebsd.org/ports/tree/devel/highway) * [GhostBSD](https://github.com/ghostbsd/ghostbsd-ports/tree/main/devel/highway) * [MidnightBSD](https://www.midnightbsd.org/mports/devel/highway/README.html)
点击展开跨平台软件包仓库 * [conan-io](https://conan.io/center/recipes/highway) * [conda-forge](https://anaconda.org/channels/conda-forge/packages/libhwy/overview) * [EasyBuild](https://docs.easybuild.io/version-specific/supported-software/h/Highway/) * [Homebrew](https://formulae.brew.sh/formula/highway) * [microsoft/vcpkg](https://vcpkg.io/en/package/highway) * [spack](https://packages.spack.io/package.html?name=highway) * [xmake-io/xmake-repo](https://github.com/xmake-io/xmake-repo/tree/dev/packages/h/highway)
点击展开 Linux 软件包仓库 从 [repology](https://repology.org/project/highway-simd-library/versions) 获取 [![Packaging status](https://repology.org/badge/vertical-allrepos/highway-simd-library.svg)](https://repology.org/project/highway-simd-library/versions)
点击展开 Windows 软件包仓库 * [fd00/yacp](https://github.com/fd00/yacp/tree/master/highway) * [MSYS2](https://packages.msys2.org/search?t=binpkg&q=highway)
点击展开使用过 Highway 的其他操作系统与环境 * [OPNsense](https://opnsense.org/) * [Xilinx/Vitis_Libraries](https://github.com/Xilinx/Vitis_Libraries)
## 当前状态 ### 目标平台 Highway 支持 27 个目标平台,按平台字母顺序列出: - Any: `EMU128`, `SCALAR`; - Armv7+: `NEON_WITHOUT_AES`, `NEON`, `NEON_BF16`, `SVE`, `SVE2`, `SVE_256`, `SVE2_128`; - IBM Z: `Z14`, `Z15`; - LoongArch: `LSX`, `LASX`; - POWER: `PPC8` (v2.07), `PPC9` (v3.0), `PPC10` (v3.1B, 由于编译器错误尚不支持,参见 #1207;同时需要 QEMU 7.2); - RISC-V: `RVV` (1.0); - WebAssembly: `WASM`, `WASM_EMU256`(wasm128 的 2 倍展开版本,在定义了 `HWY_WANT_WASM2` 时启用。在可能被未来的 WASM 版本取代之前,这将一直得到支持。); - x86: - `SSE2` - `SSSE3` (~Intel Core) - `SSE4` (~Nehalem,也包括 AES + CLMUL)。 - `AVX2` (~Haswell,也包括 BMI2 + F16 + FMA) - `AVX3` (~Skylake, AVX-512F/BW/CD/DQ/VL) - `AVX3_DL` (~Icelake,包括 `BitAlg` + `CLMUL` + `GFNI` + `VAES` + `VBMI` + `VBMI2` + `VNNI` + `VPOPCNT`), - `AVX3_ZEN4`(AVX3_DL 加上 BF16,针对 AMD Zen4 进行了优化;如果为静态调度进行编译,需要通过定义 `HWY_WANT_AVX3_ZEN4` 来选择启用,但在运行时调度中默认启用), - `AVX3_SPR` (~Sapphire Rapids,包括 AVX-512FP16) - `AVX10_2` (~Diamond Rapids) 我们的策略是,除非另有说明,只要目标平台能够使用当前支持的 Clang 或 GCC 进行(交叉)编译,并可以使用 QEMU 进行测试,它们就会继续得到支持。如果该目标平台可以使用 LLVM 主干进行编译,并且可以使用我们版本的 QEMU 进行测试而无需额外的 flags,那么它就有资格被纳入我们的持续测试基础设施。否则,在发布前,该目标平台将使用选定版本/配置的 Clang 和 GCC 进行手动测试。 SVE 最初是使用 farm_sve 进行测试的(见致谢)。 ### 版本控制 Highway 的发布旨在遵循 semver.org 系统(MAJOR.MINOR.PATCH),在向后兼容的添加后递增 MINOR,在向后兼容的修复后递增 PATCH。我们建议使用发布版本(而不是 Git 最新提交),因为它们经过了更广泛的测试,见下文。 当前的 1.0 版本标志着对向后兼容性的更加重视。使用已记录功能的应用程序将与具有相同主版本号的未来更新保持兼容。 ### 测试 持续集成测试使用最新版本的 Clang(在原生 x86 上运行,或在 RISC-V 和 Arm 的 QEMU 上运行)和 MSVC 2019(v19.28,在原生 x86 上运行)进行构建。 在发布之前,我们还会在使用 Clang 和 GCC 的 x86 平台上进行测试,并通过 GCC 交叉编译在 Armv7/8 上进行测试。有关详细信息,请参阅[测试流程](g3doc/release_testing_process.md)。 ### 相关模块 `contrib` 目录包含与 SIMD 相关的实用工具:一个带有对齐行的图像类、一个数学库(已实现 16 个函数,主要是三角函数),以及用于计算点积和排序的函数。 ### 其他库 如果您只需要 x86 支持,也可以使用 Agner Fog 的 [VCL 向量类库](https://github.com/vectorclass)。它包含许多函数,包括一个完整的数学库。 如果您有使用 x86/NEON 内联函数的现有代码,您可能会对 [SIMDe](https://github.com/simd-everywhere/simde) 感兴趣,它使用其他平台的内联函数或自动向量化来模拟这些内联函数。 [xSIMD](https://github.com/xtensor-stack/xsimd) 是一个仅头文件的 C++ 库。它支持 Arm、Power、RISC-V、WebAssembly 和 x86 目标平台。具有高级接口,但支持的操作较少。 [NumKong](https://github.com/ashvardanian/NumKong) 是一个 SIMD 加速的数学 C 语言库,专注于点积和混合精度矩阵乘法等操作。它可以在 C++、Go、Python、Rust、Swift 和 WebAssembly 中使用。加速操作适用于 Arm、LoongArch、Power、RISC-V 和 x86。 ## 安装 本项目使用 CMake 进行生成和构建。在基于 Debian 的系统中,你可以通过以下方式安装: ``` sudo apt install cmake ``` Highway 的单元测试使用 [googletest](https://github.com/google/googletest)。默认情况下,Highway 的 CMake 会在配置时下载此依赖项。你可以通过将 `HWY_SYSTEM_GTEST` CMake 变量设置为 ON 并单独安装 gtest 来避免这种情况: ``` sudo apt install libgtest-dev ``` 或者,你可以定义 `HWY_TEST_STANDALONE=1` 并在每个 BUILD 文件中删除所有出现的 `gtest_main`,这样测试就可以避免对 GUnit 的依赖。 运行交叉编译的测试需要操作支持,在 Debian 上由 `qemu-user-binfmt` 包提供。 要将 Highway 构建为动态或静态库(取决于 BUILD_SHARED_LIBS),可以使用标准的 CMake 工作流: ``` mkdir -p build && cd build cmake .. make -j && make test ``` 或者你可以运行 `run_tests.sh`(Windows 上是 `run_tests.bat`)。 也支持使用 Bazel 进行构建,但它的使用和测试不如前者广泛。 在为 Armv7 构建时,由于当前编译器的限制,你需要在 CMake 命令行中添加 `-DHWY_CMAKE_ARM7:BOOL=ON`;参见 #834 和 #1032。我们了解到消除此限制的工作正在进行中。 为了受益于 Armv8/v9 的 vusdot 和 vusdotq 指令,如果目标 CPU 支持的话,你可以在 -march 编译器 flag 中添加 "+i8mm"。 32 位 x86 上的构建并未得到官方支持,并且默认情况下禁用了 AVX2/3。请注意,johnplatts 已经在 32 位 x86(包括 AVX2/3)上,使用 GCC 7/8 和 Clang 8/11/12 成功构建并运行了 Highway 测试。在 Ubuntu 22.04 上,Clang 11 和 12(但不包括更高版本)需要额外的编译器 flags `-m32 -isystem /usr/i686-linux-gnu/include`。Clang 10 及更早版本除了上述之外还需要 `-isystem /usr/i686-linux-gnu/include/c++/12/i686-linux-gnu`。参见 [#1279](https://github.com/google/highway/issues/1279)。 ## 构建 highway - 使用 vcpkg highway 现已在 [vcpkg](https://github.com/Microsoft/vcpkg) 中可用 ``` vcpkg install highway ``` vcpkg 中的 highway 端口由 Microsoft 团队成员和社区贡献者保持最新。如果版本过期,请在 vcpkg 仓库中[创建 issue 或拉取请求](https://github.com/Microsoft/vcpkg)。 ## 快速入门 你可以使用 examples/ 中的 `benchmark` 作为起点。 [快速参考页面](g3doc/quick_reference.md) 简要列出了所有操作及其参数,[指令矩阵](g3doc/instruction_matrix.pdf) 显示了每个操作的指令数量。 [常见问题解答 (FAQ)](g3doc/faq.md) 回答了有关可移植性、API 设计以及去何处查找更多信息的问题。 我们建议尽可能使用完整的 SIMD 向量,以实现最大的性能可移植性。要获取它们,请将 `ScalableTag`(或等效的 `HWY_FULL(float)`)标签传递给 `Zero/Set/Load` 等函数。对于需要对通道数设定上限的用例,有两种替代方案: - 对于最多 `N` 个通道,指定 `CappedTag` 或等效的 `HWY_CAPPED(T, N)`。实际通道数将是向下取整到最接近 2 的幂的 `N`,例如,如果 `N` 是 5,则为 4;如果 `N` 是 8,则为 8。这对于像窄矩阵这样的数据结构很有用。仍然需要循环,因为向量实际上可能少于 `N` 个通道。 - 对于精确的 2 的幂 `N` 个通道,指定 `FixedTag`。受支持的最大 `N` 取决于目标,但保证至少为 `16/sizeof(T)`。 由于 ADL 限制,调用 Highway 操作的用户代码必须: * 位于 `namespace hwy { namespace HWY_NAMESPACE {` 内部;或者 * 为每个操作添加别名前缀,如 `namespace hn = hwy::HWY_NAMESPACE; hn::Add()`;或者 * 为每个使用的操作添加 using 声明:`using hwy::HWY_NAMESPACE::Add;`。 此外,每个调用 Highway 操作(如 `Load`)的函数必须带有 `HWY_ATTR` 前缀,或者位于 `HWY_BEFORE_NAMESPACE()` 和 `HWY_AFTER_NAMESPACE()` 之间。Lambda 函数目前要求在其左大括号之前使用 `HWY_ATTR`。 不要为 SIMD 向量使用命名空间范围或 `static` 初始化器,因为当使用运行时调度且编译器选择了当前 CPU 不支持的目标平台进行编译的初始化器时,这可能会导致 SIGILL。相反,通过 `Set` 初始化的常量通常应该是局部(const)变量。 使用 Highway 的代码入口点因使用静态调度还是动态调度而略有不同。在这两种情况下,我们都建议顶层函数接收一个或多个指向数组的指针,而不是特定于目标平台的向量类型。 * 对于静态调度,`HWY_TARGET` 将是 `HWY_BASELINE_TARGETS`(即编译器允许使用的目标)中最佳的可用目标(参见[快速参考](g3doc/quick_reference.md))。`HWY_NAMESPACE` 内的函数可以在定义它们的同一模块内使用 `HWY_STATIC_DISPATCH(func)(args)` 调用。你可以通过将函数包装在常规函数中并在头文件中声明该常规函数,来从其他模块调用该函数。 * 对于动态调度,通过 `HWY_EXPORT` 宏生成一个函数指针表,`HWY_DYNAMIC_DISPATCH(func)(args)` 使用该表为当前 CPU 支持的目标调用最佳的函数指针。如果定义了 `HWY_TARGET_INCLUDE` 并且包含了 `foreach_target.h`,则模块会自动为 `HWY_TARGETS` 中的每个目标编译(参见[快速参考](g3doc/quick_reference.md))。请注意,第一次调用 `HWY_DYNAMIC_DISPATCH`,或者每次调用第一次调用 `HWY_DYNAMIC_POINTER` 返回的指针时,都会涉及一些 CPU 检测开销。你可以通过在任何 `HWY_DYNAMIC_*` 调用之前调用以下代码来防止这种情况:`hwy::GetChosenTarget().Update(hwy::SupportedTargets());`。另见 @kfjahnke 的[动态调度简介](https://github.com/kfjahnke/zimt/blob/multi_isa/examples/multi_isa_example/multi_simd_isa.md)。 使用动态调度时,`foreach_target.h` 是从翻译单元(.cc 文件)包含的,而不是头文件。在多个翻译单元之间共享的包含向量代码的头文件需要特殊的包含保护,例如以下摘自 `examples/skeleton-inl.h` 的代码: ``` #if defined(HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_) == defined(HWY_TARGET_TOGGLE) #ifdef HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_ #undef HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_ #else #define HIGHWAY_HWY_EXAMPLES_SKELETON_INL_H_ #endif #include "hwy/highway.h" // Your vector code #endif ``` 按照惯例,我们将此类头文件命名为 `-inl.h`,因为它们的内容(通常是函数模板)通常是内联的。 ## 编译器 flags 编译应用程序时应启用优化。如果不进行内联,SIMD 代码可能会慢 10 到 100 倍。对于 clang 和 GCC,`-O2` 通常就足够了。 对于 MSVC,我们建议使用 `/Gv` 进行编译,以允许未内联的函数在寄存器中传递向量参数。如果打算将 AVX2 目标与半宽向量一起使用(例如用于 `PromoteTo`),使用 `/arch:AVX2` 进行编译也很重要。这似乎是在 MSVC 上可靠地生成 VEX 编码的 SSE 指令的唯一方法。有时 MSVC 会生成 VEX 编码的 SSE 指令,如果它们与 AVX 混合的话,但并非总是如此,参见 [DevCom-10618264](https://developercommunity.visualstudio.com/t/10618264)。 否则,混合 VEX 编码的 AVX2 指令和非 VEX SSE 可能会导致严重的性能下降。不幸的是,使用 `/arch:AVX2` 选项后,生成的二进制文件将需要 AVX2。请注意,clang 和 GCC 不需要这样的 flag,因为它们支持特定于目标的属性,我们使用这些属性来确保为 AVX2 目标正确生成 VEX 代码。 ## 条带化循环 在对循环进行向量化时,一个重要的问题是是否以及如何处理不能被向量大小 `N = Lanes(d)` 整除的迭代次数(“行程计数”,记为 `count`)。例如,可能需要避免写入数组末尾之后的位置。 在本节中,假设 `T` 表示元素类型,`d = ScalableTag`。假设循环体是一个函数 `template void LoopBody(D d, size_t index, size_t max_n)`。 “条带化”是一种将循环向外层循环和内层循环转换以实现向量化的技术,这样内层循环中的迭代次数就与向量宽度相匹配。然后,内层循环被替换为向量操作。 Highway 为循环向量化提供了几种策略: * 确保所有输入/输出都已填充。那么(外层)循环就是 for (size_t i = 0; i < count; i += N) LoopBody(d, i, 0); 在这里,模板参数和第二个函数参数是不需要的。 这是首选的方案,除非 `N` 达到数千,并且向量操作在具有长延迟的流水线中执行。这是 90 年代超级计算机的情况,但如今 ALU 很便宜,我们看到大多数实现都将向量分成 1、2 或 4 部分,因此即使我们不需要向量的所有通道,处理整个向量的成本也很低。事实上,这避免了在较旧的目标上进行断言或部分加载/存储的(潜在巨大的)成本,并且不会重复代码。 * 处理整个向量,并在最后一个向量中包含先前处理过的元素: for (size_t i = 0; i < count; i += N) LoopBody(d, HWY_MIN(i, count - N), 0); 这是第二种首选方案,前提是 `count >= N` 并且 `LoopBody` 是幂等的。某些元素可能会被处理两次,但单一的代码路径和完全向量化通常是值得的。即使 `count < N`,将输入/输出填充到 `N` 通常也是有意义的。 * 使用 hwy/contrib/algo/transform-inl.h 中的 `Transform*` 函数。这负责处理循环和剩余部分,你只需定义一个泛型 lambda 函数(C++14)或仿函数,它接收来自输入/输出数组的当前向量,外加可选的来自最多两个额外输入数组的向量,并返回要写入输入/输出数组的值。 下面是实现 BLAS 函数 SAXPY(`alpha * x + y`)的示例: Transform1(d, x, n, y, [](auto d, const auto v, const auto v1) HWY_ATTR { return MulAdd(Set(d, alpha), v, v1); }); * 如上所述处理整个向量,然后跟一个标量循环: size_t i = 0; for (; i + N <= count; i += N) LoopBody(d, i, 0); for (; i < count; ++i) LoopBody(CappedTag(), i, 0); 同样,这里不需要模板参数和第二个函数参数。 这避免了代码重复,如果 `count` 很大则是合理的。 如果 `count` 很小,第二个循环可能比下一个选项慢。 * 如上所述处理整个向量,然后跟一个对修改后的带有掩码的 `LoopBody` 的单次调用: size_t i = 0; for (; i + N <= count; i += N) { LoopBody(d, i, 0); } if (i < count) { LoopBody(d, i, count - i); } 现在可以在 `LoopBody` 内部使用模板参数和第三个函数参数,以非原子方式将 `v` 的前 `num_remaining` 个通道与后续位置内存中的先前内容“混合”: `BlendedStore(v, FirstN(d, num_remaining), d, pointer);`。类似地,`MaskedLoad(FirstN(d, num_remaining), d, pointer)` 加载前 `num_remaining` 个元素并在其他通道返回零。 当无法确保向量已填充时,这是一个很好的默认选择,但仅在 `#if !HWY_MEM_OPS_MIGHT_FAULT` 时安全! 与标量循环相比,只需要一次最终的迭代。 两个循环体增加的代码大小预计是值得的,因为它避免了在除最后一次迭代之外的所有迭代中进行掩码操作的成本。 ## 其他资源 * [Highway 简介(幻灯片)](g3doc/highway_intro.pdf) * [不同架构上每个操作的指令概述](g3doc/instruction_matrix.pdf) * [设计理念与比较](g3doc/design_philosophy.md) * [实现细节](g3doc/impl_details.md) ## 致谢 我们使用了 Berenger Bramas 的 [farm-sve](https://gitlab.inria.fr/bramas/farm-sve);它被证明对于在 x86 开发机上检查 SVE 移植非常有用。 这不是 Google 官方支持的产品。 联系:janwas@google.com
标签:Bash脚本, C++, CPU指令集, SIMD, 代码优化, 可移植性, 向量计算, 并行计算, 底层开发, 性能优化, 数据擦除, 无长度依赖, 服务器性能, 桌面端性能, 检测绕过, 硬件加速, 移动端优化, 编译器, 计算加速, 运行时分发, 高性能计算